Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / symfony / routing / Tests / Generator / UrlGeneratorTest.php
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\Generator;
13
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\Routing\Generator\UrlGenerator;
16 use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
17 use Symfony\Component\Routing\RequestContext;
18 use Symfony\Component\Routing\Route;
19 use Symfony\Component\Routing\RouteCollection;
20
21 class UrlGeneratorTest extends TestCase
22 {
23     public function testAbsoluteUrlWithPort80()
24     {
25         $routes = $this->getRoutes('test', new Route('/testing'));
26         $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
27
28         $this->assertEquals('http://localhost/app.php/testing', $url);
29     }
30
31     public function testAbsoluteSecureUrlWithPort443()
32     {
33         $routes = $this->getRoutes('test', new Route('/testing'));
34         $url = $this->getGenerator($routes, array('scheme' => 'https'))->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
35
36         $this->assertEquals('https://localhost/app.php/testing', $url);
37     }
38
39     public function testAbsoluteUrlWithNonStandardPort()
40     {
41         $routes = $this->getRoutes('test', new Route('/testing'));
42         $url = $this->getGenerator($routes, array('httpPort' => 8080))->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
43
44         $this->assertEquals('http://localhost:8080/app.php/testing', $url);
45     }
46
47     public function testAbsoluteSecureUrlWithNonStandardPort()
48     {
49         $routes = $this->getRoutes('test', new Route('/testing'));
50         $url = $this->getGenerator($routes, array('httpsPort' => 8080, 'scheme' => 'https'))->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
51
52         $this->assertEquals('https://localhost:8080/app.php/testing', $url);
53     }
54
55     public function testRelativeUrlWithoutParameters()
56     {
57         $routes = $this->getRoutes('test', new Route('/testing'));
58         $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH);
59
60         $this->assertEquals('/app.php/testing', $url);
61     }
62
63     public function testRelativeUrlWithParameter()
64     {
65         $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
66         $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_PATH);
67
68         $this->assertEquals('/app.php/testing/bar', $url);
69     }
70
71     public function testRelativeUrlWithNullParameter()
72     {
73         $routes = $this->getRoutes('test', new Route('/testing.{format}', array('format' => null)));
74         $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH);
75
76         $this->assertEquals('/app.php/testing', $url);
77     }
78
79     /**
80      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
81      */
82     public function testRelativeUrlWithNullParameterButNotOptional()
83     {
84         $routes = $this->getRoutes('test', new Route('/testing/{foo}/bar', array('foo' => null)));
85         // This must raise an exception because the default requirement for "foo" is "[^/]+" which is not met with these params.
86         // Generating path "/testing//bar" would be wrong as matching this route would fail.
87         $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH);
88     }
89
90     public function testRelativeUrlWithOptionalZeroParameter()
91     {
92         $routes = $this->getRoutes('test', new Route('/testing/{page}'));
93         $url = $this->getGenerator($routes)->generate('test', array('page' => 0), UrlGeneratorInterface::ABSOLUTE_PATH);
94
95         $this->assertEquals('/app.php/testing/0', $url);
96     }
97
98     public function testNotPassedOptionalParameterInBetween()
99     {
100         $routes = $this->getRoutes('test', new Route('/{slug}/{page}', array('slug' => 'index', 'page' => 0)));
101         $this->assertSame('/app.php/index/1', $this->getGenerator($routes)->generate('test', array('page' => 1)));
102         $this->assertSame('/app.php/', $this->getGenerator($routes)->generate('test'));
103     }
104
105     public function testRelativeUrlWithExtraParameters()
106     {
107         $routes = $this->getRoutes('test', new Route('/testing'));
108         $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_PATH);
109
110         $this->assertEquals('/app.php/testing?foo=bar', $url);
111     }
112
113     public function testAbsoluteUrlWithExtraParameters()
114     {
115         $routes = $this->getRoutes('test', new Route('/testing'));
116         $url = $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL);
117
118         $this->assertEquals('http://localhost/app.php/testing?foo=bar', $url);
119     }
120
121     public function testUrlWithNullExtraParameters()
122     {
123         $routes = $this->getRoutes('test', new Route('/testing'));
124         $url = $this->getGenerator($routes)->generate('test', array('foo' => null), UrlGeneratorInterface::ABSOLUTE_URL);
125
126         $this->assertEquals('http://localhost/app.php/testing', $url);
127     }
128
129     public function testUrlWithExtraParametersFromGlobals()
130     {
131         $routes = $this->getRoutes('test', new Route('/testing'));
132         $generator = $this->getGenerator($routes);
133         $context = new RequestContext('/app.php');
134         $context->setParameter('bar', 'bar');
135         $generator->setContext($context);
136         $url = $generator->generate('test', array('foo' => 'bar'));
137
138         $this->assertEquals('/app.php/testing?foo=bar', $url);
139     }
140
141     public function testUrlWithGlobalParameter()
142     {
143         $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
144         $generator = $this->getGenerator($routes);
145         $context = new RequestContext('/app.php');
146         $context->setParameter('foo', 'bar');
147         $generator->setContext($context);
148         $url = $generator->generate('test', array());
149
150         $this->assertEquals('/app.php/testing/bar', $url);
151     }
152
153     public function testGlobalParameterHasHigherPriorityThanDefault()
154     {
155         $routes = $this->getRoutes('test', new Route('/{_locale}', array('_locale' => 'en')));
156         $generator = $this->getGenerator($routes);
157         $context = new RequestContext('/app.php');
158         $context->setParameter('_locale', 'de');
159         $generator->setContext($context);
160         $url = $generator->generate('test', array());
161
162         $this->assertSame('/app.php/de', $url);
163     }
164
165     /**
166      * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException
167      */
168     public function testGenerateWithoutRoutes()
169     {
170         $routes = $this->getRoutes('foo', new Route('/testing/{foo}'));
171         $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
172     }
173
174     /**
175      * @expectedException \Symfony\Component\Routing\Exception\MissingMandatoryParametersException
176      */
177     public function testGenerateForRouteWithoutMandatoryParameter()
178     {
179         $routes = $this->getRoutes('test', new Route('/testing/{foo}'));
180         $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL);
181     }
182
183     /**
184      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
185      */
186     public function testGenerateForRouteWithInvalidOptionalParameter()
187     {
188         $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
189         $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL);
190     }
191
192     /**
193      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
194      */
195     public function testGenerateForRouteWithInvalidParameter()
196     {
197         $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => '1|2')));
198         $this->getGenerator($routes)->generate('test', array('foo' => '0'), UrlGeneratorInterface::ABSOLUTE_URL);
199     }
200
201     public function testGenerateForRouteWithInvalidOptionalParameterNonStrict()
202     {
203         $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
204         $generator = $this->getGenerator($routes);
205         $generator->setStrictRequirements(false);
206         $this->assertNull($generator->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL));
207     }
208
209     public function testGenerateForRouteWithInvalidOptionalParameterNonStrictWithLogger()
210     {
211         $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
212         $logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
213         $logger->expects($this->once())
214             ->method('error');
215         $generator = $this->getGenerator($routes, array(), $logger);
216         $generator->setStrictRequirements(false);
217         $this->assertNull($generator->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL));
218     }
219
220     public function testGenerateForRouteWithInvalidParameterButDisabledRequirementsCheck()
221     {
222         $routes = $this->getRoutes('test', new Route('/testing/{foo}', array('foo' => '1'), array('foo' => 'd+')));
223         $generator = $this->getGenerator($routes);
224         $generator->setStrictRequirements(null);
225         $this->assertSame('/app.php/testing/bar', $generator->generate('test', array('foo' => 'bar')));
226     }
227
228     /**
229      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
230      */
231     public function testGenerateForRouteWithInvalidMandatoryParameter()
232     {
233         $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => 'd+')));
234         $this->getGenerator($routes)->generate('test', array('foo' => 'bar'), UrlGeneratorInterface::ABSOLUTE_URL);
235     }
236
237     /**
238      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
239      */
240     public function testGenerateForRouteWithInvalidUtf8Parameter()
241     {
242         $routes = $this->getRoutes('test', new Route('/testing/{foo}', array(), array('foo' => '\pL+'), array('utf8' => true)));
243         $this->getGenerator($routes)->generate('test', array('foo' => 'abc123'), UrlGeneratorInterface::ABSOLUTE_URL);
244     }
245
246     /**
247      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
248      */
249     public function testRequiredParamAndEmptyPassed()
250     {
251         $routes = $this->getRoutes('test', new Route('/{slug}', array(), array('slug' => '.+')));
252         $this->getGenerator($routes)->generate('test', array('slug' => ''));
253     }
254
255     public function testSchemeRequirementDoesNothingIfSameCurrentScheme()
256     {
257         $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('http')));
258         $this->assertEquals('/app.php/', $this->getGenerator($routes)->generate('test'));
259
260         $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('https')));
261         $this->assertEquals('/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
262     }
263
264     public function testSchemeRequirementForcesAbsoluteUrl()
265     {
266         $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('https')));
267         $this->assertEquals('https://localhost/app.php/', $this->getGenerator($routes)->generate('test'));
268
269         $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('http')));
270         $this->assertEquals('http://localhost/app.php/', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test'));
271     }
272
273     public function testSchemeRequirementCreatesUrlForFirstRequiredScheme()
274     {
275         $routes = $this->getRoutes('test', new Route('/', array(), array(), array(), '', array('Ftp', 'https')));
276         $this->assertEquals('ftp://localhost/app.php/', $this->getGenerator($routes)->generate('test'));
277     }
278
279     public function testPathWithTwoStartingSlashes()
280     {
281         $routes = $this->getRoutes('test', new Route('//path-and-not-domain'));
282
283         // this must not generate '//path-and-not-domain' because that would be a network path
284         $this->assertSame('/path-and-not-domain', $this->getGenerator($routes, array('BaseUrl' => ''))->generate('test'));
285     }
286
287     public function testNoTrailingSlashForMultipleOptionalParameters()
288     {
289         $routes = $this->getRoutes('test', new Route('/category/{slug1}/{slug2}/{slug3}', array('slug2' => null, 'slug3' => null)));
290
291         $this->assertEquals('/app.php/category/foo', $this->getGenerator($routes)->generate('test', array('slug1' => 'foo')));
292     }
293
294     public function testWithAnIntegerAsADefaultValue()
295     {
296         $routes = $this->getRoutes('test', new Route('/{default}', array('default' => 0)));
297
298         $this->assertEquals('/app.php/foo', $this->getGenerator($routes)->generate('test', array('default' => 'foo')));
299     }
300
301     public function testNullForOptionalParameterIsIgnored()
302     {
303         $routes = $this->getRoutes('test', new Route('/test/{default}', array('default' => 0)));
304
305         $this->assertEquals('/app.php/test', $this->getGenerator($routes)->generate('test', array('default' => null)));
306     }
307
308     public function testQueryParamSameAsDefault()
309     {
310         $routes = $this->getRoutes('test', new Route('/test', array('page' => 1)));
311
312         $this->assertSame('/app.php/test?page=2', $this->getGenerator($routes)->generate('test', array('page' => 2)));
313         $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('page' => 1)));
314         $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('page' => '1')));
315         $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test'));
316     }
317
318     public function testArrayQueryParamSameAsDefault()
319     {
320         $routes = $this->getRoutes('test', new Route('/test', array('array' => array('foo', 'bar'))));
321
322         $this->assertSame('/app.php/test?array%5B0%5D=bar&array%5B1%5D=foo', $this->getGenerator($routes)->generate('test', array('array' => array('bar', 'foo'))));
323         $this->assertSame('/app.php/test?array%5Ba%5D=foo&array%5Bb%5D=bar', $this->getGenerator($routes)->generate('test', array('array' => array('a' => 'foo', 'b' => 'bar'))));
324         $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('array' => array('foo', 'bar'))));
325         $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test', array('array' => array(1 => 'bar', 0 => 'foo'))));
326         $this->assertSame('/app.php/test', $this->getGenerator($routes)->generate('test'));
327     }
328
329     public function testGenerateWithSpecialRouteName()
330     {
331         $routes = $this->getRoutes('$péß^a|', new Route('/bar'));
332
333         $this->assertSame('/app.php/bar', $this->getGenerator($routes)->generate('$péß^a|'));
334     }
335
336     public function testUrlEncoding()
337     {
338         $expectedPath = '/app.php/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
339             .'/@:%5B%5D/%28%29*%27%22%20+,;-._~%26%24%3C%3E|%7B%7D%25%5C%5E%60!%3Ffoo=bar%23id'
340             .'?query=%40%3A%5B%5D/%28%29%2A%27%22%20%2B%2C%3B-._~%26%24%3C%3E%7C%7B%7D%25%5C%5E%60%21%3Ffoo%3Dbar%23id';
341
342         // This tests the encoding of reserved characters that are used for delimiting of URI components (defined in RFC 3986)
343         // and other special ASCII chars. These chars are tested as static text path, variable path and query param.
344         $chars = '@:[]/()*\'" +,;-._~&$<>|{}%\\^`!?foo=bar#id';
345         $routes = $this->getRoutes('test', new Route("/$chars/{varpath}", array(), array('varpath' => '.+')));
346         $this->assertSame($expectedPath, $this->getGenerator($routes)->generate('test', array(
347             'varpath' => $chars,
348             'query' => $chars,
349         )));
350     }
351
352     public function testEncodingOfRelativePathSegments()
353     {
354         $routes = $this->getRoutes('test', new Route('/dir/../dir/..'));
355         $this->assertSame('/app.php/dir/%2E%2E/dir/%2E%2E', $this->getGenerator($routes)->generate('test'));
356         $routes = $this->getRoutes('test', new Route('/dir/./dir/.'));
357         $this->assertSame('/app.php/dir/%2E/dir/%2E', $this->getGenerator($routes)->generate('test'));
358         $routes = $this->getRoutes('test', new Route('/a./.a/a../..a/...'));
359         $this->assertSame('/app.php/a./.a/a../..a/...', $this->getGenerator($routes)->generate('test'));
360     }
361
362     public function testAdjacentVariables()
363     {
364         $routes = $this->getRoutes('test', new Route('/{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '\d+')));
365         $generator = $this->getGenerator($routes);
366         $this->assertSame('/app.php/foo123', $generator->generate('test', array('x' => 'foo', 'y' => '123')));
367         $this->assertSame('/app.php/foo123bar.xml', $generator->generate('test', array('x' => 'foo', 'y' => '123', 'z' => 'bar', '_format' => 'xml')));
368
369         // The default requirement for 'x' should not allow the separator '.' in this case because it would otherwise match everything
370         // and following optional variables like _format could never match.
371         $this->{method_exists($this, $_ = 'expectException') ? $_ : 'setExpectedException'}('Symfony\Component\Routing\Exception\InvalidParameterException');
372         $generator->generate('test', array('x' => 'do.t', 'y' => '123', 'z' => 'bar', '_format' => 'xml'));
373     }
374
375     public function testOptionalVariableWithNoRealSeparator()
376     {
377         $routes = $this->getRoutes('test', new Route('/get{what}', array('what' => 'All')));
378         $generator = $this->getGenerator($routes);
379
380         $this->assertSame('/app.php/get', $generator->generate('test'));
381         $this->assertSame('/app.php/getSites', $generator->generate('test', array('what' => 'Sites')));
382     }
383
384     public function testRequiredVariableWithNoRealSeparator()
385     {
386         $routes = $this->getRoutes('test', new Route('/get{what}Suffix'));
387         $generator = $this->getGenerator($routes);
388
389         $this->assertSame('/app.php/getSitesSuffix', $generator->generate('test', array('what' => 'Sites')));
390     }
391
392     public function testDefaultRequirementOfVariable()
393     {
394         $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
395         $generator = $this->getGenerator($routes);
396
397         $this->assertSame('/app.php/index.mobile.html', $generator->generate('test', array('page' => 'index', '_format' => 'mobile.html')));
398     }
399
400     /**
401      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
402      */
403     public function testDefaultRequirementOfVariableDisallowsSlash()
404     {
405         $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
406         $this->getGenerator($routes)->generate('test', array('page' => 'index', '_format' => 'sl/ash'));
407     }
408
409     /**
410      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
411      */
412     public function testDefaultRequirementOfVariableDisallowsNextSeparator()
413     {
414         $routes = $this->getRoutes('test', new Route('/{page}.{_format}'));
415         $this->getGenerator($routes)->generate('test', array('page' => 'do.t', '_format' => 'html'));
416     }
417
418     public function testWithHostDifferentFromContext()
419     {
420         $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
421
422         $this->assertEquals('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test', array('name' => 'Fabien', 'locale' => 'fr')));
423     }
424
425     public function testWithHostSameAsContext()
426     {
427         $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
428
429         $this->assertEquals('/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' => 'Fabien', 'locale' => 'fr')));
430     }
431
432     public function testWithHostSameAsContextAndAbsolute()
433     {
434         $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com'));
435
436         $this->assertEquals('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test', array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL));
437     }
438
439     /**
440      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
441      */
442     public function testUrlWithInvalidParameterInHost()
443     {
444         $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
445         $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH);
446     }
447
448     /**
449      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
450      */
451     public function testUrlWithInvalidParameterInHostWhenParamHasADefaultValue()
452     {
453         $routes = $this->getRoutes('test', new Route('/', array('foo' => 'bar'), array('foo' => 'bar'), array(), '{foo}.example.com'));
454         $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH);
455     }
456
457     /**
458      * @expectedException \Symfony\Component\Routing\Exception\InvalidParameterException
459      */
460     public function testUrlWithInvalidParameterEqualsDefaultValueInHost()
461     {
462         $routes = $this->getRoutes('test', new Route('/', array('foo' => 'baz'), array('foo' => 'bar'), array(), '{foo}.example.com'));
463         $this->getGenerator($routes)->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH);
464     }
465
466     public function testUrlWithInvalidParameterInHostInNonStrictMode()
467     {
468         $routes = $this->getRoutes('test', new Route('/', array(), array('foo' => 'bar'), array(), '{foo}.example.com'));
469         $generator = $this->getGenerator($routes);
470         $generator->setStrictRequirements(false);
471         $this->assertNull($generator->generate('test', array('foo' => 'baz'), UrlGeneratorInterface::ABSOLUTE_PATH));
472     }
473
474     public function testHostIsCaseInsensitive()
475     {
476         $routes = $this->getRoutes('test', new Route('/', array(), array('locale' => 'en|de|fr'), array(), '{locale}.FooBar.com'));
477         $generator = $this->getGenerator($routes);
478         $this->assertSame('//EN.FooBar.com/app.php/', $generator->generate('test', array('locale' => 'EN'), UrlGeneratorInterface::NETWORK_PATH));
479     }
480
481     public function testDefaultHostIsUsedWhenContextHostIsEmpty()
482     {
483         $routes = $this->getRoutes('test', new Route('/route', array('domain' => 'my.fallback.host'), array('domain' => '.+'), array(), '{domain}', array('http')));
484
485         $generator = $this->getGenerator($routes);
486         $generator->getContext()->setHost('');
487
488         $this->assertSame('http://my.fallback.host/app.php/route', $generator->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL));
489     }
490
491     public function testDefaultHostIsUsedWhenContextHostIsEmptyAndSchemeIsNot()
492     {
493         $routes = $this->getRoutes('test', new Route('/route', array('domain' => 'my.fallback.host'), array('domain' => '.+'), array(), '{domain}', array('http', 'https')));
494
495         $generator = $this->getGenerator($routes);
496         $generator->getContext()->setHost('');
497         $generator->getContext()->setScheme('https');
498
499         $this->assertSame('https://my.fallback.host/app.php/route', $generator->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL));
500     }
501
502     public function testAbsoluteUrlFallbackToRelativeIfHostIsEmptyAndSchemeIsNot()
503     {
504         $routes = $this->getRoutes('test', new Route('/route', array(), array(), array(), '', array('http', 'https')));
505
506         $generator = $this->getGenerator($routes);
507         $generator->getContext()->setHost('');
508         $generator->getContext()->setScheme('https');
509
510         $this->assertSame('/app.php/route', $generator->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_URL));
511     }
512
513     public function testGenerateNetworkPath()
514     {
515         $routes = $this->getRoutes('test', new Route('/{name}', array(), array(), array(), '{locale}.example.com', array('http')));
516
517         $this->assertSame('//fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
518             array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'network path with different host'
519         );
520         $this->assertSame('//fr.example.com/app.php/Fabien?query=string', $this->getGenerator($routes, array('host' => 'fr.example.com'))->generate('test',
521             array('name' => 'Fabien', 'locale' => 'fr', 'query' => 'string'), UrlGeneratorInterface::NETWORK_PATH), 'network path although host same as context'
522         );
523         $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes, array('scheme' => 'https'))->generate('test',
524             array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::NETWORK_PATH), 'absolute URL because scheme requirement does not match context'
525         );
526         $this->assertSame('http://fr.example.com/app.php/Fabien', $this->getGenerator($routes)->generate('test',
527             array('name' => 'Fabien', 'locale' => 'fr'), UrlGeneratorInterface::ABSOLUTE_URL), 'absolute URL with same scheme because it is requested'
528         );
529     }
530
531     public function testGenerateRelativePath()
532     {
533         $routes = new RouteCollection();
534         $routes->add('article', new Route('/{author}/{article}/'));
535         $routes->add('comments', new Route('/{author}/{article}/comments'));
536         $routes->add('host', new Route('/{article}', array(), array(), array(), '{author}.example.com'));
537         $routes->add('scheme', new Route('/{author}/blog', array(), array(), array(), '', array('https')));
538         $routes->add('unrelated', new Route('/about'));
539
540         $generator = $this->getGenerator($routes, array('host' => 'example.com', 'pathInfo' => '/fabien/symfony-is-great/'));
541
542         $this->assertSame('comments', $generator->generate('comments',
543             array('author' => 'fabien', 'article' => 'symfony-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
544         );
545         $this->assertSame('comments?page=2', $generator->generate('comments',
546             array('author' => 'fabien', 'article' => 'symfony-is-great', 'page' => 2), UrlGeneratorInterface::RELATIVE_PATH)
547         );
548         $this->assertSame('../twig-is-great/', $generator->generate('article',
549             array('author' => 'fabien', 'article' => 'twig-is-great'), UrlGeneratorInterface::RELATIVE_PATH)
550         );
551         $this->assertSame('../../bernhard/forms-are-great/', $generator->generate('article',
552             array('author' => 'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
553         );
554         $this->assertSame('//bernhard.example.com/app.php/forms-are-great', $generator->generate('host',
555             array('author' => 'bernhard', 'article' => 'forms-are-great'), UrlGeneratorInterface::RELATIVE_PATH)
556         );
557         $this->assertSame('https://example.com/app.php/bernhard/blog', $generator->generate('scheme',
558                 array('author' => 'bernhard'), UrlGeneratorInterface::RELATIVE_PATH)
559         );
560         $this->assertSame('../../about', $generator->generate('unrelated',
561             array(), UrlGeneratorInterface::RELATIVE_PATH)
562         );
563     }
564
565     /**
566      * @dataProvider provideRelativePaths
567      */
568     public function testGetRelativePath($sourcePath, $targetPath, $expectedPath)
569     {
570         $this->assertSame($expectedPath, UrlGenerator::getRelativePath($sourcePath, $targetPath));
571     }
572
573     public function provideRelativePaths()
574     {
575         return array(
576             array(
577                 '/same/dir/',
578                 '/same/dir/',
579                 '',
580             ),
581             array(
582                 '/same/file',
583                 '/same/file',
584                 '',
585             ),
586             array(
587                 '/',
588                 '/file',
589                 'file',
590             ),
591             array(
592                 '/',
593                 '/dir/file',
594                 'dir/file',
595             ),
596             array(
597                 '/dir/file.html',
598                 '/dir/different-file.html',
599                 'different-file.html',
600             ),
601             array(
602                 '/same/dir/extra-file',
603                 '/same/dir/',
604                 './',
605             ),
606             array(
607                 '/parent/dir/',
608                 '/parent/',
609                 '../',
610             ),
611             array(
612                 '/parent/dir/extra-file',
613                 '/parent/',
614                 '../',
615             ),
616             array(
617                 '/a/b/',
618                 '/x/y/z/',
619                 '../../x/y/z/',
620             ),
621             array(
622                 '/a/b/c/d/e',
623                 '/a/c/d',
624                 '../../../c/d',
625             ),
626             array(
627                 '/a/b/c//',
628                 '/a/b/c/',
629                 '../',
630             ),
631             array(
632                 '/a/b/c/',
633                 '/a/b/c//',
634                 './/',
635             ),
636             array(
637                 '/root/a/b/c/',
638                 '/root/x/b/c/',
639                 '../../../x/b/c/',
640             ),
641             array(
642                 '/a/b/c/d/',
643                 '/a',
644                 '../../../../a',
645             ),
646             array(
647                 '/special-chars/sp%20ce/1€/mäh/e=mc²',
648                 '/special-chars/sp%20ce/1€/<µ>/e=mc²',
649                 '../<µ>/e=mc²',
650             ),
651             array(
652                 'not-rooted',
653                 'dir/file',
654                 'dir/file',
655             ),
656             array(
657                 '//dir/',
658                 '',
659                 '../../',
660             ),
661             array(
662                 '/dir/',
663                 '/dir/file:with-colon',
664                 './file:with-colon',
665             ),
666             array(
667                 '/dir/',
668                 '/dir/subdir/file:with-colon',
669                 'subdir/file:with-colon',
670             ),
671             array(
672                 '/dir/',
673                 '/dir/:subdir/',
674                 './:subdir/',
675             ),
676         );
677     }
678
679     public function testFragmentsCanBeAppendedToUrls()
680     {
681         $routes = $this->getRoutes('test', new Route('/testing'));
682
683         $url = $this->getGenerator($routes)->generate('test', array('_fragment' => 'frag ment'), UrlGeneratorInterface::ABSOLUTE_PATH);
684         $this->assertEquals('/app.php/testing#frag%20ment', $url);
685
686         $url = $this->getGenerator($routes)->generate('test', array('_fragment' => '0'), UrlGeneratorInterface::ABSOLUTE_PATH);
687         $this->assertEquals('/app.php/testing#0', $url);
688     }
689
690     public function testFragmentsDoNotEscapeValidCharacters()
691     {
692         $routes = $this->getRoutes('test', new Route('/testing'));
693         $url = $this->getGenerator($routes)->generate('test', array('_fragment' => '?/'), UrlGeneratorInterface::ABSOLUTE_PATH);
694
695         $this->assertEquals('/app.php/testing#?/', $url);
696     }
697
698     public function testFragmentsCanBeDefinedAsDefaults()
699     {
700         $routes = $this->getRoutes('test', new Route('/testing', array('_fragment' => 'fragment')));
701         $url = $this->getGenerator($routes)->generate('test', array(), UrlGeneratorInterface::ABSOLUTE_PATH);
702
703         $this->assertEquals('/app.php/testing#fragment', $url);
704     }
705
706     protected function getGenerator(RouteCollection $routes, array $parameters = array(), $logger = null)
707     {
708         $context = new RequestContext('/app.php');
709         foreach ($parameters as $key => $value) {
710             $method = 'set'.$key;
711             $context->$method($value);
712         }
713
714         return new UrlGenerator($routes, $context, $logger);
715     }
716
717     protected function getRoutes($name, Route $route)
718     {
719         $routes = new RouteCollection();
720         $routes->add($name, $route);
721
722         return $routes;
723     }
724 }