1<?php 2/** 3 * CakeRequest Test case file. 4 * 5 * CakePHP(tm) : Rapid Development Framework (https://cakephp.org) 6 * Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) 7 * 8 * Licensed under The MIT License 9 * For full copyright and license information, please see the LICENSE.txt 10 * Redistributions of files must retain the above copyright notice. 11 * 12 * @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org) 13 * @link https://cakephp.org CakePHP(tm) Project 14 * @package Cake.Test.Case.Routing.Route 15 * @since CakePHP(tm) v 2.0 16 * @license https://opensource.org/licenses/mit-license.php MIT License 17 */ 18 19App::uses('CakeRoute', 'Routing/Route'); 20App::uses('Router', 'Routing'); 21 22/** 23 * Test case for CakeRoute 24 * 25 * @package Cake.Test.Case.Routing.Route 26 */ 27class CakeRouteTest extends CakeTestCase { 28 29/** 30 * setUp method 31 * 32 * @return void 33 */ 34 public function setUp() { 35 parent::setUp(); 36 Configure::write('Routing', array('admin' => null, 'prefixes' => array())); 37 } 38 39/** 40 * Test the construction of a CakeRoute 41 * 42 * @return void 43 */ 44 public function testConstruction() { 45 $route = new CakeRoute('/:controller/:action/:id', array(), array('id' => '[0-9]+')); 46 47 $this->assertEquals('/:controller/:action/:id', $route->template); 48 $this->assertEquals(array(), $route->defaults); 49 $this->assertEquals(array('id' => '[0-9]+'), $route->options); 50 $this->assertFalse($route->compiled()); 51 } 52 53/** 54 * test Route compiling. 55 * 56 * @return void 57 */ 58 public function testBasicRouteCompiling() { 59 $route = new CakeRoute('/', array('controller' => 'pages', 'action' => 'display', 'home')); 60 $result = $route->compile(); 61 $expected = '#^/*$#'; 62 $this->assertEquals($expected, $result); 63 $this->assertEquals(array(), $route->keys); 64 65 $route = new CakeRoute('/:controller/:action', array('controller' => 'posts')); 66 $result = $route->compile(); 67 68 $this->assertRegExp($result, '/posts/edit'); 69 $this->assertRegExp($result, '/posts/super_delete'); 70 $this->assertNotRegExp($result, '/posts'); 71 $this->assertNotRegExp($result, '/posts/super_delete/1'); 72 73 $route = new CakeRoute('/posts/foo:id', array('controller' => 'posts', 'action' => 'view')); 74 $result = $route->compile(); 75 76 $this->assertRegExp($result, '/posts/foo:1'); 77 $this->assertRegExp($result, '/posts/foo:param'); 78 $this->assertNotRegExp($result, '/posts'); 79 $this->assertNotRegExp($result, '/posts/'); 80 81 $this->assertEquals(array('id'), $route->keys); 82 83 $route = new CakeRoute('/:plugin/:controller/:action/*', array('plugin' => 'test_plugin', 'action' => 'index')); 84 $result = $route->compile(); 85 $this->assertRegExp($result, '/test_plugin/posts/index'); 86 $this->assertRegExp($result, '/test_plugin/posts/edit/5'); 87 $this->assertRegExp($result, '/test_plugin/posts/edit/5/name:value/nick:name'); 88 } 89 90/** 91 * test that route parameters that overlap don't cause errors. 92 * 93 * @return void 94 */ 95 public function testRouteParameterOverlap() { 96 $route = new CakeRoute('/invoices/add/:idd/:id', array('controller' => 'invoices', 'action' => 'add')); 97 $result = $route->compile(); 98 $this->assertRegExp($result, '/invoices/add/1/3'); 99 100 $route = new CakeRoute('/invoices/add/:id/:idd', array('controller' => 'invoices', 'action' => 'add')); 101 $result = $route->compile(); 102 $this->assertRegExp($result, '/invoices/add/1/3'); 103 } 104 105/** 106 * test compiling routes with keys that have patterns 107 * 108 * @return void 109 */ 110 public function testRouteCompilingWithParamPatterns() { 111 $route = new CakeRoute( 112 '/:controller/:action/:id', 113 array(), 114 array('id' => Router::ID) 115 ); 116 $result = $route->compile(); 117 $this->assertRegExp($result, '/posts/edit/1'); 118 $this->assertRegExp($result, '/posts/view/518098'); 119 $this->assertNotRegExp($result, '/posts/edit/name-of-post'); 120 $this->assertNotRegExp($result, '/posts/edit/4/other:param'); 121 $this->assertEquals(array('id', 'controller', 'action'), $route->keys); 122 123 $route = new CakeRoute( 124 '/:lang/:controller/:action/:id', 125 array('controller' => 'testing4'), 126 array('id' => Router::ID, 'lang' => '[a-z]{3}') 127 ); 128 $result = $route->compile(); 129 $this->assertRegExp($result, '/eng/posts/edit/1'); 130 $this->assertRegExp($result, '/cze/articles/view/1'); 131 $this->assertNotRegExp($result, '/language/articles/view/2'); 132 $this->assertNotRegExp($result, '/eng/articles/view/name-of-article'); 133 $this->assertEquals(array('lang', 'id', 'controller', 'action'), $route->keys); 134 135 foreach (array(':', '@', ';', '$', '-') as $delim) { 136 $route = new CakeRoute('/posts/:id' . $delim . ':title'); 137 $result = $route->compile(); 138 139 $this->assertRegExp($result, '/posts/1' . $delim . 'name-of-article'); 140 $this->assertRegExp($result, '/posts/13244' . $delim . 'name-of_Article[]'); 141 $this->assertNotRegExp($result, '/posts/11!nameofarticle'); 142 $this->assertNotRegExp($result, '/posts/11'); 143 144 $this->assertEquals(array('title', 'id'), $route->keys); 145 } 146 147 $route = new CakeRoute( 148 '/posts/:id::title/:year', 149 array('controller' => 'posts', 'action' => 'view'), 150 array('id' => Router::ID, 'year' => Router::YEAR, 'title' => '[a-z-_]+') 151 ); 152 $result = $route->compile(); 153 $this->assertRegExp($result, '/posts/1:name-of-article/2009/'); 154 $this->assertRegExp($result, '/posts/13244:name-of-article/1999'); 155 $this->assertNotRegExp($result, '/posts/hey_now:nameofarticle'); 156 $this->assertNotRegExp($result, '/posts/:nameofarticle/2009'); 157 $this->assertNotRegExp($result, '/posts/:nameofarticle/01'); 158 $this->assertEquals(array('year', 'title', 'id'), $route->keys); 159 160 $route = new CakeRoute( 161 '/posts/:url_title-(uuid::id)', 162 array('controller' => 'posts', 'action' => 'view'), 163 array('pass' => array('id', 'url_title'), 'id' => Router::ID) 164 ); 165 $result = $route->compile(); 166 $this->assertRegExp($result, '/posts/some_title_for_article-(uuid:12534)/'); 167 $this->assertRegExp($result, '/posts/some_title_for_article-(uuid:12534)'); 168 $this->assertNotRegExp($result, '/posts/'); 169 $this->assertNotRegExp($result, '/posts/nameofarticle'); 170 $this->assertNotRegExp($result, '/posts/nameofarticle-12347'); 171 $this->assertEquals(array('url_title', 'id'), $route->keys); 172 } 173 174/** 175 * test more complex route compiling & parsing with mid route greedy stars 176 * and optional routing parameters 177 * 178 * @return void 179 */ 180 public function testComplexRouteCompilingAndParsing() { 181 $route = new CakeRoute( 182 '/posts/:month/:day/:year/*', 183 array('controller' => 'posts', 'action' => 'view'), 184 array('year' => Router::YEAR, 'month' => Router::MONTH, 'day' => Router::DAY) 185 ); 186 $result = $route->compile(); 187 $this->assertRegExp($result, '/posts/08/01/2007/title-of-post'); 188 $result = $route->parse('/posts/08/01/2007/title-of-post'); 189 190 $this->assertEquals(7, count($result)); 191 $this->assertEquals('posts', $result['controller']); 192 $this->assertEquals('view', $result['action']); 193 $this->assertEquals('2007', $result['year']); 194 $this->assertEquals('08', $result['month']); 195 $this->assertEquals('01', $result['day']); 196 $this->assertEquals('title-of-post', $result['pass'][0]); 197 198 $route = new CakeRoute( 199 "/:extra/page/:slug/*", 200 array('controller' => 'pages', 'action' => 'view', 'extra' => null), 201 array("extra" => '[a-z1-9_]*', "slug" => '[a-z1-9_]+', "action" => 'view') 202 ); 203 $result = $route->compile(); 204 205 $this->assertRegExp($result, '/some_extra/page/this_is_the_slug'); 206 $this->assertRegExp($result, '/page/this_is_the_slug'); 207 $this->assertEquals(array('slug', 'extra'), $route->keys); 208 $this->assertEquals(array('extra' => '[a-z1-9_]*', 'slug' => '[a-z1-9_]+', 'action' => 'view'), $route->options); 209 $expected = array( 210 'controller' => 'pages', 211 'action' => 'view' 212 ); 213 $this->assertEquals($expected, $route->defaults); 214 215 $route = new CakeRoute( 216 '/:controller/:action/*', 217 array('project' => false), 218 array( 219 'controller' => 'source|wiki|commits|tickets|comments|view', 220 'action' => 'branches|history|branch|logs|view|start|add|edit|modify' 221 ) 222 ); 223 $this->assertFalse($route->parse('/chaw_test/wiki')); 224 225 $result = $route->compile(); 226 $this->assertNotRegExp($result, '/some_project/source'); 227 $this->assertRegExp($result, '/source/view'); 228 $this->assertRegExp($result, '/source/view/other/params'); 229 $this->assertNotRegExp($result, '/chaw_test/wiki'); 230 $this->assertNotRegExp($result, '/source/wierd_action'); 231 } 232 233/** 234 * test that routes match their pattern. 235 * 236 * @return void 237 */ 238 public function testMatchBasic() { 239 $route = new CakeRoute('/:controller/:action/:id', array('plugin' => null)); 240 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'plugin' => null)); 241 $this->assertFalse($result); 242 243 $result = $route->match(array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 0)); 244 $this->assertFalse($result); 245 246 $result = $route->match(array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => 1)); 247 $this->assertEquals('/posts/view/1', $result); 248 249 $route = new CakeRoute('/', array('controller' => 'pages', 'action' => 'display', 'home')); 250 $result = $route->match(array('controller' => 'pages', 'action' => 'display', 'home')); 251 $this->assertEquals('/', $result); 252 253 $result = $route->match(array('controller' => 'pages', 'action' => 'display', 'about')); 254 $this->assertFalse($result); 255 256 $route = new CakeRoute('/pages/*', array('controller' => 'pages', 'action' => 'display')); 257 $result = $route->match(array('controller' => 'pages', 'action' => 'display', 'home')); 258 $this->assertEquals('/pages/home', $result); 259 260 $result = $route->match(array('controller' => 'pages', 'action' => 'display', 'about')); 261 $this->assertEquals('/pages/about', $result); 262 263 $route = new CakeRoute('/blog/:action', array('controller' => 'posts')); 264 $result = $route->match(array('controller' => 'posts', 'action' => 'view')); 265 $this->assertEquals('/blog/view', $result); 266 267 $result = $route->match(array('controller' => 'nodes', 'action' => 'view')); 268 $this->assertFalse($result); 269 270 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 1)); 271 $this->assertFalse($result); 272 273 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'id' => 2)); 274 $this->assertFalse($result); 275 276 $route = new CakeRoute('/foo/:controller/:action', array('action' => 'index')); 277 $result = $route->match(array('controller' => 'posts', 'action' => 'view')); 278 $this->assertEquals('/foo/posts/view', $result); 279 280 $route = new CakeRoute('/:plugin/:id/*', array('controller' => 'posts', 'action' => 'view')); 281 $result = $route->match(array('plugin' => 'test', 'controller' => 'posts', 'action' => 'view', 'id' => '1')); 282 $this->assertEquals('/test/1/', $result); 283 284 $result = $route->match(array('plugin' => 'fo', 'controller' => 'posts', 'action' => 'view', 'id' => '1', '0')); 285 $this->assertEquals('/fo/1/0', $result); 286 287 $result = $route->match(array('plugin' => 'fo', 'controller' => 'nodes', 'action' => 'view', 'id' => 1)); 288 $this->assertFalse($result); 289 290 $result = $route->match(array('plugin' => 'fo', 'controller' => 'posts', 'action' => 'edit', 'id' => 1)); 291 $this->assertFalse($result); 292 293 $route = new CakeRoute('/admin/subscriptions/:action/*', array( 294 'controller' => 'subscribe', 'admin' => true, 'prefix' => 'admin' 295 )); 296 297 $url = array('controller' => 'subscribe', 'admin' => true, 'action' => 'edit', 1); 298 $result = $route->match($url); 299 $expected = '/admin/subscriptions/edit/1'; 300 $this->assertEquals($expected, $result); 301 302 $url = array( 303 'controller' => 'subscribe', 304 'admin' => true, 305 'action' => 'edit_admin_e', 306 1 307 ); 308 $result = $route->match($url); 309 $expected = '/admin/subscriptions/edit_admin_e/1'; 310 $this->assertEquals($expected, $result); 311 312 $url = array('controller' => 'subscribe', 'admin' => true, 'action' => 'admin_edit', 1); 313 $result = $route->match($url); 314 $expected = '/admin/subscriptions/edit/1'; 315 $this->assertEquals($expected, $result); 316 } 317 318/** 319 * test that non-greedy routes fail with extra passed args 320 * 321 * @return void 322 */ 323 public function testGreedyRouteFailurePassedArg() { 324 $route = new CakeRoute('/:controller/:action', array('plugin' => null)); 325 $result = $route->match(array('controller' => 'posts', 'action' => 'view', '0')); 326 $this->assertFalse($result); 327 328 $route = new CakeRoute('/:controller/:action', array('plugin' => null)); 329 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'test')); 330 $this->assertFalse($result); 331 } 332 333/** 334 * test that non-greedy routes fail with extra passed args 335 * 336 * @return void 337 */ 338 public function testGreedyRouteFailureNamedParam() { 339 $route = new CakeRoute('/:controller/:action', array('plugin' => null)); 340 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'page' => 1)); 341 $this->assertFalse($result); 342 } 343 344/** 345 * test that falsey values do not interrupt a match. 346 * 347 * @return void 348 */ 349 public function testMatchWithFalseyValues() { 350 $route = new CakeRoute('/:controller/:action/*', array('plugin' => null)); 351 $result = $route->match(array( 352 'controller' => 'posts', 'action' => 'index', 'plugin' => null, 'admin' => false 353 )); 354 $this->assertEquals('/posts/index/', $result); 355 } 356 357/** 358 * test match() with greedy routes, named parameters and passed args. 359 * 360 * @return void 361 */ 362 public function testMatchWithNamedParametersAndPassedArgs() { 363 Router::connectNamed(true); 364 365 $route = new CakeRoute('/:controller/:action/*', array('plugin' => null)); 366 $result = $route->match(array('controller' => 'posts', 'action' => 'index', 'plugin' => null, 'page' => 1)); 367 $this->assertEquals('/posts/index/page:1', $result); 368 369 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'plugin' => null, 5)); 370 $this->assertEquals('/posts/view/5', $result); 371 372 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'plugin' => null, 0)); 373 $this->assertEquals('/posts/view/0', $result); 374 375 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'plugin' => null, '0')); 376 $this->assertEquals('/posts/view/0', $result); 377 378 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'plugin' => null, 5, 'page' => 1, 'limit' => 20, 'order' => 'title')); 379 $this->assertEquals('/posts/view/5/page:1/limit:20/order:title', $result); 380 381 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'plugin' => null, 'word space', 'order' => 'Θ')); 382 $this->assertEquals('/posts/view/word%20space/order:%CE%98', $result); 383 384 $route = new CakeRoute('/test2/*', array('controller' => 'pages', 'action' => 'display', 2)); 385 $result = $route->match(array('controller' => 'pages', 'action' => 'display', 1)); 386 $this->assertFalse($result); 387 388 $result = $route->match(array('controller' => 'pages', 'action' => 'display', 2, 'something')); 389 $this->assertEquals('/test2/something', $result); 390 391 $result = $route->match(array('controller' => 'pages', 'action' => 'display', 5, 'something')); 392 $this->assertFalse($result); 393 } 394 395/** 396 * Ensure that named parameters are urldecoded 397 * 398 * @return void 399 */ 400 public function testParseNamedParametersUrlDecode() { 401 Router::connectNamed(true); 402 $route = new CakeRoute('/:controller/:action/*', array('plugin' => null)); 403 404 $result = $route->parse('/posts/index/page:%CE%98'); 405 $this->assertEquals('Θ', $result['named']['page']); 406 407 $result = $route->parse('/posts/index/page[]:%CE%98'); 408 $this->assertEquals('Θ', $result['named']['page'][0]); 409 410 $result = $route->parse('/posts/index/something%20else/page[]:%CE%98'); 411 $this->assertEquals('Θ', $result['named']['page'][0]); 412 $this->assertEquals('something else', $result['pass'][0]); 413 } 414 415/** 416 * Ensure that keys at named parameters are urldecoded 417 * 418 * @return void 419 */ 420 public function testParseNamedKeyUrlDecode() { 421 Router::connectNamed(true); 422 $route = new CakeRoute('/:controller/:action/*', array('plugin' => null)); 423 424 // checking /post/index/user[0]:a/user[1]:b 425 $result = $route->parse('/posts/index/user%5B0%5D:a/user%5B1%5D:b'); 426 $this->assertArrayHasKey('user', $result['named']); 427 $this->assertEquals(array('a', 'b'), $result['named']['user']); 428 429 // checking /post/index/user[]:a/user[]:b 430 $result = $route->parse('/posts/index/user%5B%5D:a/user%5B%5D:b'); 431 $this->assertArrayHasKey('user', $result['named']); 432 $this->assertEquals(array('a', 'b'), $result['named']['user']); 433 } 434 435/** 436 * test that named params with null/false are excluded 437 * 438 * @return void 439 */ 440 public function testNamedParamsWithNullFalse() { 441 $route = new CakeRoute('/:controller/:action/*'); 442 $result = $route->match(array('controller' => 'posts', 'action' => 'index', 'page' => null, 'sort' => false)); 443 $this->assertEquals('/posts/index/', $result); 444 } 445 446/** 447 * test that match with patterns works. 448 * 449 * @return void 450 */ 451 public function testMatchWithPatterns() { 452 $route = new CakeRoute('/:controller/:action/:id', array('plugin' => null), array('id' => '[0-9]+')); 453 $result = $route->match(array('controller' => 'posts', 'action' => 'view', 'id' => 'foo')); 454 $this->assertFalse($result); 455 456 $result = $route->match(array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => '9')); 457 $this->assertEquals('/posts/view/9', $result); 458 459 $result = $route->match(array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => '922')); 460 $this->assertEquals('/posts/view/922', $result); 461 462 $result = $route->match(array('plugin' => null, 'controller' => 'posts', 'action' => 'view', 'id' => 'a99')); 463 $this->assertFalse($result); 464 } 465 466/** 467 * test persistParams ability to persist parameters from $params and remove params. 468 * 469 * @return void 470 */ 471 public function testPersistParams() { 472 $route = new CakeRoute( 473 '/:lang/:color/blog/:action', 474 array('controller' => 'posts'), 475 array('persist' => array('lang', 'color')) 476 ); 477 $url = array('controller' => 'posts', 'action' => 'index'); 478 $params = array('lang' => 'en', 'color' => 'blue'); 479 $result = $route->persistParams($url, $params); 480 $this->assertEquals('en', $result['lang']); 481 $this->assertEquals('blue', $result['color']); 482 483 $url = array('controller' => 'posts', 'action' => 'index', 'color' => 'red'); 484 $params = array('lang' => 'en', 'color' => 'blue'); 485 $result = $route->persistParams($url, $params); 486 $this->assertEquals('en', $result['lang']); 487 $this->assertEquals('red', $result['color']); 488 } 489 490/** 491 * test persist with a non array value 492 * 493 * @return void 494 */ 495 public function testPersistParamsNonArray() { 496 $url = array('controller' => 'posts', 'action' => 'index'); 497 $params = array('lang' => 'en', 'color' => 'blue'); 498 499 $route = new CakeRoute( 500 '/:lang/:color/blog/:action', 501 array('controller' => 'posts') 502 // No persist options 503 ); 504 $result = $route->persistParams($url, $params); 505 $this->assertEquals($url, $result); 506 507 $route = new CakeRoute( 508 '/:lang/:color/blog/:action', 509 array('controller' => 'posts'), 510 array('persist' => false) 511 ); 512 $result = $route->persistParams($url, $params); 513 $this->assertEquals($url, $result); 514 515 $route = new CakeRoute( 516 '/:lang/:color/blog/:action', 517 array('controller' => 'posts'), 518 array('persist' => 'derp') 519 ); 520 $result = $route->persistParams($url, $params); 521 $this->assertEquals($url, $result); 522 } 523 524/** 525 * test the parse method of CakeRoute. 526 * 527 * @return void 528 */ 529 public function testParse() { 530 $route = new CakeRoute( 531 '/:controller/:action/:id', 532 array('controller' => 'testing4', 'id' => null), 533 array('id' => Router::ID) 534 ); 535 $route->compile(); 536 $result = $route->parse('/posts/view/1'); 537 $this->assertEquals('posts', $result['controller']); 538 $this->assertEquals('view', $result['action']); 539 $this->assertEquals('1', $result['id']); 540 541 $route = new Cakeroute( 542 '/admin/:controller', 543 array('prefix' => 'admin', 'admin' => 1, 'action' => 'index') 544 ); 545 $route->compile(); 546 $result = $route->parse('/admin/'); 547 $this->assertFalse($result); 548 549 $result = $route->parse('/admin/posts'); 550 $this->assertEquals('posts', $result['controller']); 551 $this->assertEquals('index', $result['action']); 552 } 553 554/** 555 * Test that :key elements are urldecoded 556 * 557 * @return void 558 */ 559 public function testParseUrlDecodeElements() { 560 $route = new Cakeroute( 561 '/:controller/:slug', 562 array('action' => 'view') 563 ); 564 $route->compile(); 565 $result = $route->parse('/posts/%E2%88%82%E2%88%82'); 566 $this->assertEquals('posts', $result['controller']); 567 $this->assertEquals('view', $result['action']); 568 $this->assertEquals('∂∂', $result['slug']); 569 570 $result = $route->parse('/posts/∂∂'); 571 $this->assertEquals('posts', $result['controller']); 572 $this->assertEquals('view', $result['action']); 573 $this->assertEquals('∂∂', $result['slug']); 574 } 575 576/** 577 * test numerically indexed defaults, get appended to pass 578 * 579 * @return void 580 */ 581 public function testParseWithPassDefaults() { 582 $route = new Cakeroute('/:controller', array('action' => 'display', 'home')); 583 $result = $route->parse('/posts'); 584 $expected = array( 585 'controller' => 'posts', 586 'action' => 'display', 587 'pass' => array('home'), 588 'named' => array() 589 ); 590 $this->assertEquals($expected, $result); 591 } 592 593/** 594 * test that http header conditions can cause route failures. 595 * 596 * @return void 597 */ 598 public function testParseWithHttpHeaderConditions() { 599 $_SERVER['REQUEST_METHOD'] = 'GET'; 600 $route = new CakeRoute('/sample', array('controller' => 'posts', 'action' => 'index', '[method]' => 'POST')); 601 602 $this->assertFalse($route->parse('/sample')); 603 } 604 605/** 606 * test that patterns work for :action 607 * 608 * @return void 609 */ 610 public function testPatternOnAction() { 611 $route = new CakeRoute( 612 '/blog/:action/*', 613 array('controller' => 'blog_posts'), 614 array('action' => 'other|actions') 615 ); 616 $result = $route->match(array('controller' => 'blog_posts', 'action' => 'foo')); 617 $this->assertFalse($result); 618 619 $result = $route->match(array('controller' => 'blog_posts', 'action' => 'actions')); 620 $this->assertNotEmpty($result); 621 622 $result = $route->parse('/blog/other'); 623 $expected = array('controller' => 'blog_posts', 'action' => 'other', 'pass' => array(), 'named' => array()); 624 $this->assertEquals($expected, $result); 625 626 $result = $route->parse('/blog/foobar'); 627 $this->assertFalse($result); 628 } 629 630/** 631 * test the parseArgs method 632 * 633 * @return void 634 */ 635 public function testParsePassedArgument() { 636 $route = new CakeRoute('/:controller/:action/*'); 637 $result = $route->parse('/posts/edit/1/2/0'); 638 $expected = array( 639 'controller' => 'posts', 640 'action' => 'edit', 641 'pass' => array('1', '2', '0'), 642 'named' => array() 643 ); 644 $this->assertEquals($expected, $result); 645 646 $result = $route->parse('/posts/edit/a-string/page:1/sort:value'); 647 $expected = array( 648 'controller' => 'posts', 649 'action' => 'edit', 650 'pass' => array('a-string'), 651 'named' => array( 652 'page' => 1, 653 'sort' => 'value' 654 ) 655 ); 656 $this->assertEquals($expected, $result); 657 } 658 659/** 660 * test that only named parameter rules are followed. 661 * 662 * @return void 663 */ 664 public function testParseNamedParametersWithRules() { 665 $route = new CakeRoute('/:controller/:action/*', array(), array( 666 'named' => array( 667 'wibble', 668 'fish' => array('action' => 'index'), 669 'fizz' => array('controller' => array('comments', 'other')), 670 'pattern' => 'val-[\d]+' 671 ) 672 )); 673 $result = $route->parse('/posts/display/wibble:spin/fish:trout/fizz:buzz/unknown:value'); 674 $expected = array( 675 'controller' => 'posts', 676 'action' => 'display', 677 'pass' => array('fish:trout', 'fizz:buzz', 'unknown:value'), 678 'named' => array( 679 'wibble' => 'spin' 680 ) 681 ); 682 $this->assertEquals($expected, $result, 'Fish should not be parsed, as action != index'); 683 684 $result = $route->parse('/posts/index/wibble:spin/fish:trout/fizz:buzz'); 685 $expected = array( 686 'controller' => 'posts', 687 'action' => 'index', 688 'pass' => array('fizz:buzz'), 689 'named' => array( 690 'wibble' => 'spin', 691 'fish' => 'trout' 692 ) 693 ); 694 $this->assertEquals($expected, $result, 'Fizz should be parsed, as controller == comments|other'); 695 696 $result = $route->parse('/comments/index/wibble:spin/fish:trout/fizz:buzz'); 697 $expected = array( 698 'controller' => 'comments', 699 'action' => 'index', 700 'pass' => array(), 701 'named' => array( 702 'wibble' => 'spin', 703 'fish' => 'trout', 704 'fizz' => 'buzz' 705 ) 706 ); 707 $this->assertEquals($expected, $result, 'All params should be parsed as conditions were met.'); 708 709 $result = $route->parse('/comments/index/pattern:val--'); 710 $expected = array( 711 'controller' => 'comments', 712 'action' => 'index', 713 'pass' => array('pattern:val--'), 714 'named' => array() 715 ); 716 $this->assertEquals($expected, $result, 'Named parameter pattern unmet.'); 717 718 $result = $route->parse('/comments/index/pattern:val-2'); 719 $expected = array( 720 'controller' => 'comments', 721 'action' => 'index', 722 'pass' => array(), 723 'named' => array('pattern' => 'val-2') 724 ); 725 $this->assertEquals($expected, $result, 'Named parameter pattern met.'); 726 } 727 728/** 729 * test that greedyNamed ignores rules. 730 * 731 * @return void 732 */ 733 public function testParseGreedyNamed() { 734 $route = new CakeRoute('/:controller/:action/*', array(), array( 735 'named' => array( 736 'fizz' => array('controller' => 'comments'), 737 'pattern' => 'val-[\d]+', 738 ), 739 'greedyNamed' => true 740 )); 741 $result = $route->parse('/posts/display/wibble:spin/fizz:buzz/pattern:ignored'); 742 $expected = array( 743 'controller' => 'posts', 744 'action' => 'display', 745 'pass' => array('fizz:buzz', 'pattern:ignored'), 746 'named' => array( 747 'wibble' => 'spin', 748 ) 749 ); 750 $this->assertEquals($expected, $result, 'Greedy named grabs everything, rules are followed'); 751 } 752 753/** 754 * Having greedNamed enabled should not capture routing.prefixes. 755 * 756 * @return void 757 */ 758 public function testMatchGreedyNamedExcludesPrefixes() { 759 Configure::write('Routing.prefixes', array('admin')); 760 Router::reload(); 761 762 $route = new CakeRoute('/sales/*', array('controller' => 'sales', 'action' => 'index')); 763 $this->assertFalse($route->match(array('controller' => 'sales', 'action' => 'index', 'admin' => 1)), 'Greedy named consume routing prefixes.'); 764 } 765 766/** 767 * test that parsing array format named parameters works 768 * 769 * @return void 770 */ 771 public function testParseArrayNamedParameters() { 772 $route = new CakeRoute('/:controller/:action/*'); 773 $result = $route->parse('/tests/action/var[]:val1/var[]:val2'); 774 $expected = array( 775 'controller' => 'tests', 776 'action' => 'action', 777 'named' => array( 778 'var' => array( 779 'val1', 780 'val2' 781 ) 782 ), 783 'pass' => array(), 784 ); 785 $this->assertEquals($expected, $result); 786 787 $result = $route->parse('/tests/action/theanswer[is]:42/var[]:val2/var[]:val3'); 788 $expected = array( 789 'controller' => 'tests', 790 'action' => 'action', 791 'named' => array( 792 'theanswer' => array( 793 'is' => 42 794 ), 795 'var' => array( 796 'val2', 797 'val3' 798 ) 799 ), 800 'pass' => array(), 801 ); 802 $this->assertEquals($expected, $result); 803 804 $result = $route->parse('/tests/action/theanswer[is][not]:42/theanswer[]:5/theanswer[is]:6'); 805 $expected = array( 806 'controller' => 'tests', 807 'action' => 'action', 808 'named' => array( 809 'theanswer' => array( 810 5, 811 'is' => array( 812 6, 813 'not' => 42 814 ) 815 ), 816 ), 817 'pass' => array(), 818 ); 819 $this->assertEquals($expected, $result); 820 } 821 822/** 823 * Test that match can handle array named parameters 824 * 825 * @return void 826 */ 827 public function testMatchNamedParametersArray() { 828 $route = new CakeRoute('/:controller/:action/*'); 829 830 $url = array( 831 'controller' => 'posts', 832 'action' => 'index', 833 'filter' => array( 834 'one', 835 'model' => 'value' 836 ) 837 ); 838 $result = $route->match($url); 839 $expected = '/posts/index/filter%5B0%5D:one/filter%5Bmodel%5D:value'; 840 $this->assertEquals($expected, $result); 841 842 $url = array( 843 'controller' => 'posts', 844 'action' => 'index', 845 'filter' => array( 846 'one', 847 'model' => array( 848 'two', 849 'order' => 'field' 850 ) 851 ) 852 ); 853 $result = $route->match($url); 854 $expected = '/posts/index/filter%5B0%5D:one/filter%5Bmodel%5D%5B0%5D:two/filter%5Bmodel%5D%5Border%5D:field'; 855 $this->assertEquals($expected, $result); 856 } 857 858/** 859 * Test matching of parameters where one parameter name starts with another parameter name 860 * 861 * @return void 862 */ 863 public function testMatchSimilarParameters() { 864 $route = new CakeRoute('/:thisParam/:thisParamIsLonger'); 865 866 $url = array( 867 'thisParamIsLonger' => 'bar', 868 'thisParam' => 'foo', 869 ); 870 871 $result = $route->match($url); 872 $expected = '/foo/bar'; 873 $this->assertEquals($expected, $result); 874 } 875 876/** 877 * Test match() with trailing ** style routes. 878 * 879 * @return void 880 */ 881 public function testMatchTrailing() { 882 $route = new CakeRoute('/pages/**', array('controller' => 'pages', 'action' => 'display')); 883 $id = 'test/ spaces/漢字/la†în'; 884 $result = $route->match(array( 885 'controller' => 'pages', 886 'action' => 'display', 887 $id 888 )); 889 $expected = '/pages/test/%20spaces/%E6%BC%A2%E5%AD%97/la%E2%80%A0%C3%AEn'; 890 $this->assertEquals($expected, $result); 891 } 892 893/** 894 * test restructuring args with pass key 895 * 896 * @return void 897 */ 898 public function testPassArgRestructure() { 899 $route = new CakeRoute('/:controller/:action/:slug', array(), array( 900 'pass' => array('slug') 901 )); 902 $result = $route->parse('/posts/view/my-title'); 903 $expected = array( 904 'controller' => 'posts', 905 'action' => 'view', 906 'slug' => 'my-title', 907 'pass' => array('my-title'), 908 'named' => array() 909 ); 910 $this->assertEquals($expected, $result, 'Slug should have moved'); 911 } 912 913/** 914 * Test the /** special type on parsing. 915 * 916 * @return void 917 */ 918 public function testParseTrailing() { 919 $route = new CakeRoute('/:controller/:action/**'); 920 $result = $route->parse('/posts/index/1/2/3/foo:bar'); 921 $expected = array( 922 'controller' => 'posts', 923 'action' => 'index', 924 'pass' => array('1/2/3/foo:bar'), 925 'named' => array() 926 ); 927 $this->assertEquals($expected, $result); 928 929 $result = $route->parse('/posts/index/http://example.com'); 930 $expected = array( 931 'controller' => 'posts', 932 'action' => 'index', 933 'pass' => array('http://example.com'), 934 'named' => array() 935 ); 936 $this->assertEquals($expected, $result); 937 } 938 939/** 940 * Test the /** special type on parsing - UTF8. 941 * 942 * @return void 943 */ 944 public function testParseTrailingUTF8() { 945 $route = new CakeRoute('/category/**', array('controller' => 'categories', 'action' => 'index')); 946 $result = $route->parse('/category/%D9%85%D9%88%D8%A8%D8%A7%DB%8C%D9%84'); 947 $expected = array( 948 'controller' => 'categories', 949 'action' => 'index', 950 'pass' => array('موبایل'), 951 'named' => array() 952 ); 953 $this->assertEquals($expected, $result); 954 } 955 956/** 957 * test that utf-8 patterns work for :section 958 * 959 * @return void 960 */ 961 public function testUTF8PatternOnSection() { 962 $route = new CakeRoute( 963 '/:section', 964 array('plugin' => 'blogs', 'controller' => 'posts', 'action' => 'index'), 965 array( 966 'persist' => array('section'), 967 'section' => 'آموزش|weblog' 968 ) 969 ); 970 971 $result = $route->parse('/%D8%A2%D9%85%D9%88%D8%B2%D8%B4'); 972 $expected = array('section' => 'آموزش', 'plugin' => 'blogs', 'controller' => 'posts', 'action' => 'index', 'pass' => array(), 'named' => array()); 973 $this->assertEquals($expected, $result); 974 975 $result = $route->parse('/weblog'); 976 $expected = array('section' => 'weblog', 'plugin' => 'blogs', 'controller' => 'posts', 'action' => 'index', 'pass' => array(), 'named' => array()); 977 $this->assertEquals($expected, $result); 978 } 979 980/** 981 * Test for __set_state magic method on CakeRoute 982 * 983 * @return void 984 */ 985 public function testSetState() { 986 $route = CakeRoute::__set_state(array( 987 'keys' => array(), 988 'options' => array(), 989 'defaults' => array( 990 'controller' => 'pages', 991 'action' => 'display', 992 'home', 993 ), 994 'template' => '/', 995 '_greedy' => false, 996 '_compiledRoute' => null, 997 '_headerMap' => array ( 998 'type' => 'content_type', 999 'method' => 'request_method', 1000 'server' => 'server_name', 1001 ), 1002 )); 1003 $this->assertInstanceOf('CakeRoute', $route); 1004 $this->assertSame('/', $route->match(array('controller' => 'pages', 'action' => 'display', 'home'))); 1005 $this->assertFalse($route->match(array('controller' => 'pages', 'action' => 'display', 'about'))); 1006 $expected = array('controller' => 'pages', 'action' => 'display', 'pass' => array('home'), 'named' => array()); 1007 $this->assertEquals($expected, $route->parse('/')); 1008 } 1009 1010} 1011