diff options
Diffstat (limited to 'vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php')
-rw-r--r-- | vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php | 383 |
1 files changed, 383 insertions, 0 deletions
diff --git a/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php new file mode 100644 index 00000000..8a1428f1 --- /dev/null +++ b/vendor/symfony/routing/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php | |||
@@ -0,0 +1,383 @@ | |||
1 | <?php | ||
2 | |||
3 | /* | ||
4 | * This file is part of the Symfony package. | ||
5 | * | ||
6 | * (c) Fabien Potencier <fabien@symfony.com> | ||
7 | * | ||
8 | * For the full copyright and license information, please view the LICENSE | ||
9 | * file that was distributed with this source code. | ||
10 | */ | ||
11 | |||
12 | namespace Symfony\Component\Routing\Tests\Matcher; | ||
13 | |||
14 | use Symfony\Component\Routing\Exception\MethodNotAllowedException; | ||
15 | use Symfony\Component\Routing\Exception\ResourceNotFoundException; | ||
16 | use Symfony\Component\Routing\Matcher\UrlMatcher; | ||
17 | use Symfony\Component\Routing\Route; | ||
18 | use Symfony\Component\Routing\RouteCollection; | ||
19 | use Symfony\Component\Routing\RequestContext; | ||
20 | |||
21 | class UrlMatcherTest extends \PHPUnit_Framework_TestCase | ||
22 | { | ||
23 | public function testNoMethodSoAllowed() | ||
24 | { | ||
25 | $coll = new RouteCollection(); | ||
26 | $coll->add('foo', new Route('/foo')); | ||
27 | |||
28 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
29 | $matcher->match('/foo'); | ||
30 | } | ||
31 | |||
32 | public function testMethodNotAllowed() | ||
33 | { | ||
34 | $coll = new RouteCollection(); | ||
35 | $coll->add('foo', new Route('/foo', array(), array('_method' => 'post'))); | ||
36 | |||
37 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
38 | |||
39 | try { | ||
40 | $matcher->match('/foo'); | ||
41 | $this->fail(); | ||
42 | } catch (MethodNotAllowedException $e) { | ||
43 | $this->assertEquals(array('POST'), $e->getAllowedMethods()); | ||
44 | } | ||
45 | } | ||
46 | |||
47 | public function testHeadAllowedWhenRequirementContainsGet() | ||
48 | { | ||
49 | $coll = new RouteCollection(); | ||
50 | $coll->add('foo', new Route('/foo', array(), array('_method' => 'get'))); | ||
51 | |||
52 | $matcher = new UrlMatcher($coll, new RequestContext('', 'head')); | ||
53 | $matcher->match('/foo'); | ||
54 | } | ||
55 | |||
56 | public function testMethodNotAllowedAggregatesAllowedMethods() | ||
57 | { | ||
58 | $coll = new RouteCollection(); | ||
59 | $coll->add('foo1', new Route('/foo', array(), array('_method' => 'post'))); | ||
60 | $coll->add('foo2', new Route('/foo', array(), array('_method' => 'put|delete'))); | ||
61 | |||
62 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
63 | |||
64 | try { | ||
65 | $matcher->match('/foo'); | ||
66 | $this->fail(); | ||
67 | } catch (MethodNotAllowedException $e) { | ||
68 | $this->assertEquals(array('POST', 'PUT', 'DELETE'), $e->getAllowedMethods()); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | public function testMatch() | ||
73 | { | ||
74 | // test the patterns are matched and parameters are returned | ||
75 | $collection = new RouteCollection(); | ||
76 | $collection->add('foo', new Route('/foo/{bar}')); | ||
77 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
78 | try { | ||
79 | $matcher->match('/no-match'); | ||
80 | $this->fail(); | ||
81 | } catch (ResourceNotFoundException $e) {} | ||
82 | $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz'), $matcher->match('/foo/baz')); | ||
83 | |||
84 | // test that defaults are merged | ||
85 | $collection = new RouteCollection(); | ||
86 | $collection->add('foo', new Route('/foo/{bar}', array('def' => 'test'))); | ||
87 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
88 | $this->assertEquals(array('_route' => 'foo', 'bar' => 'baz', 'def' => 'test'), $matcher->match('/foo/baz')); | ||
89 | |||
90 | // test that route "method" is ignored if no method is given in the context | ||
91 | $collection = new RouteCollection(); | ||
92 | $collection->add('foo', new Route('/foo', array(), array('_method' => 'GET|head'))); | ||
93 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
94 | $this->assertInternalType('array', $matcher->match('/foo')); | ||
95 | |||
96 | // route does not match with POST method context | ||
97 | $matcher = new UrlMatcher($collection, new RequestContext('', 'post')); | ||
98 | try { | ||
99 | $matcher->match('/foo'); | ||
100 | $this->fail(); | ||
101 | } catch (MethodNotAllowedException $e) {} | ||
102 | |||
103 | // route does match with GET or HEAD method context | ||
104 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
105 | $this->assertInternalType('array', $matcher->match('/foo')); | ||
106 | $matcher = new UrlMatcher($collection, new RequestContext('', 'head')); | ||
107 | $this->assertInternalType('array', $matcher->match('/foo')); | ||
108 | |||
109 | // route with an optional variable as the first segment | ||
110 | $collection = new RouteCollection(); | ||
111 | $collection->add('bar', new Route('/{bar}/foo', array('bar' => 'bar'), array('bar' => 'foo|bar'))); | ||
112 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
113 | $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/bar/foo')); | ||
114 | $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo/foo')); | ||
115 | |||
116 | $collection = new RouteCollection(); | ||
117 | $collection->add('bar', new Route('/{bar}', array('bar' => 'bar'), array('bar' => 'foo|bar'))); | ||
118 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
119 | $this->assertEquals(array('_route' => 'bar', 'bar' => 'foo'), $matcher->match('/foo')); | ||
120 | $this->assertEquals(array('_route' => 'bar', 'bar' => 'bar'), $matcher->match('/')); | ||
121 | |||
122 | // route with only optional variables | ||
123 | $collection = new RouteCollection(); | ||
124 | $collection->add('bar', new Route('/{foo}/{bar}', array('foo' => 'foo', 'bar' => 'bar'), array())); | ||
125 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
126 | $this->assertEquals(array('_route' => 'bar', 'foo' => 'foo', 'bar' => 'bar'), $matcher->match('/')); | ||
127 | $this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'bar'), $matcher->match('/a')); | ||
128 | $this->assertEquals(array('_route' => 'bar', 'foo' => 'a', 'bar' => 'b'), $matcher->match('/a/b')); | ||
129 | } | ||
130 | |||
131 | public function testMatchWithPrefixes() | ||
132 | { | ||
133 | $collection = new RouteCollection(); | ||
134 | $collection->add('foo', new Route('/{foo}')); | ||
135 | $collection->addPrefix('/b'); | ||
136 | $collection->addPrefix('/a'); | ||
137 | |||
138 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
139 | $this->assertEquals(array('_route' => 'foo', 'foo' => 'foo'), $matcher->match('/a/b/foo')); | ||
140 | } | ||
141 | |||
142 | public function testMatchWithDynamicPrefix() | ||
143 | { | ||
144 | $collection = new RouteCollection(); | ||
145 | $collection->add('foo', new Route('/{foo}')); | ||
146 | $collection->addPrefix('/b'); | ||
147 | $collection->addPrefix('/{_locale}'); | ||
148 | |||
149 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
150 | $this->assertEquals(array('_locale' => 'fr', '_route' => 'foo', 'foo' => 'foo'), $matcher->match('/fr/b/foo')); | ||
151 | } | ||
152 | |||
153 | public function testMatchSpecialRouteName() | ||
154 | { | ||
155 | $collection = new RouteCollection(); | ||
156 | $collection->add('$péß^a|', new Route('/bar')); | ||
157 | |||
158 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
159 | $this->assertEquals(array('_route' => '$péß^a|'), $matcher->match('/bar')); | ||
160 | } | ||
161 | |||
162 | public function testMatchNonAlpha() | ||
163 | { | ||
164 | $collection = new RouteCollection(); | ||
165 | $chars = '!"$%éà &\'()*+,./:;<=>@ABCDEFGHIJKLMNOPQRSTUVWXYZ\\[]^_`abcdefghijklmnopqrstuvwxyz{|}~-'; | ||
166 | $collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '['.preg_quote($chars).']+'))); | ||
167 | |||
168 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
169 | $this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.rawurlencode($chars).'/bar')); | ||
170 | $this->assertEquals(array('_route' => 'foo', 'foo' => $chars), $matcher->match('/'.strtr($chars, array('%' => '%25')).'/bar')); | ||
171 | } | ||
172 | |||
173 | public function testMatchWithDotMetacharacterInRequirements() | ||
174 | { | ||
175 | $collection = new RouteCollection(); | ||
176 | $collection->add('foo', new Route('/{foo}/bar', array(), array('foo' => '.+'))); | ||
177 | |||
178 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
179 | $this->assertEquals(array('_route' => 'foo', 'foo' => "\n"), $matcher->match('/'.urlencode("\n").'/bar'), 'linefeed character is matched'); | ||
180 | } | ||
181 | |||
182 | public function testMatchOverriddenRoute() | ||
183 | { | ||
184 | $collection = new RouteCollection(); | ||
185 | $collection->add('foo', new Route('/foo')); | ||
186 | |||
187 | $collection1 = new RouteCollection(); | ||
188 | $collection1->add('foo', new Route('/foo1')); | ||
189 | |||
190 | $collection->addCollection($collection1); | ||
191 | |||
192 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
193 | |||
194 | $this->assertEquals(array('_route' => 'foo'), $matcher->match('/foo1')); | ||
195 | $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); | ||
196 | $this->assertEquals(array(), $matcher->match('/foo')); | ||
197 | } | ||
198 | |||
199 | public function testMatchRegression() | ||
200 | { | ||
201 | $coll = new RouteCollection(); | ||
202 | $coll->add('foo', new Route('/foo/{foo}')); | ||
203 | $coll->add('bar', new Route('/foo/bar/{foo}')); | ||
204 | |||
205 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
206 | $this->assertEquals(array('foo' => 'bar', '_route' => 'bar'), $matcher->match('/foo/bar/bar')); | ||
207 | |||
208 | $collection = new RouteCollection(); | ||
209 | $collection->add('foo', new Route('/{bar}')); | ||
210 | $matcher = new UrlMatcher($collection, new RequestContext()); | ||
211 | try { | ||
212 | $matcher->match('/'); | ||
213 | $this->fail(); | ||
214 | } catch (ResourceNotFoundException $e) { | ||
215 | } | ||
216 | } | ||
217 | |||
218 | public function testDefaultRequirementForOptionalVariables() | ||
219 | { | ||
220 | $coll = new RouteCollection(); | ||
221 | $coll->add('test', new Route('/{page}.{_format}', array('page' => 'index', '_format' => 'html'))); | ||
222 | |||
223 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
224 | $this->assertEquals(array('page' => 'my-page', '_format' => 'xml', '_route' => 'test'), $matcher->match('/my-page.xml')); | ||
225 | } | ||
226 | |||
227 | public function testMatchingIsEager() | ||
228 | { | ||
229 | $coll = new RouteCollection(); | ||
230 | $coll->add('test', new Route('/{foo}-{bar}-', array(), array('foo' => '.+', 'bar' => '.+'))); | ||
231 | |||
232 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
233 | $this->assertEquals(array('foo' => 'text1-text2-text3', 'bar' => 'text4', '_route' => 'test'), $matcher->match('/text1-text2-text3-text4-')); | ||
234 | } | ||
235 | |||
236 | public function testAdjacentVariables() | ||
237 | { | ||
238 | $coll = new RouteCollection(); | ||
239 | $coll->add('test', new Route('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => 'y|Y'))); | ||
240 | |||
241 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
242 | // 'w' eagerly matches as much as possible and the other variables match the remaining chars. | ||
243 | // This also shows that the variables w-z must all exclude the separating char (the dot '.' in this case) by default requirement. | ||
244 | // Otherwise they would also consume '.xml' and _format would never match as it's an optional variable. | ||
245 | $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'Y', 'z' => 'Z','_format' => 'xml', '_route' => 'test'), $matcher->match('/wwwwwxYZ.xml')); | ||
246 | // As 'y' has custom requirement and can only be of value 'y|Y', it will leave 'ZZZ' to variable z. | ||
247 | // So with carefully chosen requirements adjacent variables, can be useful. | ||
248 | $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'ZZZ','_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxyZZZ')); | ||
249 | // z and _format are optional. | ||
250 | $this->assertEquals(array('w' => 'wwwww', 'x' => 'x', 'y' => 'y', 'z' => 'default-z','_format' => 'html', '_route' => 'test'), $matcher->match('/wwwwwxy')); | ||
251 | |||
252 | $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); | ||
253 | $matcher->match('/wxy.html'); | ||
254 | } | ||
255 | |||
256 | public function testOptionalVariableWithNoRealSeparator() | ||
257 | { | ||
258 | $coll = new RouteCollection(); | ||
259 | $coll->add('test', new Route('/get{what}', array('what' => 'All'))); | ||
260 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
261 | |||
262 | $this->assertEquals(array('what' => 'All', '_route' => 'test'), $matcher->match('/get')); | ||
263 | $this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSites')); | ||
264 | |||
265 | // Usually the character in front of an optional parameter can be left out, e.g. with pattern '/get/{what}' just '/get' would match. | ||
266 | // But here the 't' in 'get' is not a separating character, so it makes no sense to match without it. | ||
267 | $this->setExpectedException('Symfony\Component\Routing\Exception\ResourceNotFoundException'); | ||
268 | $matcher->match('/ge'); | ||
269 | } | ||
270 | |||
271 | public function testRequiredVariableWithNoRealSeparator() | ||
272 | { | ||
273 | $coll = new RouteCollection(); | ||
274 | $coll->add('test', new Route('/get{what}Suffix')); | ||
275 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
276 | |||
277 | $this->assertEquals(array('what' => 'Sites', '_route' => 'test'), $matcher->match('/getSitesSuffix')); | ||
278 | } | ||
279 | |||
280 | public function testDefaultRequirementOfVariable() | ||
281 | { | ||
282 | $coll = new RouteCollection(); | ||
283 | $coll->add('test', new Route('/{page}.{_format}')); | ||
284 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
285 | |||
286 | $this->assertEquals(array('page' => 'index', '_format' => 'mobile.html', '_route' => 'test'), $matcher->match('/index.mobile.html')); | ||
287 | } | ||
288 | |||
289 | /** | ||
290 | * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException | ||
291 | */ | ||
292 | public function testDefaultRequirementOfVariableDisallowsSlash() | ||
293 | { | ||
294 | $coll = new RouteCollection(); | ||
295 | $coll->add('test', new Route('/{page}.{_format}')); | ||
296 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
297 | |||
298 | $matcher->match('/index.sl/ash'); | ||
299 | } | ||
300 | |||
301 | /** | ||
302 | * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException | ||
303 | */ | ||
304 | public function testDefaultRequirementOfVariableDisallowsNextSeparator() | ||
305 | { | ||
306 | $coll = new RouteCollection(); | ||
307 | $coll->add('test', new Route('/{page}.{_format}', array(), array('_format' => 'html|xml'))); | ||
308 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
309 | |||
310 | $matcher->match('/do.t.html'); | ||
311 | } | ||
312 | |||
313 | /** | ||
314 | * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException | ||
315 | */ | ||
316 | public function testSchemeRequirement() | ||
317 | { | ||
318 | $coll = new RouteCollection(); | ||
319 | $coll->add('foo', new Route('/foo', array(), array('_scheme' => 'https'))); | ||
320 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
321 | $matcher->match('/foo'); | ||
322 | } | ||
323 | |||
324 | public function testDecodeOnce() | ||
325 | { | ||
326 | $coll = new RouteCollection(); | ||
327 | $coll->add('foo', new Route('/foo/{foo}')); | ||
328 | |||
329 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
330 | $this->assertEquals(array('foo' => 'bar%23', '_route' => 'foo'), $matcher->match('/foo/bar%2523')); | ||
331 | } | ||
332 | |||
333 | public function testCannotRelyOnPrefix() | ||
334 | { | ||
335 | $coll = new RouteCollection(); | ||
336 | |||
337 | $subColl = new RouteCollection(); | ||
338 | $subColl->add('bar', new Route('/bar')); | ||
339 | $subColl->addPrefix('/prefix'); | ||
340 | // overwrite the pattern, so the prefix is not valid anymore for this route in the collection | ||
341 | $subColl->get('bar')->setPattern('/new'); | ||
342 | |||
343 | $coll->addCollection($subColl); | ||
344 | |||
345 | $matcher = new UrlMatcher($coll, new RequestContext()); | ||
346 | $this->assertEquals(array('_route' => 'bar'), $matcher->match('/new')); | ||
347 | } | ||
348 | |||
349 | public function testWithHost() | ||
350 | { | ||
351 | $coll = new RouteCollection(); | ||
352 | $coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com')); | ||
353 | |||
354 | $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); | ||
355 | $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar')); | ||
356 | } | ||
357 | |||
358 | public function testWithHostOnRouteCollection() | ||
359 | { | ||
360 | $coll = new RouteCollection(); | ||
361 | $coll->add('foo', new Route('/foo/{foo}')); | ||
362 | $coll->add('bar', new Route('/bar/{foo}', array(), array(), array(), '{locale}.example.net')); | ||
363 | $coll->setHost('{locale}.example.com'); | ||
364 | |||
365 | $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); | ||
366 | $this->assertEquals(array('foo' => 'bar', '_route' => 'foo', 'locale' => 'en'), $matcher->match('/foo/bar')); | ||
367 | |||
368 | $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'en.example.com')); | ||
369 | $this->assertEquals(array('foo' => 'bar', '_route' => 'bar', 'locale' => 'en'), $matcher->match('/bar/bar')); | ||
370 | } | ||
371 | |||
372 | /** | ||
373 | * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException | ||
374 | */ | ||
375 | public function testWithOutHostHostDoesNotMatch() | ||
376 | { | ||
377 | $coll = new RouteCollection(); | ||
378 | $coll->add('foo', new Route('/foo/{foo}', array(), array(), array(), '{locale}.example.com')); | ||
379 | |||
380 | $matcher = new UrlMatcher($coll, new RequestContext('', 'GET', 'example.com')); | ||
381 | $matcher->match('/foo/bar'); | ||
382 | } | ||
383 | } | ||