Refactor router test

This commit is contained in:
PJ Dietz 2016-05-21 11:05:35 -04:00
parent 91249d885f
commit b3dc82e744
1 changed files with 68 additions and 135 deletions

View File

@ -3,12 +3,15 @@
namespace WellRESTed\Test\Unit\Routing; namespace WellRESTed\Test\Unit\Routing;
use Prophecy\Argument; use Prophecy\Argument;
use WellRESTed\Dispatching\Dispatcher;
use WellRESTed\Message\Response;
use WellRESTed\Message\ServerRequest;
use WellRESTed\Routing\Route\RouteInterface; use WellRESTed\Routing\Route\RouteInterface;
use WellRESTed\Routing\Router; use WellRESTed\Routing\Router;
use WellRESTed\Test\NextMock;
/** /**
* @coversDefaultClass WellRESTed\Routing\Router * @covers WellRESTed\Routing\Router
* @uses WellRESTed\Routing\Router
* @group routing * @group routing
*/ */
class RouterTest extends \PHPUnit_Framework_TestCase class RouterTest extends \PHPUnit_Framework_TestCase
@ -39,21 +42,9 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$this->factory = $this->prophesize('WellRESTed\Routing\Route\RouteFactory'); $this->factory = $this->prophesize('WellRESTed\Routing\Route\RouteFactory');
$this->factory->create(Argument::any())->willReturn($this->route->reveal()); $this->factory->create(Argument::any())->willReturn($this->route->reveal());
$this->request = $this->prophesize('Psr\Http\Message\ServerRequestInterface'); $this->request = new ServerRequest();
$this->request->withAttribute(Argument::cetera())->willReturn($this->request->reveal()); $this->response = new Response();
$this->next = new NextMock();
$this->response = $this->prophesize('Psr\Http\Message\ResponseInterface');
$this->next = function ($request, $response) {
return $response;
};
$this->dispatcher = $this->prophesize('WellRESTed\Dispatching\DispatcherInterface');
$this->dispatcher->dispatch(Argument::cetera())->will(
function ($args) {
list($middleware, $request, $response, $next) = $args;
return $middleware->dispatch($request, $response, $next);
}
);
$this->router = $this->getMockBuilder('WellRESTed\Routing\Router') $this->router = $this->getMockBuilder('WellRESTed\Routing\Router')
->setMethods(["getRouteFactory"]) ->setMethods(["getRouteFactory"])
@ -62,41 +53,27 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$this->router->expects($this->any()) $this->router->expects($this->any())
->method("getRouteFactory") ->method("getRouteFactory")
->will($this->returnValue($this->factory->reveal())); ->will($this->returnValue($this->factory->reveal()));
$this->router->__construct($this->dispatcher->reveal()); $this->router->__construct(new Dispatcher());
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Construction // Construction
/**
* @covers ::__construct
* @covers ::getRouteFactory
* @uses WellRESTed\Routing\Route\RouteFactory
*/
public function testCreatesInstance() public function testCreatesInstance()
{ {
$router = new Router($this->dispatcher->reveal()); $router = new Router(new Dispatcher());
$this->assertNotNull($router); $this->assertNotNull($router);
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Populating // Populating
/**
* @covers ::register
* @covers ::getRouteForTarget
* @covers ::registerRouteForTarget
*/
public function testCreatesRouteForTarget() public function testCreatesRouteForTarget()
{ {
$this->router->register("GET", "/", "middleware"); $this->router->register("GET", "/", "middleware");
$this->factory->create("/")->shouldHaveBeenCalled(); $this->factory->create("/")->shouldHaveBeenCalled();
} }
/**
* @covers ::register
* @covers ::getRouteForTarget
*/
public function testDoesNotRecreateRouteForExistingTarget() public function testDoesNotRecreateRouteForExistingTarget()
{ {
$this->router->register("GET", "/", "middleware"); $this->router->register("GET", "/", "middleware");
@ -104,9 +81,6 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$this->factory->create("/")->shouldHaveBeenCalledTimes(1); $this->factory->create("/")->shouldHaveBeenCalledTimes(1);
} }
/**
* @covers ::register
*/
public function testPassesMethodAndMiddlewareToMethodMap() public function testPassesMethodAndMiddlewareToMethodMap()
{ {
$this->router->register("GET", "/", "middleware"); $this->router->register("GET", "/", "middleware");
@ -116,65 +90,50 @@ class RouterTest extends \PHPUnit_Framework_TestCase
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Dispatching // Dispatching
/**
* @covers ::__invoke
* @covers ::getStaticRoute
* @covers ::registerRouteForTarget
*/
public function testDispatchesStaticRoute() public function testDispatchesStaticRoute()
{ {
$target = "/"; $target = "/";
$this->request = $this->request->withRequestTarget($target);
$this->request->getRequestTarget()->willReturn($target);
$this->route->getTarget()->willReturn($target); $this->route->getTarget()->willReturn($target);
$this->route->getType()->willReturn(RouteInterface::TYPE_STATIC); $this->route->getType()->willReturn(RouteInterface::TYPE_STATIC);
$this->router->register("GET", $target, "middleware"); $this->router->register("GET", $target, "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$this->route->__invoke($this->request->reveal(), $this->response->reveal(), $this->next)->shouldHaveBeenCalled(); $this->route->__invoke($this->request, $this->response, $this->next)->shouldHaveBeenCalled();
} }
/**
* @covers ::__invoke
* @covers ::getPrefixRoute
* @covers ::registerRouteForTarget
*/
public function testDispatchesPrefixRoute() public function testDispatchesPrefixRoute()
{ {
$target = "/animals/cats/*"; $target = "/animals/cats/*";
$this->request->getRequestTarget()->willReturn("/animals/cats/molly"); $this->request = $this->request->withRequestTarget("/animals/cats/molly");
$this->route->getTarget()->willReturn($target); $this->route->getTarget()->willReturn($target);
$this->route->getType()->willReturn(RouteInterface::TYPE_PREFIX); $this->route->getType()->willReturn(RouteInterface::TYPE_PREFIX);
$this->router->register("GET", $target, "middleware"); $this->router->register("GET", $target, "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$this->route->__invoke($this->request->reveal(), $this->response->reveal(), $this->next)->shouldHaveBeenCalled(); $this->route->__invoke($this->request, $this->response, $this->next)->shouldHaveBeenCalled();
} }
/**
* @covers ::__invoke
* @covers ::registerRouteForTarget
*/
public function testDispatchesPatternRoute() public function testDispatchesPatternRoute()
{ {
$target = "/"; $target = "/";
$this->request = $this->request->withRequestTarget($target);
$this->request->getRequestTarget()->willReturn($target);
$this->route->getTarget()->willReturn($target); $this->route->getTarget()->willReturn($target);
$this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN);
$this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true);
$this->router->register("GET", $target, "middleware"); $this->router->register("GET", $target, "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$this->route->__invoke($this->request->reveal(), $this->response->reveal(), $this->next)->shouldHaveBeenCalled(); $this->route->__invoke($this->request, $this->response, $this->next)->shouldHaveBeenCalled();
} }
/** /** @coversNothing */
* @coversNothing
*/
public function testDispatchesStaticRouteBeforePrefixRoute() public function testDispatchesStaticRouteBeforePrefixRoute()
{ {
$staticRoute = $this->prophesize('WellRESTed\Routing\Route\RouteInterface'); $staticRoute = $this->prophesize('WellRESTed\Routing\Route\RouteInterface');
@ -189,21 +148,18 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); $prefixRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX);
$prefixRoute->__invoke(Argument::cetera())->willReturn(); $prefixRoute->__invoke(Argument::cetera())->willReturn();
$this->request->getRequestTarget()->willReturn("/cats/"); $this->request = $this->request->withRequestTarget("/cats/");
$this->factory->create("/cats/")->willReturn($staticRoute->reveal()); $this->factory->create("/cats/")->willReturn($staticRoute->reveal());
$this->factory->create("/cats/*")->willReturn($prefixRoute->reveal()); $this->factory->create("/cats/*")->willReturn($prefixRoute->reveal());
$this->router->register("GET", "/cats/", "middleware"); $this->router->register("GET", "/cats/", "middleware");
$this->router->register("GET", "/cats/*", "middleware"); $this->router->register("GET", "/cats/*", "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$staticRoute->__invoke($this->request->reveal(), $this->response->reveal(), $this->next)->shouldHaveBeenCalled(); $staticRoute->__invoke($this->request, $this->response, $this->next)->shouldHaveBeenCalled();
} }
/**
* @covers ::getPrefixRoute
*/
public function testDispatchesLongestMatchingPrefixRoute() public function testDispatchesLongestMatchingPrefixRoute()
{ {
// Note: The longest route is also good for 2 points in Settlers of Catan. // Note: The longest route is also good for 2 points in Settlers of Catan.
@ -220,21 +176,18 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$longRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX); $longRoute->getType()->willReturn(RouteInterface::TYPE_PREFIX);
$longRoute->__invoke(Argument::cetera())->willReturn(); $longRoute->__invoke(Argument::cetera())->willReturn();
$this->request->getRequestTarget()->willReturn("/animals/cats/molly"); $this->request = $this->request->withRequestTarget("/animals/cats/molly");
$this->factory->create("/animals/*")->willReturn($shortRoute->reveal()); $this->factory->create("/animals/*")->willReturn($shortRoute->reveal());
$this->factory->create("/animals/cats/*")->willReturn($longRoute->reveal()); $this->factory->create("/animals/cats/*")->willReturn($longRoute->reveal());
$this->router->register("GET", "/animals/*", "middleware"); $this->router->register("GET", "/animals/*", "middleware");
$this->router->register("GET", "/animals/cats/*", "middleware"); $this->router->register("GET", "/animals/cats/*", "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$longRoute->__invoke($this->request->reveal(), $this->response->reveal(), $this->next)->shouldHaveBeenCalled(); $longRoute->__invoke($this->request, $this->response, $this->next)->shouldHaveBeenCalled();
} }
/**
* @coversNothing
*/
public function testDispatchesPrefixRouteBeforePatternRoute() public function testDispatchesPrefixRouteBeforePatternRoute()
{ {
$prefixRoute = $this->prophesize('WellRESTed\Routing\Route\RouteInterface'); $prefixRoute = $this->prophesize('WellRESTed\Routing\Route\RouteInterface');
@ -249,21 +202,18 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$patternRoute->getType()->willReturn(RouteInterface::TYPE_PATTERN); $patternRoute->getType()->willReturn(RouteInterface::TYPE_PATTERN);
$patternRoute->__invoke(Argument::cetera())->willReturn(); $patternRoute->__invoke(Argument::cetera())->willReturn();
$this->request->getRequestTarget()->willReturn("/cats/"); $this->request = $this->request->withRequestTarget("/cats/");
$this->factory->create("/cats/*")->willReturn($prefixRoute->reveal()); $this->factory->create("/cats/*")->willReturn($prefixRoute->reveal());
$this->factory->create("/cats/{id}")->willReturn($patternRoute->reveal()); $this->factory->create("/cats/{id}")->willReturn($patternRoute->reveal());
$this->router->register("GET", "/cats/*", "middleware"); $this->router->register("GET", "/cats/*", "middleware");
$this->router->register("GET", "/cats/{id}", "middleware"); $this->router->register("GET", "/cats/{id}", "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$prefixRoute->__invoke($this->request->reveal(), $this->response->reveal(), $this->next)->shouldHaveBeenCalled(); $prefixRoute->__invoke($this->request, $this->response, $this->next)->shouldHaveBeenCalled();
} }
/**
* @coversNothing
*/
public function testDispatchesFirstMatchingPatternRoute() public function testDispatchesFirstMatchingPatternRoute()
{ {
$patternRoute1 = $this->prophesize('WellRESTed\Routing\Route\RouteInterface'); $patternRoute1 = $this->prophesize('WellRESTed\Routing\Route\RouteInterface');
@ -282,21 +232,18 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$patternRoute2->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute2->matchesRequestTarget(Argument::any())->willReturn(true);
$patternRoute2->__invoke(Argument::cetera())->willReturn(); $patternRoute2->__invoke(Argument::cetera())->willReturn();
$this->request->getRequestTarget()->willReturn("/cats/molly"); $this->request = $this->request->withRequestTarget("/cats/molly");
$this->factory->create("/cats/{id}")->willReturn($patternRoute1->reveal()); $this->factory->create("/cats/{id}")->willReturn($patternRoute1->reveal());
$this->factory->create("/cats/{name}")->willReturn($patternRoute2->reveal()); $this->factory->create("/cats/{name}")->willReturn($patternRoute2->reveal());
$this->router->register("GET", "/cats/{id}", "middleware"); $this->router->register("GET", "/cats/{id}", "middleware");
$this->router->register("GET", "/cats/{name}", "middleware"); $this->router->register("GET", "/cats/{name}", "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$patternRoute1->__invoke($this->request->reveal(), $this->response->reveal(), $this->next)->shouldHaveBeenCalled(); $patternRoute1->__invoke($this->request, $this->response, $this->next)->shouldHaveBeenCalled();
} }
/**
* @coversNothing
*/
public function testStopsTestingPatternsAfterFirstSuccessfulMatch() public function testStopsTestingPatternsAfterFirstSuccessfulMatch()
{ {
$patternRoute1 = $this->prophesize('WellRESTed\Routing\Route\RouteInterface'); $patternRoute1 = $this->prophesize('WellRESTed\Routing\Route\RouteInterface');
@ -315,33 +262,30 @@ class RouterTest extends \PHPUnit_Framework_TestCase
$patternRoute2->matchesRequestTarget(Argument::any())->willReturn(true); $patternRoute2->matchesRequestTarget(Argument::any())->willReturn(true);
$patternRoute2->__invoke(Argument::cetera())->willReturn(); $patternRoute2->__invoke(Argument::cetera())->willReturn();
$this->request->getRequestTarget()->willReturn("/cats/molly"); $this->request = $this->request->withRequestTarget("/cats/molly");
$this->factory->create("/cats/{id}")->willReturn($patternRoute1->reveal()); $this->factory->create("/cats/{id}")->willReturn($patternRoute1->reveal());
$this->factory->create("/cats/{name}")->willReturn($patternRoute2->reveal()); $this->factory->create("/cats/{name}")->willReturn($patternRoute2->reveal());
$this->router->register("GET", "/cats/{id}", "middleware"); $this->router->register("GET", "/cats/{id}", "middleware");
$this->router->register("GET", "/cats/{name}", "middleware"); $this->router->register("GET", "/cats/{name}", "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$patternRoute2->matchesRequestTarget(Argument::any())->shouldNotHaveBeenCalled(); $patternRoute2->matchesRequestTarget(Argument::any())->shouldNotHaveBeenCalled();
} }
/**
* @covers ::__invoke
* @covers ::registerRouteForTarget
*/
public function testMatchesPathAgainstRouteWithoutQuery() public function testMatchesPathAgainstRouteWithoutQuery()
{ {
$target = "/my/path?cat=molly&dog=bear"; $target = "/my/path?cat=molly&dog=bear";
$this->request->getRequestTarget()->willReturn($target); $this->request = $this->request->withRequestTarget($target);
$this->route->getTarget()->willReturn($target); $this->route->getTarget()->willReturn($target);
$this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN);
$this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true);
$this->router->register("GET", $target, "middleware"); $this->router->register("GET", $target, "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$this->route->matchesRequestTarget("/my/path")->shouldHaveBeenCalled(); $this->route->matchesRequestTarget("/my/path")->shouldHaveBeenCalled();
} }
@ -349,31 +293,33 @@ class RouterTest extends \PHPUnit_Framework_TestCase
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Path Variables // Path Variables
/** /** @dataProvider pathVariableProvider */
* @covers ::__invoke
* @dataProvider pathVariableProvider
*/
public function testSetPathVariablesAttributeIndividually($name, $value) public function testSetPathVariablesAttributeIndividually($name, $value)
{ {
$attributeName = "pathVariables";
$target = "/"; $target = "/";
$variables = [ $variables = [
"id" => "1024", "id" => "1024",
"name" => "Molly" "name" => "Molly"
]; ];
$this->request->getRequestTarget()->willReturn($target); $this->request = $this->request->withRequestTarget($target);
$this->route->getTarget()->willReturn($target); $this->route->getTarget()->willReturn($target);
$this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN);
$this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true);
$this->route->getPathVariables()->willReturn($variables); $this->route->getPathVariables()->willReturn($variables);
$this->router->__construct($this->dispatcher->reveal());
$this->router->register("GET", $target, "middleware"); $this->router->register("GET", $target, "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$this->request->withAttribute($name, $value)->shouldHaveBeenCalled(); $isRequestWithExpectedAttribute = function ($request) use ($name, $value) {
return $request->getAttribute($name) === $value;
};
$this->route->__invoke(
Argument::that($isRequestWithExpectedAttribute),
Argument::cetera()
)->shouldHaveBeenCalled();
} }
public function pathVariableProvider() public function pathVariableProvider()
@ -384,9 +330,6 @@ class RouterTest extends \PHPUnit_Framework_TestCase
]; ];
} }
/**
* @covers ::__invoke
*/
public function testSetPathVariablesAttributeAsArray() public function testSetPathVariablesAttributeAsArray()
{ {
$attributeName = "pathVariables"; $attributeName = "pathVariables";
@ -397,52 +340,42 @@ class RouterTest extends \PHPUnit_Framework_TestCase
"name" => "Molly" "name" => "Molly"
]; ];
$this->request->getRequestTarget()->willReturn($target); $this->request = $this->request->withRequestTarget($target);
$this->route->getTarget()->willReturn($target); $this->route->getTarget()->willReturn($target);
$this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN); $this->route->getType()->willReturn(RouteInterface::TYPE_PATTERN);
$this->route->matchesRequestTarget(Argument::cetera())->willReturn(true); $this->route->matchesRequestTarget(Argument::cetera())->willReturn(true);
$this->route->getPathVariables()->willReturn($variables); $this->route->getPathVariables()->willReturn($variables);
$this->router->__construct($this->dispatcher->reveal(), $attributeName); $this->router->__construct(new Dispatcher(), $attributeName);
$this->router->register("GET", $target, "middleware"); $this->router->register("GET", $target, "middleware");
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->router->__invoke($this->request, $this->response, $this->next);
$this->request->withAttribute("pathVariables", $variables)->shouldHaveBeenCalled(); $isRequestWithExpectedAttribute = function ($request) use ($attributeName, $variables) {
return $request->getAttribute($attributeName) === $variables;
};
$this->route->__invoke(
Argument::that($isRequestWithExpectedAttribute),
Argument::cetera()
)->shouldHaveBeenCalled();
} }
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// No Matching Routes // No Matching Routes
/**
* @covers ::__invoke
* @covers ::getStaticRoute
* @covers ::getPrefixRoute
*/
public function testResponds404WhenNoRouteMatches() public function testResponds404WhenNoRouteMatches()
{ {
$this->request->getRequestTarget()->willReturn("/no/match"); $this->request = $this->request->withRequestTarget("/no/match");
$this->response->withStatus(Argument::any())->willReturn($this->response->reveal()); $response = $this->router->__invoke($this->request, $this->response, $this->next);
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $this->next); $this->assertEquals(404, $response->getStatusCode());
$this->response->withStatus(404)->shouldHaveBeenCalled();
} }
/**
* @covers ::__invoke
* @covers ::getStaticRoute
* @covers ::getPrefixRoute
*/
public function testStopsPropagatingWhenNoRouteMatches() public function testStopsPropagatingWhenNoRouteMatches()
{ {
$calledNext = false; $this->request = $this->request->withRequestTarget("/no/match");
$next = function ($request, $response) use (&$calledNext) { $this->router->__invoke($this->request, $this->response, $this->next);
$calledNext = true; $this->assertFalse($this->next->called);
return $response;
};
$this->request->getRequestTarget()->willReturn("/no/match");
$this->response->withStatus(Argument::any())->willReturn($this->response->reveal());
$this->router->__invoke($this->request->reveal(), $this->response->reveal(), $next);
$this->assertFalse($calledNext);
} }
public function testRegisterIsFluid() public function testRegisterIsFluid()