default services conflit ?

This commit is contained in:
armansansd
2022-04-27 11:30:43 +02:00
parent 28190a5749
commit 8bb1064a3b
8132 changed files with 900138 additions and 426 deletions

View File

@@ -0,0 +1,106 @@
<?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\Candidates;
use PHPUnit\Framework\TestCase;
use Symfony\Cmf\Component\Routing\Candidates\Candidates;
use Symfony\Component\HttpFoundation\Request;
class CandidatesTest extends TestCase
{
/**
* Everything is a candidate.
*/
public function testIsCandidate()
{
$candidates = new Candidates();
$this->assertTrue($candidates->isCandidate('/routes'));
$this->assertTrue($candidates->isCandidate('/routes/my/path'));
}
/**
* Nothing should be called on the query builder.
*/
public function testRestrictQuery()
{
$candidates = new Candidates();
$candidates->restrictQuery(null);
}
public function testGetCandidates()
{
$request = Request::create('/my/path.html');
$candidates = new Candidates();
$paths = $candidates->getCandidates($request);
$this->assertEquals(
[
'/my/path.html',
'/my/path',
'/my',
'/',
],
$paths
);
}
public function testGetCandidatesLocales()
{
$candidates = new Candidates(['de', 'fr']);
$request = Request::create('/fr/path.html');
$paths = $candidates->getCandidates($request);
$this->assertEquals(
[
'/fr/path.html',
'/fr/path',
'/fr',
'/',
'/path.html',
'/path',
],
$paths
);
$request = Request::create('/it/path.html');
$paths = $candidates->getCandidates($request);
$this->assertEquals(
[
'/it/path.html',
'/it/path',
'/it',
'/',
],
$paths
);
}
public function testGetCandidatesLimit()
{
$candidates = new Candidates([], 1);
$request = Request::create('/my/path/is/deep.html');
$paths = $candidates->getCandidates($request);
$this->assertEquals(
[
'/my/path/is/deep.html',
'/my/path/is/deep',
],
$paths
);
}
}

View File

@@ -0,0 +1,72 @@
<?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\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Cmf\Component\Routing\DependencyInjection\Compiler\RegisterRouteEnhancersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
class RegisterRouteEnhancersPassTest extends TestCase
{
public function testRouteEnhancerPass()
{
$serviceIds = [
'test_enhancer' => [
0 => [
'id' => 'foo_enhancer',
],
],
];
$builder = $this->createMock(ContainerBuilder::class);
$definition = new Definition('router');
$builder->expects($this->atLeastOnce())
->method('hasDefinition')
->with('cmf_routing.dynamic_router')
->will($this->returnValue(true))
;
$builder->expects($this->any())
->method('findTaggedServiceIds')
->will($this->returnValue($serviceIds))
;
$builder->expects($this->any())
->method('getDefinition')
->with('cmf_routing.dynamic_router')
->will($this->returnValue($definition))
;
$pass = new RegisterRouteEnhancersPass();
$pass->process($builder);
$calls = $definition->getMethodCalls();
$this->assertEquals(1, count($calls));
$this->assertEquals('addRouteEnhancer', $calls[0][0]);
}
/**
* If there is no dynamic router defined in the container builder, nothing
* should be processed.
*/
public function testNoDynamicRouter()
{
$builder = $this->createMock(ContainerBuilder::class);
$builder->expects($this->once())
->method('hasDefinition')
->with('cmf_routing.dynamic_router')
->will($this->returnValue(false))
;
$pass = new RegisterRouteEnhancersPass();
$pass->process($builder);
}
}

View File

@@ -0,0 +1,97 @@
<?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\Routing\Tests\Unit\DependencyInjection\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Cmf\Component\Routing\DependencyInjection\Compiler\RegisterRoutersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
class RegisterRoutersPassTest extends TestCase
{
/**
* @dataProvider getValidRoutersData
*/
public function testValidRouters($name, $priority = null)
{
$services = [];
$services[$name] = [0 => ['priority' => $priority]];
$priority = $priority ?: 0;
$definition = $this->createMock(Definition::class);
$definition->expects($this->atLeastOnce())
->method('addMethodCall')
->with($this->equalTo('add'), $this->callback(function ($arg) use ($name, $priority) {
if (!$arg[0] instanceof Reference || $name !== $arg[0]->__toString()) {
return false;
}
if ($priority !== $arg[1]) {
return false;
}
return true;
}));
$builder = $this->createMock(ContainerBuilder::class);
$builder->expects($this->any())
->method('hasDefinition')
->with('cmf_routing.router')
->will($this->returnValue(true));
$builder->expects($this->atLeastOnce())
->method('findTaggedServiceIds')
->will($this->returnValue($services));
$builder->expects($this->atLeastOnce())
->method('getDefinition')
->will($this->returnValue($definition));
$registerRoutersPass = new RegisterRoutersPass();
$registerRoutersPass->process($builder);
}
public function getValidRoutersData()
{
return [
['my_router'],
['my_primary_router', 99],
['my_router', 0],
];
}
/**
* If there is no chain router defined in the container builder, nothing
* should be processed.
*/
public function testNoChainRouter()
{
$builder = $this->createMock(ContainerBuilder::class);
$builder->expects($this->once())
->method('hasDefinition')
->with('cmf_routing.router')
->will($this->returnValue(false))
;
$builder->expects($this->never())
->method('findTaggedServiceIds')
;
$builder->expects($this->never())
->method('getDefinition')
;
$registerRoutersPass = new RegisterRoutersPass();
$registerRoutersPass->process($builder);
}
}

View File

@@ -0,0 +1,81 @@
<?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\Enhancer;
use PHPUnit\Framework\TestCase;
use Symfony\Cmf\Component\Routing\ContentRepositoryInterface;
use Symfony\Cmf\Component\Routing\Enhancer\ContentRepositoryEnhancer;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Request;
class ContentRepositoryEnhancerTest extends TestCase
{
/**
* {@inheritdoc}
*/
public function setUp(): void
{
$cRepository = $this->createMock(ContentRepositoryInterface::class);
$cRepository
->method('findById')
->will($this->returnValue('document'))
;
$this->mapper = new ContentRepositoryEnhancer($cRepository);
$this->request = Request::create('/test');
}
/**
* @dataProvider dataEnhancer
*/
public function testEnhancer($defaults, $expected)
{
$this->assertEquals($expected, $this->mapper->enhance($defaults, $this->request));
}
/**
* @return array
*/
public function dataEnhancer()
{
return [
'empty' => [[], []],
'with content_id' => [
[
RouteObjectInterface::CONTENT_ID => 'Simple:1',
],
[
RouteObjectInterface::CONTENT_ID => 'Simple:1',
RouteObjectInterface::CONTENT_OBJECT => 'document',
],
],
'with content_id and content' => [
[
RouteObjectInterface::CONTENT_ID => 'Simple:1',
RouteObjectInterface::CONTENT_OBJECT => 'exist object',
],
[
RouteObjectInterface::CONTENT_ID => 'Simple:1',
RouteObjectInterface::CONTENT_OBJECT => 'exist object',
],
],
'with content' => [
[
RouteObjectInterface::CONTENT_OBJECT => 'exist object',
],
[
RouteObjectInterface::CONTENT_OBJECT => 'exist object',
],
],
];
}
}

View File

@@ -0,0 +1,71 @@
<?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\Enhancer;
use PHPUnit\Framework\TestCase;
use Symfony\Cmf\Component\Routing\Enhancer\FieldByClassEnhancer;
use Symfony\Component\HttpFoundation\Request;
class FieldByClassEnhancerTest extends TestCase
{
private $request;
/**
* @var FieldByClassEnhancer
*/
private $mapper;
private $document;
public function setUp(): void
{
$this->document = $this->createMock(RouteObject::class);
$mapping = [RouteObject::class => 'cmf_content.controller:indexAction'];
$this->mapper = new FieldByClassEnhancer('_content', '_controller', $mapping);
$this->request = Request::create('/test');
}
public function testClassFoundInMapping()
{
// this is the mock, thus a child class to make sure we properly check with instanceof
$defaults = ['_content' => $this->document];
$expected = [
'_content' => $this->document,
'_controller' => 'cmf_content.controller:indexAction',
];
$this->assertEquals($expected, $this->mapper->enhance($defaults, $this->request));
}
public function testFieldAlreadyThere()
{
$defaults = [
'_content' => $this->document,
'_controller' => 'custom.controller:indexAction',
];
$this->assertEquals($defaults, $this->mapper->enhance($defaults, $this->request));
}
public function testClassNotFoundInMapping()
{
$defaults = ['_content' => $this];
$this->assertEquals($defaults, $this->mapper->enhance($defaults, $this->request));
}
public function testNoClass()
{
$defaults = ['foo' => 'bar'];
$this->assertEquals($defaults, $this->mapper->enhance($defaults, $this->request));
}
}

View File

@@ -0,0 +1,68 @@
<?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\Mapper;
use PHPUnit\Framework\TestCase;
use Symfony\Cmf\Component\Routing\Enhancer\FieldMapEnhancer;
use Symfony\Component\HttpFoundation\Request;
class FieldMapEnhancerTest extends TestCase
{
/**
* @var Request
*/
private $request;
/**
* @var FieldMapEnhancer
*/
private $enhancer;
public function setUp(): void
{
$this->request = Request::create('/test');
$mapping = ['static_pages' => 'cmf_content.controller:indexAction'];
$this->enhancer = new FieldMapEnhancer('type', '_controller', $mapping);
}
public function testFieldFoundInMapping()
{
$defaults = ['type' => 'static_pages'];
$expected = [
'type' => 'static_pages',
'_controller' => 'cmf_content.controller:indexAction',
];
$this->assertEquals($expected, $this->enhancer->enhance($defaults, $this->request));
}
public function testFieldAlreadyThere()
{
$defaults = [
'type' => 'static_pages',
'_controller' => 'custom.controller:indexAction',
];
$this->assertEquals($defaults, $this->enhancer->enhance($defaults, $this->request));
}
public function testNoType()
{
$defaults = [];
$this->assertEquals([], $this->enhancer->enhance($defaults, $this->request));
}
public function testNotFoundInMapping()
{
$defaults = ['type' => 'unknown_route'];
$this->assertEquals($defaults, $this->enhancer->enhance($defaults, $this->request));
}
}

View File

@@ -0,0 +1,70 @@
<?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\Enhancer;
use PHPUnit\Framework\TestCase;
use Symfony\Cmf\Component\Routing\Enhancer\FieldPresenceEnhancer;
use Symfony\Component\HttpFoundation\Request;
class FieldPresenceEnhancerTest extends TestCase
{
/**
* @var FieldPresenceEnhancer
*/
private $mapper;
private $request;
public function setUp(): void
{
$this->mapper = new FieldPresenceEnhancer('_template', '_controller', 'cmf_content.controller:indexAction');
$this->request = Request::create('/test');
}
public function testHasTemplate()
{
$defaults = ['_template' => 'Bundle:Topic:template.html.twig'];
$expected = [
'_template' => 'Bundle:Topic:template.html.twig',
'_controller' => 'cmf_content.controller:indexAction',
];
$this->assertEquals($expected, $this->mapper->enhance($defaults, $this->request));
}
public function testFieldAlreadyThere()
{
$defaults = [
'_template' => 'Bundle:Topic:template.html.twig',
'_controller' => 'custom.controller:indexAction',
];
$this->assertEquals($defaults, $this->mapper->enhance($defaults, $this->request));
}
public function testHasNoSourceValue()
{
$defaults = ['foo' => 'bar'];
$this->assertEquals($defaults, $this->mapper->enhance($defaults, $this->request));
}
public function testHasNoSource()
{
$this->mapper = new FieldPresenceEnhancer(null, '_controller', 'cmf_content.controller:indexAction');
$defaults = ['foo' => 'bar'];
$expected = [
'foo' => 'bar',
'_controller' => 'cmf_content.controller:indexAction',
];
$this->assertEquals($expected, $this->mapper->enhance($defaults, $this->request));
}
}

View File

@@ -0,0 +1,87 @@
<?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\Enhancer;
use PHPUnit\Framework\TestCase;
use Symfony\Cmf\Component\Routing\Enhancer\RouteContentEnhancer;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
class RouteContentEnhancerTest extends TestCase
{
/**
* @var RouteContentEnhancer
*/
private $mapper;
private $document;
private $request;
public function setUp(): void
{
$this->document = $this->createMock(RouteObject::class);
$this->mapper = new RouteContentEnhancer(RouteObjectInterface::ROUTE_OBJECT, '_content');
$this->request = Request::create('/test');
}
public function testContent()
{
$targetDocument = new TargetDocument();
$this->document->expects($this->once())
->method('getContent')
->will($this->returnValue($targetDocument));
$defaults = [RouteObjectInterface::ROUTE_OBJECT => $this->document];
$expected = [RouteObjectInterface::ROUTE_OBJECT => $this->document, '_content' => $targetDocument];
$this->assertEquals($expected, $this->mapper->enhance($defaults, $this->request));
}
public function testFieldAlreadyThere()
{
$this->document->expects($this->never())
->method('getContent')
;
$defaults = [RouteObjectInterface::ROUTE_OBJECT => $this->document, '_content' => 'foo'];
$this->assertEquals($defaults, $this->mapper->enhance($defaults, $this->request));
}
public function testNoContent()
{
$this->document->expects($this->once())
->method('getContent')
->will($this->returnValue(null));
$defaults = [RouteObjectInterface::ROUTE_OBJECT => $this->document];
$this->assertEquals($defaults, $this->mapper->enhance($defaults, $this->request));
}
public function testNoCmfRoute()
{
$defaults = [RouteObjectInterface::ROUTE_OBJECT => $this->createMock(Route::class)];
$this->assertEquals($defaults, $this->mapper->enhance($defaults, $this->request));
}
}
class TargetDocument
{
}
class UnknownDocument
{
}

View File

@@ -0,0 +1,26 @@
<?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\Enhancer;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\Routing\Route;
/**
* Empty abstract class to be able to mock an object that both extends Route
* and implements RouteObjectInterface.
*/
abstract class RouteObject extends Route implements RouteObjectInterface
{
public function getRouteKey()
{
}
}

View File

@@ -0,0 +1,141 @@
<?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\NestedMatcher;
use PHPUnit\Framework\TestCase;
use Symfony\Cmf\Component\Routing\NestedMatcher\FinalMatcherInterface;
use Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher;
use Symfony\Cmf\Component\Routing\NestedMatcher\RouteFilterInterface;
use Symfony\Cmf\Component\Routing\RouteProviderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
class NestedMatcherTest extends TestCase
{
private $provider;
private $routeFilter1;
private $routeFilter2;
private $finalMatcher;
public function setUp(): void
{
$this->provider = $this->createMock(RouteProviderInterface::class);
$this->routeFilter1 = $this->createMock(RouteFilterInterface::class);
$this->routeFilter2 = $this->createMock(RouteFilterInterface::class);
$this->finalMatcher = $this->createMock(FinalMatcherInterface::class);
}
public function testNestedMatcher()
{
$request = Request::create('/path/one');
$routeCollection = new RouteCollection();
$route = $this->createMock(Route::class);
$routeCollection->add('route', $route);
$this->provider->expects($this->once())
->method('getRouteCollectionForRequest')
->with($request)
->will($this->returnValue($routeCollection))
;
$this->routeFilter1->expects($this->once())
->method('filter')
->with($routeCollection, $request)
->will($this->returnValue($routeCollection))
;
$this->routeFilter2->expects($this->once())
->method('filter')
->with($routeCollection, $request)
->will($this->returnValue($routeCollection))
;
$this->finalMatcher->expects($this->once())
->method('finalMatch')
->with($routeCollection, $request)
->will($this->returnValue(['foo' => 'bar']))
;
$matcher = new NestedMatcher($this->provider, $this->finalMatcher);
$matcher->addRouteFilter($this->routeFilter1);
$matcher->addRouteFilter($this->routeFilter2);
$attributes = $matcher->matchRequest($request);
$this->assertEquals(['foo' => 'bar'], $attributes);
}
/**
* Test priorities and exception handling.
*/
public function testNestedMatcherPriority()
{
$request = Request::create('/path/one');
$routeCollection = new RouteCollection();
$route = $this->createMock(Route::class);
$routeCollection->add('route', $route);
$wrongProvider = $this->createMock(RouteProviderInterface::class);
$wrongProvider->expects($this->never())
->method('getRouteCollectionForRequest')
;
$this->provider->expects($this->once())
->method('getRouteCollectionForRequest')
->with($request)
->will($this->returnValue($routeCollection))
;
$this->routeFilter1->expects($this->once())
->method('filter')
->with($routeCollection, $request)
->will($this->throwException(new ResourceNotFoundException()))
;
$this->routeFilter2->expects($this->never())
->method('filter')
;
$this->finalMatcher->expects($this->never())
->method('finalMatch')
;
$matcher = new NestedMatcher($wrongProvider, $this->finalMatcher);
$matcher->setRouteProvider($this->provider);
$matcher->addRouteFilter($this->routeFilter2, 10);
$matcher->addRouteFilter($this->routeFilter1, 20);
try {
$matcher->matchRequest($request);
fail('nested matcher is eating exception');
} catch (ResourceNotFoundException $e) {
// expected
}
}
public function testProviderNoMatch()
{
$request = Request::create('/path/one');
$routeCollection = new RouteCollection();
$this->provider->expects($this->once())
->method('getRouteCollectionForRequest')
->with($request)
->will($this->returnValue($routeCollection))
;
$this->finalMatcher->expects($this->never())
->method('finalMatch')
;
$matcher = new NestedMatcher($this->provider, $this->finalMatcher);
$this->expectException(ResourceNotFoundException::class);
$matcher->matchRequest($request);
}
}

View File

@@ -0,0 +1,172 @@
<?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\NestedMatcher;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Cmf\Component\Routing\Tests\Unit\Routing\RouteMock;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\CompiledRoute;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;
class UrlMatcherTest extends TestCase
{
/**
* @var RouteMock|MockObject
*/
private $routeDocument;
/**
* @var CompiledRoute|MockObject
*/
private $routeCompiled;
/**
* @var UrlMatcher
*/
private $matcher;
/**
* @var RequestContext|MockObject
*/
private $context;
/**
* @var Request
*/
private $request;
/**
* @var string
*/
private $url = '/foo/bar';
public function setUp(): void
{
$this->routeDocument = $this->createMock(RouteMock::class);
$this->routeCompiled = $this->createMock(CompiledRoute::class);
$this->context = $this->createMock(RequestContext::class);
$this->request = Request::create($this->url);
$this->matcher = new UrlMatcher(new RouteCollection(), $this->context);
}
public function testMatchRouteKey()
{
$this->doTestMatchRouteKey($this->url);
}
public function testMatchNoKey()
{
$this->doTestMatchRouteKey(null);
}
public function doTestMatchRouteKey($routeKey)
{
$this->routeCompiled->expects($this->atLeastOnce())
->method('getStaticPrefix')
->will($this->returnValue($this->url))
;
$this->routeCompiled->expects($this->atLeastOnce())
->method('getRegex')
->will($this->returnValue('#'.str_replace('/', '\/', $this->url).'$#sD'))
;
$this->routeDocument->expects($this->atLeastOnce())
->method('compile')
->will($this->returnValue($this->routeCompiled))
;
$this->routeDocument->expects($this->atLeastOnce())
->method('getRouteKey')
->will($this->returnValue($routeKey))
;
$this->routeDocument->expects($this->atLeastOnce())
->method('getDefaults')
->will($this->returnValue(['foo' => 'bar']))
;
$mockCompiled = $this->createMock(CompiledRoute::class);
$mockCompiled->expects($this->any())
->method('getStaticPrefix')
->will($this->returnValue('/no/match'))
;
$mockRoute = $this->createMock(Route::class);
$mockRoute->expects($this->any())
->method('compile')
->will($this->returnValue($mockCompiled))
;
$routeCollection = new RouteCollection();
$routeCollection->add('some', $mockRoute);
$routeCollection->add('_company_more', $this->routeDocument);
$routeCollection->add('other', $mockRoute);
$results = $this->matcher->finalMatch($routeCollection, $this->request);
$expected = [
RouteObjectInterface::ROUTE_NAME => $routeKey ? $routeKey : '_company_more',
RouteObjectInterface::ROUTE_OBJECT => $this->routeDocument,
'foo' => 'bar',
];
$this->assertEquals($expected, $results);
}
public function testMatchNoRouteObject()
{
$this->routeCompiled->expects($this->atLeastOnce())
->method('getStaticPrefix')
->will($this->returnValue($this->url))
;
$this->routeCompiled->expects($this->atLeastOnce())
->method('getRegex')
->will($this->returnValue('#'.str_replace('/', '\/', $this->url).'$#sD'))
;
$this->routeDocument = $this->createMock(Route::class);
$this->routeDocument->expects($this->atLeastOnce())
->method('compile')
->will($this->returnValue($this->routeCompiled))
;
$this->routeDocument->expects($this->atLeastOnce())
->method('getDefaults')
->will($this->returnValue(['foo' => 'bar']))
;
$mockCompiled = $this->createMock(CompiledRoute::class);
$mockCompiled->expects($this->any())
->method('getStaticPrefix')
->will($this->returnValue('/no/match'))
;
$mockRoute = $this->createMock(Route::class);
$mockRoute->expects($this->any())
->method('compile')
->will($this->returnValue($mockCompiled))
;
$routeCollection = new RouteCollection();
$routeCollection->add('some', $mockRoute);
$routeCollection->add('_company_more', $this->routeDocument);
$routeCollection->add('other', $mockRoute);
$results = $this->matcher->finalMatch($routeCollection, $this->request);
$expected = [
RouteObjectInterface::ROUTE_NAME => '_company_more',
RouteObjectInterface::ROUTE_OBJECT => $this->routeDocument,
'foo' => 'bar',
];
$this->assertEquals($expected, $results);
}
}

View File

@@ -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
{
}

View File

@@ -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 [];
}
}

View File

@@ -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));
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View File

@@ -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;
}

View File

@@ -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;
}
}