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@13
|
112 ];
|
Chris@13
|
113 }
|
Chris@13
|
114
|
Chris@13
|
115 /**
|
Chris@13
|
116 * @dataProvider getValid
|
Chris@13
|
117 */
|
Chris@13
|
118 public function testProcessValid($code)
|
Chris@13
|
119 {
|
Chris@13
|
120 $this->parseAndTraverse($code);
|
Chris@13
|
121 $this->assertTrue(true);
|
Chris@13
|
122 }
|
Chris@13
|
123
|
Chris@13
|
124 public function getValid()
|
Chris@13
|
125 {
|
Chris@13
|
126 $valid = [
|
Chris@13
|
127 // class declarations
|
Chris@13
|
128 ['class Psy_Test_CodeCleaner_ValidClassNamePass_Epsilon {}'],
|
Chris@13
|
129 ['namespace Psy\Test\CodeCleaner\ValidClassNamePass; class Zeta {}'],
|
Chris@13
|
130 ['
|
Chris@13
|
131 namespace { class Psy_Test_CodeCleaner_ValidClassNamePass_Eta {}; }
|
Chris@13
|
132 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@13
|
133 class Psy_Test_CodeCleaner_ValidClassNamePass_Eta {}
|
Chris@13
|
134 }
|
Chris@13
|
135 '],
|
Chris@13
|
136 ['namespace Psy\Test\CodeCleaner\ValidClassNamePass { class stdClass {} }'],
|
Chris@13
|
137
|
Chris@13
|
138 // class instantiations
|
Chris@13
|
139 ['new stdClass();'],
|
Chris@13
|
140 ['new stdClass();'],
|
Chris@13
|
141 ['
|
Chris@13
|
142 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@13
|
143 class Theta {}
|
Chris@13
|
144 }
|
Chris@13
|
145 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@13
|
146 new Theta();
|
Chris@13
|
147 }
|
Chris@13
|
148 '],
|
Chris@13
|
149 ['
|
Chris@13
|
150 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@13
|
151 class Iota {}
|
Chris@13
|
152 new Iota();
|
Chris@13
|
153 }
|
Chris@13
|
154 '],
|
Chris@13
|
155 ['
|
Chris@13
|
156 namespace Psy\\Test\\CodeCleaner\\ValidClassNamePass {
|
Chris@13
|
157 class Kappa {}
|
Chris@13
|
158 }
|
Chris@13
|
159 namespace {
|
Chris@13
|
160 new \\Psy\\Test\\CodeCleaner\\ValidClassNamePass\\Kappa();
|
Chris@13
|
161 }
|
Chris@13
|
162 '],
|
Chris@13
|
163
|
Chris@13
|
164 // Class constant fetch (ValidConstantPassTest validates the actual constant)
|
Chris@13
|
165 ['class A {} A::FOO'],
|
Chris@13
|
166 ['$a = new DateTime; $a::ATOM'],
|
Chris@13
|
167 ['interface A { const B = 1; } A::B'],
|
Chris@13
|
168
|
Chris@13
|
169 // static call
|
Chris@13
|
170 ['DateTime::createFromFormat()'],
|
Chris@13
|
171 ['DateTime::$someMethod()'],
|
Chris@13
|
172 ['Psy\Test\CodeCleaner\Fixtures\ClassWithStatic::doStuff()'],
|
Chris@13
|
173 ['Psy\Test\CodeCleaner\Fixtures\ClassWithCallStatic::doStuff()'],
|
Chris@13
|
174
|
Chris@13
|
175 // Allow `self` and `static` as class names.
|
Chris@13
|
176 ['
|
Chris@13
|
177 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
178 public static function getInstance() {
|
Chris@13
|
179 return new self();
|
Chris@13
|
180 }
|
Chris@13
|
181 }
|
Chris@13
|
182 '],
|
Chris@13
|
183 ['
|
Chris@13
|
184 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
185 public static function getInstance() {
|
Chris@13
|
186 return new SELF();
|
Chris@13
|
187 }
|
Chris@13
|
188 }
|
Chris@13
|
189 '],
|
Chris@13
|
190 ['
|
Chris@13
|
191 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
192 public static function getInstance() {
|
Chris@13
|
193 return new self;
|
Chris@13
|
194 }
|
Chris@13
|
195 }
|
Chris@13
|
196 '],
|
Chris@13
|
197 ['
|
Chris@13
|
198 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
199 public static function getInstance() {
|
Chris@13
|
200 return new static();
|
Chris@13
|
201 }
|
Chris@13
|
202 }
|
Chris@13
|
203 '],
|
Chris@13
|
204 ['
|
Chris@13
|
205 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
206 public static function getInstance() {
|
Chris@13
|
207 return new Static();
|
Chris@13
|
208 }
|
Chris@13
|
209 }
|
Chris@13
|
210 '],
|
Chris@13
|
211 ['
|
Chris@13
|
212 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
213 public static function getInstance() {
|
Chris@13
|
214 return new static;
|
Chris@13
|
215 }
|
Chris@13
|
216 }
|
Chris@13
|
217 '],
|
Chris@13
|
218 ['
|
Chris@13
|
219 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
220 public static function foo() {
|
Chris@13
|
221 return parent::bar();
|
Chris@13
|
222 }
|
Chris@13
|
223 }
|
Chris@13
|
224 '],
|
Chris@13
|
225 ['
|
Chris@13
|
226 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
227 public static function foo() {
|
Chris@13
|
228 return self::bar();
|
Chris@13
|
229 }
|
Chris@13
|
230 }
|
Chris@13
|
231 '],
|
Chris@13
|
232 ['
|
Chris@13
|
233 class Psy_Test_CodeCleaner_ValidClassNamePass_ClassWithStatic {
|
Chris@13
|
234 public static function foo() {
|
Chris@13
|
235 return static::bar();
|
Chris@13
|
236 }
|
Chris@13
|
237 }
|
Chris@13
|
238 '],
|
Chris@13
|
239
|
Chris@13
|
240 ['class A { static function b() { return new A; } }'],
|
Chris@13
|
241 ['
|
Chris@13
|
242 class A {
|
Chris@13
|
243 const B = 123;
|
Chris@13
|
244 function c() {
|
Chris@13
|
245 return A::B;
|
Chris@13
|
246 }
|
Chris@13
|
247 }
|
Chris@13
|
248 '],
|
Chris@13
|
249 ['class A {} class B { function c() { return new A; } }'],
|
Chris@13
|
250
|
Chris@13
|
251 // recursion
|
Chris@13
|
252 ['class A { function a() { A::a(); } }'],
|
Chris@13
|
253
|
Chris@13
|
254 // conditionally defined classes
|
Chris@13
|
255 ['
|
Chris@13
|
256 class A {}
|
Chris@13
|
257 if (false) {
|
Chris@13
|
258 class A {}
|
Chris@13
|
259 }
|
Chris@13
|
260 '],
|
Chris@13
|
261 ['
|
Chris@13
|
262 class A {}
|
Chris@13
|
263 if (true) {
|
Chris@13
|
264 class A {}
|
Chris@13
|
265 } else if (false) {
|
Chris@13
|
266 class A {}
|
Chris@13
|
267 } else {
|
Chris@13
|
268 class A {}
|
Chris@13
|
269 }
|
Chris@13
|
270 '],
|
Chris@13
|
271 // ewww
|
Chris@13
|
272 ['
|
Chris@13
|
273 class A {}
|
Chris@13
|
274 if (true):
|
Chris@13
|
275 class A {}
|
Chris@13
|
276 elseif (false):
|
Chris@13
|
277 class A {}
|
Chris@13
|
278 else:
|
Chris@13
|
279 class A {}
|
Chris@13
|
280 endif;
|
Chris@13
|
281 '],
|
Chris@13
|
282 ['
|
Chris@13
|
283 class A {}
|
Chris@13
|
284 while (false) { class A {} }
|
Chris@13
|
285 '],
|
Chris@13
|
286 ['
|
Chris@13
|
287 class A {}
|
Chris@13
|
288 do { class A {} } while (false);
|
Chris@13
|
289 '],
|
Chris@13
|
290 ['
|
Chris@13
|
291 class A {}
|
Chris@13
|
292 switch (1) {
|
Chris@13
|
293 case 0:
|
Chris@13
|
294 class A {}
|
Chris@13
|
295 break;
|
Chris@13
|
296 case 1:
|
Chris@13
|
297 class A {}
|
Chris@13
|
298 break;
|
Chris@13
|
299 case 2:
|
Chris@13
|
300 class A {}
|
Chris@13
|
301 break;
|
Chris@13
|
302 }
|
Chris@13
|
303 '],
|
Chris@13
|
304 ];
|
Chris@13
|
305
|
Chris@13
|
306 // Ugh. There's gotta be a better way to test for this.
|
Chris@13
|
307 if (class_exists('PhpParser\ParserFactory')) {
|
Chris@13
|
308 // PHP 7.0 anonymous classes, only supported by PHP Parser v2.x
|
Chris@13
|
309 $valid[] = ['$obj = new class() {}'];
|
Chris@13
|
310 }
|
Chris@13
|
311
|
Chris@13
|
312 if (version_compare(PHP_VERSION, '5.5', '>=')) {
|
Chris@13
|
313 $valid[] = ['interface A {} A::class'];
|
Chris@13
|
314 $valid[] = ['interface A {} A::CLASS'];
|
Chris@13
|
315 $valid[] = ['class A {} A::class'];
|
Chris@13
|
316 $valid[] = ['class A {} A::CLASS'];
|
Chris@13
|
317 $valid[] = ['A::class'];
|
Chris@13
|
318 $valid[] = ['A::CLASS'];
|
Chris@13
|
319 }
|
Chris@13
|
320
|
Chris@13
|
321 return $valid;
|
Chris@13
|
322 }
|
Chris@13
|
323 }
|