AnnotationClassLoaderTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  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\Routing\Tests\Loader;
  11. use Symfony\Component\Routing\Annotation\Route;
  12. class AnnotationClassLoaderTest extends AbstractAnnotationLoaderTest
  13. {
  14. protected $loader;
  15. private $reader;
  16. protected function setUp()
  17. {
  18. parent::setUp();
  19. $this->reader = $this->getReader();
  20. $this->loader = $this->getClassLoader($this->reader);
  21. }
  22. /**
  23. * @expectedException \InvalidArgumentException
  24. */
  25. public function testLoadMissingClass()
  26. {
  27. $this->loader->load('MissingClass');
  28. }
  29. /**
  30. * @expectedException \InvalidArgumentException
  31. */
  32. public function testLoadAbstractClass()
  33. {
  34. $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\AbstractClass');
  35. }
  36. /**
  37. * @dataProvider provideTestSupportsChecksResource
  38. */
  39. public function testSupportsChecksResource($resource, $expectedSupports)
  40. {
  41. $this->assertSame($expectedSupports, $this->loader->supports($resource), '->supports() returns true if the resource is loadable');
  42. }
  43. public function provideTestSupportsChecksResource()
  44. {
  45. return [
  46. ['class', true],
  47. ['\fully\qualified\class\name', true],
  48. ['namespaced\class\without\leading\slash', true],
  49. ['ÿClassWithLegalSpecialCharacters', true],
  50. ['5', false],
  51. ['foo.foo', false],
  52. [null, false],
  53. ];
  54. }
  55. public function testSupportsChecksTypeIfSpecified()
  56. {
  57. $this->assertTrue($this->loader->supports('class', 'annotation'), '->supports() checks the resource type if specified');
  58. $this->assertFalse($this->loader->supports('class', 'foo'), '->supports() checks the resource type if specified');
  59. }
  60. public function getLoadTests()
  61. {
  62. return [
  63. [
  64. 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
  65. ['name' => 'route1', 'path' => '/path'],
  66. ['arg2' => 'defaultValue2', 'arg3' => 'defaultValue3'],
  67. ],
  68. [
  69. 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
  70. ['defaults' => ['arg2' => 'foo'], 'requirements' => ['arg3' => '\w+']],
  71. ['arg2' => 'defaultValue2', 'arg3' => 'defaultValue3'],
  72. ],
  73. [
  74. 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
  75. ['options' => ['foo' => 'bar']],
  76. ['arg2' => 'defaultValue2', 'arg3' => 'defaultValue3'],
  77. ],
  78. [
  79. 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
  80. ['schemes' => ['https'], 'methods' => ['GET']],
  81. ['arg2' => 'defaultValue2', 'arg3' => 'defaultValue3'],
  82. ],
  83. [
  84. 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass',
  85. ['condition' => 'context.getMethod() == "GET"'],
  86. ['arg2' => 'defaultValue2', 'arg3' => 'defaultValue3'],
  87. ],
  88. ];
  89. }
  90. /**
  91. * @dataProvider getLoadTests
  92. */
  93. public function testLoad($className, $routeData = [], $methodArgs = [])
  94. {
  95. $routeData = array_replace([
  96. 'name' => 'route',
  97. 'path' => '/',
  98. 'requirements' => [],
  99. 'options' => [],
  100. 'defaults' => [],
  101. 'schemes' => [],
  102. 'methods' => [],
  103. 'condition' => '',
  104. ], $routeData);
  105. $this->reader
  106. ->expects($this->once())
  107. ->method('getMethodAnnotations')
  108. ->willReturn([$this->getAnnotatedRoute($routeData)])
  109. ;
  110. $routeCollection = $this->loader->load($className);
  111. $route = $routeCollection->get($routeData['name']);
  112. $this->assertSame($routeData['path'], $route->getPath(), '->load preserves path annotation');
  113. $this->assertCount(
  114. \count($routeData['requirements']),
  115. array_intersect_assoc($routeData['requirements'], $route->getRequirements()),
  116. '->load preserves requirements annotation'
  117. );
  118. $this->assertCount(
  119. \count($routeData['options']),
  120. array_intersect_assoc($routeData['options'], $route->getOptions()),
  121. '->load preserves options annotation'
  122. );
  123. $this->assertCount(
  124. \count($routeData['defaults']),
  125. $route->getDefaults(),
  126. '->load preserves defaults annotation'
  127. );
  128. $this->assertEquals($routeData['schemes'], $route->getSchemes(), '->load preserves schemes annotation');
  129. $this->assertEquals($routeData['methods'], $route->getMethods(), '->load preserves methods annotation');
  130. $this->assertSame($routeData['condition'], $route->getCondition(), '->load preserves condition annotation');
  131. }
  132. public function testClassRouteLoad()
  133. {
  134. $classRouteData = [
  135. 'name' => 'prefix_',
  136. 'path' => '/prefix',
  137. 'schemes' => ['https'],
  138. 'methods' => ['GET'],
  139. ];
  140. $methodRouteData = [
  141. 'name' => 'route1',
  142. 'path' => '/path',
  143. 'schemes' => ['http'],
  144. 'methods' => ['POST', 'PUT'],
  145. ];
  146. $this->reader
  147. ->expects($this->once())
  148. ->method('getClassAnnotation')
  149. ->willReturn($this->getAnnotatedRoute($classRouteData))
  150. ;
  151. $this->reader
  152. ->expects($this->once())
  153. ->method('getMethodAnnotations')
  154. ->willReturn([$this->getAnnotatedRoute($methodRouteData)])
  155. ;
  156. $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass');
  157. $route = $routeCollection->get($classRouteData['name'].$methodRouteData['name']);
  158. $this->assertSame($classRouteData['path'].$methodRouteData['path'], $route->getPath(), '->load concatenates class and method route path');
  159. $this->assertEquals(array_merge($classRouteData['schemes'], $methodRouteData['schemes']), $route->getSchemes(), '->load merges class and method route schemes');
  160. $this->assertEquals(array_merge($classRouteData['methods'], $methodRouteData['methods']), $route->getMethods(), '->load merges class and method route methods');
  161. }
  162. public function testInvokableClassRouteLoadWithMethodAnnotation()
  163. {
  164. $classRouteData = [
  165. 'name' => 'route1',
  166. 'path' => '/',
  167. 'schemes' => ['https'],
  168. 'methods' => ['GET'],
  169. ];
  170. $this->reader
  171. ->expects($this->exactly(1))
  172. ->method('getClassAnnotations')
  173. ->willReturn([$this->getAnnotatedRoute($classRouteData)])
  174. ;
  175. $this->reader
  176. ->expects($this->once())
  177. ->method('getMethodAnnotations')
  178. ->willReturn([])
  179. ;
  180. $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass');
  181. $route = $routeCollection->get($classRouteData['name']);
  182. $this->assertSame($classRouteData['path'], $route->getPath(), '->load preserves class route path');
  183. $this->assertEquals($classRouteData['schemes'], $route->getSchemes(), '->load preserves class route schemes');
  184. $this->assertEquals($classRouteData['methods'], $route->getMethods(), '->load preserves class route methods');
  185. }
  186. public function testInvokableClassRouteLoadWithClassAnnotation()
  187. {
  188. $classRouteData = [
  189. 'name' => 'route1',
  190. 'path' => '/',
  191. 'schemes' => ['https'],
  192. 'methods' => ['GET'],
  193. ];
  194. $this->reader
  195. ->expects($this->exactly(1))
  196. ->method('getClassAnnotation')
  197. ->willReturn($this->getAnnotatedRoute($classRouteData))
  198. ;
  199. $this->reader
  200. ->expects($this->exactly(1))
  201. ->method('getClassAnnotations')
  202. ->willReturn([$this->getAnnotatedRoute($classRouteData)])
  203. ;
  204. $this->reader
  205. ->expects($this->once())
  206. ->method('getMethodAnnotations')
  207. ->willReturn([])
  208. ;
  209. $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass');
  210. $route = $routeCollection->get($classRouteData['name']);
  211. $this->assertSame($classRouteData['path'], $route->getPath(), '->load preserves class route path');
  212. $this->assertEquals($classRouteData['schemes'], $route->getSchemes(), '->load preserves class route schemes');
  213. $this->assertEquals($classRouteData['methods'], $route->getMethods(), '->load preserves class route methods');
  214. }
  215. public function testInvokableClassMultipleRouteLoad()
  216. {
  217. $classRouteData1 = [
  218. 'name' => 'route1',
  219. 'path' => '/1',
  220. 'schemes' => ['https'],
  221. 'methods' => ['GET'],
  222. ];
  223. $classRouteData2 = [
  224. 'name' => 'route2',
  225. 'path' => '/2',
  226. 'schemes' => ['https'],
  227. 'methods' => ['GET'],
  228. ];
  229. $this->reader
  230. ->expects($this->exactly(1))
  231. ->method('getClassAnnotations')
  232. ->willReturn([$this->getAnnotatedRoute($classRouteData1), $this->getAnnotatedRoute($classRouteData2)])
  233. ;
  234. $this->reader
  235. ->expects($this->once())
  236. ->method('getMethodAnnotations')
  237. ->willReturn([])
  238. ;
  239. $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass');
  240. $route = $routeCollection->get($classRouteData1['name']);
  241. $this->assertSame($classRouteData1['path'], $route->getPath(), '->load preserves class route path');
  242. $this->assertEquals($classRouteData1['schemes'], $route->getSchemes(), '->load preserves class route schemes');
  243. $this->assertEquals($classRouteData1['methods'], $route->getMethods(), '->load preserves class route methods');
  244. $route = $routeCollection->get($classRouteData2['name']);
  245. $this->assertSame($classRouteData2['path'], $route->getPath(), '->load preserves class route path');
  246. $this->assertEquals($classRouteData2['schemes'], $route->getSchemes(), '->load preserves class route schemes');
  247. $this->assertEquals($classRouteData2['methods'], $route->getMethods(), '->load preserves class route methods');
  248. }
  249. public function testInvokableClassWithMethodRouteLoad()
  250. {
  251. $classRouteData = [
  252. 'name' => 'route1',
  253. 'path' => '/prefix',
  254. 'schemes' => ['https'],
  255. 'methods' => ['GET'],
  256. ];
  257. $methodRouteData = [
  258. 'name' => 'route2',
  259. 'path' => '/path',
  260. 'schemes' => ['http'],
  261. 'methods' => ['POST', 'PUT'],
  262. ];
  263. $this->reader
  264. ->expects($this->once())
  265. ->method('getClassAnnotation')
  266. ->willReturn($this->getAnnotatedRoute($classRouteData))
  267. ;
  268. $this->reader
  269. ->expects($this->once())
  270. ->method('getMethodAnnotations')
  271. ->willReturn([$this->getAnnotatedRoute($methodRouteData)])
  272. ;
  273. $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass');
  274. $route = $routeCollection->get($classRouteData['name']);
  275. $this->assertNull($route, '->load ignores class route');
  276. $route = $routeCollection->get($classRouteData['name'].$methodRouteData['name']);
  277. $this->assertSame($classRouteData['path'].$methodRouteData['path'], $route->getPath(), '->load concatenates class and method route path');
  278. $this->assertEquals(array_merge($classRouteData['schemes'], $methodRouteData['schemes']), $route->getSchemes(), '->load merges class and method route schemes');
  279. $this->assertEquals(array_merge($classRouteData['methods'], $methodRouteData['methods']), $route->getMethods(), '->load merges class and method route methods');
  280. }
  281. /**
  282. * @requires function mb_strtolower
  283. */
  284. public function testDefaultRouteName()
  285. {
  286. $methodRouteData = [
  287. 'name' => null,
  288. ];
  289. $this->reader
  290. ->expects($this->once())
  291. ->method('getMethodAnnotations')
  292. ->willReturn([$this->getAnnotatedRoute($methodRouteData)])
  293. ;
  294. $routeCollection = $this->loader->load('Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\EncodingClass');
  295. $defaultName = array_keys($routeCollection->all())[0];
  296. $this->assertSame($defaultName, 'symfony_component_routing_tests_fixtures_annotatedclasses_encodingclass_routeàction');
  297. }
  298. private function getAnnotatedRoute($data)
  299. {
  300. return new Route($data);
  301. }
  302. }