packages/ztd-query-core/tests/Unit/Config/SqlBehaviorRuleTest.php

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Config;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\TestCase;
9use ZtdQuery\Config\SqlBehaviorRule;
10use ZtdQuery\Config\UnsupportedSqlBehavior;
11
12#[CoversClass(SqlBehaviorRule::class)]
13final class SqlBehaviorRuleTest extends TestCase
14{
15    public function testPrefixMatchesCaseInsensitive(): void
16    {
17        $rule = new SqlBehaviorRule('SET', UnsupportedSqlBehavior::Ignore);
18
19        self::assertTrue($rule->matches('SET foo = 1'));
20        self::assertTrue($rule->matches('set foo = 1'));
21        self::assertTrue($rule->matches('Set Session foo = 1'));
22    }
23
24    public function testPrefixMatchesWithLeadingWhitespace(): void
25    {
26        $rule = new SqlBehaviorRule('SET', UnsupportedSqlBehavior::Ignore);
27
28        self::assertTrue($rule->matches('  SET foo = 1'));
29        self::assertTrue($rule->matches("\t\nSET foo = 1"));
30    }
31
32    public function testPrefixDoesNotMatchNonPrefix(): void
33    {
34        $rule = new SqlBehaviorRule('SET', UnsupportedSqlBehavior::Ignore);
35
36        self::assertFalse($rule->matches('SELECT SET FROM t'));
37        self::assertFalse($rule->matches('RESET foo'));
38    }
39
40    public function testRegexMatches(): void
41    {
42        $rule = new SqlBehaviorRule('/^SET\s+SESSION/i', UnsupportedSqlBehavior::Notice);
43
44        self::assertTrue($rule->matches('SET SESSION foo = 1'));
45        self::assertTrue($rule->matches('set session foo = 1'));
46        self::assertTrue($rule->matches('SET  SESSION foo = 1'));
47    }
48
49    public function testRegexDoesNotMatchNonMatching(): void
50    {
51        $rule = new SqlBehaviorRule('/^SET\s+SESSION/i', UnsupportedSqlBehavior::Notice);
52
53        self::assertFalse($rule->matches('SET foo = 1'));
54        self::assertFalse($rule->matches('SETSESSION foo = 1'));
55    }
56
57    public function testIsRegexDetection(): void
58    {
59        $prefix = new SqlBehaviorRule('SET', UnsupportedSqlBehavior::Ignore);
60        $regex = new SqlBehaviorRule('/^SET/', UnsupportedSqlBehavior::Ignore);
61
62        self::assertFalse($prefix->isRegex());
63        self::assertTrue($regex->isRegex());
64    }
65
66    public function testBehaviorReturnsConfiguredValue(): void
67    {
68        $ignoreRule = new SqlBehaviorRule('SET', UnsupportedSqlBehavior::Ignore);
69        $noticeRule = new SqlBehaviorRule('BEGIN', UnsupportedSqlBehavior::Notice);
70        $exceptionRule = new SqlBehaviorRule('DROP', UnsupportedSqlBehavior::Exception);
71
72        self::assertSame(UnsupportedSqlBehavior::Ignore, $ignoreRule->behavior());
73        self::assertSame(UnsupportedSqlBehavior::Notice, $noticeRule->behavior());
74        self::assertSame(UnsupportedSqlBehavior::Exception, $exceptionRule->behavior());
75    }
76
77    public function testPatternReturnsOriginalPattern(): void
78    {
79        $rule = new SqlBehaviorRule('/^SET\s+/i', UnsupportedSqlBehavior::Ignore);
80
81        self::assertSame('/^SET\s+/i', $rule->pattern());
82    }
83
84    public function testComplexRegexPatterns(): void
85    {
86        $cases = [
87            'variable reference matches' => ['/@@\w+/', 'SELECT @@version', true],
88            'variable reference not matches' => ['/@@\w+/', 'SELECT version()', false],
89            'transaction pattern matches BEGIN' => ['/^(BEGIN|COMMIT|ROLLBACK)\b/i', 'BEGIN', true],
90            'transaction pattern matches COMMIT' => ['/^(BEGIN|COMMIT|ROLLBACK)\b/i', 'COMMIT', true],
91            'transaction pattern matches ROLLBACK' => ['/^(BEGIN|COMMIT|ROLLBACK)\b/i', 'ROLLBACK', true],
92            'transaction pattern not matches' => ['/^(BEGIN|COMMIT|ROLLBACK)\b/i', 'SELECT * FROM t', false],
93        ];
94
95        array_walk($cases, function (array $case, string $label): void {
96            [$pattern, $sql, $expected] = $case;
97            $rule = new SqlBehaviorRule($pattern, UnsupportedSqlBehavior::Ignore);
98            self::assertSame($expected, $rule->matches($sql), $label);
99        });
100    }
101
102    public function testMatchesAnswersForTheStatementsTheRuleIsWrittenFor(): void
103    {
104        $rule = new SqlBehaviorRule('SELECT', UnsupportedSqlBehavior::Ignore);
105
106        self::assertTrue($rule->matches('select 1'));
107        self::assertFalse($rule->matches('INSERT INTO t VALUES (1)'));
108    }
109}
110