4 * This file is part of the Symfony package.
6 * (c) Fabien Potencier <fabien@symfony.com>
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
12 namespace Symfony\Component\Routing\Tests;
14 use PHPUnit\Framework\TestCase;
15 use Symfony\Component\Routing\Route;
16 use Symfony\Component\Routing\RouteCompiler;
18 class RouteCompilerTest extends TestCase
21 * @dataProvider provideCompileData
23 public function testCompile($name, $arguments, $prefix, $regex, $variables, $tokens)
25 $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route');
26 $route = $r->newInstanceArgs($arguments);
28 $compiled = $route->compile();
29 $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)');
30 $this->assertEquals($regex, $compiled->getRegex(), $name.' (regex)');
31 $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)');
32 $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)');
35 public function provideCompileData()
41 '/foo', '#^/foo$#s', array(), array(
42 array('text', '/foo'),
47 'Route with a variable',
49 '/foo', '#^/foo/(?P<bar>[^/]++)$#s', array('bar'), array(
50 array('variable', '/', '[^/]++', 'bar'),
51 array('text', '/foo'),
56 'Route with a variable that has a default value',
57 array('/foo/{bar}', array('bar' => 'bar')),
58 '/foo', '#^/foo(?:/(?P<bar>[^/]++))?$#s', array('bar'), array(
59 array('variable', '/', '[^/]++', 'bar'),
60 array('text', '/foo'),
65 'Route with several variables',
66 array('/foo/{bar}/{foobar}'),
67 '/foo', '#^/foo/(?P<bar>[^/]++)/(?P<foobar>[^/]++)$#s', array('bar', 'foobar'), array(
68 array('variable', '/', '[^/]++', 'foobar'),
69 array('variable', '/', '[^/]++', 'bar'),
70 array('text', '/foo'),
75 'Route with several variables that have default values',
76 array('/foo/{bar}/{foobar}', array('bar' => 'bar', 'foobar' => '')),
77 '/foo', '#^/foo(?:/(?P<bar>[^/]++)(?:/(?P<foobar>[^/]++))?)?$#s', array('bar', 'foobar'), array(
78 array('variable', '/', '[^/]++', 'foobar'),
79 array('variable', '/', '[^/]++', 'bar'),
80 array('text', '/foo'),
85 'Route with several variables but some of them have no default values',
86 array('/foo/{bar}/{foobar}', array('bar' => 'bar')),
87 '/foo', '#^/foo/(?P<bar>[^/]++)/(?P<foobar>[^/]++)$#s', array('bar', 'foobar'), array(
88 array('variable', '/', '[^/]++', 'foobar'),
89 array('variable', '/', '[^/]++', 'bar'),
90 array('text', '/foo'),
95 'Route with an optional variable as the first segment',
96 array('/{bar}', array('bar' => 'bar')),
97 '', '#^/(?P<bar>[^/]++)?$#s', array('bar'), array(
98 array('variable', '/', '[^/]++', 'bar'),
103 'Route with a requirement of 0',
104 array('/{bar}', array('bar' => null), array('bar' => '0')),
105 '', '#^/(?P<bar>0)?$#s', array('bar'), array(
106 array('variable', '/', '0', 'bar'),
111 'Route with an optional variable as the first segment with requirements',
112 array('/{bar}', array('bar' => 'bar'), array('bar' => '(foo|bar)')),
113 '', '#^/(?P<bar>(foo|bar))?$#s', array('bar'), array(
114 array('variable', '/', '(foo|bar)', 'bar'),
119 'Route with only optional variables',
120 array('/{foo}/{bar}', array('foo' => 'foo', 'bar' => 'bar')),
121 '', '#^/(?P<foo>[^/]++)?(?:/(?P<bar>[^/]++))?$#s', array('foo', 'bar'), array(
122 array('variable', '/', '[^/]++', 'bar'),
123 array('variable', '/', '[^/]++', 'foo'),
128 'Route with a variable in last position',
130 '/foo', '#^/foo\-(?P<bar>[^/]++)$#s', array('bar'), array(
131 array('variable', '-', '[^/]++', 'bar'),
132 array('text', '/foo'),
137 'Route with nested placeholders',
138 array('/{static{var}static}'),
139 '/{static', '#^/\{static(?P<var>[^/]+)static\}$#s', array('var'), array(
140 array('text', 'static}'),
141 array('variable', '', '[^/]+', 'var'),
142 array('text', '/{static'),
147 'Route without separator between variables',
148 array('/{w}{x}{y}{z}.{_format}', array('z' => 'default-z', '_format' => 'html'), array('y' => '(y|Y)')),
149 '', '#^/(?P<w>[^/\.]+)(?P<x>[^/\.]+)(?P<y>(y|Y))(?:(?P<z>[^/\.]++)(?:\.(?P<_format>[^/]++))?)?$#s', array('w', 'x', 'y', 'z', '_format'), array(
150 array('variable', '.', '[^/]++', '_format'),
151 array('variable', '', '[^/\.]++', 'z'),
152 array('variable', '', '(y|Y)', 'y'),
153 array('variable', '', '[^/\.]+', 'x'),
154 array('variable', '/', '[^/\.]+', 'w'),
159 'Route with a format',
160 array('/foo/{bar}.{_format}'),
161 '/foo', '#^/foo/(?P<bar>[^/\.]++)\.(?P<_format>[^/]++)$#s', array('bar', '_format'), array(
162 array('variable', '.', '[^/]++', '_format'),
163 array('variable', '/', '[^/\.]++', 'bar'),
164 array('text', '/foo'),
171 * @expectedException \LogicException
173 public function testRouteWithSameVariableTwice()
175 $route = new Route('/{name}/{name}');
177 $compiled = $route->compile();
181 * @dataProvider getVariableNamesStartingWithADigit
182 * @expectedException \DomainException
184 public function testRouteWithVariableNameStartingWithADigit($name)
186 $route = new Route('/{'.$name.'}');
190 public function getVariableNamesStartingWithADigit()
200 * @dataProvider provideCompileWithHostData
202 public function testCompileWithHost($name, $arguments, $prefix, $regex, $variables, $pathVariables, $tokens, $hostRegex, $hostVariables, $hostTokens)
204 $r = new \ReflectionClass('Symfony\\Component\\Routing\\Route');
205 $route = $r->newInstanceArgs($arguments);
207 $compiled = $route->compile();
208 $this->assertEquals($prefix, $compiled->getStaticPrefix(), $name.' (static prefix)');
209 $this->assertEquals($regex, str_replace(array("\n", ' '), '', $compiled->getRegex()), $name.' (regex)');
210 $this->assertEquals($variables, $compiled->getVariables(), $name.' (variables)');
211 $this->assertEquals($pathVariables, $compiled->getPathVariables(), $name.' (path variables)');
212 $this->assertEquals($tokens, $compiled->getTokens(), $name.' (tokens)');
213 $this->assertEquals($hostRegex, str_replace(array("\n", ' '), '', $compiled->getHostRegex()), $name.' (host regex)');
214 $this->assertEquals($hostVariables, $compiled->getHostVariables(), $name.' (host variables)');
215 $this->assertEquals($hostTokens, $compiled->getHostTokens(), $name.' (host tokens)');
218 public function provideCompileWithHostData()
222 'Route with host pattern',
223 array('/hello', array(), array(), array(), 'www.example.com'),
224 '/hello', '#^/hello$#s', array(), array(), array(
225 array('text', '/hello'),
227 '#^www\.example\.com$#si', array(), array(
228 array('text', 'www.example.com'),
232 'Route with host pattern and some variables',
233 array('/hello/{name}', array(), array(), array(), 'www.example.{tld}'),
234 '/hello', '#^/hello/(?P<name>[^/]++)$#s', array('tld', 'name'), array('name'), array(
235 array('variable', '/', '[^/]++', 'name'),
236 array('text', '/hello'),
238 '#^www\.example\.(?P<tld>[^\.]++)$#si', array('tld'), array(
239 array('variable', '.', '[^\.]++', 'tld'),
240 array('text', 'www.example'),
244 'Route with variable at beginning of host',
245 array('/hello', array(), array(), array(), '{locale}.example.{tld}'),
246 '/hello', '#^/hello$#s', array('locale', 'tld'), array(), array(
247 array('text', '/hello'),
249 '#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#si', array('locale', 'tld'), array(
250 array('variable', '.', '[^\.]++', 'tld'),
251 array('text', '.example'),
252 array('variable', '', '[^\.]++', 'locale'),
256 'Route with host variables that has a default value',
257 array('/hello', array('locale' => 'a', 'tld' => 'b'), array(), array(), '{locale}.example.{tld}'),
258 '/hello', '#^/hello$#s', array('locale', 'tld'), array(), array(
259 array('text', '/hello'),
261 '#^(?P<locale>[^\.]++)\.example\.(?P<tld>[^\.]++)$#si', array('locale', 'tld'), array(
262 array('variable', '.', '[^\.]++', 'tld'),
263 array('text', '.example'),
264 array('variable', '', '[^\.]++', 'locale'),
271 * @expectedException \DomainException
273 public function testRouteWithTooLongVariableName()
275 $route = new Route(sprintf('/{%s}', str_repeat('a', RouteCompiler::VARIABLE_MAXIMUM_LENGTH + 1)));