router = new ChainRouter($this->getMock('Psr\Log\LoggerInterface')); $this->context = $this->getMock('Symfony\Component\Routing\RequestContext'); } public function testPriority() { $this->assertEquals(array(), $this->router->all()); list($low, $high) = $this->createRouterMocks(); $this->router->add($low, 10); $this->router->add($high, 100); $this->assertEquals(array( $high, $low, ), $this->router->all()); } public function testHasRouters() { $this->assertEquals(array(), $this->router->all()); $this->assertFalse($this->router->hasRouters()); list($low, $high) = $this->createRouterMocks(); $this->router->add($low, 10); $this->router->add($high, 100); $this->assertTrue($this->router->hasRouters()); } /** * Routers are supposed to be sorted only once. * This test will check that by trying to get all routers several times. * * @covers \Symfony\Cmf\Component\Routing\ChainRouter::sortRouters * @covers \Symfony\Cmf\Component\Routing\ChainRouter::all */ public function testSortRouters() { list($low, $medium, $high) = $this->createRouterMocks(); // We're using a mock here and not $this->router because we need to ensure that the sorting operation is done only once. /** @var $router ChainRouter|\PHPUnit_Framework_MockObject_MockObject */ $router = $this->buildMock('Symfony\Cmf\Component\Routing\ChainRouter', array('sortRouters')); $router ->expects($this->once()) ->method('sortRouters') ->will( $this->returnValue( array($high, $medium, $low) ) ) ; $router->add($low, 10); $router->add($medium, 50); $router->add($high, 100); $expectedSortedRouters = array($high, $medium, $low); // Let's get all routers 5 times, we should only sort once. for ($i = 0; $i < 5; ++$i) { $this->assertSame($expectedSortedRouters, $router->all()); } } /** * This test ensures that if a router is being added on the fly, the sorting is reset. * * @covers \Symfony\Cmf\Component\Routing\ChainRouter::sortRouters * @covers \Symfony\Cmf\Component\Routing\ChainRouter::all * @covers \Symfony\Cmf\Component\Routing\ChainRouter::add */ public function testReSortRouters() { list($low, $medium, $high) = $this->createRouterMocks(); $highest = clone $high; // We're using a mock here and not $this->router because we need to ensure that the sorting operation is done only once. /** @var $router ChainRouter|\PHPUnit_Framework_MockObject_MockObject */ $router = $this->buildMock('Symfony\Cmf\Component\Routing\ChainRouter', array('sortRouters')); $router ->expects($this->at(0)) ->method('sortRouters') ->will( $this->returnValue( array($high, $medium, $low) ) ) ; // The second time sortRouters() is called, we're supposed to get the newly added router ($highest) $router ->expects($this->at(1)) ->method('sortRouters') ->will( $this->returnValue( array($highest, $high, $medium, $low) ) ) ; $router->add($low, 10); $router->add($medium, 50); $router->add($high, 100); $this->assertSame(array($high, $medium, $low), $router->all()); // Now adding another router on the fly, sorting must have been reset $router->add($highest, 101); $this->assertSame(array($highest, $high, $medium, $low), $router->all()); } /** * context must be propagated to chained routers and be stored locally. */ public function testContext() { list($low, $high) = $this->createRouterMocks(); $low ->expects($this->once()) ->method('setContext') ->with($this->context) ; $high ->expects($this->once()) ->method('setContext') ->with($this->context) ; $this->router->add($low, 10); $this->router->add($high, 100); $this->router->setContext($this->context); $this->assertSame($this->context, $this->router->getContext()); } /** * context must be propagated also when routers are added after context is set. */ public function testContextOrder() { list($low, $high) = $this->createRouterMocks(); $low ->expects($this->once()) ->method('setContext') ->with($this->context) ; $high ->expects($this->once()) ->method('setContext') ->with($this->context) ; $this->router->setContext($this->context); $this->router->add($low, 10); $this->router->add($high, 100); $this->router->all(); $this->assertSame($this->context, $this->router->getContext()); } /** * The first usable match is used, no further routers are queried once a match is found. */ public function testMatch() { $url = '/test'; list($lower, $low, $high) = $this->createRouterMocks(); $high ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new \Symfony\Component\Routing\Exception\ResourceNotFoundException())) ; $low ->expects($this->once()) ->method('match') ->with($url) ->will($this->returnValue(array('test'))) ; $lower ->expects($this->never()) ->method('match'); $this->router->add($lower, 5); $this->router->add($low, 10); $this->router->add($high, 100); $result = $this->router->match('/test'); $this->assertEquals(array('test'), $result); } /** * The first usable match is used, no further routers are queried once a match is found. */ public function testMatchRequest() { $url = '/test'; list($lower, $low, $high) = $this->createRouterMocks(); $highest = $this->getMock('Symfony\Cmf\Component\Routing\Tests\Routing\RequestMatcher'); $request = Request::create('/test'); $highest ->expects($this->once()) ->method('matchRequest') ->will($this->throwException(new \Symfony\Component\Routing\Exception\ResourceNotFoundException())) ; $high ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new \Symfony\Component\Routing\Exception\ResourceNotFoundException())) ; $low ->expects($this->once()) ->method('match') ->with($url) ->will($this->returnValue(array('test'))) ; $lower ->expects($this->never()) ->method('match') ; $this->router->add($lower, 5); $this->router->add($low, 10); $this->router->add($high, 100); $this->router->add($highest, 200); $result = $this->router->matchRequest($request); $this->assertEquals(array('test'), $result); } /** * Call match on ChainRouter that has RequestMatcher in the chain. */ public function testMatchWithRequestMatchers() { $url = '/test'; list($low) = $this->createRouterMocks(); $high = $this->getMock('Symfony\Cmf\Component\Routing\Tests\Routing\RequestMatcher'); $high ->expects($this->once()) ->method('matchRequest') ->with($this->callback(function (Request $r) use ($url) { return $r->getPathInfo() === $url; })) ->will($this->throwException(new \Symfony\Component\Routing\Exception\ResourceNotFoundException())) ; $low ->expects($this->once()) ->method('match') ->with($url) ->will($this->returnValue(array('test'))) ; $this->router->add($low, 10); $this->router->add($high, 20); $result = $this->router->match($url); $this->assertEquals(array('test'), $result); } public function provideBaseUrl() { return array( array(''), array('/web'), ); } /** * Call match on ChainRouter that has RequestMatcher in the chain. * * @dataProvider provideBaseUrl */ public function testMatchWithRequestMatchersAndContext($baseUrl) { $url = '//test'; list($low) = $this->createRouterMocks(); $high = $this->getMock('Symfony\Cmf\Component\Routing\Tests\Routing\RequestMatcher'); $high ->expects($this->once()) ->method('matchRequest') ->with($this->callback(function (Request $r) use ($url, $baseUrl) { return true === $r->isSecure() && 'foobar.com' === $r->getHost() && 4433 === $r->getPort() && $baseUrl === $r->getBaseUrl() && $url === $r->getPathInfo() ; })) ->will($this->throwException(new \Symfony\Component\Routing\Exception\ResourceNotFoundException())) ; $low ->expects($this->once()) ->method('match') ->with($url) ->will($this->returnValue(array('test'))) ; $this->router->add($low, 10); $this->router->add($high, 20); $requestContext = new RequestContext(); $requestContext->setScheme('https'); $requestContext->setHost('foobar.com'); $requestContext->setHttpsPort(4433); $requestContext->setBaseUrl($baseUrl); $this->router->setContext($requestContext); $result = $this->router->match($url); $this->assertEquals(array('test'), $result); } /** * If there is a method not allowed but another router matches, that one is used. */ public function testMatchAndNotAllowed() { $url = '/test'; list($low, $high) = $this->createRouterMocks(); $high ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new \Symfony\Component\Routing\Exception\MethodNotAllowedException(array()))) ; $low ->expects($this->once()) ->method('match') ->with($url) ->will($this->returnValue(array('test'))) ; $this->router->add($low, 10); $this->router->add($high, 100); $result = $this->router->match('/test'); $this->assertEquals(array('test'), $result); } /** * If there is a method not allowed but another router matches, that one is used. */ public function testMatchRequestAndNotAllowed() { $url = '/test'; list($low, $high) = $this->createRouterMocks(); $high ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new \Symfony\Component\Routing\Exception\MethodNotAllowedException(array()))) ; $low ->expects($this->once()) ->method('match') ->with($url) ->will($this->returnValue(array('test'))) ; $this->router->add($low, 10); $this->router->add($high, 100); $result = $this->router->matchRequest(Request::create('/test')); $this->assertEquals(array('test'), $result); } /** * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException */ public function testMatchNotFound() { $url = '/test'; list($low, $high) = $this->createRouterMocks(); $high ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new ResourceNotFoundException())) ; $low ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new ResourceNotFoundException())) ; $this->router->add($low, 10); $this->router->add($high, 100); $this->router->match('/test'); } /** * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException */ public function testMatchRequestNotFound() { $url = '/test'; list($low, $high) = $this->createRouterMocks(); $high ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new ResourceNotFoundException())) ; $low ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new ResourceNotFoundException())) ; $this->router->add($low, 10); $this->router->add($high, 100); $this->router->matchRequest(Request::create('/test')); } /** * Call match on ChainRouter that has RequestMatcher in the chain. * * @expectedException \Symfony\Component\Routing\Exception\ResourceNotFoundException * @expectedExceptionMessage None of the routers in the chain matched url '/test' */ public function testMatchWithRequestMatchersNotFound() { $url = '/test'; $request = Request::create('/test'); $high = $this->getMock('Symfony\Cmf\Component\Routing\Tests\Routing\RequestMatcher'); $high ->expects($this->once()) ->method('matchRequest') ->with($request) ->will($this->throwException(new \Symfony\Component\Routing\Exception\ResourceNotFoundException())) ; $this->router->add($high, 20); $this->router->match($url); } /** * If any of the routers throws a not allowed exception and no other matches, we need to see this. * * @expectedException \Symfony\Component\Routing\Exception\MethodNotAllowedException */ public function testMatchMethodNotAllowed() { $url = '/test'; list($low, $high) = $this->createRouterMocks(); $high ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new MethodNotAllowedException(array()))) ; $low ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new ResourceNotFoundException())) ; $this->router->add($low, 10); $this->router->add($high, 100); $this->router->match('/test'); } /** * If any of the routers throws a not allowed exception and no other matches, we need to see this. * * @expectedException \Symfony\Component\Routing\Exception\MethodNotAllowedException */ public function testMatchRequestMethodNotAllowed() { $url = '/test'; list($low, $high) = $this->createRouterMocks(); $high ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new MethodNotAllowedException(array()))) ; $low ->expects($this->once()) ->method('match') ->with($url) ->will($this->throwException(new ResourceNotFoundException())) ; $this->router->add($low, 10); $this->router->add($high, 100); $this->router->matchRequest(Request::create('/test')); } public function testGenerate() { $url = '/test'; $name = 'test'; $parameters = array('test' => 'value'); list($lower, $low, $high) = $this->createRouterMocks(); $high ->expects($this->once()) ->method('generate') ->with($name, $parameters, UrlGeneratorInterface::ABSOLUTE_PATH) ->will($this->throwException(new RouteNotFoundException())) ; $low ->expects($this->once()) ->method('generate') ->with($name, $parameters, UrlGeneratorInterface::ABSOLUTE_PATH) ->will($this->returnValue($url)) ; $lower ->expects($this->never()) ->method('generate') ; $this->router->add($low, 10); $this->router->add($high, 100); $result = $this->router->generate($name, $parameters); $this->assertEquals($url, $result); } /** * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException */ public function testGenerateNotFound() { $name = 'test'; $parameters = array('test' => 'value'); list($low, $high) = $this->createRouterMocks(); $high ->expects($this->once()) ->method('generate') ->with($name, $parameters, UrlGeneratorInterface::ABSOLUTE_PATH) ->will($this->throwException(new RouteNotFoundException())) ; $low->expects($this->once()) ->method('generate') ->with($name, $parameters, UrlGeneratorInterface::ABSOLUTE_PATH) ->will($this->throwException(new RouteNotFoundException())) ; $this->router->add($low, 10); $this->router->add($high, 100); $this->router->generate($name, $parameters); } /** * Route is an object but no versatile generator around to do the debug message. * * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException */ public function testGenerateObjectNotFound() { $name = new \stdClass(); $parameters = array('test' => 'value'); $defaultRouter = $this->getMock('Symfony\Component\Routing\RouterInterface'); $defaultRouter ->expects($this->never()) ->method('generate') ; $this->router->add($defaultRouter, 200); $this->router->generate($name, $parameters); } /** * A versatile router will generate the debug message. * * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException */ public function testGenerateObjectNotFoundVersatile() { $name = new \stdClass(); $parameters = array('test' => 'value'); $chainedRouter = $this->getMock('Symfony\Cmf\Component\Routing\Tests\Routing\VersatileRouter'); $chainedRouter ->expects($this->once()) ->method('supports') ->will($this->returnValue(true)) ; $chainedRouter->expects($this->once()) ->method('generate') ->with($name, $parameters, UrlGeneratorInterface::ABSOLUTE_PATH) ->will($this->throwException(new RouteNotFoundException())) ; $chainedRouter->expects($this->once()) ->method('getRouteDebugMessage') ->with($name, $parameters) ->will($this->returnValue('message')) ; $this->router->add($chainedRouter, 10); $this->router->generate($name, $parameters); } public function testGenerateObjectName() { $name = new \stdClass(); $parameters = array('test' => 'value'); $defaultRouter = $this->getMock('Symfony\Component\Routing\RouterInterface'); $chainedRouter = $this->getMock('Symfony\Cmf\Component\Routing\Tests\Routing\VersatileRouter'); $defaultRouter ->expects($this->never()) ->method('generate') ; $chainedRouter ->expects($this->once()) ->method('supports') ->will($this->returnValue(true)) ; $chainedRouter ->expects($this->once()) ->method('generate') ->with($name, $parameters, UrlGeneratorInterface::ABSOLUTE_PATH) ->will($this->returnValue($name)) ; $this->router->add($defaultRouter, 200); $this->router->add($chainedRouter, 100); $result = $this->router->generate($name, $parameters); $this->assertEquals($name, $result); } public function testWarmup() { $dir = 'test_dir'; list($low) = $this->createRouterMocks(); $low ->expects($this->never()) ->method('warmUp') ; $high = $this->getMock('Symfony\Cmf\Component\Routing\Tests\Routing\WarmableRouterMock'); $high ->expects($this->once()) ->method('warmUp') ->with($dir) ; $this->router->add($low, 10); $this->router->add($high, 100); $this->router->warmUp($dir); } public function testRouteCollection() { list($low, $high) = $this->createRouterMocks(); $lowcol = new RouteCollection(); $lowcol->add('low', $this->buildMock('Symfony\Component\Routing\Route')); $highcol = new RouteCollection(); $highcol->add('high', $this->buildMock('Symfony\Component\Routing\Route')); $low ->expects($this->once()) ->method('getRouteCollection') ->will($this->returnValue($lowcol)) ; $high ->expects($this->once()) ->method('getRouteCollection') ->will($this->returnValue($highcol)) ; $this->router->add($low, 10); $this->router->add($high, 100); $collection = $this->router->getRouteCollection(); $this->assertInstanceOf('Symfony\Component\Routing\RouteCollection', $collection); $names = array(); foreach ($collection->all() as $name => $route) { $this->assertInstanceOf('Symfony\Component\Routing\Route', $route); $names[] = $name; } $this->assertEquals(array('high', 'low'), $names); } /** * @expectedException \Symfony\Component\Routing\Exception\RouteNotFoundException */ public function testSupport() { $router = $this->getMock('Symfony\Cmf\Component\Routing\Tests\Routing\VersatileRouter'); $router ->expects($this->once()) ->method('supports') ->will($this->returnValue(false)) ; $router ->expects($this->never()) ->method('generate') ->will($this->returnValue(false)) ; $this->router->add($router); $this->router->generate('foobar'); } /** * @return RouterInterface[]|\PHPUnit_Framework_MockObject_MockObject[] */ protected function createRouterMocks() { return array( $this->getMock('Symfony\Component\Routing\RouterInterface'), $this->getMock('Symfony\Component\Routing\RouterInterface'), $this->getMock('Symfony\Component\Routing\RouterInterface'), ); } } abstract class WarmableRouterMock implements RouterInterface, WarmableInterface { } abstract class RequestMatcher implements RouterInterface, RequestMatcherInterface { } abstract class VersatileRouter implements VersatileGeneratorInterface, RequestMatcherInterface { }