packages/sql-faker/tests/Unit/Generation/Plan/Compilation/ScopeTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Generation\Plan\Compilation;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlFaker\Generation\Plan\Compilation\Scope;
11use SqlFaker\Generation\Plan\LexemeConstraint;
12use SqlFaker\Generation\Plan\RulePlan;
13
14#[CoversClass(Scope::class)]
15#[UsesClass(RulePlan::class)]
16#[UsesClass(LexemeConstraint::class)]
17final class ScopeTest extends TestCase
18{
19    public function testEnterNearerScopesOverrideDefaultsWithoutLeakingToSiblings(): void
20    {
21        $outer = new Scope([], ['ID' => LexemeConstraint::oneOf('outer')]);
22        $inner = $outer->enter(RulePlan::any()->withLexeme('ID', LexemeConstraint::oneOf('inner')));
23        self::assertTrue($inner->lexemes['ID']->accepts('inner'));
24        self::assertFalse($inner->lexemes['ID']->accepts('outer'));
25        self::assertTrue($outer->lexemes['ID']->accepts('outer'));
26    }
27
28    public function testEnterOverridesOnlyDeclaredRolesAndCanonicalizesIndependentDeclarationOrder(): void
29    {
30        $defaultName = RulePlan::any();
31        $targetName = RulePlan::any()->withLexeme('ID', LexemeConstraint::oneOf('users'));
32        $value = RulePlan::any()->withLexeme('INTEGER', LexemeConstraint::oneOf('42'));
33        $identifier = LexemeConstraint::oneOf('outer');
34        $literal = LexemeConstraint::oneOf("'Alice'");
35        $first = (new Scope(['value' => $value, 'name' => $defaultName], ['STRING' => $literal, 'ID' => $identifier]))
36            ->enter(RulePlan::any()->withRule('name', $targetName)->withLexeme('ID', LexemeConstraint::oneOf('inner')));
37        $second = (new Scope(['name' => $defaultName, 'value' => $value], ['ID' => $identifier, 'STRING' => $literal]))
38            ->enter(RulePlan::any()->withLexeme('ID', LexemeConstraint::oneOf('inner'))->withRule('name', $targetName));
39        self::assertSame(['name' => $targetName, 'value' => $value], $first->rules);
40        self::assertSame($literal, $first->lexemes['STRING']);
41        self::assertSame(serialize($first), serialize($second));
42    }
43
44}
45