packages/sql-faker/tests/Unit/Sqlite/Generation/Lexeme/JoinModifiersTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\Sqlite\Generation\Lexeme;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\DataProvider;
9use PHPUnit\Framework\Attributes\UsesClass;
10use PHPUnit\Framework\TestCase;
11use SqlFaker\Generation\Exception\LexicalException;
12use SqlFaker\Sqlite\Generation\Lexeme\JoinModifiers;
13
14#[CoversClass(JoinModifiers::class)]
15#[UsesClass(LexicalException::class)]
16final class JoinModifiersTest extends TestCase
17{
18    public function testMaskRecognizesCaseInsensitiveSourceWordsAndFullJoinFlags(): void
19    {
20        $types = new JoinModifiers();
21        self::assertSame($types->mask('LEFT') | $types->mask('RIGHT'), $types->mask('full'));
22        self::assertSame($types->mask('INNER') | 32, $types->mask('CROSS'));
23    }
24
25    public function testMaskReportsAnUnknownSourceRegistration(): void
26    {
27        $this->expectException(LexicalException::class);
28        $this->expectExceptionMessage('Unknown SQLite join modifier: UNREVIEWED');
29        (new JoinModifiers())->mask('UNREVIEWED');
30    }
31
32    public function testValidRejectsInnerOuterConflictsAndNaturalJoinConditions(): void
33    {
34        $types = new JoinModifiers();
35        self::assertFalse($types->valid($types->mask('LEFT') | $types->mask('INNER'), false));
36        self::assertFalse($types->valid($types->mask('OUTER'), false));
37        self::assertFalse($types->valid($types->mask('NATURAL'), true));
38        self::assertTrue($types->valid($types->mask('FULL') | $types->mask('OUTER'), true));
39    }
40
41    public function testCanCompleteConsidersAllReachablePrefixStates(): void
42    {
43        $types = new JoinModifiers();
44        $words = ['INNER', 'CROSS', 'NATURAL', 'LEFT', 'RIGHT', 'FULL', 'OUTER'];
45        self::assertFalse($types->canComplete($types->mask('OUTER'), 0, false, $words));
46        self::assertTrue($types->canComplete($types->mask('OUTER'), 1, false, $words));
47        self::assertFalse($types->canComplete($types->mask('INNER') | $types->mask('OUTER'), 2, false, $words));
48        self::assertFalse($types->canComplete($types->mask('NATURAL'), 2, true, $words));
49    }
50    #[DataProvider('providerModifierPairs')]
51    public function testValidChecksNaturalOuterAndDirectionalCombinations(string $first, string $second, bool $hasCondition, bool $valid): void
52    {
53        $types = new JoinModifiers();
54        self::assertSame($valid, $types->valid($types->mask($first) | $types->mask($second), $hasCondition));
55    }
56
57    /**
58     * @return iterable<array{string, string, bool, bool}>
59     */
60    public static function providerModifierPairs(): iterable
61    {
62        yield ['NATURAL', 'OUTER', false, false];
63        yield ['NATURAL', 'LEFT', false, true];
64        yield ['NATURAL', 'RIGHT', false, true];
65        yield ['LEFT', 'OUTER', true, true];
66        yield ['RIGHT', 'OUTER', true, true];
67        yield ['LEFT', 'CROSS', false, false];
68        yield ['FULL', 'INNER', false, false];
69        yield ['NATURAL', 'FULL', true, false];
70        yield ['NATURAL', 'INNER', false, true];
71        yield ['NATURAL', 'INNER', true, false];
72    }
73}
74