ValidClassNamePassTest.php 11 KB

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