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