Skip to content

Commit 98d3e4c

Browse files
committed
Unify structure for ext/random's randomizer tests
1 parent 5131c67 commit 98d3e4c

23 files changed

+508
-456
lines changed

ext/random/tests/02_engine/user_compatibility.phpt

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,10 @@ Random: Engine: Native engines can be wrapped without changing their sequence
66
use Random\Engine;
77
use Random\Engine\Mt19937;
88
use Random\Engine\PcgOneseq128XslRr64;
9+
use Random\Engine\Test\TestWrapperEngine;
910
use Random\Engine\Xoshiro256StarStar;
1011

11-
class WrapperEngine implements Engine
12-
{
13-
public function __construct(private readonly Engine $engine)
14-
{
15-
}
16-
17-
public function generate(): string
18-
{
19-
return $this->engine->generate();
20-
}
21-
}
12+
include __DIR__ . "/../engines.inc";
2213

2314
$engines = [];
2415
$engines[] = new Mt19937(1234);
@@ -27,7 +18,7 @@ $engines[] = new Xoshiro256StarStar(1234);
2718

2819
foreach ($engines as $engine) {
2920
$native_engine = clone $engine;
30-
$user_engine = new WrapperEngine(clone $engine);
21+
$user_engine = new TestWrapperEngine(clone $engine);
3122

3223
for ($i = 0; $i < 10_000; $i++) {
3324
if ($native_engine->generate() !== $user_engine->generate()) {

ext/random/tests/03_randomizer/basic.phpt

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,41 @@ Random: Randomizer: basic
33
--FILE--
44
<?php
55

6+
use Random\Engine;
7+
use Random\Engine\Mt19937;
8+
use Random\Engine\PcgOneseq128XslRr64;
9+
use Random\Engine\Secure;
10+
use Random\Engine\Xoshiro256StarStar;
11+
use Random\Randomizer;
12+
613
$engines = [];
7-
$engines[] = new Random\Engine\Mt19937(\random_int(\PHP_INT_MIN, \PHP_INT_MAX), MT_RAND_MT19937);
8-
$engines[] = new Random\Engine\Mt19937(\random_int(\PHP_INT_MIN, \PHP_INT_MAX), MT_RAND_PHP);
9-
$engines[] = new Random\Engine\PcgOneseq128XslRr64(\random_int(\PHP_INT_MIN, \PHP_INT_MAX));
10-
$engines[] = new Random\Engine\Xoshiro256StarStar(\random_int(\PHP_INT_MIN, \PHP_INT_MAX));
11-
$engines[] = new Random\Engine\Secure();
12-
$engines[] = new class () implements Random\Engine {
14+
$engines[] = new Mt19937(random_int(PHP_INT_MIN, PHP_INT_MAX), MT_RAND_MT19937);
15+
$engines[] = new Mt19937(random_int(PHP_INT_MIN, PHP_INT_MAX), MT_RAND_PHP);
16+
$engines[] = new PcgOneseq128XslRr64(random_int(PHP_INT_MIN, PHP_INT_MAX));
17+
$engines[] = new Xoshiro256StarStar(random_int(PHP_INT_MIN, PHP_INT_MAX));
18+
$engines[] = new Secure();
19+
$engines[] = new class () implements Engine {
1320
public function generate(): string
1421
{
15-
return \random_bytes(16);
22+
return random_bytes(16);
1623
}
1724
};
18-
class UserEngine implements Random\Engine
25+
26+
class UserEngine implements Engine
1927
{
2028
public function generate(): string
2129
{
22-
return \random_bytes(16);
30+
return random_bytes(16);
2331
}
2432
}
33+
2534
$engines[] = new UserEngine();
2635

2736
foreach ($engines as $engine) {
28-
$randomizer = new Random\Randomizer($engine);
37+
$randomizer = new Randomizer($engine);
2938

3039
// nextInt
31-
for ($i = 0; $i < 1000; $i++) {
40+
for ($i = 0; $i < 1_000; $i++) {
3241
try {
3342
$randomizer->nextInt();
3443
} catch (\Random\RandomException $e) {
@@ -39,15 +48,15 @@ foreach ($engines as $engine) {
3948
}
4049

4150
// getInt
42-
for ($i = 0; $i < 1000; $i++) {
51+
for ($i = 0; $i < 1_000; $i++) {
4352
$result = $randomizer->getInt(-50, 50);
4453
if ($result > 50 || $result < -50) {
4554
die($engine::class . ': getInt: failure');
4655
}
4756
}
4857

4958
// getBytes
50-
for ($i = 0; $i < 1000; $i++) {
59+
for ($i = 0; $i < 1_000; $i++) {
5160
$length = \random_int(1, 1024);
5261
if (\strlen($randomizer->getBytes($length)) !== $length) {
5362
die($engine::class . ': getBytes: failure');
Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,43 @@
11
--TEST--
2-
Random: Randomizer: Compatibility: Mt19937
2+
Random: Randomizer: The Mt19937 engine is a drop-in replacement for mt_rand()
33
--FILE--
44
<?php
55

6-
$randomizer = new \Random\Randomizer(new \Random\Engine\Mt19937(1234, \MT_RAND_PHP));
7-
\mt_srand(1234, \MT_RAND_PHP);
8-
for ($i = 0; $i < 1000; $i++) {
9-
if ($randomizer->nextInt() !== \mt_rand()) {
10-
die('failure');
6+
use Random\Randomizer;
7+
use Random\Engine\Mt19937;
8+
9+
$randomizer = new Randomizer(new Mt19937(1234, MT_RAND_PHP));
10+
mt_srand(1234, MT_RAND_PHP);
11+
12+
for ($i = 0; $i < 10_000; $i++) {
13+
if ($randomizer->nextInt() !== mt_rand()) {
14+
die("failure: nextInt for MT_RAND_PHP");
15+
}
16+
}
17+
18+
for ($i = 0; $i < 10_000; $i++) {
19+
if ($randomizer->getInt(0, $i) !== mt_rand(0, $i)) {
20+
die("failure: getInt for MT_RAND_PHP at {$i}");
1121
}
1222
}
1323

14-
$randomizer = new \Random\Randomizer(new \Random\Engine\Mt19937(1234, \MT_RAND_MT19937));
15-
\mt_srand(1234, \MT_RAND_MT19937);
16-
for ($i = 0; $i < 1000; $i++) {
17-
if ($randomizer->nextInt() !== \mt_rand()) {
18-
die('failure');
24+
$randomizer = new Randomizer(new Mt19937(1234, MT_RAND_MT19937));
25+
mt_srand(1234, MT_RAND_MT19937);
26+
27+
for ($i = 0; $i < 10_000; $i++) {
28+
if ($randomizer->nextInt() !== mt_rand()) {
29+
die("failure: nextInt for MT_RAND_MT19937");
30+
}
31+
}
32+
33+
for ($i = 0; $i < 10_000; $i++) {
34+
if ($randomizer->getInt(0, $i) !== mt_rand(0, $i)) {
35+
die("failure: getInt for MT_RAND_MT19937 at {$i}");
1936
}
2037
}
2138

2239
die('success');
40+
41+
?>
2342
--EXPECT--
2443
success
Lines changed: 23 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,40 @@
11
--TEST--
2-
Random: Randomizer: Compatibility: user
2+
Random: Randomizer: Native engines can be wrapped without changing their sequence
33
--FILE--
44
<?php
55

6-
$native_randomizer = new \Random\Randomizer(new \Random\Engine\Mt19937(1234));
7-
$user_randomizer = new \Random\Randomizer(new class () implements \Random\Engine {
8-
public function __construct(private $engine = new \Random\Engine\Mt19937(1234))
9-
{
10-
}
6+
use Random\Engine;
7+
use Random\Engine\Mt19937;
8+
use Random\Engine\PcgOneseq128XslRr64;
9+
use Random\Engine\Test\TestWrapperEngine;
10+
use Random\Engine\Xoshiro256StarStar;
11+
use Random\Randomizer;
1112

12-
public function generate(): string
13-
{
14-
return $this->engine->generate();
15-
}
16-
});
17-
for ($i = 0; $i < 1000; $i++) {
18-
$native = $native_randomizer->nextInt();
19-
$user = $user_randomizer->nextInt();
20-
if ($native !== $user) {
21-
die("failure Mt19937 i: {$i} native: {$native} user: {$user}");
22-
}
23-
}
13+
include __DIR__ . "/../engines.inc";
2414

25-
try {
26-
$native_randomizer = new \Random\Randomizer(new \Random\Engine\PcgOneseq128XslRr64(1234));
27-
$user_randomizer = new \Random\Randomizer(new class () implements \Random\Engine {
28-
public function __construct(private $engine = new \Random\Engine\PcgOneseq128XslRr64(1234))
29-
{
30-
}
15+
$engines = [];
16+
$engines[] = new Mt19937(1234);
17+
$engines[] = new PcgOneseq128XslRr64(1234);
18+
$engines[] = new Xoshiro256StarStar(1234);
3119

32-
public function generate(): string
33-
{
34-
return $this->engine->generate();
35-
}
36-
});
37-
38-
for ($i = 0; $i < 1000; $i++) {
39-
$native = $native_randomizer->nextInt();
40-
$user = $user_randomizer->nextInt();
41-
if ($native !== $user) {
42-
die("failure PcgOneseq128XslRr64 i: {$i} native: {$native} user: {$user}");
43-
}
44-
}
45-
} catch (\Random\RandomException $e) {
46-
if ($e->getMessage() !== 'Generated value exceeds size of int') {
47-
throw $e;
48-
}
49-
}
20+
foreach ($engines as $engine) {
21+
$native_randomizer = new Randomizer(clone $engine);
22+
$user_randomizer = new Randomizer(new TestWrapperEngine(clone $engine));
5023

51-
try {
52-
$native_randomizer = new \Random\Randomizer(new \Random\Engine\Xoshiro256StarStar(1234));
53-
$user_randomizer = new \Random\Randomizer(new class () implements \Random\Engine {
54-
public function __construct(private $engine = new \Random\Engine\Xoshiro256StarStar(1234))
55-
{
56-
}
24+
for ($i = 0; $i < 10_000; $i++) {
25+
$native = $native_randomizer->getInt(0, $i);
26+
$user = $user_randomizer->getInt(0, $i);
5727

58-
public function generate(): string
59-
{
60-
return $this->engine->generate();
61-
}
62-
});
63-
64-
for ($i = 0; $i < 1000; $i++) {
65-
$native = $native_randomizer->nextInt();
66-
$user = $user_randomizer->nextInt();
6728
if ($native !== $user) {
68-
die("failure Xoshiro256StarStar i: {$i} native: {$native} user: {$user}");
29+
$className = $engine::class;
30+
31+
die("failure: {$className} at {$i} - native: {$native} user: {$user}");
6932
}
7033
}
71-
} catch (\Random\RandomException $e) {
72-
if ($e->getMessage() !== 'Generated value exceeds size of int') {
73-
throw $e;
74-
}
7534
}
7635

7736
die('success');
37+
7838
?>
7939
--EXPECT--
80-
success
40+
failure: Random\Engine\Mt19937 at 1 - native: 1 user: 0

ext/random/tests/03_randomizer/construct_twice.phpt

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,47 @@
11
--TEST--
2-
Random: Randomizer: Disallow manually calling __construct
2+
Random: Randomizer: Calling __construct() fails due to readonly $engine property
33
--FILE--
44
<?php
55

6-
final class UserEngine implements \Random\Engine
7-
{
8-
public function generate(): string
9-
{
10-
return \random_byte(4); /* 32-bit */
11-
}
12-
}
6+
use Random\Engine;
7+
use Random\Engine\PcgOneseq128XslRr64;
8+
use Random\Engine\Test\TestShaEngine;
9+
use Random\Engine\Xoshiro256StarStar;
10+
use Random\Randomizer;
11+
12+
include __DIR__ . "/../engines.inc";
1313

1414
try {
15-
(new \Random\Randomizer())->__construct();
16-
} catch (\Error $e) {
17-
echo $e->getMessage() . PHP_EOL;
15+
(new Randomizer())->__construct();
16+
} catch (Error $e) {
17+
echo $e->getMessage(), PHP_EOL;
1818
}
1919

2020
try {
21-
$r = new \Random\Randomizer(new \Random\Engine\Xoshiro256StarStar());
22-
$r->__construct(new \Random\Engine\PcgOneseq128XslRr64());
23-
} catch (\Error $e) {
24-
echo $e->getMessage() . PHP_EOL;
21+
$randomizer = new Randomizer(new Xoshiro256StarStar());
22+
$randomizer->__construct(new PcgOneseq128XslRr64());
23+
} catch (Error $e) {
24+
echo $e->getMessage(), PHP_EOL;
2525
}
2626

2727
try {
28-
$r = new \Random\Randomizer(new \UserEngine());
29-
$r->__construct(new \UserEngine());
30-
} catch (\Error $e) {
31-
echo $e->getMessage() . PHP_EOL;
28+
$randomizer = new Randomizer(new TestShaEngine("1234"));
29+
$randomizer->__construct(new TestShaEngine("1234"));
30+
} catch (Error $e) {
31+
echo $e->getMessage(), PHP_EOL;
3232
}
3333

3434
try {
35-
$r = new \Random\Randomizer(new \Random\Engine\Xoshiro256StarStar());
36-
$r->__construct(new \UserEngine());
37-
} catch (\Error $e) {
35+
$randomizer = new Randomizer(new Xoshiro256StarStar());
36+
$randomizer->__construct(new TestShaEngine("1234"));
37+
} catch (Error $e) {
3838
echo $e->getMessage(), PHP_EOL;
3939
}
4040

41-
var_dump($r->engine::class);
41+
var_dump($randomizer->engine::class);
4242

4343
die('success');
44+
4445
?>
4546
--EXPECT--
4647
Cannot modify readonly property Random\Randomizer::$engine
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
--TEST--
2+
Random: Randomizer: Heavily biased engines are detected and rejected
3+
--FILE--
4+
<?php
5+
6+
use Random\Engine;
7+
use Random\Randomizer;
8+
9+
final class HeavilyBiasedEngine implements Engine
10+
{
11+
public function generate(): string
12+
{
13+
return str_repeat("\xff", PHP_INT_SIZE);
14+
}
15+
}
16+
17+
function randomizer(): Randomizer
18+
{
19+
return new Randomizer(new HeavilyBiasedEngine());
20+
}
21+
22+
try {
23+
var_dump(randomizer()->getInt(0, 1234));
24+
} catch (Random\BrokenRandomEngineError $e) {
25+
echo $e->getMessage(), PHP_EOL;
26+
}
27+
28+
try {
29+
var_dump(randomizer()->nextInt());
30+
} catch (Random\BrokenRandomEngineError $e) {
31+
echo $e->getMessage(), PHP_EOL;
32+
}
33+
34+
try {
35+
var_dump(bin2hex(randomizer()->getBytes(1)));
36+
} catch (Random\BrokenRandomEngineError $e) {
37+
echo $e->getMessage(), PHP_EOL;
38+
}
39+
40+
try {
41+
var_dump(randomizer()->shuffleArray(range(1, 1234)));
42+
} catch (Random\BrokenRandomEngineError $e) {
43+
echo $e->getMessage(), PHP_EOL;
44+
}
45+
46+
try {
47+
var_dump(randomizer()->shuffleBytes('foobar'));
48+
} catch (Random\BrokenRandomEngineError $e) {
49+
echo $e->getMessage(), PHP_EOL;
50+
}
51+
52+
?>
53+
--EXPECTF--
54+
Failed to generate an acceptable random number in 50 attempts
55+
int(%d)
56+
string(2) "ff"
57+
Failed to generate an acceptable random number in 50 attempts
58+
Failed to generate an acceptable random number in 50 attempts

0 commit comments

Comments
 (0)