Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 * This file is part of Psy Shell.
|
Chris@0
|
5 *
|
Chris@0
|
6 * (c) 2012-2017 Justin Hileman
|
Chris@0
|
7 *
|
Chris@0
|
8 * For the full copyright and license information, please view the LICENSE
|
Chris@0
|
9 * file that was distributed with this source code.
|
Chris@0
|
10 */
|
Chris@0
|
11
|
Chris@0
|
12 namespace Psy\Test\CodeCleaner;
|
Chris@0
|
13
|
Chris@0
|
14 use Psy\CodeCleaner\ValidClassNamePass;
|
Chris@0
|
15 use Psy\Exception\Exception;
|
Chris@0
|
16
|
Chris@0
|
17 class ValidClassNamePassTest extends CodeCleanerTestCase
|
Chris@0
|
18 {
|
Chris@0
|
19 public function setUp()
|
Chris@0
|
20 {
|
Chris@0
|
21 $this->setPass(new ValidClassNamePass());
|
Chris@0
|
22 }
|
Chris@0
|
23
|
Chris@0
|
24 /**
|
Chris@0
|
25 * @dataProvider getInvalid
|
Chris@0
|
26 */
|
Chris@0
|
27 public function testProcessInvalid($code, $php54 = false)
|
Chris@0
|
28 {
|
Chris@0
|
29 try {
|
Chris@0
|
30 $stmts = $this->parse($code);
|
Chris@0
|
31 $this->traverse($stmts);
|
Chris@0
|
32 $this->fail();
|
Chris@0
|
33 } catch (Exception $e) {
|
Chris@0
|
34 if ($php54 && version_compare(PHP_VERSION, '5.4', '<')) {
|
Chris@0
|
35 $this->assertInstanceOf('Psy\Exception\ParseErrorException', $e);
|
Chris@0
|
36 } else {
|
Chris@0
|
37 $this->assertInstanceOf('Psy\Exception\FatalErrorException', $e);
|
Chris@0
|
38 }
|
Chris@0
|
39 }
|
Chris@0
|
40 }
|
Chris@0
|
41
|
Chris@0
|
42 public function getInvalid()
|
Chris@0
|
43 {
|
Chris@0
|
44 // class declarations
|
Chris@0
|
45 return array(
|
Chris@0
|
46 // core class
|
Chris@0
|
47 array('class stdClass {}'),
|
Chris@0
|
48 // capitalization
|
Chris@0
|
49 array('class stdClass {}'),
|
Chris@0
|
50
|
Chris@0
|
51 // collisions with interfaces and traits
|
Chris@0
|
52 array('interface stdClass {}'),
|
Chris@0
|
53 array('trait stdClass {}', true),
|
Chris@0
|
54
|
Chris@0
|
55 // collisions inside the same code snippet
|
Chris@0
|
56 array('
|
Chris@0
|
57 class Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
58 class Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
59 '),
|
Chris@0
|
60 array('
|
Chris@0
|
61 class Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
62 trait Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
63 ', true),
|
Chris@0
|
64 array('
|
Chris@0
|
65 trait Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
66 class Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
67 ', true),
|
Chris@0
|
68 array('
|
Chris@0
|
69 trait Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
70 interface Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
71 ', true),
|
Chris@0
|
72 array('
|
Chris@0
|
73 interface Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
74 trait Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
75 ', true),
|
Chris@0
|
76 array('
|
Chris@0
|
77 interface Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
78 class Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
79 '),
|
Chris@0
|
80 array('
|
Chris@0
|
81 class Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
82 interface Psy_Test_CodeCleaner_ValidClassNamePass_Alpha {}
|
Chris@0
|
83 '),
|
Chris@0
|
84
|
Chris@0
|
85 // namespaced collisions
|
Chris@0
|
86 array('
|
Chris@0
|
87 namespace Psy\\Test\\CodeCleaner {
|
Chris@0
|
88 class ValidClassNamePassTest {}
|
Chris@0
|
89 }
|
Chris@0
|
90 '),
|
Chris@0
|
91 array('
|
Chris@0
|
92 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@0
|
93 class Beta {}
|
Chris@0
|
94 }
|
Chris@0
|
95 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@0
|
96 class Beta {}
|
Chris@0
|
97 }
|
Chris@0
|
98 '),
|
Chris@0
|
99
|
Chris@0
|
100 // extends and implements
|
Chris@0
|
101 array('class ValidClassNamePassTest extends NotAClass {}'),
|
Chris@0
|
102 array('class ValidClassNamePassTest extends ArrayAccess {}'),
|
Chris@0
|
103 array('class ValidClassNamePassTest implements stdClass {}'),
|
Chris@0
|
104 array('class ValidClassNamePassTest implements ArrayAccess, stdClass {}'),
|
Chris@0
|
105 array('interface ValidClassNamePassTest extends stdClass {}'),
|
Chris@0
|
106 array('interface ValidClassNamePassTest extends ArrayAccess, stdClass {}'),
|
Chris@0
|
107
|
Chris@0
|
108 // class instantiations
|
Chris@0
|
109 array('new Psy_Test_CodeCleaner_ValidClassNamePass_Gamma();'),
|
Chris@0
|
110 array('
|
Chris@0
|
111 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@0
|
112 new Psy_Test_CodeCleaner_ValidClassNamePass_Delta();
|
Chris@0
|
113 }
|
Chris@0
|
114 '),
|
Chris@0
|
115
|
Chris@0
|
116 // class constant fetch
|
Chris@0
|
117 array('Psy\\Test\\CodeCleaner\\ValidClassNamePass\\NotAClass::FOO'),
|
Chris@0
|
118
|
Chris@0
|
119 // static call
|
Chris@0
|
120 array('Psy\\Test\\CodeCleaner\\ValidClassNamePass\\NotAClass::foo()'),
|
Chris@0
|
121 array('Psy\\Test\\CodeCleaner\\ValidClassNamePass\\NotAClass::$foo()'),
|
Chris@0
|
122 );
|
Chris@0
|
123 }
|
Chris@0
|
124
|
Chris@0
|
125 /**
|
Chris@0
|
126 * @dataProvider getValid
|
Chris@0
|
127 */
|
Chris@0
|
128 public function testProcessValid($code)
|
Chris@0
|
129 {
|
Chris@0
|
130 $stmts = $this->parse($code);
|
Chris@0
|
131 $this->traverse($stmts);
|
Chris@12
|
132
|
Chris@12
|
133 // @todo a better thing to assert here?
|
Chris@12
|
134 $this->assertTrue(true);
|
Chris@0
|
135 }
|
Chris@0
|
136
|
Chris@0
|
137 public function getValid()
|
Chris@0
|
138 {
|
Chris@0
|
139 $valid = array(
|
Chris@0
|
140 // class declarations
|
Chris@0
|
141 array('class Psy_Test_CodeCleaner_ValidClassNamePass_Epsilon {}'),
|
Chris@0
|
142 array('namespace Psy\Test\CodeCleaner\ValidClassNamePass; class Zeta {}'),
|
Chris@0
|
143 array('
|
Chris@0
|
144 namespace { class Psy_Test_CodeCleaner_ValidClassNamePass_Eta {}; }
|
Chris@0
|
145 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@0
|
146 class Psy_Test_CodeCleaner_ValidClassNamePass_Eta {}
|
Chris@0
|
147 }
|
Chris@0
|
148 '),
|
Chris@0
|
149 array('namespace Psy\Test\CodeCleaner\ValidClassNamePass { class stdClass {} }'),
|
Chris@0
|
150
|
Chris@0
|
151 // class instantiations
|
Chris@0
|
152 array('new stdClass();'),
|
Chris@0
|
153 array('new stdClass();'),
|
Chris@0
|
154 array('
|
Chris@0
|
155 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@0
|
156 class Theta {}
|
Chris@0
|
157 }
|
Chris@0
|
158 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@0
|
159 new Theta();
|
Chris@0
|
160 }
|
Chris@0
|
161 '),
|
Chris@0
|
162 array('
|
Chris@0
|
163 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@0
|
164 class Iota {}
|
Chris@0
|
165 new Iota();
|
Chris@0
|
166 }
|
Chris@0
|
167 '),
|
Chris@0
|
168 array('
|
Chris@0
|
169 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@0
|
170 class Kappa {}
|
Chris@0
|
171 }
|
Chris@0
|
172 namespace {
|
Chris@0
|
173 new \\Psy\\Test\\CodeCleaner\\ValidClassNamePass\\Kappa();
|
Chris@0
|
174 }
|
Chris@0
|
175 '),
|
Chris@0
|
176
|
Chris@0
|
177 // Class constant fetch (ValidConstantPassTest validates the actual constant)
|
Chris@0
|
178 array('class A {} A::FOO'),
|
Chris@0
|
179 array('$a = new DateTime; $a::ATOM'),
|
Chris@0
|
180 array('interface A { const B = 1; } A::B'),
|
Chris@0
|
181
|
Chris@0
|
182 // static call
|
Chris@0
|
183 array('DateTime::createFromFormat()'),
|
Chris@0
|
184 array('DateTime::$someMethod()'),
|
Chris@0
|
185 array('Psy\Test\CodeCleaner\Fixtures\ClassWithStatic::doStuff()'),
|
Chris@0
|
186 array('Psy\Test\CodeCleaner\Fixtures\ClassWithCallStatic::doStuff()'),
|
Chris@0
|
187
|
Chris@0
|
188 // Allow `self` and `static` as class names.
|
Chris@0
|
189 array('
|
Chris@0
|
190 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@0
|
191 public static function getInstance() {
|
Chris@0
|
192 return new self();
|
Chris@0
|
193 }
|
Chris@0
|
194 }
|
Chris@0
|
195 '),
|
Chris@0
|
196 array('
|
Chris@0
|
197 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@0
|
198 public static function getInstance() {
|
Chris@0
|
199 return new SELF();
|
Chris@0
|
200 }
|
Chris@0
|
201 }
|
Chris@0
|
202 '),
|
Chris@0
|
203 array('
|
Chris@0
|
204 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@0
|
205 public static function getInstance() {
|
Chris@0
|
206 return new self;
|
Chris@0
|
207 }
|
Chris@0
|
208 }
|
Chris@0
|
209 '),
|
Chris@0
|
210 array('
|
Chris@0
|
211 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@0
|
212 public static function getInstance() {
|
Chris@0
|
213 return new static();
|
Chris@0
|
214 }
|
Chris@0
|
215 }
|
Chris@0
|
216 '),
|
Chris@0
|
217 array('
|
Chris@0
|
218 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@0
|
219 public static function getInstance() {
|
Chris@0
|
220 return new Static();
|
Chris@0
|
221 }
|
Chris@0
|
222 }
|
Chris@0
|
223 '),
|
Chris@0
|
224 array('
|
Chris@0
|
225 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@0
|
226 public static function getInstance() {
|
Chris@0
|
227 return new static;
|
Chris@0
|
228 }
|
Chris@0
|
229 }
|
Chris@0
|
230 '),
|
Chris@0
|
231 array('
|
Chris@0
|
232 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@0
|
233 public static function foo() {
|
Chris@0
|
234 return parent::bar();
|
Chris@0
|
235 }
|
Chris@0
|
236 }
|
Chris@0
|
237 '),
|
Chris@0
|
238 array('
|
Chris@0
|
239 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@0
|
240 public static function foo() {
|
Chris@0
|
241 return self::bar();
|
Chris@0
|
242 }
|
Chris@0
|
243 }
|
Chris@0
|
244 '),
|
Chris@0
|
245 array('
|
Chris@0
|
246 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@0
|
247 public static function foo() {
|
Chris@0
|
248 return static::bar();
|
Chris@0
|
249 }
|
Chris@0
|
250 }
|
Chris@0
|
251 '),
|
Chris@0
|
252
|
Chris@0
|
253 array('class A { static function b() { return new A; } }'),
|
Chris@0
|
254 array('
|
Chris@0
|
255 class A {
|
Chris@0
|
256 const B = 123;
|
Chris@0
|
257 function c() {
|
Chris@0
|
258 return A::B;
|
Chris@0
|
259 }
|
Chris@0
|
260 }
|
Chris@0
|
261 '),
|
Chris@0
|
262 array('class A {} class B { function c() { return new A; } }'),
|
Chris@0
|
263
|
Chris@0
|
264 // recursion
|
Chris@0
|
265 array('class A { function a() { A::a(); } }'),
|
Chris@0
|
266
|
Chris@0
|
267 // conditionally defined classes
|
Chris@0
|
268 array('
|
Chris@0
|
269 class A {}
|
Chris@0
|
270 if (false) {
|
Chris@0
|
271 class A {}
|
Chris@0
|
272 }
|
Chris@0
|
273 '),
|
Chris@0
|
274 array('
|
Chris@0
|
275 class A {}
|
Chris@0
|
276 if (true) {
|
Chris@0
|
277 class A {}
|
Chris@0
|
278 } else if (false) {
|
Chris@0
|
279 class A {}
|
Chris@0
|
280 } else {
|
Chris@0
|
281 class A {}
|
Chris@0
|
282 }
|
Chris@0
|
283 '),
|
Chris@0
|
284 // ewww
|
Chris@0
|
285 array('
|
Chris@0
|
286 class A {}
|
Chris@0
|
287 if (true):
|
Chris@0
|
288 class A {}
|
Chris@0
|
289 elseif (false):
|
Chris@0
|
290 class A {}
|
Chris@0
|
291 else:
|
Chris@0
|
292 class A {}
|
Chris@0
|
293 endif;
|
Chris@0
|
294 '),
|
Chris@0
|
295 array('
|
Chris@0
|
296 class A {}
|
Chris@0
|
297 while (false) { class A {} }
|
Chris@0
|
298 '),
|
Chris@0
|
299 array('
|
Chris@0
|
300 class A {}
|
Chris@0
|
301 do { class A {} } while (false);
|
Chris@0
|
302 '),
|
Chris@0
|
303 array('
|
Chris@0
|
304 class A {}
|
Chris@0
|
305 switch (1) {
|
Chris@0
|
306 case 0:
|
Chris@0
|
307 class A {}
|
Chris@0
|
308 break;
|
Chris@0
|
309 case 1:
|
Chris@0
|
310 class A {}
|
Chris@0
|
311 break;
|
Chris@0
|
312 case 2:
|
Chris@0
|
313 class A {}
|
Chris@0
|
314 break;
|
Chris@0
|
315 }
|
Chris@0
|
316 '),
|
Chris@0
|
317 );
|
Chris@0
|
318
|
Chris@0
|
319 // Ugh. There's gotta be a better way to test for this.
|
Chris@0
|
320 if (class_exists('PhpParser\ParserFactory')) {
|
Chris@0
|
321 // PHP 7.0 anonymous classes, only supported by PHP Parser v2.x
|
Chris@0
|
322 $valid[] = array('$obj = new class() {}');
|
Chris@0
|
323 }
|
Chris@0
|
324
|
Chris@0
|
325 if (version_compare(PHP_VERSION, '5.5', '>=')) {
|
Chris@0
|
326 $valid[] = array('interface A {} A::class');
|
Chris@0
|
327 $valid[] = array('interface A {} A::CLASS');
|
Chris@0
|
328 $valid[] = array('class A {} A::class');
|
Chris@0
|
329 $valid[] = array('class A {} A::CLASS');
|
Chris@0
|
330 $valid[] = array('A::class');
|
Chris@0
|
331 $valid[] = array('A::CLASS');
|
Chris@0
|
332 }
|
Chris@0
|
333
|
Chris@0
|
334 return $valid;
|
Chris@0
|
335 }
|
Chris@0
|
336 }
|