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

1<?php
2
3declare(strict_types=1);
4
5namespace Tests\Unit\Config;
6
7use PHPUnit\Framework\Attributes\CoversClass;
8use PHPUnit\Framework\Attributes\UsesClass;
9use PHPUnit\Framework\TestCase;
10use ZtdQuery\Config\SqlBehaviorRule;
11use ZtdQuery\Config\UnknownSchemaBehavior;
12use ZtdQuery\Config\UnsupportedSqlBehavior;
13use ZtdQuery\Config\ZtdConfig;
14
15#[UsesClass(SqlBehaviorRule::class)]
16#[CoversClass(ZtdConfig::class)]
17final class ZtdConfigTest extends TestCase
18{
19    public function testDefaultCreatesConfigWithExceptionBehavior(): void
20    {
21        $config = ZtdConfig::default();
22
23        self::assertSame(UnsupportedSqlBehavior::Exception, $config->unsupportedBehavior());
24        self::assertSame(UnknownSchemaBehavior::Passthrough, $config->unknownSchemaBehavior());
25        self::assertSame([], $config->behaviorRules());
26    }
27
28    public function testUnsupportedBehaviorReturnsConfiguredValue(): void
29    {
30        $config = new ZtdConfig(UnsupportedSqlBehavior::Ignore);
31
32        self::assertSame(UnsupportedSqlBehavior::Ignore, $config->unsupportedBehavior());
33    }
34
35    public function testUnknownSchemaBehaviorReturnsConfiguredValue(): void
36    {
37        $config = new ZtdConfig(
38            UnsupportedSqlBehavior::Exception,
39            UnknownSchemaBehavior::Exception
40        );
41
42        self::assertSame(UnknownSchemaBehavior::Exception, $config->unknownSchemaBehavior());
43    }
44
45    public function testBehaviorRulesReturnsConfiguredRules(): void
46    {
47        $config = new ZtdConfig(
48            UnsupportedSqlBehavior::Exception,
49            UnknownSchemaBehavior::Passthrough,
50            [
51                'SET' => UnsupportedSqlBehavior::Ignore,
52                '/^SHOW\s+/i' => UnsupportedSqlBehavior::Notice,
53            ]
54        );
55
56        $rules = $config->behaviorRules();
57
58        self::assertCount(2, $rules);
59        self::assertSame('SET', $rules[0]->pattern());
60        self::assertSame(UnsupportedSqlBehavior::Ignore, $rules[0]->behavior());
61        self::assertSame('/^SHOW\s+/i', $rules[1]->pattern());
62        self::assertSame(UnsupportedSqlBehavior::Notice, $rules[1]->behavior());
63    }
64
65    public function testGetBehaviorForReturnsMatchingRuleBehavior(): void
66    {
67        $config = new ZtdConfig(
68            UnsupportedSqlBehavior::Exception,
69            UnknownSchemaBehavior::Passthrough,
70            [
71                '/^SET\s+/i' => UnsupportedSqlBehavior::Notice,
72                'BEGIN' => UnsupportedSqlBehavior::Ignore,
73            ]
74        );
75
76        self::assertSame(UnsupportedSqlBehavior::Notice, $config->getBehaviorFor('SET foo = 1'));
77        self::assertSame(UnsupportedSqlBehavior::Ignore, $config->getBehaviorFor('BEGIN'));
78    }
79
80    public function testGetBehaviorForReturnsNullWhenNoMatch(): void
81    {
82        $config = new ZtdConfig(
83            UnsupportedSqlBehavior::Exception,
84            UnknownSchemaBehavior::Passthrough,
85            ['SET' => UnsupportedSqlBehavior::Ignore]
86        );
87
88        self::assertNull($config->getBehaviorFor('DROP TABLE users'));
89    }
90
91    public function testResolveUnsupportedBehaviorUsesMatchingRule(): void
92    {
93        $config = new ZtdConfig(
94            UnsupportedSqlBehavior::Exception,
95            UnknownSchemaBehavior::Passthrough,
96            ['SET' => UnsupportedSqlBehavior::Ignore]
97        );
98
99        self::assertSame(
100            UnsupportedSqlBehavior::Ignore,
101            $config->resolveUnsupportedBehavior('SET foo = 1')
102        );
103    }
104
105    public function testResolveUnsupportedBehaviorUsesDefaultWhenNoMatch(): void
106    {
107        $config = new ZtdConfig(
108            UnsupportedSqlBehavior::Exception,
109            UnknownSchemaBehavior::Passthrough,
110            ['SET' => UnsupportedSqlBehavior::Ignore]
111        );
112
113        self::assertSame(
114            UnsupportedSqlBehavior::Exception,
115            $config->resolveUnsupportedBehavior('DROP TABLE users')
116        );
117    }
118
119    public function testFirstMatchWins(): void
120    {
121        $config = new ZtdConfig(
122            UnsupportedSqlBehavior::Exception,
123            UnknownSchemaBehavior::Passthrough,
124            [
125                '/^SET\s+SESSION/i' => UnsupportedSqlBehavior::Ignore,
126                '/^SET\s+/i' => UnsupportedSqlBehavior::Notice,
127            ]
128        );
129
130        self::assertSame(
131            UnsupportedSqlBehavior::Ignore,
132            $config->getBehaviorFor('SET SESSION foo = 1')
133        );
134
135        self::assertSame(
136            UnsupportedSqlBehavior::Notice,
137            $config->getBehaviorFor('SET foo = 1')
138        );
139    }
140
141    public function testPrefixMatchingBehavior(): void
142    {
143        $config = new ZtdConfig(
144            UnsupportedSqlBehavior::Exception,
145            UnknownSchemaBehavior::Passthrough,
146            [
147                'SHOW' => UnsupportedSqlBehavior::Ignore,
148                'SET SESSION' => UnsupportedSqlBehavior::Notice,
149            ]
150        );
151
152        self::assertSame(UnsupportedSqlBehavior::Ignore, $config->getBehaviorFor('SHOW TABLES'));
153        self::assertSame(UnsupportedSqlBehavior::Ignore, $config->getBehaviorFor('show tables'));
154        self::assertSame(UnsupportedSqlBehavior::Ignore, $config->getBehaviorFor('  SHOW TABLES'));
155        self::assertSame(UnsupportedSqlBehavior::Notice, $config->getBehaviorFor('SET SESSION foo = 1'));
156        self::assertNull($config->getBehaviorFor('SET foo = 1'));
157        self::assertNull($config->getBehaviorFor('SELECT * FROM users'));
158    }
159
160    public function testRegexMatchingBehavior(): void
161    {
162        $config = new ZtdConfig(
163            UnsupportedSqlBehavior::Exception,
164            UnknownSchemaBehavior::Passthrough,
165            [
166                '/^SHOW\s+VARIABLES/i' => UnsupportedSqlBehavior::Ignore,
167                '/@@\w+/' => UnsupportedSqlBehavior::Notice,
168            ]
169        );
170
171        self::assertSame(UnsupportedSqlBehavior::Ignore, $config->getBehaviorFor('SHOW VARIABLES'));
172        self::assertSame(UnsupportedSqlBehavior::Ignore, $config->getBehaviorFor('SHOW  VARIABLES'));
173        self::assertSame(UnsupportedSqlBehavior::Notice, $config->getBehaviorFor('SELECT @@version'));
174        self::assertNull($config->getBehaviorFor('SELECT version()'));
175    }
176
177    public function testMixedPrefixAndRegexRules(): void
178    {
179        $config = new ZtdConfig(
180            UnsupportedSqlBehavior::Exception,
181            UnknownSchemaBehavior::Passthrough,
182            [
183                'BEGIN' => UnsupportedSqlBehavior::Ignore,
184                '/^COMMIT\b/i' => UnsupportedSqlBehavior::Ignore,
185                'ROLLBACK' => UnsupportedSqlBehavior::Ignore,
186                '/^SET\s+/i' => UnsupportedSqlBehavior::Notice,
187            ]
188        );
189
190        self::assertSame(UnsupportedSqlBehavior::Ignore, $config->getBehaviorFor('BEGIN'));
191        self::assertSame(UnsupportedSqlBehavior::Ignore, $config->getBehaviorFor('COMMIT'));
192        self::assertSame(UnsupportedSqlBehavior::Ignore, $config->getBehaviorFor('ROLLBACK TO SAVEPOINT sp1'));
193        self::assertSame(UnsupportedSqlBehavior::Notice, $config->getBehaviorFor('SET NAMES utf8mb4'));
194        self::assertNull($config->getBehaviorFor('DROP TABLE users'));
195    }
196
197    public function testEmptyBehaviorRules(): void
198    {
199        $config = new ZtdConfig(
200            UnsupportedSqlBehavior::Notice,
201            UnknownSchemaBehavior::Passthrough,
202            []
203        );
204
205        self::assertNull($config->getBehaviorFor('SET foo = 1'));
206        self::assertSame(
207            UnsupportedSqlBehavior::Notice,
208            $config->resolveUnsupportedBehavior('SET foo = 1')
209        );
210    }
211}
212