[TASK] Add test coverage for RouteDispatcher 95/56095/4
authorChristian Kuhn <lolli@schwarzbu.ch>
Sun, 11 Mar 2018 09:31:05 +0000 (10:31 +0100)
committerAnja Leichsenring <aleichsenring@ab-softlab.de>
Sat, 9 Jun 2018 11:37:09 +0000 (13:37 +0200)
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 <no-reply@typo3.com>
Reviewed-by: Benni Mack <benni@typo3.org>
Tested-by: Benni Mack <benni@typo3.org>
Reviewed-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
Tested-by: Anja Leichsenring <aleichsenring@ab-softlab.de>
typo3/sysext/backend/Classes/Http/RouteDispatcher.php
typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassFixture.php [new file with mode: 0644]
typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassInvokeFixture.php [new file with mode: 0644]
typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassWithoutInvokeFixture.php [new file with mode: 0644]
typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherStaticClassFixture.php [new file with mode: 0644]
typo3/sysext/backend/Tests/Unit/Http/RouteDispatcherTest.php [new file with mode: 0644]

index c63e94c..b5044aa 100644 (file)
@@ -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 (file)
index 0000000..58b8c8a
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+namespace TYPO3\CMS\Backend\Tests\Unit\Http\Fixtures;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Test fixture
+ */
+class RouteDispatcherClassFixture
+{
+    public function mainAction(ServerRequestInterface $request)
+    {
+        throw new \RuntimeException(
+            'I have been called. Good!',
+            1520756142
+        );
+    }
+}
diff --git a/typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassInvokeFixture.php b/typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassInvokeFixture.php
new file mode 100644 (file)
index 0000000..fcfbc50
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+namespace TYPO3\CMS\Backend\Tests\Unit\Http\Fixtures;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Test fixture
+ */
+class RouteDispatcherClassInvokeFixture
+{
+    public function __invoke(ServerRequestInterface $request)
+    {
+        throw new \RuntimeException(
+            'I have been called. Good!',
+            1520756623
+        );
+    }
+}
diff --git a/typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassWithoutInvokeFixture.php b/typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherClassWithoutInvokeFixture.php
new file mode 100644 (file)
index 0000000..bb6ee56
--- /dev/null
@@ -0,0 +1,22 @@
+<?php
+namespace TYPO3\CMS\Backend\Tests\Unit\Http\Fixtures;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Test fixture
+ */
+class RouteDispatcherClassWithoutInvokeFixture
+{
+}
diff --git a/typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherStaticClassFixture.php b/typo3/sysext/backend/Tests/Unit/Http/Fixtures/RouteDispatcherStaticClassFixture.php
new file mode 100644 (file)
index 0000000..fb6235e
--- /dev/null
@@ -0,0 +1,31 @@
+<?php
+namespace TYPO3\CMS\Backend\Tests\Unit\Http\Fixtures;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Psr\Http\Message\ServerRequestInterface;
+
+/**
+ * Test fixture
+ */
+class RouteDispatcherStaticClassFixture
+{
+    public static function mainAction(ServerRequestInterface $request)
+    {
+        throw new \RuntimeException(
+            'I have been called. Good!',
+            1520757000
+        );
+    }
+}
diff --git a/typo3/sysext/backend/Tests/Unit/Http/RouteDispatcherTest.php b/typo3/sysext/backend/Tests/Unit/Http/RouteDispatcherTest.php
new file mode 100644 (file)
index 0000000..d267151
--- /dev/null
@@ -0,0 +1,265 @@
+<?php
+namespace TYPO3\CMS\Backend\Tests\Unit\Http;
+
+/*
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use Prophecy\Argument;
+use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Backend\Http\RouteDispatcher;
+use TYPO3\CMS\Backend\Routing\Route;
+use TYPO3\CMS\Backend\Routing\Router;
+use TYPO3\CMS\Backend\Tests\Unit\Http\Fixtures\RouteDispatcherClassFixture;
+use TYPO3\CMS\Backend\Tests\Unit\Http\Fixtures\RouteDispatcherClassInvokeFixture;
+use TYPO3\CMS\Backend\Tests\Unit\Http\Fixtures\RouteDispatcherClassWithoutInvokeFixture;
+use TYPO3\CMS\Backend\Tests\Unit\Http\Fixtures\RouteDispatcherStaticClassFixture;
+use TYPO3\CMS\Core\FormProtection\AbstractFormProtection;
+use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
+
+/**
+ * Test case
+ */
+class RouteDispatcherTest extends UnitTestCase
+{
+    public function tearDown()
+    {
+        FormProtectionFactory::purgeInstances();
+        GeneralUtility::purgeInstances();
+        parent::tearDown();
+    }
+
+    /**
+     * @test
+     */
+    public function dispatchThrowsExceptionIfTargetIsNotCallable()
+    {
+        $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 = 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());
+    }
+}