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