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