Passed
Push — master ( 4843cb...58e2f3 )
by William
03:06 queued 13s
created

ContextTest   A

Complexity

Total Complexity 14

Size/Duplication

Total Lines 221
Duplicated Lines 0 %

Importance

Changes 5
Bugs 1 Features 0
Metric Value
eloc 123
c 5
b 1
f 0
dl 0
loc 221
rs 10
wmc 14

13 Methods

Rating   Name   Duplication   Size   Complexity  
A contextLoadingProvider() 0 30 1
A testModeWithCombinedModes() 0 19 1
A tearDownAfterClass() 0 3 1
A testMode() 0 5 1
A testLoadError() 0 3 1
A testLoadClosest() 0 11 2
A testEscapeAll() 0 4 1
A testLoad() 0 12 1
A testLoadAll() 0 8 1
A testModeWithString() 0 17 1
A contextNamesProvider() 0 13 1
A testEscape() 0 12 1
A providerForTestMode() 0 37 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace PhpMyAdmin\SqlParser\Tests\Lexer;
6
7
use PhpMyAdmin\SqlParser\Context;
8
use PhpMyAdmin\SqlParser\Tests\TestCase;
9
use PHPUnit\Framework\Attributes\DataProvider;
10
11
use function class_exists;
12
13
class ContextTest extends TestCase
14
{
15
    public static function tearDownAfterClass(): void
16
    {
17
        Context::setMode();
18
    }
19
20
    public function testLoad(): void
21
    {
22
        // Default context is 5.7.0.
23
        $this->assertEquals('\\PhpMyAdmin\\SqlParser\\Contexts\\ContextMySql50700', Context::$loadedContext);
24
        $this->assertArrayHasKey('STORED', Context::$keywords);
25
        $this->assertArrayNotHasKey('AUTHORS', Context::$keywords);
26
27
        // Restoring context.
28
        Context::load('');
29
        $this->assertEquals('\\PhpMyAdmin\\SqlParser\\Contexts\\ContextMySql50700', Context::$defaultContext);
30
        $this->assertArrayHasKey('STORED', Context::$keywords);
31
        $this->assertArrayNotHasKey('AUTHORS', Context::$keywords);
32
    }
33
34
    /**
35
     * Test for loading closest SQL context
36
     */
37
    #[DataProvider('contextLoadingProvider')]
38
    public function testLoadClosest(string $context, string|null $expected): void
39
    {
40
        $this->assertEquals($expected, Context::loadClosest($context));
41
        if ($expected !== null) {
42
            $this->assertEquals('\\PhpMyAdmin\\SqlParser\\Contexts\\Context' . $expected, Context::$loadedContext);
43
            $this->assertTrue(class_exists(Context::$loadedContext));
44
        }
45
46
        // Restoring context.
47
        Context::load('');
48
    }
49
50
    /**
51
     * @return array<string, array<int, string|null>>
52
     * @psalm-return array<string, array{string, (string|null)}>
53
     */
54
    public static function contextLoadingProvider(): array
55
    {
56
        return [
57
            'MySQL match' => [
58
                'MySql50500',
59
                'MySql50500',
60
            ],
61
            'MySQL strip' => [
62
                'MySql50712',
63
                'MySql50700',
64
            ],
65
            'MySQL fallback' => [
66
                'MySql99999',
67
                'MySql50700',
68
            ],
69
            'MariaDB match' => [
70
                'MariaDb100000',
71
                'MariaDb100000',
72
            ],
73
            'MariaDB stripg' => [
74
                'MariaDb109900',
75
                'MariaDb100000',
76
            ],
77
            'MariaDB fallback' => [
78
                'MariaDb990000',
79
                'MariaDb100300',
80
            ],
81
            'Invalid' => [
82
                'Sql',
83
                null,
84
            ],
85
        ];
86
    }
87
88
    #[DataProvider('contextNamesProvider')]
89
    public function testLoadAll(string $context): void
90
    {
91
        Context::load($context);
92
        $this->assertEquals('\\PhpMyAdmin\\SqlParser\\Contexts\\Context' . $context, Context::$loadedContext);
93
94
        // Restoring context.
95
        Context::load('');
96
    }
97
98
    /**
99
     * @return string[][]
100
     */
101
    public static function contextNamesProvider(): array
102
    {
103
        return [
104
            ['MySql50000'],
105
            ['MySql50100'],
106
            ['MySql50500'],
107
            ['MySql50600'],
108
            ['MySql50700'],
109
            ['MySql80000'],
110
            ['MariaDb100000'],
111
            ['MariaDb100100'],
112
            ['MariaDb100200'],
113
            ['MariaDb100300'],
114
        ];
115
    }
116
117
    public function testLoadError(): void
118
    {
119
        $this->assertFalse(Context::load('Foo'));
120
    }
121
122
    /**
123
     * @param int|string $mode
124
     */
125
    #[DataProvider('providerForTestMode')]
126
    public function testMode($mode, int $expected): void
127
    {
128
        Context::setMode($mode);
129
        $this->assertSame($expected, Context::getMode());
130
    }
131
132
    /**
133
     * @return array<int, array<int, int|string>>
134
     * @psalm-return list<array{int|string, int}>
135
     */
136
    public static function providerForTestMode(): array
137
    {
138
        return [
139
            [0, Context::SQL_MODE_NONE],
140
            [1, 1],
141
            ['', Context::SQL_MODE_NONE],
142
            ['invalid', Context::SQL_MODE_NONE],
143
            ['ALLOW_INVALID_DATES', Context::SQL_MODE_ALLOW_INVALID_DATES],
144
            ['ANSI_QUOTES', Context::SQL_MODE_ANSI_QUOTES],
145
            ['COMPAT_MYSQL', Context::SQL_MODE_COMPAT_MYSQL],
146
            ['ERROR_FOR_DIVISION_BY_ZERO', Context::SQL_MODE_ERROR_FOR_DIVISION_BY_ZERO],
147
            ['HIGH_NOT_PRECEDENCE', Context::SQL_MODE_HIGH_NOT_PRECEDENCE],
148
            ['IGNORE_SPACE', Context::SQL_MODE_IGNORE_SPACE],
149
            ['NO_AUTO_CREATE_USER', Context::SQL_MODE_NO_AUTO_CREATE_USER],
150
            ['NO_AUTO_VALUE_ON_ZERO', Context::SQL_MODE_NO_AUTO_VALUE_ON_ZERO],
151
            ['NO_BACKSLASH_ESCAPES', Context::SQL_MODE_NO_BACKSLASH_ESCAPES],
152
            ['NO_DIR_IN_CREATE', Context::SQL_MODE_NO_DIR_IN_CREATE],
153
            ['NO_ENGINE_SUBSTITUTION', Context::SQL_MODE_NO_ENGINE_SUBSTITUTION],
154
            ['NO_FIELD_OPTIONS', Context::SQL_MODE_NO_FIELD_OPTIONS],
155
            ['NO_KEY_OPTIONS', Context::SQL_MODE_NO_KEY_OPTIONS],
156
            ['NO_TABLE_OPTIONS', Context::SQL_MODE_NO_TABLE_OPTIONS],
157
            ['NO_UNSIGNED_SUBTRACTION', Context::SQL_MODE_NO_UNSIGNED_SUBTRACTION],
158
            ['NO_ZERO_DATE', Context::SQL_MODE_NO_ZERO_DATE],
159
            ['NO_ZERO_IN_DATE', Context::SQL_MODE_NO_ZERO_IN_DATE],
160
            ['ONLY_FULL_GROUP_BY', Context::SQL_MODE_ONLY_FULL_GROUP_BY],
161
            ['PIPES_AS_CONCAT', Context::SQL_MODE_PIPES_AS_CONCAT],
162
            ['REAL_AS_FLOAT', Context::SQL_MODE_REAL_AS_FLOAT],
163
            ['STRICT_ALL_TABLES', Context::SQL_MODE_STRICT_ALL_TABLES],
164
            ['STRICT_TRANS_TABLES', Context::SQL_MODE_STRICT_TRANS_TABLES],
165
            ['NO_ENCLOSING_QUOTES', Context::SQL_MODE_NO_ENCLOSING_QUOTES],
166
            ['ANSI', Context::SQL_MODE_ANSI],
167
            ['DB2', Context::SQL_MODE_DB2],
168
            ['MAXDB', Context::SQL_MODE_MAXDB],
169
            ['MSSQL', Context::SQL_MODE_MSSQL],
170
            ['ORACLE', Context::SQL_MODE_ORACLE],
171
            ['POSTGRESQL', Context::SQL_MODE_POSTGRESQL],
172
            ['TRADITIONAL', Context::SQL_MODE_TRADITIONAL],
173
        ];
174
    }
175
176
    public function testModeWithCombinedModes(): void
177
    {
178
        Context::setMode(
179
            Context::SQL_MODE_REAL_AS_FLOAT | Context::SQL_MODE_ANSI_QUOTES | Context::SQL_MODE_IGNORE_SPACE
180
        );
181
        $this->assertSame(
182
            Context::SQL_MODE_REAL_AS_FLOAT | Context::SQL_MODE_ANSI_QUOTES | Context::SQL_MODE_IGNORE_SPACE,
183
            Context::getMode()
184
        );
185
        $this->assertTrue(Context::hasMode(Context::SQL_MODE_REAL_AS_FLOAT | Context::SQL_MODE_IGNORE_SPACE));
186
        $this->assertTrue(Context::hasMode(Context::SQL_MODE_ANSI_QUOTES));
187
        $this->assertFalse(Context::hasMode(Context::SQL_MODE_REAL_AS_FLOAT | Context::SQL_MODE_ALLOW_INVALID_DATES));
188
        $this->assertFalse(Context::hasMode(Context::SQL_MODE_ALLOW_INVALID_DATES));
189
190
        Context::setMode(Context::SQL_MODE_TRADITIONAL);
191
        $this->assertSame(Context::SQL_MODE_TRADITIONAL, Context::getMode());
192
193
        Context::setMode();
194
        $this->assertSame(Context::SQL_MODE_NONE, Context::getMode());
195
    }
196
197
    public function testModeWithString(): void
198
    {
199
        Context::setMode('REAL_AS_FLOAT,ANSI_QUOTES,IGNORE_SPACE');
200
        $this->assertSame(
201
            Context::SQL_MODE_REAL_AS_FLOAT | Context::SQL_MODE_ANSI_QUOTES | Context::SQL_MODE_IGNORE_SPACE,
202
            Context::getMode()
203
        );
204
        $this->assertTrue(Context::hasMode(Context::SQL_MODE_REAL_AS_FLOAT | Context::SQL_MODE_IGNORE_SPACE));
205
        $this->assertTrue(Context::hasMode(Context::SQL_MODE_ANSI_QUOTES));
206
        $this->assertFalse(Context::hasMode(Context::SQL_MODE_REAL_AS_FLOAT | Context::SQL_MODE_ALLOW_INVALID_DATES));
207
        $this->assertFalse(Context::hasMode(Context::SQL_MODE_ALLOW_INVALID_DATES));
208
209
        Context::setMode('TRADITIONAL');
210
        $this->assertSame(Context::SQL_MODE_TRADITIONAL, Context::getMode());
211
212
        Context::setMode('');
213
        $this->assertSame(Context::SQL_MODE_NONE, Context::getMode());
214
    }
215
216
    public function testEscape(): void
217
    {
218
        Context::setMode(Context::SQL_MODE_NO_ENCLOSING_QUOTES);
219
        $this->assertEquals('test', Context::escape('test'));
220
221
        Context::setMode(Context::SQL_MODE_ANSI_QUOTES);
222
        $this->assertEquals('"test"', Context::escape('test'));
223
224
        Context::setMode();
225
        $this->assertEquals('`test`', Context::escape('test'));
226
227
        $this->assertEquals(['`a`', '`b`'], Context::escapeAll(['a', 'b']));
228
    }
229
230
    public function testEscapeAll(): void
231
    {
232
        Context::setMode();
233
        $this->assertEquals(['`a`', '`b`'], Context::escapeAll(['a', 'b']));
234
    }
235
}
236