Import random/randomizer/methods tests

master
Anton Smirnov 2022-09-14 20:57:35 +03:00
parent c9be5ccc01
commit 6dedd00d98
23 changed files with 454 additions and 80 deletions

View File

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\DevEngines\FromPHP;
use Random\Engine;
class TestByteEngine implements Engine
{
/** @var int */
public $count = 0;
public function generate(): string
{
return "\x01\x02\x03\x04\x05\x06\x07\x08"[$this->count++];
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Arokettu\Random\Tests\DevEngines;
namespace Arokettu\Random\Tests\DevEngines\FromPHP;
use Random\Engine;

View File

@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\DevEngines\FromPHP;
use Random\Engine;
class TestGetBytesEngine implements Engine
{
/** @var int */
private $count = 0;
public function generate(): string
{
switch ($this->count++) {
case 0:
return 'H';
case 1:
return 'e';
case 2:
return 'll';
case 3:
return 'o';
case 4:
return 'abcdefghijklmnopqrstuvwxyz';
case 5:
return 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
case 6:
return 'success';
default:
throw new \Exception('Unhandled');
}
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Arokettu\Random\Tests\DevEngines;
namespace Arokettu\Random\Tests\DevEngines\FromPHP;
use Random\Engine;

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Arokettu\Random\Tests\DevEngines;
namespace Arokettu\Random\Tests\DevEngines\FromPHP;
use Random\Engine;

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Arokettu\Random\Tests\DevEngines;
namespace Arokettu\Random\Tests\DevEngines\FromPHP;
use Random\Engine;

View File

@ -4,8 +4,8 @@ declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Engine;
use Arokettu\Random\Tests\DevEngines\TestCountingEngine32;
use Arokettu\Random\Tests\DevEngines\TestShaEngine;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestCountingEngine32;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestShaEngine;
use PHPUnit\Framework\TestCase;
/**

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Engine;
use Arokettu\Random\Tests\DevEngines\TestWrapperEngine;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestWrapperEngine;
use PHPUnit\Framework\TestCase;
use Random\Engine\Mt19937;
use Random\Engine\PcgOneseq128XslRr64;

View File

@ -1,54 +0,0 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer;
use PHPUnit\Framework\TestCase;
use Random\Engine;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/get_bytes.phpt
*/
class GetBytesTest extends TestCase
{
public function testGetBytes(): void
{
$randomizer = new Randomizer(
new class () implements Engine
{
/** @var int */
private $count = 0;
public function generate(): string
{
if ($this->count > 5) {
throw new \RuntimeException('overflow');
}
switch ($this->count++) {
case 0:
return 'H';
case 1:
return 'e';
case 2:
return 'll';
case 3:
return 'o';
case 4:
return 'abcdefghijklmnopqrstuvwxyz';
case 5:
return 'success';
default:
return \random_bytes(16);
}
}
}
);
self::assertEquals('Hello', $randomizer->getBytes(5));
self::assertEquals('abcdefgh', $randomizer->getBytes(8)); // 64 bits
self::assertEquals('success', $randomizer->getBytes(7)); // 64 bits
}
}

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestGetBytesEngine;
use PHPUnit\Framework\TestCase;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/get_bytes.phpt
*/
class GetBytesExpansionTest extends TestCase
{
public function testGetBytes(): void
{
$randomizer = new Randomizer(new TestGetBytesEngine());
self::assertEquals('Hello', $randomizer->getBytes(5));
// Returned values are truncated to 64-bits for technical reasons, thus dropping i-z
self::assertEquals('abcdefghABC', $randomizer->getBytes(11));
self::assertEquals('success', $randomizer->getBytes(7));
}
}

View File

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestShaEngine;
use PHPUnit\Framework\TestCase;
use Random\Engine\Mt19937;
use Random\Engine\PcgOneseq128XslRr64;
use Random\Engine\Secure;
use Random\Engine\Xoshiro256StarStar;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/getBytes.phpt
*/
class GetBytesTest extends TestCase
{
public function testGetBytes(): void
{
$engines = [];
$engines[] = new Mt19937(null, \MT_RAND_MT19937);
$engines[] = new Mt19937(null, \MT_RAND_PHP);
$engines[] = new PcgOneseq128XslRr64();
$engines[] = new Xoshiro256StarStar();
$engines[] = new Secure();
$engines[] = new TestShaEngine();
foreach ($engines as $engine) {
$randomizer = new Randomizer($engine);
for ($i = 1; $i < 1000; $i++) {
self::assertEquals($i, \strlen($randomizer->getBytes($i)));
}
}
}
}

View File

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestByteEngine;
use PHPUnit\Framework\TestCase;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/getInt_expansion_32.phpt
*/
class GetIntExpansion32 extends TestCase
{
public function testGetInt(): void
{
$randomizer = new Randomizer(new TestByteEngine());
self::assertEquals('01020300', \bin2hex(\pack('V', $randomizer->getInt(0, 0x00FFFFFF))));
}
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestByteEngine;
use PHPUnit\Framework\TestCase;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/getInt_expansion_64.phpt
*/
class GetIntExpansion64 extends TestCase
{
public function testGetInt(): void
{
// only when running 64 bit
if (\PHP_INT_SIZE < 8) {
$this->markTestSkipped("It's a 64 bit test");
}
$randomizer = new Randomizer(new TestByteEngine());
self::assertEquals('0102030405060700', \bin2hex(\pack('V', $randomizer->getInt(0, 0x00FFFFFFFFFFFFFF))));
}
}

View File

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use PHPUnit\Framework\TestCase;
use Random\Engine\Mt19937;
use Random\Randomizer;
/**
* GH-9415: Randomizer::getInt(0, 2**32 - 1) with Mt19937 always returns 1
* polyfill never was affected but import it anyway
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/getInt_gh9415.phpt
*/
class GetIntGh9415 extends TestCase
{
public function testGh9415(): void
{
$randomizer = new Randomizer(new Mt19937(1234));
// Parameters shifted by -2147483648 to be compatible with 32-bit.
self::assertEquals(-1324913873, $randomizer->getInt(-2147483648, 2147483647));
$randomizer = new Randomizer(new Mt19937(4321));
self::assertEquals(-1843387587, $randomizer->getInt(-2147483648, 2147483647));
}
}

View File

@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestShaEngine;
use PHPUnit\Framework\TestCase;
use Random\Engine\Mt19937;
use Random\Engine\PcgOneseq128XslRr64;
use Random\Engine\Secure;
use Random\Engine\Xoshiro256StarStar;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/getInt.phpt
*/
class GetIntTest extends TestCase
{
public function testGetInt(): void
{
$engines = [];
$engines[] = new Mt19937(null, \MT_RAND_MT19937);
$engines[] = new Mt19937(null, \MT_RAND_PHP);
$engines[] = new PcgOneseq128XslRr64();
$engines[] = new Xoshiro256StarStar();
$engines[] = new Secure();
$engines[] = new TestShaEngine();
foreach ($engines as $engine) {
$randomizer = new Randomizer($engine);
// Basic range test.
for ($i = 0; $i < 10000; $i++) {
$result = $randomizer->getInt(-$i, $i);
self::assertGreaterThanOrEqual(-$i, $result, \get_class($engine));
self::assertLessThanOrEqual($i, $result, \get_class($engine));
}
// Test that extreme ranges do not throw.
for ($i = 0; $i < 10000; $i++) {
self::assertIsInt($randomizer->getInt(\PHP_INT_MIN, \PHP_INT_MAX));
}
}
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer;
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use PHPUnit\Framework\TestCase;
use Random\Engine\Xoshiro256StarStar;
@ -10,9 +10,9 @@ use Random\RandomException;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/nextint_error.phpt
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/nextInt_64_engine_on_32_platform.phpt
*/
class NextIntErrorTest extends TestCase
class NextInt64EngineOn32PlatformTest extends TestCase
{
public function testNextIntError(): void
{

View File

@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestShaEngine;
use PHPUnit\Framework\TestCase;
use Random\Engine\Mt19937;
use Random\Engine\PcgOneseq128XslRr64;
use Random\Engine\Secure;
use Random\Engine\Xoshiro256StarStar;
use Random\RandomException;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/nextInt.phpt
*/
class NextIntTest extends TestCase
{
public function testGetInt(): void
{
$engines = [];
$engines[] = new Mt19937(null, \MT_RAND_MT19937);
$engines[] = new Mt19937(null, \MT_RAND_PHP);
$engines[] = new PcgOneseq128XslRr64();
$engines[] = new Xoshiro256StarStar();
$engines[] = new Secure();
$engines[] = new TestShaEngine();
foreach ($engines as $engine) {
$randomizer = new Randomizer($engine);
try {
self::assertIsInt($randomizer->nextInt());
} catch (RandomException $e) {
self::assertEquals(4, \PHP_INT_SIZE); // can only happen with 32 bit
self::assertEquals('Generated value exceeds size of int', $e->getMessage());
}
}
}
}

View File

@ -2,7 +2,7 @@
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer;
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use PHPUnit\Framework\TestCase;
use Random\Randomizer;
@ -11,7 +11,7 @@ use Throwable;
use ValueError;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/pick_array_keys_error.phpt
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/pickArrayKeys_error.phpt
*/
class PickArrayKeysErrorTest extends TestCase
{

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestShaEngine;
use PHPUnit\Framework\TestCase;
use Random\Engine\Mt19937;
use Random\Engine\PcgOneseq128XslRr64;
use Random\Engine\Secure;
use Random\Engine\Xoshiro256StarStar;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/pickArrayKeys.phpt
*/
class PickArrayKeysTest extends TestCase
{
public function testPickArrayKeys(): void
{
$engines = [];
$engines[] = new Mt19937(null, \MT_RAND_MT19937);
$engines[] = new Mt19937(null, \MT_RAND_PHP);
$engines[] = new PcgOneseq128XslRr64();
$engines[] = new Xoshiro256StarStar();
$engines[] = new Secure();
$engines[] = new TestShaEngine();
$array1 = []; // list
$array2 = []; // associative array with only strings
$array3 = []; // mixed key array
for ($i = 0; $i < 500; $i++) {
$string = \sha1((string)$i);
$array1[] = $i;
$array2[$string] = $i;
$array3[$string] = $i;
$array3[$i] = $string;
}
foreach ($engines as $engine) {
$randomizer = new Randomizer($engine);
for ($i = 1; $i < 100; $i++) {
$result = @$randomizer->pickArrayKeys($array1, $i);
self::assertEquals($result, \array_unique($result)); // no duplicates
self::assertEmpty(\array_diff($result, \array_keys($array1))); // no non-keys returned
$result = @$randomizer->pickArrayKeys($array2, $i);
self::assertEquals($result, \array_unique($result)); // no duplicates
self::assertEmpty(\array_diff($result, \array_keys($array2))); // no non-keys returned
$result = @$randomizer->pickArrayKeys($array3, $i);
self::assertEquals($result, \array_unique($result)); // no duplicates
self::assertEmpty(\array_diff($result, \array_keys($array3))); // no non-keys returned
}
}
}
}

View File

@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestShaEngine;
use PHPUnit\Framework\TestCase;
use Random\Engine\Mt19937;
use Random\Engine\PcgOneseq128XslRr64;
use Random\Engine\Secure;
use Random\Engine\Xoshiro256StarStar;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/shuffleArray.phpt
*/
class ShuffleArrayTest extends TestCase
{
public function testShuffleArray(): void
{
$engines = [];
$engines[] = new Mt19937(null, \MT_RAND_MT19937);
$engines[] = new Mt19937(null, \MT_RAND_PHP);
$engines[] = new PcgOneseq128XslRr64();
$engines[] = new Xoshiro256StarStar();
$engines[] = new Secure();
$engines[] = new TestShaEngine();
foreach ($engines as $engine) {
$randomizer = new Randomizer($engine);
// This test is slow, test all numbers smaller than 50 and then in steps of 677 (which is prime).
for ($i = 1; $i < 5000; $i += ($i < 50 ? 1 : 677)) {
$array = \range(1, $i);
$result = $randomizer->shuffleArray($array);
\sort($result);
self::assertEquals($array, $result); // is a permutation
}
}
}
}

View File

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer\Methods;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestShaEngine;
use PHPUnit\Framework\TestCase;
use Random\Engine\Mt19937;
use Random\Engine\PcgOneseq128XslRr64;
use Random\Engine\Secure;
use Random\Engine\Xoshiro256StarStar;
use Random\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/methods/shuffleBytes.phpt
*/
class ShuffleBytesTest extends TestCase
{
private function sortBytes(string $bytes): string
{
$bytes = \str_split($bytes);
\sort($bytes);
return \implode('', $bytes);
}
public function testShuffleBytes(): void
{
$engines = [];
$engines[] = new Mt19937(null, \MT_RAND_MT19937);
$engines[] = new Mt19937(null, \MT_RAND_PHP);
$engines[] = new PcgOneseq128XslRr64();
$engines[] = new Xoshiro256StarStar();
$engines[] = new Secure();
$engines[] = new TestShaEngine();
foreach ($engines as $engine) {
$randomizer = new Randomizer($engine);
// This test is slow, test all numbers smaller than 50 and then in steps of 677 (which is prime).
for ($i = 1; $i < 5000; $i += ($i < 50 ? 1 : 677)) {
$bytes = self::sortBytes(\random_bytes($i));
$result = $randomizer->shuffleBytes($bytes);
$result = self::sortBytes($result);
self::assertEquals($bytes, $result); // is a permutation
}
}
}
}

View File

@ -1,13 +0,0 @@
<?php
declare(strict_types=1);
namespace Arokettu\Random\Tests\FromPHP\Randomizer;
/**
* @see https://github.com/php/php-src/blob/master/ext/random/tests/03_randomizer/pick_array_keys.phpt
*/
class PickArrayKeysTest
{
// skip, known incompatibility
}

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Arokettu\Random\Tests;
use Arokettu\Random\Tests\DevEngines\TestXoshiro128PlusPlusEngine;
use Arokettu\Random\Tests\DevEngines\FromPHP\TestXoshiro128PlusPlusEngine;
use PHPUnit\Framework\TestCase;
/**