wellrested/test/RouterTest.php

395 lines
15 KiB
PHP

<?php
namespace pjdietz\WellRESTed\Test;
use pjdietz\WellRESTed\Exceptions\HttpExceptions\HttpException;
use pjdietz\WellRESTed\Router;
use Prophecy\Argument;
/**
* @covers pjdietz\WellRESTed\Router
*/
class RouterTest extends \PHPUnit_Framework_TestCase
{
private $handler;
private $request;
private $response;
private $route;
public function setUp()
{
$this->request = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\RequestInterface");
$this->response = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\ResponseInterface");
$this->route = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$this->handler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
}
public function testMatchesStaticRoute()
{
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$this->route->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\StaticRouteInterface");
$this->route->getPaths()->willReturn(["/cats/"]);
$this->route->getHandler()->willReturn($this->handler->reveal());
$this->request->getPath()->willReturn("/cats/");
$router = new Router();
$router->addRoute($this->route->reveal());
$router->getResponse($this->request->reveal());
$this->route->getHandler()->shouldHaveBeenCalled();
}
public function testMatchesPrefixRoute()
{
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$this->route->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\PrefixRouteInterface");
$this->route->getPrefixes()->willReturn(["/cats/"]);
$this->route->getHandler()->willReturn($this->handler->reveal());
$this->request->getPath()->willReturn("/cats/molly");
$router = new Router();
$router->addRoute($this->route->reveal());
$router->getResponse($this->request->reveal());
$this->route->getHandler()->shouldHaveBeenCalled();
}
public function testMatchesBestPrefixRoute()
{
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$route1 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route1->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\PrefixRouteInterface");
$route1->getPrefixes()->willReturn(["/animals/"]);
$route1->getHandler()->willReturn($this->handler->reveal());
$route2 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route2->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\PrefixRouteInterface");
$route2->getPrefixes()->willReturn(["/animals/cats/"]);
$route2->getHandler()->willReturn($this->handler->reveal());
$this->request->getPath()->willReturn("/animals/cats/molly");
$router = new Router();
$router->addRoute($route1->reveal());
$router->addRoute($route2->reveal());
$router->getResponse($this->request->reveal());
$route1->getHandler()->shouldNotHaveBeenCalled();
$route2->getHandler()->shouldHaveBeenCalled();
}
public function testMatchesStaticRouteBeforePrefixRoute()
{
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$route1 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route1->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\PrefixRouteInterface");
$route1->getPrefixes()->willReturn(["/animals/cats/"]);
$route1->getHandler()->willReturn($this->handler->reveal());
$route2 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route2->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\StaticRouteInterface");
$route2->getPaths()->willReturn(["/animals/cats/molly"]);
$route2->getHandler()->willReturn($this->handler->reveal());
$this->request->getPath()->willReturn("/animals/cats/molly");
$router = new Router();
$router->addRoute($route1->reveal());
$router->addRoute($route2->reveal());
$router->getResponse($this->request->reveal());
$route1->getHandler()->shouldNotHaveBeenCalled();
$route2->getHandler()->shouldHaveBeenCalled();
}
public function testMatchesPrefixRouteBeforeHandlerRoute()
{
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$route1 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route1->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\PrefixRouteInterface");
$route1->getPrefixes()->willReturn(["/animals/cats/"]);
$route1->getHandler()->willReturn($this->handler->reveal());
$route2 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route2->getResponse(Argument::cetera())->willReturn(null);
$this->request->getPath()->willReturn("/animals/cats/molly");
$router = new Router();
$router->addRoute($route1->reveal());
$router->addRoute($route2->reveal());
$router->getResponse($this->request->reveal());
$route1->getHandler()->shouldHaveBeenCalled();
$route2->getResponse(Argument::cetera())->shouldNotHaveBeenCalled();
}
public function testReturnsFirstNonNullResponse()
{
$route1 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route1->getResponse(Argument::cetera())->willReturn(null);
$route2 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route2->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$route3 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route3->getResponse(Argument::cetera())->willReturn(null);
$this->request->getPath()->willReturn("/");
$router = new Router();
$router->addRoutes(
[
$route1->reveal(),
$route2->reveal(),
$route3->reveal()
]
);
$response = $router->getResponse($this->request->reveal());
$this->assertNotNull($response);
$route1->getResponse(Argument::cetera())->shouldHaveBeenCalled();
$route2->getResponse(Argument::cetera())->shouldHaveBeenCalled();
$route3->getResponse(Argument::cetera())->shouldNotHaveBeenCalled();
}
public function testReturnsNullWhenNoRouteMatches()
{
$route1 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route1->getResponse(Argument::cetera())->willReturn(null);
$route2 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route2->getResponse(Argument::cetera())->willReturn(null);
$route3 = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$route3->getResponse(Argument::cetera())->willReturn(null);
$router = new Router();
$router->addRoutes(
[
$route1->reveal(),
$route2->reveal(),
$route3->reveal()
]
);
$response = $router->getResponse($this->request->reveal());
$this->assertNull($response);
$route1->getResponse(Argument::cetera())->shouldHaveBeenCalled();
$route2->getResponse(Argument::cetera())->shouldHaveBeenCalled();
$route3->getResponse(Argument::cetera())->shouldHaveBeenCalled();
}
public function testRespondsWithErrorResponseForHttpException()
{
$this->route->getResponse(Argument::cetera())->willThrow(new HttpException());
$this->request->getPath()->willReturn("/");
$router = new Router();
$router->addRoute($this->route->reveal());
$response = $router->getResponse($this->request->reveal());
$this->assertEquals(500, $response->getStatusCode());
}
public function testDispatchesErrorHandlerForStatusCode()
{
$this->request->getPath()->willReturn("/");
$this->response->getStatusCode()->willReturn(403);
$this->route->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$errorHandler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$errorHandler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$router = new Router();
$router->addRoute($this->route->reveal());
$router->setErrorHandlers([403 => $errorHandler->reveal()]);
$router->getResponse($this->request->reveal());
$errorHandler->getResponse(Argument::cetera())->shouldHaveBeenCalled();
}
public function testDispatchesErrorHandlerWithOriginalRequest()
{
$this->request->getPath()->willReturn("/");
$this->response->getStatusCode()->willReturn(403);
$this->route->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$errorHandler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$errorHandler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$request = $this->request->reveal();
$router = new Router();
$router->addRoute($this->route->reveal());
$router->setErrorHandlers([403 => $errorHandler->reveal()]);
$router->getResponse($request);
$errorHandler->getResponse(
Argument::that(
function ($arg) use ($request) {
return $arg === $request;
}
),
Argument::any()
)->shouldHaveBeenCalled();
}
public function testDispatchesErrorHandlerWithOriginalArguments()
{
$this->request->getPath()->willReturn("/");
$this->response->getStatusCode()->willReturn(403);
$response = $this->response->reveal();
$this->route->getResponse(Argument::cetera())->willReturn($response);
$errorHandler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$errorHandler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$arguments = [
"cat" => "Molly",
"dog" => "Bear"
];
$router = new Router();
$router->addRoute($this->route->reveal());
$router->setErrorHandlers([403 => $errorHandler->reveal()]);
$router->getResponse($this->request->reveal(), $arguments);
$errorHandler->getResponse(
Argument::any(),
Argument::that(
function ($args) use ($arguments) {
return count(array_diff_assoc($arguments, $args)) === 0;
}
)
)->shouldHaveBeenCalled();
}
public function testDispatchesErrorHandlerWithPreviousResponse()
{
$this->request->getPath()->willReturn("/");
$this->response->getStatusCode()->willReturn(403);
$response = $this->response->reveal();
$this->route->getResponse(Argument::cetera())->willReturn($response);
$errorHandler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$errorHandler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$router = new Router();
$router->addRoute($this->route->reveal());
$router->setErrorHandlers([403 => $errorHandler->reveal()]);
$router->getResponse($this->request->reveal());
$errorHandler->getResponse(
Argument::any(),
Argument::that(
function ($arg) use ($response) {
return isset($arg["response"]) && $arg["response"] === $response;
}
)
)->shouldHaveBeenCalled();
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testRoutesStaticRequest()
{
$_SERVER["REQUEST_URI"] = "/cats/";
$_SERVER["HTTP_HOST"] = "localhost";
$_SERVER["REQUEST_METHOD"] = "GET";
$this->response->getStatusCode()->willReturn(200);
$this->response->respond()->willReturn();
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$this->route->willImplement("\\pjdietz\\WellRESTed\\Interfaces\\Routes\\StaticRouteInterface");
$this->route->getPaths()->willReturn(["/cats/"]);
$this->route->getHandler()->willReturn($this->handler->reveal());
$router = new Router();
$router->addRoute($this->route->reveal());
ob_start();
$router->respond();
ob_end_clean();
$this->response->respond()->shouldHaveBeenCalled();
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testRoutesStaticRequestToNoRouteResponse()
{
$_SERVER["REQUEST_URI"] = "/cats/";
$_SERVER["HTTP_HOST"] = "localhost";
$_SERVER["REQUEST_METHOD"] = "GET";
$router = new Router();
ob_start();
$router->respond();
$captured = ob_get_contents();
ob_end_clean();
$this->assertEquals("No resource at /cats/", $captured);
}
/**
* @runInSeparateProcess
* @preserveGlobalState disabled
*/
public function testRoutesStaticRequestTo404ErrorHandler()
{
$_SERVER["REQUEST_URI"] = "/cats/";
$_SERVER["HTTP_HOST"] = "localhost";
$_SERVER["REQUEST_METHOD"] = "GET";
$errorHandler = $this->prophesize("\\pjdietz\\WellRESTed\\Interfaces\\HandlerInterface");
$errorHandler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$router = new Router();
$router->setErrorHandler(404, $errorHandler->reveal());
ob_start();
$router->respond();
ob_end_clean();
$errorHandler->getResponse(Argument::cetera())->shouldHaveBeenCalled();
}
public function testDeprecatedSetStaticRoute()
{
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$this->request->getPath()->willReturn("/cats/");
$router = new Router();
@$router->setStaticRoute(["/cats/"], $this->handler->reveal());
$router->getResponse($this->request->reveal());
$this->handler->getResponse(Argument::cetera())->shouldHaveBeenCalled();
}
public function testDeprecatedSetPrefixRoute()
{
$this->handler->getResponse(Argument::cetera())->willReturn($this->response->reveal());
$this->request->getPath()->willReturn("/cats/molly");
$router = new Router();
@$router->setPrefixRoute(["/cats/"], $this->handler->reveal());
$router->getResponse($this->request->reveal());
$this->handler->getResponse(Argument::cetera())->shouldHaveBeenCalled();
}
}