update
This commit is contained in:
@@ -1,46 +1,41 @@
|
||||
{
|
||||
"name": "paragonie\/random-lib",
|
||||
"name": "paragonie/random-lib",
|
||||
"type": "library",
|
||||
"description": "A Library For Generating Secure Random Numbers",
|
||||
"keywords": [
|
||||
"random",
|
||||
"random-numbers",
|
||||
"random-strings",
|
||||
"cryptography"
|
||||
],
|
||||
"homepage": "https:\/\/github.com\/ircmaxell\/RandomLib",
|
||||
"keywords": ["random", "random-numbers", "random-strings", "cryptography"],
|
||||
"homepage": "https://github.com/ircmaxell/RandomLib",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Paragon Initiative Enterprises",
|
||||
"email": "security@paragonie.com",
|
||||
"homepage": "https:\/\/paragonie.com"
|
||||
"homepage": "https://paragonie.com"
|
||||
},
|
||||
{
|
||||
"name": "Anthony Ferrara",
|
||||
"email": "ircmaxell@ircmaxell.com",
|
||||
"homepage": "http:\/\/blog.ircmaxell.com"
|
||||
"homepage": "http://blog.ircmaxell.com"
|
||||
}
|
||||
],
|
||||
"require-dev": {
|
||||
"mikey179\/vfsstream": "^1.6",
|
||||
"friendsofphp\/php-cs-fixer": "^1.11",
|
||||
"phpunit\/phpunit": "^4.8 || >=5.0.0 <5.4"
|
||||
"mikey179/vfsstream": "^1.6",
|
||||
"friendsofphp/php-cs-fixer": "^1.11",
|
||||
"phpunit/phpunit": "^4.8 || >=5.0.0 <5.4"
|
||||
},
|
||||
"require": {
|
||||
"ircmaxell\/security-lib": "^1.1",
|
||||
"paragonie\/random_compat": "^2|~9.99",
|
||||
"paragonie\/sodium_compat": "^1|^2",
|
||||
"ircmaxell/security-lib": "^1.1",
|
||||
"paragonie/random_compat": "^2|~9.99",
|
||||
"paragonie/sodium_compat": "^1|^2",
|
||||
"php": ">=5.3.2"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"RandomLib\\": "lib\/RandomLib\/"
|
||||
"psr-0": {
|
||||
"RandomLib": "lib"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1.x-dev"
|
||||
"dev-master": "2.1.x-dev"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version Build @@version@@
|
||||
*/
|
||||
|
||||
/**
|
||||
* The interface that all hash implementations must implement
|
||||
*
|
||||
@@ -34,18 +35,22 @@ namespace RandomLibtest\Mocks;
|
||||
class AbstractMock
|
||||
{
|
||||
protected $callbacks = array();
|
||||
|
||||
public static function init()
|
||||
{
|
||||
}
|
||||
|
||||
public function __construct(array $callbacks = array())
|
||||
{
|
||||
$this->callbacks = $callbacks;
|
||||
}
|
||||
|
||||
public function __call($name, array $args = array())
|
||||
{
|
||||
if (isset($this->callbacks[$name])) {
|
||||
return call_user_func_array($this->callbacks[$name], $args);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version Build @@version@@
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Mixer strategy interface.
|
||||
*
|
||||
@@ -38,32 +39,40 @@ namespace RandomLibtest\Mocks\Random;
|
||||
class Generator extends \RandomLib\Generator
|
||||
{
|
||||
protected $callbacks = array();
|
||||
|
||||
public static function init()
|
||||
{
|
||||
}
|
||||
|
||||
public function __construct(array $callbacks = array())
|
||||
{
|
||||
$this->callbacks = $callbacks;
|
||||
}
|
||||
|
||||
public function __call($name, array $args = array())
|
||||
{
|
||||
if (isset($this->callbacks[$name])) {
|
||||
return call_user_func_array($this->callbacks[$name], $args);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function addSource(\PasswordLib\Random\Source $source)
|
||||
{
|
||||
return $this->__call('addSource', array($source));
|
||||
}
|
||||
|
||||
public function generate($size)
|
||||
{
|
||||
return $this->__call('generate', array($size));
|
||||
}
|
||||
|
||||
public function generateInt($min = 0, $max = \PHP_INT_MAX)
|
||||
{
|
||||
return $this->__call('generateInt', array($min, $max));
|
||||
}
|
||||
|
||||
public function generateString($length, $chars = '')
|
||||
{
|
||||
return $this->__call('generateString', array($length, $chars));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version Build @@version@@
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Mixer strategy interface.
|
||||
*
|
||||
@@ -26,6 +27,7 @@
|
||||
namespace RandomLibtest\Mocks\Random;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
|
||||
/**
|
||||
* The Mixer strategy interface.
|
||||
*
|
||||
@@ -39,12 +41,15 @@ use SecurityLib\Strength;
|
||||
class Mixer extends \RandomLibTest\Mocks\AbstractMock implements \RandomLib\Mixer
|
||||
{
|
||||
public static $strength = null;
|
||||
public static $test = \true;
|
||||
|
||||
public static $test = true;
|
||||
|
||||
public static function init()
|
||||
{
|
||||
static::$strength = new Strength(Strength::HIGH);
|
||||
static::$test = \true;
|
||||
static::$test = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of Strength indicating the strength of the mixer
|
||||
*
|
||||
@@ -54,6 +59,7 @@ class Mixer extends \RandomLibTest\Mocks\AbstractMock implements \RandomLib\Mixe
|
||||
{
|
||||
return static::$strength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the mixer is available
|
||||
*
|
||||
@@ -63,6 +69,7 @@ class Mixer extends \RandomLibTest\Mocks\AbstractMock implements \RandomLib\Mixe
|
||||
{
|
||||
return static::$test;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mix the provided array of strings into a single output of the same size
|
||||
*
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version Build @@version@@
|
||||
*/
|
||||
|
||||
/**
|
||||
* The Random Number Source interface.
|
||||
*
|
||||
@@ -26,6 +27,7 @@
|
||||
namespace RandomLibtest\Mocks\Random;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
|
||||
/**
|
||||
* The Random Number Source interface.
|
||||
*
|
||||
@@ -39,10 +41,12 @@ use SecurityLib\Strength;
|
||||
class Source extends \RandomLibTest\Mocks\AbstractMock implements \RandomLib\Source
|
||||
{
|
||||
public static $strength = null;
|
||||
|
||||
public static function init()
|
||||
{
|
||||
static::$strength = new Strength(Strength::VERYLOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an instance of Strength indicating the strength of the source
|
||||
*
|
||||
@@ -52,6 +56,7 @@ class Source extends \RandomLibTest\Mocks\AbstractMock implements \RandomLib\Sou
|
||||
{
|
||||
return static::$strength;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the source is currently available.
|
||||
* Reasons might be because the library is not installed
|
||||
@@ -60,8 +65,9 @@ class Source extends \RandomLibTest\Mocks\AbstractMock implements \RandomLib\Sou
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return \true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random string of the specified size
|
||||
*
|
||||
|
||||
@@ -11,20 +11,26 @@
|
||||
namespace RandomLib;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
|
||||
class FactoryTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testConstruct()
|
||||
{
|
||||
$factory = new \RandomLib\Factory();
|
||||
$this->assertTrue($factory instanceof \RandomLib\Factory);
|
||||
$factory = new Factory();
|
||||
$this->assertTrue($factory instanceof Factory);
|
||||
}
|
||||
|
||||
public function testGetGeneratorFallback()
|
||||
{
|
||||
$factory = new \RandomLib\Factory();
|
||||
$factory = new Factory();
|
||||
$generator = $factory->getGenerator(new Strength(Strength::VERYLOW));
|
||||
$mixer = call_user_func(array(get_class($generator->getMixer()), 'getStrength'));
|
||||
$mixer = call_user_func(array(
|
||||
get_class($generator->getMixer()),
|
||||
'getStrength',
|
||||
));
|
||||
$this->assertTrue($mixer->compare(new Strength(Strength::VERYLOW)) <= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers RandomLib\Factory::getMediumStrengthGenerator
|
||||
* @covers RandomLib\Factory::getGenerator
|
||||
@@ -33,25 +39,29 @@ class FactoryTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testGetMediumStrengthGenerator()
|
||||
{
|
||||
$factory = new \RandomLib\Factory();
|
||||
$factory = new Factory();
|
||||
$generator = $factory->getMediumStrengthGenerator();
|
||||
$this->assertTrue($generator instanceof \RandomLib\Generator);
|
||||
$mixer = call_user_func(array(get_class($generator->getMixer()), 'getStrength'));
|
||||
$this->assertTrue($generator instanceof Generator);
|
||||
$mixer = call_user_func(array(
|
||||
get_class($generator->getMixer()),
|
||||
'getStrength',
|
||||
));
|
||||
$this->assertTrue($mixer->compare(new Strength(Strength::MEDIUM)) <= 0);
|
||||
foreach ($generator->getSources() as $source) {
|
||||
$strength = call_user_func(array(get_class($source), 'getStrength'));
|
||||
$this->assertTrue($strength->compare(new Strength(Strength::MEDIUM)) >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException RuntimeException
|
||||
* @expectedExceptionMessage Could not find sources
|
||||
*/
|
||||
public function testNoAvailableSource()
|
||||
{
|
||||
$factory = new \RandomLib\Factory();
|
||||
$factory = new Factory();
|
||||
$sources = new \ReflectionProperty($factory, 'sources');
|
||||
$sources->setAccessible(\true);
|
||||
$sources->setAccessible(true);
|
||||
$sources->setValue($factory, array());
|
||||
$factory->getMediumStrengthGenerator();
|
||||
}
|
||||
|
||||
@@ -24,42 +24,78 @@ class GeneratorStringTest extends \PHPUnit_Framework_TestCase
|
||||
* @var array<int, Source>
|
||||
*/
|
||||
protected $sources = array();
|
||||
|
||||
public static function provideCharCombinations()
|
||||
{
|
||||
return array(array("CHAR_LOWER", implode("", range("a", "z"))), array("CHAR_UPPER", implode("", range("A", "Z"))), array("CHAR_DIGITS", implode("", range(0, 9))), array("CHAR_UPPER_HEX", "0123456789ABCDEF"), array("CHAR_LOWER_HEX", "0123456789abcdef"), array("CHAR_BASE64", "+/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), array("EASY_TO_READ", "3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz"), array("CHAR_BRACKETS", "()<>[]{}"), array("CHAR_SYMBOLS", " !\"#\$%&'()*+,-./:;<=>?@[\\]^_`{|}~"), array("CHAR_PUNCT", ",.:;"), array("CHAR_ALPHA", implode("", array_merge(range("A", "Z"), range("a", "z")))), array("CHAR_ALNUM", implode("", array_merge(range(0, 9), range("A", "Z"), range("a", "z")))), array("CHAR_ALPHA | PUNCT", ",.:;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", \RandomLib\Generator::CHAR_ALPHA | \RandomLib\Generator::CHAR_PUNCT), array("CHAR_LOWER | EASY_TO_READ", "abcdefghijkmnopqrstuvwxyz", \RandomLib\Generator::CHAR_LOWER | \RandomLib\Generator::EASY_TO_READ), array("CHAR_DIGITS | EASY_TO_READ", "3479", \RandomLib\Generator::CHAR_DIGITS | \RandomLib\Generator::EASY_TO_READ));
|
||||
return array(
|
||||
array("CHAR_LOWER", implode("", range("a", "z"))),
|
||||
array("CHAR_UPPER", implode("", range("A", "Z"))),
|
||||
array("CHAR_DIGITS", implode("", range(0, 9))),
|
||||
array("CHAR_UPPER_HEX", "0123456789ABCDEF"),
|
||||
array("CHAR_LOWER_HEX", "0123456789abcdef"),
|
||||
array("CHAR_BASE64", "+/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"),
|
||||
array("EASY_TO_READ", "3479ACEFHJKLMNPRTUVWXYabcdefghijkmnopqrstuvwxyz"),
|
||||
array("CHAR_BRACKETS", "()<>[]{}"),
|
||||
array("CHAR_SYMBOLS", " !\"#$%&'()*+,-./:;<=>?@[\]^_`{|}~"),
|
||||
array("CHAR_PUNCT", ",.:;"),
|
||||
array("CHAR_ALPHA", implode("", array_merge(range("A", "Z"), range("a", "z")))),
|
||||
array("CHAR_ALNUM", implode("", array_merge(range(0, 9), range("A", "Z"), range("a", "z")))),
|
||||
array("CHAR_ALPHA | PUNCT", ",.:;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", Generator::CHAR_ALPHA | Generator::CHAR_PUNCT),
|
||||
array("CHAR_LOWER | EASY_TO_READ", "abcdefghijkmnopqrstuvwxyz", Generator::CHAR_LOWER | Generator::EASY_TO_READ),
|
||||
array("CHAR_DIGITS | EASY_TO_READ", "3479", Generator::CHAR_DIGITS | Generator::EASY_TO_READ),
|
||||
);
|
||||
}
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$source1 = $this->getMock('RandomLib\Source');
|
||||
$source1->expects($this->any())->method('generate')->will($this->returnCallback(function ($size) {
|
||||
$r = '';
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$r .= chr($i % 256);
|
||||
$source1->expects($this->any())
|
||||
->method('generate')
|
||||
->will($this->returnCallback(function ($size) {
|
||||
$r = '';
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$r .= chr($i % 256);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
return $r;
|
||||
}));
|
||||
));
|
||||
$source2 = $this->getMock('RandomLib\Source');
|
||||
$source2->expects($this->any())->method('generate')->will($this->returnCallback(function ($size) {
|
||||
$r = '';
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$r .= chr(0);
|
||||
$source2->expects($this->any())
|
||||
->method('generate')
|
||||
->will($this->returnCallback(function ($size) {
|
||||
$r = '';
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$r .= chr(0);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
return $r;
|
||||
}));
|
||||
));
|
||||
|
||||
$this->mixer = $this->getMock('RandomLib\Mixer');
|
||||
$this->mixer->expects($this->any())->method('mix')->will($this->returnCallback(function (array $sources) {
|
||||
if (empty($sources)) {
|
||||
return '';
|
||||
}
|
||||
$start = array_pop($sources);
|
||||
// throw new \Exception('test');
|
||||
return array_reduce($sources, function ($el1, $el2) {
|
||||
return $el1 ^ $el2;
|
||||
}, $start);
|
||||
}));
|
||||
$this->mixer->expects($this->any())
|
||||
->method('mix')
|
||||
->will($this->returnCallback(function (array $sources) {
|
||||
if (empty($sources)) {
|
||||
return '';
|
||||
}
|
||||
$start = array_pop($sources);
|
||||
|
||||
// throw new \Exception('test');
|
||||
return array_reduce(
|
||||
$sources,
|
||||
function ($el1, $el2) {
|
||||
return $el1 ^ $el2;
|
||||
},
|
||||
$start
|
||||
);
|
||||
}));
|
||||
|
||||
$this->sources = array($source1, $source2);
|
||||
$this->generator = new \RandomLib\Generator($this->sources, $this->mixer);
|
||||
$this->generator = new Generator($this->sources, $this->mixer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideCharCombinations
|
||||
*/
|
||||
@@ -67,7 +103,7 @@ class GeneratorStringTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
// test for overspecification by doubling the expected amount
|
||||
if (!$scheme) {
|
||||
$scheme = constant("RandomLib\\Generator::{$schemeName}");
|
||||
$scheme = constant("RandomLib\Generator::$schemeName");
|
||||
}
|
||||
$chars = $this->generator->generateString(strlen($expected) * 2, $scheme);
|
||||
$this->assertEquals($expected . $expected, $chars, sprintf("Testing Generator::%s failed", $schemeName));
|
||||
|
||||
@@ -15,65 +15,122 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
|
||||
protected $generator = null;
|
||||
protected $mixer = null;
|
||||
protected $sources = array();
|
||||
|
||||
public static function provideGenerate()
|
||||
{
|
||||
return array(array(0, ''), array(1, chr(0)), array(2, chr(1) . chr(1)), array(3, chr(2) . chr(0) . chr(2)), array(4, chr(3) . chr(3) . chr(3) . chr(3)));
|
||||
return array(
|
||||
array(0, ''),
|
||||
array(1, chr(0)),
|
||||
array(2, chr(1) . chr(1)),
|
||||
array(3, chr(2) . chr(0) . chr(2)),
|
||||
array(4, chr(3) . chr(3) . chr(3) . chr(3)),
|
||||
);
|
||||
}
|
||||
|
||||
public static function provideGenerateInt()
|
||||
{
|
||||
return array(array(1, 1, 1), array(0, 1, 0), array(0, 255, 0), array(400, 655, 400), array(0, 65535, 257), array(65535, 131070, 65792), array(0, 16777215, (2 << 16) + 2), array(-10, 0, -10), array(-655, -400, -655), array(-131070, -65535, -130813));
|
||||
return array(
|
||||
array(1, 1, 1),
|
||||
array(0, 1, 0),
|
||||
array(0, 255, 0),
|
||||
array(400, 655, 400),
|
||||
array(0, 65535, 257),
|
||||
array(65535, 131070, 65792),
|
||||
array(0, 16777215, (2<<16) + 2),
|
||||
array(-10, 0, -10),
|
||||
array(-655, -400, -655),
|
||||
array(-131070, -65535, -130813),
|
||||
);
|
||||
}
|
||||
|
||||
public static function provideGenerateIntRangeTest()
|
||||
{
|
||||
return array(array(0, 0), array(0, 1), array(1, 10000), array(100000, \PHP_INT_MAX));
|
||||
return array(
|
||||
array(0, 0),
|
||||
array(0, 1),
|
||||
array(1, 10000),
|
||||
array(100000, \PHP_INT_MAX),
|
||||
);
|
||||
}
|
||||
|
||||
public static function provideGenerateStringTest()
|
||||
{
|
||||
return array(array(0, 'ab', ''), array(1, 'ab', 'a'), array(1, 'a', ''), array(2, 'ab', 'bb'), array(3, 'abc', 'cac'), array(8, '0123456789abcdef', '77777777'), array(16, '0123456789abcdef', 'ffffffffffffffff'), array(16, '', 'DDDDDDDDDDDDDDDD'));
|
||||
return array(
|
||||
array(0, 'ab', ''),
|
||||
array(1, 'ab', 'a'),
|
||||
array(1, 'a', ''),
|
||||
array(2, 'ab', 'bb'),
|
||||
array(3, 'abc', 'cac'),
|
||||
array(8, '0123456789abcdef', '77777777'),
|
||||
array(16, '0123456789abcdef', 'ffffffffffffffff'),
|
||||
array(16, '', 'DDDDDDDDDDDDDDDD'),
|
||||
);
|
||||
}
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$source1 = $this->getMock('RandomLib\Source');
|
||||
$source1->expects($this->any())->method('generate')->will($this->returnCallback(function ($size) {
|
||||
$r = '';
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$r .= chr($i);
|
||||
$source1->expects($this->any())
|
||||
->method('generate')
|
||||
->will($this->returnCallback(function ($size) {
|
||||
$r = '';
|
||||
for ($i = 0; $i < $size; $i++) {
|
||||
$r .= chr($i);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
return $r;
|
||||
}));
|
||||
));
|
||||
$source2 = $this->getMock('RandomLib\Source');
|
||||
$source2->expects($this->any())->method('generate')->will($this->returnCallback(function ($size) {
|
||||
$r = '';
|
||||
for ($i = $size - 1; $i >= 0; $i--) {
|
||||
$r .= chr($i);
|
||||
$source2->expects($this->any())
|
||||
->method('generate')
|
||||
->will($this->returnCallback(function ($size) {
|
||||
$r = '';
|
||||
for ($i = $size - 1; $i >= 0; $i--) {
|
||||
$r .= chr($i);
|
||||
}
|
||||
|
||||
return $r;
|
||||
}
|
||||
return $r;
|
||||
}));
|
||||
));
|
||||
|
||||
$this->mixer = $this->getMock('RandomLib\Mixer');
|
||||
$this->mixer->expects($this->any())->method('mix')->will($this->returnCallback(function (array $sources) {
|
||||
if (empty($sources)) {
|
||||
return '';
|
||||
}
|
||||
$start = array_pop($sources);
|
||||
return array_reduce($sources, function ($el1, $el2) {
|
||||
return $el1 ^ $el2;
|
||||
}, $start);
|
||||
}));
|
||||
$this->mixer->expects($this->any())
|
||||
->method('mix')
|
||||
->will($this->returnCallback(function (array $sources) {
|
||||
if (empty($sources)) {
|
||||
return '';
|
||||
}
|
||||
$start = array_pop($sources);
|
||||
|
||||
return array_reduce(
|
||||
$sources,
|
||||
function ($el1, $el2) {
|
||||
return $el1 ^ $el2;
|
||||
},
|
||||
$start
|
||||
);
|
||||
}));
|
||||
|
||||
$this->sources = array($source1, $source2);
|
||||
$this->generator = new \RandomLib\Generator($this->sources, $this->mixer);
|
||||
$this->generator = new Generator($this->sources, $this->mixer);
|
||||
}
|
||||
|
||||
public function testConstruct()
|
||||
{
|
||||
$this->assertTrue($this->generator instanceof \RandomLib\Generator);
|
||||
$this->assertTrue($this->generator instanceof Generator);
|
||||
}
|
||||
|
||||
public function testGetMixer()
|
||||
{
|
||||
$this->assertSame($this->mixer, $this->generator->getMixer());
|
||||
}
|
||||
|
||||
public function testGetSources()
|
||||
{
|
||||
$this->assertSame($this->sources, $this->generator->getSources());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGenerate
|
||||
*/
|
||||
@@ -81,6 +138,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$this->assertEquals($expect, $this->generator->generate($size));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGenerateInt
|
||||
*/
|
||||
@@ -88,6 +146,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
$this->assertEquals($expect, $this->generator->generateInt($min, $max));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGenerateIntRangeTest
|
||||
*/
|
||||
@@ -97,24 +156,28 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertTrue($min <= $n);
|
||||
$this->assertTrue($max >= $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException RangeException
|
||||
*/
|
||||
public function testGenerateIntFail()
|
||||
{
|
||||
$n = $this->generator->generateInt(-1, \PHP_INT_MAX);
|
||||
$n = $this->generator->generateInt(-1, PHP_INT_MAX);
|
||||
}
|
||||
|
||||
|
||||
public function testGenerateIntLargeTest()
|
||||
{
|
||||
$bits = 30;
|
||||
$expected = 50529027;
|
||||
if (\PHP_INT_MAX > 4000000000) {
|
||||
if (PHP_INT_MAX > 4000000000) {
|
||||
$bits = 55;
|
||||
$expected = 1693273676973062;
|
||||
}
|
||||
$n = $this->generator->generateInt(0, (int) pow(2, $bits));
|
||||
$this->assertEquals($expected, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGenerateStringTest
|
||||
*/
|
||||
@@ -123,6 +186,7 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
|
||||
$n = $this->generator->generateString($length, $chars);
|
||||
$this->assertEquals($expected, $n);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test checks for issue #22:
|
||||
*
|
||||
@@ -130,9 +194,9 @@ class GeneratorTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testGenerateLargeRange()
|
||||
{
|
||||
if (\PHP_INT_MAX < pow(2, 32)) {
|
||||
if (PHP_INT_MAX < pow(2, 32)) {
|
||||
$this->markTestSkipped("Only test on 64 bit platforms");
|
||||
}
|
||||
$this->assertEquals(506381209866536711, $this->generator->generateInt(0, \PHP_INT_MAX));
|
||||
$this->assertEquals(506381209866536711, $this->generator->generateInt(0, PHP_INT_MAX));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
namespace RandomLib\Mixer;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
|
||||
class HashTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public static function provideMix()
|
||||
@@ -27,30 +28,35 @@ class HashTest extends \PHPUnit_Framework_TestCase
|
||||
array(array('aa', 'bb', 'cc'), 'a14c'),
|
||||
array(array('aabbcc', 'bbccdd', 'ccddee'), 'a8aff3939934'),
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testConstructWithoutArgument()
|
||||
{
|
||||
$hash = new \RandomLib\Mixer\Hash();
|
||||
$hash = new Hash();
|
||||
$this->assertTrue($hash instanceof \RandomLib\Mixer);
|
||||
}
|
||||
|
||||
public function testGetStrength()
|
||||
{
|
||||
$strength = new Strength(Strength::MEDIUM);
|
||||
$actual = \RandomLib\Mixer\Hash::getStrength();
|
||||
$actual = Hash::getStrength();
|
||||
$this->assertEquals($actual, $strength);
|
||||
}
|
||||
|
||||
public function testTest()
|
||||
{
|
||||
$actual = \RandomLib\Mixer\Hash::test();
|
||||
$actual = Hash::test();
|
||||
$this->assertTrue($actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideMix
|
||||
*/
|
||||
public function testMix($parts, $result)
|
||||
{
|
||||
$mixer = new \RandomLib\Mixer\Hash('md5');
|
||||
$mixer = new Hash('md5');
|
||||
$actual = $mixer->mix($parts);
|
||||
$this->assertEquals($result, bin2hex($actual));
|
||||
}
|
||||
|
||||
@@ -11,41 +11,58 @@
|
||||
namespace RandomLib\Mixer;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
|
||||
class McryptRijndael128Test extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public static function provideMix()
|
||||
{
|
||||
$data = array(array(array(), ''), array(array('', ''), ''), array(array('a'), '61'), array(array('a', 'b'), '6a'), array(array('aa', 'ba'), '688d'), array(array('ab', 'bb'), 'f8bc'), array(array('aa', 'bb'), 'a0f3'), array(array('aa', 'bb', 'cc'), '87c3'), array(array('aabbcc', 'bbccdd', 'ccddee'), '7cf2273e46c7'));
|
||||
$data = array(
|
||||
array(array(), ''),
|
||||
array(array('', ''), ''),
|
||||
array(array('a'), '61'),
|
||||
array(array('a', 'b'), '6a'),
|
||||
array(array('aa', 'ba'), '688d'),
|
||||
array(array('ab', 'bb'), 'f8bc'),
|
||||
array(array('aa', 'bb'), 'a0f3'),
|
||||
array(array('aa', 'bb', 'cc'), '87c3'),
|
||||
array(array('aabbcc', 'bbccdd', 'ccddee'), '7cf2273e46c7'),
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
if (!\extension_loaded('mcrypt') || \PHP_VERSION_ID >= 70100) {
|
||||
if (!\extension_loaded('mcrypt') || PHP_VERSION_ID >= 70100) {
|
||||
$this->markTestSkipped('mcrypt extension is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public function testConstructWithoutArgument()
|
||||
{
|
||||
$hash = new \RandomLib\Mixer\McryptRijndael128();
|
||||
$hash = new McryptRijndael128();
|
||||
$this->assertTrue($hash instanceof \RandomLib\Mixer);
|
||||
}
|
||||
|
||||
public function testGetStrength()
|
||||
{
|
||||
$strength = new Strength(Strength::HIGH);
|
||||
$actual = \RandomLib\Mixer\McryptRijndael128::getStrength();
|
||||
$actual = McryptRijndael128::getStrength();
|
||||
$this->assertEquals($actual, $strength);
|
||||
}
|
||||
|
||||
public function testTest()
|
||||
{
|
||||
$actual = \RandomLib\Mixer\McryptRijndael128::test();
|
||||
$actual = McryptRijndael128::test();
|
||||
$this->assertTrue($actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideMix
|
||||
*/
|
||||
public function testMix($parts, $result)
|
||||
{
|
||||
$mixer = new \RandomLib\Mixer\McryptRijndael128();
|
||||
$mixer = new McryptRijndael128();
|
||||
$actual = $mixer->mix($parts);
|
||||
$this->assertEquals($result, bin2hex($actual));
|
||||
}
|
||||
|
||||
@@ -11,41 +11,58 @@
|
||||
namespace RandomLib\Mixer;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
|
||||
class SodiumTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public static function provideMix()
|
||||
{
|
||||
$data = array(array(array(), ''), array(array('', ''), ''), array(array('a'), '61'), array(array('a', 'b'), '44'), array(array('aa', 'ba'), '6967'), array(array('ab', 'bb'), '73a6'), array(array('aa', 'bb'), 'bc7b'), array(array('aa', 'bb', 'cc'), '0cbd'), array(array('aabbcc', 'bbccdd', 'ccddee'), '5f0005cacd7c'));
|
||||
$data = array(
|
||||
array(array(), ''),
|
||||
array(array('', ''), ''),
|
||||
array(array('a'), '61'),
|
||||
array(array('a', 'b'), '44'),
|
||||
array(array('aa', 'ba'), '6967'),
|
||||
array(array('ab', 'bb'), '73a6'),
|
||||
array(array('aa', 'bb'), 'bc7b'),
|
||||
array(array('aa', 'bb', 'cc'), '0cbd'),
|
||||
array(array('aabbcc', 'bbccdd', 'ccddee'), '5f0005cacd7c'),
|
||||
);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
if (!\is_callable('sodium_crypto_generichash') || defined('HHVM_VERSION')) {
|
||||
$this->markTestSkipped('sodium extension is not available');
|
||||
}
|
||||
}
|
||||
|
||||
public function testConstructWithoutArgument()
|
||||
{
|
||||
$hash = new \RandomLib\Mixer\SodiumMixer();
|
||||
$hash = new SodiumMixer();
|
||||
$this->assertTrue($hash instanceof \RandomLib\Mixer);
|
||||
}
|
||||
|
||||
public function testGetStrength()
|
||||
{
|
||||
$strength = new Strength(Strength::HIGH);
|
||||
$actual = \RandomLib\Mixer\SodiumMixer::getStrength();
|
||||
$actual = SodiumMixer::getStrength();
|
||||
$this->assertEquals($actual, $strength);
|
||||
}
|
||||
|
||||
public function testTest()
|
||||
{
|
||||
$actual = \RandomLib\Mixer\SodiumMixer::test();
|
||||
$actual = SodiumMixer::test();
|
||||
$this->assertTrue($actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideMix
|
||||
*/
|
||||
public function testMix($parts, $result)
|
||||
{
|
||||
$mixer = new \RandomLib\Mixer\SodiumMixer();
|
||||
$mixer = new SodiumMixer();
|
||||
$actual = $mixer->mix($parts);
|
||||
$this->assertEquals($result, bin2hex($actual));
|
||||
}
|
||||
|
||||
@@ -11,23 +11,28 @@
|
||||
namespace RandomLib\Source;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
|
||||
abstract class AbstractSourceTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$class = static::getTestedClass();
|
||||
|
||||
if (!$class::isSupported()) {
|
||||
$this->markTestSkipped();
|
||||
}
|
||||
}
|
||||
|
||||
protected static function getTestedClass()
|
||||
{
|
||||
return preg_replace('/Test$/', '', get_called_class());
|
||||
}
|
||||
|
||||
protected static function getExpectedStrength()
|
||||
{
|
||||
return new Strength(Strength::VERYLOW);
|
||||
}
|
||||
|
||||
public static function provideGenerate()
|
||||
{
|
||||
$data = array();
|
||||
@@ -35,8 +40,10 @@ abstract class AbstractSourceTest extends \PHPUnit_Framework_TestCase
|
||||
$not = $i > 0 ? str_repeat(chr(0), $i) : chr(0);
|
||||
$data[] = array($i, $not);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function testGetStrength()
|
||||
{
|
||||
$class = static::getTestedClass();
|
||||
@@ -44,6 +51,7 @@ abstract class AbstractSourceTest extends \PHPUnit_Framework_TestCase
|
||||
$actual = $class::getStrength();
|
||||
$this->assertEquals($actual, $strength);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGenerate
|
||||
* @group slow
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
namespace RandomLib\Source;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
class CAPICOMTest extends \RandomLib\Source\AbstractSourceTest
|
||||
|
||||
class CAPICOMTest extends AbstractSourceTest
|
||||
{
|
||||
protected static function getExpectedStrength()
|
||||
{
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
namespace RandomLib\Source;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
class MTRandTest extends \RandomLib\Source\AbstractSourceTest
|
||||
|
||||
class MTRandTest extends AbstractSourceTest
|
||||
{
|
||||
protected static function getExpectedStrength()
|
||||
{
|
||||
|
||||
@@ -11,12 +11,14 @@
|
||||
namespace RandomLib\Source;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
class MicroTimeTest extends \RandomLib\Source\AbstractSourceTest
|
||||
|
||||
class MicroTimeTest extends AbstractSourceTest
|
||||
{
|
||||
protected static function getExpectedStrength()
|
||||
{
|
||||
return new Strength(Strength::VERYLOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the initialization of the static counter (!== 0)
|
||||
*/
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
namespace RandomLib\Source;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
class RandTest extends \RandomLib\Source\AbstractSourceTest
|
||||
|
||||
class RandTest extends AbstractSourceTest
|
||||
{
|
||||
protected static function getExpectedStrength()
|
||||
{
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
namespace RandomLib\Source;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
|
||||
class SodiumTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function setUp()
|
||||
@@ -19,6 +20,7 @@ class SodiumTest extends \PHPUnit_Framework_TestCase
|
||||
$this->markTestSkipped('The libsodium extension is not loaded');
|
||||
}
|
||||
}
|
||||
|
||||
public static function provideGenerate()
|
||||
{
|
||||
$data = array();
|
||||
@@ -26,14 +28,18 @@ class SodiumTest extends \PHPUnit_Framework_TestCase
|
||||
$not = str_repeat(chr(0), $i);
|
||||
$data[] = array($i, $not);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
public function testGetStrength()
|
||||
{
|
||||
$strength = new Strength(Strength::HIGH);
|
||||
$actual = \RandomLib\Source\Sodium::getStrength();
|
||||
$actual = Sodium::getStrength();
|
||||
$this->assertEquals($actual, $strength);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGenerate
|
||||
*/
|
||||
@@ -42,34 +48,39 @@ class SodiumTest extends \PHPUnit_Framework_TestCase
|
||||
if (!extension_loaded('libsodium')) {
|
||||
$this->markTestSkipped('The libsodium extension is not loaded');
|
||||
}
|
||||
$rand = new \RandomLib\Source\Sodium();
|
||||
|
||||
$rand = new Sodium();
|
||||
$stub = $rand->generate($length);
|
||||
$this->assertEquals($length, strlen($stub));
|
||||
$this->assertNotEquals($not, $stub);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGenerate
|
||||
*/
|
||||
public function testGenerateWithoutLibsodium($length, $not)
|
||||
{
|
||||
$rand = new \RandomLib\Source\Sodium(\false);
|
||||
$rand = new Sodium(false);
|
||||
$stub = $rand->generate($length);
|
||||
$this->assertEquals($length, strlen($stub));
|
||||
$this->assertEquals($not, $stub);
|
||||
}
|
||||
|
||||
public function testGenerateWithZeroLength()
|
||||
{
|
||||
if (!extension_loaded('libsodium')) {
|
||||
$this->markTestSkipped('The libsodium extension is not loaded');
|
||||
}
|
||||
$rand = new \RandomLib\Source\Sodium();
|
||||
|
||||
$rand = new Sodium();
|
||||
$stub = $rand->generate(0);
|
||||
$this->assertEquals(0, strlen($stub));
|
||||
$this->assertEquals('', $stub);
|
||||
}
|
||||
|
||||
public function testGenerateWithZeroLengthWithoutLibsodium()
|
||||
{
|
||||
$rand = new \RandomLib\Source\Sodium(\false);
|
||||
$rand = new Sodium(false);
|
||||
$stub = $rand->generate(0);
|
||||
$this->assertEquals(0, strlen($stub));
|
||||
$this->assertEquals('', $stub);
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
namespace RandomLib\Source;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
class URandomTest extends \RandomLib\Source\AbstractSourceTest
|
||||
|
||||
class URandomTest extends AbstractSourceTest
|
||||
{
|
||||
protected static function getExpectedStrength()
|
||||
{
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
namespace RandomLib\Source;
|
||||
|
||||
use SecurityLib\Strength;
|
||||
class UniqIDTest extends \RandomLib\Source\AbstractSourceTest
|
||||
|
||||
class UniqIDTest extends AbstractSourceTest
|
||||
{
|
||||
protected static function getExpectedStrength()
|
||||
{
|
||||
|
||||
@@ -1,147 +1,168 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* The RandomLib library for securely generating random numbers and strings in PHP
|
||||
*
|
||||
* @author Anthony Ferrara <ircmaxell@ircmaxell.com>
|
||||
* @copyright 2011 The Authors
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version Build @@version@@
|
||||
*/
|
||||
|
||||
/*
|
||||
* The RandomLib library for securely generating random numbers and strings in PHP
|
||||
*
|
||||
* @author Anthony Ferrara <ircmaxell@ircmaxell.com>
|
||||
* @copyright 2011 The Authors
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version Build @@version@@
|
||||
*/
|
||||
use RandomLib\Generator;
|
||||
use RandomLibTest\Mocks\Random\Mixer;
|
||||
use RandomLibTest\Mocks\Random\Source;
|
||||
class Vectors_Random_GeneratorTest extends \PHPUnit_Framework_TestCase
|
||||
use RandomLib\Generator;
|
||||
use RandomLibTest\Mocks\Random\Mixer;
|
||||
use RandomLibTest\Mocks\Random\Source;
|
||||
|
||||
class Vectors_Random_GeneratorTest extends PHPUnit_Framework_TestCase
|
||||
{
|
||||
public static function provideGenerateInt()
|
||||
{
|
||||
public static function provideGenerateInt()
|
||||
{
|
||||
return array(
|
||||
// First, lets test each offset based range
|
||||
array(0, 7),
|
||||
array(0, 15),
|
||||
array(0, 31),
|
||||
array(0, 63),
|
||||
array(0, 127),
|
||||
array(0, 255),
|
||||
array(0, 511),
|
||||
array(0, 1023),
|
||||
// Let's try a range not starting at 0
|
||||
array(8, 15),
|
||||
// Let's try a range with a negative number
|
||||
array(-18, -11),
|
||||
// Let's try a non-power-of-2 range
|
||||
array(10, 100),
|
||||
// Finally, let's try two large numbers
|
||||
array(100000, 100007),
|
||||
array(100000000, 100002047),
|
||||
// Now, let's force a few loops by setting a valid offset
|
||||
array(0, 5, 2),
|
||||
array(0, 9, 5),
|
||||
array(0, 27, 4),
|
||||
);
|
||||
return array(
|
||||
// First, lets test each offset based range
|
||||
array(0, 7),
|
||||
array(0, 15),
|
||||
array(0, 31),
|
||||
array(0, 63),
|
||||
array(0, 127),
|
||||
array(0, 255),
|
||||
array(0, 511),
|
||||
array(0, 1023),
|
||||
// Let's try a range not starting at 0
|
||||
array(8, 15),
|
||||
// Let's try a range with a negative number
|
||||
array(-18, -11),
|
||||
// Let's try a non-power-of-2 range
|
||||
array(10, 100),
|
||||
// Finally, let's try two large numbers
|
||||
array(100000, 100007),
|
||||
array(100000000, 100002047),
|
||||
// Now, let's force a few loops by setting a valid offset
|
||||
array(0, 5, 2),
|
||||
array(0, 9, 5),
|
||||
array(0, 27, 4),
|
||||
);
|
||||
}
|
||||
|
||||
public static function provideGenerators()
|
||||
{
|
||||
$factory = new \RandomLib\Factory();
|
||||
$generator = $factory->getLowStrengthGenerator();
|
||||
$sources = $generator->getSources();
|
||||
$ret = array();
|
||||
|
||||
$ret[] = array(new Generator($sources, new \RandomLib\Mixer\Hash()), 10000, 'hash');
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* This test asserts that the algorithm that generates the integers does not
|
||||
* actually introduce any bias into the generated numbers. If this test
|
||||
* passes, the generated integers from the generator will be as unbiased as
|
||||
* the sources that provide the data.
|
||||
*
|
||||
* @dataProvider provideGenerateInt
|
||||
*/
|
||||
public function testGenerateInt($min, $max, $offset = 0)
|
||||
{
|
||||
$generator = $this->getGenerator($max - $min + $offset);
|
||||
for ($i = $max; $i >= $min; $i--) {
|
||||
$this->assertEquals($i, $generator->generateInt($min, $max));
|
||||
}
|
||||
public static function provideGenerators()
|
||||
{
|
||||
$factory = new \RandomLib\Factory();
|
||||
$generator = $factory->getLowStrengthGenerator();
|
||||
$sources = $generator->getSources();
|
||||
$ret = array();
|
||||
$ret[] = array(new Generator($sources, new \RandomLib\Mixer\Hash()), 10000, 'hash');
|
||||
return $ret;
|
||||
}
|
||||
/**
|
||||
* This test asserts that the algorithm that generates the integers does not
|
||||
* actually introduce any bias into the generated numbers. If this test
|
||||
* passes, the generated integers from the generator will be as unbiased as
|
||||
* the sources that provide the data.
|
||||
*
|
||||
* @dataProvider provideGenerateInt
|
||||
*/
|
||||
public function testGenerateInt($min, $max, $offset = 0)
|
||||
{
|
||||
$generator = $this->getGenerator($max - $min + $offset);
|
||||
for ($i = $max; $i >= $min; $i--) {
|
||||
$this->assertEquals($i, $generator->generateInt($min, $max));
|
||||
}
|
||||
|
||||
/**
|
||||
* This generator generates two bytes at a time, and uses each 8 bit segment of
|
||||
* the generated byte as a coordinate on a grid (so 01011010 would be the
|
||||
* coordinate (0101, 1010) or (5, 10). These are used as inputs to a MonteCarlo
|
||||
* algorithm for the integral of y=x over a 15x15 grid. The expected answer is
|
||||
* 1/2 * 15 * 15 (or 1/2 * base * height, since the result is a triangle).
|
||||
* Therefore, if we get an answer close to that, we know the generator is good.
|
||||
*
|
||||
* Now, since the area under the line should be equal to the area above the line.
|
||||
* Therefore, the ratio of the two areas should be equal. This way, we can avoid
|
||||
* computing total to figure out the areas.
|
||||
*
|
||||
* I have set the bounds on the test to be 80% and 120%. Meaning that I will
|
||||
* consider the test valid and unbiased if the number of random elements that
|
||||
* fall under (inside) of the line and the number that fall outside of the line
|
||||
* are at most 20% apart.
|
||||
*
|
||||
* Since testing randomness is not reliable or repeatable, I will only fail the
|
||||
* test in two different scenarios. The first is if after the iterations the
|
||||
* outside or the inside is 0. The chances of that happening are so low that
|
||||
* if it happens, it's relatively safe to assume that something bad happened. The
|
||||
* second scenario happens when the ratio is outside of the 20% tolerance. If
|
||||
* that happens, I will re-run the entire test. If that test is outside of the 20%
|
||||
* tolerance, then the test will fail
|
||||
*
|
||||
*
|
||||
* @dataProvider provideGenerators
|
||||
*/
|
||||
public function testGenerate(\RandomLib\Generator $generator, $times)
|
||||
{
|
||||
$ratio = $this->doTestGenerate($generator, $times);
|
||||
if ($ratio < 0.8 || $ratio > 1.2) {
|
||||
$ratio2 = $this->doTestGenerate($generator, $times);
|
||||
if ($ratio2 > 1.2 || $ratio2 < 0.8) {
|
||||
$this->fail(
|
||||
sprintf(
|
||||
'The test failed multiple runs with final ratios %f and %f',
|
||||
$ratio,
|
||||
$ratio2
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This generator generates two bytes at a time, and uses each 8 bit segment of
|
||||
* the generated byte as a coordinate on a grid (so 01011010 would be the
|
||||
* coordinate (0101, 1010) or (5, 10). These are used as inputs to a MonteCarlo
|
||||
* algorithm for the integral of y=x over a 15x15 grid. The expected answer is
|
||||
* 1/2 * 15 * 15 (or 1/2 * base * height, since the result is a triangle).
|
||||
* Therefore, if we get an answer close to that, we know the generator is good.
|
||||
*
|
||||
* Now, since the area under the line should be equal to the area above the line.
|
||||
* Therefore, the ratio of the two areas should be equal. This way, we can avoid
|
||||
* computing total to figure out the areas.
|
||||
*
|
||||
* I have set the bounds on the test to be 80% and 120%. Meaning that I will
|
||||
* consider the test valid and unbiased if the number of random elements that
|
||||
* fall under (inside) of the line and the number that fall outside of the line
|
||||
* are at most 20% apart.
|
||||
*
|
||||
* Since testing randomness is not reliable or repeatable, I will only fail the
|
||||
* test in two different scenarios. The first is if after the iterations the
|
||||
* outside or the inside is 0. The chances of that happening are so low that
|
||||
* if it happens, it's relatively safe to assume that something bad happened. The
|
||||
* second scenario happens when the ratio is outside of the 20% tolerance. If
|
||||
* that happens, I will re-run the entire test. If that test is outside of the 20%
|
||||
* tolerance, then the test will fail
|
||||
*
|
||||
*
|
||||
* @dataProvider provideGenerators
|
||||
*/
|
||||
public function testGenerate(\RandomLib\Generator $generator, $times)
|
||||
{
|
||||
$ratio = $this->doTestGenerate($generator, $times);
|
||||
if ($ratio < 0.8 || $ratio > 1.2) {
|
||||
$ratio2 = $this->doTestGenerate($generator, $times);
|
||||
if ($ratio2 > 1.2 || $ratio2 < 0.8) {
|
||||
$this->fail(\sprintf('The test failed multiple runs with final ratios %f and %f', $ratio, $ratio2));
|
||||
}
|
||||
}
|
||||
|
||||
protected function doTestGenerate(\RandomLib\Generator $generator, $times)
|
||||
{
|
||||
$inside = 0;
|
||||
$outside = 0;
|
||||
$on = 0;
|
||||
for ($i = 0; $i < $times; $i++) {
|
||||
$byte = $generator->generate(2);
|
||||
$byte = unpack('n', $byte);
|
||||
$byte = array_shift($byte);
|
||||
$xCoord = ($byte >> 8);
|
||||
$yCoord = ($byte & 0xFF);
|
||||
if ($xCoord < $yCoord) {
|
||||
$outside++;
|
||||
} elseif ($xCoord == $yCoord) {
|
||||
$on++;
|
||||
} else {
|
||||
$inside++;
|
||||
}
|
||||
}
|
||||
protected function doTestGenerate(\RandomLib\Generator $generator, $times)
|
||||
{
|
||||
$inside = 0;
|
||||
$outside = 0;
|
||||
$on = 0;
|
||||
for ($i = 0; $i < $times; $i++) {
|
||||
$byte = $generator->generate(2);
|
||||
$byte = \unpack('n', $byte);
|
||||
$byte = \array_shift($byte);
|
||||
$xCoord = $byte >> 8;
|
||||
$yCoord = $byte & 0xff;
|
||||
if ($xCoord < $yCoord) {
|
||||
$outside++;
|
||||
} elseif ($xCoord == $yCoord) {
|
||||
$on++;
|
||||
} else {
|
||||
$inside++;
|
||||
}
|
||||
}
|
||||
$this->assertGreaterThan(0, $outside, 'Outside Is 0');
|
||||
$this->assertGreaterThan(0, $inside, 'Inside Is 0');
|
||||
$ratio = $inside / $outside;
|
||||
return $ratio;
|
||||
}
|
||||
public function getGenerator($random)
|
||||
{
|
||||
$source1 = new Source(array('generate' => function ($size) use (&$random) {
|
||||
$ret = \pack('N', $random);
|
||||
$this->assertGreaterThan(0, $outside, 'Outside Is 0');
|
||||
$this->assertGreaterThan(0, $inside, 'Inside Is 0');
|
||||
$ratio = $inside / $outside;
|
||||
|
||||
return $ratio;
|
||||
}
|
||||
|
||||
public function getGenerator($random)
|
||||
{
|
||||
$source1 = new Source(array(
|
||||
'generate' => function ($size) use (&$random) {
|
||||
$ret = pack('N', $random);
|
||||
$random--;
|
||||
return \substr($ret, -1 * $size);
|
||||
}));
|
||||
$sources = array($source1);
|
||||
$mixer = new Mixer(array('mix' => function (array $sources) {
|
||||
|
||||
return substr($ret, -1 * $size);
|
||||
},
|
||||
));
|
||||
$sources = array($source1);
|
||||
$mixer = new Mixer(array(
|
||||
'mix'=> function (array $sources) {
|
||||
if (empty($sources)) {
|
||||
return '';
|
||||
}
|
||||
return \array_pop($sources);
|
||||
}));
|
||||
return new Generator($sources, $mixer);
|
||||
}
|
||||
|
||||
return array_pop($sources);
|
||||
},
|
||||
));
|
||||
|
||||
return new Generator($sources, $mixer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
||||
* @version Build @@version@@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Bootstrap the library. This registers a simple autoloader for autoloading
|
||||
* classes
|
||||
@@ -28,6 +29,7 @@
|
||||
namespace RandomLibTest;
|
||||
|
||||
ini_set('memory_limit', '1G');
|
||||
|
||||
/**
|
||||
* The simple autoloader for the PasswordLibTest libraries.
|
||||
*
|
||||
@@ -50,5 +52,7 @@ spl_autoload_register(function ($class) {
|
||||
require $path;
|
||||
}
|
||||
});
|
||||
|
||||
define('PATH_ROOT', dirname(__DIR__));
|
||||
|
||||
require_once dirname(__DIR__) . '/vendor/autoload.php';
|
||||
|
||||
Reference in New Issue
Block a user