PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php

http://github.com/fabpot/symfony
PHP | 252 lines | 189 code | 42 blank | 21 comment | 6 complexity | 1fbd5ac5adcdb49597378de940f7dff5 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  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 Symfony\Component\Config\Tests\Resource;
  11. use PHPUnit\Framework\TestCase;
  12. use Symfony\Component\Config\Resource\ReflectionClassResource;
  13. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  14. use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
  15. use Symfony\Contracts\Service\ServiceSubscriberInterface;
  16. class ReflectionClassResourceTest extends TestCase
  17. {
  18. public function testToString()
  19. {
  20. $res = new ReflectionClassResource(new \ReflectionClass('ErrorException'));
  21. $this->assertSame('reflection.ErrorException', (string) $res);
  22. }
  23. public function testSerializeUnserialize()
  24. {
  25. $res = new ReflectionClassResource(new \ReflectionClass(DummyInterface::class));
  26. $ser = unserialize(serialize($res));
  27. $this->assertTrue($res->isFresh(0));
  28. $this->assertTrue($ser->isFresh(0));
  29. $this->assertSame((string) $res, (string) $ser);
  30. }
  31. public function testIsFresh()
  32. {
  33. $res = new ReflectionClassResource(new \ReflectionClass(__CLASS__));
  34. $mtime = filemtime(__FILE__);
  35. $this->assertTrue($res->isFresh($mtime), '->isFresh() returns true if the resource has not changed in same second');
  36. $this->assertTrue($res->isFresh($mtime + 10), '->isFresh() returns true if the resource has not changed');
  37. $this->assertTrue($res->isFresh($mtime - 86400), '->isFresh() returns true if the resource has not changed');
  38. }
  39. public function testIsFreshForDeletedResources()
  40. {
  41. $now = time();
  42. $tmp = sys_get_temp_dir().'/tmp.php';
  43. file_put_contents($tmp, '<?php class ReflectionClassResourceTestClass {}');
  44. require $tmp;
  45. $res = new ReflectionClassResource(new \ReflectionClass('ReflectionClassResourceTestClass'));
  46. $this->assertTrue($res->isFresh($now));
  47. unlink($tmp);
  48. $this->assertFalse($res->isFresh($now), '->isFresh() returns false if the resource does not exist');
  49. }
  50. /**
  51. * @dataProvider provideHashedSignature
  52. */
  53. public function testHashedSignature($changeExpected, $changedLine, $changedCode, $setContext = null)
  54. {
  55. if ($setContext) {
  56. $setContext();
  57. }
  58. $code = <<<'EOPHP'
  59. /* 0*/
  60. /* 1*/ class %s extends ErrorException
  61. /* 2*/ {
  62. /* 3*/ const FOO = 123;
  63. /* 4*/
  64. /* 5*/ public $pub = [];
  65. /* 6*/
  66. /* 7*/ protected $prot;
  67. /* 8*/
  68. /* 9*/ private $priv;
  69. /*10*/
  70. /*11*/ public function pub($arg = null) {}
  71. /*12*/
  72. /*13*/ protected function prot($a = []) {}
  73. /*14*/
  74. /*15*/ private function priv() {}
  75. /*16*/
  76. /*17*/ public function ccc($bar = A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC) {}
  77. /*18*/ }
  78. EOPHP;
  79. static $expectedSignature, $generateSignature;
  80. if (null === $expectedSignature) {
  81. eval(sprintf($code, $class = 'Foo'.str_replace('.', '_', uniqid('', true))));
  82. $r = new \ReflectionClass(ReflectionClassResource::class);
  83. $generateSignature = $r->getMethod('generateSignature');
  84. $generateSignature->setAccessible(true);
  85. $generateSignature = $generateSignature->getClosure($r->newInstanceWithoutConstructor());
  86. $expectedSignature = implode("\n", iterator_to_array($generateSignature(new \ReflectionClass($class))));
  87. }
  88. $code = explode("\n", $code);
  89. if (null !== $changedCode) {
  90. $code[$changedLine] = $changedCode;
  91. }
  92. eval(sprintf(implode("\n", $code), $class = 'Foo'.str_replace('.', '_', uniqid('', true))));
  93. $signature = implode("\n", iterator_to_array($generateSignature(new \ReflectionClass($class))));
  94. if ($changeExpected) {
  95. $this->assertNotSame($expectedSignature, $signature);
  96. } else {
  97. $this->assertSame($expectedSignature, $signature);
  98. }
  99. }
  100. public function provideHashedSignature(): iterable
  101. {
  102. yield [0, 0, "// line change\n\n"];
  103. yield [1, 0, '/** class docblock */'];
  104. yield [1, 1, 'abstract class %s'];
  105. yield [1, 1, 'final class %s'];
  106. yield [1, 1, 'class %s extends Exception'];
  107. yield [1, 1, 'class %s implements '.DummyInterface::class];
  108. yield [1, 3, 'const FOO = 456;'];
  109. yield [1, 3, 'const BAR = 123;'];
  110. yield [1, 4, '/** pub docblock */'];
  111. yield [1, 5, 'protected $pub = [];'];
  112. yield [1, 5, 'public $pub = [123];'];
  113. yield [1, 6, '/** prot docblock */'];
  114. yield [1, 7, 'private $prot;'];
  115. yield [0, 8, '/** priv docblock */'];
  116. yield [0, 9, 'private $priv = 123;'];
  117. yield [1, 10, '/** pub docblock */'];
  118. yield [1, 11, 'public function pub(...$arg) {}'];
  119. yield [1, 11, 'public function pub($arg = null): Foo {}'];
  120. yield [0, 11, "public function pub(\$arg = null) {\nreturn 123;\n}"];
  121. yield [1, 12, '/** prot docblock */'];
  122. yield [1, 13, 'protected function prot($a = [123]) {}'];
  123. yield [0, 14, '/** priv docblock */'];
  124. yield [0, 15, ''];
  125. if (\PHP_VERSION_ID >= 70400) {
  126. // PHP7.4 typed properties without default value are
  127. // undefined, make sure this doesn't throw an error
  128. yield [1, 5, 'public array $pub;'];
  129. yield [0, 7, 'protected int $prot;'];
  130. yield [0, 9, 'private string $priv;'];
  131. }
  132. yield [1, 17, 'public function ccc($bar = 187) {}'];
  133. yield [1, 17, 'public function ccc($bar = ANOTHER_ONE_THAT_WILL_NEVER_BE_DEFINED_CCCCCCCCC) {}'];
  134. yield [1, 17, null, static function () { \define('A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC', 'foo'); }];
  135. }
  136. public function testEventSubscriber()
  137. {
  138. $res = new ReflectionClassResource(new \ReflectionClass(TestEventSubscriber::class));
  139. $this->assertTrue($res->isFresh(0));
  140. TestEventSubscriber::$subscribedEvents = [123];
  141. $this->assertFalse($res->isFresh(0));
  142. $res = new ReflectionClassResource(new \ReflectionClass(TestEventSubscriber::class));
  143. $this->assertTrue($res->isFresh(0));
  144. }
  145. public function testMessageSubscriber()
  146. {
  147. $res = new ReflectionClassResource(new \ReflectionClass(TestMessageSubscriber::class));
  148. $this->assertTrue($res->isFresh(0));
  149. TestMessageSubscriberConfigHolder::$handledMessages = ['SomeMessageClass' => []];
  150. $this->assertFalse($res->isFresh(0));
  151. $res = new ReflectionClassResource(new \ReflectionClass(TestMessageSubscriber::class));
  152. $this->assertTrue($res->isFresh(0));
  153. TestMessageSubscriberConfigHolder::$handledMessages = ['OtherMessageClass' => []];
  154. $this->assertFalse($res->isFresh(0));
  155. $res = new ReflectionClassResource(new \ReflectionClass(TestMessageSubscriber::class));
  156. $this->assertTrue($res->isFresh(0));
  157. }
  158. public function testServiceSubscriber()
  159. {
  160. $res = new ReflectionClassResource(new \ReflectionClass(TestServiceSubscriber::class));
  161. $this->assertTrue($res->isFresh(0));
  162. TestServiceSubscriber::$subscribedServices = [123];
  163. $this->assertFalse($res->isFresh(0));
  164. $res = new ReflectionClassResource(new \ReflectionClass(TestServiceSubscriber::class));
  165. $this->assertTrue($res->isFresh(0));
  166. }
  167. public function testIgnoresObjectsInSignature()
  168. {
  169. $res = new ReflectionClassResource(new \ReflectionClass(TestServiceWithStaticProperty::class));
  170. $this->assertTrue($res->isFresh(0));
  171. TestServiceWithStaticProperty::$initializedObject = new TestServiceWithStaticProperty();
  172. $this->assertTrue($res->isFresh(0));
  173. }
  174. }
  175. interface DummyInterface
  176. {
  177. }
  178. class TestEventSubscriber implements EventSubscriberInterface
  179. {
  180. public static $subscribedEvents = [];
  181. public static function getSubscribedEvents(): array
  182. {
  183. return self::$subscribedEvents;
  184. }
  185. }
  186. class TestMessageSubscriber implements MessageSubscriberInterface
  187. {
  188. public static function getHandledMessages(): iterable
  189. {
  190. foreach (TestMessageSubscriberConfigHolder::$handledMessages as $key => $subscribedMessage) {
  191. yield $key => $subscribedMessage;
  192. }
  193. }
  194. }
  195. class TestMessageSubscriberConfigHolder
  196. {
  197. public static $handledMessages = [];
  198. }
  199. class TestServiceSubscriber implements ServiceSubscriberInterface
  200. {
  201. public static $subscribedServices = [];
  202. public static function getSubscribedServices(): array
  203. {
  204. return self::$subscribedServices;
  205. }
  206. }
  207. class TestServiceWithStaticProperty
  208. {
  209. public static $initializedObject;
  210. }