forked from fzaninotto/Faker
-
Notifications
You must be signed in to change notification settings - Fork 348
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enhancement: Implement MersenneTwisterIntegerGenerator
- Loading branch information
1 parent
6eda5c1
commit 6849a57
Showing
4 changed files
with
189 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Faker\Generator; | ||
|
||
/** | ||
* @experimental | ||
*/ | ||
interface IntegerGenerator | ||
{ | ||
/** | ||
* Returns an integer. | ||
*/ | ||
public function integer(): int; | ||
|
||
/** | ||
* Returns an integer that is between minimum and maximum (inclusive). | ||
* | ||
* @throws \InvalidArgumentException | ||
*/ | ||
public function integerBetween(int $minimum, int $maximum): int; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Faker\Generator; | ||
|
||
/** | ||
* @experimental | ||
*/ | ||
final class MersenneTwisterIntegerGenerator implements SeedableIntegerGenerator | ||
{ | ||
public function integer(): int | ||
{ | ||
return mt_rand(); | ||
} | ||
|
||
public function integerBetween(int $minimum, int $maximum): int | ||
{ | ||
if ($minimum > $maximum) { | ||
throw new \InvalidArgumentException(sprintf( | ||
'Minimum value %d should not be greater than the maximum value %d.', | ||
$minimum, | ||
$maximum, | ||
)); | ||
} | ||
|
||
$largestInteger = mt_getrandmax(); | ||
|
||
if ($maximum > $largestInteger) { | ||
throw new \InvalidArgumentException(sprintf( | ||
'Maximum value %d should not be greater than %d.', | ||
$maximum, | ||
$largestInteger, | ||
)); | ||
} | ||
|
||
return mt_rand($minimum, $maximum); | ||
} | ||
|
||
public function seed(int $value): void | ||
{ | ||
mt_srand($value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Faker\Generator; | ||
|
||
/** | ||
* @experimental | ||
*/ | ||
interface SeedableIntegerGenerator extends IntegerGenerator | ||
{ | ||
/** | ||
* Seeds the number generator. | ||
*/ | ||
public function seed(int $value): void; | ||
} |
106 changes: 106 additions & 0 deletions
106
test/Faker/Generator/MersenneTwisterIntegerGeneratorTest.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace Faker\Test\Generator; | ||
|
||
use Faker\Generator; | ||
use PHPUnit\Framework; | ||
|
||
/** | ||
* @covers \Faker\Generator\MersenneTwisterIntegerGenerator | ||
*/ | ||
final class MersenneTwisterIntegerGeneratorTest extends Framework\TestCase | ||
{ | ||
public function testIntegerBetweenReturnsIntegerBetweenMinAndMax(): void | ||
{ | ||
$min = 3; | ||
$max = 1000; | ||
|
||
$generator = new Generator\MersenneTwisterIntegerGenerator(); | ||
|
||
$values = self::generateValues( | ||
static function () use ($generator, $min, $max): int { | ||
return $generator->integerBetween( | ||
$min, | ||
$max, | ||
); | ||
}, | ||
100, | ||
); | ||
|
||
self::assertValuesSatisfySpecification( | ||
static function (int $value) use ($min, $max): bool { | ||
return $value >= $min && $value <= $max; | ||
}, | ||
$values, | ||
); | ||
} | ||
|
||
public function testSeedSeedsIntegerGenerator(): void | ||
{ | ||
$value = 9001; | ||
|
||
$generator = new Generator\MersenneTwisterIntegerGenerator(); | ||
|
||
$generator->seed($value); | ||
|
||
$first = self::generateValues( | ||
static function () use ($generator): int { | ||
return $generator->integer(); | ||
}, | ||
100, | ||
); | ||
|
||
$generator->seed($value); | ||
|
||
$second = self::generateValues( | ||
static function () use ($generator): int { | ||
return $generator->integer(); | ||
}, | ||
100, | ||
); | ||
|
||
self::assertSame($first, $second); | ||
} | ||
|
||
/** | ||
* @param \Closure(): mixed $generator | ||
* | ||
* @throws \InvalidArgumentException | ||
* | ||
* @return list<mixed> | ||
*/ | ||
private static function generateValues( | ||
\Closure $generator, | ||
int $count | ||
): array { | ||
if ($count < 1) { | ||
throw new \InvalidArgumentException(sprintf( | ||
'Count needs to be greater than 0, got %d instead', | ||
$count, | ||
)); | ||
} | ||
|
||
return array_map(static function () use ($generator) { | ||
return $generator(); | ||
}, range(0, $count - 1)); | ||
} | ||
|
||
/** | ||
* @param \Closure(mixed):bool $specification | ||
* @param list<mixed> $values | ||
* | ||
* @throws \InvalidArgumentException | ||
*/ | ||
private static function assertValuesSatisfySpecification( | ||
\Closure $specification, | ||
array $values | ||
): void { | ||
$invalidValues = array_filter($values, static function ($value) use ($specification): bool { | ||
return $specification($value) === false; | ||
}); | ||
|
||
self::assertCount(0, $invalidValues, 'Failed asserting that all generated values satisfy the specification.'); | ||
} | ||
} |