1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace Symfony\Component\Routing\Tests;
13:
14: use PHPUnit\Framework\TestCase;
15: use Symfony\Component\Routing\Route;
16:
17: class RouteTest extends TestCase
18: {
19: public function testConstructor()
20: {
21: $route = new Route('/{foo}', array('foo' => 'bar'), array('foo' => '\d+'), array('foo' => 'bar'), '{locale}.example.com');
22: $this->assertEquals('/{foo}', $route->getPath(), '__construct() takes a path as its first argument');
23: $this->assertEquals(array('foo' => 'bar'), $route->getDefaults(), '__construct() takes defaults as its second argument');
24: $this->assertEquals(array('foo' => '\d+'), $route->getRequirements(), '__construct() takes requirements as its third argument');
25: $this->assertEquals('bar', $route->getOption('foo'), '__construct() takes options as its fourth argument');
26: $this->assertEquals('{locale}.example.com', $route->getHost(), '__construct() takes a host pattern as its fifth argument');
27:
28: $route = new Route('/', array(), array(), array(), '', array('Https'), array('POST', 'put'), 'context.getMethod() == "GET"');
29: $this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes schemes as its sixth argument and lowercases it');
30: $this->assertEquals(array('POST', 'PUT'), $route->getMethods(), '__construct() takes methods as its seventh argument and uppercases it');
31: $this->assertEquals('context.getMethod() == "GET"', $route->getCondition(), '__construct() takes a condition as its eight argument');
32:
33: $route = new Route('/', array(), array(), array(), '', 'Https', 'Post');
34: $this->assertEquals(array('https'), $route->getSchemes(), '__construct() takes a single scheme as its sixth argument');
35: $this->assertEquals(array('POST'), $route->getMethods(), '__construct() takes a single method as its seventh argument');
36: }
37:
38: public function testPath()
39: {
40: $route = new Route('/{foo}');
41: $route->setPath('/{bar}');
42: $this->assertEquals('/{bar}', $route->getPath(), '->setPath() sets the path');
43: $route->setPath('');
44: $this->assertEquals('/', $route->getPath(), '->setPath() adds a / at the beginning of the path if needed');
45: $route->setPath('bar');
46: $this->assertEquals('/bar', $route->getPath(), '->setPath() adds a / at the beginning of the path if needed');
47: $this->assertEquals($route, $route->setPath(''), '->setPath() implements a fluent interface');
48: $route->setPath('//path');
49: $this->assertEquals('/path', $route->getPath(), '->setPath() does not allow two slashes "//" at the beginning of the path as it would be confused with a network path when generating the path from the route');
50: }
51:
52: public function testOptions()
53: {
54: $route = new Route('/{foo}');
55: $route->setOptions(array('foo' => 'bar'));
56: $this->assertEquals(array_merge(array(
57: 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler',
58: ), array('foo' => 'bar')), $route->getOptions(), '->setOptions() sets the options');
59: $this->assertEquals($route, $route->setOptions(array()), '->setOptions() implements a fluent interface');
60:
61: $route->setOptions(array('foo' => 'foo'));
62: $route->addOptions(array('bar' => 'bar'));
63: $this->assertEquals($route, $route->addOptions(array()), '->addOptions() implements a fluent interface');
64: $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar', 'compiler_class' => 'Symfony\\Component\\Routing\\RouteCompiler'), $route->getOptions(), '->addDefaults() keep previous defaults');
65: }
66:
67: public function testOption()
68: {
69: $route = new Route('/{foo}');
70: $this->assertFalse($route->hasOption('foo'), '->hasOption() return false if option is not set');
71: $this->assertEquals($route, $route->setOption('foo', 'bar'), '->setOption() implements a fluent interface');
72: $this->assertEquals('bar', $route->getOption('foo'), '->setOption() sets the option');
73: $this->assertTrue($route->hasOption('foo'), '->hasOption() return true if option is set');
74: }
75:
76: public function testDefaults()
77: {
78: $route = new Route('/{foo}');
79: $route->setDefaults(array('foo' => 'bar'));
80: $this->assertEquals(array('foo' => 'bar'), $route->getDefaults(), '->setDefaults() sets the defaults');
81: $this->assertEquals($route, $route->setDefaults(array()), '->setDefaults() implements a fluent interface');
82:
83: $route->setDefault('foo', 'bar');
84: $this->assertEquals('bar', $route->getDefault('foo'), '->setDefault() sets a default value');
85:
86: $route->setDefault('foo2', 'bar2');
87: $this->assertEquals('bar2', $route->getDefault('foo2'), '->getDefault() return the default value');
88: $this->assertNull($route->getDefault('not_defined'), '->getDefault() return null if default value is not set');
89:
90: $route->setDefault('_controller', $closure = function () { return 'Hello'; });
91: $this->assertEquals($closure, $route->getDefault('_controller'), '->setDefault() sets a default value');
92:
93: $route->setDefaults(array('foo' => 'foo'));
94: $route->addDefaults(array('bar' => 'bar'));
95: $this->assertEquals($route, $route->addDefaults(array()), '->addDefaults() implements a fluent interface');
96: $this->assertEquals(array('foo' => 'foo', 'bar' => 'bar'), $route->getDefaults(), '->addDefaults() keep previous defaults');
97: }
98:
99: public function testRequirements()
100: {
101: $route = new Route('/{foo}');
102: $route->setRequirements(array('foo' => '\d+'));
103: $this->assertEquals(array('foo' => '\d+'), $route->getRequirements(), '->setRequirements() sets the requirements');
104: $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() returns a requirement');
105: $this->assertNull($route->getRequirement('bar'), '->getRequirement() returns null if a requirement is not defined');
106: $route->setRequirements(array('foo' => '^\d+$'));
107: $this->assertEquals('\d+', $route->getRequirement('foo'), '->getRequirement() removes ^ and $ from the path');
108: $this->assertEquals($route, $route->setRequirements(array()), '->setRequirements() implements a fluent interface');
109:
110: $route->setRequirements(array('foo' => '\d+'));
111: $route->addRequirements(array('bar' => '\d+'));
112: $this->assertEquals($route, $route->addRequirements(array()), '->addRequirements() implements a fluent interface');
113: $this->assertEquals(array('foo' => '\d+', 'bar' => '\d+'), $route->getRequirements(), '->addRequirement() keep previous requirements');
114: }
115:
116: public function testRequirement()
117: {
118: $route = new Route('/{foo}');
119: $this->assertFalse($route->hasRequirement('foo'), '->hasRequirement() return false if requirement is not set');
120: $route->setRequirement('foo', '^\d+$');
121: $this->assertEquals('\d+', $route->getRequirement('foo'), '->setRequirement() removes ^ and $ from the path');
122: $this->assertTrue($route->hasRequirement('foo'), '->hasRequirement() return true if requirement is set');
123: }
124:
125: 126: 127: 128:
129: public function testSetInvalidRequirement($req)
130: {
131: $route = new Route('/{foo}');
132: $route->setRequirement('foo', $req);
133: }
134:
135: public function getInvalidRequirements()
136: {
137: return array(
138: array(''),
139: array(array()),
140: array('^$'),
141: array('^'),
142: array('$'),
143: );
144: }
145:
146: public function testHost()
147: {
148: $route = new Route('/');
149: $route->setHost('{locale}.example.net');
150: $this->assertEquals('{locale}.example.net', $route->getHost(), '->setHost() sets the host pattern');
151: }
152:
153: public function testScheme()
154: {
155: $route = new Route('/');
156: $this->assertEquals(array(), $route->getSchemes(), 'schemes is initialized with array()');
157: $this->assertFalse($route->hasScheme('http'));
158: $route->setSchemes('hTTp');
159: $this->assertEquals(array('http'), $route->getSchemes(), '->setSchemes() accepts a single scheme string and lowercases it');
160: $this->assertTrue($route->hasScheme('htTp'));
161: $this->assertFalse($route->hasScheme('httpS'));
162: $route->setSchemes(array('HttpS', 'hTTp'));
163: $this->assertEquals(array('https', 'http'), $route->getSchemes(), '->setSchemes() accepts an array of schemes and lowercases them');
164: $this->assertTrue($route->hasScheme('htTp'));
165: $this->assertTrue($route->hasScheme('httpS'));
166: }
167:
168: 169: 170:
171: public function testLegacySchemeRequirement()
172: {
173: $route = new Route('/');
174: $route->setRequirement('_scheme', 'http|https');
175: $this->assertEquals('http|https', $route->getRequirement('_scheme'));
176: $this->assertEquals(array('http', 'https'), $route->getSchemes());
177: $this->assertTrue($route->hasScheme('https'));
178: $this->assertTrue($route->hasScheme('http'));
179: $this->assertFalse($route->hasScheme('ftp'));
180: $route->setSchemes(array('hTTp'));
181: $this->assertEquals('http', $route->getRequirement('_scheme'));
182: $route->setSchemes(array());
183: $this->assertNull($route->getRequirement('_scheme'));
184: }
185:
186: public function testMethod()
187: {
188: $route = new Route('/');
189: $this->assertEquals(array(), $route->getMethods(), 'methods is initialized with array()');
190: $route->setMethods('gEt');
191: $this->assertEquals(array('GET'), $route->getMethods(), '->setMethods() accepts a single method string and uppercases it');
192: $route->setMethods(array('gEt', 'PosT'));
193: $this->assertEquals(array('GET', 'POST'), $route->getMethods(), '->setMethods() accepts an array of methods and uppercases them');
194: }
195:
196: 197: 198:
199: public function testLegacyMethodRequirement()
200: {
201: $route = new Route('/');
202: $route->setRequirement('_method', 'GET|POST');
203: $this->assertEquals('GET|POST', $route->getRequirement('_method'));
204: $this->assertEquals(array('GET', 'POST'), $route->getMethods());
205: $route->setMethods(array('gEt'));
206: $this->assertEquals('GET', $route->getRequirement('_method'));
207: $route->setMethods(array());
208: $this->assertNull($route->getRequirement('_method'));
209: }
210:
211: public function testCondition()
212: {
213: $route = new Route('/');
214: $this->assertSame('', $route->getCondition());
215: $route->setCondition('context.getMethod() == "GET"');
216: $this->assertSame('context.getMethod() == "GET"', $route->getCondition());
217: }
218:
219: public function testCompile()
220: {
221: $route = new Route('/{foo}');
222: $this->assertInstanceOf('Symfony\Component\Routing\CompiledRoute', $compiled = $route->compile(), '->compile() returns a compiled route');
223: $this->assertSame($compiled, $route->compile(), '->compile() only compiled the route once if unchanged');
224: $route->setRequirement('foo', '.*');
225: $this->assertNotSame($compiled, $route->compile(), '->compile() recompiles if the route was modified');
226: }
227:
228: 229: 230:
231: public function testLegacyPattern()
232: {
233: $route = new Route('/{foo}');
234: $this->assertEquals('/{foo}', $route->getPattern());
235:
236: $route->setPattern('/bar');
237: $this->assertEquals('/bar', $route->getPattern());
238: }
239:
240: public function testSerialize()
241: {
242: $route = new Route('/prefix/{foo}', array('foo' => 'default'), array('foo' => '\d+'));
243:
244: $serialized = serialize($route);
245: $unserialized = unserialize($serialized);
246:
247: $this->assertEquals($route, $unserialized);
248: $this->assertNotSame($route, $unserialized);
249: }
250:
251: 252: 253: 254:
255: public function testSerializeWhenCompiled()
256: {
257: $route = new Route('/prefix/{foo}', array('foo' => 'default'), array('foo' => '\d+'));
258: $route->setHost('{locale}.example.net');
259: $route->compile();
260:
261: $serialized = serialize($route);
262: $unserialized = unserialize($serialized);
263:
264: $this->assertEquals($route, $unserialized);
265: $this->assertNotSame($route, $unserialized);
266: }
267:
268: 269: 270: 271: 272:
273: public function testSerializedRepresentationKeepsWorking()
274: {
275: $serialized = 'C:31:"Symfony\Component\Routing\Route":934:{a:8:{s:4:"path";s:13:"/prefix/{foo}";s:4:"host";s:20:"{locale}.example.net";s:8:"defaults";a:1:{s:3:"foo";s:7:"default";}s:12:"requirements";a:1:{s:3:"foo";s:3:"\d+";}s:7:"options";a:1:{s:14:"compiler_class";s:39:"Symfony\Component\Routing\RouteCompiler";}s:7:"schemes";a:0:{}s:7:"methods";a:0:{}s:8:"compiled";C:39:"Symfony\Component\Routing\CompiledRoute":569:{a:8:{s:4:"vars";a:2:{i:0;s:6:"locale";i:1;s:3:"foo";}s:11:"path_prefix";s:7:"/prefix";s:10:"path_regex";s:30:"#^/prefix(?:/(?P<foo>\d+))?$#s";s:11:"path_tokens";a:2:{i:0;a:4:{i:0;s:8:"variable";i:1;s:1:"/";i:2;s:3:"\d+";i:3;s:3:"foo";}i:1;a:2:{i:0;s:4:"text";i:1;s:7:"/prefix";}}s:9:"path_vars";a:1:{i:0;s:3:"foo";}s:10:"host_regex";s:39:"#^(?P<locale>[^\.]++)\.example\.net$#si";s:11:"host_tokens";a:2:{i:0;a:2:{i:0;s:4:"text";i:1;s:12:".example.net";}i:1;a:4:{i:0;s:8:"variable";i:1;s:0:"";i:2;s:7:"[^\.]++";i:3;s:6:"locale";}}s:9:"host_vars";a:1:{i:0;s:6:"locale";}}}}}';
276: $unserialized = unserialize($serialized);
277:
278: $route = new Route('/prefix/{foo}', array('foo' => 'default'), array('foo' => '\d+'));
279: $route->setHost('{locale}.example.net');
280: $route->compile();
281:
282: $this->assertEquals($route, $unserialized);
283: $this->assertNotSame($route, $unserialized);
284: }
285: }
286: