DispatcherTest.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. <?php
  2. /**
  3. * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
  4. * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  5. *
  6. * Licensed under The MIT License
  7. * Redistributions of files must retain the above copyright notice
  8. *
  9. * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
  10. * @link http://cakephp.org CakePHP(tm) Project
  11. * @since 1.2.0
  12. * @license http://www.opensource.org/licenses/mit-license.php MIT License
  13. */
  14. namespace Cake\Test\TestCase\Routing;
  15. use Cake\Controller\Controller;
  16. use Cake\Core\App;
  17. use Cake\Core\Configure;
  18. use Cake\Core\Plugin;
  19. use Cake\Event\Event;
  20. use Cake\Network\Request;
  21. use Cake\Network\Response;
  22. use Cake\Network\Session;
  23. use Cake\Routing\Dispatcher;
  24. use Cake\Routing\Filter\ControllerFactoryFilter;
  25. use Cake\TestSuite\TestCase;
  26. use Cake\Utility\Inflector;
  27. /**
  28. * A testing stub that doesn't send headers.
  29. */
  30. class DispatcherMockResponse extends Response
  31. {
  32. protected function _sendHeader($name, $value = null)
  33. {
  34. return $name . ' ' . $value;
  35. }
  36. }
  37. /**
  38. * TestDispatcher class
  39. */
  40. class TestDispatcher extends Dispatcher
  41. {
  42. /**
  43. * Controller instance, made publicly available for testing
  44. *
  45. * @var Controller
  46. */
  47. public $controller;
  48. /**
  49. * invoke method
  50. *
  51. * @param \Cake\Controller\Controller $controller
  52. * @return \Cake\Network\Response $response
  53. */
  54. protected function _invoke(Controller $controller)
  55. {
  56. $this->controller = $controller;
  57. return parent::_invoke($controller);
  58. }
  59. }
  60. /**
  61. * MyPluginAppController class
  62. *
  63. */
  64. class MyPluginAppController extends Controller
  65. {
  66. }
  67. interface DispatcherTestInterfaceController
  68. {
  69. public function index();
  70. }
  71. /**
  72. * MyPluginController class
  73. *
  74. */
  75. class MyPluginController extends MyPluginAppController
  76. {
  77. /**
  78. * name property
  79. *
  80. * @var string
  81. */
  82. public $name = 'MyPlugin';
  83. /**
  84. * index method
  85. *
  86. * @return void
  87. */
  88. public function index()
  89. {
  90. return true;
  91. }
  92. /**
  93. * add method
  94. *
  95. * @return void
  96. */
  97. public function add()
  98. {
  99. return true;
  100. }
  101. /**
  102. * admin_add method
  103. *
  104. * @param mixed $id
  105. * @return void
  106. */
  107. public function admin_add($id = null)
  108. {
  109. return $id;
  110. }
  111. }
  112. /**
  113. * OtherPagesController class
  114. *
  115. */
  116. class OtherPagesController extends MyPluginAppController
  117. {
  118. /**
  119. * name property
  120. *
  121. * @var string
  122. */
  123. public $name = 'OtherPages';
  124. /**
  125. * display method
  126. *
  127. * @param string $page
  128. * @return void
  129. */
  130. public function display($page = null)
  131. {
  132. return $page;
  133. }
  134. /**
  135. * index method
  136. *
  137. * @return void
  138. */
  139. public function index()
  140. {
  141. return true;
  142. }
  143. }
  144. /**
  145. * ArticlesTestAppController class
  146. *
  147. */
  148. class ArticlesTestAppController extends Controller
  149. {
  150. }
  151. /**
  152. * ArticlesTestController class
  153. *
  154. */
  155. class ArticlesTestController extends ArticlesTestAppController
  156. {
  157. /**
  158. * name property
  159. *
  160. * @var string
  161. */
  162. public $name = 'ArticlesTest';
  163. /**
  164. * admin_index method
  165. *
  166. * @return void
  167. */
  168. public function admin_index()
  169. {
  170. return true;
  171. }
  172. /**
  173. * fake index method.
  174. *
  175. * @return void
  176. */
  177. public function index()
  178. {
  179. return true;
  180. }
  181. }
  182. /**
  183. * DispatcherTest class
  184. *
  185. */
  186. class DispatcherTest extends TestCase
  187. {
  188. /**
  189. * setUp method
  190. *
  191. * @return void
  192. */
  193. public function setUp()
  194. {
  195. parent::setUp();
  196. $_GET = [];
  197. Configure::write('App.base', false);
  198. Configure::write('App.baseUrl', false);
  199. Configure::write('App.dir', 'app');
  200. Configure::write('App.webroot', 'webroot');
  201. Configure::write('App.namespace', 'TestApp');
  202. $this->dispatcher = new TestDispatcher();
  203. $this->dispatcher->addFilter(new ControllerFactoryFilter());
  204. }
  205. /**
  206. * tearDown method
  207. *
  208. * @return void
  209. */
  210. public function tearDown()
  211. {
  212. parent::tearDown();
  213. Plugin::unload();
  214. }
  215. /**
  216. * testMissingController method
  217. *
  218. * @expectedException \Cake\Routing\Exception\MissingControllerException
  219. * @expectedExceptionMessage Controller class SomeController could not be found.
  220. * @return void
  221. */
  222. public function testMissingController()
  223. {
  224. $request = new Request([
  225. 'url' => 'some_controller/home',
  226. 'params' => [
  227. 'controller' => 'SomeController',
  228. 'action' => 'home',
  229. ]
  230. ]);
  231. $response = $this->getMock('Cake\Network\Response');
  232. $this->dispatcher->dispatch($request, $response, ['return' => 1]);
  233. }
  234. /**
  235. * testMissingControllerInterface method
  236. *
  237. * @expectedException \Cake\Routing\Exception\MissingControllerException
  238. * @expectedExceptionMessage Controller class DispatcherTestInterface could not be found.
  239. * @return void
  240. */
  241. public function testMissingControllerInterface()
  242. {
  243. $request = new Request([
  244. 'url' => 'dispatcher_test_interface/index',
  245. 'params' => [
  246. 'controller' => 'DispatcherTestInterface',
  247. 'action' => 'index',
  248. ]
  249. ]);
  250. $url = new Request('dispatcher_test_interface/index');
  251. $response = $this->getMock('Cake\Network\Response');
  252. $this->dispatcher->dispatch($request, $response, ['return' => 1]);
  253. }
  254. /**
  255. * testMissingControllerInterface method
  256. *
  257. * @expectedException \Cake\Routing\Exception\MissingControllerException
  258. * @expectedExceptionMessage Controller class Abstract could not be found.
  259. * @return void
  260. */
  261. public function testMissingControllerAbstract()
  262. {
  263. $request = new Request([
  264. 'url' => 'abstract/index',
  265. 'params' => [
  266. 'controller' => 'Abstract',
  267. 'action' => 'index',
  268. ]
  269. ]);
  270. $response = $this->getMock('Cake\Network\Response');
  271. $this->dispatcher->dispatch($request, $response, ['return' => 1]);
  272. }
  273. /**
  274. * testDispatch method
  275. *
  276. * @return void
  277. */
  278. public function testDispatchBasic()
  279. {
  280. $url = new Request([
  281. 'url' => 'pages/home',
  282. 'params' => [
  283. 'controller' => 'Pages',
  284. 'action' => 'display',
  285. 'pass' => ['extract'],
  286. 'return' => 1
  287. ]
  288. ]);
  289. $response = $this->getMock('Cake\Network\Response');
  290. $this->dispatcher->dispatch($url, $response);
  291. $expected = 'Pages';
  292. $this->assertEquals($expected, $this->dispatcher->controller->name);
  293. }
  294. /**
  295. * Test that Dispatcher handles actions that return response objects.
  296. *
  297. * @return void
  298. */
  299. public function testDispatchActionReturnsResponse()
  300. {
  301. $request = new Request([
  302. 'url' => 'some_pages/responseGenerator',
  303. 'params' => [
  304. 'controller' => 'SomePages',
  305. 'action' => 'responseGenerator',
  306. 'pass' => []
  307. ]
  308. ]);
  309. $response = $this->getMock('Cake\Network\Response', ['_sendHeader']);
  310. ob_start();
  311. $this->dispatcher->dispatch($request, $response);
  312. $result = ob_get_clean();
  313. $this->assertEquals('new response', $result);
  314. }
  315. /**
  316. * testPrefixDispatch method
  317. *
  318. * @return void
  319. */
  320. public function testPrefixDispatch()
  321. {
  322. $request = new Request([
  323. 'url' => 'admin/posts/index',
  324. 'params' => [
  325. 'prefix' => 'Admin',
  326. 'controller' => 'Posts',
  327. 'action' => 'index',
  328. 'pass' => [],
  329. 'return' => 1
  330. ]
  331. ]);
  332. $response = $this->getMock('Cake\Network\Response');
  333. $this->dispatcher->dispatch($request, $response);
  334. $this->assertInstanceOf(
  335. 'TestApp\Controller\Admin\PostsController',
  336. $this->dispatcher->controller
  337. );
  338. $expected = '/admin/posts/index';
  339. $this->assertSame($expected, $request->here);
  340. }
  341. /**
  342. * test prefix dispatching in a plugin.
  343. *
  344. * @return void
  345. */
  346. public function testPrefixDispatchPlugin()
  347. {
  348. Plugin::load('TestPlugin');
  349. $request = new Request([
  350. 'url' => 'admin/test_plugin/comments/index',
  351. 'params' => [
  352. 'plugin' => 'TestPlugin',
  353. 'prefix' => 'Admin',
  354. 'controller' => 'Comments',
  355. 'action' => 'index',
  356. 'pass' => [],
  357. 'return' => 1
  358. ]
  359. ]);
  360. $response = $this->getMock('Cake\Network\Response');
  361. $this->dispatcher->dispatch($request, $response);
  362. $this->assertInstanceOf(
  363. 'TestPlugin\Controller\Admin\CommentsController',
  364. $this->dispatcher->controller
  365. );
  366. }
  367. /**
  368. * test forbidden controller names.
  369. *
  370. * @expectedException \Cake\Routing\Exception\MissingControllerException
  371. * @expectedExceptionMessage Controller class TestPlugin.Tests could not be found.
  372. * @return void
  373. */
  374. public function testDispatchBadPluginName()
  375. {
  376. Plugin::load('TestPlugin');
  377. $request = new Request([
  378. 'url' => 'TestPlugin.Tests/index',
  379. 'params' => [
  380. 'plugin' => '',
  381. 'controller' => 'TestPlugin.Tests',
  382. 'action' => 'index',
  383. 'pass' => [],
  384. 'return' => 1
  385. ]
  386. ]);
  387. $response = $this->getMock('Cake\Network\Response');
  388. $this->dispatcher->dispatch($request, $response);
  389. }
  390. /**
  391. * test forbidden controller names.
  392. *
  393. * @expectedException \Cake\Routing\Exception\MissingControllerException
  394. * @expectedExceptionMessage Controller class TestApp\Controller\PostsController could not be found.
  395. * @return void
  396. */
  397. public function testDispatchBadName()
  398. {
  399. $request = new Request([
  400. 'url' => 'TestApp%5CController%5CPostsController/index',
  401. 'params' => [
  402. 'plugin' => '',
  403. 'controller' => 'TestApp\Controller\PostsController',
  404. 'action' => 'index',
  405. 'pass' => [],
  406. 'return' => 1
  407. ]
  408. ]);
  409. $response = $this->getMock('Cake\Network\Response');
  410. $this->dispatcher->dispatch($request, $response);
  411. }
  412. /**
  413. * Test dispatcher filters being called.
  414. *
  415. * @return void
  416. */
  417. public function testDispatcherFilter()
  418. {
  419. $filter = $this->getMock(
  420. 'Cake\Routing\DispatcherFilter',
  421. ['beforeDispatch', 'afterDispatch']
  422. );
  423. $filter->expects($this->at(0))
  424. ->method('beforeDispatch');
  425. $filter->expects($this->at(1))
  426. ->method('afterDispatch');
  427. $this->dispatcher->addFilter($filter);
  428. $request = new Request([
  429. 'url' => '/',
  430. 'params' => [
  431. 'controller' => 'pages',
  432. 'action' => 'display',
  433. 'home',
  434. 'pass' => []
  435. ]
  436. ]);
  437. $response = $this->getMock('Cake\Network\Response', ['send']);
  438. $this->dispatcher->dispatch($request, $response);
  439. }
  440. /**
  441. * Test dispatcher filters being called and changing the response.
  442. *
  443. * @return void
  444. */
  445. public function testBeforeDispatchAbortDispatch()
  446. {
  447. $response = $this->getMock('Cake\Network\Response', ['send']);
  448. $response->expects($this->once())
  449. ->method('send');
  450. $filter = $this->getMock(
  451. 'Cake\Routing\DispatcherFilter',
  452. ['beforeDispatch', 'afterDispatch']
  453. );
  454. $filter->expects($this->once())
  455. ->method('beforeDispatch')
  456. ->will($this->returnValue($response));
  457. $filter->expects($this->never())
  458. ->method('afterDispatch');
  459. $request = new Request();
  460. $res = new Response();
  461. $this->dispatcher->addFilter($filter);
  462. $this->dispatcher->dispatch($request, $res);
  463. }
  464. /**
  465. * Test dispatcher filters being called and changing the response.
  466. *
  467. * @return void
  468. */
  469. public function testAfterDispatchReplaceResponse()
  470. {
  471. $response = $this->getMock('Cake\Network\Response', ['_sendHeader', 'send']);
  472. $response->expects($this->once())
  473. ->method('send');
  474. $filter = $this->getMock(
  475. 'Cake\Routing\DispatcherFilter',
  476. ['beforeDispatch', 'afterDispatch']
  477. );
  478. $filter->expects($this->once())
  479. ->method('afterDispatch')
  480. ->will($this->returnValue($response));
  481. $request = new Request([
  482. 'url' => '/posts',
  483. 'params' => [
  484. 'plugin' => null,
  485. 'controller' => 'Posts',
  486. 'action' => 'index',
  487. 'pass' => [],
  488. ],
  489. 'session' => new Session
  490. ]);
  491. $this->dispatcher->addFilter($filter);
  492. $this->dispatcher->dispatch($request, $response);
  493. }
  494. }