/* Decoded by unphp.net */ prophesize(ResponseFactoryInterface::class); $containerProphecy = $this->prophesize(ContainerInterface::class); $app = new App($responseFactoryProphecy->reveal(), $containerProphecy->reveal()); $containerProphecy->has(Argument::type("string"))->shouldNotHaveBeenCalled(); $containerProphecy->get(Argument::type("string"))->shouldNotHaveBeenCalled(); } public function testGetContainer() : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $containerProphecy = $this->prophesize(ContainerInterface::class); $app = new App($responseFactoryProphecy->reveal(), $containerProphecy->reveal()); $this->assertSame($containerProphecy->reveal(), $app->getContainer()); } public function testGetCallableResolverReturnsInjectedInstance() : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $callableResolverProphecy = $this->prophesize(CallableResolverInterface::class); $app = new App($responseFactoryProphecy->reveal(), null, $callableResolverProphecy->reveal()); $this->assertSame($callableResolverProphecy->reveal(), $app->getCallableResolver()); } public function testCreatesCallableResolverWhenNull() : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $containerProphecy = $this->prophesize(ContainerInterface::class); $callableResolver = new CallableResolver($containerProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal(), $containerProphecy->reveal(), null); $this->assertEquals($callableResolver, $app->getCallableResolver()); } public function testGetRouteCollectorReturnsInjectedInstance() : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $routeCollectorProphecy = $this->prophesize(RouteCollectorInterface::class); $routeParserProphecy = $this->prophesize(RouteParserInterface::class); $routeCollectorProphecy->getRouteParser()->willReturn($routeParserProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal(), null, null, $routeCollectorProphecy->reveal()); $this->assertSame($routeCollectorProphecy->reveal(), $app->getRouteCollector()); } public function testCreatesRouteCollectorWhenNullWithInjectedContainer() : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $containerProphecy = $this->prophesize(ContainerInterface::class); $callableResolverProphecy = $this->prophesize(CallableResolverInterface::class); $routeCollector = new RouteCollector($responseFactoryProphecy->reveal(), $callableResolverProphecy->reveal(), $containerProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal(), $containerProphecy->reveal(), $callableResolverProphecy->reveal()); $this->assertEquals($routeCollector, $app->getRouteCollector()); } public function testGetMiddlewareDispatcherGetsSeededAndReturnsInjectedInstance() : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $middlewareDispatcherProphecy = $this->prophesize(MiddlewareDispatcherInterface::class); $middlewareDispatcherProphecy->seedMiddlewareStack(Argument::any())->shouldBeCalledOnce(); $app = new App($responseFactoryProphecy->reveal(), null, null, null, null, $middlewareDispatcherProphecy->reveal()); $this->assertSame($middlewareDispatcherProphecy->reveal(), $app->getMiddlewareDispatcher()); } public function lowerCaseRequestMethodsProvider() : array { return array(array("get"), array("post"), array("put"), array("patch"), array("delete"), array("options")); } public function testGetPostPutPatchDeleteOptionsMethods(string $method) : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn($method); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $methodName = strtolower($method); $app = new App($responseFactoryProphecy->reveal()); $app->{$methodName}("/", function (ServerRequestInterface $request, ResponseInterface $response) { return $response; }); $response = $app->handle($requestProphecy->reveal()); $this->assertSame("Hello World", (string) $response->getBody()); } public function testAnyRoute() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->any("/", function (ServerRequestInterface $request, ResponseInterface $response) { return $response; }); foreach ($this->upperCaseRequestMethodsProvider() as $methods) { $method = $methods[0]; $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn($method); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertSame("Hello World", (string) $response->getBody()); } } public function upperCaseRequestMethodsProvider() : array { return array(array("GET"), array("POST"), array("PUT"), array("PATCH"), array("DELETE"), array("OPTIONS")); } public function testMapRoute(string $method) : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn($method); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $app = new App($responseFactoryProphecy->reveal()); $app->map(array($method), "/", function (ServerRequestInterface $request, ResponseInterface $response) { return $response; }); $response = $app->handle($requestProphecy->reveal()); $this->assertSame("Hello World", (string) $response->getBody()); } public function testRedirectRoute() : void { $from = "/from"; $to = "/to"; $routeCreatedResponse = $this->prophesize(ResponseInterface::class); $handlerCreatedResponse = $this->prophesize(ResponseInterface::class); $handlerCreatedResponse->getStatusCode()->willReturn(301); $handlerCreatedResponse->getHeaderLine("Location")->willReturn($to); $handlerCreatedResponse->withHeader(Argument::type("string"), Argument::type("string"))->will(function ($args) { $this->getHeader($args[0])->willReturn($args[1]); return $this; }); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($routeCreatedResponse->reveal()); $responseFactoryProphecy->createResponse(301)->willReturn($handlerCreatedResponse->reveal()); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn($from); $uriProphecy->__toString()->willReturn($to); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $app = new App($responseFactoryProphecy->reveal()); $app->redirect($from, $to, 301); $response = $app->handle($requestProphecy->reveal()); $responseFactoryProphecy->createResponse(301)->shouldHaveBeenCalled(); $this->assertSame(301, $response->getStatusCode()); $this->assertSame($to, $response->getHeaderLine("Location")); } public function testRouteWithInternationalCharacters() : void { $path = "/\xd0\xbd\320\276\xd0\xb2\xd0\xbe\xd1\x81\321\202\320\270"; $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get($path, function () use($responseProphecy) { return $responseProphecy->reveal(); }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn($path); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function routePatternsProvider() : array { return array(array(''), array("/"), array("foo"), array("/foo"), array("/foo/")); } public function testRoutePatterns(string $pattern) : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $app = new App($responseFactoryProphecy->reveal()); $app->get($pattern, function () { }); $routeCollector = $app->getRouteCollector(); $route = $routeCollector->lookupRoute("route0"); $this->assertSame($pattern, $route->getPattern()); } public function routeGroupsDataProvider() : array { return array("empty group with empty route" => array(array('', ''), ''), "empty group with single slash route" => array(array('', "/"), "/"), "empty group with segment route that does not end in aSlash" => array(array('', "/foo"), "/foo"), "empty group with segment route that ends in aSlash" => array(array('', "/foo/"), "/foo/"), "group single slash with empty route" => array(array("/", ''), "/"), "group single slash with single slash route" => array(array("/", "/"), "//"), "group single slash with segment route that does not end in aSlash" => array(array("/", "/foo"), "//foo"), "group single slash with segment route that ends in aSlash" => array(array("/", "/foo/"), "//foo/"), "group segment with empty route" => array(array("/foo", ''), "/foo"), "group segment with single slash route" => array(array("/foo", "/"), "/foo/"), "group segment with segment route that does not end in aSlash" => array(array("/foo", "/bar"), "/foo/bar"), "group segment with segment route that ends in aSlash" => array(array("/foo", "/bar/"), "/foo/bar/"), "empty group with nested group segment with an empty route" => array(array('', "/foo", ''), "/foo"), "empty group with nested group segment with single slash route" => array(array('', "/foo", "/"), "/foo/"), "group single slash with empty nested group and segment route without leading slash" => array(array("/", '', "foo"), "/foo"), "group single slash with empty nested group and segment route" => array(array("/", '', "/foo"), "//foo"), "group single slash with single slash group and segment route without leading slash" => array(array("/", "/", "foo"), "//foo"), "group single slash with single slash nested group and segment route" => array(array("/", "/", "/foo"), "///foo"), "group single slash with nested group segment with an empty route" => array(array("/", "/foo", ''), "//foo"), "group single slash with nested group segment with single slash route" => array(array("/", "/foo", "/"), "//foo/"), "group single slash with nested group segment with segment route" => array(array("/", "/foo", "/bar"), "//foo/bar"), "group single slash with nested group segment with segment route that has aTrailing slash" => array(array("/", "/foo", "/bar/"), "//foo/bar/"), "empty group with empty nested group and segment route without leading slash" => array(array('', '', "foo"), "foo"), "empty group with empty nested group and segment route" => array(array('', '', "/foo"), "/foo"), "empty group with single slash group and segment route without leading slash" => array(array('', "/", "foo"), "/foo"), "empty group with single slash nested group and segment route" => array(array('', "/", "/foo"), "//foo"), "empty group with nested group segment with segment route" => array(array('', "/foo", "/bar"), "/foo/bar"), "empty group with nested group segment with segment route that has aTrailing slash" => array(array('', "/foo", "/bar/"), "/foo/bar/"), "group segment with empty nested group and segment route without leading slash" => array(array("/foo", '', "bar"), "/foobar"), "group segment with empty nested group and segment route" => array(array("/foo", '', "/bar"), "/foo/bar"), "group segment with single slash nested group and segment route" => array(array("/foo", "/", "bar"), "/foo/bar"), "group segment with single slash nested group and slash segment route" => array(array("/foo", "/", "/bar"), "/foo//bar"), "two group segments with empty route" => array(array("/foo", "/bar", ''), "/foo/bar"), "two group segments with single slash route" => array(array("/foo", "/bar", "/"), "/foo/bar/"), "two group segments with segment route" => array(array("/foo", "/bar", "/baz"), "/foo/bar/baz"), "two group segments with segment route that has aTrailing slash" => array(array("/foo", "/bar", "/baz/"), "/foo/bar/baz/")); } public function testGroupClosureIsBoundToThisClass() : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $app = new App($responseFactoryProphecy->reveal()); $testCase = $this; $app->group("/foo", function () use($testCase) { $testCase->assertSame($testCase, $this); }); } public function testRouteGroupCombinations(array $sequence, string $expectedPath) : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $app = new App($responseFactoryProphecy->reveal()); $processSequence = function (RouteCollectorProxy $app, array $sequence, $processSequence) { $path = array_shift($sequence); if (count($sequence)) { $app->group($path, function (RouteCollectorProxy $group) use(&$sequence, $processSequence) { $processSequence($group, $sequence, $processSequence); }); } else { $app->get($path, function () { }); } }; $processSequence($app, $sequence, $processSequence); $routeCollector = $app->getRouteCollector(); $route = $routeCollector->lookupRoute("route0"); $this->assertSame($expectedPath, $route->getPattern()); } public function testRouteGroupPattern() : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryInterface = $responseFactoryProphecy->reveal(); $app = new App($responseFactoryInterface); $group = $app->group("/foo", function () { }); $this->assertSame("/foo", $group->getPattern()); } public function testAddMiddleware() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $middlewareProphecy = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy->process(Argument::cetera())->will(function () use($responseProphecy) { return $responseProphecy->reveal(); }); $middlewareProphecy2 = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy2->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->will(function ($args) { $request = $args[0]; $handler = $args[1]; return $handler->handle($request); }); $app->add($middlewareProphecy->reveal()); $app->addMiddleware($middlewareProphecy2->reveal()); $app->get("/", function (ServerRequestInterface $request, $response) { return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $middlewareProphecy->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->shouldHaveBeenCalled(); $middlewareProphecy2->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->shouldHaveBeenCalled(); $this->assertSame($responseProphecy->reveal(), $response); } public function testAddMiddlewareUsingDeferredResolution() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $middlewareProphecy = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy->process(Argument::cetera())->willReturn($responseProphecy->reveal()); $containerProphecy = $this->prophesize(ContainerInterface::class); $containerProphecy->has("middleware")->willReturn(true); $containerProphecy->get("middleware")->willReturn($middlewareProphecy); $app = new App($responseFactoryProphecy->reveal(), $containerProphecy->reveal()); $app->add("middleware"); $app->get("/", function (ServerRequestInterface $request, ResponseInterface $response) { return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $response = $app->handle($requestProphecy->reveal()); $this->assertSame("Hello World", (string) $response->getBody()); } public function testAddRoutingMiddleware() : void { $responseFactory = $this->prophesize(ResponseFactoryInterface::class)->reveal(); $app = new App($responseFactory); $routingMiddleware = $app->addRoutingMiddleware(); $middlewareDispatcherProperty = new ReflectionProperty(App::class, "middlewareDispatcher"); $middlewareDispatcherProperty->setAccessible(true); $middlewareDispatcher = $middlewareDispatcherProperty->getValue($app); $tipProperty = new ReflectionProperty(MiddlewareDispatcher::class, "tip"); $tipProperty->setAccessible(true); $tip = $tipProperty->getValue($middlewareDispatcher); $reflection = new ReflectionClass($tip); $middlewareProperty = $reflection->getProperty("middleware"); $middlewareProperty->setAccessible(true); $this->assertSame($routingMiddleware, $middlewareProperty->getValue($tip)); $this->assertInstanceOf(RoutingMiddleware::class, $routingMiddleware); } public function testAddErrorMiddleware() : void { $responseFactory = $this->prophesize(ResponseFactoryInterface::class)->reveal(); $logger = $this->prophesize(LoggerInterface::class)->reveal(); $app = new App($responseFactory); $errorMiddleware = $app->addErrorMiddleware(true, true, true, $logger); $middlewareDispatcherProperty = new ReflectionProperty(App::class, "middlewareDispatcher"); $middlewareDispatcherProperty->setAccessible(true); $middlewareDispatcher = $middlewareDispatcherProperty->getValue($app); $tipProperty = new ReflectionProperty(MiddlewareDispatcher::class, "tip"); $tipProperty->setAccessible(true); $tip = $tipProperty->getValue($middlewareDispatcher); $reflection = new ReflectionClass($tip); $middlewareProperty = $reflection->getProperty("middleware"); $middlewareProperty->setAccessible(true); $this->assertSame($errorMiddleware, $middlewareProperty->getValue($tip)); $this->assertInstanceOf(ErrorMiddleware::class, $errorMiddleware); } public function testAddBodyParsingMiddleware() : void { $responseFactory = $this->prophesize(ResponseFactoryInterface::class)->reveal(); $app = new App($responseFactory); $bodyParsingMiddleware = $app->addBodyParsingMiddleware(); $middlewareDispatcherProperty = new ReflectionProperty(App::class, "middlewareDispatcher"); $middlewareDispatcherProperty->setAccessible(true); $middlewareDispatcher = $middlewareDispatcherProperty->getValue($app); $tipProperty = new ReflectionProperty(MiddlewareDispatcher::class, "tip"); $tipProperty->setAccessible(true); $tip = $tipProperty->getValue($middlewareDispatcher); $reflection = new ReflectionClass($tip); $middlewareProperty = $reflection->getProperty("middleware"); $middlewareProperty->setAccessible(true); $this->assertSame($bodyParsingMiddleware, $middlewareProperty->getValue($tip)); $this->assertInstanceOf(BodyParsingMiddleware::class, $bodyParsingMiddleware); } public function testAddMiddlewareOnRoute() : void { $output = ''; $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $middlewareProphecy = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->will(function ($args) use(&$output) { $request = $args[0]; $handler = $args[1]; $output .= "In1"; $response = $handler->handle($request); $output .= "Out1"; return $response; }); $middlewareProphecy2 = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy2->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->will(function ($args) use(&$output) { $request = $args[0]; $handler = $args[1]; $output .= "In2"; $response = $handler->handle($request); $output .= "Out2"; return $response; }); $app = new App($responseFactoryProphecy->reveal()); $app->get("/", function (ServerRequestInterface $request, ResponseInterface $response) use(&$output) { $output .= "Center"; return $response; })->add($middlewareProphecy->reveal())->addMiddleware($middlewareProphecy2->reveal()); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $app->handle($requestProphecy->reveal()); $this->assertSame("In2In1CenterOut1Out2", $output); } public function testAddMiddlewareOnRouteGroup() : void { $output = ''; $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $middlewareProphecy = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->will(function ($args) use(&$output) { $request = $args[0]; $handler = $args[1]; $output .= "In1"; $response = $handler->handle($request); $output .= "Out1"; return $response; }); $middlewareProphecy2 = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy2->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->will(function ($args) use(&$output) { $request = $args[0]; $handler = $args[1]; $output .= "In2"; $response = $handler->handle($request); $output .= "Out2"; return $response; }); $app = new App($responseFactoryProphecy->reveal()); $app->group("/foo", function (RouteCollectorProxy $proxy) use(&$output) { $proxy->get("/bar", function (ServerRequestInterface $request, ResponseInterface $response) use(&$output) { $output .= "Center"; return $response; }); })->add($middlewareProphecy->reveal())->addMiddleware($middlewareProphecy2->reveal()); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/foo/bar"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $app->handle($requestProphecy->reveal()); $this->assertSame("In2In1CenterOut1Out2", $output); } public function testAddMiddlewareOnTwoRouteGroup() : void { $output = ''; $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $middlewareProphecy = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->will(function ($args) use(&$output) { $request = $args[0]; $handler = $args[1]; $output .= "In1"; $response = $handler->handle($request); $output .= "Out1"; return $response; }); $middlewareProphecy2 = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy2->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->will(function ($args) use(&$output) { $request = $args[0]; $handler = $args[1]; $output .= "In2"; $response = $handler->handle($request); $output .= "Out2"; return $response; }); $middlewareProphecy3 = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy3->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->will(function ($args) use(&$output) { $request = $args[0]; $handler = $args[1]; $output .= "In3"; $response = $handler->handle($request); $output .= "Out3"; return $response; }); $app = new App($responseFactoryProphecy->reveal()); $app->group("/foo", function (RouteCollectorProxyInterface $group) use($middlewareProphecy2, $middlewareProphecy3, &$output) { $group->group("/fizz", function (RouteCollectorProxyInterface $group) { $group->get("/buzz", function (ServerRequestInterface $request, ResponseInterface $response) { return $response; }); }); $group->group("/bar", function (RouteCollectorProxyInterface $group) use($middlewareProphecy3, &$output) { $group->get("/baz", function (ServerRequestInterface $request, ResponseInterface $response) use(&$output) { $output .= "Center"; return $response; })->add($middlewareProphecy3->reveal()); })->add($middlewareProphecy2->reveal()); })->add($middlewareProphecy->reveal()); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/foo/bar/baz"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $app->handle($requestProphecy->reveal()); $this->assertSame("In1In2In3CenterOut3Out2Out1", $output); } public function testAddMiddlewareAsStringNotImplementingInterfaceThrowsException() : void { $this->expectException(RuntimeException::class); $this->expectExceptionMessage("A middleware must be an object/class name referencing an implementation of " . "MiddlewareInterface or a callable with a matching signature."); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $app = new App($responseFactoryProphecy->reveal()); $app->add(new stdClass()); } public function testInvokeReturnMethodNotAllowed() : void { $this->expectException(HttpMethodNotAllowedException::class); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $app = new App($responseFactoryProphecy->reveal()); $app->get("/", function () { }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("POST"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $app->handle($requestProphecy->reveal()); } public function testInvokeWithMatchingRoute() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get("/", function (ServerRequestInterface $request, $response) { return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testInvokeWithMatchingRouteWithSetArgument() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get("/", function (ServerRequestInterface $request, ResponseInterface $response, $args) { $response->getBody()->write("Hello {$args["name"]}"); return $response; })->setArgument("name", "World"); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testInvokeWithMatchingRouteWithSetArguments() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get("/", function (ServerRequestInterface $request, ResponseInterface $response, $args) { $response->getBody()->write("{$args["greeting"]} {$args["name"]}"); return $response; })->setArguments(array("greeting" => "Hello", "name" => "World")); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testInvokeWithMatchingRouteWithNamedParameterRequestResponseStrategy() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get("/Hello/{name}", function (ServerRequestInterface $request, ResponseInterface $response, $args) { $response->getBody()->write("Hello {$args["name"]}"); return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/Hello/World"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testInvokeWithMatchingRouteWithNamedParameterRequestResponseArgStrategy() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->getRouteCollector()->setDefaultInvocationStrategy(new RequestResponseArgs()); $app->get("/Hello/{name}", function (ServerRequestInterface $request, ResponseInterface $response, $name) { $response->getBody()->write("Hello {$name}"); return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/Hello/World"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testInvokeWithMatchingRouteWithNamedParameterRequestResponseNamedArgsStrategy() : void { if (PHP_VERSION_ID < 80000) { $this->markTestSkipped("Named arguments are not supported in PHP versions prior to 8.0"); } $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->getRouteCollector()->setDefaultInvocationStrategy(new RequestResponseNamedArgs()); $app->get("/{greeting}/{name}", function (ServerRequestInterface $request, ResponseInterface $response, $name, $greeting) { $response->getBody()->write("{$greeting} {$name}"); return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/Hello/World"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testInvokeWithMatchingRouteWithNamedParameterOverwritesSetArgument() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get("/Hello/{name}", function (ServerRequestInterface $request, ResponseInterface $response, $args) { $response->getBody()->write("Hello {$args["name"]}"); return $response; })->setArgument("name", "World!"); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/Hello/World"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testInvokeWithoutMatchingRoute() : void { $this->expectException(HttpNotFoundException::class); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $app = new App($responseFactoryProphecy->reveal()); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $app->handle($requestProphecy->reveal()); } public function testInvokeWithCallableRegisteredInContainer() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $handler = new class { public function foo(ServerRequestInterface $request, ResponseInterface $response) { return $response; } }; $containerProphecy = $this->prophesize(ContainerInterface::class); $containerProphecy->has("handler")->willReturn(true); $containerProphecy->get("handler")->willReturn($handler); $app = new App($responseFactoryProphecy->reveal(), $containerProphecy->reveal()); $app->get("/", "handler:foo"); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testInvokeWithNonExistentMethodOnCallableRegisteredInContainer() : void { $this->expectException(RuntimeException::class); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $handler = new class { }; $containerProphecy = $this->prophesize(ContainerInterface::class); $containerProphecy->has("handler")->willReturn(true); $containerProphecy->get("handler")->willReturn($handler); $app = new App($responseFactoryProphecy->reveal(), $containerProphecy->reveal()); $app->get("/", "handler:method_does_not_exist"); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $app->handle($requestProphecy->reveal()); } public function testInvokeWithCallableInContainerViaCallMagicMethod() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $mockAction = new MockAction(); $containerProphecy = $this->prophesize(ContainerInterface::class); $containerProphecy->has("handler")->willReturn(true); $containerProphecy->get("handler")->willReturn($mockAction); $app = new App($responseFactoryProphecy->reveal(), $containerProphecy->reveal()); $app->get("/", "handler:foo"); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $expectedPayload = json_encode(array("name" => "foo", "arguments" => array())); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame($expectedPayload, (string) $response->getBody()); } public function testInvokeFunctionName() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); function handle($request, ResponseInterface $response) { $response->getBody()->write("Hello World"); return $response; } $app = new App($responseFactoryProphecy->reveal()); $app->get("/", __NAMESPACE__ . "\handle"); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testCurrentRequestAttributesAreNotLostWhenAddingRouteArguments() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get("/Hello/{name}", function (ServerRequestInterface $request, ResponseInterface $response, $args) { $response->getBody()->write($request->getAttribute("greeting") . " " . $args["name"]); return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/Hello/World"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()->withAttribute("greeting", "Hello")); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testCurrentRequestAttributesAreNotLostWhenAddingRouteArgumentsRequestResponseArg() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->getRouteCollector()->setDefaultInvocationStrategy(new RequestResponseArgs()); $app->get("/Hello/{name}", function (ServerRequestInterface $request, ResponseInterface $response, $name) { $response->getBody()->write($request->getAttribute("greeting") . " " . $name); return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/Hello/World"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()->withAttribute("greeting", "Hello")); $this->assertInstanceOf(ResponseInterface::class, $response); $this->assertSame("Hello World", (string) $response->getBody()); } public function testRun() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $streamProphecy->read(1)->willReturn("_"); $streamProphecy->read("11")->will(function () { $this->eof()->willReturn(true); return $this->reveal()->__toString(); }); $streamProphecy->eof()->willReturn(false); $streamProphecy->isSeekable()->willReturn(true); $streamProphecy->rewind()->willReturn(true); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseProphecy->getStatusCode()->willReturn(200); $responseProphecy->getHeaders()->willReturn(array("Content-Length" => array("11"))); $responseProphecy->getProtocolVersion()->willReturn("1.1"); $responseProphecy->getReasonPhrase()->willReturn(''); $responseProphecy->getHeaderLine("Content-Length")->willReturn("11"); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get("/", function (ServerRequestInterface $request, ResponseInterface $response) { $response->getBody()->write("Hello World"); return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $app->run($requestProphecy->reveal()); $this->expectOutputString("Hello World"); } public function testRunWithoutPassingInServerRequest() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $streamProphecy->read(1)->willReturn("_"); $streamProphecy->read("11")->will(function () { $this->eof()->willReturn(true); return $this->reveal()->__toString(); }); $streamProphecy->eof()->willReturn(false); $streamProphecy->isSeekable()->willReturn(true); $streamProphecy->rewind()->willReturn(true); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseProphecy->getStatusCode()->willReturn(200); $responseProphecy->getHeaders()->willReturn(array("Content-Length" => array("11"))); $responseProphecy->getProtocolVersion()->willReturn("1.1"); $responseProphecy->getReasonPhrase()->willReturn(''); $responseProphecy->getHeaderLine("Content-Length")->willReturn("11"); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get("/", function (ServerRequestInterface $request, ResponseInterface $response) { $response->getBody()->write("Hello World"); return $response; }); $app->run(); $this->expectOutputString("Hello World"); } public function testHandleReturnsEmptyResponseBodyWithHeadRequestMethod() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseProphecy->withBody(Argument::type(StreamInterface::class))->will(function ($args) { $this->getBody()->willReturn($args[0]); return $this; }); $emptyStreamProphecy = $this->prophesize(StreamInterface::class); $emptyStreamProphecy->__toString()->willReturn(''); $emptyResponseProphecy = $this->prophesize(ResponseInterface::class); $emptyResponseProphecy->getBody()->willReturn($emptyStreamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal(), $emptyResponseProphecy->reveal()); $called = 0; $app = new App($responseFactoryProphecy->reveal()); $app->get("/", function (ServerRequestInterface $request, ResponseInterface $response) use(&$called) { $called++; $response->getBody()->write("Hello World"); return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("HEAD"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertSame(1, $called); $this->assertEmpty((string) $response->getBody()); } public function testCanBeReExecutedRecursivelyDuringDispatch() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseHeaders = array(); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseProphecy->getStatusCode()->willReturn(200); $responseProphecy->getHeader(Argument::type("string"))->will(function ($args) use(&$responseHeaders) { return $responseHeaders[$args[0]]; }); $responseProphecy->withAddedHeader(Argument::type("string"), Argument::type("string"))->will(function ($args) use(&$responseHeaders) { $key = $args[0]; $value = $args[1]; if (!isset($responseHeaders[$key])) { $responseHeaders[$key] = array(); } $responseHeaders[$key][] = $value; return $this; }); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse(Argument::type("integer"))->will(function ($args) use($responseProphecy) { $responseProphecy->getStatusCode()->willReturn($args[0]); return $responseProphecy->reveal(); }); $app = new App($responseFactoryProphecy->reveal()); $middlewareProphecy = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->will(function ($args) use($app, $responseFactoryProphecy) { $request = $args[0]; if ($request->hasHeader("X-NESTED")) { return $responseFactoryProphecy->reveal()->createResponse(204)->withAddedHeader("X-TRACE", "nested"); } $response = $app->handle($request->withAddedHeader("X-NESTED", "1")); return $response->withAddedHeader("X-TRACE", "outer"); }); $middlewareProphecy2 = $this->prophesize(MiddlewareInterface::class); $middlewareProphecy2->process(Argument::type(ServerRequestInterface::class), Argument::type(RequestHandlerInterface::class))->will(function ($args) { $request = $args[0]; $handler = $args[1]; $response = $handler->handle($request); $response->getBody()->write("1"); return $response; }); $app->add($middlewareProphecy->reveal())->add($middlewareProphecy2->reveal()); $app->get("/", function (ServerRequestInterface $request, ResponseInterface $response) { return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $responseHeaders = array(); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->hasHeader(Argument::type("string"))->will(function ($args) use(&$responseHeaders) { return array_key_exists($args[0], $responseHeaders); }); $requestProphecy->withAddedHeader(Argument::type("string"), Argument::type("string"))->will(function ($args) use(&$responseHeaders) { $key = $args[0]; $value = $args[1]; if (!isset($responseHeaders[$key])) { $responseHeaders[$key] = array(); } $responseHeaders[$key][] = $value; return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertSame(204, $response->getStatusCode()); $this->assertSame(array("nested", "outer"), $response->getHeader("X-TRACE")); $this->assertSame("11", (string) $response->getBody()); } public function testContainerSetToRoute() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn("Hello World"); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $containerProphecy = $this->prophesize(ContainerInterface::class); $containerProphecy->has("handler")->willReturn(true); $containerProphecy->get("handler")->willReturn(function () use($responseProphecy) { return $responseProphecy->reveal(); }); $app = new App($responseFactoryProphecy->reveal(), $containerProphecy->reveal()); $routeCollector = $app->getRouteCollector(); $routeCollector->map(array("GET"), "/", "handler"); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertSame("Hello World", (string) $response->getBody()); } public function testAppIsARequestHandler() : void { $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $app = new App($responseFactoryProphecy->reveal()); $this->assertInstanceOf(RequestHandlerInterface::class, $app); } public function testInvokeSequentialProcessToAPathWithOptionalArgsAndWithoutOptionalArgs() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get("/Hello[/{name}]", function (ServerRequestInterface $request, ResponseInterface $response, $args) { $response->getBody()->write((string) count($args)); return $response; }); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/Hello/World"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertSame("1", (string) $response->getBody()); $uriProphecy2 = $this->prophesize(UriInterface::class); $uriProphecy2->getPath()->willReturn("/Hello"); $requestProphecy2 = $this->prophesize(ServerRequestInterface::class); $requestProphecy2->getMethod()->willReturn("GET"); $requestProphecy2->getUri()->willReturn($uriProphecy2->reveal()); $requestProphecy2->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy2->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $streamProphecy->__toString()->willReturn(''); $response = $app->handle($requestProphecy2->reveal()); $this->assertSame("0", (string) $response->getBody()); } public function testInvokeSequentialProcessToAPathWithOptionalArgsAndWithoutOptionalArgsAndKeepSetedArgs() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $app->get("/Hello[/{name}]", function (ServerRequestInterface $request, ResponseInterface $response, $args) { $response->getBody()->write((string) count($args)); return $response; })->setArgument("extra", "value"); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/Hello/World"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertSame("2", (string) $response->getBody()); $uriProphecy2 = $this->prophesize(UriInterface::class); $uriProphecy2->getPath()->willReturn("/Hello"); $requestProphecy2 = $this->prophesize(ServerRequestInterface::class); $requestProphecy2->getMethod()->willReturn("GET"); $requestProphecy2->getUri()->willReturn($uriProphecy2->reveal()); $requestProphecy2->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy2->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $streamProphecy->__toString()->willReturn(''); $response = $app->handle($requestProphecy2->reveal()); $this->assertSame("1", (string) $response->getBody()); } public function testInvokeSequentialProcessAfterAddingAnotherRouteArgument() : void { $streamProphecy = $this->prophesize(StreamInterface::class); $streamProphecy->__toString()->willReturn(''); $streamProphecy->write(Argument::type("string"))->will(function ($args) { $body = $this->reveal()->__toString(); $body .= $args[0]; $this->__toString()->willReturn($body); }); $responseProphecy = $this->prophesize(ResponseInterface::class); $responseProphecy->getBody()->willReturn($streamProphecy->reveal()); $responseFactoryProphecy = $this->prophesize(ResponseFactoryInterface::class); $responseFactoryProphecy->createResponse()->willReturn($responseProphecy->reveal()); $app = new App($responseFactoryProphecy->reveal()); $route = $app->get("/Hello[/{name}]", function (ServerRequestInterface $request, ResponseInterface $response, $args) { $response->getBody()->write((string) count($args)); return $response; })->setArgument("extra", "value"); $uriProphecy = $this->prophesize(UriInterface::class); $uriProphecy->getPath()->willReturn("/Hello/World"); $requestProphecy = $this->prophesize(ServerRequestInterface::class); $requestProphecy->getMethod()->willReturn("GET"); $requestProphecy->getUri()->willReturn($uriProphecy->reveal()); $requestProphecy->getAttribute(RouteContext::ROUTE)->willReturn($route); $requestProphecy->getAttribute(RouteContext::ROUTING_RESULTS)->willReturn(null); $requestProphecy->withAttribute(Argument::type("string"), Argument::any())->will(function ($args) { $this->getAttribute($args[0])->willReturn($args[1]); return $this; }); $response = $app->handle($requestProphecy->reveal()); $this->assertSame("2", (string) $response->getBody()); $route->setArgument("extra2", "value2"); $streamProphecy->__toString()->willReturn(''); $response = $app->handle($requestProphecy->reveal()); $this->assertSame("3", (string) $response->getBody()); } } ?>