/vendor/phpspec/prophecy/spec/Prophecy/Doubler/Generator/ClassMirrorSpec.php

https://gitlab.com/ealexis.t/trends · PHP · 784 lines · 574 code · 124 blank · 86 comment · 31 complexity · 286146bd32c2b5d400673147d96e4223 MD5 · raw file

  1. <?php
  2. namespace spec\Prophecy\Doubler\Generator;
  3. use I\Simply;
  4. use PhpSpec\ObjectBehavior;
  5. use ReflectionClass;
  6. use ReflectionMethod;
  7. use ReflectionParameter;
  8. class ClassMirrorSpec extends ObjectBehavior
  9. {
  10. /**
  11. * @param ReflectionClass $class
  12. * @param ReflectionClass $parent
  13. * @param ReflectionMethod $method1
  14. * @param ReflectionMethod $method2
  15. * @param ReflectionMethod $method3
  16. */
  17. function it_reflects_a_class_by_mirroring_all_its_public_methods(
  18. $class, $parent, $method1, $method2, $method3
  19. )
  20. {
  21. $class->getName()->willReturn('Custom\ClassName');
  22. $class->getParentClass()->willReturn($parent);
  23. $class->isInterface()->willReturn(false);
  24. $class->isFinal()->willReturn(false);
  25. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array());
  26. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array(
  27. $method1, $method2, $method3
  28. ));
  29. $parent->getName()->willReturn('Custom\ParentClassName');
  30. $method1->getDeclaringClass()->willReturn($class);
  31. $method2->getDeclaringClass()->willReturn($class);
  32. $method3->getDeclaringClass()->willReturn($class);
  33. $method1->getName()->willReturn('getName');
  34. $method2->getName()->willReturn('getSelf');
  35. $method3->getName()->willReturn('getParent');
  36. $method1->isFinal()->willReturn(false);
  37. $method2->isFinal()->willReturn(false);
  38. $method3->isFinal()->willReturn(false);
  39. $method1->isProtected()->willReturn(false);
  40. $method2->isProtected()->willReturn(false);
  41. $method3->isProtected()->willReturn(false);
  42. $method1->isStatic()->willReturn(false);
  43. $method2->isStatic()->willReturn(false);
  44. $method3->isStatic()->willReturn(false);
  45. $method1->returnsReference()->willReturn(false);
  46. $method2->returnsReference()->willReturn(false);
  47. $method3->returnsReference()->willReturn(false);
  48. $method1->getParameters()->willReturn(array());
  49. $method2->getParameters()->willReturn(array());
  50. $method3->getParameters()->willReturn(array());
  51. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  52. $method1->hasReturnType()->willReturn(true);
  53. $method1->getReturnType()->willReturn('string');
  54. $method2->hasReturnType()->willReturn(true);
  55. $method2->getReturnType()->willReturn('self');
  56. $method3->hasReturnType()->willReturn(true);
  57. $method3->getReturnType()->willReturn('parent');
  58. }
  59. $classNode = $this->reflect($class, array());
  60. $classNode->shouldBeAnInstanceOf('Prophecy\Doubler\Generator\Node\ClassNode');
  61. $classNode->getParentClass()->shouldReturn('Custom\ClassName');
  62. $methodNodes = $classNode->getMethods();
  63. $methodNodes->shouldHaveCount(3);
  64. $classNode->hasMethod('getName')->shouldReturn(true);
  65. $classNode->hasMethod('getSelf')->shouldReturn(true);
  66. $classNode->hasMethod('getParent')->shouldReturn(true);
  67. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  68. $classNode->getMethod('getName')->getReturnType()->shouldReturn('string');
  69. $classNode->getMethod('getSelf')->getReturnType()->shouldReturn('\Custom\ClassName');
  70. $classNode->getMethod('getParent')->getReturnType()->shouldReturn('\Custom\ParentClassName');
  71. }
  72. }
  73. /**
  74. * @param ReflectionClass $class
  75. * @param ReflectionMethod $method
  76. * @param ReflectionParameter $parameter
  77. */
  78. function it_changes_argument_names_if_they_are_varying($class, $method, $parameter)
  79. {
  80. $class->getName()->willReturn('Custom\ClassName');
  81. $class->isInterface()->willReturn(false);
  82. $class->isFinal()->willReturn(false);
  83. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array($method));
  84. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array());
  85. $method->getParameters()->willReturn(array($parameter));
  86. $method->getName()->willReturn('methodName');
  87. $method->isFinal()->willReturn(false);
  88. $method->isProtected()->willReturn(false);
  89. $method->isStatic()->willReturn(false);
  90. $method->returnsReference()->willReturn(false);
  91. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  92. $method->hasReturnType()->willReturn(false);
  93. }
  94. $parameter->getName()->willReturn('...');
  95. $parameter->isDefaultValueAvailable()->willReturn(true);
  96. $parameter->getDefaultValue()->willReturn(null);
  97. $parameter->isPassedByReference()->willReturn(false);
  98. $parameter->getClass()->willReturn($class);
  99. if (version_compare(PHP_VERSION, '5.6', '>=')) {
  100. $parameter->isVariadic()->willReturn(false);
  101. }
  102. $classNode = $this->reflect($class, array());
  103. $methodNodes = $classNode->getMethods();
  104. $argumentNodes = $methodNodes['methodName']->getArguments();
  105. $argumentNode = $argumentNodes[0];
  106. $argumentNode->getName()->shouldReturn('__dot_dot_dot__');
  107. }
  108. /**
  109. * @param ReflectionClass $class
  110. * @param ReflectionMethod $method
  111. */
  112. function it_reflects_protected_abstract_methods($class, $method)
  113. {
  114. $class->getName()->willReturn('Custom\ClassName');
  115. $class->isInterface()->willReturn(false);
  116. $class->isFinal()->willReturn(false);
  117. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array($method));
  118. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array());
  119. $method->isProtected()->willReturn(true);
  120. $method->isStatic()->willReturn(false);
  121. $method->getParameters()->willReturn(array());
  122. $method->getName()->willReturn('innerDetail');
  123. $method->returnsReference()->willReturn(false);
  124. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  125. $method->hasReturnType()->willReturn(false);
  126. }
  127. $classNode = $this->reflect($class, array());
  128. $classNode->shouldBeAnInstanceOf('Prophecy\Doubler\Generator\Node\ClassNode');
  129. $classNode->getParentClass()->shouldReturn('Custom\ClassName');
  130. $methodNodes = $classNode->getMethods();
  131. $methodNodes->shouldHaveCount(1);
  132. $methodNodes['innerDetail']->getVisibility()->shouldReturn('protected');
  133. }
  134. /**
  135. * @param ReflectionClass $class
  136. * @param ReflectionMethod $method
  137. */
  138. function it_reflects_public_static_methods($class, $method)
  139. {
  140. $class->getName()->willReturn('Custom\ClassName');
  141. $class->isInterface()->willReturn(false);
  142. $class->isFinal()->willReturn(false);
  143. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array($method));
  144. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array());
  145. $method->isProtected()->willReturn(true);
  146. $method->isStatic()->willReturn(true);
  147. $method->getParameters()->willReturn(array());
  148. $method->getName()->willReturn('innerDetail');
  149. $method->returnsReference()->willReturn(false);
  150. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  151. $method->hasReturnType()->willReturn(false);
  152. }
  153. $classNode = $this->reflect($class, array());
  154. $classNode->shouldBeAnInstanceOf('Prophecy\Doubler\Generator\Node\ClassNode');
  155. $classNode->getParentClass()->shouldReturn('Custom\ClassName');
  156. $methodNodes = $classNode->getMethods();
  157. $methodNodes->shouldHaveCount(1);
  158. $methodNodes['innerDetail']->getVisibility()->shouldReturn('protected');
  159. $methodNodes['innerDetail']->isStatic()->shouldReturn(true);
  160. }
  161. /**
  162. * @param ReflectionClass $class
  163. * @param ReflectionMethod $constructMethod
  164. * @param ReflectionMethod $destructMethod
  165. * @param ReflectionMethod $sleepMethod
  166. * @param ReflectionMethod $wakeupMethod
  167. * @param ReflectionMethod $toStringMethod
  168. * @param ReflectionMethod $callMethod
  169. * @param ReflectionMethod $invokeMethod
  170. */
  171. function it_reflects_allowed_magic_methods($class, $constructMethod, $destructMethod, $sleepMethod, $wakeupMethod, $toStringMethod, $callMethod, $invokeMethod)
  172. {
  173. $class->getName()->willReturn('Custom\ClassName');
  174. $class->isInterface()->willReturn(false);
  175. $class->isFinal()->willReturn(false);
  176. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array());
  177. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array(
  178. $constructMethod, $destructMethod, $sleepMethod, $wakeupMethod, $toStringMethod, $callMethod, $invokeMethod
  179. ));
  180. $constructMethod->getName()->willReturn('__construct');
  181. $destructMethod->getName()->willReturn('__destruct');
  182. $sleepMethod->getName()->willReturn('__sleep');
  183. $wakeupMethod->getName()->willReturn('__wakeup');
  184. $toStringMethod->getName()->willReturn('__toString');
  185. $callMethod->getName()->willReturn('__call');
  186. $invokeMethod->getName()->willReturn('__invoke');
  187. $constructMethod->isFinal()->willReturn(false);
  188. $destructMethod->isFinal()->willReturn(false);
  189. $sleepMethod->isFinal()->willReturn(false);
  190. $wakeupMethod->isFinal()->willReturn(false);
  191. $toStringMethod->isFinal()->willReturn(false);
  192. $callMethod->isFinal()->willReturn(false);
  193. $invokeMethod->isFinal()->willReturn(false);
  194. $constructMethod->isProtected()->willReturn(false);
  195. $destructMethod->isProtected()->willReturn(false);
  196. $sleepMethod->isProtected()->willReturn(false);
  197. $wakeupMethod->isProtected()->willReturn(false);
  198. $toStringMethod->isProtected()->willReturn(false);
  199. $callMethod->isProtected()->willReturn(false);
  200. $invokeMethod->isProtected()->willReturn(false);
  201. $constructMethod->isStatic()->willReturn(false);
  202. $destructMethod->isStatic()->willReturn(false);
  203. $sleepMethod->isStatic()->willReturn(false);
  204. $wakeupMethod->isStatic()->willReturn(false);
  205. $toStringMethod->isStatic()->willReturn(false);
  206. $callMethod->isStatic()->willReturn(false);
  207. $invokeMethod->isStatic()->willReturn(false);
  208. $constructMethod->returnsReference()->willReturn(false);
  209. $destructMethod->returnsReference()->willReturn(false);
  210. $sleepMethod->returnsReference()->willReturn(false);
  211. $wakeupMethod->returnsReference()->willReturn(false);
  212. $toStringMethod->returnsReference()->willReturn(false);
  213. $callMethod->returnsReference()->willReturn(false);
  214. $invokeMethod->returnsReference()->willReturn(false);
  215. $constructMethod->getParameters()->willReturn(array());
  216. $destructMethod->getParameters()->willReturn(array());
  217. $sleepMethod->getParameters()->willReturn(array());
  218. $wakeupMethod->getParameters()->willReturn(array());
  219. $toStringMethod->getParameters()->willReturn(array());
  220. $callMethod->getParameters()->willReturn(array());
  221. $invokeMethod->getParameters()->willReturn(array());
  222. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  223. $constructMethod->hasReturnType()->willReturn(false);
  224. $destructMethod->hasReturnType()->willReturn(false);
  225. $sleepMethod->hasReturnType()->willReturn(false);
  226. $wakeupMethod->hasReturnType()->willReturn(false);
  227. $toStringMethod->hasReturnType()->willReturn(false);
  228. $callMethod->hasReturnType()->willReturn(false);
  229. $invokeMethod->hasReturnType()->willReturn(false);
  230. }
  231. $classNode = $this->reflect($class, array());
  232. $classNode->shouldBeAnInstanceOf('Prophecy\Doubler\Generator\Node\ClassNode');
  233. $classNode->getParentClass()->shouldReturn('Custom\ClassName');
  234. $methodNodes = $classNode->getMethods();
  235. $methodNodes->shouldHaveCount(7);
  236. }
  237. /**
  238. * @param ReflectionClass $class
  239. * @param ReflectionMethod $method
  240. * @param ReflectionParameter $param1
  241. * @param ReflectionParameter $param2
  242. * @param ReflectionClass $typeHint
  243. * @param ReflectionParameter $param3
  244. * @param ReflectionParameter $param4
  245. */
  246. function it_properly_reads_methods_arguments_with_types(
  247. $class, $method, $param1, $param2, $typeHint, $param3, $param4
  248. )
  249. {
  250. $class->getName()->willReturn('Custom\ClassName');
  251. $class->isInterface()->willReturn(false);
  252. $class->isFinal()->willReturn(false);
  253. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array());
  254. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array($method));
  255. $method->getName()->willReturn('methodWithArgs');
  256. $method->isFinal()->willReturn(false);
  257. $method->isProtected()->willReturn(true);
  258. $method->isStatic()->willReturn(false);
  259. $method->returnsReference()->willReturn(false);
  260. $method->getParameters()->willReturn(array($param1, $param2, $param3, $param4));
  261. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  262. $method->hasReturnType()->willReturn(false);
  263. }
  264. $param1->getName()->willReturn('arg_1');
  265. $param1->isArray()->willReturn(true);
  266. $param1->getClass()->willReturn(null);
  267. $param1->isDefaultValueAvailable()->willReturn(true);
  268. $param1->isPassedByReference()->willReturn(false);
  269. $param1->allowsNull()->willReturn(false);
  270. $param1->getDefaultValue()->willReturn(array());
  271. $param2->getName()->willReturn('arg2');
  272. $param2->isArray()->willReturn(false);
  273. $param2->getClass()->willReturn($typeHint);
  274. $param2->isDefaultValueAvailable()->willReturn(false);
  275. $param2->isOptional()->willReturn(false);
  276. $param2->isPassedByReference()->willReturn(false);
  277. $param2->allowsNull()->willReturn(false);
  278. $typeHint->getName()->willReturn('ArrayAccess');
  279. $param3->getName()->willReturn('arg_3');
  280. $param3->isArray()->willReturn(false);
  281. if (version_compare(PHP_VERSION, '5.4', '>=')) {
  282. $param3->isCallable()->willReturn(true);
  283. }
  284. $param3->getClass()->willReturn(null);
  285. $param3->isOptional()->willReturn(false);
  286. $param3->isDefaultValueAvailable()->willReturn(false);
  287. $param3->isPassedByReference()->willReturn(false);
  288. $param3->allowsNull()->willReturn(true);
  289. $param4->getName()->willReturn('arg_4');
  290. $param4->isArray()->willReturn(false);
  291. $param4->getClass()->willReturn($typeHint);
  292. $param4->isPassedByReference()->willReturn(false);
  293. $param4->allowsNull()->willReturn(true);
  294. if (version_compare(PHP_VERSION, '5.6', '>=')) {
  295. $param1->isVariadic()->willReturn(false);
  296. $param2->isVariadic()->willReturn(false);
  297. $param3->isVariadic()->willReturn(false);
  298. $param4->isVariadic()->willReturn(true);
  299. } else {
  300. $param4->isOptional()->willReturn(true);
  301. $param4->isDefaultValueAvailable()->willReturn(false);
  302. }
  303. $classNode = $this->reflect($class, array());
  304. $methodNodes = $classNode->getMethods();
  305. $argNodes = $methodNodes['methodWithArgs']->getArguments();
  306. $argNodes[0]->getName()->shouldReturn('arg_1');
  307. $argNodes[0]->getTypeHint()->shouldReturn('array');
  308. $argNodes[0]->isOptional()->shouldReturn(true);
  309. $argNodes[0]->getDefault()->shouldReturn(array());
  310. $argNodes[1]->getName()->shouldReturn('arg2');
  311. $argNodes[1]->getTypeHint()->shouldReturn('ArrayAccess');
  312. $argNodes[1]->isOptional()->shouldReturn(false);
  313. $argNodes[2]->getName()->shouldReturn('arg_3');
  314. if (version_compare(PHP_VERSION, '5.4', '>=')) {
  315. $argNodes[2]->getTypeHint()->shouldReturn('callable');
  316. $argNodes[2]->isOptional()->shouldReturn(true);
  317. $argNodes[2]->getDefault()->shouldReturn(null);
  318. } else {
  319. $argNodes[2]->isOptional()->shouldReturn(false);
  320. }
  321. $argNodes[3]->getName()->shouldReturn('arg_4');
  322. $argNodes[3]->getTypeHint()->shouldReturn('ArrayAccess');
  323. if (version_compare(PHP_VERSION, '5.6', '>=')) {
  324. $argNodes[3]->isVariadic()->shouldReturn(true);
  325. } else {
  326. $argNodes[3]->isOptional()->shouldReturn(true);
  327. $argNodes[3]->getDefault()->shouldReturn(null);
  328. }
  329. }
  330. /**
  331. * @param ReflectionClass $class
  332. * @param ReflectionMethod $method
  333. * @param ReflectionParameter $param1
  334. */
  335. function it_marks_required_args_without_types_as_not_optional(
  336. $class, $method, $param1
  337. )
  338. {
  339. $class->getName()->willReturn('Custom\ClassName');
  340. $class->isInterface()->willReturn(false);
  341. $class->isFinal()->willReturn(false);
  342. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array());
  343. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array($method));
  344. $method->getName()->willReturn('methodWithArgs');
  345. $method->isFinal()->willReturn(false);
  346. $method->isProtected()->willReturn(false);
  347. $method->isStatic()->willReturn(false);
  348. $method->returnsReference()->willReturn(false);
  349. $method->getParameters()->willReturn(array($param1));
  350. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  351. $method->hasReturnType()->willReturn(false);
  352. }
  353. $param1->getName()->willReturn('arg_1');
  354. $param1->isArray()->willReturn(false);
  355. if (version_compare(PHP_VERSION, '5.4', '>=')) {
  356. $param1->isCallable()->willReturn(false);
  357. }
  358. $param1->getClass()->willReturn(null);
  359. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  360. $param1->hasType()->willReturn(false);
  361. }
  362. if (version_compare(PHP_VERSION, '5.6', '>=')) {
  363. $param1->isVariadic()->willReturn(false);
  364. }
  365. $param1->isDefaultValueAvailable()->willReturn(false);
  366. $param1->isOptional()->willReturn(false);
  367. $param1->isPassedByReference()->willReturn(false);
  368. $param1->allowsNull()->willReturn(true);
  369. if (defined('HHVM_VERSION')) {
  370. $param1->getTypehintText()->willReturn(null);
  371. }
  372. $classNode = $this->reflect($class, array());
  373. $methodNodes = $classNode->getMethods();
  374. $argNodes = $methodNodes['methodWithArgs']->getArguments();
  375. $argNodes[0]->isOptional()->shouldReturn(false);
  376. }
  377. /**
  378. * @param ReflectionClass $class
  379. * @param ReflectionMethod $method
  380. * @param ReflectionParameter $param1
  381. * @param ReflectionParameter $param2
  382. * @param ReflectionParameter $param3
  383. * @param ReflectionClass $typeHint
  384. */
  385. function it_marks_passed_by_reference_args_as_passed_by_reference(
  386. $class, $method, $param1, $param2, $param3, $typeHint
  387. )
  388. {
  389. $class->getName()->willReturn('Custom\ClassName');
  390. $class->isInterface()->willReturn(false);
  391. $class->isFinal()->willReturn(false);
  392. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array());
  393. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array($method));
  394. $method->getName()->willReturn('methodWithArgs');
  395. $method->isFinal()->willReturn(false);
  396. $method->isProtected()->willReturn(false);
  397. $method->isStatic()->willReturn(false);
  398. $method->returnsReference()->willReturn(false);
  399. $method->getParameters()->willReturn(array($param1, $param2, $param3));
  400. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  401. $method->hasReturnType()->willReturn(false);
  402. }
  403. $param1->getName()->willReturn('arg_1');
  404. $param1->isArray()->willReturn(false);
  405. if (version_compare(PHP_VERSION, '5.4', '>=')) {
  406. $param1->isCallable()->willReturn(false);
  407. }
  408. $param1->getClass()->willReturn(null);
  409. if (version_compare(PHP_VERSION, '5.6', '>=')) {
  410. $param1->isVariadic()->willReturn(false);
  411. }
  412. $param1->isDefaultValueAvailable()->willReturn(false);
  413. $param1->isOptional()->willReturn(true);
  414. $param1->isPassedByReference()->willReturn(true);
  415. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  416. $param1->hasType()->willReturn(false);
  417. }
  418. $param1->allowsNull()->willReturn(false);
  419. if (defined('HHVM_VERSION')) {
  420. $param1->getTypehintText()->willReturn(null);
  421. }
  422. $param2->getName()->willReturn('arg2');
  423. $param2->isArray()->willReturn(false);
  424. $param2->getClass()->willReturn($typeHint);
  425. if (version_compare(PHP_VERSION, '5.6', '>=')) {
  426. $param2->isVariadic()->willReturn(false);
  427. }
  428. $param2->isDefaultValueAvailable()->willReturn(false);
  429. $param2->isOptional()->willReturn(false);
  430. $param2->isPassedByReference()->willReturn(false);
  431. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  432. $param2->hasType()->willReturn(false);
  433. }
  434. $param2->allowsNull()->willReturn(false);
  435. $typeHint->getName()->willReturn('ArrayAccess');
  436. $param3->getName()->willReturn('arg2');
  437. $param3->isArray()->willReturn(false);
  438. $param3->getClass()->willReturn($typeHint);
  439. if (version_compare(PHP_VERSION, '5.6', '>=')) {
  440. $param3->isVariadic()->willReturn(true);
  441. } else {
  442. $param3->isOptional()->willReturn(true);
  443. $param3->isDefaultValueAvailable()->willReturn(false);
  444. }
  445. $param3->isPassedByReference()->willReturn(true);
  446. $param3->allowsNull()->willReturn(true);
  447. $classNode = $this->reflect($class, array());
  448. $methodNodes = $classNode->getMethods();
  449. $argNodes = $methodNodes['methodWithArgs']->getArguments();
  450. $argNodes[0]->isPassedByReference()->shouldReturn(true);
  451. $argNodes[1]->isPassedByReference()->shouldReturn(false);
  452. $argNodes[2]->isPassedByReference()->shouldReturn(true);
  453. }
  454. /**
  455. * @param ReflectionClass $class
  456. */
  457. function it_throws_an_exception_if_class_is_final($class)
  458. {
  459. $class->isInterface()->willReturn(false);
  460. $class->isFinal()->willReturn(true);
  461. $class->getName()->willReturn('Custom\ClassName');
  462. $this->shouldThrow('Prophecy\Exception\Doubler\ClassMirrorException')
  463. ->duringReflect($class, array());
  464. }
  465. /**
  466. * @param ReflectionClass $class
  467. * @param ReflectionMethod $method
  468. */
  469. function it_ignores_final_methods($class, $method)
  470. {
  471. $class->getName()->willReturn('Custom\ClassName');
  472. $class->isInterface()->willReturn(false);
  473. $class->isFinal()->willReturn(false);
  474. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array());
  475. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array($method));
  476. $method->isFinal()->willReturn(true);
  477. $method->getName()->willReturn('finalImplementation');
  478. $classNode = $this->reflect($class, array());
  479. $classNode->getMethods()->shouldHaveCount(0);
  480. }
  481. /**
  482. * @param ReflectionClass $class
  483. * @param ReflectionMethod $method
  484. */
  485. function it_marks_final_methods_as_unextendable($class, $method)
  486. {
  487. $class->getName()->willReturn('Custom\ClassName');
  488. $class->isInterface()->willReturn(false);
  489. $class->isFinal()->willReturn(false);
  490. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array());
  491. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array($method));
  492. $method->isFinal()->willReturn(true);
  493. $method->getName()->willReturn('finalImplementation');
  494. $classNode = $this->reflect($class, array());
  495. $classNode->getUnextendableMethods()->shouldHaveCount(1);
  496. $classNode->isExtendable('finalImplementation')->shouldReturn(false);
  497. }
  498. /**
  499. * @param ReflectionClass $interface
  500. */
  501. function it_throws_an_exception_if_interface_provided_instead_of_class($interface)
  502. {
  503. $interface->isInterface()->willReturn(true);
  504. $interface->getName()->willReturn('Custom\ClassName');
  505. $this->shouldThrow('Prophecy\Exception\InvalidArgumentException')
  506. ->duringReflect($interface, array());
  507. }
  508. /**
  509. * @param ReflectionClass $interface1
  510. * @param ReflectionClass $interface2
  511. * @param ReflectionMethod $method1
  512. * @param ReflectionMethod $method2
  513. * @param ReflectionMethod $method3
  514. */
  515. function it_reflects_all_interfaces_methods(
  516. $interface1, $interface2, $method1, $method2, $method3
  517. )
  518. {
  519. $interface1->getName()->willReturn('MyInterface1');
  520. $interface2->getName()->willReturn('MyInterface2');
  521. $interface1->isInterface()->willReturn(true);
  522. $interface2->isInterface()->willReturn(true);
  523. $interface1->getMethods()->willReturn(array($method1));
  524. $interface2->getMethods()->willReturn(array($method2, $method3));
  525. $method1->getName()->willReturn('getName');
  526. $method2->getName()->willReturn('isPublic');
  527. $method3->getName()->willReturn('isAbstract');
  528. $method1->isProtected()->willReturn(false);
  529. $method2->isProtected()->willReturn(false);
  530. $method3->isProtected()->willReturn(false);
  531. $method1->returnsReference()->willReturn(false);
  532. $method2->returnsReference()->willReturn(false);
  533. $method3->returnsReference()->willReturn(false);
  534. $method1->isStatic()->willReturn(false);
  535. $method2->isStatic()->willReturn(false);
  536. $method3->isStatic()->willReturn(false);
  537. $method1->getParameters()->willReturn(array());
  538. $method2->getParameters()->willReturn(array());
  539. $method3->getParameters()->willReturn(array());
  540. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  541. $method1->hasReturnType()->willReturn(false);
  542. $method2->hasReturnType()->willReturn(false);
  543. $method3->hasReturnType()->willReturn(false);
  544. }
  545. $classNode = $this->reflect(null, array($interface1, $interface2));
  546. $classNode->shouldBeAnInstanceOf('Prophecy\Doubler\Generator\Node\ClassNode');
  547. $classNode->getParentClass()->shouldReturn('stdClass');
  548. $classNode->getInterfaces()->shouldReturn(array(
  549. 'Prophecy\Doubler\Generator\ReflectionInterface', 'MyInterface2', 'MyInterface1',
  550. ));
  551. $methodNodes = $classNode->getMethods();
  552. $methodNodes->shouldHaveCount(3);
  553. $classNode->hasMethod('getName')->shouldReturn(true);
  554. $classNode->hasMethod('isPublic')->shouldReturn(true);
  555. $classNode->hasMethod('isAbstract')->shouldReturn(true);
  556. }
  557. /**
  558. * @param ReflectionClass $class
  559. * @param ReflectionMethod $method1
  560. * @param ReflectionMethod $method2
  561. * @param ReflectionMethod $method3
  562. */
  563. function it_ignores_virtually_private_methods($class, $method1, $method2, $method3)
  564. {
  565. $class->getName()->willReturn('SomeClass');
  566. $class->isInterface()->willReturn(false);
  567. $class->isFinal()->willReturn(false);
  568. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array());
  569. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array($method1, $method2, $method3));
  570. $method1->getName()->willReturn('_getName');
  571. $method2->getName()->willReturn('__toString');
  572. $method3->getName()->willReturn('isAbstract');
  573. $method1->isFinal()->willReturn(false);
  574. $method2->isFinal()->willReturn(false);
  575. $method3->isFinal()->willReturn(false);
  576. $method1->isProtected()->willReturn(false);
  577. $method2->isProtected()->willReturn(false);
  578. $method3->isProtected()->willReturn(false);
  579. $method1->isStatic()->willReturn(false);
  580. $method2->isStatic()->willReturn(false);
  581. $method3->isStatic()->willReturn(false);
  582. $method1->returnsReference()->willReturn(false);
  583. $method2->returnsReference()->willReturn(false);
  584. $method3->returnsReference()->willReturn(false);
  585. $method1->getParameters()->willReturn(array());
  586. $method2->getParameters()->willReturn(array());
  587. $method3->getParameters()->willReturn(array());
  588. if (version_compare(PHP_VERSION, '7.0', '>=')) {
  589. $method1->hasReturnType()->willReturn(false);
  590. $method2->hasReturnType()->willReturn(false);
  591. $method3->hasReturnType()->willReturn(false);
  592. }
  593. $classNode = $this->reflect($class, array());
  594. $methodNodes = $classNode->getMethods();
  595. $methodNodes->shouldHaveCount(2);
  596. $classNode->hasMethod('isAbstract')->shouldReturn(true);
  597. }
  598. /**
  599. * @param ReflectionClass $class
  600. * @param ReflectionMethod $method
  601. */
  602. function it_does_not_throw_exception_for_virtually_private_finals($class, $method)
  603. {
  604. $class->getName()->willReturn('SomeClass');
  605. $class->isInterface()->willReturn(false);
  606. $class->isFinal()->willReturn(false);
  607. $class->getMethods(ReflectionMethod::IS_ABSTRACT)->willReturn(array());
  608. $class->getMethods(ReflectionMethod::IS_PUBLIC)->willReturn(array($method));
  609. $method->getName()->willReturn('__toString');
  610. $method->isFinal()->willReturn(true);
  611. $this->shouldNotThrow()->duringReflect($class, array());
  612. }
  613. /**
  614. * @param ReflectionClass $class
  615. */
  616. function it_throws_an_exception_if_class_provided_in_interfaces_list($class)
  617. {
  618. $class->getName()->willReturn('MyClass');
  619. $class->isInterface()->willReturn(false);
  620. $this->shouldThrow('InvalidArgumentException')
  621. ->duringReflect(null, array($class));
  622. }
  623. function it_throws_an_exception_if_not_reflection_provided_as_interface()
  624. {
  625. $this->shouldThrow('InvalidArgumentException')
  626. ->duringReflect(null, array(null));
  627. }
  628. function it_doesnt_fail_to_typehint_nonexistent_FQCN()
  629. {
  630. $classNode = $this->reflect(new ReflectionClass('spec\Prophecy\Doubler\Generator\OptionalDepsClass'), array());
  631. $method = $classNode->getMethod('iHaveAStrangeTypeHintedArg');
  632. $arguments = $method->getArguments();
  633. $arguments[0]->getTypeHint()->shouldBe('I\Simply\Am\Nonexistent');
  634. }
  635. function it_doesnt_fail_to_typehint_nonexistent_RQCN()
  636. {
  637. $classNode = $this->reflect(new ReflectionClass('spec\Prophecy\Doubler\Generator\OptionalDepsClass'), array());
  638. $method = $classNode->getMethod('iHaveAnEvenStrangerTypeHintedArg');
  639. $arguments = $method->getArguments();
  640. $arguments[0]->getTypeHint()->shouldBe('I\Simply\Am\Not');
  641. }
  642. function it_doesnt_use_scalar_typehints()
  643. {
  644. $classNode = $this->reflect(new ReflectionClass('ReflectionMethod'), array());
  645. $method = $classNode->getMethod('export');
  646. $arguments = $method->getArguments();
  647. $arguments[0]->getTypeHint()->shouldReturn(null);
  648. $arguments[1]->getTypeHint()->shouldReturn(null);
  649. $arguments[2]->getTypeHint()->shouldReturn(null);
  650. }
  651. }
  652. class OptionalDepsClass
  653. {
  654. public function iHaveAStrangeTypeHintedArg(\I\Simply\Am\Nonexistent $class)
  655. {
  656. }
  657. public function iHaveAnEvenStrangerTypeHintedArg(Simply\Am\Not $class)
  658. {
  659. }
  660. }