1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Graze\Morphism\Parse; |
4
|
|
|
|
5
|
|
|
use Graze\Morphism\Test\Parse\TestCase; |
6
|
|
|
use LogicException; |
7
|
|
|
use RuntimeException; |
8
|
|
|
|
9
|
|
|
class IndexDefinitionTest extends TestCase |
10
|
|
|
{ |
11
|
|
|
/** |
12
|
|
|
* @dataProvider parseProvider |
13
|
|
|
* @param string $type |
14
|
|
|
* @param string $text |
15
|
|
|
* @param string|null $constraint |
16
|
|
|
* @param string $expected |
17
|
|
|
*/ |
18
|
|
View Code Duplication |
public function testParse($type, $text, $constraint, $expected) |
|
|
|
|
19
|
|
|
{ |
20
|
|
|
$stream = $this->makeStream($text); |
21
|
|
|
|
22
|
|
|
$index = new IndexDefinition(); |
23
|
|
|
$index->parse($stream, $type, $constraint); |
24
|
|
|
if (is_null($index->name)) { |
25
|
|
|
$index->name = 'k1'; |
26
|
|
|
} |
27
|
|
|
|
28
|
|
|
$this->assertSame($expected, $index->toString()); |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
/** |
32
|
|
|
* @return array |
33
|
|
|
*/ |
34
|
|
|
public function parseProvider() |
35
|
|
|
{ |
36
|
|
|
return [ |
37
|
|
|
// [ type, text, constraint, expected ] |
38
|
|
|
["PRIMARY KEY", "(a)", null, "PRIMARY KEY (`a`)"], |
39
|
|
|
|
40
|
|
|
["UNIQUE KEY", "(a)", null, "UNIQUE KEY `k1` (`a`)"], |
41
|
|
|
["UNIQUE KEY", "k (a)", null, "UNIQUE KEY `k` (`a`)"], |
42
|
|
|
["UNIQUE KEY", "(a)", 'foo', "UNIQUE KEY `foo` (`a`)"], |
43
|
|
|
|
44
|
|
|
["FULLTEXT KEY", "(a)", null, "FULLTEXT KEY `k1` (`a`)"], |
45
|
|
|
["FULLTEXT KEY", "k (a)", null, "FULLTEXT KEY `k` (`a`)"], |
46
|
|
|
["FULLTEXT KEY", "(a) WITH PARSER foo_parser", null, "FULLTEXT KEY `k1` (`a`) WITH PARSER foo_parser"], |
47
|
|
|
|
48
|
|
|
["KEY", "(a)", null, "KEY `k1` (`a`)"], |
49
|
|
|
["KEY", "(a ASC)", null, "KEY `k1` (`a`)"], |
50
|
|
|
["KEY", "(a DESC)", null, "KEY `k1` (`a`)"], |
51
|
|
|
["KEY", "k (a)", null, "KEY `k` (`a`)"], |
52
|
|
|
["KEY", "(a,b,c)", null, "KEY `k1` (`a`,`b`,`c`)"], |
53
|
|
|
["KEY", "(a,b,c)", null, "KEY `k1` (`a`,`b`,`c`)"], |
54
|
|
|
["KEY", "(a(10))", null, "KEY `k1` (`a`(10))"], |
55
|
|
|
["KEY", "(a(10),b(12))", null, "KEY `k1` (`a`(10),`b`(12))"], |
56
|
|
|
["KEY", "USING BTREE (a)", null, "KEY `k1` (`a`) USING BTREE"], |
57
|
|
|
["KEY", "k USING BTREE (a)", null, "KEY `k` (`a`) USING BTREE"], |
58
|
|
|
["KEY", "(a) USING BTREE", null, "KEY `k1` (`a`) USING BTREE"], |
59
|
|
|
["KEY", "(a) USING HASH", null, "KEY `k1` (`a`) USING HASH"], |
60
|
|
|
["KEY", "(a) KEY_BLOCK_SIZE 10", null, "KEY `k1` (`a`) KEY_BLOCK_SIZE=10"], |
61
|
|
|
["KEY", "(a) KEY_BLOCK_SIZE=10", null, "KEY `k1` (`a`) KEY_BLOCK_SIZE=10"], |
62
|
|
|
["KEY", "(a) KEY_BLOCK_SIZE=0", null, "KEY `k1` (`a`)"], |
63
|
|
|
["KEY", "(a) COMMENT 'foo'", null, "KEY `k1` (`a`) COMMENT 'foo'"], |
64
|
|
|
["KEY", "(a) COMMENT ''", null, "KEY `k1` (`a`)"], |
65
|
|
|
["KEY", "(a) COMMENT 'foo' USING BTREE KEY_BLOCK_SIZE=10", null, |
66
|
|
|
"KEY `k1` (`a`) USING BTREE KEY_BLOCK_SIZE=10 COMMENT 'foo'"], |
67
|
|
|
|
68
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta)", "c1", |
69
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`)"], |
70
|
|
|
|
71
|
|
|
["FOREIGN KEY", "(a) REFERENCES foo.t(ta)", "c1", |
72
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `foo`.`t` (`ta`)"], |
73
|
|
|
|
74
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta(10))", "c1", |
75
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`(10))"], |
76
|
|
|
|
77
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) ON DELETE RESTRICT", "c1", |
78
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`)"], |
79
|
|
|
|
80
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) ON DELETE CASCADE", "c1", |
81
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`) ON DELETE CASCADE"], |
82
|
|
|
|
83
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) ON DELETE NO ACTION", "c1", |
84
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`) ON DELETE NO ACTION"], |
85
|
|
|
|
86
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) ON DELETE SET NULL", "c1", |
87
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`) ON DELETE SET NULL"], |
88
|
|
|
|
89
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) ON UPDATE RESTRICT", "c1", |
90
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`)"], |
91
|
|
|
|
92
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) ON UPDATE CASCADE", "c1", |
93
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`) ON UPDATE CASCADE"], |
94
|
|
|
|
95
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) ON UPDATE NO ACTION", "c1", |
96
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`) ON UPDATE NO ACTION"], |
97
|
|
|
|
98
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) ON UPDATE SET NULL", "c1", |
99
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`) ON UPDATE SET NULL"], |
100
|
|
|
|
101
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) ON UPDATE NO ACTION ON DELETE NO ACTION", "c1", |
102
|
|
|
"CONSTRAINT `c1` FOREIGN KEY (`a`) REFERENCES `t` (`ta`) ON DELETE NO ACTION ON UPDATE NO ACTION"], |
103
|
|
|
|
104
|
|
|
]; |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
/** |
108
|
|
|
* @dataProvider badParseProvider |
109
|
|
|
* @param string $type |
110
|
|
|
* @param string $text |
111
|
|
|
* @param string $exception |
112
|
|
|
*/ |
113
|
|
|
public function testBadParse($type, $text, $exception) |
114
|
|
|
{ |
115
|
|
|
$stream = $this->makeStream($text); |
116
|
|
|
|
117
|
|
|
$this->setExpectedException($exception); |
118
|
|
|
|
119
|
|
|
$index = new IndexDefinition(); |
120
|
|
|
$index->parse($stream, $type); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* @return array |
125
|
|
|
*/ |
126
|
|
|
public function badParseProvider() |
127
|
|
|
{ |
128
|
|
|
return [ |
129
|
|
|
// [ type, text ] |
130
|
|
|
// Invalid key type |
131
|
|
|
["INVALID_INDEX_TYPE", "foo", LogicException::class], |
132
|
|
|
// Invalid tree type |
133
|
|
|
["KEY", "USING FOOTREE (a)", RuntimeException::class], |
134
|
|
|
// Unsupported 'MATCH' keyword |
135
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) MATCH FULL", RuntimeException::class], |
136
|
|
|
// Unsupported reference action |
137
|
|
|
["FOREIGN KEY", "(a) REFERENCES t(ta) ON UPDATE FOO", RuntimeException::class], |
138
|
|
|
]; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* @dataProvider providerCovers |
143
|
|
|
* @param string $text |
144
|
|
|
* @param array $expected |
145
|
|
|
*/ |
146
|
|
View Code Duplication |
public function testCovers($text, array $expected) |
|
|
|
|
147
|
|
|
{ |
148
|
|
|
$stream = $this->makeStream($text); |
149
|
|
|
|
150
|
|
|
$index = new IndexDefinition(); |
151
|
|
|
$index->parse($stream, 'KEY'); |
152
|
|
|
$covers = $index->getCovers(); |
153
|
|
|
|
154
|
|
|
sort($expected); |
155
|
|
|
sort($covers); |
156
|
|
|
|
157
|
|
|
$this->assertSame($covers, $expected); |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
/** |
161
|
|
|
* @return array |
162
|
|
|
*/ |
163
|
|
|
public function providerCovers() |
164
|
|
|
{ |
165
|
|
|
return [ |
166
|
|
|
[ '(x)', [['x']] ], |
167
|
|
|
[ '(x,y)', [['x'], ['x','y']] ], |
168
|
|
|
[ '(x,y,z)', [['x'], ['x','y'], ['x','y','z']] ], |
169
|
|
|
[ '(x,y(10),z)', [['x'], ['x','y(10)'], ['x','y(10)','z']] ], |
170
|
|
|
]; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
/** |
174
|
|
|
* @dataProvider providerColumns() |
175
|
|
|
* @param string $text |
176
|
|
|
* @param array $expected |
177
|
|
|
*/ |
178
|
|
|
public function testColumns($text, array $expected) |
179
|
|
|
{ |
180
|
|
|
$stream = $this->makeStream($text); |
181
|
|
|
|
182
|
|
|
$index = new IndexDefinition(); |
183
|
|
|
$index->parse($stream, 'KEY'); |
184
|
|
|
$columns = $index->getColumns(); |
185
|
|
|
|
186
|
|
|
$this->assertSame($columns, $expected); |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
/** |
190
|
|
|
* @return array |
191
|
|
|
*/ |
192
|
|
|
public function providerColumns() |
193
|
|
|
{ |
194
|
|
|
return [ |
195
|
|
|
[ '(x)', ['x'] ], |
196
|
|
|
[ '(x,y)', ['x','y'] ], |
197
|
|
|
[ '(x,y,z)', ['x','y','z'] ], |
198
|
|
|
[ '(x,y(10),z)', ['x','y(10)','z'] ], |
199
|
|
|
]; |
200
|
|
|
} |
201
|
|
|
} |
202
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.