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@17
|
175 ['Psy\Test\CodeCleaner\Fixtures\TraitWithStatic::doStuff()'],
|
Chris@13
|
176
|
Chris@13
|
177 // Allow `self` and `static` as class names.
|
Chris@13
|
178 ['
|
Chris@13
|
179 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
180 public static function getInstance() {
|
Chris@13
|
181 return new self();
|
Chris@13
|
182 }
|
Chris@13
|
183 }
|
Chris@13
|
184 '],
|
Chris@13
|
185 ['
|
Chris@13
|
186 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
187 public static function getInstance() {
|
Chris@13
|
188 return new SELF();
|
Chris@13
|
189 }
|
Chris@13
|
190 }
|
Chris@13
|
191 '],
|
Chris@13
|
192 ['
|
Chris@13
|
193 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
194 public static function getInstance() {
|
Chris@13
|
195 return new self;
|
Chris@13
|
196 }
|
Chris@13
|
197 }
|
Chris@13
|
198 '],
|
Chris@13
|
199 ['
|
Chris@13
|
200 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
201 public static function getInstance() {
|
Chris@13
|
202 return new static();
|
Chris@13
|
203 }
|
Chris@13
|
204 }
|
Chris@13
|
205 '],
|
Chris@13
|
206 ['
|
Chris@13
|
207 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
208 public static function getInstance() {
|
Chris@13
|
209 return new Static();
|
Chris@13
|
210 }
|
Chris@13
|
211 }
|
Chris@13
|
212 '],
|
Chris@13
|
213 ['
|
Chris@13
|
214 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
215 public static function getInstance() {
|
Chris@13
|
216 return new static;
|
Chris@13
|
217 }
|
Chris@13
|
218 }
|
Chris@13
|
219 '],
|
Chris@13
|
220 ['
|
Chris@13
|
221 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
222 public static function foo() {
|
Chris@13
|
223 return parent::bar();
|
Chris@13
|
224 }
|
Chris@13
|
225 }
|
Chris@13
|
226 '],
|
Chris@13
|
227 ['
|
Chris@13
|
228 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
229 public static function foo() {
|
Chris@13
|
230 return self::bar();
|
Chris@13
|
231 }
|
Chris@13
|
232 }
|
Chris@13
|
233 '],
|
Chris@13
|
234 ['
|
Chris@13
|
235 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
236 public static function foo() {
|
Chris@13
|
237 return static::bar();
|
Chris@13
|
238 }
|
Chris@13
|
239 }
|
Chris@13
|
240 '],
|
Chris@13
|
241
|
Chris@13
|
242 ['class A { static function b() { return new A; } }'],
|
Chris@13
|
243 ['
|
Chris@13
|
244 class A {
|
Chris@13
|
245 const B = 123;
|
Chris@13
|
246 function c() {
|
Chris@13
|
247 return A::B;
|
Chris@13
|
248 }
|
Chris@13
|
249 }
|
Chris@13
|
250 '],
|
Chris@13
|
251 ['class A {} class B { function c() { return new A; } }'],
|
Chris@13
|
252
|
Chris@13
|
253 // recursion
|
Chris@13
|
254 ['class A { function a() { A::a(); } }'],
|
Chris@13
|
255
|
Chris@13
|
256 // conditionally defined classes
|
Chris@13
|
257 ['
|
Chris@13
|
258 class A {}
|
Chris@13
|
259 if (false) {
|
Chris@13
|
260 class A {}
|
Chris@13
|
261 }
|
Chris@13
|
262 '],
|
Chris@13
|
263 ['
|
Chris@13
|
264 class A {}
|
Chris@13
|
265 if (true) {
|
Chris@13
|
266 class A {}
|
Chris@13
|
267 } else if (false) {
|
Chris@13
|
268 class A {}
|
Chris@13
|
269 } else {
|
Chris@13
|
270 class A {}
|
Chris@13
|
271 }
|
Chris@13
|
272 '],
|
Chris@13
|
273 // ewww
|
Chris@13
|
274 ['
|
Chris@13
|
275 class A {}
|
Chris@13
|
276 if (true):
|
Chris@13
|
277 class A {}
|
Chris@13
|
278 elseif (false):
|
Chris@13
|
279 class A {}
|
Chris@13
|
280 else:
|
Chris@13
|
281 class A {}
|
Chris@13
|
282 endif;
|
Chris@13
|
283 '],
|
Chris@13
|
284 ['
|
Chris@13
|
285 class A {}
|
Chris@13
|
286 while (false) { class A {} }
|
Chris@13
|
287 '],
|
Chris@13
|
288 ['
|
Chris@13
|
289 class A {}
|
Chris@13
|
290 do { class A {} } while (false);
|
Chris@13
|
291 '],
|
Chris@13
|
292 ['
|
Chris@13
|
293 class A {}
|
Chris@13
|
294 switch (1) {
|
Chris@13
|
295 case 0:
|
Chris@13
|
296 class A {}
|
Chris@13
|
297 break;
|
Chris@13
|
298 case 1:
|
Chris@13
|
299 class A {}
|
Chris@13
|
300 break;
|
Chris@13
|
301 case 2:
|
Chris@13
|
302 class A {}
|
Chris@13
|
303 break;
|
Chris@13
|
304 }
|
Chris@13
|
305 '],
|
Chris@13
|
306 ];
|
Chris@13
|
307
|
Chris@13
|
308 // Ugh. There's gotta be a better way to test for this.
|
Chris@17
|
309 if (\class_exists('PhpParser\ParserFactory')) {
|
Chris@13
|
310 // PHP 7.0 anonymous classes, only supported by PHP Parser v2.x
|
Chris@13
|
311 $valid[] = ['$obj = new class() {}'];
|
Chris@13
|
312 }
|
Chris@13
|
313
|
Chris@17
|
314 if (\version_compare(PHP_VERSION, '5.5', '>=')) {
|
Chris@13
|
315 $valid[] = ['interface A {} A::class'];
|
Chris@13
|
316 $valid[] = ['interface A {} A::CLASS'];
|
Chris@13
|
317 $valid[] = ['class A {} A::class'];
|
Chris@13
|
318 $valid[] = ['class A {} A::CLASS'];
|
Chris@13
|
319 $valid[] = ['A::class'];
|
Chris@13
|
320 $valid[] = ['A::CLASS'];
|
Chris@13
|
321 }
|
Chris@13
|
322
|
Chris@13
|
323 return $valid;
|
Chris@13
|
324 }
|
Chris@13
|
325 }
|