From a1bc763a16ee8be109de5c9053fbc5eded53824e Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Sat, 25 Aug 2018 21:16:20 +0200 Subject: Added nikic/fast-route as routing dispatcher --- tests/Unit/Middleware/CallableHandlerTest.php | 141 ++++++++++++++++++++ tests/Unit/Middleware/DispatcherTest.php | 58 ++------ tests/Unit/Middleware/LegacyMiddlewareTest.php | 8 +- tests/Unit/Middleware/NotFoundResponseTest.php | 39 ------ .../RequestHandlerServiceProviderTest.php | 36 +++++ tests/Unit/Middleware/RequestHandlerTest.php | 89 +++++++++++++ .../Middleware/ResolvesMiddlewareTraitTest.php | 67 ++++++++++ .../RouteDispatcherServiceProviderTest.php | 65 +++++++++ tests/Unit/Middleware/RouteDispatcherTest.php | 148 +++++++++++++++++++++ tests/Unit/Middleware/Stub/HasStaticMethod.php | 8 ++ .../Stub/ResolvesMiddlewareTraitImplementation.php | 35 +++++ 11 files changed, 604 insertions(+), 90 deletions(-) create mode 100644 tests/Unit/Middleware/CallableHandlerTest.php delete mode 100644 tests/Unit/Middleware/NotFoundResponseTest.php create mode 100644 tests/Unit/Middleware/RequestHandlerServiceProviderTest.php create mode 100644 tests/Unit/Middleware/RequestHandlerTest.php create mode 100644 tests/Unit/Middleware/ResolvesMiddlewareTraitTest.php create mode 100644 tests/Unit/Middleware/RouteDispatcherServiceProviderTest.php create mode 100644 tests/Unit/Middleware/RouteDispatcherTest.php create mode 100644 tests/Unit/Middleware/Stub/HasStaticMethod.php create mode 100644 tests/Unit/Middleware/Stub/ResolvesMiddlewareTraitImplementation.php (limited to 'tests/Unit/Middleware') diff --git a/tests/Unit/Middleware/CallableHandlerTest.php b/tests/Unit/Middleware/CallableHandlerTest.php new file mode 100644 index 00000000..6e6dab58 --- /dev/null +++ b/tests/Unit/Middleware/CallableHandlerTest.php @@ -0,0 +1,141 @@ +getProperty('callable'); + $property->setAccessible(true); + + $this->assertEquals($callable, $property->getValue($handler)); + } + + /** + * @covers \Engelsystem\Middleware\CallableHandler::process + */ + public function testProcess() + { + /** @var ServerRequestInterface|MockObject $request */ + /** @var ResponseInterface|MockObject $response */ + /** @var callable|MockObject $callable */ + /** @var RequestHandlerInterface|MockObject $handler */ + list($request, $response, $callable, $handler) = $this->getMocks(); + + $callable->expects($this->once()) + ->method('__invoke') + ->with($request, $handler) + ->willReturn($response); + + $middleware = new CallableHandler($callable); + $middleware->process($request, $handler); + } + + /** + * @covers \Engelsystem\Middleware\CallableHandler::handle + */ + public function testHandler() + { + /** @var ServerRequestInterface|MockObject $request */ + /** @var ResponseInterface|MockObject $response */ + /** @var callable|MockObject $callable */ + list($request, $response, $callable) = $this->getMocks(); + + $callable->expects($this->once()) + ->method('__invoke') + ->with($request) + ->willReturn($response); + + $middleware = new CallableHandler($callable); + $middleware->handle($request); + } + + /** + * @covers \Engelsystem\Middleware\CallableHandler::execute + */ + public function testExecute() + { + /** @var ServerRequestInterface|MockObject $request */ + /** @var Response|MockObject $response */ + /** @var callable|MockObject $callable */ + list($request, $response, $callable) = $this->getMocks(); + /** @var Container|MockObject $container */ + $container = $this->createMock(Container::class); + + $callable->expects($this->exactly(3)) + ->method('__invoke') + ->with($request) + ->willReturnOnConsecutiveCalls($response, 'Lorem ipsum?', 'I\'m not an exception!'); + + $container->expects($this->once()) + ->method('get') + ->with('response') + ->willReturn($response); + + $response->expects($this->once()) + ->method('withContent') + ->with('Lorem ipsum?') + ->willReturn($response); + + $middleware = new CallableHandler($callable, $container); + $return = $middleware->handle($request); + $this->assertInstanceOf(ResponseInterface::class, $return); + $this->assertEquals($response, $return); + + $return = $middleware->handle($request); + $this->assertInstanceOf(ResponseInterface::class, $return); + $this->assertEquals($response, $return); + + $middleware = new CallableHandler($callable); + $this->expectException(\InvalidArgumentException::class); + $middleware->handle($request); + } + + /** + * @return array + */ + protected function getMocks(): array + { + /** @var ServerRequestInterface|MockObject $request */ + $request = $this->getMockForAbstractClass(ServerRequestInterface::class); + /** @var RequestHandlerInterface|MockObject $handler */ + $handler = $this->getMockForAbstractClass(RequestHandlerInterface::class); + /** @var Response|MockObject $response */ + $response = $this->createMock(Response::class); + /** @var callable|MockObject $callable */ + $callable = $this->getMockBuilder(stdClass::class) + ->setMethods(['__invoke']) + ->getMock(); + return array($request, $response, $callable, $handler); + } +} diff --git a/tests/Unit/Middleware/DispatcherTest.php b/tests/Unit/Middleware/DispatcherTest.php index c01c5029..4e1c51a7 100644 --- a/tests/Unit/Middleware/DispatcherTest.php +++ b/tests/Unit/Middleware/DispatcherTest.php @@ -5,7 +5,6 @@ namespace Engelsystem\Test\Unit\Middleware; use Engelsystem\Application; use Engelsystem\Middleware\Dispatcher; use Engelsystem\Test\Unit\Middleware\Stub\NotARealMiddleware; -use Engelsystem\Test\Unit\Middleware\Stub\ReturnResponseMiddleware; use InvalidArgumentException; use LogicException; use PHPUnit\Framework\TestCase; @@ -158,14 +157,14 @@ class DispatcherTest extends TestCase /** @var Dispatcher|MockObject $dispatcher */ $dispatcher = $this->getMockBuilder(Dispatcher::class) - ->setConstructorArgs([[MiddlewareInterface::class]]) + ->setConstructorArgs([[MiddlewareInterface::class, MiddlewareInterface::class]]) ->setMethods(['resolveMiddleware']) ->getMock(); - $dispatcher->expects($this->once()) + $dispatcher->expects($this->exactly(2)) ->method('resolveMiddleware') ->with(MiddlewareInterface::class) - ->willReturn($middleware); + ->willReturnOnConsecutiveCalls($middleware, null); $middleware->expects($this->once()) ->method('process') @@ -174,57 +173,26 @@ class DispatcherTest extends TestCase $return = $dispatcher->handle($request); $this->assertEquals($response, $return); + + $this->expectException(InvalidArgumentException::class); + $dispatcher->handle($request); } /** - * @covers \Engelsystem\Middleware\Dispatcher::resolveMiddleware * @covers \Engelsystem\Middleware\Dispatcher::setContainer */ - public function testResolveMiddleware() + public function testSetContainer() { /** @var Application|MockObject $container */ $container = $this->createMock(Application::class); - /** @var ServerRequestInterface|MockObject $request */ - $request = $this->createMock(ServerRequestInterface::class); - /** @var ResponseInterface|MockObject $response */ - $response = $this->createMock(ResponseInterface::class); - - $returnResponseMiddleware = new ReturnResponseMiddleware($response); - - $container->expects($this->exactly(2)) - ->method('has') - ->withConsecutive([ReturnResponseMiddleware::class], ['middleware']) - ->willReturnOnConsecutiveCalls(false, true); - - $container->expects($this->once()) - ->method('make') - ->with(ReturnResponseMiddleware::class) - ->willReturn($returnResponseMiddleware); - - $container->expects($this->once()) - ->method('get') - ->with('middleware') - ->willReturn($returnResponseMiddleware); - - $dispatcher = new Dispatcher([ReturnResponseMiddleware::class]); - $dispatcher->setContainer($container); - $dispatcher->handle($request); - $dispatcher = new Dispatcher(['middleware'], $container); - $dispatcher->handle($request); - } + $middleware = new Dispatcher(); + $middleware->setContainer($container); - /** - * @covers \Engelsystem\Middleware\Dispatcher::resolveMiddleware - */ - public function testResolveMiddlewareNoContainer() - { - /** @var ServerRequestInterface|MockObject $request */ - $request = $this->createMock(ServerRequestInterface::class); - - $this->expectException(InvalidArgumentException::class); + $reflection = new Reflection(get_class($middleware)); + $property = $reflection->getProperty('container'); + $property->setAccessible(true); - $dispatcher = new Dispatcher([ReturnResponseMiddleware::class]); - $dispatcher->handle($request); + $this->assertEquals($container, $property->getValue($middleware)); } } diff --git a/tests/Unit/Middleware/LegacyMiddlewareTest.php b/tests/Unit/Middleware/LegacyMiddlewareTest.php index 34e60b60..ed9a5a74 100644 --- a/tests/Unit/Middleware/LegacyMiddlewareTest.php +++ b/tests/Unit/Middleware/LegacyMiddlewareTest.php @@ -46,10 +46,11 @@ class LegacyMiddlewareTest extends TestCase ['title2', 'content2'] ); - $middleware->expects($this->exactly(2)) + $middleware->expects($this->exactly(3)) ->method('renderPage') ->withConsecutive( ['user_worklog', 'title', 'content'], + ['404', 'Page not found'], ['login', 'title2', 'content2'] ) ->willReturn($response); @@ -73,11 +74,6 @@ class LegacyMiddlewareTest extends TestCase '/' ); - $handler->expects($this->once()) - ->method('handle') - ->with($request) - ->willReturn($response); - $middleware->process($request, $handler); $middleware->process($request, $handler); $middleware->process($request, $handler); diff --git a/tests/Unit/Middleware/NotFoundResponseTest.php b/tests/Unit/Middleware/NotFoundResponseTest.php deleted file mode 100644 index 9279e81d..00000000 --- a/tests/Unit/Middleware/NotFoundResponseTest.php +++ /dev/null @@ -1,39 +0,0 @@ -getMockBuilder(NotFoundResponse::class) - ->setMethods(['renderPage']) - ->getMock(); - /** @var ResponseInterface|MockObject $response */ - $response = $this->getMockForAbstractClass(ResponseInterface::class); - /** @var RequestHandlerInterface|MockObject $handler */ - $handler = $this->getMockForAbstractClass(RequestHandlerInterface::class); - /** @var ServerRequestInterface|MockObject $request */ - $request = $this->getMockForAbstractClass(ServerRequestInterface::class); - - $middleware->expects($this->once()) - ->method('renderPage') - ->willReturn($response); - - $handler->expects($this->never()) - ->method('handle'); - - $middleware->process($request, $handler); - } -} diff --git a/tests/Unit/Middleware/RequestHandlerServiceProviderTest.php b/tests/Unit/Middleware/RequestHandlerServiceProviderTest.php new file mode 100644 index 00000000..281016b5 --- /dev/null +++ b/tests/Unit/Middleware/RequestHandlerServiceProviderTest.php @@ -0,0 +1,36 @@ +createMock(RequestHandler::class); + + $app = $this->getApp(['make', 'instance', 'bind']); + + $app->expects($this->once()) + ->method('make') + ->with(RequestHandler::class) + ->willReturn($requestHandler); + $app->expects($this->once()) + ->method('instance') + ->with('request.handler', $requestHandler); + $app->expects($this->once()) + ->method('bind') + ->with(RequestHandler::class, 'request.handler'); + + $serviceProvider = new RequestHandlerServiceProvider($app); + $serviceProvider->register(); + } +} diff --git a/tests/Unit/Middleware/RequestHandlerTest.php b/tests/Unit/Middleware/RequestHandlerTest.php new file mode 100644 index 00000000..896b55c3 --- /dev/null +++ b/tests/Unit/Middleware/RequestHandlerTest.php @@ -0,0 +1,89 @@ +createMock(Application::class); + + $handler = new RequestHandler($container); + + $reflection = new Reflection(get_class($handler)); + $property = $reflection->getProperty('container'); + $property->setAccessible(true); + + $this->assertEquals($container, $property->getValue($handler)); + } + + /** + * @covers \Engelsystem\Middleware\RequestHandler::process + */ + public function testProcess() + { + /** @var Application|MockObject $container */ + $container = $this->createMock(Application::class); + /** @var ServerRequestInterface|MockObject $request */ + $request = $this->getMockForAbstractClass(ServerRequestInterface::class); + /** @var RequestHandlerInterface|MockObject $handler */ + $handler = $this->getMockForAbstractClass(RequestHandlerInterface::class); + /** @var ResponseInterface|MockObject $response */ + $response = $this->getMockForAbstractClass(ResponseInterface::class); + + $middlewareInterface = $this->getMockForAbstractClass(MiddlewareInterface::class); + $requestHandlerInterface = $this->getMockForAbstractClass(RequestHandlerInterface::class); + + $request->expects($this->exactly(3)) + ->method('getAttribute') + ->with('route-request-handler') + ->willReturn('FooBarClass'); + + /** @var RequestHandler|MockObject $middleware */ + $middleware = $this->getMockBuilder(RequestHandler::class) + ->setConstructorArgs([$container]) + ->setMethods(['resolveMiddleware']) + ->getMock(); + $middleware->expects($this->exactly(3)) + ->method('resolveMiddleware') + ->with('FooBarClass') + ->willReturnOnConsecutiveCalls( + $middlewareInterface, + $requestHandlerInterface, + null + ); + + $middlewareInterface->expects($this->once()) + ->method('process') + ->with($request, $handler) + ->willReturn($response); + $requestHandlerInterface->expects($this->once()) + ->method('handle') + ->with($request) + ->willReturn($response); + + $return = $middleware->process($request, $handler); + $this->assertEquals($return, $response); + + $middleware->process($request, $handler); + $this->assertEquals($return, $response); + + $this->expectException(InvalidArgumentException::class); + $middleware->process($request, $handler); + } +} diff --git a/tests/Unit/Middleware/ResolvesMiddlewareTraitTest.php b/tests/Unit/Middleware/ResolvesMiddlewareTraitTest.php new file mode 100644 index 00000000..320a6d6b --- /dev/null +++ b/tests/Unit/Middleware/ResolvesMiddlewareTraitTest.php @@ -0,0 +1,67 @@ +createMock(Application::class); + $middlewareInterface = $this->getMockForAbstractClass(MiddlewareInterface::class); + $callable = [HasStaticMethod::class, 'foo']; + + $container->expects($this->exactly(3)) + ->method('make') + ->withConsecutive( + ['FooBarClass'], + [CallableHandler::class, ['callable' => $callable]], + ['UnresolvableClass'] + ) + ->willReturnOnConsecutiveCalls( + $middlewareInterface, + $middlewareInterface, + null + ); + + $middleware = new ResolvesMiddlewareTraitImplementation($container); + + $return = $middleware->callResolveMiddleware('FooBarClass'); + $this->assertEquals($middlewareInterface, $return); + + $return = $middleware->callResolveMiddleware($callable); + $this->assertEquals($middlewareInterface, $return); + + $this->expectException(InvalidArgumentException::class); + $middleware->callResolveMiddleware('UnresolvableClass'); + } + + /** + * @covers \Engelsystem\Middleware\ResolvesMiddlewareTrait::resolveMiddleware + */ + public function testResolveMiddlewareNoContainer() + { + $middlewareInterface = $this->getMockForAbstractClass(MiddlewareInterface::class); + + $middleware = new ResolvesMiddlewareTraitImplementation(); + $return = $middleware->callResolveMiddleware($middlewareInterface); + + $this->assertEquals($middlewareInterface, $return); + + $this->expectException(InvalidArgumentException::class); + $middleware->callResolveMiddleware('FooBarClass'); + } +} diff --git a/tests/Unit/Middleware/RouteDispatcherServiceProviderTest.php b/tests/Unit/Middleware/RouteDispatcherServiceProviderTest.php new file mode 100644 index 00000000..ca784c73 --- /dev/null +++ b/tests/Unit/Middleware/RouteDispatcherServiceProviderTest.php @@ -0,0 +1,65 @@ +createMock(ContextualBindingBuilder::class); + $routeDispatcher = $this->getMockForAbstractClass(FastRouteDispatcher::class); + + $app = $this->getApp(['alias', 'when']); + + $app->expects($this->once()) + ->method('alias') + ->with(RouteDispatcher::class, 'route.dispatcher'); + + $app->expects($this->exactly(2)) + ->method('when') + ->with(RouteDispatcher::class) + ->willReturn($bindingBuilder); + + $bindingBuilder->expects($this->exactly(2)) + ->method('needs') + ->withConsecutive( + [FastRouteDispatcher::class], + [MiddlewareInterface::class] + ) + ->willReturn($bindingBuilder); + + $bindingBuilder->expects($this->exactly(2)) + ->method('give') + ->with($this->callback(function ($subject) { + if (is_callable($subject)) { + $subject(); + } + + return is_callable($subject) || $subject == LegacyMiddleware::class; + })); + + /** @var RouteDispatcherServiceProvider|MockObject $serviceProvider */ + $serviceProvider = $this->getMockBuilder(RouteDispatcherServiceProvider::class) + ->setConstructorArgs([$app]) + ->setMethods(['generateRouting']) + ->getMock(); + + $serviceProvider->expects($this->once()) + ->method('generateRouting') + ->willReturn($routeDispatcher); + + $serviceProvider->register(); + } +} diff --git a/tests/Unit/Middleware/RouteDispatcherTest.php b/tests/Unit/Middleware/RouteDispatcherTest.php new file mode 100644 index 00000000..edb2f158 --- /dev/null +++ b/tests/Unit/Middleware/RouteDispatcherTest.php @@ -0,0 +1,148 @@ +getMocks(); + + $dispatcher->expects($this->once()) + ->method('dispatch') + ->with('HEAD', '/foo!bar') + ->willReturn([FastRouteDispatcher::FOUND, $handler, ['foo' => 'bar', 'lorem' => 'ipsum']]); + + $request->expects($this->exactly(3)) + ->method('withAttribute') + ->withConsecutive( + ['route-request-handler', $handler], + ['foo', 'bar'], + ['lorem', 'ipsum'] + ) + ->willReturn($request); + + $handler->expects($this->once()) + ->method('handle') + ->with($request) + ->willReturn($response); + + $middleware = new RouteDispatcher($dispatcher, $response); + $return = $middleware->process($request, $handler); + $this->assertEquals($response, $return); + } + + /** + * @covers \Engelsystem\Middleware\RouteDispatcher::process + */ + public function testProcessNotFound() + { + /** @var FastRouteDispatcher|MockObject $dispatcher */ + /** @var ResponseInterface|MockObject $response */ + /** @var ServerRequestInterface|MockObject $request */ + /** @var RequestHandlerInterface|MockObject $handler */ + list($dispatcher, $response, $request, $handler) = $this->getMocks(); + /** @var MiddlewareInterface|MockObject $notFound */ + $notFound = $this->createMock(MiddlewareInterface::class); + + $dispatcher->expects($this->exactly(2)) + ->method('dispatch') + ->with('HEAD', '/foo!bar') + ->willReturn([FastRouteDispatcher::NOT_FOUND]); + + $response->expects($this->once()) + ->method('withStatus') + ->with(404) + ->willReturn($response); + + $notFound->expects($this->once()) + ->method('process') + ->with($request, $handler) + ->willReturn($response); + + $middleware = new RouteDispatcher($dispatcher, $response, $notFound); + $return = $middleware->process($request, $handler); + $this->assertEquals($response, $return); + + $middleware = new RouteDispatcher($dispatcher, $response); + $return = $middleware->process($request, $handler); + $this->assertEquals($response, $return); + } + + /** + * @covers \Engelsystem\Middleware\RouteDispatcher::process + */ + public function testProcessNotAllowed() + { + /** @var FastRouteDispatcher|MockObject $dispatcher */ + /** @var ResponseInterface|MockObject $response */ + /** @var ServerRequestInterface|MockObject $request */ + /** @var RequestHandlerInterface|MockObject $handler */ + list($dispatcher, $response, $request, $handler) = $this->getMocks(); + + $dispatcher->expects($this->once()) + ->method('dispatch') + ->with('HEAD', '/foo!bar') + ->willReturn([FastRouteDispatcher::METHOD_NOT_ALLOWED, ['POST', 'TEST']]); + + $response->expects($this->once()) + ->method('withStatus') + ->with(405) + ->willReturn($response); + $response->expects($this->once()) + ->method('withHeader') + ->with('Allow', 'POST, TEST') + ->willReturn($response); + + $middleware = new RouteDispatcher($dispatcher, $response); + $return = $middleware->process($request, $handler); + $this->assertEquals($response, $return); + } + + /** + * @return array + */ + protected function getMocks(): array + { + /** @var FastRouteDispatcher|MockObject $dispatcher */ + $dispatcher = $this->getMockForAbstractClass(FastRouteDispatcher::class); + /** @var ResponseInterface|MockObject $response */ + $response = $this->getMockForAbstractClass(ResponseInterface::class); + /** @var ServerRequestInterface|MockObject $request */ + $request = $this->getMockForAbstractClass(ServerRequestInterface::class); + /** @var RequestHandlerInterface|MockObject $handler */ + $handler = $this->getMockForAbstractClass(RequestHandlerInterface::class); + /** @var UriInterface|MockObject $uriInterface */ + $uriInterface = $this->getMockForAbstractClass(UriInterface::class); + + $request->expects($this->atLeastOnce()) + ->method('getMethod') + ->willReturn('HEAD'); + $request->expects($this->atLeastOnce()) + ->method('getUri') + ->willReturn($uriInterface); + $uriInterface->expects($this->atLeastOnce()) + ->method('getPath') + ->willReturn('/foo%21bar'); + + return array($dispatcher, $response, $request, $handler); + } +} diff --git a/tests/Unit/Middleware/Stub/HasStaticMethod.php b/tests/Unit/Middleware/Stub/HasStaticMethod.php new file mode 100644 index 00000000..5ca2670e --- /dev/null +++ b/tests/Unit/Middleware/Stub/HasStaticMethod.php @@ -0,0 +1,8 @@ +container = $container; + } + + /** + * @param string|callable|MiddlewareInterface|RequestHandlerInterface $middleware + * @return MiddlewareInterface|RequestHandlerInterface + * @throws InvalidArgumentException + */ + public function callResolveMiddleware($middleware) + { + return $this->resolveMiddleware($middleware); + } +} -- cgit v1.2.3-54-g00ecf