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