DispatcherTest.php 9.8 KB

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