packages/sql-faker/tests/Unit/MySql/Generation/Rewrite/RoleGrantRuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\SqlFaker\MySql\Generation\Rewrite;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use SqlFaker\Generation\Derivation\DerivationTrace;
11use SqlFaker\Grammar\Model\NonTerminal;
12use SqlFaker\Grammar\Model\Production;
13use SqlFaker\Grammar\Model\Terminal;
14use SqlFaker\MySql\Generation\Rewrite\RoleGrantRule;
15
16#[CoversClass(RoleGrantRule::class)]
17#[UsesClass(DerivationTrace::class)]
18#[UsesClass(NonTerminal::class)]
19#[UsesClass(Production::class)]
20#[UsesClass(Terminal::class)]
21#[UsesClass(\SqlFaker\Generation\Token\ProductionOccurrence::class)]
22#[UsesClass(\SqlFaker\Generation\Token\TerminalOccurrence::class)]
23#[UsesClass(\SqlFaker\Generation\Token\TerminalSequence::class)]
24final class RoleGrantRuleTest extends TestCase
25{
26    public function testRewriteChangesPrivilegesToRolesOnlyWithoutAnOnTarget(): void
27    {
28        $trace = new DerivationTrace('grant');
29        $trace->expand(0, new Production([new Terminal('GRANT'), new NonTerminal('role_or_privilege'), new Terminal('TO_SYM'), new Terminal('IDENT')]), 0);
30        $trace->expand(1, new Production([new Terminal('CREATE'), new Terminal('TABLESPACE_SYM')]), 29);
31        $input = $trace->terminals();
32        $result = (new RoleGrantRule())->rewrite($input);
33        self::assertSame(['GRANT', 'IDENT_QUOTED', 'TO_SYM', 'IDENT'], $result->names());
34        self::assertSame($input->original, $result->original);
35        self::assertCount(count($result->terminals), array_unique(array_map(static fn ($terminal): int => $terminal->id, $result->terminals)));
36        self::assertSame(29, $result->productions[1]->ordinal);
37    }
38
39    public function testRewriteKeepsAPrivilegeGrantWithAnExplicitTarget(): void
40    {
41        $trace = new DerivationTrace('grant');
42        $trace->expand(0, new Production([new Terminal('GRANT'), new NonTerminal('role_or_privilege'), new Terminal('ON_SYM'), new NonTerminal('grant_ident')]), 1);
43        $trace->expand(1, new Production([new Terminal('SELECT_SYM')]), 2);
44        $trace->expand(3, new Production([new Terminal('*'), new Terminal('.'), new Terminal('*')]), 2);
45        $input = $trace->terminals();
46        self::assertSame($input, (new RoleGrantRule())->rewrite($input));
47    }
48
49    public function testRewritePreservesARoleNameButRemovesItsInvalidColumnList(): void
50    {
51        $trace = new DerivationTrace('revoke');
52        $trace->expand(0, new Production([new NonTerminal('role_or_privilege')]), 0);
53        $trace->expand(0, new Production([new NonTerminal('role_ident_or_text'), new NonTerminal('opt_column_list')]), 0);
54        $trace->expand(0, new Production([new Terminal('IDENT_QUOTED')]), 0);
55        $trace->expand(1, new Production([new Terminal('('), new Terminal('IDENT'), new Terminal(')')]), 1);
56        self::assertSame(['IDENT_QUOTED'], (new RoleGrantRule())->rewrite($trace->terminals())->names());
57    }
58
59    public function testRewriteRemovesAHostOnlyWhenTheRoleIsUsedAsAPrivilege(): void
60    {
61        $trace = new DerivationTrace('grant');
62        $trace->expand(0, new Production([new NonTerminal('role_or_privilege'), new NonTerminal('grant_ident')]), 1);
63        $trace->expand(0, new Production([new NonTerminal('role_ident_or_text'), new Terminal('@'), new Terminal('IDENT')]), 1);
64        $trace->expand(0, new Production([new Terminal('IDENT_QUOTED')]), 0);
65        $trace->expand(3, new Production([new Terminal('*')]), 0);
66        $input = $trace->terminals();
67        $result = (new RoleGrantRule())->rewrite($input);
68        self::assertSame(['IDENT_QUOTED', '*'], $result->names());
69        self::assertSame($input->terminals[0], $result->terminals[0]);
70        self::assertSame($input->original, $result->original);
71        self::assertSame($result, (new RoleGrantRule())->rewrite($result));
72    }
73
74    public function testRewriteRemovesColumnListsFromRoutinePrivileges(): void
75    {
76        $trace = new DerivationTrace('revoke');
77        $trace->expand(0, new Production([new NonTerminal('role_or_privilege'), new NonTerminal('opt_acl_type'), new NonTerminal('grant_ident')]), 1);
78        $trace->expand(0, new Production([new Terminal('INSERT_SYM'), new NonTerminal('opt_column_list')]), 1);
79        $trace->expand(1, new Production([new Terminal('('), new Terminal('IDENT'), new Terminal(')')]), 1);
80        $trace->expand(4, new Production([new Terminal('FUNCTION_SYM')]), 2);
81        $trace->expand(5, new Production([new Terminal('*')]), 0);
82        $input = $trace->terminals();
83        self::assertSame(['INSERT_SYM', 'FUNCTION_SYM', '*'], (new RoleGrantRule())->rewrite($input)->names());
84    }
85
86    public function testPrivilegePreservesMissingOccurrences(): void
87    {
88        $input = \SqlFaker\Generation\Token\TerminalSequence::fromNames(['SELECT_SYM']);
89        self::assertSame($input, (new RoleGrantRule())->privilege($input, 0, 1));
90    }
91}
92