Skip to content

Commit 4d0315c

Browse files
krsriqlocalheinz
andauthored
[Core] Added number extension (#257)
* add number extension * Apply suggestions from code review Co-authored-by: Andreas Möller <[email protected]> * removed docblock * add method type declaration * remove method argument type check * rename arguments * add docblocks to generator methods * renamed randomDigitNotNull Co-authored-by: Andreas Möller <[email protected]>
1 parent 9328e44 commit 4d0315c

File tree

5 files changed

+285
-3
lines changed

5 files changed

+285
-3
lines changed

src/Faker/Core/Number.php

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Faker\Core;
6+
7+
use Faker\Extension;
8+
9+
/**
10+
* @experimental This class is experimental and does not fall under our BC promise
11+
*/
12+
final class Number implements Extension\NumberExtension
13+
{
14+
public function numberBetween(int $min = 0, int $max = 2147483647): int
15+
{
16+
$int1 = $min < $max ? $min : $max;
17+
$int2 = $min < $max ? $max : $min;
18+
19+
return mt_rand($int1, $int2);
20+
}
21+
22+
public function randomDigit(): int
23+
{
24+
return mt_rand(0, 9);
25+
}
26+
27+
public function randomDigitNot(int $except): int
28+
{
29+
$result = self::numberBetween(0, 8);
30+
31+
if ($result >= $except) {
32+
++$result;
33+
}
34+
35+
return $result;
36+
}
37+
38+
public function randomDigitNotZero(): int
39+
{
40+
return mt_rand(1, 9);
41+
}
42+
43+
public function randomFloat(int $nbMaxDecimals = null, float $min = 0, float $max = null): float
44+
{
45+
if (null === $nbMaxDecimals) {
46+
$nbMaxDecimals = $this->randomDigit();
47+
}
48+
49+
if (null === $max) {
50+
$max = $this->randomNumber();
51+
52+
if ($min > $max) {
53+
$max = $min;
54+
}
55+
}
56+
57+
if ($min > $max) {
58+
$tmp = $min;
59+
$min = $max;
60+
$max = $tmp;
61+
}
62+
63+
return round($min + mt_rand() / mt_getrandmax() * ($max - $min), $nbMaxDecimals);
64+
}
65+
66+
public function randomNumber(int $nbDigits = null, bool $strict = false): int
67+
{
68+
if (null === $nbDigits) {
69+
$nbDigits = $this->randomDigitNotZero();
70+
}
71+
$max = 10 ** $nbDigits - 1;
72+
73+
if ($max > mt_getrandmax()) {
74+
throw new \InvalidArgumentException('randomNumber() can only generate numbers up to mt_getrandmax()');
75+
}
76+
77+
if ($strict) {
78+
return mt_rand(10 ** ($nbDigits - 1), $max);
79+
}
80+
81+
return mt_rand(0, $max);
82+
}
83+
}

src/Faker/Extension/ContainerBuilder.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public static function defaultExtensions(): array
6464
BarcodeExtension::class => Core\Barcode::class,
6565
BloodExtension::class => Core\Blood::class,
6666
FileExtension::class => Core\File::class,
67+
NumberExtension::class => Core\Number::class,
6768
];
6869
}
6970

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
namespace Faker\Extension;
4+
5+
/**
6+
* @experimental This interface is experimental and does not fall under our BC promise
7+
*/
8+
interface NumberExtension extends Extension
9+
{
10+
/**
11+
* Returns a random number between $int1 and $int2 (any order)
12+
*
13+
* @param int $min default to 0
14+
* @param int $max defaults to 32 bit max integer, ie 2147483647
15+
*
16+
* @example 79907610
17+
*/
18+
public function numberBetween(int $min, int $max): int;
19+
20+
/**
21+
* Returns a random number between 0 and 9
22+
*/
23+
public function randomDigit(): int;
24+
25+
/**
26+
* Generates a random digit, which cannot be $except
27+
*/
28+
public function randomDigitNot(int $except): int;
29+
30+
/**
31+
* Returns a random number between 1 and 9
32+
*/
33+
public function randomDigitNotZero(): int;
34+
35+
/**
36+
* Return a random float number
37+
*
38+
* @example 48.8932
39+
*/
40+
public function randomFloat(?int $nbMaxDecimals, float $min, float $max): float;
41+
42+
/**
43+
* Returns a random integer with 0 to $nbDigits digits.
44+
*
45+
* The maximum value returned is mt_getrandmax()
46+
*
47+
* @param int|null $nbDigits Defaults to a random number between 1 and 9
48+
* @param bool $strict Whether the returned number should have exactly $nbDigits
49+
*
50+
* @example 79907610
51+
*/
52+
public function randomNumber(?int $nbDigits, bool $strict): int;
53+
}

src/Faker/Generator.php

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,10 +166,7 @@
166166
* @property string $randomLetter
167167
* @property string $randomAscii
168168
*
169-
* @method int randomNumber($nbDigits = null, $strict = false)
170169
* @method int|string|null randomKey(array $array = array())
171-
* @method int numberBetween($min = 0, $max = 2147483647)
172-
* @method float randomFloat($nbMaxDecimals = null, $min = 0, $max = null)
173170
* @method mixed randomElement(array $array = array('a', 'b', 'c'))
174171
* @method array randomElements(array $array = array('a', 'b', 'c'), $count = 1, $allowDuplicates = false)
175172
* @method array|string shuffle($arg = '')
@@ -365,6 +362,65 @@ public function isbn13(): string
365362
return $this->ext(Extension\BarcodeExtension::class)->isbn13();
366363
}
367364

365+
/**
366+
* Returns a random number between $int1 and $int2 (any order)
367+
*
368+
* @example 79907610
369+
*/
370+
public function numberBetween($int1 = 0, $int2 = 2147483647): int
371+
{
372+
return $this->ext(Extension\NumberExtension::class)->numberBetween((int) $int1, (int) $int2);
373+
}
374+
375+
/**
376+
* Returns a random number between 0 and 9
377+
*/
378+
public function randomDigit(): int
379+
{
380+
return $this->ext(Extension\NumberExtension::class)->randomDigit();
381+
}
382+
383+
/**
384+
* Generates a random digit, which cannot be $except
385+
*/
386+
public function randomDigitNot($except): int
387+
{
388+
return $this->ext(Extension\NumberExtension::class)->randomDigitNot((int) $except);
389+
}
390+
391+
/**
392+
* Returns a random number between 1 and 9
393+
*/
394+
public function randomDigitNotZero(): int
395+
{
396+
return $this->ext(Extension\NumberExtension::class)->randomDigitNotZero();
397+
}
398+
399+
/**
400+
* Return a random float number
401+
*
402+
* @example 48.8932
403+
*/
404+
public function randomFloat($nbMaxDecimals = null, $min = 0, $max = null): float
405+
{
406+
return $this->ext(Extension\NumberExtension::class)->randomFloat((int) $nbMaxDecimals, (float) $min, (float) $max);
407+
}
408+
409+
/**
410+
* Returns a random integer with 0 to $nbDigits digits.
411+
*
412+
* The maximum value returned is mt_getrandmax()
413+
*
414+
* @param int|null $nbDigits Defaults to a random number between 1 and 9
415+
* @param bool $strict Whether the returned number should have exactly $nbDigits
416+
*
417+
* @example 79907610
418+
*/
419+
public function randomNumber($nbDigits = null, $strict = false): int
420+
{
421+
return $this->ext(Extension\NumberExtension::class)->randomNumber((int) $nbDigits, (bool) $strict);
422+
}
423+
368424
protected function callFormatWithMatches($matches)
369425
{
370426
return $this->format($matches[1]);

test/Faker/Core/NumberTest.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Faker\Test\Core;
6+
7+
use Faker\Test\TestCase;
8+
9+
final class NumberTest extends TestCase
10+
{
11+
public function testRandomDigitReturnsInteger()
12+
{
13+
self::assertIsInt($this->faker->randomDigit());
14+
}
15+
16+
public function testRandomDigitReturnsDigit()
17+
{
18+
self::assertGreaterThanOrEqual(0, $this->faker->randomDigit());
19+
self::assertLessThan(10, $this->faker->randomDigit());
20+
}
21+
22+
public function testRandomDigitNotNullReturnsNotNullDigit()
23+
{
24+
self::assertGreaterThan(0, $this->faker->randomDigitNotZero());
25+
self::assertLessThan(10, $this->faker->randomDigitNotZero());
26+
}
27+
28+
public function testRandomDigitNotReturnsValidDigit()
29+
{
30+
for ($i = 0; $i <= 9; ++$i) {
31+
self::assertGreaterThanOrEqual(0, $this->faker->randomDigitNot($i));
32+
self::assertLessThan(10, $this->faker->randomDigitNot($i));
33+
self::assertNotSame($this->faker->randomDigitNot($i), $i);
34+
}
35+
}
36+
37+
public function testRandomNumberThrowsExceptionWhenCalledWithATooHighNumberOfDigits()
38+
{
39+
$this->expectException(\InvalidArgumentException::class);
40+
$this->faker->randomNumber(10);
41+
}
42+
43+
public function testRandomNumberReturnsInteger()
44+
{
45+
self::assertIsInt($this->faker->randomNumber());
46+
self::assertIsInt($this->faker->randomNumber(5, false));
47+
}
48+
49+
public function testRandomNumberReturnsDigit()
50+
{
51+
self::assertGreaterThanOrEqual(0, $this->faker->randomNumber(3));
52+
self::assertLessThan(1000, $this->faker->randomNumber(3));
53+
}
54+
55+
public function testRandomNumberAcceptsStrictParamToEnforceNumberSize()
56+
{
57+
self::assertEquals(5, strlen((string) $this->faker->randomNumber(5, true)));
58+
}
59+
60+
public function testNumberBetween()
61+
{
62+
$min = 5;
63+
$max = 6;
64+
65+
self::assertGreaterThanOrEqual($min, $this->faker->numberBetween($min, $max));
66+
self::assertGreaterThanOrEqual($this->faker->numberBetween($min, $max), $max);
67+
}
68+
69+
public function testNumberBetweenAcceptsZeroAsMax()
70+
{
71+
self::assertEquals(0, $this->faker->numberBetween(0, 0));
72+
}
73+
74+
public function testRandomFloat()
75+
{
76+
$min = 4;
77+
$max = 10;
78+
$nbMaxDecimals = 8;
79+
80+
$result = $this->faker->randomFloat($nbMaxDecimals, $min, $max);
81+
82+
$parts = explode('.', (string) $result);
83+
84+
self::assertIsFloat($result);
85+
self::assertGreaterThanOrEqual($min, $result);
86+
self::assertLessThanOrEqual($max, $result);
87+
self::assertLessThanOrEqual($nbMaxDecimals, strlen($parts[1]));
88+
}
89+
}

0 commit comments

Comments
 (0)