dispatcher = new ActionDispatcher(); } /** * Teardown * * @return void */ public function tearDown() { parent::tearDown(); DispatcherFactory::clear(); } /** * Ensure the constructor args end up on the right protected properties. * * @return void */ public function testConstructorArgs() { $factory = $this->getMockBuilder('Cake\Http\ControllerFactory')->getMock(); $events = $this->getMockBuilder('Cake\Event\EventManager')->getMock(); $dispatcher = new ActionDispatcher($factory, $events); $this->assertAttributeSame($events, '_eventManager', $dispatcher); $this->assertAttributeSame($factory, 'factory', $dispatcher); } /** * Ensure that filters connected to the DispatcherFactory are * also applied * * @group deprecated * @return void */ public function testDispatcherFactoryCompat() { $this->deprecated(function () { $filter = $this->getMockBuilder('Cake\Routing\DispatcherFilter') ->setMethods(['beforeDispatch', 'afterDispatch']) ->getMock(); DispatcherFactory::add($filter); $dispatcher = new ActionDispatcher(null, null, DispatcherFactory::filters()); $this->assertCount(1, $dispatcher->getFilters()); $this->assertSame($filter, $dispatcher->getFilters()[0]); }); } /** * Test adding routing filters * * @group deprecated * @return void */ public function testAddFilter() { $this->deprecated(function () { $this->assertCount(0, $this->dispatcher->getFilters()); $events = $this->dispatcher->getEventManager(); $this->assertCount(0, $events->listeners('Dispatcher.beforeDispatch')); $this->assertCount(0, $events->listeners('Dispatcher.afterDispatch')); $filter = $this->getMockBuilder('Cake\Routing\DispatcherFilter') ->setMethods(['beforeDispatch', 'afterDispatch']) ->getMock(); $this->dispatcher->addFilter($filter); $this->assertCount(1, $this->dispatcher->getFilters()); $this->assertCount(1, $events->listeners('Dispatcher.beforeDispatch')); $this->assertCount(1, $events->listeners('Dispatcher.afterDispatch')); }); } /** * Ensure that aborting in the beforeDispatch doesn't invoke the controller * * @return void */ public function testBeforeDispatchEventAbort() { $response = new Response(); $dispatcher = new ActionDispatcher(); $req = new ServerRequest(); $res = new Response(); $dispatcher->getEventManager()->on('Dispatcher.beforeDispatch', function () use ($response) { return $response; }); $result = $dispatcher->dispatch($req, $res); $this->assertSame($response, $result, 'Should be response from filter.'); } /** * Ensure afterDispatch can replace the response * * @return void */ public function testDispatchAfterDispatchEventModifyResponse() { $req = new ServerRequest([ 'url' => '/cakes', 'params' => [ 'plugin' => null, 'controller' => 'Cakes', 'action' => 'index', 'pass' => [], ], 'session' => new Session ]); $res = new Response(); $this->dispatcher->getEventManager()->on('Dispatcher.afterDispatch', function (Event $event) { $response = $event->getData('response'); $event->setData('response', $response->withStringBody('Filter body')); }); $result = $this->dispatcher->dispatch($req, $res); $this->assertSame('Filter body', (string)$result->getBody(), 'Should be response from filter.'); } /** * Test that a controller action returning a response * results in no afterDispatch event. * * @return void */ public function testDispatchActionReturnResponseNoAfterDispatch() { $req = new ServerRequest([ 'url' => '/cakes', 'params' => [ 'plugin' => null, 'controller' => 'Cakes', 'action' => 'index', 'pass' => [], 'return' => true, ], ]); $res = new Response(); $this->dispatcher->getEventManager()->on('Dispatcher.afterDispatch', function () { $this->fail('no afterDispatch event should be fired'); }); $result = $this->dispatcher->dispatch($req, $res); $this->assertSame('Hello Jane', (string)$result->getBody(), 'Response from controller.'); } /** * Test that dispatching sets the Router request state. * * @return void */ public function testDispatchSetsRequestContext() { $this->assertNull(Router::getRequest()); $req = new ServerRequest([ 'url' => '/cakes', 'params' => [ 'plugin' => null, 'controller' => 'Cakes', 'action' => 'index', 'pass' => [], 'return' => true, ], ]); $res = new Response(); $this->dispatcher->dispatch($req, $res); $this->assertSame($req, Router::getRequest(true)); } /** * test invalid response from dispatch process. * * @return void */ public function testDispatchInvalidResponse() { $this->expectException(\LogicException::class); $this->expectExceptionMessage('Controller actions can only return Cake\Http\Response or null'); $req = new ServerRequest([ 'url' => '/cakes', 'params' => [ 'plugin' => null, 'controller' => 'Cakes', 'action' => 'invalid', 'pass' => [], ], ]); $res = new Response(); $result = $this->dispatcher->dispatch($req, $res); } /** * Test dispatch with autorender * * @return void */ public function testDispatchAutoRender() { $request = new ServerRequest([ 'url' => 'posts', 'params' => [ 'controller' => 'Posts', 'action' => 'index', 'pass' => [], ] ]); $response = new Response(); $result = $this->dispatcher->dispatch($request, $response); $this->assertInstanceOf('Cake\Http\Response', $result); $this->assertContains('posts index', (string)$result->getBody()); } /** * Test dispatch with autorender=false * * @return void */ public function testDispatchAutoRenderFalse() { $request = new ServerRequest([ 'url' => 'posts', 'params' => [ 'controller' => 'Cakes', 'action' => 'noRender', 'pass' => [], ] ]); $response = new Response(); $result = $this->dispatcher->dispatch($request, $response); $this->assertInstanceOf('Cake\Http\Response', $result); $this->assertContains('autoRender false body', (string)$result->getBody()); } /** * testMissingController method * * @return void */ public function testMissingController() { $this->expectException(\Cake\Routing\Exception\MissingControllerException::class); $this->expectExceptionMessage('Controller class SomeController could not be found.'); $request = new ServerRequest([ 'url' => 'some_controller/home', 'params' => [ 'controller' => 'SomeController', 'action' => 'home', ] ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); $this->dispatcher->dispatch($request, $response); } /** * testMissingControllerInterface method * * @return void */ public function testMissingControllerInterface() { $this->expectException(\Cake\Routing\Exception\MissingControllerException::class); $this->expectExceptionMessage('Controller class Interface could not be found.'); $request = new ServerRequest([ 'url' => 'interface/index', 'params' => [ 'controller' => 'Interface', 'action' => 'index', ] ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); $this->dispatcher->dispatch($request, $response); } /** * testMissingControllerInterface method * * @return void */ public function testMissingControllerAbstract() { $this->expectException(\Cake\Routing\Exception\MissingControllerException::class); $this->expectExceptionMessage('Controller class Abstract could not be found.'); $request = new ServerRequest([ 'url' => 'abstract/index', 'params' => [ 'controller' => 'Abstract', 'action' => 'index', ] ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); $this->dispatcher->dispatch($request, $response); } /** * Test that lowercase controller names result in missing controller errors. * * In case-insensitive file systems, lowercase controller names will kind of work. * This causes annoying deployment issues for lots of folks. * * @return void */ public function testMissingControllerLowercase() { $this->expectException(\Cake\Routing\Exception\MissingControllerException::class); $this->expectExceptionMessage('Controller class somepages could not be found.'); $request = new ServerRequest([ 'url' => 'pages/home', 'params' => [ 'plugin' => null, 'controller' => 'somepages', 'action' => 'display', 'pass' => ['home'], ] ]); $response = $this->getMockBuilder('Cake\Http\Response')->getMock(); $this->dispatcher->dispatch($request, $response); } /** * Ensure that a controller's startup event can stop the request. * * @return void */ public function testStartupProcessAbort() { $request = new ServerRequest([ 'url' => 'cakes/index', 'params' => [ 'plugin' => null, 'controller' => 'Cakes', 'action' => 'index', 'stop' => 'startup', 'pass' => [], ] ]); $response = new Response(); $result = $this->dispatcher->dispatch($request, $response); $this->assertSame('startup stop', (string)$result->getBody()); } /** * Ensure that a controllers startup process can emit a response * * @return void */ public function testShutdownProcessResponse() { $request = new ServerRequest([ 'url' => 'cakes/index', 'params' => [ 'plugin' => null, 'controller' => 'Cakes', 'action' => 'index', 'stop' => 'shutdown', 'pass' => [], ] ]); $response = new Response(); $result = $this->dispatcher->dispatch($request, $response); $this->assertSame('shutdown stop', (string)$result->getBody()); } }