Version 1
[yaffs-website] / vendor / symfony-cmf / routing / Tests / Routing / ChainRouterTest.php
diff --git a/vendor/symfony-cmf/routing/Tests/Routing/ChainRouterTest.php b/vendor/symfony-cmf/routing/Tests/Routing/ChainRouterTest.php
new file mode 100644 (file)
index 0000000..48bc3fa
--- /dev/null
@@ -0,0 +1,797 @@
+<?php
+
+/*
+ * This file is part of the Symfony CMF package.
+ *
+ * (c) 2011-2015 Symfony CMF
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Cmf\Component\Routing\Tests\Routing;
+
+use Symfony\Cmf\Component\Routing\VersatileGeneratorInterface;
+use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface;
+use Symfony\Component\Routing\Exception\MethodNotAllowedException;
+use Symfony\Component\Routing\Exception\ResourceNotFoundException;
+use Symfony\Component\Routing\Exception\RouteNotFoundException;
+use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
+use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
+use Symfony\Component\Routing\RequestContext;
+use Symfony\Component\Routing\RouteCollection;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Cmf\Component\Routing\ChainRouter;
+use Symfony\Cmf\Component\Routing\Test\CmfUnitTestCase;
+use Symfony\Component\Routing\RouterInterface;
+
+class ChainRouterTest extends CmfUnitTestCase
+{
+    /**
+     * @var ChainRouter
+     */
+    private $router;
+    /**
+     * @var RequestContext|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $context;
+
+    public function setUp()
+    {
+        $this->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
+{
+}