From 0970664ccdc99e9ae1e49dde5f99439acad91e25 Mon Sep 17 00:00:00 2001 From: Christian Kuhn Date: Sun, 11 Mar 2018 10:31:05 +0100 Subject: [PATCH] [TASK] Add test coverage for RouteDispatcher The backend route dispatcher with its different controller incarnations benefits from a basic code coverage. Resolves: #85191 Related: #84196 Releases: master Change-Id: I0ff1efae64c41e7fbeba8fb3569c5601cb005669 Reviewed-on: https://review.typo3.org/56095 Tested-by: TYPO3com Reviewed-by: Benni Mack Tested-by: Benni Mack Reviewed-by: Anja Leichsenring Tested-by: Anja Leichsenring --- .../backend/Classes/Http/RouteDispatcher.php | 2 - .../Fixtures/RouteDispatcherClassFixture.php | 31 ++ .../RouteDispatcherClassInvokeFixture.php | 31 ++ ...uteDispatcherClassWithoutInvokeFixture.php | 22 ++ .../RouteDispatcherStaticClassFixture.php | 31 ++ .../Tests/Unit/Http/RouteDispatcherTest.php | 265 ++++++++++++++++++ 6 files changed, 380 insertions(+), 2 deletions(-) create mode 100644 typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassFixture.php create mode 100644 typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassInvokeFixture.php create mode 100644 typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassWithoutInvokeFixture.php create mode 100644 typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherStaticClassFixture.php create mode 100644 typo3/sysext/backend/Tests/Unit/Http/RouteDispatcherTest.php diff --git a/typo3/sysext/backend/Classes/Http/RouteDispatcher.php b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php index c63e94c998d3..b5044aa8bfb8 100644 --- a/typo3/sysext/backend/Classes/Http/RouteDispatcher.php +++ b/typo3/sysext/backend/Classes/Http/RouteDispatcher.php @@ -42,9 +42,7 @@ class RouteDispatcher extends Dispatcher */ public function dispatch(ServerRequestInterface $request, ResponseInterface $response) { - /** @var Router $router */ $router = GeneralUtility::makeInstance(Router::class); - /** @var Route $route */ $route = $router->matchRequest($request); $request = $request->withAttribute('route', $route); $request = $request->withAttribute('target', $route->getOption('target')); diff --git a/typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassFixture.php b/typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassFixture.php new file mode 100644 index 000000000000..58b8c8af7d93 --- /dev/null +++ b/typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassFixture.php @@ -0,0 +1,31 @@ +prophesize(AbstractFormProtection::class); + $formProtectionProphecy->validateToken(Argument::cetera())->willReturn(true); + FormProtectionFactory::set('default', $formProtectionProphecy->reveal()); + + $requestProphecy = $this->prophesize(ServerRequestInterface::class); + $responseProphecy = $this->prophesize(ResponseInterface::class); + $routerProphecy = $this->prophesize(Router::class); + GeneralUtility::setSingletonInstance(Router::class, $routerProphecy->reveal()); + $routeProphecy = $this->prophesize(Route::class); + $routerProphecy->matchRequest($requestProphecy->reveal())->willReturn($routeProphecy->reveal()); + $routeProphecy->getOption('access')->willReturn('public'); + $routeProphecy->getOption('module')->willReturn(false); + $requestProphecy->withAttribute('route', $routeProphecy->reveal())->willReturn($requestProphecy->reveal()); + $requestProphecy->getAttribute('route')->willReturn($routeProphecy->reveal()); + + $target = 42; + $routeProphecy->getOption('target')->willReturn($target); + $requestProphecy->withAttribute('target', $target)->willReturn($requestProphecy->reveal()); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionCode(1425381442); + + $subject = new RouteDispatcher(); + $subject->dispatch($requestProphecy->reveal(), $responseProphecy->reveal()); + } + + /** + * @test + */ + public function dispatchCallsTargetIfTargetIsArray() + { + $formProtectionProphecy = $this->prophesize(AbstractFormProtection::class); + $formProtectionProphecy->validateToken(Argument::cetera())->willReturn(true); + FormProtectionFactory::set('default', $formProtectionProphecy->reveal()); + + $requestProphecy = $this->prophesize(ServerRequestInterface::class); + $responseProphecy = $this->prophesize(ResponseInterface::class); + $routerProphecy = $this->prophesize(Router::class); + GeneralUtility::setSingletonInstance(Router::class, $routerProphecy->reveal()); + $routeProphecy = $this->prophesize(Route::class); + $routerProphecy->matchRequest($requestProphecy->reveal())->willReturn($routeProphecy->reveal()); + $routeProphecy->getOption('access')->willReturn('public'); + $routeProphecy->getOption('module')->willReturn(false); + $requestProphecy->withAttribute('route', $routeProphecy->reveal())->willReturn($requestProphecy->reveal()); + $requestProphecy->getAttribute('route')->willReturn($routeProphecy->reveal()); + + $target = [ + RouteDispatcherClassFixture::class, + 'mainAction' + ]; + $routeProphecy->getOption('target')->willReturn($target); + $requestProphecy->withAttribute('target', $target)->willReturn($requestProphecy->reveal()); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionCode(1520756142); + + $subject = new RouteDispatcher(); + $subject->dispatch($requestProphecy->reveal(), $responseProphecy->reveal()); + } + + /** + * @test + */ + public function dispatchCallsTargetIfTargetIsClosure() + { + $formProtectionProphecy = $this->prophesize(AbstractFormProtection::class); + $formProtectionProphecy->validateToken(Argument::cetera())->willReturn(true); + FormProtectionFactory::set('default', $formProtectionProphecy->reveal()); + + $requestProphecy = $this->prophesize(ServerRequestInterface::class); + $responseProphecy = $this->prophesize(ResponseInterface::class); + $routerProphecy = $this->prophesize(Router::class); + GeneralUtility::setSingletonInstance(Router::class, $routerProphecy->reveal()); + $routeProphecy = $this->prophesize(Route::class); + $routerProphecy->matchRequest($requestProphecy->reveal())->willReturn($routeProphecy->reveal()); + $routeProphecy->getOption('access')->willReturn('public'); + $routeProphecy->getOption('module')->willReturn(false); + $requestProphecy->withAttribute('route', $routeProphecy->reveal())->willReturn($requestProphecy->reveal()); + $requestProphecy->getAttribute('route')->willReturn($routeProphecy->reveal()); + + $target = function (ServerRequestInterface $request) { + throw new \RuntimeException('I have been called. Good!', 1520756466); + }; + $routeProphecy->getOption('target')->willReturn($target); + $requestProphecy->withAttribute('target', $target)->willReturn($requestProphecy->reveal()); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionCode(1520756466); + + $subject = new RouteDispatcher(); + $subject->dispatch($requestProphecy->reveal(), $responseProphecy->reveal()); + } + + /** + * @test + */ + public function dispatchCallsTargetIfTargetIsClassImplementingInvoke() + { + $formProtectionProphecy = $this->prophesize(AbstractFormProtection::class); + $formProtectionProphecy->validateToken(Argument::cetera())->willReturn(true); + FormProtectionFactory::set('default', $formProtectionProphecy->reveal()); + + $requestProphecy = $this->prophesize(ServerRequestInterface::class); + $responseProphecy = $this->prophesize(ResponseInterface::class); + $routerProphecy = $this->prophesize(Router::class); + GeneralUtility::setSingletonInstance(Router::class, $routerProphecy->reveal()); + $routeProphecy = $this->prophesize(Route::class); + $routerProphecy->matchRequest($requestProphecy->reveal())->willReturn($routeProphecy->reveal()); + $routeProphecy->getOption('access')->willReturn('public'); + $routeProphecy->getOption('module')->willReturn(false); + $requestProphecy->withAttribute('route', $routeProphecy->reveal())->willReturn($requestProphecy->reveal()); + $requestProphecy->getAttribute('route')->willReturn($routeProphecy->reveal()); + + $target = RouteDispatcherClassInvokeFixture::class; + $routeProphecy->getOption('target')->willReturn($target); + $requestProphecy->withAttribute('target', $target)->willReturn($requestProphecy->reveal()); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionCode(1520756623); + + $subject = new RouteDispatcher(); + $subject->dispatch($requestProphecy->reveal(), $responseProphecy->reveal()); + } + + /** + * @test + */ + public function dispatchThrowsExceptionIfTargetWithClassNameOnlyDoesNotImplementInvoke() + { + $formProtectionProphecy = $this->prophesize(AbstractFormProtection::class); + $formProtectionProphecy->validateToken(Argument::cetera())->willReturn(true); + FormProtectionFactory::set('default', $formProtectionProphecy->reveal()); + + $requestProphecy = $this->prophesize(ServerRequestInterface::class); + $responseProphecy = $this->prophesize(ResponseInterface::class); + $routerProphecy = $this->prophesize(Router::class); + GeneralUtility::setSingletonInstance(Router::class, $routerProphecy->reveal()); + $routeProphecy = $this->prophesize(Route::class); + $routerProphecy->matchRequest($requestProphecy->reveal())->willReturn($routeProphecy->reveal()); + $routeProphecy->getOption('access')->willReturn('public'); + $routeProphecy->getOption('module')->willReturn(false); + $requestProphecy->withAttribute('route', $routeProphecy->reveal())->willReturn($requestProphecy->reveal()); + $requestProphecy->getAttribute('route')->willReturn($routeProphecy->reveal()); + + $target = RouteDispatcherClassWithoutInvokeFixture::class; + $routeProphecy->getOption('target')->willReturn($target); + $requestProphecy->withAttribute('target', $target)->willReturn($requestProphecy->reveal()); + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionCode(1442431631); + + $subject = new RouteDispatcher(); + $subject->dispatch($requestProphecy->reveal(), $responseProphecy->reveal()); + } + + /** + * @test + */ + public function dispatchCallsClassMethodCombinationGivenAsString() + { + $formProtectionProphecy = $this->prophesize(AbstractFormProtection::class); + $formProtectionProphecy->validateToken(Argument::cetera())->willReturn(true); + FormProtectionFactory::set('default', $formProtectionProphecy->reveal()); + + $requestProphecy = $this->prophesize(ServerRequestInterface::class); + $responseProphecy = $this->prophesize(ResponseInterface::class); + $routerProphecy = $this->prophesize(Router::class); + GeneralUtility::setSingletonInstance(Router::class, $routerProphecy->reveal()); + $routeProphecy = $this->prophesize(Route::class); + $routerProphecy->matchRequest($requestProphecy->reveal())->willReturn($routeProphecy->reveal()); + $routeProphecy->getOption('access')->willReturn('public'); + $routeProphecy->getOption('module')->willReturn(false); + $requestProphecy->withAttribute('route', $routeProphecy->reveal())->willReturn($requestProphecy->reveal()); + $requestProphecy->getAttribute('route')->willReturn($routeProphecy->reveal()); + + $target = RouteDispatcherClassFixture::class . '::mainAction'; + $routeProphecy->getOption('target')->willReturn($target); + $requestProphecy->withAttribute('target', $target)->willReturn($requestProphecy->reveal()); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionCode(1520756142); + + $subject = new RouteDispatcher(); + $subject->dispatch($requestProphecy->reveal(), $responseProphecy->reveal()); + } + + /** + * @test + */ + public function dispatchCallsStaticClassMethodCombinationGivenAsString() + { + $formProtectionProphecy = $this->prophesize(AbstractFormProtection::class); + $formProtectionProphecy->validateToken(Argument::cetera())->willReturn(true); + FormProtectionFactory::set('default', $formProtectionProphecy->reveal()); + + $requestProphecy = $this->prophesize(ServerRequestInterface::class); + $responseProphecy = $this->prophesize(ResponseInterface::class); + $routerProphecy = $this->prophesize(Router::class); + GeneralUtility::setSingletonInstance(Router::class, $routerProphecy->reveal()); + $routeProphecy = $this->prophesize(Route::class); + $routerProphecy->matchRequest($requestProphecy->reveal())->willReturn($routeProphecy->reveal()); + $routeProphecy->getOption('access')->willReturn('public'); + $routeProphecy->getOption('module')->willReturn(false); + $requestProphecy->withAttribute('route', $routeProphecy->reveal())->willReturn($requestProphecy->reveal()); + $requestProphecy->getAttribute('route')->willReturn($routeProphecy->reveal()); + + $target = RouteDispatcherStaticClassFixture::class . '::mainAction'; + $routeProphecy->getOption('target')->willReturn($target); + $requestProphecy->withAttribute('target', $target)->willReturn($requestProphecy->reveal()); + + $this->expectException(\RuntimeException::class); + $this->expectExceptionCode(1520757000); + + $subject = new RouteDispatcher(); + $subject->dispatch($requestProphecy->reveal(), $responseProphecy->reveal()); + } +}