ValidClassNamePassTest.php 9.8 KB

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