packages/sql-faker/tests/Unit/Generation/Value/IntegerDomainTest.php
1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\Generation\Value;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFaker\Generation\Value\CharacterDomain;
12use SqlFaker\Generation\Value\ChoiceDomain;
13use SqlFaker\Generation\Value\IntegerDomain;
14use SqlFaker\Generation\Value\SequenceDomain;
15use SqlFaker\Generation\Value\ValueChoices;
16use SqlFaker\Generation\Value\ValueDomain;
17
18#[CoversClass(IntegerDomain::class)]
19#[UsesClass(CharacterDomain::class)]
20#[UsesClass(SequenceDomain::class)]
21#[UsesClass(ChoiceDomain::class)]
22#[UsesClass(ValueChoices::class)]
23#[UsesClass(ValueDomain::class)]
24final class IntegerDomainTest extends TestCase
25{
26 #[DataProvider('providerBounds')]
27 public function testChooseReachesBothBoundsWithoutEnumeratingTheDomain(string $minimum, string $maximum): void
28 {
29 $domain = new IntegerDomain($minimum, $maximum);
30 $visits = 0;
31 $last = $domain->choose(static function (int $count) use (&$visits): int {
32 ++$visits;
33 return $count - 1;
34 });
35 self::assertSame($minimum, $domain->choose(static fn (int $count): int => 0));
36 self::assertSame(str_repeat('0', 16) . $maximum, $last);
37 self::assertLessThanOrEqual(strlen($maximum) + 2, $visits);
38 }
39
40 public function testChooseReachesAnInteriorValueAndCanForbidPadding(): void
41 {
42 $decisions = [1, 3, 2, 0];
43 self::assertSame('42', (new IntegerDomain('0', '99', 0))->choose(static function (int $count) use (&$decisions): int {
44 return array_shift($decisions) ?? 0;
45 }));
46 }
47
48 /**
49 * @return iterable<array{string, string}>
50 */
51 public static function providerBounds(): iterable
52 {
53 yield ['0', '0'];
54 yield ['0', '2147483647'];
55 yield ['2147483648', '9223372036854775807'];
56 yield ['9223372036854775808', '18446744073709551615'];
57 yield ['99', '101'];
58 }
59
60 public function testMatchChecksMagnitudeWhilePreservingLeadingZeroesAndSeparators(): void
61 {
62 $domain = new IntegerDomain('10', '20', digitSeparators: true);
63 self::assertSame([5], $domain->match('00020!'));
64 self::assertSame([3], $domain->match('1_0'));
65 self::assertSame([], $domain->match('1__0'));
66 self::assertNotContains(3, $domain->match('20_'));
67 self::assertSame([], $domain->match('-10'));
68 self::assertSame([], $domain->match('21'));
69 self::assertContains(70, (new IntegerDomain('0', null))->match(str_repeat('9', 70)));
70 }
71
72 public function testNormalizedRecognizesCanonicalDeclarationBounds(): void
73 {
74 $domain = new IntegerDomain('0', '10');
75 self::assertTrue($domain->normalized('0'));
76 self::assertTrue($domain->normalized('18446744073709551615'));
77 self::assertFalse($domain->normalized('00'));
78 self::assertFalse($domain->normalized(''));
79 self::assertFalse($domain->normalized('1x'));
80 }
81
82 public function testCompareOrdersMagnitudesWithoutMachineIntegerConversion(): void
83 {
84 $domain = new IntegerDomain('0', '10');
85 self::assertLessThan(0, $domain->compare('9', '10'));
86 self::assertSame(0, $domain->compare('10', '10'));
87 self::assertGreaterThan(0, $domain->compare('18446744073709551615', '18446744073709551614'));
88 }
89
90 public function testChooseSamplesUpToSixtyFiveDigitsWhenNoMaximumIsDeclared(): void
91 {
92 self::assertSame(str_repeat('0', 16) . str_repeat('9', 65), (new IntegerDomain('0', null))->choose(static fn (int $count): int => $count - 1));
93 }
94
95 public function testChooseCompletesDigitsBeyondTheMaximumPrefixUpToNine(): void
96 {
97 $decisions = [1, 0];
98 self::assertSame('19', (new IntegerDomain('0', '99', 0))->choose(static function (int $count) use (&$decisions): int {
99 return array_shift($decisions) ?? $count - 1;
100 }));
101 }
102
103 public function testChooseAllowsTheLargestPaddingChoice(): void
104 {
105 self::assertSame(str_repeat('0', 1024) . '5', (new IntegerDomain('5', '5', 1024))->choose(static fn (int $count): int => $count - 1));
106 }
107
108 public function testMatchReadsSeparatorsOnlyWhenTheScannerAcceptsThem(): void
109 {
110 self::assertSame([], (new IntegerDomain('10', '20'))->match('1_0'));
111 }
112}
113