default services conflit ?
This commit is contained in:
@@ -0,0 +1,865 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony CMF package.
|
||||
*
|
||||
* (c) 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 PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Cmf\Component\Routing\ChainRouter;
|
||||
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
||||
use Symfony\Cmf\Component\Routing\VersatileGeneratorInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
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\Loader\ObjectRouteLoader;
|
||||
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
|
||||
use Symfony\Component\Routing\RequestContext;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
use Symfony\Component\Routing\RouterInterface;
|
||||
|
||||
class ChainRouterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var ChainRouter
|
||||
*/
|
||||
private $router;
|
||||
|
||||
/**
|
||||
* @var RequestContext|MockObject
|
||||
*/
|
||||
private $context;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->router = new ChainRouter($this->createMock(LoggerInterface::class));
|
||||
$this->context = $this->createMock(RequestContext::class);
|
||||
}
|
||||
|
||||
public function testPriority()
|
||||
{
|
||||
$this->assertEquals([], $this->router->all());
|
||||
|
||||
list($low, $high) = $this->createRouterMocks();
|
||||
|
||||
$this->router->add($low, 10);
|
||||
$this->router->add($high, 100);
|
||||
|
||||
$this->assertEquals([
|
||||
$high,
|
||||
$low,
|
||||
], $this->router->all());
|
||||
}
|
||||
|
||||
public function testHasRouters()
|
||||
{
|
||||
$this->assertEquals([], $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|MockObject */
|
||||
$router = $this->getMockBuilder(ChainRouter::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['sortRouters'])
|
||||
->getMock();
|
||||
$router
|
||||
->expects($this->once())
|
||||
->method('sortRouters')
|
||||
->will(
|
||||
$this->returnValue(
|
||||
[$high, $medium, $low]
|
||||
)
|
||||
)
|
||||
;
|
||||
|
||||
$router->add($low, 10);
|
||||
$router->add($medium, 50);
|
||||
$router->add($high, 100);
|
||||
$expectedSortedRouters = [$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|MockObject */
|
||||
$router = $this->getMockBuilder(ChainRouter::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['sortRouters'])
|
||||
->getMock();
|
||||
$router
|
||||
->expects($this->exactly(2))
|
||||
->method('sortRouters')
|
||||
->willReturnOnConsecutiveCalls(
|
||||
[$high, $medium, $low],
|
||||
// The second time sortRouters() is called, we're supposed to get the newly added router ($highest)
|
||||
[$highest, $high, $medium, $low]
|
||||
)
|
||||
;
|
||||
|
||||
$router->add($low, 10);
|
||||
$router->add($medium, 50);
|
||||
$router->add($high, 100);
|
||||
$this->assertSame([$high, $medium, $low], $router->all());
|
||||
|
||||
// Now adding another router on the fly, sorting must have been reset
|
||||
$router->add($highest, 101);
|
||||
$this->assertSame([$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 ResourceNotFoundException()))
|
||||
;
|
||||
$low
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->returnValue(['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(['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->createMock(RequestMatcher::class);
|
||||
|
||||
$request = Request::create('/test');
|
||||
|
||||
$highest
|
||||
->expects($this->once())
|
||||
->method('matchRequest')
|
||||
->will($this->throwException(new ResourceNotFoundException()))
|
||||
;
|
||||
$high
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->throwException(new ResourceNotFoundException()))
|
||||
;
|
||||
$low
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->returnValue(['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(['test'], $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call match on ChainRouter that has RequestMatcher in the chain.
|
||||
*/
|
||||
public function testMatchWithRequestMatchers()
|
||||
{
|
||||
$url = '/test';
|
||||
|
||||
list($low) = $this->createRouterMocks();
|
||||
|
||||
$high = $this->createMock(RequestMatcher::class);
|
||||
|
||||
$high
|
||||
->expects($this->once())
|
||||
->method('matchRequest')
|
||||
->with($this->callback(function (Request $r) use ($url) {
|
||||
return $r->getPathInfo() === $url;
|
||||
}))
|
||||
->will($this->throwException(new ResourceNotFoundException()))
|
||||
;
|
||||
$low
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->returnValue(['test']))
|
||||
;
|
||||
|
||||
$this->router->add($low, 10);
|
||||
$this->router->add($high, 20);
|
||||
|
||||
$result = $this->router->match($url);
|
||||
$this->assertEquals(['test'], $result);
|
||||
}
|
||||
|
||||
public function provideBaseUrl()
|
||||
{
|
||||
return [
|
||||
[''],
|
||||
['/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->createMock(RequestMatcher::class);
|
||||
|
||||
$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 ResourceNotFoundException()))
|
||||
;
|
||||
$low
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->returnValue(['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(['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 MethodNotAllowedException([])))
|
||||
;
|
||||
$low
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->returnValue(
|
||||
['test']
|
||||
))
|
||||
;
|
||||
$this->router->add($low, 10);
|
||||
$this->router->add($high, 100);
|
||||
|
||||
$result = $this->router->match('/test');
|
||||
$this->assertEquals(['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 MethodNotAllowedException([])))
|
||||
;
|
||||
$low
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->returnValue(['test']))
|
||||
;
|
||||
$this->router->add($low, 10);
|
||||
$this->router->add($high, 100);
|
||||
|
||||
$result = $this->router->matchRequest(Request::create('/test'));
|
||||
$this->assertEquals(['test'], $result);
|
||||
}
|
||||
|
||||
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->expectException(ResourceNotFoundException::class);
|
||||
$this->router->match('/test');
|
||||
}
|
||||
|
||||
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->expectException(ResourceNotFoundException::class);
|
||||
$this->router->matchRequest(Request::create('/test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Call match on ChainRouter that has RequestMatcher in the chain.
|
||||
*/
|
||||
public function testMatchWithRequestMatchersNotFound()
|
||||
{
|
||||
$url = '/test';
|
||||
$expected = Request::create('/test');
|
||||
$expected->server->remove('REQUEST_TIME_FLOAT');
|
||||
|
||||
$high = $this->createMock(RequestMatcher::class);
|
||||
|
||||
$high
|
||||
->expects($this->once())
|
||||
->method('matchRequest')
|
||||
->with($this->callback(function (Request $actual) use ($expected): bool {
|
||||
$actual->server->remove('REQUEST_TIME_FLOAT');
|
||||
|
||||
return $actual == $expected;
|
||||
}))
|
||||
->will($this->throwException(new ResourceNotFoundException()))
|
||||
;
|
||||
|
||||
$this->router->add($high, 20);
|
||||
|
||||
$this->expectException(ResourceNotFoundException::class);
|
||||
$this->expectExceptionMessage('None of the routers in the chain matched url \'/test\'');
|
||||
$this->router->match($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* If any of the routers throws a not allowed exception and no other matches, we need to see this.
|
||||
*/
|
||||
public function testMatchMethodNotAllowed()
|
||||
{
|
||||
$url = '/test';
|
||||
list($low, $high) = $this->createRouterMocks();
|
||||
|
||||
$high
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->throwException(new MethodNotAllowedException([])))
|
||||
;
|
||||
$low
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->throwException(new ResourceNotFoundException()))
|
||||
;
|
||||
$this->router->add($low, 10);
|
||||
$this->router->add($high, 100);
|
||||
|
||||
$this->expectException(MethodNotAllowedException::class);
|
||||
$this->router->match('/test');
|
||||
}
|
||||
|
||||
/**
|
||||
* If any of the routers throws a not allowed exception and no other matches, we need to see this.
|
||||
*/
|
||||
public function testMatchRequestMethodNotAllowed()
|
||||
{
|
||||
$url = '/test';
|
||||
list($low, $high) = $this->createRouterMocks();
|
||||
|
||||
$high
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->throwException(new MethodNotAllowedException([])))
|
||||
;
|
||||
$low
|
||||
->expects($this->once())
|
||||
->method('match')
|
||||
->with($url)
|
||||
->will($this->throwException(new ResourceNotFoundException()))
|
||||
;
|
||||
$this->router->add($low, 10);
|
||||
$this->router->add($high, 100);
|
||||
|
||||
$this->expectException(MethodNotAllowedException::class);
|
||||
$this->router->matchRequest(Request::create('/test'));
|
||||
}
|
||||
|
||||
public function testGenerate()
|
||||
{
|
||||
$url = '/test';
|
||||
$name = 'test';
|
||||
$parameters = ['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);
|
||||
}
|
||||
|
||||
public function testGenerateNotFound()
|
||||
{
|
||||
$name = 'test';
|
||||
$parameters = ['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->expectException(RouteNotFoundException::class);
|
||||
$this->router->generate($name, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Route is an object but no versatile generator around to do the debug message.
|
||||
*
|
||||
* @group legacy
|
||||
* @expectedDeprecation Passing an object as route name is deprecated since version 2.3. Pass the `RouteObjectInterface::OBJECT_BASED_ROUTE_NAME` as route name and the object in the parameters with key `RouteObjectInterface::ROUTE_OBJECT`.
|
||||
*/
|
||||
public function testGenerateObjectNotFound()
|
||||
{
|
||||
if (!class_exists(ObjectRouteLoader::class)) {
|
||||
$this->markTestSkipped('Symfony 5 would throw a TypeError.');
|
||||
}
|
||||
|
||||
$name = new \stdClass();
|
||||
$parameters = ['test' => 'value'];
|
||||
|
||||
$defaultRouter = $this->createMock(RouterInterface::class);
|
||||
|
||||
$defaultRouter
|
||||
->expects($this->never())
|
||||
->method('generate')
|
||||
;
|
||||
|
||||
$this->router->add($defaultRouter, 200);
|
||||
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->router->generate($name, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* A versatile router will generate the debug message.
|
||||
*
|
||||
* @group legacy
|
||||
* @expectedDeprecation Passing an object as route name is deprecated since version 2.3. Pass the `RouteObjectInterface::OBJECT_BASED_ROUTE_NAME` as route name and the object in the parameters with key `RouteObjectInterface::ROUTE_OBJECT`.
|
||||
*/
|
||||
public function testGenerateObjectNotFoundVersatile()
|
||||
{
|
||||
if (!class_exists(ObjectRouteLoader::class)) {
|
||||
$this->markTestSkipped('Symfony 5 would throw a TypeError.');
|
||||
}
|
||||
|
||||
$name = new \stdClass();
|
||||
$parameters = ['test' => 'value'];
|
||||
|
||||
$chainedRouter = $this->createMock(VersatileRouter::class);
|
||||
$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->expectException(RouteNotFoundException::class);
|
||||
$this->router->generate($name, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Passing an object as route name is deprecated since version 2.3. Pass the `RouteObjectInterface::OBJECT_BASED_ROUTE_NAME` as route name and the object in the parameters with key `RouteObjectInterface::ROUTE_OBJECT`.
|
||||
*/
|
||||
public function testGenerateObjectName()
|
||||
{
|
||||
if (!class_exists(ObjectRouteLoader::class)) {
|
||||
$this->markTestSkipped('Symfony 5 would throw a TypeError.');
|
||||
}
|
||||
|
||||
$name = new \stdClass();
|
||||
$parameters = ['test' => 'value'];
|
||||
|
||||
$defaultRouter = $this->createMock(RouterInterface::class);
|
||||
$chainedRouter = $this->createMock(VersatileRouter::class);
|
||||
|
||||
$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);
|
||||
}
|
||||
|
||||
/**
|
||||
* This test currently triggers a deprecation notice because of ChainRouter BC.
|
||||
*/
|
||||
public function testGenerateWithObjectNameInParametersNotFoundVersatile()
|
||||
{
|
||||
$name = RouteObjectInterface::OBJECT_BASED_ROUTE_NAME;
|
||||
$parameters = ['test' => 'value', '_route_object' => new \stdClass()];
|
||||
|
||||
$chainedRouter = $this->createMock(VersatileRouter::class);
|
||||
$chainedRouter
|
||||
->expects($this->once())
|
||||
->method('supports')
|
||||
->willReturn(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)
|
||||
->willReturn('message')
|
||||
;
|
||||
|
||||
$this->router->add($chainedRouter, 10);
|
||||
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->router->generate($name, $parameters);
|
||||
}
|
||||
|
||||
public function testGenerateWithObjectNameInParameters()
|
||||
{
|
||||
$name = RouteObjectInterface::OBJECT_BASED_ROUTE_NAME;
|
||||
$parameters = ['test' => 'value', '_route_object' => new \stdClass()];
|
||||
|
||||
$defaultRouter = $this->createMock(RouterInterface::class);
|
||||
|
||||
$defaultRouter
|
||||
->expects($this->once())
|
||||
->method('generate')
|
||||
->with($name, $parameters, UrlGeneratorInterface::ABSOLUTE_PATH)
|
||||
->willReturn('/foo/bar')
|
||||
;
|
||||
|
||||
$this->router->add($defaultRouter, 200);
|
||||
|
||||
$result = $this->router->generate($name, $parameters);
|
||||
$this->assertEquals('/foo/bar', $result);
|
||||
}
|
||||
|
||||
public function testWarmup()
|
||||
{
|
||||
$dir = 'test_dir';
|
||||
list($low) = $this->createRouterMocks();
|
||||
|
||||
$high = $this->createMock(WarmableRouterMock::class);
|
||||
$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->createMock(Route::class));
|
||||
$highcol = new RouteCollection();
|
||||
$highcol->add('high', $this->createMock(Route::class));
|
||||
|
||||
$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(RouteCollection::class, $collection);
|
||||
|
||||
$names = [];
|
||||
foreach ($collection->all() as $name => $route) {
|
||||
$this->assertInstanceOf(Route::class, $route);
|
||||
$names[] = $name;
|
||||
}
|
||||
$this->assertEquals(['high', 'low'], $names);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testSupport()
|
||||
{
|
||||
$router = $this->createMock(VersatileRouter::class);
|
||||
$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->expectException(RouteNotFoundException::class);
|
||||
$this->router->generate('foobar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RouterInterface[]|MockObject[]
|
||||
*/
|
||||
protected function createRouterMocks()
|
||||
{
|
||||
return [
|
||||
$this->createMock(RouterInterface::class),
|
||||
$this->createMock(RouterInterface::class),
|
||||
$this->createMock(RouterInterface::class),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
abstract class WarmableRouterMock implements RouterInterface, WarmableInterface
|
||||
{
|
||||
}
|
||||
|
||||
abstract class RequestMatcher implements RouterInterface, RequestMatcherInterface
|
||||
{
|
||||
}
|
||||
|
||||
abstract class VersatileRouter implements VersatileGeneratorInterface, RequestMatcherInterface
|
||||
{
|
||||
}
|
@@ -0,0 +1,581 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony CMF package.
|
||||
*
|
||||
* (c) 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 PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Cmf\Component\Routing\ContentAwareGenerator;
|
||||
use Symfony\Cmf\Component\Routing\ContentRepositoryInterface;
|
||||
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
||||
use Symfony\Cmf\Component\Routing\RouteProviderInterface;
|
||||
use Symfony\Cmf\Component\Routing\RouteReferrersReadInterface;
|
||||
use Symfony\Cmf\Component\Routing\Tests\Unit\Routing\RouteMock;
|
||||
use Symfony\Component\Routing\CompiledRoute;
|
||||
use Symfony\Component\Routing\Exception\RouteNotFoundException;
|
||||
use Symfony\Component\Routing\Loader\ObjectRouteLoader;
|
||||
use Symfony\Component\Routing\RequestContext;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
class ContentAwareGeneratorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var RouteReferrersReadInterface|MockObject
|
||||
*/
|
||||
private $contentDocument;
|
||||
|
||||
/**
|
||||
* @var RouteMock|MockObject
|
||||
*/
|
||||
private $routeDocument;
|
||||
|
||||
/**
|
||||
* @var CompiledRoute|MockObject
|
||||
*/
|
||||
private $routeCompiled;
|
||||
|
||||
/**
|
||||
* @var RouteProviderInterface|MockObject
|
||||
*/
|
||||
private $provider;
|
||||
|
||||
/**
|
||||
* @var TestableContentAwareGenerator
|
||||
*/
|
||||
private $generator;
|
||||
|
||||
/**
|
||||
* @var RequestContext|MockObject
|
||||
*/
|
||||
private $context;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->contentDocument = $this->createMock(RouteReferrersReadInterface::class);
|
||||
$this->routeDocument = $this->getMockBuilder(RouteMock::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['compile', 'getContent'])
|
||||
->getMock();
|
||||
|
||||
$this->routeCompiled = $this->createMock(CompiledRoute::class);
|
||||
$this->provider = $this->createMock(RouteProviderInterface::class);
|
||||
$this->context = $this->createMock(RequestContext::class);
|
||||
|
||||
$this->generator = new TestableContentAwareGenerator($this->provider);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
* @expectedDeprecation Passing an object as route name is deprecated since version 2.3. Pass the `RouteObjectInterface::OBJECT_BASED_ROUTE_NAME` as route name and the object in the parameters with key `RouteObjectInterface::ROUTE_OBJECT`.
|
||||
*/
|
||||
public function testGenerateFromContent(): void
|
||||
{
|
||||
if (!class_exists(ObjectRouteLoader::class)) {
|
||||
$this->markTestSkipped('Symfony 5 would throw a TypeError.');
|
||||
}
|
||||
|
||||
$this->provider->expects($this->never())
|
||||
->method('getRouteByName')
|
||||
;
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([$this->routeDocument])
|
||||
;
|
||||
$this->routeDocument->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$this->assertEquals('result_url', $this->generator->generate($this->contentDocument));
|
||||
}
|
||||
|
||||
public function testGenerateFromContentInParameters(): void
|
||||
{
|
||||
$this->provider->expects($this->never())
|
||||
->method('getRouteByName')
|
||||
;
|
||||
$this->routeDocument->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$this->assertEquals('result_url', $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [RouteObjectInterface::ROUTE_OBJECT => $this->routeDocument]));
|
||||
}
|
||||
|
||||
public function testGenerateFromContentIdEmptyRouteName(): void
|
||||
{
|
||||
$this->provider->expects($this->never())
|
||||
->method('getRouteByName')
|
||||
;
|
||||
|
||||
$contentRepository = $this->createMock(ContentRepositoryInterface::class);
|
||||
$contentRepository->expects($this->once())
|
||||
->method('findById')
|
||||
->with('/content/id')
|
||||
->willReturn($this->contentDocument)
|
||||
;
|
||||
$this->generator->setContentRepository($contentRepository);
|
||||
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([$this->routeDocument])
|
||||
;
|
||||
|
||||
$this->routeDocument->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$this->assertEquals('result_url', $this->generator->generate('', ['content_id' => '/content/id']));
|
||||
}
|
||||
|
||||
public function testGenerateFromContentId()
|
||||
{
|
||||
$this->provider->expects($this->never())
|
||||
->method('getRouteByName')
|
||||
;
|
||||
|
||||
$contentRepository = $this->createMock(ContentRepositoryInterface::class);
|
||||
$contentRepository->expects($this->once())
|
||||
->method('findById')
|
||||
->with('/content/id')
|
||||
->willReturn($this->contentDocument)
|
||||
;
|
||||
$this->generator->setContentRepository($contentRepository);
|
||||
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([$this->routeDocument])
|
||||
;
|
||||
|
||||
$this->routeDocument->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$generated = $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, ['content_id' => '/content/id']);
|
||||
$this->assertEquals('result_url', $generated);
|
||||
}
|
||||
|
||||
public function testGenerateEmptyRouteString()
|
||||
{
|
||||
$this->provider->expects($this->never())
|
||||
->method('getRouteByName')
|
||||
;
|
||||
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([$this->routeDocument])
|
||||
;
|
||||
|
||||
$this->routeDocument->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$generated = $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [RouteObjectInterface::ROUTE_OBJECT => $this->contentDocument]);
|
||||
$this->assertEquals('result_url', $generated);
|
||||
}
|
||||
|
||||
public function testGenerateRouteMultilang()
|
||||
{
|
||||
/** @var RouteMock&MockObject $route_en */
|
||||
$route_en = $this->getMockBuilder(RouteMock::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['compile', 'getContent'])
|
||||
->getMock();
|
||||
$route_en->setLocale('en');
|
||||
$route_de = $this->routeDocument;
|
||||
$route_de->setLocale('de');
|
||||
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([$route_en, $route_de])
|
||||
;
|
||||
$route_en->expects($this->once())
|
||||
->method('getContent')
|
||||
->willReturn($this->contentDocument)
|
||||
;
|
||||
$route_en->expects($this->never())
|
||||
->method('compile')
|
||||
;
|
||||
$route_de->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$generated = $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, ['_locale' => 'de', RouteObjectInterface::ROUTE_OBJECT => $route_en]);
|
||||
$this->assertEquals('result_url', $generated);
|
||||
}
|
||||
|
||||
public function testGenerateRouteMultilangDefaultLocale()
|
||||
{
|
||||
$route = $this->createMock(RouteMock::class);
|
||||
$route->expects($this->any())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
$route->expects($this->any())
|
||||
->method('getRequirement')
|
||||
->with('_locale')
|
||||
->willReturn('de|en')
|
||||
;
|
||||
$route->expects($this->any())
|
||||
->method('getDefault')
|
||||
->with('_locale')
|
||||
->willReturn('en')
|
||||
;
|
||||
$this->routeCompiled->expects($this->any())
|
||||
->method('getVariables')
|
||||
->willReturn([])
|
||||
;
|
||||
|
||||
$generated = $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, ['_locale' => 'en', RouteObjectInterface::ROUTE_OBJECT => $route]);
|
||||
$this->assertEquals('result_url', $generated);
|
||||
}
|
||||
|
||||
public function testGenerateRouteMultilangLocaleNomatch(): void
|
||||
{
|
||||
/** @var RouteMock&MockObject $route_en */
|
||||
$route_en = $this->getMockBuilder(RouteMock::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['compile', 'getContent'])
|
||||
->getMock();
|
||||
$route_en->setLocale('en');
|
||||
$route_de = $this->routeDocument;
|
||||
$route_de->setLocale('de');
|
||||
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([$route_en, $route_de])
|
||||
;
|
||||
$route_en->expects($this->once())
|
||||
->method('getContent')
|
||||
->willReturn($this->contentDocument)
|
||||
;
|
||||
$route_en->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
$route_de->expects($this->never())
|
||||
->method('compile')
|
||||
;
|
||||
|
||||
$generated = $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, ['_locale' => 'fr', RouteObjectInterface::ROUTE_OBJECT => $route_en]);
|
||||
$this->assertEquals('result_url', $generated);
|
||||
}
|
||||
|
||||
public function testGenerateNoncmfRouteMultilang(): void
|
||||
{
|
||||
$route_en = $this->createMock(Route::class);
|
||||
|
||||
$route_en->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$generated = $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, ['_locale' => 'de', RouteObjectInterface::ROUTE_OBJECT => $route_en]);
|
||||
$this->assertEquals('result_url', $generated);
|
||||
}
|
||||
|
||||
public function testGenerateRoutenameMultilang(): void
|
||||
{
|
||||
$name = 'foo/bar';
|
||||
$route_en = $this->getMockBuilder(RouteMock::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['compile', 'getContent'])
|
||||
->getMock();
|
||||
$route_en->setLocale('en');
|
||||
$route_de = $this->routeDocument;
|
||||
$route_de->setLocale('de');
|
||||
|
||||
$this->provider->expects($this->once())
|
||||
->method('getRouteByName')
|
||||
->with($name)
|
||||
->willReturn($route_en)
|
||||
;
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([$route_en, $route_de])
|
||||
;
|
||||
$route_en->expects($this->once())
|
||||
->method('getContent')
|
||||
->willReturn($this->contentDocument)
|
||||
;
|
||||
$route_en->expects($this->never())
|
||||
->method('compile')
|
||||
;
|
||||
$route_de->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$this->assertEquals('result_url', $this->generator->generate($name, ['_locale' => 'de']));
|
||||
}
|
||||
|
||||
public function testGenerateRoutenameMultilangNotFound(): void
|
||||
{
|
||||
$name = 'foo/bar';
|
||||
|
||||
$this->provider->expects($this->once())
|
||||
->method('getRouteByName')
|
||||
->with($name)
|
||||
->willReturn(null)
|
||||
;
|
||||
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->generator->generate($name, ['_locale' => 'de']);
|
||||
}
|
||||
|
||||
public function testGenerateDocumentMultilang(): void
|
||||
{
|
||||
/** @var RouteMock&MockObject $route_en */
|
||||
$route_en = $this->getMockBuilder(RouteMock::class)
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(['compile', 'getContent'])
|
||||
->getMock();
|
||||
$route_en->setLocale('en');
|
||||
$route_de = $this->routeDocument;
|
||||
$route_de->setLocale('de');
|
||||
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([$route_en, $route_de])
|
||||
;
|
||||
$route_en->expects($this->never())
|
||||
->method('compile')
|
||||
;
|
||||
$route_de->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$generated = $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, ['_locale' => 'de', RouteObjectInterface::ROUTE_OBJECT => $this->contentDocument]);
|
||||
$this->assertEquals('result_url', $generated);
|
||||
}
|
||||
|
||||
public function testGenerateDocumentMultilangLocaleNomatch(): void
|
||||
{
|
||||
$route_en = $this->createMock(RouteMock::class);
|
||||
$route_en->setLocale('en');
|
||||
$route_de = $this->routeDocument;
|
||||
$route_de->setLocale('de');
|
||||
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([$route_en, $route_de])
|
||||
;
|
||||
$route_en->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
$route_de->expects($this->never())
|
||||
->method('compile')
|
||||
;
|
||||
|
||||
$generated = $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, ['_locale' => 'fr', RouteObjectInterface::ROUTE_OBJECT => $this->contentDocument]);
|
||||
$this->assertEquals('result_url', $generated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate without any information.
|
||||
*/
|
||||
public function testGenerateNoContent(): void
|
||||
{
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->generator->generate('', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate with an object that is neither a route nor route aware.
|
||||
*/
|
||||
public function testGenerateInvalidContent(): void
|
||||
{
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [RouteObjectInterface::ROUTE_OBJECT => $this]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate with an object that is neither a route nor route aware.
|
||||
*
|
||||
* @group legacy
|
||||
*/
|
||||
public function testGenerateInvalidContentLegacy(): void
|
||||
{
|
||||
if (!class_exists(ObjectRouteLoader::class)) {
|
||||
$this->markTestSkipped('Symfony 5 would throw a TypeError.');
|
||||
}
|
||||
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->generator->generate($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate with a content_id but there is no content repository.
|
||||
*/
|
||||
public function testGenerateNoContentRepository(): void
|
||||
{
|
||||
$this->provider->expects($this->never())
|
||||
->method('getRouteByName')
|
||||
;
|
||||
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->generator->generate('', ['content_id' => '/content/id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate with content_id but the content is not found.
|
||||
*/
|
||||
public function testGenerateNoContentFoundInRepository(): void
|
||||
{
|
||||
$this->provider->expects($this->never())
|
||||
->method('getRouteByName')
|
||||
;
|
||||
|
||||
$contentRepository = $this->createMock(ContentRepositoryInterface::class);
|
||||
$contentRepository->expects($this->once())
|
||||
->method('findById')
|
||||
->with('/content/id')
|
||||
->willReturn(null)
|
||||
;
|
||||
$this->generator->setContentRepository($contentRepository);
|
||||
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->generator->generate('', ['content_id' => '/content/id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate with content_id but the object at id is not route aware.
|
||||
*/
|
||||
public function testGenerateWrongContentClassInRepository(): void
|
||||
{
|
||||
$this->provider->expects($this->never())
|
||||
->method('getRouteByName')
|
||||
;
|
||||
|
||||
$contentRepository = $this->createMock(ContentRepositoryInterface::class);
|
||||
$contentRepository->expects($this->once())
|
||||
->method('findById')
|
||||
->with('/content/id')
|
||||
->willReturn($this)
|
||||
;
|
||||
$this->generator->setContentRepository($contentRepository);
|
||||
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->generator->generate('', ['content_id' => '/content/id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate from a content that has no routes associated.
|
||||
*/
|
||||
public function testGenerateNoRoutes(): void
|
||||
{
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([]);
|
||||
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [RouteObjectInterface::ROUTE_OBJECT => $this->contentDocument]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate from a content that returns something that is not a route as route.
|
||||
*/
|
||||
public function testGenerateInvalidRoute(): void
|
||||
{
|
||||
$this->contentDocument->expects($this->once())
|
||||
->method('getRoutes')
|
||||
->willReturn([$this]);
|
||||
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [RouteObjectInterface::ROUTE_OBJECT => $this->contentDocument]);
|
||||
}
|
||||
|
||||
public function testGetLocaleAttribute(): void
|
||||
{
|
||||
$this->generator->setDefaultLocale('en');
|
||||
|
||||
$attributes = ['_locale' => 'fr'];
|
||||
$this->assertEquals('fr', $this->generator->getLocale($attributes));
|
||||
}
|
||||
|
||||
public function testGetLocaleDefault(): void
|
||||
{
|
||||
$this->generator->setDefaultLocale('en');
|
||||
|
||||
$attributes = [];
|
||||
$this->assertEquals('en', $this->generator->getLocale($attributes));
|
||||
}
|
||||
|
||||
public function testGetLocaleContext(): void
|
||||
{
|
||||
$this->generator->setDefaultLocale('en');
|
||||
|
||||
$this->generator->getContext()->setParameter('_locale', 'de');
|
||||
|
||||
$attributes = [];
|
||||
$this->assertEquals('de', $this->generator->getLocale($attributes));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testSupports(): void
|
||||
{
|
||||
$this->assertTrue($this->generator->supports(''));
|
||||
$this->assertTrue($this->generator->supports(null));
|
||||
$this->assertTrue($this->generator->supports($this->contentDocument));
|
||||
$this->assertFalse($this->generator->supports($this));
|
||||
}
|
||||
|
||||
public function testGetRouteDebugMessage(): void
|
||||
{
|
||||
$this->assertStringContainsString('/some/content', $this->generator->getRouteDebugMessage(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, ['content_id' => '/some/content']));
|
||||
$this->assertStringContainsString('Route aware content Symfony\Cmf\Component\Routing\Tests\Routing\RouteAware', $this->generator->getRouteDebugMessage(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [RouteObjectInterface::ROUTE_OBJECT => new RouteAware()]));
|
||||
$this->assertStringContainsString('/some/content', $this->generator->getRouteDebugMessage('/some/content'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @legacy
|
||||
*/
|
||||
public function testGetRouteDebugMessageLegacy(): void
|
||||
{
|
||||
$this->assertStringContainsString('/some/content', $this->generator->getRouteDebugMessage(null, ['content_id' => '/some/content']));
|
||||
$this->assertStringContainsString('Route aware content Symfony\Cmf\Component\Routing\Tests\Routing\RouteAware', $this->generator->getRouteDebugMessage(new RouteAware()));
|
||||
$this->assertStringContainsString('/some/content', $this->generator->getRouteDebugMessage('/some/content'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite doGenerate to reduce amount of mocking needed.
|
||||
*/
|
||||
class TestableContentAwareGenerator extends ContentAwareGenerator
|
||||
{
|
||||
protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, array $requiredSchemes = [])
|
||||
{
|
||||
return 'result_url';
|
||||
}
|
||||
|
||||
// expose as public
|
||||
|
||||
public function getLocale($parameters)
|
||||
{
|
||||
return parent::getLocale($parameters);
|
||||
}
|
||||
}
|
||||
|
||||
class RouteAware implements RouteReferrersReadInterface
|
||||
{
|
||||
public function getRoutes()
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
@@ -0,0 +1,425 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony CMF package.
|
||||
*
|
||||
* (c) 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 PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Cmf\Component\Routing\DynamicRouter;
|
||||
use Symfony\Cmf\Component\Routing\Enhancer\RouteEnhancerInterface;
|
||||
use Symfony\Cmf\Component\Routing\Event\Events;
|
||||
use Symfony\Cmf\Component\Routing\Event\RouterGenerateEvent;
|
||||
use Symfony\Cmf\Component\Routing\Event\RouterMatchEvent;
|
||||
use Symfony\Cmf\Component\Routing\LazyRouteCollection;
|
||||
use Symfony\Cmf\Component\Routing\RouteProviderInterface;
|
||||
use Symfony\Cmf\Component\Routing\Tests\Unit\Routing\RouteMock;
|
||||
use Symfony\Cmf\Component\Routing\VersatileGeneratorInterface;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
|
||||
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
|
||||
use Symfony\Component\Routing\Matcher\RequestMatcherInterface;
|
||||
use Symfony\Component\Routing\Matcher\UrlMatcherInterface;
|
||||
use Symfony\Component\Routing\RequestContext;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
class DynamicRouterTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var RouteMock|MockObject
|
||||
*/
|
||||
private $routeDocument;
|
||||
|
||||
/**
|
||||
* @var UrlMatcherInterface|MockObject
|
||||
*/
|
||||
private $matcher;
|
||||
|
||||
/**
|
||||
* @var VersatileGeneratorInterface|MockObject
|
||||
*/
|
||||
private $generator;
|
||||
|
||||
/**
|
||||
* @var RouteEnhancerInterface|MockObject
|
||||
*/
|
||||
private $enhancer;
|
||||
|
||||
/**
|
||||
* @var DynamicRouter
|
||||
*/
|
||||
private $router;
|
||||
|
||||
/**
|
||||
* @var RequestContext|MockObject
|
||||
*/
|
||||
private $context;
|
||||
|
||||
/**
|
||||
* @var Request
|
||||
*/
|
||||
private $request;
|
||||
|
||||
const URL = '/foo/bar';
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->routeDocument = $this->createMock(RouteMock::class);
|
||||
|
||||
$this->matcher = $this->createMock(UrlMatcherInterface::class);
|
||||
$this->generator = $this->createMock(VersatileGeneratorInterface::class);
|
||||
$this->enhancer = $this->createMock(RouteEnhancerInterface::class);
|
||||
|
||||
$this->context = $this->createMock(RequestContext::class);
|
||||
$this->request = Request::create(self::URL);
|
||||
|
||||
$this->router = new DynamicRouter($this->context, $this->matcher, $this->generator);
|
||||
$this->router->addRouteEnhancer($this->enhancer);
|
||||
}
|
||||
|
||||
/**
|
||||
* rather trivial, but we want 100% coverage.
|
||||
*/
|
||||
public function testContext()
|
||||
{
|
||||
$this->router->setContext($this->context);
|
||||
$this->assertSame($this->context, $this->router->getContext());
|
||||
}
|
||||
|
||||
public function testRouteCollectionEmpty()
|
||||
{
|
||||
$collection = $this->router->getRouteCollection();
|
||||
$this->assertInstanceOf(RouteCollection::class, $collection);
|
||||
}
|
||||
|
||||
public function testRouteCollectionLazy()
|
||||
{
|
||||
$provider = $this->createMock(RouteProviderInterface::class);
|
||||
$router = new DynamicRouter($this->context, $this->matcher, $this->generator, '', null, $provider);
|
||||
|
||||
$collection = $router->getRouteCollection();
|
||||
$this->assertInstanceOf(LazyRouteCollection::class, $collection);
|
||||
}
|
||||
|
||||
/// generator tests ///
|
||||
|
||||
public function testGetGenerator()
|
||||
{
|
||||
$this->generator->expects($this->once())
|
||||
->method('setContext')
|
||||
->with($this->equalTo($this->context));
|
||||
|
||||
$generator = $this->router->getGenerator();
|
||||
$this->assertInstanceOf(UrlGeneratorInterface::class, $generator);
|
||||
$this->assertSame($this->generator, $generator);
|
||||
}
|
||||
|
||||
public function testGenerate()
|
||||
{
|
||||
$name = 'my_route_name';
|
||||
$parameters = ['foo' => 'bar'];
|
||||
$absolute = UrlGeneratorInterface::ABSOLUTE_PATH;
|
||||
|
||||
$this->generator->expects($this->once())
|
||||
->method('generate')
|
||||
->with($name, $parameters, $absolute)
|
||||
->will($this->returnValue('http://test'))
|
||||
;
|
||||
|
||||
$url = $this->router->generate($name, $parameters, $absolute);
|
||||
$this->assertEquals('http://test', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testSupports()
|
||||
{
|
||||
$name = 'foo/bar';
|
||||
$this->generator->expects($this->once())
|
||||
->method('supports')
|
||||
->with($this->equalTo($name))
|
||||
->will($this->returnValue(true))
|
||||
;
|
||||
|
||||
$this->assertTrue($this->router->supports($name));
|
||||
}
|
||||
|
||||
public function testSupportsNonversatile()
|
||||
{
|
||||
$generator = $this->createMock(UrlGeneratorInterface::class);
|
||||
$router = new DynamicRouter($this->context, $this->matcher, $generator);
|
||||
$this->assertIsString($router->getRouteDebugMessage('test'));
|
||||
|
||||
$this->assertTrue($router->supports('some string'));
|
||||
$this->assertFalse($router->supports($this));
|
||||
}
|
||||
|
||||
/// match tests ///
|
||||
|
||||
public function testGetMatcher()
|
||||
{
|
||||
$this->matcher->expects($this->once())
|
||||
->method('setContext')
|
||||
->with($this->equalTo($this->context));
|
||||
|
||||
$matcher = $this->router->getMatcher();
|
||||
$this->assertInstanceOf(UrlMatcherInterface::class, $matcher);
|
||||
$this->assertSame($this->matcher, $matcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testMatchUrl()
|
||||
{
|
||||
$routeDefaults = ['foo' => 'bar'];
|
||||
$this->matcher->expects($this->once())
|
||||
->method('match')
|
||||
->with(self::URL)
|
||||
->will($this->returnValue($routeDefaults))
|
||||
;
|
||||
|
||||
$expected = ['this' => 'that'];
|
||||
$test = $this;
|
||||
$this->enhancer->expects($this->once())
|
||||
->method('enhance')
|
||||
->with($this->equalTo($routeDefaults), $this->callback(function (Request $request) {
|
||||
return self::URL === $request->server->get('REQUEST_URI');
|
||||
}))
|
||||
->will($this->returnValue($expected))
|
||||
;
|
||||
|
||||
$results = $this->router->match(self::URL);
|
||||
|
||||
$this->assertEquals($expected, $results);
|
||||
}
|
||||
|
||||
public function testMatchRequestWithUrlMatcher()
|
||||
{
|
||||
$routeDefaults = ['foo' => 'bar'];
|
||||
|
||||
$this->matcher->expects($this->once())
|
||||
->method('match')
|
||||
->with(self::URL)
|
||||
->will($this->returnValue($routeDefaults))
|
||||
;
|
||||
|
||||
$expected = ['this' => 'that'];
|
||||
$test = $this;
|
||||
$this->enhancer->expects($this->once())
|
||||
->method('enhance')
|
||||
->with($this->equalTo($routeDefaults), $this->callback(function (Request $request) {
|
||||
return self::URL === $request->server->get('REQUEST_URI');
|
||||
}))
|
||||
->will($this->returnValue($expected))
|
||||
;
|
||||
|
||||
$results = $this->router->matchRequest($this->request);
|
||||
|
||||
$this->assertEquals($expected, $results);
|
||||
}
|
||||
|
||||
public function testMatchRequest()
|
||||
{
|
||||
$routeDefaults = ['foo' => 'bar'];
|
||||
|
||||
$matcher = $this->createMock(RequestMatcherInterface::class);
|
||||
$router = new DynamicRouter($this->context, $matcher, $this->generator);
|
||||
|
||||
$matcher->expects($this->once())
|
||||
->method('matchRequest')
|
||||
->with($this->request)
|
||||
->will($this->returnValue($routeDefaults))
|
||||
;
|
||||
|
||||
$expected = ['this' => 'that'];
|
||||
$test = $this;
|
||||
$this->enhancer->expects($this->once())
|
||||
->method('enhance')
|
||||
->with($this->equalTo($routeDefaults), $this->callback(function (Request $request) {
|
||||
return self::URL === $request->server->get('REQUEST_URI');
|
||||
}))
|
||||
->will($this->returnValue($expected))
|
||||
;
|
||||
|
||||
$router->addRouteEnhancer($this->enhancer);
|
||||
|
||||
$this->assertEquals($expected, $router->matchRequest($this->request));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testMatchFilter()
|
||||
{
|
||||
$router = new DynamicRouter($this->context, $this->matcher, $this->generator, '#/different/prefix.*#');
|
||||
$router->addRouteEnhancer($this->enhancer);
|
||||
|
||||
$this->matcher->expects($this->never())
|
||||
->method('match')
|
||||
;
|
||||
|
||||
$this->enhancer->expects($this->never())
|
||||
->method('enhance')
|
||||
;
|
||||
|
||||
$this->expectException(ResourceNotFoundException::class);
|
||||
$router->match(self::URL);
|
||||
}
|
||||
|
||||
public function testMatchRequestFilter()
|
||||
{
|
||||
$matcher = $this->createMock(RequestMatcherInterface::class);
|
||||
|
||||
$router = new DynamicRouter($this->context, $matcher, $this->generator, '#/different/prefix.*#');
|
||||
$router->addRouteEnhancer($this->enhancer);
|
||||
|
||||
$matcher->expects($this->never())
|
||||
->method('matchRequest')
|
||||
;
|
||||
|
||||
$this->enhancer->expects($this->never())
|
||||
->method('enhance')
|
||||
;
|
||||
|
||||
$this->expectException(ResourceNotFoundException::class);
|
||||
$router->matchRequest($this->request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testMatchUrlWithRequestMatcher()
|
||||
{
|
||||
$matcher = $this->createMock(RequestMatcherInterface::class);
|
||||
$router = new DynamicRouter($this->context, $matcher, $this->generator);
|
||||
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
$router->match(self::URL);
|
||||
}
|
||||
|
||||
public function testInvalidMatcher()
|
||||
{
|
||||
$this->expectException(\InvalidArgumentException::class);
|
||||
new DynamicRouter($this->context, $this, $this->generator);
|
||||
}
|
||||
|
||||
public function testRouteDebugMessage()
|
||||
{
|
||||
$this->generator->expects($this->once())
|
||||
->method('getRouteDebugMessage')
|
||||
->with($this->equalTo('test'), $this->equalTo([]))
|
||||
->will($this->returnValue('debug message'))
|
||||
;
|
||||
|
||||
$this->assertEquals('debug message', $this->router->getRouteDebugMessage('test'));
|
||||
}
|
||||
|
||||
public function testRouteDebugMessageNonversatile()
|
||||
{
|
||||
$generator = $this->createMock(UrlGeneratorInterface::class);
|
||||
$router = new DynamicRouter($this->context, $this->matcher, $generator);
|
||||
$this->assertIsString($router->getRouteDebugMessage('test'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*/
|
||||
public function testEventHandler()
|
||||
{
|
||||
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$router = new DynamicRouter($this->context, $this->matcher, $this->generator, '', $eventDispatcher);
|
||||
|
||||
$eventDispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with($this->equalTo(new RouterMatchEvent()), Events::PRE_DYNAMIC_MATCH)
|
||||
;
|
||||
|
||||
$routeDefaults = ['foo' => 'bar'];
|
||||
$this->matcher->expects($this->once())
|
||||
->method('match')
|
||||
->with(self::URL)
|
||||
->will($this->returnValue($routeDefaults))
|
||||
;
|
||||
|
||||
$this->assertEquals($routeDefaults, $router->match(self::URL));
|
||||
}
|
||||
|
||||
public function testEventHandlerRequest()
|
||||
{
|
||||
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$router = new DynamicRouter($this->context, $this->matcher, $this->generator, '', $eventDispatcher);
|
||||
|
||||
$that = $this;
|
||||
$eventDispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with($this->callback(function ($event) use ($that) {
|
||||
$that->assertInstanceOf(RouterMatchEvent::class, $event);
|
||||
$that->assertEquals($that->request, $event->getRequest());
|
||||
|
||||
return true;
|
||||
}), Events::PRE_DYNAMIC_MATCH_REQUEST)
|
||||
;
|
||||
|
||||
$routeDefaults = ['foo' => 'bar'];
|
||||
$this->matcher->expects($this->once())
|
||||
->method('match')
|
||||
->with(self::URL)
|
||||
->will($this->returnValue($routeDefaults))
|
||||
;
|
||||
|
||||
$this->assertEquals($routeDefaults, $router->matchRequest($this->request));
|
||||
}
|
||||
|
||||
public function testEventHandlerGenerate()
|
||||
{
|
||||
$eventDispatcher = $this->createMock(EventDispatcherInterface::class);
|
||||
$router = new DynamicRouter($this->context, $this->matcher, $this->generator, '', $eventDispatcher);
|
||||
|
||||
$oldname = 'old_route_name';
|
||||
$newname = 'new_route_name';
|
||||
$oldparameters = ['foo' => 'bar'];
|
||||
$newparameters = ['a' => 'b'];
|
||||
$oldReferenceType = false;
|
||||
$newReferenceType = true;
|
||||
|
||||
$that = $this;
|
||||
$eventDispatcher->expects($this->once())
|
||||
->method('dispatch')
|
||||
->with($this->callback(function ($event) use ($that, $oldname, $newname, $oldparameters, $newparameters, $oldReferenceType, $newReferenceType) {
|
||||
$that->assertInstanceOf(RouterGenerateEvent::class, $event);
|
||||
if (empty($that->seen)) {
|
||||
// phpunit is calling the callback twice, and because we update the event the second time fails
|
||||
$that->seen = true;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
$that->assertEquals($oldname, $event->getRoute());
|
||||
$that->assertEquals($oldparameters, $event->getParameters());
|
||||
$that->assertEquals($oldReferenceType, $event->getReferenceType());
|
||||
$event->setRoute($newname);
|
||||
$event->setParameters($newparameters);
|
||||
$event->setReferenceType($newReferenceType);
|
||||
|
||||
return true;
|
||||
}), Events::PRE_DYNAMIC_GENERATE)
|
||||
;
|
||||
|
||||
$this->generator->expects($this->once())
|
||||
->method('generate')
|
||||
->with($newname, $newparameters, $newReferenceType)
|
||||
->will($this->returnValue('http://test'))
|
||||
;
|
||||
|
||||
$this->assertEquals('http://test', $router->generate($oldname, $oldparameters, $oldReferenceType));
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony CMF package.
|
||||
*
|
||||
* (c) 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;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Tests the lazy route collection.
|
||||
*
|
||||
* @group cmf/routing
|
||||
*/
|
||||
class LazyRouteCollectionTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Tests the iterator without a paged route provider.
|
||||
*/
|
||||
public function testGetIterator()
|
||||
{
|
||||
$routeProvider = $this->createMock(RouteProviderInterface::class);
|
||||
$testRoutes = [
|
||||
'route_1' => new Route('/route-1'),
|
||||
'route_2"' => new Route('/route-2'),
|
||||
];
|
||||
$routeProvider->expects($this->exactly(2))
|
||||
->method('getRoutesByNames')
|
||||
->with(null)
|
||||
->will($this->returnValue($testRoutes));
|
||||
$lazyRouteCollection = new LazyRouteCollection($routeProvider);
|
||||
$this->assertEquals($testRoutes, iterator_to_array($lazyRouteCollection->getIterator()));
|
||||
$this->assertEquals($testRoutes, $lazyRouteCollection->all());
|
||||
}
|
||||
}
|
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony CMF package.
|
||||
*
|
||||
* (c) 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;
|
||||
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
/**
|
||||
* Tests the page route collection.
|
||||
*
|
||||
* @group cmf/routing
|
||||
*/
|
||||
class PagedRouteCollectionTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* Contains a mocked route provider.
|
||||
*
|
||||
* @var PagedRouteProviderInterface|MockObject
|
||||
*/
|
||||
private $routeProvider;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->routeProvider = $this->createMock(PagedRouteProviderInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests iterating a small amount of routes.
|
||||
*
|
||||
* @dataProvider providerIterator
|
||||
*/
|
||||
public function testIterator($amountRoutes, $routesLoadedInParallel, $expectedCalls = [])
|
||||
{
|
||||
$routes = [];
|
||||
for ($i = 0; $i < $amountRoutes; ++$i) {
|
||||
$routes['test_'.$i] = new Route("/example-$i");
|
||||
}
|
||||
$names = array_keys($routes);
|
||||
|
||||
$with = [];
|
||||
$will = [];
|
||||
foreach ($expectedCalls as $i => $range) {
|
||||
$with[] = [$range[0], $range[1]];
|
||||
$will[] = array_slice($routes, $range[0], $range[1]);
|
||||
}
|
||||
$mocker = $this->routeProvider->expects($this->exactly(\count($expectedCalls)))
|
||||
->method('getRoutesPaged');
|
||||
\call_user_func_array([$mocker, 'withConsecutive'], $with);
|
||||
\call_user_func_array([$mocker, 'willReturnOnConsecutiveCalls'], $will);
|
||||
|
||||
$route_collection = new PagedRouteCollection($this->routeProvider, $routesLoadedInParallel);
|
||||
|
||||
$counter = 0;
|
||||
foreach ($route_collection as $route_name => $route) {
|
||||
// Ensure the route did not changed.
|
||||
$this->assertEquals($routes[$route_name], $route);
|
||||
// Ensure that the order did not changed.
|
||||
$this->assertEquals($route_name, $names[$counter]);
|
||||
++$counter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test data for testIterator().
|
||||
*/
|
||||
public function providerIterator()
|
||||
{
|
||||
$data = [];
|
||||
// Non total routes.
|
||||
$data[] = [0, 20, [[0, 20]]];
|
||||
// Less total routes than loaded in parallel.
|
||||
$data[] = [10, 20, [[0, 20]]];
|
||||
// Exact the same amount of routes then loaded in parallel.
|
||||
$data[] = [20, 20, [[0, 20], [20, 20]]];
|
||||
// Less than twice the amount.
|
||||
$data[] = [39, 20, [[0, 20], [20, 20]]];
|
||||
// More total routes than loaded in parallel.
|
||||
$data[] = [40, 20, [[0, 20], [20, 20], [40, 20]]];
|
||||
$data[] = [41, 20, [[0, 20], [20, 20], [40, 20]]];
|
||||
// why not.
|
||||
$data[] = [42, 23, [[0, 23], [23, 23]]];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the count() method.
|
||||
*/
|
||||
public function testCount()
|
||||
{
|
||||
$this->routeProvider->expects($this->once())
|
||||
->method('getRoutesCount')
|
||||
->will($this->returnValue(12));
|
||||
$routeCollection = new PagedRouteCollection($this->routeProvider);
|
||||
$this->assertEquals(12, $routeCollection->count());
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the rewind method once the iterator is at the end.
|
||||
*/
|
||||
public function testIteratingAndRewind()
|
||||
{
|
||||
$routes = [];
|
||||
for ($i = 0; $i < 30; ++$i) {
|
||||
$routes['test_'.$i] = new Route("/example-$i");
|
||||
}
|
||||
$this->routeProvider->expects($this->any())
|
||||
->method('getRoutesPaged')
|
||||
->will($this->returnValueMap([
|
||||
[0, 10, array_slice($routes, 0, 10)],
|
||||
[10, 10, array_slice($routes, 9, 10)],
|
||||
[20, 10, []],
|
||||
]));
|
||||
|
||||
$routeCollection = new PagedRouteCollection($this->routeProvider, 10);
|
||||
|
||||
// Force the iterating process.
|
||||
$routeCollection->rewind();
|
||||
for ($i = 0; $i < 29; ++$i) {
|
||||
$routeCollection->next();
|
||||
}
|
||||
$routeCollection->rewind();
|
||||
|
||||
$this->assertEquals('test_0', $routeCollection->key());
|
||||
$this->assertEquals($routes['test_0'], $routeCollection->current());
|
||||
}
|
||||
}
|
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony CMF package.
|
||||
*
|
||||
* (c) 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 PHPUnit\Framework\MockObject\MockObject;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Cmf\Component\Routing\ProviderBasedGenerator;
|
||||
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
||||
use Symfony\Cmf\Component\Routing\RouteProviderInterface;
|
||||
use Symfony\Component\Routing\CompiledRoute;
|
||||
use Symfony\Component\Routing\Exception\InvalidParameterException;
|
||||
use Symfony\Component\Routing\Exception\RouteNotFoundException;
|
||||
use Symfony\Component\Routing\RequestContext;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\Route as SymfonyRoute;
|
||||
|
||||
class ProviderBasedGeneratorTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var Route|MockObject
|
||||
*/
|
||||
private $routeDocument;
|
||||
|
||||
/**
|
||||
* @var CompiledRoute|MockObject
|
||||
*/
|
||||
private $routeCompiled;
|
||||
|
||||
/**
|
||||
* @var RouteProviderInterface|MockObject
|
||||
*/
|
||||
private $provider;
|
||||
|
||||
/**
|
||||
* @var ProviderBasedGenerator
|
||||
*/
|
||||
private $generator;
|
||||
|
||||
/**
|
||||
* @var RequestContext|MockObject
|
||||
*/
|
||||
private $context;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->routeDocument = $this->createMock(Route::class);
|
||||
$this->routeCompiled = $this->createMock(CompiledRoute::class);
|
||||
$this->provider = $this->createMock(RouteProviderInterface::class);
|
||||
$this->context = $this->createMock(RequestContext::class);
|
||||
|
||||
$this->generator = new TestableProviderBasedGenerator($this->provider);
|
||||
}
|
||||
|
||||
public function testGenerateFromName(): void
|
||||
{
|
||||
$name = 'foo/bar';
|
||||
|
||||
$this->provider->expects($this->once())
|
||||
->method('getRouteByName')
|
||||
->with($name)
|
||||
->willReturn($this->routeDocument)
|
||||
;
|
||||
$this->routeDocument->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$this->assertEquals('result_url', $this->generator->generate($name));
|
||||
}
|
||||
|
||||
public function testGenerateNotFound(): void
|
||||
{
|
||||
$name = 'foo/bar';
|
||||
|
||||
$this->provider->expects($this->once())
|
||||
->method('getRouteByName')
|
||||
->with($name)
|
||||
->willReturn(null)
|
||||
;
|
||||
|
||||
$this->expectException(RouteNotFoundException::class);
|
||||
$this->generator->generate($name);
|
||||
}
|
||||
|
||||
public function testGenerateFromRoute(): void
|
||||
{
|
||||
$this->provider->expects($this->never())
|
||||
->method('getRouteByName')
|
||||
;
|
||||
$this->routeDocument->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$url = $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [
|
||||
RouteObjectInterface::ROUTE_OBJECT => $this->routeDocument,
|
||||
]);
|
||||
$this->assertEquals('result_url', $url);
|
||||
}
|
||||
|
||||
public function testRemoveRouteObject(): void
|
||||
{
|
||||
$url = $this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [
|
||||
RouteObjectInterface::ROUTE_OBJECT => new Proxy('/path'),
|
||||
]);
|
||||
|
||||
$this->assertEquals('result_url', $url);
|
||||
}
|
||||
|
||||
/**
|
||||
* @group legacy
|
||||
*
|
||||
* @expectedDeprecation Passing an object as route name is deprecated since version 2.3. Pass the `RouteObjectInterface::OBJECT_BASED_ROUTE_NAME` as route name and the object in the parameters with key `RouteObjectInterface::ROUTE_OBJECT`
|
||||
*/
|
||||
public function testGenerateFromRouteLegacy(): void
|
||||
{
|
||||
$this->provider->expects($this->never())
|
||||
->method('getRouteByName')
|
||||
;
|
||||
$this->routeDocument->expects($this->once())
|
||||
->method('compile')
|
||||
->willReturn($this->routeCompiled)
|
||||
;
|
||||
|
||||
$this->assertEquals('result_url', $this->generator->generate($this->routeDocument));
|
||||
}
|
||||
|
||||
public function testSupports(): void
|
||||
{
|
||||
$this->assertTrue($this->generator->supports('foo/bar'));
|
||||
$this->assertTrue($this->generator->supports($this->routeDocument));
|
||||
$this->assertFalse($this->generator->supports($this));
|
||||
}
|
||||
|
||||
public function testGetRouteDebugMessage(): void
|
||||
{
|
||||
$this->assertStringContainsString('/some/key', $this->generator->getRouteDebugMessage(new RouteObject()));
|
||||
$this->assertStringContainsString('/de/test', $this->generator->getRouteDebugMessage(new Route('/de/test')));
|
||||
$this->assertStringContainsString('/some/route', $this->generator->getRouteDebugMessage('/some/route'));
|
||||
$this->assertStringContainsString('a:1:{s:10:"route_name";s:7:"example";}', $this->generator->getRouteDebugMessage(['route_name' => 'example']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the generate method with passing in a route object into generate().
|
||||
*/
|
||||
public function testGenerateByRoute(): void
|
||||
{
|
||||
$this->generator = new ProviderBasedGenerator($this->provider);
|
||||
|
||||
// Setup a route with a numeric parameter, but pass in a string, so it
|
||||
// fails and getRouteDebugMessage should be triggered.
|
||||
$route = new Route('/test');
|
||||
$route->setPath('/test/{number}');
|
||||
$route->setRequirement('number', '\+d');
|
||||
|
||||
$this->generator->setStrictRequirements(true);
|
||||
|
||||
$context = new RequestContext();
|
||||
$this->generator->setContext($context);
|
||||
|
||||
$this->expectException(InvalidParameterException::class);
|
||||
$this->generator->generate(RouteObjectInterface::OBJECT_BASED_ROUTE_NAME, [
|
||||
RouteObjectInterface::ROUTE_OBJECT => $route,
|
||||
'number' => 'string',
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite doGenerate to reduce amount of mocking needed.
|
||||
*/
|
||||
class TestableProviderBasedGenerator extends ProviderBasedGenerator
|
||||
{
|
||||
protected function doGenerate($variables, $defaults, $requirements, $tokens, $parameters, $name, $referenceType, $hostTokens, array $requiredSchemes = [])
|
||||
{
|
||||
$url = 'result_url';
|
||||
if ($parameters && $query = http_build_query($parameters, '', '&', PHP_QUERY_RFC3986)) {
|
||||
$url .= '?'.$query;
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
|
||||
class RouteObject implements RouteObjectInterface
|
||||
{
|
||||
public function getRouteKey(): string
|
||||
{
|
||||
return '/some/key';
|
||||
}
|
||||
|
||||
public function getContent(): ?object
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class Proxy extends SymfonyRoute
|
||||
{
|
||||
public $__isInitialized__ = true;
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony CMF package.
|
||||
*
|
||||
* (c) 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\Unit\Routing;
|
||||
|
||||
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
|
||||
use Symfony\Component\Routing\Route as SymfonyRoute;
|
||||
|
||||
class RouteMock extends SymfonyRoute implements RouteObjectInterface
|
||||
{
|
||||
private $locale;
|
||||
|
||||
public function setLocale($locale)
|
||||
{
|
||||
$this->locale = $locale;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public function getDefaults()
|
||||
{
|
||||
$defaults = [];
|
||||
if (null !== $this->locale) {
|
||||
$defaults['_locale'] = $this->locale;
|
||||
}
|
||||
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
public function getRequirement($key)
|
||||
{
|
||||
if ('_locale' !== $key) {
|
||||
throw new \Exception();
|
||||
}
|
||||
|
||||
return $this->locale;
|
||||
}
|
||||
|
||||
public function getRouteKey()
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user