1
0

提交代码

This commit is contained in:
2020-08-06 14:50:07 +08:00
parent 9d0d5f4be9
commit d7a848c824
11299 changed files with 1321854 additions and 0 deletions

View File

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Bundle;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionNotValidBundle\ExtensionNotValidBundle;
use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\ExtensionPresentBundle;
class BundleTest extends TestCase
{
public function testGetContainerExtension()
{
$bundle = new ExtensionPresentBundle();
$this->assertInstanceOf(
'Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\DependencyInjection\ExtensionPresentExtension',
$bundle->getContainerExtension()
);
}
/**
* @group legacy
*/
public function testGetContainerExtensionWithInvalidClass()
{
$this->expectException('LogicException');
$this->expectExceptionMessage('must implement Symfony\Component\DependencyInjection\Extension\ExtensionInterface');
$bundle = new ExtensionNotValidBundle();
$bundle->getContainerExtension();
}
public function testBundleNameIsGuessedFromClass()
{
$bundle = new GuessedNameBundle();
$this->assertSame('Symfony\Component\HttpKernel\Tests\Bundle', $bundle->getNamespace());
$this->assertSame('GuessedNameBundle', $bundle->getName());
}
public function testBundleNameCanBeExplicitlyProvided()
{
$bundle = new NamedBundle();
$this->assertSame('ExplicitlyNamedBundle', $bundle->getName());
$this->assertSame('Symfony\Component\HttpKernel\Tests\Bundle', $bundle->getNamespace());
$this->assertSame('ExplicitlyNamedBundle', $bundle->getName());
}
}
class NamedBundle extends Bundle
{
public function __construct()
{
$this->name = 'ExplicitlyNamedBundle';
}
}
class GuessedNameBundle extends Bundle
{
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\CacheClearer;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\CacheClearer\ChainCacheClearer;
class ChainCacheClearerTest extends TestCase
{
protected static $cacheDir;
public static function setUpBeforeClass(): void
{
self::$cacheDir = tempnam(sys_get_temp_dir(), 'sf_cache_clearer_dir');
}
public static function tearDownAfterClass(): void
{
@unlink(self::$cacheDir);
}
public function testInjectClearersInConstructor()
{
$clearer = $this->getMockClearer();
$clearer
->expects($this->once())
->method('clear');
$chainClearer = new ChainCacheClearer([$clearer]);
$chainClearer->clear(self::$cacheDir);
}
protected function getMockClearer()
{
return $this->getMockBuilder('Symfony\Component\HttpKernel\CacheClearer\CacheClearerInterface')->getMock();
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\CacheClearer;
use PHPUnit\Framework\TestCase;
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\HttpKernel\CacheClearer\Psr6CacheClearer;
class Psr6CacheClearerTest extends TestCase
{
public function testClearPoolsInjectedInConstructor()
{
$pool = $this->getMockBuilder(CacheItemPoolInterface::class)->getMock();
$pool
->expects($this->once())
->method('clear');
(new Psr6CacheClearer(['pool' => $pool]))->clear('');
}
public function testClearPool()
{
$pool = $this->getMockBuilder(CacheItemPoolInterface::class)->getMock();
$pool
->expects($this->once())
->method('clear');
(new Psr6CacheClearer(['pool' => $pool]))->clearPool('pool');
}
public function testClearPoolThrowsExceptionOnUnreferencedPool()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('Cache pool not found: unknown');
(new Psr6CacheClearer())->clearPool('unknown');
}
}

View File

@@ -0,0 +1,79 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\CacheWarmer;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate;
class CacheWarmerAggregateTest extends TestCase
{
protected static $cacheDir;
public static function setUpBeforeClass(): void
{
self::$cacheDir = tempnam(sys_get_temp_dir(), 'sf_cache_warmer_dir');
}
public static function tearDownAfterClass(): void
{
@unlink(self::$cacheDir);
}
public function testInjectWarmersUsingConstructor()
{
$warmer = $this->getCacheWarmerMock();
$warmer
->expects($this->once())
->method('warmUp');
$aggregate = new CacheWarmerAggregate([$warmer]);
$aggregate->warmUp(self::$cacheDir);
}
public function testWarmupDoesCallWarmupOnOptionalWarmersWhenEnableOptionalWarmersIsEnabled()
{
$warmer = $this->getCacheWarmerMock();
$warmer
->expects($this->never())
->method('isOptional');
$warmer
->expects($this->once())
->method('warmUp');
$aggregate = new CacheWarmerAggregate([$warmer]);
$aggregate->enableOptionalWarmers();
$aggregate->warmUp(self::$cacheDir);
}
public function testWarmupDoesNotCallWarmupOnOptionalWarmersWhenEnableOptionalWarmersIsNotEnabled()
{
$warmer = $this->getCacheWarmerMock();
$warmer
->expects($this->once())
->method('isOptional')
->willReturn(true);
$warmer
->expects($this->never())
->method('warmUp');
$aggregate = new CacheWarmerAggregate([$warmer]);
$aggregate->warmUp(self::$cacheDir);
}
protected function getCacheWarmerMock()
{
$warmer = $this->getMockBuilder('Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface')
->disableOriginalConstructor()
->getMock();
return $warmer;
}
}

View File

@@ -0,0 +1,66 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\CacheWarmer;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmer;
class CacheWarmerTest extends TestCase
{
protected static $cacheFile;
public static function setUpBeforeClass(): void
{
self::$cacheFile = tempnam(sys_get_temp_dir(), 'sf_cache_warmer_dir');
}
public static function tearDownAfterClass(): void
{
@unlink(self::$cacheFile);
}
public function testWriteCacheFileCreatesTheFile()
{
$warmer = new TestCacheWarmer(self::$cacheFile);
$warmer->warmUp(\dirname(self::$cacheFile));
$this->assertFileExists(self::$cacheFile);
}
public function testWriteNonWritableCacheFileThrowsARuntimeException()
{
$this->expectException('RuntimeException');
$nonWritableFile = '/this/file/is/very/probably/not/writable';
$warmer = new TestCacheWarmer($nonWritableFile);
$warmer->warmUp(\dirname($nonWritableFile));
}
}
class TestCacheWarmer extends CacheWarmer
{
protected $file;
public function __construct($file)
{
$this->file = $file;
}
public function warmUp($cacheDir)
{
$this->writeCacheFile($this->file, 'content');
}
public function isOptional()
{
return false;
}
}

View File

@@ -0,0 +1,48 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Config;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\Config\FileLocator;
class FileLocatorTest extends TestCase
{
public function testLocate()
{
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\KernelInterface')->getMock();
$kernel
->expects($this->atLeastOnce())
->method('locateResource')
->with('@BundleName/some/path', null, true)
->willReturn('/bundle-name/some/path');
$locator = new FileLocator($kernel);
$this->assertEquals('/bundle-name/some/path', $locator->locate('@BundleName/some/path'));
$kernel
->expects($this->never())
->method('locateResource');
$this->expectException('LogicException');
$locator->locate('/some/path');
}
public function testLocateWithGlobalResourcePath()
{
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\KernelInterface')->getMock();
$kernel
->expects($this->atLeastOnce())
->method('locateResource')
->with('@BundleName/some/path', '/global/resource/path', false);
$locator = new FileLocator($kernel, '/global/resource/path');
$locator->locate('@BundleName/some/path', null, false);
}
}

View File

@@ -0,0 +1,109 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\NotTaggedControllerValueResolver;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
class NotTaggedControllerValueResolverTest extends TestCase
{
public function testDoSupportWhenControllerDoNotExists()
{
$resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));
$argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null);
$request = $this->requestWithAttributes(['_controller' => 'my_controller']);
$this->assertTrue($resolver->supports($request, $argument));
}
public function testDoNotSupportWhenControllerExists()
{
$resolver = new NotTaggedControllerValueResolver(new ServiceLocator([
'App\\Controller\\Mine::method' => function () {
return new ServiceLocator([
'dummy' => function () {
return new \stdClass();
},
]);
},
]));
$argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null);
$request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::method']);
$this->assertFalse($resolver->supports($request, $argument));
}
public function testDoNotSupportEmptyController()
{
$resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));
$argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null);
$request = $this->requestWithAttributes(['_controller' => '']);
$this->assertFalse($resolver->supports($request, $argument));
}
public function testController()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException');
$this->expectExceptionMessage('Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?');
$resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));
$argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null);
$request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::method']);
$this->assertTrue($resolver->supports($request, $argument));
$resolver->resolve($request, $argument);
}
public function testControllerWithATrailingBackSlash()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException');
$this->expectExceptionMessage('Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?');
$resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));
$argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null);
$request = $this->requestWithAttributes(['_controller' => '\\App\\Controller\\Mine::method']);
$this->assertTrue($resolver->supports($request, $argument));
$resolver->resolve($request, $argument);
}
public function testControllerWithMethodNameStartUppercase()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException');
$this->expectExceptionMessage('Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?');
$resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));
$argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null);
$request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::Method']);
$this->assertTrue($resolver->supports($request, $argument));
$resolver->resolve($request, $argument);
}
public function testControllerNameIsAnArray()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException');
$this->expectExceptionMessage('Could not resolve argument $dummy of "App\Controller\Mine::method()", maybe you forgot to register the controller as a service or missed tagging it with the "controller.service_arguments"?');
$resolver = new NotTaggedControllerValueResolver(new ServiceLocator([]));
$argument = new ArgumentMetadata('dummy', \stdClass::class, false, false, null);
$request = $this->requestWithAttributes(['_controller' => ['App\\Controller\\Mine', 'method']]);
$this->assertTrue($resolver->supports($request, $argument));
$resolver->resolve($request, $argument);
}
private function requestWithAttributes(array $attributes)
{
$request = Request::create('/');
foreach ($attributes as $name => $value) {
$request->attributes->set($name, $value);
}
return $request;
}
}

View File

@@ -0,0 +1,156 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\ServiceValueResolver;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass;
class ServiceValueResolverTest extends TestCase
{
public function testDoNotSupportWhenControllerDoNotExists()
{
$resolver = new ServiceValueResolver(new ServiceLocator([]));
$argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);
$request = $this->requestWithAttributes(['_controller' => 'my_controller']);
$this->assertFalse($resolver->supports($request, $argument));
}
public function testExistingController()
{
$resolver = new ServiceValueResolver(new ServiceLocator([
'App\\Controller\\Mine::method' => function () {
return new ServiceLocator([
'dummy' => function () {
return new DummyService();
},
]);
},
]));
$request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::method']);
$argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);
$this->assertTrue($resolver->supports($request, $argument));
$this->assertYieldEquals([new DummyService()], $resolver->resolve($request, $argument));
}
public function testExistingControllerWithATrailingBackSlash()
{
$resolver = new ServiceValueResolver(new ServiceLocator([
'App\\Controller\\Mine::method' => function () {
return new ServiceLocator([
'dummy' => function () {
return new DummyService();
},
]);
},
]));
$request = $this->requestWithAttributes(['_controller' => '\\App\\Controller\\Mine::method']);
$argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);
$this->assertTrue($resolver->supports($request, $argument));
$this->assertYieldEquals([new DummyService()], $resolver->resolve($request, $argument));
}
public function testExistingControllerWithMethodNameStartUppercase()
{
$resolver = new ServiceValueResolver(new ServiceLocator([
'App\\Controller\\Mine::method' => function () {
return new ServiceLocator([
'dummy' => function () {
return new DummyService();
},
]);
},
]));
$request = $this->requestWithAttributes(['_controller' => 'App\\Controller\\Mine::Method']);
$argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);
$this->assertTrue($resolver->supports($request, $argument));
$this->assertYieldEquals([new DummyService()], $resolver->resolve($request, $argument));
}
public function testControllerNameIsAnArray()
{
$resolver = new ServiceValueResolver(new ServiceLocator([
'App\\Controller\\Mine::method' => function () {
return new ServiceLocator([
'dummy' => function () {
return new DummyService();
},
]);
},
]));
$request = $this->requestWithAttributes(['_controller' => ['App\\Controller\\Mine', 'method']]);
$argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);
$this->assertTrue($resolver->supports($request, $argument));
$this->assertYieldEquals([new DummyService()], $resolver->resolve($request, $argument));
}
public function testErrorIsTruncated()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException');
$this->expectExceptionMessage('Cannot autowire argument $dummy of "Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver\DummyController::index()": it references class "Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver\DummyService" but no such service exists.');
$container = new ContainerBuilder();
$container->addCompilerPass(new RegisterControllerArgumentLocatorsPass());
$container->register('argument_resolver.service', ServiceValueResolver::class)->addArgument(null)->setPublic(true);
$container->register(DummyController::class)->addTag('controller.service_arguments')->setPublic(true);
$container->compile();
$request = $this->requestWithAttributes(['_controller' => [DummyController::class, 'index']]);
$argument = new ArgumentMetadata('dummy', DummyService::class, false, false, null);
$container->get('argument_resolver.service')->resolve($request, $argument)->current();
}
private function requestWithAttributes(array $attributes)
{
$request = Request::create('/');
foreach ($attributes as $name => $value) {
$request->attributes->set($name, $value);
}
return $request;
}
private function assertYieldEquals(array $expected, \Generator $generator)
{
$args = [];
foreach ($generator as $arg) {
$args[] = $arg;
}
$this->assertEquals($expected, $args);
}
}
class DummyService
{
}
class DummyController
{
public function index(DummyService $dummy)
{
}
}

View File

@@ -0,0 +1,76 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\TraceableValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\Stopwatch\Stopwatch;
class TraceableValueResolverTest extends TestCase
{
public function testTimingsInSupports()
{
$stopwatch = new Stopwatch();
$resolver = new TraceableValueResolver(new ResolverStub(), $stopwatch);
$argument = new ArgumentMetadata('dummy', 'string', false, false, null);
$request = new Request();
$this->assertTrue($resolver->supports($request, $argument));
$event = $stopwatch->getEvent(ResolverStub::class.'::supports');
$this->assertCount(1, $event->getPeriods());
}
public function testTimingsInResolve()
{
$stopwatch = new Stopwatch();
$resolver = new TraceableValueResolver(new ResolverStub(), $stopwatch);
$argument = new ArgumentMetadata('dummy', 'string', false, false, null);
$request = new Request();
$iterable = $resolver->resolve($request, $argument);
foreach ($iterable as $index => $resolved) {
$event = $stopwatch->getEvent(ResolverStub::class.'::resolve');
$this->assertTrue($event->isStarted());
$this->assertEmpty($event->getPeriods());
switch ($index) {
case 0:
$this->assertEquals('first', $resolved);
break;
case 1:
$this->assertEquals('second', $resolved);
break;
}
}
$event = $stopwatch->getEvent(ResolverStub::class.'::resolve');
$this->assertCount(1, $event->getPeriods());
}
}
class ResolverStub implements ArgumentValueResolverInterface
{
public function supports(Request $request, ArgumentMetadata $argument)
{
return true;
}
public function resolve(Request $request, ArgumentMetadata $argument)
{
yield 'first';
yield 'second';
}
}

View File

@@ -0,0 +1,326 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Controller;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\RequestAttributeValueResolver;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory;
use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\ExtendingRequest;
use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\ExtendingSession;
use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\NullableController;
use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\VariadicController;
class ArgumentResolverTest extends TestCase
{
/** @var ArgumentResolver */
private static $resolver;
public static function setUpBeforeClass(): void
{
$factory = new ArgumentMetadataFactory();
self::$resolver = new ArgumentResolver($factory);
}
public function testDefaultState()
{
$this->assertEquals(self::$resolver, new ArgumentResolver());
$this->assertNotEquals(self::$resolver, new ArgumentResolver(null, [new RequestAttributeValueResolver()]));
}
public function testGetArguments()
{
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$controller = [new self(), 'controllerWithFoo'];
$this->assertEquals(['foo'], self::$resolver->getArguments($request, $controller), '->getArguments() returns an array of arguments for the controller method');
}
public function testGetArgumentsReturnsEmptyArrayWhenNoArguments()
{
$request = Request::create('/');
$controller = [new self(), 'controllerWithoutArguments'];
$this->assertEquals([], self::$resolver->getArguments($request, $controller), '->getArguments() returns an empty array if the method takes no arguments');
}
public function testGetArgumentsUsesDefaultValue()
{
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$controller = [new self(), 'controllerWithFooAndDefaultBar'];
$this->assertEquals(['foo', null], self::$resolver->getArguments($request, $controller), '->getArguments() uses default values if present');
}
public function testGetArgumentsOverrideDefaultValueByRequestAttribute()
{
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$request->attributes->set('bar', 'bar');
$controller = [new self(), 'controllerWithFooAndDefaultBar'];
$this->assertEquals(['foo', 'bar'], self::$resolver->getArguments($request, $controller), '->getArguments() overrides default values if provided in the request attributes');
}
public function testGetArgumentsFromClosure()
{
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$controller = function ($foo) {};
$this->assertEquals(['foo'], self::$resolver->getArguments($request, $controller));
}
public function testGetArgumentsUsesDefaultValueFromClosure()
{
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$controller = function ($foo, $bar = 'bar') {};
$this->assertEquals(['foo', 'bar'], self::$resolver->getArguments($request, $controller));
}
public function testGetArgumentsFromInvokableObject()
{
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$controller = new self();
$this->assertEquals(['foo', null], self::$resolver->getArguments($request, $controller));
// Test default bar overridden by request attribute
$request->attributes->set('bar', 'bar');
$this->assertEquals(['foo', 'bar'], self::$resolver->getArguments($request, $controller));
}
public function testGetArgumentsFromFunctionName()
{
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$request->attributes->set('foobar', 'foobar');
$controller = __NAMESPACE__.'\controller_function';
$this->assertEquals(['foo', 'foobar'], self::$resolver->getArguments($request, $controller));
}
public function testGetArgumentsFailsOnUnresolvedValue()
{
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$request->attributes->set('foobar', 'foobar');
$controller = [new self(), 'controllerWithFooBarFoobar'];
try {
self::$resolver->getArguments($request, $controller);
$this->fail('->getArguments() throws a \RuntimeException exception if it cannot determine the argument value');
} catch (\Exception $e) {
$this->assertInstanceOf('\RuntimeException', $e, '->getArguments() throws a \RuntimeException exception if it cannot determine the argument value');
}
}
public function testGetArgumentsInjectsRequest()
{
$request = Request::create('/');
$controller = [new self(), 'controllerWithRequest'];
$this->assertEquals([$request], self::$resolver->getArguments($request, $controller), '->getArguments() injects the request');
}
public function testGetArgumentsInjectsExtendingRequest()
{
$request = ExtendingRequest::create('/');
$controller = [new self(), 'controllerWithExtendingRequest'];
$this->assertEquals([$request], self::$resolver->getArguments($request, $controller), '->getArguments() injects the request when extended');
}
public function testGetVariadicArguments()
{
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$request->attributes->set('bar', ['foo', 'bar']);
$controller = [new VariadicController(), 'action'];
$this->assertEquals(['foo', 'foo', 'bar'], self::$resolver->getArguments($request, $controller));
}
public function testGetVariadicArgumentsWithoutArrayInRequest()
{
$this->expectException('InvalidArgumentException');
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$request->attributes->set('bar', 'foo');
$controller = [new VariadicController(), 'action'];
self::$resolver->getArguments($request, $controller);
}
public function testGetArgumentWithoutArray()
{
$this->expectException('InvalidArgumentException');
$factory = new ArgumentMetadataFactory();
$valueResolver = $this->getMockBuilder(ArgumentValueResolverInterface::class)->getMock();
$resolver = new ArgumentResolver($factory, [$valueResolver]);
$valueResolver->expects($this->any())->method('supports')->willReturn(true);
$valueResolver->expects($this->any())->method('resolve')->willReturn('foo');
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$request->attributes->set('bar', 'foo');
$controller = [$this, 'controllerWithFooAndDefaultBar'];
$resolver->getArguments($request, $controller);
}
public function testIfExceptionIsThrownWhenMissingAnArgument()
{
$this->expectException('RuntimeException');
$request = Request::create('/');
$controller = [$this, 'controllerWithFoo'];
self::$resolver->getArguments($request, $controller);
}
public function testGetNullableArguments()
{
$request = Request::create('/');
$request->attributes->set('foo', 'foo');
$request->attributes->set('bar', new \stdClass());
$request->attributes->set('mandatory', 'mandatory');
$controller = [new NullableController(), 'action'];
$this->assertEquals(['foo', new \stdClass(), 'value', 'mandatory'], self::$resolver->getArguments($request, $controller));
}
public function testGetNullableArgumentsWithDefaults()
{
$request = Request::create('/');
$request->attributes->set('mandatory', 'mandatory');
$controller = [new NullableController(), 'action'];
$this->assertEquals([null, null, 'value', 'mandatory'], self::$resolver->getArguments($request, $controller));
}
public function testGetSessionArguments()
{
$session = new Session(new MockArraySessionStorage());
$request = Request::create('/');
$request->setSession($session);
$controller = [$this, 'controllerWithSession'];
$this->assertEquals([$session], self::$resolver->getArguments($request, $controller));
}
public function testGetSessionArgumentsWithExtendedSession()
{
$session = new ExtendingSession(new MockArraySessionStorage());
$request = Request::create('/');
$request->setSession($session);
$controller = [$this, 'controllerWithExtendingSession'];
$this->assertEquals([$session], self::$resolver->getArguments($request, $controller));
}
public function testGetSessionArgumentsWithInterface()
{
$session = $this->getMockBuilder(SessionInterface::class)->getMock();
$request = Request::create('/');
$request->setSession($session);
$controller = [$this, 'controllerWithSessionInterface'];
$this->assertEquals([$session], self::$resolver->getArguments($request, $controller));
}
public function testGetSessionMissMatchWithInterface()
{
$this->expectException('RuntimeException');
$session = $this->getMockBuilder(SessionInterface::class)->getMock();
$request = Request::create('/');
$request->setSession($session);
$controller = [$this, 'controllerWithExtendingSession'];
self::$resolver->getArguments($request, $controller);
}
public function testGetSessionMissMatchWithImplementation()
{
$this->expectException('RuntimeException');
$session = new Session(new MockArraySessionStorage());
$request = Request::create('/');
$request->setSession($session);
$controller = [$this, 'controllerWithExtendingSession'];
self::$resolver->getArguments($request, $controller);
}
public function testGetSessionMissMatchOnNull()
{
$this->expectException('RuntimeException');
$request = Request::create('/');
$controller = [$this, 'controllerWithExtendingSession'];
self::$resolver->getArguments($request, $controller);
}
public function __invoke($foo, $bar = null)
{
}
public function controllerWithFoo($foo)
{
}
public function controllerWithoutArguments()
{
}
protected function controllerWithFooAndDefaultBar($foo, $bar = null)
{
}
protected function controllerWithFooBarFoobar($foo, $bar, $foobar)
{
}
protected function controllerWithRequest(Request $request)
{
}
protected function controllerWithExtendingRequest(ExtendingRequest $request)
{
}
protected function controllerWithSession(Session $session)
{
}
protected function controllerWithSessionInterface(SessionInterface $session)
{
}
protected function controllerWithExtendingSession(ExtendingSession $session)
{
}
}
function controller_function($foo, $foobar)
{
}

View File

@@ -0,0 +1,259 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Controller;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ContainerControllerResolver;
class ContainerControllerResolverTest extends ControllerResolverTest
{
public function testGetControllerServiceWithSingleColon()
{
$service = new ControllerTestService('foo');
$container = $this->createMockContainer();
$container->expects($this->once())
->method('has')
->with('foo')
->willReturn(true);
$container->expects($this->once())
->method('get')
->with('foo')
->willReturn($service)
;
$resolver = $this->createControllerResolver(null, $container);
$request = Request::create('/');
$request->attributes->set('_controller', 'foo:action');
$controller = $resolver->getController($request);
$this->assertSame($service, $controller[0]);
$this->assertSame('action', $controller[1]);
}
public function testGetControllerService()
{
$service = new ControllerTestService('foo');
$container = $this->createMockContainer();
$container->expects($this->once())
->method('has')
->with('foo')
->willReturn(true);
$container->expects($this->once())
->method('get')
->with('foo')
->willReturn($service)
;
$resolver = $this->createControllerResolver(null, $container);
$request = Request::create('/');
$request->attributes->set('_controller', 'foo::action');
$controller = $resolver->getController($request);
$this->assertSame($service, $controller[0]);
$this->assertSame('action', $controller[1]);
}
public function testGetControllerInvokableService()
{
$service = new InvokableControllerService('bar');
$container = $this->createMockContainer();
$container->expects($this->once())
->method('has')
->with('foo')
->willReturn(true)
;
$container->expects($this->once())
->method('get')
->with('foo')
->willReturn($service)
;
$resolver = $this->createControllerResolver(null, $container);
$request = Request::create('/');
$request->attributes->set('_controller', 'foo');
$controller = $resolver->getController($request);
$this->assertSame($service, $controller);
}
public function testGetControllerInvokableServiceWithClassNameAsName()
{
$service = new InvokableControllerService('bar');
$container = $this->createMockContainer();
$container->expects($this->once())
->method('has')
->with(InvokableControllerService::class)
->willReturn(true)
;
$container->expects($this->once())
->method('get')
->with(InvokableControllerService::class)
->willReturn($service)
;
$resolver = $this->createControllerResolver(null, $container);
$request = Request::create('/');
$request->attributes->set('_controller', InvokableControllerService::class);
$controller = $resolver->getController($request);
$this->assertSame($service, $controller);
}
/**
* @dataProvider getControllers
*/
public function testInstantiateControllerWhenControllerStartsWithABackslash($controller)
{
$service = new ControllerTestService('foo');
$class = ControllerTestService::class;
$container = $this->createMockContainer();
$container->expects($this->once())->method('has')->with($class)->willReturn(true);
$container->expects($this->once())->method('get')->with($class)->willReturn($service);
$resolver = $this->createControllerResolver(null, $container);
$request = Request::create('/');
$request->attributes->set('_controller', $controller);
$controller = $resolver->getController($request);
$this->assertInstanceOf(ControllerTestService::class, $controller[0]);
$this->assertSame('action', $controller[1]);
}
public function getControllers()
{
return [
['\\'.ControllerTestService::class.'::action'],
['\\'.ControllerTestService::class.':action'],
];
}
public function testExceptionWhenUsingRemovedControllerServiceWithClassNameAsName()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('Controller "Symfony\Component\HttpKernel\Tests\Controller\ControllerTestService" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?');
$container = $this->getMockBuilder(Container::class)->getMock();
$container->expects($this->once())
->method('has')
->with(ControllerTestService::class)
->willReturn(false)
;
$container->expects($this->atLeastOnce())
->method('getRemovedIds')
->with()
->willReturn([ControllerTestService::class => true])
;
$resolver = $this->createControllerResolver(null, $container);
$request = Request::create('/');
$request->attributes->set('_controller', [ControllerTestService::class, 'action']);
$resolver->getController($request);
}
public function testExceptionWhenUsingRemovedControllerService()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('Controller "app.my_controller" cannot be fetched from the container because it is private. Did you forget to tag the service with "controller.service_arguments"?');
$container = $this->getMockBuilder(Container::class)->getMock();
$container->expects($this->once())
->method('has')
->with('app.my_controller')
->willReturn(false)
;
$container->expects($this->atLeastOnce())
->method('getRemovedIds')
->with()
->willReturn(['app.my_controller' => true])
;
$resolver = $this->createControllerResolver(null, $container);
$request = Request::create('/');
$request->attributes->set('_controller', 'app.my_controller');
$resolver->getController($request);
}
public function getUndefinedControllers()
{
$tests = parent::getUndefinedControllers();
$tests[0] = ['foo', \InvalidArgumentException::class, 'Controller "foo" does neither exist as service nor as class'];
$tests[1] = ['oof::bar', \InvalidArgumentException::class, 'Controller "oof" does neither exist as service nor as class'];
$tests[2] = [['oof', 'bar'], \InvalidArgumentException::class, 'Controller "oof" does neither exist as service nor as class'];
$tests[] = [
[ControllerTestService::class, 'action'],
\InvalidArgumentException::class,
'Controller "Symfony\Component\HttpKernel\Tests\Controller\ControllerTestService" has required constructor arguments and does not exist in the container. Did you forget to define such a service?',
];
$tests[] = [
ControllerTestService::class.'::action',
\InvalidArgumentException::class, 'Controller "Symfony\Component\HttpKernel\Tests\Controller\ControllerTestService" has required constructor arguments and does not exist in the container. Did you forget to define such a service?',
];
$tests[] = [
InvokableControllerService::class,
\InvalidArgumentException::class,
'Controller "Symfony\Component\HttpKernel\Tests\Controller\InvokableControllerService" has required constructor arguments and does not exist in the container. Did you forget to define such a service?',
];
return $tests;
}
protected function createControllerResolver(LoggerInterface $logger = null, ContainerInterface $container = null)
{
if (!$container) {
$container = $this->createMockContainer();
}
return new ContainerControllerResolver($container, $logger);
}
protected function createMockContainer()
{
return $this->getMockBuilder(ContainerInterface::class)->getMock();
}
}
class InvokableControllerService
{
public function __construct($bar) // mandatory argument to prevent automatic instantiation
{
}
public function __invoke()
{
}
}
class ControllerTestService
{
public function __construct($foo)
{
}
public function action()
{
}
}

View File

@@ -0,0 +1,253 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Controller;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
class ControllerResolverTest extends TestCase
{
public function testGetControllerWithoutControllerParameter()
{
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$logger->expects($this->once())->method('warning')->with('Unable to look for the controller as the "_controller" parameter is missing.');
$resolver = $this->createControllerResolver($logger);
$request = Request::create('/');
$this->assertFalse($resolver->getController($request), '->getController() returns false when the request has no _controller attribute');
}
public function testGetControllerWithLambda()
{
$resolver = $this->createControllerResolver();
$request = Request::create('/');
$request->attributes->set('_controller', $lambda = function () {});
$controller = $resolver->getController($request);
$this->assertSame($lambda, $controller);
}
public function testGetControllerWithObjectAndInvokeMethod()
{
$resolver = $this->createControllerResolver();
$object = new InvokableController();
$request = Request::create('/');
$request->attributes->set('_controller', $object);
$controller = $resolver->getController($request);
$this->assertSame($object, $controller);
}
public function testGetControllerWithObjectAndMethod()
{
$resolver = $this->createControllerResolver();
$object = new ControllerTest();
$request = Request::create('/');
$request->attributes->set('_controller', [$object, 'publicAction']);
$controller = $resolver->getController($request);
$this->assertSame([$object, 'publicAction'], $controller);
}
public function testGetControllerWithClassAndMethodAsArray()
{
$resolver = $this->createControllerResolver();
$request = Request::create('/');
$request->attributes->set('_controller', [ControllerTest::class, 'publicAction']);
$controller = $resolver->getController($request);
$this->assertInstanceOf(ControllerTest::class, $controller[0]);
$this->assertSame('publicAction', $controller[1]);
}
public function testGetControllerWithClassAndMethodAsString()
{
$resolver = $this->createControllerResolver();
$request = Request::create('/');
$request->attributes->set('_controller', ControllerTest::class.'::publicAction');
$controller = $resolver->getController($request);
$this->assertInstanceOf(ControllerTest::class, $controller[0]);
$this->assertSame('publicAction', $controller[1]);
}
public function testGetControllerWithInvokableClass()
{
$resolver = $this->createControllerResolver();
$request = Request::create('/');
$request->attributes->set('_controller', InvokableController::class);
$controller = $resolver->getController($request);
$this->assertInstanceOf(InvokableController::class, $controller);
}
public function testGetControllerOnObjectWithoutInvokeMethod()
{
$this->expectException('InvalidArgumentException');
$resolver = $this->createControllerResolver();
$request = Request::create('/');
$request->attributes->set('_controller', new \stdClass());
$resolver->getController($request);
}
public function testGetControllerWithFunction()
{
$resolver = $this->createControllerResolver();
$request = Request::create('/');
$request->attributes->set('_controller', 'Symfony\Component\HttpKernel\Tests\Controller\some_controller_function');
$controller = $resolver->getController($request);
$this->assertSame('Symfony\Component\HttpKernel\Tests\Controller\some_controller_function', $controller);
}
public function testGetControllerWithClosure()
{
$resolver = $this->createControllerResolver();
$closure = function () {
return 'test';
};
$request = Request::create('/');
$request->attributes->set('_controller', $closure);
$controller = $resolver->getController($request);
$this->assertInstanceOf(\Closure::class, $controller);
$this->assertSame('test', $controller());
}
/**
* @dataProvider getStaticControllers
*/
public function testGetControllerWithStaticController($staticController, $returnValue)
{
$resolver = $this->createControllerResolver();
$request = Request::create('/');
$request->attributes->set('_controller', $staticController);
$controller = $resolver->getController($request);
$this->assertSame($staticController, $controller);
$this->assertSame($returnValue, $controller());
}
public function getStaticControllers()
{
return [
[TestAbstractController::class.'::staticAction', 'foo'],
[[TestAbstractController::class, 'staticAction'], 'foo'],
[PrivateConstructorController::class.'::staticAction', 'bar'],
[[PrivateConstructorController::class, 'staticAction'], 'bar'],
];
}
/**
* @dataProvider getUndefinedControllers
*/
public function testGetControllerWithUndefinedController($controller, $exceptionName = null, $exceptionMessage = null)
{
$resolver = $this->createControllerResolver();
$this->expectException($exceptionName);
$this->expectExceptionMessage($exceptionMessage);
$request = Request::create('/');
$request->attributes->set('_controller', $controller);
$resolver->getController($request);
}
public function getUndefinedControllers()
{
$controller = new ControllerTest();
return [
['foo', \Error::class, 'Class \'foo\' not found'],
['oof::bar', \Error::class, 'Class \'oof\' not found'],
[['oof', 'bar'], \Error::class, 'Class \'oof\' not found'],
['Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::staticsAction', \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Expected method "staticsAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest", did you mean "staticAction"?'],
['Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::privateAction', \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Method "privateAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" should be public and non-abstract'],
['Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::protectedAction', \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Method "protectedAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" should be public and non-abstract'],
['Symfony\Component\HttpKernel\Tests\Controller\ControllerTest::undefinedAction', \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Expected method "undefinedAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest". Available methods: "publicAction", "staticAction"'],
['Symfony\Component\HttpKernel\Tests\Controller\ControllerTest', \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Controller class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" cannot be called without a method name. You need to implement "__invoke" or use one of the available methods: "publicAction", "staticAction".'],
[[$controller, 'staticsAction'], \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Expected method "staticsAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest", did you mean "staticAction"?'],
[[$controller, 'privateAction'], \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Method "privateAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" should be public and non-abstract'],
[[$controller, 'protectedAction'], \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Method "protectedAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" should be public and non-abstract'],
[[$controller, 'undefinedAction'], \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Expected method "undefinedAction" on class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest". Available methods: "publicAction", "staticAction"'],
[$controller, \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Controller class "Symfony\Component\HttpKernel\Tests\Controller\ControllerTest" cannot be called without a method name. You need to implement "__invoke" or use one of the available methods: "publicAction", "staticAction".'],
[['a' => 'foo', 'b' => 'bar'], \InvalidArgumentException::class, 'The controller for URI "/" is not callable. Invalid array callable, expected [controller, method].'],
];
}
protected function createControllerResolver(LoggerInterface $logger = null)
{
return new ControllerResolver($logger);
}
}
function some_controller_function($foo, $foobar)
{
}
class ControllerTest
{
public function __construct()
{
}
public function __toString()
{
return '';
}
public function publicAction()
{
}
private function privateAction()
{
}
protected function protectedAction()
{
}
public static function staticAction()
{
}
}
class InvokableController
{
public function __invoke($foo, $bar = null)
{
}
}
abstract class TestAbstractController
{
public static function staticAction()
{
return 'foo';
}
}
class PrivateConstructorController
{
private function __construct()
{
}
public static function staticAction()
{
return 'bar';
}
}

View File

@@ -0,0 +1,139 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\ControllerMetadata;
use Fake\ImportedAndFake;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory;
use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\BasicTypesController;
use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\NullableController;
use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\VariadicController;
class ArgumentMetadataFactoryTest extends TestCase
{
/**
* @var ArgumentMetadataFactory
*/
private $factory;
protected function setUp(): void
{
$this->factory = new ArgumentMetadataFactory();
}
public function testSignature1()
{
$arguments = $this->factory->createArgumentMetadata([$this, 'signature1']);
$this->assertEquals([
new ArgumentMetadata('foo', self::class, false, false, null),
new ArgumentMetadata('bar', 'array', false, false, null),
new ArgumentMetadata('baz', 'callable', false, false, null),
], $arguments);
}
public function testSignature2()
{
$arguments = $this->factory->createArgumentMetadata([$this, 'signature2']);
$this->assertEquals([
new ArgumentMetadata('foo', self::class, false, true, null, true),
new ArgumentMetadata('bar', __NAMESPACE__.'\FakeClassThatDoesNotExist', false, true, null, true),
new ArgumentMetadata('baz', 'Fake\ImportedAndFake', false, true, null, true),
], $arguments);
}
public function testSignature3()
{
$arguments = $this->factory->createArgumentMetadata([$this, 'signature3']);
$this->assertEquals([
new ArgumentMetadata('bar', __NAMESPACE__.'\FakeClassThatDoesNotExist', false, false, null),
new ArgumentMetadata('baz', 'Fake\ImportedAndFake', false, false, null),
], $arguments);
}
public function testSignature4()
{
$arguments = $this->factory->createArgumentMetadata([$this, 'signature4']);
$this->assertEquals([
new ArgumentMetadata('foo', null, false, true, 'default'),
new ArgumentMetadata('bar', null, false, true, 500),
new ArgumentMetadata('baz', null, false, true, []),
], $arguments);
}
public function testSignature5()
{
$arguments = $this->factory->createArgumentMetadata([$this, 'signature5']);
$this->assertEquals([
new ArgumentMetadata('foo', 'array', false, true, null, true),
new ArgumentMetadata('bar', null, false, false, null),
], $arguments);
}
public function testVariadicSignature()
{
$arguments = $this->factory->createArgumentMetadata([new VariadicController(), 'action']);
$this->assertEquals([
new ArgumentMetadata('foo', null, false, false, null),
new ArgumentMetadata('bar', null, true, false, null),
], $arguments);
}
public function testBasicTypesSignature()
{
$arguments = $this->factory->createArgumentMetadata([new BasicTypesController(), 'action']);
$this->assertEquals([
new ArgumentMetadata('foo', 'string', false, false, null),
new ArgumentMetadata('bar', 'int', false, false, null),
new ArgumentMetadata('baz', 'float', false, false, null),
], $arguments);
}
public function testNullableTypesSignature()
{
$arguments = $this->factory->createArgumentMetadata([new NullableController(), 'action']);
$this->assertEquals([
new ArgumentMetadata('foo', 'string', false, false, null, true),
new ArgumentMetadata('bar', \stdClass::class, false, false, null, true),
new ArgumentMetadata('baz', 'string', false, true, 'value', true),
new ArgumentMetadata('mandatory', null, false, false, null, true),
], $arguments);
}
private function signature1(self $foo, array $bar, callable $baz)
{
}
private function signature2(self $foo = null, FakeClassThatDoesNotExist $bar = null, ImportedAndFake $baz = null)
{
}
private function signature3(FakeClassThatDoesNotExist $bar, ImportedAndFake $baz)
{
}
private function signature4($foo = 'default', $bar = 500, $baz = [])
{
}
private function signature5(array $foo = null, $bar)
{
}
}

View File

@@ -0,0 +1,44 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\ControllerMetadata;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
class ArgumentMetadataTest extends TestCase
{
public function testWithBcLayerWithDefault()
{
$argument = new ArgumentMetadata('foo', 'string', false, true, 'default value');
$this->assertFalse($argument->isNullable());
}
public function testDefaultValueAvailable()
{
$argument = new ArgumentMetadata('foo', 'string', false, true, 'default value', true);
$this->assertTrue($argument->isNullable());
$this->assertTrue($argument->hasDefaultValue());
$this->assertSame('default value', $argument->getDefaultValue());
}
public function testDefaultValueUnavailable()
{
$this->expectException('LogicException');
$argument = new ArgumentMetadata('foo', 'string', false, false, null, false);
$this->assertFalse($argument->isNullable());
$this->assertFalse($argument->hasDefaultValue());
$argument->getDefaultValue();
}
}

View File

@@ -0,0 +1,4 @@
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Psr\Container\ContainerInterface"; reason: private alias.
Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass: Removed service "Symfony\Component\DependencyInjection\ContainerInterface"; reason: private alias.
Some custom logging message
With ending :

View File

@@ -0,0 +1,76 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DataCollector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector;
use Symfony\Component\HttpKernel\Kernel;
class ConfigDataCollectorTest extends TestCase
{
public function testCollect()
{
$kernel = new KernelForTest('test', true);
$c = new ConfigDataCollector();
$c->setKernel($kernel);
$c->collect(new Request(), new Response());
$this->assertSame('test', $c->getEnv());
$this->assertTrue($c->isDebug());
$this->assertSame('config', $c->getName());
$this->assertRegExp('~^'.preg_quote($c->getPhpVersion(), '~').'~', PHP_VERSION);
$this->assertRegExp('~'.preg_quote((string) $c->getPhpVersionExtra(), '~').'$~', PHP_VERSION);
$this->assertSame(PHP_INT_SIZE * 8, $c->getPhpArchitecture());
$this->assertSame(class_exists('Locale', false) && \Locale::getDefault() ? \Locale::getDefault() : 'n/a', $c->getPhpIntlLocale());
$this->assertSame(date_default_timezone_get(), $c->getPhpTimezone());
$this->assertSame(Kernel::VERSION, $c->getSymfonyVersion());
$this->assertNull($c->getToken());
$this->assertSame(\extension_loaded('xdebug'), $c->hasXDebug());
$this->assertSame(\extension_loaded('Zend OPcache') && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN), $c->hasZendOpcache());
$this->assertSame(\extension_loaded('apcu') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN), $c->hasApcu());
}
/**
* @group legacy
* @expectedDeprecation The "$name" argument in method "Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector::__construct()" is deprecated since Symfony 4.2.
* @expectedDeprecation The "$version" argument in method "Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector::__construct()" is deprecated since Symfony 4.2.
* @expectedDeprecation The method "Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector::getApplicationName()" is deprecated since Symfony 4.2.
* @expectedDeprecation The method "Symfony\Component\HttpKernel\DataCollector\ConfigDataCollector::getApplicationVersion()" is deprecated since Symfony 4.2.
*/
public function testLegacy()
{
$c = new ConfigDataCollector('name', null);
$c->collect(new Request(), new Response());
$this->assertSame('name', $c->getApplicationName());
$this->assertNull($c->getApplicationVersion());
}
}
class KernelForTest extends Kernel
{
public function registerBundles()
{
}
public function getBundles()
{
return [];
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DataCollector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Tests\Fixtures\DataCollector\CloneVarDataCollector;
use Symfony\Component\VarDumper\Cloner\VarCloner;
class DataCollectorTest extends TestCase
{
public function testCloneVarStringWithScheme()
{
$c = new CloneVarDataCollector('scheme://foo');
$c->collect(new Request(), new Response());
$cloner = new VarCloner();
$this->assertEquals($cloner->cloneVar('scheme://foo'), $c->getData());
}
public function testCloneVarExistingFilePath()
{
$c = new CloneVarDataCollector([$filePath = tempnam(sys_get_temp_dir(), 'clone_var_data_collector_')]);
$c->collect(new Request(), new Response());
$this->assertSame($filePath, $c->getData()[0]);
}
}

View File

@@ -0,0 +1,154 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DataCollector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DumpDataCollector;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Server\Connection;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class DumpDataCollectorTest extends TestCase
{
public function testDump()
{
$data = new Data([[123]]);
$collector = new DumpDataCollector();
$this->assertSame('dump', $collector->getName());
$collector->dump($data);
$line = __LINE__ - 1;
$this->assertSame(1, $collector->getDumpsCount());
$dump = $collector->getDumps('html');
$this->assertArrayHasKey('data', $dump[0]);
$dump[0]['data'] = preg_replace('/^.*?<pre/', '<pre', $dump[0]['data']);
$dump[0]['data'] = preg_replace('/sf-dump-\d+/', 'sf-dump', $dump[0]['data']);
$xDump = [
[
'data' => "<pre class=sf-dump id=sf-dump data-indent-pad=\" \"><span class=sf-dump-num>123</span>\n</pre><script>Sfdump(\"sf-dump\")</script>\n",
'name' => 'DumpDataCollectorTest.php',
'file' => __FILE__,
'line' => $line,
'fileExcerpt' => false,
],
];
$this->assertEquals($xDump, $dump);
$this->assertStringMatchesFormat('%a;a:%d:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', serialize($collector));
$this->assertSame(0, $collector->getDumpsCount());
$this->assertSame("O:60:\"Symfony\Component\HttpKernel\DataCollector\DumpDataCollector\":1:{s:7:\"\0*\0data\";a:2:{i:0;b:0;i:1;s:5:\"UTF-8\";}}", serialize($collector));
}
public function testDumpWithServerConnection()
{
$data = new Data([[123]]);
// Server is up, server dumper is used
$serverDumper = $this->getMockBuilder(Connection::class)->disableOriginalConstructor()->getMock();
$serverDumper->expects($this->once())->method('write')->willReturn(true);
$collector = new DumpDataCollector(null, null, null, null, $serverDumper);
$collector->dump($data);
// Collect doesn't re-trigger dump
ob_start();
$collector->collect(new Request(), new Response());
$this->assertEmpty(ob_get_clean());
$this->assertStringMatchesFormat('%a;a:%d:{i:0;a:5:{s:4:"data";%c:39:"Symfony\Component\VarDumper\Cloner\Data":%a', serialize($collector));
}
public function testCollectDefault()
{
$data = new Data([[123]]);
$collector = new DumpDataCollector();
$collector->dump($data);
$line = __LINE__ - 1;
ob_start();
$collector->collect(new Request(), new Response());
$output = preg_replace("/\033\[[^m]*m/", '', ob_get_clean());
$this->assertSame("DumpDataCollectorTest.php on line {$line}:\n123\n", $output);
$this->assertSame(1, $collector->getDumpsCount());
serialize($collector);
}
public function testCollectHtml()
{
$data = new Data([[123]]);
$collector = new DumpDataCollector(null, 'test://%f:%l');
$collector->dump($data);
$line = __LINE__ - 1;
$file = __FILE__;
$xOutput = <<<EOTXT
<pre class=sf-dump id=sf-dump data-indent-pad=" "><a href="test://{$file}:{$line}" title="{$file}"><span class=sf-dump-meta>DumpDataCollectorTest.php</span></a> on line <span class=sf-dump-meta>{$line}</span>:
<span class=sf-dump-num>123</span>
</pre>
EOTXT;
ob_start();
$response = new Response();
$response->headers->set('Content-Type', 'text/html');
$collector->collect(new Request(), $response);
$output = ob_get_clean();
$output = preg_replace('#<(script|style).*?</\1>#s', '', $output);
$output = preg_replace('/sf-dump-\d+/', 'sf-dump', $output);
$this->assertSame($xOutput, trim($output));
$this->assertSame(1, $collector->getDumpsCount());
serialize($collector);
}
public function testFlush()
{
$data = new Data([[456]]);
$collector = new DumpDataCollector();
$collector->dump($data);
$line = __LINE__ - 1;
ob_start();
$collector->__destruct();
$output = preg_replace("/\033\[[^m]*m/", '', ob_get_clean());
$this->assertSame("DumpDataCollectorTest.php on line {$line}:\n456\n", $output);
}
public function testFlushNothingWhenDataDumperIsProvided()
{
$data = new Data([[456]]);
$dumper = new CliDumper('php://output');
$collector = new DumpDataCollector(null, null, null, null, $dumper);
ob_start();
$collector->dump($data);
$line = __LINE__ - 1;
$output = preg_replace("/\033\[[^m]*m/", '', ob_get_clean());
$this->assertSame("DumpDataCollectorTest.php on line {$line}:\n456\n", $output);
ob_start();
$collector->__destruct();
$this->assertEmpty(ob_get_clean());
}
}

View File

@@ -0,0 +1,59 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DataCollector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\ExceptionDataCollector;
class ExceptionDataCollectorTest extends TestCase
{
public function testCollect()
{
$e = new \Exception('foo', 500);
$c = new ExceptionDataCollector();
$flattened = FlattenException::create($e);
$trace = $flattened->getTrace();
$this->assertFalse($c->hasException());
$c->collect(new Request(), new Response(), $e);
$this->assertTrue($c->hasException());
$this->assertEquals($flattened, $c->getException());
$this->assertSame('foo', $c->getMessage());
$this->assertSame(500, $c->getCode());
$this->assertSame('exception', $c->getName());
$this->assertSame($trace, $c->getTrace());
}
public function testCollectWithoutException()
{
$c = new ExceptionDataCollector();
$c->collect(new Request(), new Response());
$this->assertFalse($c->hasException());
}
public function testReset()
{
$c = new ExceptionDataCollector();
$c->collect(new Request(), new Response(), new \Exception());
$c->reset();
$c->collect(new Request(), new Response());
$this->assertFalse($c->hasException());
}
}

View File

@@ -0,0 +1,188 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DataCollector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Debug\Exception\SilencedErrorContext;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\LoggerDataCollector;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
class LoggerDataCollectorTest extends TestCase
{
public function testCollectWithUnexpectedFormat()
{
$logger = $this
->getMockBuilder('Symfony\Component\HttpKernel\Log\DebugLoggerInterface')
->setMethods(['countErrors', 'getLogs', 'clear'])
->getMock();
$logger->expects($this->once())->method('countErrors')->willReturn(123);
$logger->expects($this->exactly(2))->method('getLogs')->willReturn([]);
$c = new LoggerDataCollector($logger, __DIR__.'/');
$c->lateCollect();
$compilerLogs = $c->getCompilerLogs()->getValue('message');
$this->assertSame([
['message' => 'Removed service "Psr\Container\ContainerInterface"; reason: private alias.'],
['message' => 'Removed service "Symfony\Component\DependencyInjection\ContainerInterface"; reason: private alias.'],
], $compilerLogs['Symfony\Component\DependencyInjection\Compiler\RemovePrivateAliasesPass']);
$this->assertSame([
['message' => 'Some custom logging message'],
['message' => 'With ending :'],
], $compilerLogs['Unknown Compiler Pass']);
}
public function testWithMasterRequest()
{
$masterRequest = new Request();
$stack = new RequestStack();
$stack->push($masterRequest);
$logger = $this
->getMockBuilder(DebugLoggerInterface::class)
->setMethods(['countErrors', 'getLogs', 'clear'])
->getMock();
$logger->expects($this->once())->method('countErrors')->with(null);
$logger->expects($this->exactly(2))->method('getLogs')->with(null)->willReturn([]);
$c = new LoggerDataCollector($logger, __DIR__.'/', $stack);
$c->collect($masterRequest, new Response());
$c->lateCollect();
}
public function testWithSubRequest()
{
$masterRequest = new Request();
$subRequest = new Request();
$stack = new RequestStack();
$stack->push($masterRequest);
$stack->push($subRequest);
$logger = $this
->getMockBuilder(DebugLoggerInterface::class)
->setMethods(['countErrors', 'getLogs', 'clear'])
->getMock();
$logger->expects($this->once())->method('countErrors')->with($subRequest);
$logger->expects($this->exactly(2))->method('getLogs')->with($subRequest)->willReturn([]);
$c = new LoggerDataCollector($logger, __DIR__.'/', $stack);
$c->collect($subRequest, new Response());
$c->lateCollect();
}
/**
* @dataProvider getCollectTestData
*/
public function testCollect($nb, $logs, $expectedLogs, $expectedDeprecationCount, $expectedScreamCount, $expectedPriorities = null)
{
$logger = $this
->getMockBuilder('Symfony\Component\HttpKernel\Log\DebugLoggerInterface')
->setMethods(['countErrors', 'getLogs', 'clear'])
->getMock();
$logger->expects($this->once())->method('countErrors')->willReturn($nb);
$logger->expects($this->exactly(2))->method('getLogs')->willReturn($logs);
$c = new LoggerDataCollector($logger);
$c->lateCollect();
$this->assertEquals('logger', $c->getName());
$this->assertEquals($nb, $c->countErrors());
$logs = array_map(function ($v) {
if (isset($v['context']['exception'])) {
$e = &$v['context']['exception'];
$e = isset($e["\0*\0message"]) ? [$e["\0*\0message"], $e["\0*\0severity"]] : [$e["\0Symfony\Component\Debug\Exception\SilencedErrorContext\0severity"]];
}
return $v;
}, $c->getLogs()->getValue(true));
$this->assertEquals($expectedLogs, $logs);
$this->assertEquals($expectedDeprecationCount, $c->countDeprecations());
$this->assertEquals($expectedScreamCount, $c->countScreams());
if (isset($expectedPriorities)) {
$this->assertSame($expectedPriorities, $c->getPriorities()->getValue(true));
}
}
public function testReset()
{
$logger = $this
->getMockBuilder('Symfony\Component\HttpKernel\Log\DebugLoggerInterface')
->setMethods(['countErrors', 'getLogs', 'clear'])
->getMock();
$logger->expects($this->once())->method('clear');
$c = new LoggerDataCollector($logger);
$c->reset();
}
public function getCollectTestData()
{
yield 'simple log' => [
1,
[['message' => 'foo', 'context' => [], 'priority' => 100, 'priorityName' => 'DEBUG']],
[['message' => 'foo', 'context' => [], 'priority' => 100, 'priorityName' => 'DEBUG']],
0,
0,
];
yield 'log with a context' => [
1,
[['message' => 'foo', 'context' => ['foo' => 'bar'], 'priority' => 100, 'priorityName' => 'DEBUG']],
[['message' => 'foo', 'context' => ['foo' => 'bar'], 'priority' => 100, 'priorityName' => 'DEBUG']],
0,
0,
];
if (!class_exists(SilencedErrorContext::class)) {
return;
}
yield 'logs with some deprecations' => [
1,
[
['message' => 'foo3', 'context' => ['exception' => new \ErrorException('warning', 0, E_USER_WARNING)], 'priority' => 100, 'priorityName' => 'DEBUG'],
['message' => 'foo', 'context' => ['exception' => new \ErrorException('deprecated', 0, E_DEPRECATED)], 'priority' => 100, 'priorityName' => 'DEBUG'],
['message' => 'foo2', 'context' => ['exception' => new \ErrorException('deprecated', 0, E_USER_DEPRECATED)], 'priority' => 100, 'priorityName' => 'DEBUG'],
],
[
['message' => 'foo3', 'context' => ['exception' => ['warning', E_USER_WARNING]], 'priority' => 100, 'priorityName' => 'DEBUG'],
['message' => 'foo', 'context' => ['exception' => ['deprecated', E_DEPRECATED]], 'priority' => 100, 'priorityName' => 'DEBUG', 'errorCount' => 1, 'scream' => false],
['message' => 'foo2', 'context' => ['exception' => ['deprecated', E_USER_DEPRECATED]], 'priority' => 100, 'priorityName' => 'DEBUG', 'errorCount' => 1, 'scream' => false],
],
2,
0,
[100 => ['count' => 3, 'name' => 'DEBUG']],
];
yield 'logs with some silent errors' => [
1,
[
['message' => 'foo3', 'context' => ['exception' => new \ErrorException('warning', 0, E_USER_WARNING)], 'priority' => 100, 'priorityName' => 'DEBUG'],
['message' => 'foo3', 'context' => ['exception' => new SilencedErrorContext(E_USER_WARNING, __FILE__, __LINE__)], 'priority' => 100, 'priorityName' => 'DEBUG'],
],
[
['message' => 'foo3', 'context' => ['exception' => ['warning', E_USER_WARNING]], 'priority' => 100, 'priorityName' => 'DEBUG'],
['message' => 'foo3', 'context' => ['exception' => [E_USER_WARNING]], 'priority' => 100, 'priorityName' => 'DEBUG', 'errorCount' => 1, 'scream' => true],
],
0,
1,
];
}
}

View File

@@ -0,0 +1,59 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DataCollector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\MemoryDataCollector;
class MemoryDataCollectorTest extends TestCase
{
public function testCollect()
{
$collector = new MemoryDataCollector();
$collector->collect(new Request(), new Response());
$this->assertIsInt($collector->getMemory());
$this->assertIsInt($collector->getMemoryLimit());
$this->assertSame('memory', $collector->getName());
}
/** @dataProvider getBytesConversionTestData */
public function testBytesConversion($limit, $bytes)
{
$collector = new MemoryDataCollector();
$method = new \ReflectionMethod($collector, 'convertToBytes');
$method->setAccessible(true);
$this->assertEquals($bytes, $method->invoke($collector, $limit));
}
public function getBytesConversionTestData()
{
return [
['2k', 2048],
['2 k', 2048],
['8m', 8 * 1024 * 1024],
['+2 k', 2048],
['+2???k', 2048],
['0x10', 16],
['0xf', 15],
['010', 8],
['+0x10 k', 16 * 1024],
['1g', 1024 * 1024 * 1024],
['1G', 1024 * 1024 * 1024],
['-1', -1],
['0', 0],
['2mk', 2048], // the unit must be the last char, so in this case 'k', not 'm'
];
}
}

View File

@@ -0,0 +1,390 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DataCollector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Cookie;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
use Symfony\Component\HttpKernel\DataCollector\RequestDataCollector;
use Symfony\Component\HttpKernel\Event\ControllerEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class RequestDataCollectorTest extends TestCase
{
public function testCollect()
{
$c = new RequestDataCollector();
$c->collect($request = $this->createRequest(), $this->createResponse());
$c->lateCollect();
$attributes = $c->getRequestAttributes();
$this->assertSame('request', $c->getName());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\ParameterBag', $c->getRequestHeaders());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\ParameterBag', $c->getRequestServer());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\ParameterBag', $c->getRequestCookies());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\ParameterBag', $attributes);
$this->assertInstanceOf('Symfony\Component\HttpFoundation\ParameterBag', $c->getRequestRequest());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\ParameterBag', $c->getRequestQuery());
$this->assertInstanceOf(ParameterBag::class, $c->getResponseCookies());
$this->assertSame('html', $c->getFormat());
$this->assertEquals('foobar', $c->getRoute());
$this->assertEquals(['name' => 'foo'], $c->getRouteParams());
$this->assertSame([], $c->getSessionAttributes());
$this->assertSame('en', $c->getLocale());
$this->assertContains(__FILE__, $attributes->get('resource'));
$this->assertSame('stdClass', $attributes->get('object')->getType());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\ParameterBag', $c->getResponseHeaders());
$this->assertSame('OK', $c->getStatusText());
$this->assertSame(200, $c->getStatusCode());
$this->assertSame('application/json', $c->getContentType());
}
public function testCollectWithoutRouteParams()
{
$request = $this->createRequest([]);
$c = new RequestDataCollector();
$c->collect($request, $this->createResponse());
$c->lateCollect();
$this->assertEquals([], $c->getRouteParams());
}
/**
* @dataProvider provideControllerCallables
*/
public function testControllerInspection($name, $callable, $expected)
{
$c = new RequestDataCollector();
$request = $this->createRequest();
$response = $this->createResponse();
$this->injectController($c, $callable, $request);
$c->collect($request, $response);
$c->lateCollect();
$this->assertSame($expected, $c->getController()->getValue(true), sprintf('Testing: %s', $name));
}
public function provideControllerCallables()
{
// make sure we always match the line number
$r1 = new \ReflectionMethod($this, 'testControllerInspection');
$r2 = new \ReflectionMethod($this, 'staticControllerMethod');
$r3 = new \ReflectionClass($this);
// test name, callable, expected
return [
[
'"Regular" callable',
[$this, 'testControllerInspection'],
[
'class' => __NAMESPACE__.'\RequestDataCollectorTest',
'method' => 'testControllerInspection',
'file' => __FILE__,
'line' => $r1->getStartLine(),
],
],
[
'Closure',
function () { return 'foo'; },
[
'class' => __NAMESPACE__.'\{closure}',
'method' => null,
'file' => __FILE__,
'line' => __LINE__ - 5,
],
],
[
'Static callback as string',
__NAMESPACE__.'\RequestDataCollectorTest::staticControllerMethod',
[
'class' => 'Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest',
'method' => 'staticControllerMethod',
'file' => __FILE__,
'line' => $r2->getStartLine(),
],
],
[
'Static callable with instance',
[$this, 'staticControllerMethod'],
[
'class' => 'Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest',
'method' => 'staticControllerMethod',
'file' => __FILE__,
'line' => $r2->getStartLine(),
],
],
[
'Static callable with class name',
['Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest', 'staticControllerMethod'],
[
'class' => 'Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest',
'method' => 'staticControllerMethod',
'file' => __FILE__,
'line' => $r2->getStartLine(),
],
],
[
'Callable with instance depending on __call()',
[$this, 'magicMethod'],
[
'class' => 'Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest',
'method' => 'magicMethod',
'file' => 'n/a',
'line' => 'n/a',
],
],
[
'Callable with class name depending on __callStatic()',
['Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest', 'magicMethod'],
[
'class' => 'Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest',
'method' => 'magicMethod',
'file' => 'n/a',
'line' => 'n/a',
],
],
[
'Invokable controller',
$this,
[
'class' => 'Symfony\Component\HttpKernel\Tests\DataCollector\RequestDataCollectorTest',
'method' => null,
'file' => __FILE__,
'line' => $r3->getStartLine(),
],
],
];
}
public function testItIgnoresInvalidCallables()
{
$request = $this->createRequestWithSession();
$response = new RedirectResponse('/');
$c = new RequestDataCollector();
$c->collect($request, $response);
$this->assertSame('n/a', $c->getController());
}
public function testItAddsRedirectedAttributesWhenRequestContainsSpecificCookie()
{
$request = $this->createRequest();
$request->cookies->add([
'sf_redirect' => '{}',
]);
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$c = new RequestDataCollector();
$c->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $this->createResponse()));
$this->assertTrue($request->attributes->get('_redirected'));
}
public function testItSetsARedirectCookieIfTheResponseIsARedirection()
{
$c = new RequestDataCollector();
$response = $this->createResponse();
$response->setStatusCode(302);
$response->headers->set('Location', '/somewhere-else');
$c->collect($request = $this->createRequest(), $response);
$c->lateCollect();
$cookie = $this->getCookieByName($response, 'sf_redirect');
$this->assertNotEmpty($cookie->getValue());
$this->assertSame('lax', $cookie->getSameSite());
$this->assertFalse($cookie->isSecure());
}
public function testItCollectsTheRedirectionAndClearTheCookie()
{
$c = new RequestDataCollector();
$request = $this->createRequest();
$request->attributes->set('_redirected', true);
$request->cookies->add([
'sf_redirect' => '{"method": "POST"}',
]);
$c->collect($request, $response = $this->createResponse());
$c->lateCollect();
$this->assertEquals('POST', $c->getRedirect()['method']);
$cookie = $this->getCookieByName($response, 'sf_redirect');
$this->assertNull($cookie->getValue());
}
protected function createRequest($routeParams = ['name' => 'foo'])
{
$request = Request::create('http://test.com/foo?bar=baz');
$request->attributes->set('foo', 'bar');
$request->attributes->set('_route', 'foobar');
$request->attributes->set('_route_params', $routeParams);
$request->attributes->set('resource', fopen(__FILE__, 'r'));
$request->attributes->set('object', new \stdClass());
return $request;
}
private function createRequestWithSession()
{
$request = $this->createRequest();
$request->attributes->set('_controller', 'Foo::bar');
$request->setSession(new Session(new MockArraySessionStorage()));
$request->getSession()->start();
return $request;
}
protected function createResponse()
{
$response = new Response();
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'application/json');
$response->headers->set('X-Foo-Bar', null);
$response->headers->setCookie(new Cookie('foo', 'bar', 1, '/foo', 'localhost', true, true, false, null));
$response->headers->setCookie(new Cookie('bar', 'foo', new \DateTime('@946684800'), '/', null, false, true, false, null));
$response->headers->setCookie(new Cookie('bazz', 'foo', '2000-12-12', '/', null, false, true, false, null));
return $response;
}
/**
* Inject the given controller callable into the data collector.
*/
protected function injectController($collector, $controller, $request)
{
$resolver = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface')->getMock();
$httpKernel = new HttpKernel(new EventDispatcher(), $resolver, null, $this->getMockBuilder(ArgumentResolverInterface::class)->getMock());
$event = new ControllerEvent($httpKernel, $controller, $request, HttpKernelInterface::MASTER_REQUEST);
$collector->onKernelController($event);
}
/**
* Dummy method used as controller callable.
*/
public static function staticControllerMethod()
{
throw new \LogicException('Unexpected method call');
}
/**
* Magic method to allow non existing methods to be called and delegated.
*/
public function __call($method, $args)
{
throw new \LogicException('Unexpected method call');
}
/**
* Magic method to allow non existing methods to be called and delegated.
*/
public static function __callStatic($method, $args)
{
throw new \LogicException('Unexpected method call');
}
public function __invoke()
{
throw new \LogicException('Unexpected method call');
}
private function getCookieByName(Response $response, $name)
{
foreach ($response->headers->getCookies() as $cookie) {
if ($cookie->getName() == $name) {
return $cookie;
}
}
throw new \InvalidArgumentException(sprintf('Cookie named "%s" is not in response', $name));
}
/**
* @dataProvider provideJsonContentTypes
*/
public function testIsJson($contentType, $expected)
{
$response = $this->createResponse();
$request = $this->createRequest();
$request->headers->set('Content-Type', $contentType);
$c = new RequestDataCollector();
$c->collect($request, $response);
$this->assertSame($expected, $c->isJsonRequest());
}
public function provideJsonContentTypes()
{
return [
['text/csv', false],
['application/json', true],
['application/JSON', true],
['application/hal+json', true],
['application/xml+json', true],
['application/xml', false],
['', false],
];
}
/**
* @dataProvider providePrettyJson
*/
public function testGetPrettyJsonValidity($content, $expected)
{
$response = $this->createResponse();
$request = Request::create('/', 'POST', [], [], [], [], $content);
$c = new RequestDataCollector();
$c->collect($request, $response);
$this->assertSame($expected, $c->getPrettyJson());
}
public function providePrettyJson()
{
return [
['null', 'null'],
['{ "foo": "bar" }', '{
"foo": "bar"
}'],
['{ "abc" }', null],
['', null],
];
}
}

View File

@@ -0,0 +1,57 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DataCollector;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\TimeDataCollector;
use Symfony\Component\Stopwatch\Stopwatch;
/**
* @group time-sensitive
*/
class TimeDataCollectorTest extends TestCase
{
public function testCollect()
{
$c = new TimeDataCollector();
$request = new Request();
$request->server->set('REQUEST_TIME', 1);
$c->collect($request, new Response());
$this->assertEquals(0, $c->getStartTime());
$request->server->set('REQUEST_TIME_FLOAT', 2);
$c->collect($request, new Response());
$this->assertEquals(2000, $c->getStartTime());
$request = new Request();
$c->collect($request, new Response());
$this->assertEquals(0, $c->getStartTime());
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\KernelInterface')->getMock();
$kernel->expects($this->once())->method('getStartTime')->willReturn(123456.0);
$c = new TimeDataCollector($kernel);
$request = new Request();
$request->server->set('REQUEST_TIME', 1);
$c->collect($request, new Response());
$this->assertEquals(123456000, $c->getStartTime());
$this->assertSame(class_exists(Stopwatch::class, false), $c->isStopwatchInstalled());
}
}

View File

@@ -0,0 +1,54 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Debug;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Debug\FileLinkFormatter;
class FileLinkFormatterTest extends TestCase
{
public function testWhenNoFileLinkFormatAndNoRequest()
{
$sut = new FileLinkFormatter();
$this->assertFalse($sut->format('/kernel/root/src/my/very/best/file.php', 3));
}
public function testWhenFileLinkFormatAndNoRequest()
{
$file = __DIR__.\DIRECTORY_SEPARATOR.'file.php';
$sut = new FileLinkFormatter('debug://open?url=file://%f&line=%l', new RequestStack());
$this->assertSame("debug://open?url=file://$file&line=3", $sut->format($file, 3));
}
public function testWhenNoFileLinkFormatAndRequest()
{
$file = __DIR__.\DIRECTORY_SEPARATOR.'file.php';
$requestStack = new RequestStack();
$request = new Request();
$requestStack->push($request);
$request->server->set('SERVER_NAME', 'www.example.org');
$request->server->set('SERVER_PORT', 80);
$request->server->set('SCRIPT_NAME', '/index.php');
$request->server->set('SCRIPT_FILENAME', '/public/index.php');
$request->server->set('REQUEST_URI', '/index.php/example');
$sut = new FileLinkFormatter(null, $requestStack, __DIR__, '/_profiler/open?file=%f&line=%l#line%l');
$this->assertSame('http://www.example.org/_profiler/open?file=file.php&line=3#line3', $sut->format($file, 3));
}
}

View File

@@ -0,0 +1,120 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Debug;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Debug\TraceableEventDispatcher;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\Stopwatch\Stopwatch;
class TraceableEventDispatcherTest extends TestCase
{
public function testStopwatchSections()
{
$dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch = new Stopwatch());
$kernel = $this->getHttpKernel($dispatcher, function () { return new Response('', 200, ['X-Debug-Token' => '292e1e']); });
$request = Request::create('/');
$response = $kernel->handle($request);
$kernel->terminate($request, $response);
$events = $stopwatch->getSectionEvents($response->headers->get('X-Debug-Token'));
$this->assertEquals([
'__section__',
'kernel.request',
'kernel.controller',
'kernel.controller_arguments',
'controller',
'kernel.response',
'kernel.terminate',
], array_keys($events));
}
public function testStopwatchCheckControllerOnRequestEvent()
{
$stopwatch = $this->getMockBuilder('Symfony\Component\Stopwatch\Stopwatch')
->setMethods(['isStarted'])
->getMock();
$stopwatch->expects($this->once())
->method('isStarted')
->willReturn(false);
$dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch);
$kernel = $this->getHttpKernel($dispatcher, function () { return new Response(); });
$request = Request::create('/');
$kernel->handle($request);
}
public function testStopwatchStopControllerOnRequestEvent()
{
$stopwatch = $this->getMockBuilder('Symfony\Component\Stopwatch\Stopwatch')
->setMethods(['isStarted', 'stop'])
->getMock();
$stopwatch->expects($this->once())
->method('isStarted')
->willReturn(true);
$stopwatch->expects($this->once())
->method('stop');
$dispatcher = new TraceableEventDispatcher(new EventDispatcher(), $stopwatch);
$kernel = $this->getHttpKernel($dispatcher, function () { return new Response(); });
$request = Request::create('/');
$kernel->handle($request);
}
public function testAddListenerNested()
{
$called1 = false;
$called2 = false;
$dispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
$dispatcher->addListener('my-event', function () use ($dispatcher, &$called1, &$called2) {
$called1 = true;
$dispatcher->addListener('my-event', function () use (&$called2) {
$called2 = true;
});
});
$dispatcher->dispatch(new Event(), 'my-event');
$this->assertTrue($called1);
$this->assertFalse($called2);
$dispatcher->dispatch(new Event(), 'my-event');
$this->assertTrue($called2);
}
public function testListenerCanRemoveItselfWhenExecuted()
{
$eventDispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
$listener1 = function () use ($eventDispatcher, &$listener1) {
$eventDispatcher->removeListener('foo', $listener1);
};
$eventDispatcher->addListener('foo', $listener1);
$eventDispatcher->addListener('foo', function () {});
$eventDispatcher->dispatch(new Event(), 'foo');
$this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed');
}
protected function getHttpKernel($dispatcher, $controller)
{
$controllerResolver = $this->getMockBuilder('Symfony\Component\HttpKernel\Controller\ControllerResolverInterface')->getMock();
$controllerResolver->expects($this->once())->method('getController')->willReturn($controller);
$argumentResolver = $this->getMockBuilder('Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface')->getMock();
$argumentResolver->expects($this->once())->method('getArguments')->willReturn([]);
return new HttpKernel($dispatcher, $controllerResolver, new RequestStack(), $argumentResolver);
}
}

View File

@@ -0,0 +1,99 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\DependencyInjection\AddAnnotatedClassesToCachePass;
class AddAnnotatedClassesToCachePassTest extends TestCase
{
public function testExpandClasses()
{
$r = new \ReflectionClass(AddAnnotatedClassesToCachePass::class);
$pass = $r->newInstanceWithoutConstructor();
$r = new \ReflectionMethod(AddAnnotatedClassesToCachePass::class, 'expandClasses');
$r->setAccessible(true);
$expand = $r->getClosure($pass);
$this->assertSame('Foo', $expand(['Foo'], [])[0]);
$this->assertSame('Foo', $expand(['\\Foo'], [])[0]);
$this->assertSame('Foo', $expand(['Foo'], ['\\Foo'])[0]);
$this->assertSame('Foo', $expand(['Foo'], ['Foo'])[0]);
$this->assertSame('Foo', $expand(['\\Foo'], ['\\Foo\\Bar'])[0]);
$this->assertSame('Foo', $expand(['Foo'], ['\\Foo\\Bar'])[0]);
$this->assertSame('Foo', $expand(['\\Foo'], ['\\Foo\\Bar\\Acme'])[0]);
$this->assertSame('Foo\\Bar', $expand(['Foo\\'], ['\\Foo\\Bar'])[0]);
$this->assertSame('Foo\\Bar\\Acme', $expand(['Foo\\'], ['\\Foo\\Bar\\Acme'])[0]);
$this->assertEmpty($expand(['Foo\\'], ['\\Foo']));
$this->assertSame('Acme\\Foo\\Bar', $expand(['**\\Foo\\'], ['\\Acme\\Foo\\Bar'])[0]);
$this->assertEmpty($expand(['**\\Foo\\'], ['\\Foo\\Bar']));
$this->assertEmpty($expand(['**\\Foo\\'], ['\\Acme\\Foo']));
$this->assertEmpty($expand(['**\\Foo\\'], ['\\Foo']));
$this->assertSame('Acme\\Foo', $expand(['**\\Foo'], ['\\Acme\\Foo'])[0]);
$this->assertEmpty($expand(['**\\Foo'], ['\\Acme\\Foo\\AcmeBundle']));
$this->assertEmpty($expand(['**\\Foo'], ['\\Acme\\FooBar\\AcmeBundle']));
$this->assertSame('Foo\\Acme\\Bar', $expand(['Foo\\*\\Bar'], ['\\Foo\\Acme\\Bar'])[0]);
$this->assertEmpty($expand(['Foo\\*\\Bar'], ['\\Foo\\Acme\\Bundle\\Bar']));
$this->assertSame('Foo\\Acme\\Bar', $expand(['Foo\\**\\Bar'], ['\\Foo\\Acme\\Bar'])[0]);
$this->assertSame('Foo\\Acme\\Bundle\\Bar', $expand(['Foo\\**\\Bar'], ['\\Foo\\Acme\\Bundle\\Bar'])[0]);
$this->assertSame('Acme\\Bar', $expand(['*\\Bar'], ['\\Acme\\Bar'])[0]);
$this->assertEmpty($expand(['*\\Bar'], ['\\Bar']));
$this->assertEmpty($expand(['*\\Bar'], ['\\Foo\\Acme\\Bar']));
$this->assertSame('Foo\\Acme\\Bar', $expand(['**\\Bar'], ['\\Foo\\Acme\\Bar'])[0]);
$this->assertSame('Foo\\Acme\\Bundle\\Bar', $expand(['**\\Bar'], ['\\Foo\\Acme\\Bundle\\Bar'])[0]);
$this->assertEmpty($expand(['**\\Bar'], ['\\Bar']));
$this->assertSame('Foo\\Bar', $expand(['Foo\\*'], ['\\Foo\\Bar'])[0]);
$this->assertEmpty($expand(['Foo\\*'], ['\\Foo\\Acme\\Bar']));
$this->assertSame('Foo\\Bar', $expand(['Foo\\**'], ['\\Foo\\Bar'])[0]);
$this->assertSame('Foo\\Acme\\Bar', $expand(['Foo\\**'], ['\\Foo\\Acme\\Bar'])[0]);
$this->assertSame(['Foo\\Bar'], $expand(['Foo\\*'], ['Foo\\Bar', 'Foo\\BarTest']));
$this->assertSame(['Foo\\Bar', 'Foo\\BarTest'], $expand(['Foo\\*', 'Foo\\*Test'], ['Foo\\Bar', 'Foo\\BarTest']));
$this->assertSame(
'Acme\\FooBundle\\Controller\\DefaultController',
$expand(['**Bundle\\Controller\\'], ['\\Acme\\FooBundle\\Controller\\DefaultController'])[0]
);
$this->assertSame(
'FooBundle\\Controller\\DefaultController',
$expand(['**Bundle\\Controller\\'], ['\\FooBundle\\Controller\\DefaultController'])[0]
);
$this->assertSame(
'Acme\\FooBundle\\Controller\\Bar\\DefaultController',
$expand(['**Bundle\\Controller\\'], ['\\Acme\\FooBundle\\Controller\\Bar\\DefaultController'])[0]
);
$this->assertSame(
'Bundle\\Controller\\Bar\\DefaultController',
$expand(['**Bundle\\Controller\\'], ['\\Bundle\\Controller\\Bar\\DefaultController'])[0]
);
$this->assertSame(
'Acme\\Bundle\\Controller\\Bar\\DefaultController',
$expand(['**Bundle\\Controller\\'], ['\\Acme\\Bundle\\Controller\\Bar\\DefaultController'])[0]
);
$this->assertSame('Foo\\Bar', $expand(['Foo\\Bar'], [])[0]);
$this->assertSame('Foo\\Acme\\Bar', $expand(['Foo\\**'], ['\\Foo\\Acme\\Bar'])[0]);
}
}

View File

@@ -0,0 +1,131 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\DependencyInjection\ControllerArgumentValueResolverPass;
use Symfony\Component\Stopwatch\Stopwatch;
class ControllerArgumentValueResolverPassTest extends TestCase
{
public function testServicesAreOrderedAccordingToPriority()
{
$services = [
'n3' => [[]],
'n1' => [['priority' => 200]],
'n2' => [['priority' => 100]],
];
$expected = [
new Reference('n1'),
new Reference('n2'),
new Reference('n3'),
];
$definition = new Definition(ArgumentResolver::class, [null, []]);
$container = new ContainerBuilder();
$container->setDefinition('argument_resolver', $definition);
foreach ($services as $id => list($tag)) {
$container->register($id)->addTag('controller.argument_value_resolver', $tag);
}
$container->setParameter('kernel.debug', false);
(new ControllerArgumentValueResolverPass())->process($container);
$this->assertEquals($expected, $definition->getArgument(1)->getValues());
$this->assertFalse($container->hasDefinition('n1.traceable'));
$this->assertFalse($container->hasDefinition('n2.traceable'));
$this->assertFalse($container->hasDefinition('n3.traceable'));
}
public function testInDebugWithStopWatchDefinition()
{
$services = [
'n3' => [[]],
'n1' => [['priority' => 200]],
'n2' => [['priority' => 100]],
];
$expected = [
new Reference('n1'),
new Reference('n2'),
new Reference('n3'),
];
$definition = new Definition(ArgumentResolver::class, [null, []]);
$container = new ContainerBuilder();
$container->register('debug.stopwatch', Stopwatch::class);
$container->setDefinition('argument_resolver', $definition);
foreach ($services as $id => list($tag)) {
$container->register($id)->addTag('controller.argument_value_resolver', $tag);
}
$container->setParameter('kernel.debug', true);
(new ControllerArgumentValueResolverPass())->process($container);
$this->assertEquals($expected, $definition->getArgument(1)->getValues());
$this->assertTrue($container->hasDefinition('debug.n1'));
$this->assertTrue($container->hasDefinition('debug.n2'));
$this->assertTrue($container->hasDefinition('debug.n3'));
$this->assertTrue($container->hasDefinition('n1'));
$this->assertTrue($container->hasDefinition('n2'));
$this->assertTrue($container->hasDefinition('n3'));
}
public function testInDebugWithouStopWatchDefinition()
{
$expected = [new Reference('n1')];
$definition = new Definition(ArgumentResolver::class, [null, []]);
$container = new ContainerBuilder();
$container->register('n1')->addTag('controller.argument_value_resolver');
$container->setDefinition('argument_resolver', $definition);
$container->setParameter('kernel.debug', true);
(new ControllerArgumentValueResolverPass())->process($container);
$this->assertEquals($expected, $definition->getArgument(1)->getValues());
$this->assertFalse($container->hasDefinition('debug.n1'));
$this->assertTrue($container->hasDefinition('n1'));
}
public function testReturningEmptyArrayWhenNoService()
{
$definition = new Definition(ArgumentResolver::class, [null, []]);
$container = new ContainerBuilder();
$container->setDefinition('argument_resolver', $definition);
$container->setParameter('kernel.debug', false);
(new ControllerArgumentValueResolverPass())->process($container);
$this->assertEquals([], $definition->getArgument(1)->getValues());
}
public function testNoArgumentResolver()
{
$container = new ContainerBuilder();
(new ControllerArgumentValueResolverPass())->process($container);
$this->assertFalse($container->hasDefinition('argument_resolver'));
}
}

View File

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\DependencyInjection\FragmentRendererPass;
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
class FragmentRendererPassTest extends TestCase
{
/**
* Tests that content rendering not implementing FragmentRendererInterface
* triggers an exception.
*/
public function testContentRendererWithoutInterface()
{
$this->expectException('InvalidArgumentException');
$builder = new ContainerBuilder();
$fragmentHandlerDefinition = $builder->register('fragment.handler');
$builder->register('my_content_renderer', 'Symfony\Component\DependencyInjection\Definition')
->addTag('kernel.fragment_renderer', ['alias' => 'foo']);
$pass = new FragmentRendererPass();
$pass->process($builder);
$this->assertEquals([['addRendererService', ['foo', 'my_content_renderer']]], $fragmentHandlerDefinition->getMethodCalls());
}
public function testValidContentRenderer()
{
$builder = new ContainerBuilder();
$fragmentHandlerDefinition = $builder->register('fragment.handler')
->addArgument(null);
$builder->register('my_content_renderer', 'Symfony\Component\HttpKernel\Tests\DependencyInjection\RendererService')
->addTag('kernel.fragment_renderer', ['alias' => 'foo']);
$pass = new FragmentRendererPass();
$pass->process($builder);
$serviceLocatorDefinition = $builder->getDefinition((string) $fragmentHandlerDefinition->getArgument(0));
$this->assertSame(ServiceLocator::class, $serviceLocatorDefinition->getClass());
$this->assertEquals(['foo' => new ServiceClosureArgument(new Reference('my_content_renderer'))], $serviceLocatorDefinition->getArgument(0));
}
}
class RendererService implements FragmentRendererInterface
{
public function render($uri, Request $request = null, array $options = [])
{
}
public function getName()
{
return 'test';
}
}

View File

@@ -0,0 +1,41 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DependencyInjection\LazyLoadingFragmentHandler;
class LazyLoadingFragmentHandlerTest extends TestCase
{
public function testRender()
{
$renderer = $this->getMockBuilder('Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface')->getMock();
$renderer->expects($this->once())->method('getName')->willReturn('foo');
$renderer->expects($this->any())->method('render')->willReturn(new Response());
$requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock();
$requestStack->expects($this->any())->method('getCurrentRequest')->willReturn(Request::create('/'));
$container = $this->getMockBuilder('Psr\Container\ContainerInterface')->getMock();
$container->expects($this->once())->method('has')->with('foo')->willReturn(true);
$container->expects($this->once())->method('get')->willReturn($renderer);
$handler = new LazyLoadingFragmentHandler($container, $requestStack, false);
$handler->render('/foo', 'foo');
// second call should not lazy-load anymore (see once() above on the get() method)
$handler->render('/foo', 'foo');
}
}

View File

@@ -0,0 +1,56 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\DependencyInjection\LoggerPass;
use Symfony\Component\HttpKernel\Log\Logger;
/**
* @author Kévin Dunglas <dunglas@gmail.com>
*/
class LoggerPassTest extends TestCase
{
public function testAlwaysSetAutowiringAlias()
{
$container = new ContainerBuilder();
$container->register('logger', 'Foo');
(new LoggerPass())->process($container);
$this->assertFalse($container->getAlias(LoggerInterface::class)->isPublic());
}
public function testDoNotOverrideExistingLogger()
{
$container = new ContainerBuilder();
$container->register('logger', 'Foo');
(new LoggerPass())->process($container);
$this->assertSame('Foo', $container->getDefinition('logger')->getClass());
}
public function testRegisterLogger()
{
$container = new ContainerBuilder();
$container->setParameter('kernel.debug', false);
(new LoggerPass())->process($container);
$definition = $container->getDefinition('logger');
$this->assertSame(Logger::class, $definition->getClass());
$this->assertFalse($definition->isPublic());
}
}

View File

@@ -0,0 +1,50 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass;
class MergeExtensionConfigurationPassTest extends TestCase
{
public function testAutoloadMainExtension()
{
$container = new ContainerBuilder();
$container->registerExtension(new LoadedExtension());
$container->registerExtension(new NotLoadedExtension());
$container->loadFromExtension('loaded', []);
$configPass = new MergeExtensionConfigurationPass(['loaded', 'not_loaded']);
$configPass->process($container);
$this->assertTrue($container->hasDefinition('loaded.foo'));
$this->assertTrue($container->hasDefinition('not_loaded.bar'));
}
}
class LoadedExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$container->register('loaded.foo');
}
}
class NotLoadedExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
$container->register('not_loaded.bar');
}
}

View File

@@ -0,0 +1,436 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\DependencyInjection\TypedReference;
use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass;
class RegisterControllerArgumentLocatorsPassTest extends TestCase
{
public function testInvalidClass()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Class "Symfony\Component\HttpKernel\Tests\DependencyInjection\NotFound" used for service "foo" cannot be found.');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', NotFound::class)
->addTag('controller.service_arguments')
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testNoAction()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Missing "action" attribute on tag "controller.service_arguments" {"argument":"bar"} for service "foo".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['argument' => 'bar'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testNoArgument()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Missing "argument" attribute on tag "controller.service_arguments" {"action":"fooAction"} for service "foo".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'fooAction'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testNoService()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Missing "id" attribute on tag "controller.service_arguments" {"action":"fooAction","argument":"bar"} for service "foo".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testInvalidMethod()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Invalid "action" attribute on tag "controller.service_arguments" for service "foo": no public "barAction()" method found on class "Symfony\Component\HttpKernel\Tests\DependencyInjection\RegisterTestController".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'barAction', 'argument' => 'bar', 'id' => 'bar_service'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testInvalidArgument()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Invalid "controller.service_arguments" tag for service "foo": method "fooAction()" has no "baz" argument on class "Symfony\Component\HttpKernel\Tests\DependencyInjection\RegisterTestController".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'baz', 'id' => 'bar'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testAllActions()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments')
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertEquals(['foo::fooAction'], array_keys($locator));
$this->assertInstanceof(ServiceClosureArgument::class, $locator['foo::fooAction']);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
$this->assertSame(ServiceLocator::class, $locator->getClass());
$this->assertFalse($locator->isPublic());
$expected = ['bar' => new ServiceClosureArgument(new TypedReference(ControllerDummy::class, ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE, 'bar'))];
$this->assertEquals($expected, $locator->getArgument(0));
}
public function testExplicitArgument()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar', 'id' => 'bar'])
->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar', 'id' => 'baz']) // should be ignored, the first wins
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
$expected = ['bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE))];
$this->assertEquals($expected, $locator->getArgument(0));
}
public function testOptionalArgument()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->addTag('controller.service_arguments', ['action' => 'fooAction', 'argument' => 'bar', 'id' => '?bar'])
;
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
$expected = ['bar' => new ServiceClosureArgument(new TypedReference('bar', ControllerDummy::class, ContainerInterface::IGNORE_ON_INVALID_REFERENCE))];
$this->assertEquals($expected, $locator->getArgument(0));
}
public function testSkipSetContainer()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', ContainerAwareRegisterTestController::class)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertSame(['foo::fooAction'], array_keys($locator));
}
public function testExceptionOnNonExistentTypeHint()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Cannot determine controller argument for "Symfony\Component\HttpKernel\Tests\DependencyInjection\NonExistentClassController::fooAction()": the $nonExistent argument is type-hinted with the non-existent class or interface: "Symfony\Component\HttpKernel\Tests\DependencyInjection\NonExistentClass". Did you forget to add a use statement?');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', NonExistentClassController::class)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testExceptionOnNonExistentTypeHintDifferentNamespace()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Cannot determine controller argument for "Symfony\Component\HttpKernel\Tests\DependencyInjection\NonExistentClassDifferentNamespaceController::fooAction()": the $nonExistent argument is type-hinted with the non-existent class or interface: "Acme\NonExistentClass".');
$container = new ContainerBuilder();
$container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', NonExistentClassDifferentNamespaceController::class)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
}
public function testNoExceptionOnNonExistentTypeHintOptionalArg()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', NonExistentClassOptionalController::class)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertSame(['foo::barAction', 'foo::fooAction'], array_keys($locator));
}
public function testArgumentWithNoTypeHintIsOk()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', ArgumentWithoutTypeController::class)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertEmpty(array_keys($locator));
}
public function testControllersAreMadePublic()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', ArgumentWithoutTypeController::class)
->setPublic(false)
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$this->assertTrue($container->getDefinition('foo')->isPublic());
}
/**
* @dataProvider provideBindings
*/
public function testBindings($bindingName)
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', RegisterTestController::class)
->setBindings([$bindingName => new Reference('foo')])
->addTag('controller.service_arguments');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
$expected = ['bar' => new ServiceClosureArgument(new Reference('foo'))];
$this->assertEquals($expected, $locator->getArgument(0));
}
public function provideBindings()
{
return [
[ControllerDummy::class.'$bar'],
[ControllerDummy::class],
['$bar'],
];
}
/**
* @dataProvider provideBindScalarValueToControllerArgument
*/
public function testBindScalarValueToControllerArgument($bindingKey)
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', ArgumentWithoutTypeController::class)
->setBindings([$bindingKey => '%foo%'])
->addTag('controller.service_arguments');
$container->setParameter('foo', 'foo_val');
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$locator = $container->getDefinition((string) $locator['foo::fooAction']->getValues()[0]);
// assert the locator has a someArg key
$arguments = $locator->getArgument(0);
$this->assertArrayHasKey('someArg', $arguments);
$this->assertInstanceOf(ServiceClosureArgument::class, $arguments['someArg']);
// get the Reference that someArg points to
$reference = $arguments['someArg']->getValues()[0];
// make sure this service *does* exist and returns the correct value
$this->assertTrue($container->has((string) $reference));
$this->assertSame('foo_val', $container->get((string) $reference));
}
public function provideBindScalarValueToControllerArgument()
{
yield ['$someArg'];
yield ['string $someArg'];
}
public function testBindingsOnChildDefinitions()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('parent', ArgumentWithoutTypeController::class);
$container->setDefinition('child', (new ChildDefinition('parent'))
->setBindings(['$someArg' => new Reference('parent')])
->addTag('controller.service_arguments')
);
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertInstanceOf(ServiceClosureArgument::class, $locator['child::fooAction']);
$locator = $container->getDefinition((string) $locator['child::fooAction']->getValues()[0])->getArgument(0);
$this->assertInstanceOf(ServiceClosureArgument::class, $locator['someArg']);
$this->assertEquals(new Reference('parent'), $locator['someArg']->getValues()[0]);
}
public function testNotTaggedControllerServiceReceivesLocatorArgument()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.not_tagged_controller')->addArgument([]);
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$locatorArgument = $container->getDefinition('argument_resolver.not_tagged_controller')->getArgument(0);
$this->assertInstanceOf(Reference::class, $locatorArgument);
}
}
class RegisterTestController
{
public function __construct(ControllerDummy $bar)
{
}
public function fooAction(ControllerDummy $bar)
{
}
protected function barAction(ControllerDummy $bar)
{
}
}
class ContainerAwareRegisterTestController implements ContainerAwareInterface
{
use ContainerAwareTrait;
public function fooAction(ControllerDummy $bar)
{
}
}
class ControllerDummy
{
}
class NonExistentClassController
{
public function fooAction(NonExistentClass $nonExistent)
{
}
}
class NonExistentClassDifferentNamespaceController
{
public function fooAction(\Acme\NonExistentClass $nonExistent)
{
}
}
class NonExistentClassOptionalController
{
public function fooAction(NonExistentClass $nonExistent = null)
{
}
public function barAction(NonExistentClass $nonExistent = null, $bar)
{
}
}
class ArgumentWithoutTypeController
{
public function fooAction(string $someArg)
{
}
}

View File

@@ -0,0 +1,59 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\RegisterLocaleAwareServicesPass;
use Symfony\Component\HttpKernel\EventListener\LocaleAwareListener;
use Symfony\Contracts\Translation\LocaleAwareInterface;
class RegisterLocaleAwareServicesPassTest extends TestCase
{
public function testCompilerPass()
{
$container = new ContainerBuilder();
$container->register('locale_aware_listener', LocaleAwareListener::class)
->setPublic(true)
->setArguments([null, null]);
$container->register('some_locale_aware_service', LocaleAwareInterface::class)
->setPublic(true)
->addTag('kernel.locale_aware');
$container->register('another_locale_aware_service', LocaleAwareInterface::class)
->setPublic(true)
->addTag('kernel.locale_aware');
$container->addCompilerPass(new RegisterLocaleAwareServicesPass());
$container->compile();
$this->assertEquals(
[
new IteratorArgument([
0 => new Reference('some_locale_aware_service'),
1 => new Reference('another_locale_aware_service'),
]),
null,
],
$container->getDefinition('locale_aware_listener')->getArguments()
);
}
public function testListenerUnregisteredWhenNoLocaleAwareServices()
{
$container = new ContainerBuilder();
$container->register('locale_aware_listener', LocaleAwareListener::class)
->setPublic(true)
->setArguments([null, null]);
$container->addCompilerPass(new RegisterLocaleAwareServicesPass());
$container->compile();
$this->assertFalse($container->hasDefinition('locale_aware_listener'));
}
}

View File

@@ -0,0 +1,109 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Compiler\ResolveInvalidReferencesPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\RegisterControllerArgumentLocatorsPass;
use Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass;
class RemoveEmptyControllerArgumentLocatorsPassTest extends TestCase
{
public function testProcess()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('stdClass', 'stdClass');
$container->register(TestCase::class, 'stdClass');
$container->register('c1', RemoveTestController1::class)->addTag('controller.service_arguments');
$container->register('c2', RemoveTestController2::class)->addTag('controller.service_arguments')
->addMethodCall('setTestCase', [new Reference('c1')]);
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
$controllers = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertCount(2, $container->getDefinition((string) $controllers['c1::fooAction']->getValues()[0])->getArgument(0));
$this->assertCount(1, $container->getDefinition((string) $controllers['c2::setTestCase']->getValues()[0])->getArgument(0));
$this->assertCount(1, $container->getDefinition((string) $controllers['c2::fooAction']->getValues()[0])->getArgument(0));
(new ResolveInvalidReferencesPass())->process($container);
$this->assertCount(1, $container->getDefinition((string) $controllers['c2::setTestCase']->getValues()[0])->getArgument(0));
$this->assertSame([], $container->getDefinition((string) $controllers['c2::fooAction']->getValues()[0])->getArgument(0));
(new RemoveEmptyControllerArgumentLocatorsPass())->process($container);
$controllers = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
$this->assertSame(['c1::fooAction', 'c1:fooAction'], array_keys($controllers));
$this->assertSame(['bar'], array_keys($container->getDefinition((string) $controllers['c1::fooAction']->getValues()[0])->getArgument(0)));
$expectedLog = [
'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing service-argument resolver for controller "c2::fooAction": no corresponding services exist for the referenced types.',
'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing method "setTestCase" of service "c2" from controller candidates: the method is called at instantiation, thus cannot be an action.',
];
$this->assertSame($expectedLog, $container->getCompiler()->getLog());
}
public function testInvoke()
{
$container = new ContainerBuilder();
$resolver = $container->register('argument_resolver.service')->addArgument([]);
$container->register('invokable', InvokableRegisterTestController::class)
->addTag('controller.service_arguments')
;
(new RegisterControllerArgumentLocatorsPass())->process($container);
(new RemoveEmptyControllerArgumentLocatorsPass())->process($container);
$this->assertEquals(
['invokable::__invoke', 'invokable:__invoke', 'invokable'],
array_keys($container->getDefinition((string) $resolver->getArgument(0))->getArgument(0))
);
}
}
class RemoveTestController1
{
public function fooAction(\stdClass $bar, ClassNotInContainer $baz = null)
{
}
}
class RemoveTestController2
{
public function setTestCase(TestCase $test)
{
}
public function fooAction(ClassNotInContainer $bar = null)
{
}
}
class InvokableRegisterTestController
{
public function __invoke(\stdClass $bar)
{
}
}
class ClassNotInContainer
{
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\ResettableServicePass;
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableService;
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
class ResettableServicePassTest extends TestCase
{
public function testCompilerPass()
{
$container = new ContainerBuilder();
$container->register('one', ResettableService::class)
->setPublic(true)
->addTag('kernel.reset', ['method' => 'reset']);
$container->register('two', ClearableService::class)
->setPublic(true)
->addTag('kernel.reset', ['method' => 'clear']);
$container->register('services_resetter', ServicesResetter::class)
->setPublic(true)
->setArguments([null, []]);
$container->addCompilerPass(new ResettableServicePass());
$container->compile();
$definition = $container->getDefinition('services_resetter');
$this->assertEquals(
[
new IteratorArgument([
'one' => new Reference('one', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),
'two' => new Reference('two', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE),
]),
[
'one' => 'reset',
'two' => 'clear',
],
],
$definition->getArguments()
);
}
public function testMissingMethod()
{
$this->expectException('Symfony\Component\DependencyInjection\Exception\RuntimeException');
$this->expectExceptionMessage('Tag kernel.reset requires the "method" attribute to be set.');
$container = new ContainerBuilder();
$container->register(ResettableService::class)
->addTag('kernel.reset');
$container->register('services_resetter', ServicesResetter::class)
->setArguments([null, []]);
$container->addCompilerPass(new ResettableServicePass());
$container->compile();
}
public function testCompilerPassWithoutResetters()
{
$container = new ContainerBuilder();
$container->register('services_resetter', ServicesResetter::class)
->setArguments([null, []]);
$container->addCompilerPass(new ResettableServicePass());
$container->compile();
$this->assertFalse($container->has('services_resetter'));
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\DependencyInjection;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\DependencyInjection\ServicesResetter;
use Symfony\Component\HttpKernel\Tests\Fixtures\ClearableService;
use Symfony\Component\HttpKernel\Tests\Fixtures\ResettableService;
class ServicesResetterTest extends TestCase
{
protected function setUp(): void
{
ResettableService::$counter = 0;
ClearableService::$counter = 0;
}
public function testResetServices()
{
$resetter = new ServicesResetter(new \ArrayIterator([
'id1' => new ResettableService(),
'id2' => new ClearableService(),
]), [
'id1' => 'reset',
'id2' => 'clear',
]);
$resetter->reset();
$this->assertEquals(1, ResettableService::$counter);
$this->assertEquals(1, ClearableService::$counter);
}
}

View File

@@ -0,0 +1,17 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Event;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent;
use Symfony\Component\HttpKernel\Tests\TestHttpKernel;
class ControllerArgumentsEventTest extends TestCase
{
public function testControllerArgumentsEvent()
{
$filterController = new ControllerArgumentsEvent(new TestHttpKernel(), function () {}, ['test'], new Request(), 1);
$this->assertEquals($filterController->getArguments(), ['test']);
}
}

View File

@@ -0,0 +1,27 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Event;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Tests\TestHttpKernel;
class ExceptionEventTest extends TestCase
{
public function testAllowSuccessfulResponseIsFalseByDefault()
{
$event = new ExceptionEvent(new TestHttpKernel(), new Request(), 1, new \Exception());
$this->assertFalse($event->isAllowingCustomResponseCode());
}
}

View File

@@ -0,0 +1,85 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\EventListener\AddRequestFormatsListener;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* Test AddRequestFormatsListener class.
*
* @author Gildas Quemener <gildas.quemener@gmail.com>
*/
class AddRequestFormatsListenerTest extends TestCase
{
/**
* @var AddRequestFormatsListener
*/
private $listener;
protected function setUp(): void
{
$this->listener = new AddRequestFormatsListener(['csv' => ['text/csv', 'text/plain']]);
}
protected function tearDown(): void
{
$this->listener = null;
}
public function testIsAnEventSubscriber()
{
$this->assertInstanceOf('Symfony\Component\EventDispatcher\EventSubscriberInterface', $this->listener);
}
public function testRegisteredEvent()
{
$this->assertEquals(
[KernelEvents::REQUEST => ['onKernelRequest', 100]],
AddRequestFormatsListener::getSubscribedEvents()
);
}
public function testSetAdditionalFormats()
{
$request = $this->getRequestMock();
$event = $this->getRequestEventMock($request);
$request->expects($this->once())
->method('setFormat')
->with('csv', ['text/csv', 'text/plain']);
$this->listener->onKernelRequest($event);
}
protected function getRequestMock()
{
return $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')->getMock();
}
protected function getRequestEventMock(Request $request)
{
$event = $this
->getMockBuilder(RequestEvent::class)
->disableOriginalConstructor()
->getMock();
$event->expects($this->any())
->method('getRequest')
->willReturn($request);
return $event;
}
}

View File

@@ -0,0 +1,156 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Psr\Log\LogLevel;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleEvent;
use Symfony\Component\Console\Helper\HelperSet;
use Symfony\Component\Console\Input\ArgvInput;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Debug\ErrorHandler;
use Symfony\Component\Debug\ExceptionHandler;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\KernelEvent;
use Symfony\Component\HttpKernel\EventListener\DebugHandlersListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
class DebugHandlersListenerTest extends TestCase
{
public function testConfigure()
{
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$userHandler = function () {};
$listener = new DebugHandlersListener($userHandler, $logger);
$xHandler = new ExceptionHandler();
$eHandler = new ErrorHandler();
$eHandler->setExceptionHandler([$xHandler, 'handle']);
$exception = null;
set_error_handler([$eHandler, 'handleError']);
set_exception_handler([$eHandler, 'handleException']);
try {
$listener->configure();
} catch (\Exception $exception) {
}
restore_exception_handler();
restore_error_handler();
if (null !== $exception) {
throw $exception;
}
$this->assertSame($userHandler, $xHandler->setHandler('var_dump'));
$loggers = $eHandler->setLoggers([]);
$this->assertArrayHasKey(E_DEPRECATED, $loggers);
$this->assertSame([$logger, LogLevel::INFO], $loggers[E_DEPRECATED]);
}
public function testConfigureForHttpKernelWithNoTerminateWithException()
{
$listener = new DebugHandlersListener(null);
$eHandler = new ErrorHandler();
$event = new KernelEvent(
$this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(),
Request::create('/'),
HttpKernelInterface::MASTER_REQUEST
);
$exception = null;
$h = set_exception_handler([$eHandler, 'handleException']);
try {
$listener->configure($event);
} catch (\Exception $exception) {
}
restore_exception_handler();
if (null !== $exception) {
throw $exception;
}
$this->assertNull($h);
}
public function testConsoleEvent()
{
$dispatcher = new EventDispatcher();
$listener = new DebugHandlersListener(null);
$app = $this->getMockBuilder('Symfony\Component\Console\Application')->getMock();
$app->expects($this->once())->method('getHelperSet')->willReturn(new HelperSet());
$command = new Command(__FUNCTION__);
$command->setApplication($app);
$event = new ConsoleEvent($command, new ArgvInput(), new ConsoleOutput());
$dispatcher->addSubscriber($listener);
$xListeners = [
KernelEvents::REQUEST => [[$listener, 'configure']],
ConsoleEvents::COMMAND => [[$listener, 'configure']],
KernelEvents::EXCEPTION => [[$listener, 'onKernelException']],
];
$this->assertSame($xListeners, $dispatcher->getListeners());
$exception = null;
$eHandler = new ErrorHandler();
set_error_handler([$eHandler, 'handleError']);
set_exception_handler([$eHandler, 'handleException']);
try {
$dispatcher->dispatch($event, ConsoleEvents::COMMAND);
} catch (\Exception $exception) {
}
restore_exception_handler();
restore_error_handler();
if (null !== $exception) {
throw $exception;
}
$xHandler = $eHandler->setExceptionHandler('var_dump');
$this->assertInstanceOf('Closure', $xHandler);
$app->expects($this->once())
->method('renderException');
$xHandler(new \Exception());
}
public function testReplaceExistingExceptionHandler()
{
$userHandler = function () {};
$listener = new DebugHandlersListener($userHandler);
$eHandler = new ErrorHandler();
$eHandler->setExceptionHandler('var_dump');
$exception = null;
set_exception_handler([$eHandler, 'handleException']);
try {
$listener->configure();
} catch (\Exception $exception) {
}
restore_exception_handler();
if (null !== $exception) {
throw $exception;
}
$this->assertSame($userHandler, $eHandler->setExceptionHandler('var_dump'));
}
}

View File

@@ -0,0 +1,47 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\EventListener\DisallowRobotsIndexingListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelInterface;
class DisallowRobotsIndexingListenerTest extends TestCase
{
/**
* @dataProvider provideResponses
*/
public function testInvoke(?string $expected, Response $response): void
{
$listener = new DisallowRobotsIndexingListener();
$event = new ResponseEvent($this->createMock(HttpKernelInterface::class), $this->createMock(Request::class), KernelInterface::MASTER_REQUEST, $response);
$listener->onResponse($event);
$this->assertSame($expected, $response->headers->get('X-Robots-Tag'), 'Header doesn\'t match expectations');
}
public function provideResponses(): iterable
{
yield 'No header' => ['noindex', new Response()];
yield 'Header already set' => [
'something else',
new Response('', 204, ['X-Robots-Tag' => 'something else']),
];
}
}

View File

@@ -0,0 +1,81 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\HttpKernel\EventListener\DumpListener;
use Symfony\Component\VarDumper\Cloner\ClonerInterface;
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Dumper\DataDumperInterface;
use Symfony\Component\VarDumper\VarDumper;
/**
* DumpListenerTest.
*
* @author Nicolas Grekas <p@tchwork.com>
*/
class DumpListenerTest extends TestCase
{
public function testSubscribedEvents()
{
$this->assertSame(
[ConsoleEvents::COMMAND => ['configure', 1024]],
DumpListener::getSubscribedEvents()
);
}
public function testConfigure()
{
$prevDumper = VarDumper::setHandler('var_dump');
VarDumper::setHandler($prevDumper);
$cloner = new MockCloner();
$dumper = new MockDumper();
ob_start();
$exception = null;
$listener = new DumpListener($cloner, $dumper);
try {
$listener->configure();
VarDumper::dump('foo');
VarDumper::dump('bar');
$this->assertSame('+foo-+bar-', ob_get_clean());
} catch (\Exception $exception) {
}
VarDumper::setHandler($prevDumper);
if (null !== $exception) {
throw $exception;
}
}
}
class MockCloner implements ClonerInterface
{
public function cloneVar($var)
{
return new Data([[$var.'-']]);
}
}
class MockDumper implements DataDumperInterface
{
public function dump(Data $data)
{
echo '+'.$data->getValue();
}
}

View File

@@ -0,0 +1,182 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\EventListener\ExceptionListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
use Symfony\Component\HttpKernel\Tests\Logger;
/**
* ExceptionListenerTest.
*
* @author Robert Schönthal <seroscho@googlemail.com>
*
* @group time-sensitive
*/
class ExceptionListenerTest extends TestCase
{
public function testConstruct()
{
$logger = new TestLogger();
$l = new ExceptionListener('foo', $logger);
$_logger = new \ReflectionProperty(\get_class($l), 'logger');
$_logger->setAccessible(true);
$_controller = new \ReflectionProperty(\get_class($l), 'controller');
$_controller->setAccessible(true);
$this->assertSame($logger, $_logger->getValue($l));
$this->assertSame('foo', $_controller->getValue($l));
}
/**
* @dataProvider provider
*/
public function testHandleWithoutLogger($event, $event2)
{
$this->iniSet('error_log', file_exists('/dev/null') ? '/dev/null' : 'nul');
$l = new ExceptionListener('foo');
$l->logKernelException($event);
$l->onKernelException($event);
$this->assertEquals(new Response('foo'), $event->getResponse());
try {
$l->logKernelException($event2);
$l->onKernelException($event2);
$this->fail('RuntimeException expected');
} catch (\RuntimeException $e) {
$this->assertSame('bar', $e->getMessage());
$this->assertSame('foo', $e->getPrevious()->getMessage());
}
}
/**
* @dataProvider provider
*/
public function testHandleWithLogger($event, $event2)
{
$logger = new TestLogger();
$l = new ExceptionListener('foo', $logger);
$l->logKernelException($event);
$l->onKernelException($event);
$this->assertEquals(new Response('foo'), $event->getResponse());
try {
$l->logKernelException($event2);
$l->onKernelException($event2);
$this->fail('RuntimeException expected');
} catch (\RuntimeException $e) {
$this->assertSame('bar', $e->getMessage());
$this->assertSame('foo', $e->getPrevious()->getMessage());
}
$this->assertEquals(3, $logger->countErrors());
$this->assertCount(3, $logger->getLogs('critical'));
}
public function provider()
{
if (!class_exists('Symfony\Component\HttpFoundation\Request')) {
return [[null, null]];
}
$request = new Request();
$exception = new \Exception('foo');
$event = new ExceptionEvent(new TestKernel(), $request, HttpKernelInterface::MASTER_REQUEST, $exception);
$event2 = new ExceptionEvent(new TestKernelThatThrowsException(), $request, HttpKernelInterface::MASTER_REQUEST, $exception);
return [
[$event, $event2],
];
}
public function testSubRequestFormat()
{
$listener = new ExceptionListener('foo', $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock());
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$kernel->expects($this->once())->method('handle')->willReturnCallback(function (Request $request) {
return new Response($request->getRequestFormat());
});
$request = Request::create('/');
$request->setRequestFormat('xml');
$event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo'));
$listener->onKernelException($event);
$response = $event->getResponse();
$this->assertEquals('xml', $response->getContent());
}
public function testCSPHeaderIsRemoved()
{
$dispatcher = new EventDispatcher();
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$kernel->expects($this->once())->method('handle')->willReturnCallback(function (Request $request) {
return new Response($request->getRequestFormat());
});
$listener = new ExceptionListener('foo', $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(), true);
$dispatcher->addSubscriber($listener);
$request = Request::create('/');
$event = new ExceptionEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, new \Exception('foo'));
$dispatcher->dispatch($event, KernelEvents::EXCEPTION);
$response = new Response('', 200, ['content-security-policy' => "style-src 'self'"]);
$this->assertTrue($response->headers->has('content-security-policy'));
$event = new ResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response);
$dispatcher->dispatch($event, KernelEvents::RESPONSE);
$this->assertFalse($response->headers->has('content-security-policy'), 'CSP header has been removed');
$this->assertFalse($dispatcher->hasListeners(KernelEvents::RESPONSE), 'CSP removal listener has been removed');
}
}
class TestLogger extends Logger implements DebugLoggerInterface
{
public function countErrors(Request $request = null): int
{
return \count($this->logs['critical']);
}
}
class TestKernel implements HttpKernelInterface
{
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)
{
return new Response('foo');
}
}
class TestKernelThatThrowsException implements HttpKernelInterface
{
public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)
{
throw new \RuntimeException('bar');
}
}

View File

@@ -0,0 +1,118 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\EventListener\FragmentListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\UriSigner;
class FragmentListenerTest extends TestCase
{
public function testOnlyTriggeredOnFragmentRoute()
{
$request = Request::create('http://example.com/foo?_path=foo%3Dbar%26_controller%3Dfoo');
$listener = new FragmentListener(new UriSigner('foo'));
$event = $this->createRequestEvent($request);
$expected = $request->attributes->all();
$listener->onKernelRequest($event);
$this->assertEquals($expected, $request->attributes->all());
$this->assertTrue($request->query->has('_path'));
}
public function testOnlyTriggeredIfControllerWasNotDefinedYet()
{
$request = Request::create('http://example.com/_fragment?_path=foo%3Dbar%26_controller%3Dfoo');
$request->attributes->set('_controller', 'bar');
$listener = new FragmentListener(new UriSigner('foo'));
$event = $this->createRequestEvent($request, HttpKernelInterface::SUB_REQUEST);
$expected = $request->attributes->all();
$listener->onKernelRequest($event);
$this->assertEquals($expected, $request->attributes->all());
}
public function testAccessDeniedWithNonSafeMethods()
{
$this->expectException('Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException');
$request = Request::create('http://example.com/_fragment', 'POST');
$listener = new FragmentListener(new UriSigner('foo'));
$event = $this->createRequestEvent($request);
$listener->onKernelRequest($event);
}
public function testAccessDeniedWithWrongSignature()
{
$this->expectException('Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException');
$request = Request::create('http://example.com/_fragment', 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1']);
$listener = new FragmentListener(new UriSigner('foo'));
$event = $this->createRequestEvent($request);
$listener->onKernelRequest($event);
}
public function testWithSignature()
{
$signer = new UriSigner('foo');
$request = Request::create($signer->sign('http://example.com/_fragment?_path=foo%3Dbar%26_controller%3Dfoo'), 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1']);
$listener = new FragmentListener($signer);
$event = $this->createRequestEvent($request);
$listener->onKernelRequest($event);
$this->assertEquals(['foo' => 'bar', '_controller' => 'foo'], $request->attributes->get('_route_params'));
$this->assertFalse($request->query->has('_path'));
}
public function testRemovesPathWithControllerDefined()
{
$request = Request::create('http://example.com/_fragment?_path=foo%3Dbar%26_controller%3Dfoo');
$listener = new FragmentListener(new UriSigner('foo'));
$event = $this->createRequestEvent($request, HttpKernelInterface::SUB_REQUEST);
$listener->onKernelRequest($event);
$this->assertFalse($request->query->has('_path'));
}
public function testRemovesPathWithControllerNotDefined()
{
$signer = new UriSigner('foo');
$request = Request::create($signer->sign('http://example.com/_fragment?_path=foo%3Dbar'), 'GET', [], [], [], ['REMOTE_ADDR' => '10.0.0.1']);
$listener = new FragmentListener($signer);
$event = $this->createRequestEvent($request);
$listener->onKernelRequest($event);
$this->assertFalse($request->query->has('_path'));
}
private function createRequestEvent(Request $request, $requestType = HttpKernelInterface::MASTER_REQUEST)
{
return new RequestEvent($this->getMockBuilder(HttpKernelInterface::class)->getMock(), $request, $requestType);
}
}

View File

@@ -0,0 +1,119 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\EventListener\LocaleAwareListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
class LocaleAwareListenerTest extends TestCase
{
private $listener;
private $localeAwareService;
private $requestStack;
protected function setUp(): void
{
$this->localeAwareService = $this->getMockBuilder(LocaleAwareInterface::class)->getMock();
$this->requestStack = new RequestStack();
$this->listener = new LocaleAwareListener(new \ArrayIterator([$this->localeAwareService]), $this->requestStack);
}
public function testLocaleIsSetInOnKernelRequest()
{
$this->localeAwareService
->expects($this->once())
->method('setLocale')
->with($this->equalTo('fr'));
$event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST);
$this->listener->onKernelRequest($event);
}
public function testDefaultLocaleIsUsedOnExceptionsInOnKernelRequest()
{
$this->localeAwareService
->expects($this->at(0))
->method('setLocale')
->will($this->throwException(new \InvalidArgumentException()));
$this->localeAwareService
->expects($this->at(1))
->method('setLocale')
->with($this->equalTo('en'));
$event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST);
$this->listener->onKernelRequest($event);
}
public function testLocaleIsSetInOnKernelFinishRequestWhenParentRequestExists()
{
$this->localeAwareService
->expects($this->once())
->method('setLocale')
->with($this->equalTo('fr'));
$this->requestStack->push($this->createRequest('fr'));
$this->requestStack->push($subRequest = $this->createRequest('de'));
$event = new FinishRequestEvent($this->createHttpKernel(), $subRequest, HttpKernelInterface::SUB_REQUEST);
$this->listener->onKernelFinishRequest($event);
}
public function testLocaleIsSetToDefaultOnKernelFinishRequestWhenParentRequestDoesNotExist()
{
$this->localeAwareService
->expects($this->once())
->method('setLocale')
->with($this->equalTo('en'));
$this->requestStack->push($subRequest = $this->createRequest('de'));
$event = new FinishRequestEvent($this->createHttpKernel(), $subRequest, HttpKernelInterface::SUB_REQUEST);
$this->listener->onKernelFinishRequest($event);
}
public function testDefaultLocaleIsUsedOnExceptionsInOnKernelFinishRequest()
{
$this->localeAwareService
->expects($this->at(0))
->method('setLocale')
->will($this->throwException(new \InvalidArgumentException()));
$this->localeAwareService
->expects($this->at(1))
->method('setLocale')
->with($this->equalTo('en'));
$this->requestStack->push($this->createRequest('fr'));
$this->requestStack->push($subRequest = $this->createRequest('de'));
$event = new FinishRequestEvent($this->createHttpKernel(), $subRequest, HttpKernelInterface::SUB_REQUEST);
$this->listener->onKernelFinishRequest($event);
}
private function createHttpKernel()
{
return $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
}
private function createRequest($locale)
{
$request = new Request();
$request->setLocale($locale);
return $request;
}
}

View File

@@ -0,0 +1,120 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\EventListener\LocaleListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
class LocaleListenerTest extends TestCase
{
private $requestStack;
protected function setUp(): void
{
$this->requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->disableOriginalConstructor()->getMock();
}
public function testIsAnEventSubscriber()
{
$this->assertInstanceOf(EventSubscriberInterface::class, new LocaleListener($this->requestStack));
}
public function testRegisteredEvent()
{
$this->assertEquals(
[
KernelEvents::REQUEST => [['setDefaultLocale', 100], ['onKernelRequest', 16]],
KernelEvents::FINISH_REQUEST => [['onKernelFinishRequest', 0]],
],
LocaleListener::getSubscribedEvents()
);
}
public function testDefaultLocale()
{
$listener = new LocaleListener($this->requestStack, 'fr');
$event = $this->getEvent($request = Request::create('/'));
$listener->setDefaultLocale($event);
$this->assertEquals('fr', $request->getLocale());
}
public function testLocaleFromRequestAttribute()
{
$request = Request::create('/');
$request->cookies->set(session_name(), 'value');
$request->attributes->set('_locale', 'es');
$listener = new LocaleListener($this->requestStack, 'fr');
$event = $this->getEvent($request);
$listener->onKernelRequest($event);
$this->assertEquals('es', $request->getLocale());
}
public function testLocaleSetForRoutingContext()
{
// the request context is updated
$context = $this->getMockBuilder('Symfony\Component\Routing\RequestContext')->getMock();
$context->expects($this->once())->method('setParameter')->with('_locale', 'es');
$router = $this->getMockBuilder('Symfony\Component\Routing\Router')->setMethods(['getContext'])->disableOriginalConstructor()->getMock();
$router->expects($this->once())->method('getContext')->willReturn($context);
$request = Request::create('/');
$request->attributes->set('_locale', 'es');
$listener = new LocaleListener($this->requestStack, 'fr', $router);
$listener->onKernelRequest($this->getEvent($request));
}
public function testRouterResetWithParentRequestOnKernelFinishRequest()
{
// the request context is updated
$context = $this->getMockBuilder('Symfony\Component\Routing\RequestContext')->getMock();
$context->expects($this->once())->method('setParameter')->with('_locale', 'es');
$router = $this->getMockBuilder('Symfony\Component\Routing\Router')->setMethods(['getContext'])->disableOriginalConstructor()->getMock();
$router->expects($this->once())->method('getContext')->willReturn($context);
$parentRequest = Request::create('/');
$parentRequest->setLocale('es');
$this->requestStack->expects($this->once())->method('getParentRequest')->willReturn($parentRequest);
$event = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\FinishRequestEvent')->disableOriginalConstructor()->getMock();
$listener = new LocaleListener($this->requestStack, 'fr', $router);
$listener->onKernelFinishRequest($event);
}
public function testRequestLocaleIsNotOverridden()
{
$request = Request::create('/');
$request->setLocale('de');
$listener = new LocaleListener($this->requestStack, 'fr');
$event = $this->getEvent($request);
$listener->onKernelRequest($event);
$this->assertEquals('de', $request->getLocale());
}
private function getEvent(Request $request): RequestEvent
{
return new RequestEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $request, HttpKernelInterface::MASTER_REQUEST);
}
}

View File

@@ -0,0 +1,70 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\Event\TerminateEvent;
use Symfony\Component\HttpKernel\EventListener\ProfilerListener;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\Component\HttpKernel\Profiler\Profile;
class ProfilerListenerTest extends TestCase
{
/**
* Test a master and sub request with an exception and `onlyException` profiler option enabled.
*/
public function testKernelTerminate()
{
$profile = new Profile('token');
$profiler = $this->getMockBuilder('Symfony\Component\HttpKernel\Profiler\Profiler')
->disableOriginalConstructor()
->getMock();
$profiler->expects($this->once())
->method('collect')
->willReturn($profile);
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$masterRequest = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')
->disableOriginalConstructor()
->getMock();
$subRequest = $this->getMockBuilder('Symfony\Component\HttpFoundation\Request')
->disableOriginalConstructor()
->getMock();
$response = $this->getMockBuilder('Symfony\Component\HttpFoundation\Response')
->disableOriginalConstructor()
->getMock();
$requestStack = new RequestStack();
$requestStack->push($masterRequest);
$onlyException = true;
$listener = new ProfilerListener($profiler, $requestStack, null, $onlyException);
// master request
$listener->onKernelResponse(new ResponseEvent($kernel, $masterRequest, Kernel::MASTER_REQUEST, $response));
// sub request
$listener->onKernelException(new ExceptionEvent($kernel, $subRequest, Kernel::SUB_REQUEST, new HttpException(404)));
$listener->onKernelResponse(new ResponseEvent($kernel, $subRequest, Kernel::SUB_REQUEST, $response));
$listener->onKernelTerminate(new TerminateEvent($kernel, $masterRequest, $response));
}
}

View File

@@ -0,0 +1,95 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\EventListener\ResponseListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
class ResponseListenerTest extends TestCase
{
private $dispatcher;
private $kernel;
protected function setUp(): void
{
$this->dispatcher = new EventDispatcher();
$listener = new ResponseListener('UTF-8');
$this->dispatcher->addListener(KernelEvents::RESPONSE, [$listener, 'onKernelResponse']);
$this->kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
}
protected function tearDown(): void
{
$this->dispatcher = null;
$this->kernel = null;
}
public function testFilterDoesNothingForSubRequests()
{
$response = new Response('foo');
$event = new ResponseEvent($this->kernel, new Request(), HttpKernelInterface::SUB_REQUEST, $response);
$this->dispatcher->dispatch($event, KernelEvents::RESPONSE);
$this->assertEquals('', $event->getResponse()->headers->get('content-type'));
}
public function testFilterSetsNonDefaultCharsetIfNotOverridden()
{
$listener = new ResponseListener('ISO-8859-15');
$this->dispatcher->addListener(KernelEvents::RESPONSE, [$listener, 'onKernelResponse'], 1);
$response = new Response('foo');
$event = new ResponseEvent($this->kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $response);
$this->dispatcher->dispatch($event, KernelEvents::RESPONSE);
$this->assertEquals('ISO-8859-15', $response->getCharset());
}
public function testFilterDoesNothingIfCharsetIsOverridden()
{
$listener = new ResponseListener('ISO-8859-15');
$this->dispatcher->addListener(KernelEvents::RESPONSE, [$listener, 'onKernelResponse'], 1);
$response = new Response('foo');
$response->setCharset('ISO-8859-1');
$event = new ResponseEvent($this->kernel, Request::create('/'), HttpKernelInterface::MASTER_REQUEST, $response);
$this->dispatcher->dispatch($event, KernelEvents::RESPONSE);
$this->assertEquals('ISO-8859-1', $response->getCharset());
}
public function testFiltersSetsNonDefaultCharsetIfNotOverriddenOnNonTextContentType()
{
$listener = new ResponseListener('ISO-8859-15');
$this->dispatcher->addListener(KernelEvents::RESPONSE, [$listener, 'onKernelResponse'], 1);
$response = new Response('foo');
$request = Request::create('/');
$request->setRequestFormat('application/json');
$event = new ResponseEvent($this->kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response);
$this->dispatcher->dispatch($event, KernelEvents::RESPONSE);
$this->assertEquals('ISO-8859-15', $response->getCharset());
}
}

View File

@@ -0,0 +1,217 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Controller\ArgumentResolver;
use Symfony\Component\HttpKernel\Controller\ControllerResolver;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\EventListener\ExceptionListener;
use Symfony\Component\HttpKernel\EventListener\RouterListener;
use Symfony\Component\HttpKernel\EventListener\ValidateRequestListener;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Routing\Exception\NoConfigurationException;
use Symfony\Component\Routing\RequestContext;
class RouterListenerTest extends TestCase
{
private $requestStack;
protected function setUp(): void
{
$this->requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->disableOriginalConstructor()->getMock();
}
/**
* @dataProvider getPortData
*/
public function testPort($defaultHttpPort, $defaultHttpsPort, $uri, $expectedHttpPort, $expectedHttpsPort)
{
$urlMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\UrlMatcherInterface')
->disableOriginalConstructor()
->getMock();
$context = new RequestContext();
$context->setHttpPort($defaultHttpPort);
$context->setHttpsPort($defaultHttpsPort);
$urlMatcher->expects($this->any())
->method('getContext')
->willReturn($context);
$listener = new RouterListener($urlMatcher, $this->requestStack);
$event = $this->createRequestEventForUri($uri);
$listener->onKernelRequest($event);
$this->assertEquals($expectedHttpPort, $context->getHttpPort());
$this->assertEquals($expectedHttpsPort, $context->getHttpsPort());
$this->assertEquals(0 === strpos($uri, 'https') ? 'https' : 'http', $context->getScheme());
}
public function getPortData()
{
return [
[80, 443, 'http://localhost/', 80, 443],
[80, 443, 'http://localhost:90/', 90, 443],
[80, 443, 'https://localhost/', 80, 443],
[80, 443, 'https://localhost:90/', 80, 90],
];
}
private function createRequestEventForUri(string $uri): RequestEvent
{
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$request = Request::create($uri);
$request->attributes->set('_controller', null); // Prevents going in to routing process
return new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
}
public function testInvalidMatcher()
{
$this->expectException('InvalidArgumentException');
new RouterListener(new \stdClass(), $this->requestStack);
}
public function testRequestMatcher()
{
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$request = Request::create('http://localhost/');
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
$requestMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock();
$requestMatcher->expects($this->once())
->method('matchRequest')
->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
->willReturn([]);
$listener = new RouterListener($requestMatcher, $this->requestStack, new RequestContext());
$listener->onKernelRequest($event);
}
public function testSubRequestWithDifferentMethod()
{
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$request = Request::create('http://localhost/', 'post');
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
$requestMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock();
$requestMatcher->expects($this->any())
->method('matchRequest')
->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Request'))
->willReturn([]);
$context = new RequestContext();
$listener = new RouterListener($requestMatcher, $this->requestStack, new RequestContext());
$listener->onKernelRequest($event);
// sub-request with another HTTP method
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$request = Request::create('http://localhost/', 'get');
$event = new RequestEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST);
$listener->onKernelRequest($event);
$this->assertEquals('GET', $context->getMethod());
}
/**
* @dataProvider getLoggingParameterData
*/
public function testLoggingParameter($parameter, $log, $parameters)
{
$requestMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock();
$requestMatcher->expects($this->once())
->method('matchRequest')
->willReturn($parameter);
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
$logger->expects($this->once())
->method('info')
->with($this->equalTo($log), $this->equalTo($parameters));
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$request = Request::create('http://localhost/');
$listener = new RouterListener($requestMatcher, $this->requestStack, new RequestContext(), $logger);
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST));
}
public function getLoggingParameterData()
{
return [
[['_route' => 'foo'], 'Matched route "{route}".', ['route' => 'foo', 'route_parameters' => ['_route' => 'foo'], 'request_uri' => 'http://localhost/', 'method' => 'GET']],
[[], 'Matched route "{route}".', ['route' => 'n/a', 'route_parameters' => [], 'request_uri' => 'http://localhost/', 'method' => 'GET']],
];
}
public function testWithBadRequest()
{
$requestStack = new RequestStack();
$requestMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock();
$requestMatcher->expects($this->never())->method('matchRequest');
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new ValidateRequestListener());
$dispatcher->addSubscriber(new RouterListener($requestMatcher, $requestStack, new RequestContext()));
$dispatcher->addSubscriber(new ExceptionListener(function () {
return new Response('Exception handled', 400);
}));
$kernel = new HttpKernel($dispatcher, new ControllerResolver(), $requestStack, new ArgumentResolver());
$request = Request::create('http://localhost/');
$request->headers->set('host', '###');
$response = $kernel->handle($request);
$this->assertSame(400, $response->getStatusCode());
}
public function testNoRoutingConfigurationResponse()
{
$requestStack = new RequestStack();
$requestMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock();
$requestMatcher
->expects($this->once())
->method('matchRequest')
->willThrowException(new NoConfigurationException())
;
$dispatcher = new EventDispatcher();
$dispatcher->addSubscriber(new RouterListener($requestMatcher, $requestStack, new RequestContext()));
$kernel = new HttpKernel($dispatcher, new ControllerResolver(), $requestStack, new ArgumentResolver());
$request = Request::create('http://localhost/');
$response = $kernel->handle($request);
$this->assertSame(404, $response->getStatusCode());
$this->assertStringContainsString('Welcome', $response->getContent());
}
public function testRequestWithBadHost()
{
$this->expectException('Symfony\Component\HttpKernel\Exception\BadRequestHttpException');
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$request = Request::create('http://bad host %22/');
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
$requestMatcher = $this->getMockBuilder('Symfony\Component\Routing\Matcher\RequestMatcherInterface')->getMock();
$listener = new RouterListener($requestMatcher, $this->requestStack, new RequestContext());
$listener->onKernelRequest($event);
}
}

View File

@@ -0,0 +1,52 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\EventListener\SaveSessionListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* @group legacy
*/
class SaveSessionListenerTest extends TestCase
{
public function testOnlyTriggeredOnMasterRequest()
{
$listener = new SaveSessionListener();
$event = $this->getMockBuilder(ResponseEvent::class)->disableOriginalConstructor()->getMock();
$event->expects($this->once())->method('isMasterRequest')->willReturn(false);
$event->expects($this->never())->method('getRequest');
// sub request
$listener->onKernelResponse($event);
}
public function testSessionSaved()
{
$listener = new SaveSessionListener();
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock();
$session = $this->getMockBuilder(SessionInterface::class)->disableOriginalConstructor()->getMock();
$session->expects($this->once())->method('isStarted')->willReturn(true);
$session->expects($this->once())->method('save');
$request = new Request();
$request->setSession($session);
$response = new Response();
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response));
}
}

View File

@@ -0,0 +1,181 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\EventListener\AbstractSessionListener;
use Symfony\Component\HttpKernel\EventListener\SessionListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class SessionListenerTest extends TestCase
{
public function testOnlyTriggeredOnMasterRequest()
{
$listener = $this->getMockForAbstractClass(AbstractSessionListener::class);
$event = $this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock();
$event->expects($this->once())->method('isMasterRequest')->willReturn(false);
$event->expects($this->never())->method('getRequest');
// sub request
$listener->onKernelRequest($event);
}
public function testSessionIsSet()
{
$session = $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock();
$requestStack = $this->getMockBuilder(RequestStack::class)->getMock();
$requestStack->expects($this->once())->method('getMasterRequest')->willReturn(null);
$sessionStorage = $this->getMockBuilder(NativeSessionStorage::class)->getMock();
$sessionStorage->expects($this->never())->method('setOptions')->with(['cookie_secure' => true]);
$container = new Container();
$container->set('session', $session);
$container->set('request_stack', $requestStack);
$container->set('session_storage', $sessionStorage);
$request = new Request();
$listener = new SessionListener($container);
$event = $this->getMockBuilder(RequestEvent::class)->disableOriginalConstructor()->getMock();
$event->expects($this->once())->method('isMasterRequest')->willReturn(true);
$event->expects($this->once())->method('getRequest')->willReturn($request);
$listener->onKernelRequest($event);
$this->assertTrue($request->hasSession());
$this->assertSame($session, $request->getSession());
}
public function testResponseIsPrivateIfSessionStarted()
{
$session = $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock();
$session->expects($this->exactly(2))->method('getUsageIndex')->will($this->onConsecutiveCalls(0, 1));
$container = new Container();
$container->set('initialized_session', $session);
$listener = new SessionListener($container);
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock();
$request = new Request();
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST));
$response = new Response();
$listener->onKernelResponse(new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response));
$this->assertTrue($response->headers->has('Expires'));
$this->assertTrue($response->headers->hasCacheControlDirective('private'));
$this->assertTrue($response->headers->hasCacheControlDirective('must-revalidate'));
$this->assertSame('0', $response->headers->getCacheControlDirective('max-age'));
$this->assertLessThanOrEqual((new \DateTime('now', new \DateTimeZone('UTC'))), (new \DateTime($response->headers->get('Expires'))));
$this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));
}
public function testResponseIsStillPublicIfSessionStartedAndHeaderPresent()
{
$session = $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock();
$session->expects($this->exactly(2))->method('getUsageIndex')->will($this->onConsecutiveCalls(0, 1));
$container = new Container();
$container->set('initialized_session', $session);
$listener = new SessionListener($container);
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock();
$request = new Request();
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST));
$response = new Response();
$response->setSharedMaxAge(60);
$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');
$listener->onKernelResponse(new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response));
$this->assertTrue($response->headers->hasCacheControlDirective('public'));
$this->assertFalse($response->headers->has('Expires'));
$this->assertFalse($response->headers->hasCacheControlDirective('private'));
$this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate'));
$this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage'));
$this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));
}
public function testUninitializedSession()
{
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock();
$response = new Response();
$response->setSharedMaxAge(60);
$response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');
$container = new ServiceLocator([
'initialized_session' => function () {},
]);
$listener = new SessionListener($container);
$listener->onKernelResponse(new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response));
$this->assertFalse($response->headers->has('Expires'));
$this->assertTrue($response->headers->hasCacheControlDirective('public'));
$this->assertFalse($response->headers->hasCacheControlDirective('private'));
$this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate'));
$this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage'));
$this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));
}
public function testSurrogateMasterRequestIsPublic()
{
$session = $this->getMockBuilder(Session::class)->disableOriginalConstructor()->getMock();
$session->expects($this->exactly(4))->method('getUsageIndex')->will($this->onConsecutiveCalls(0, 1, 1, 1));
$container = new Container();
$container->set('initialized_session', $session);
$container->set('session', $session);
$listener = new SessionListener($container);
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->disableOriginalConstructor()->getMock();
$request = new Request();
$response = new Response();
$response->setCache(['public' => true, 'max_age' => '30']);
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST));
$this->assertTrue($request->hasSession());
$subRequest = clone $request;
$this->assertSame($request->getSession(), $subRequest->getSession());
$listener->onKernelRequest(new RequestEvent($kernel, $subRequest, HttpKernelInterface::MASTER_REQUEST));
$listener->onKernelResponse(new ResponseEvent($kernel, $subRequest, HttpKernelInterface::MASTER_REQUEST, $response));
$listener->onFinishRequest(new FinishRequestEvent($kernel, $subRequest, HttpKernelInterface::MASTER_REQUEST));
$this->assertFalse($response->headers->has('Expires'));
$this->assertFalse($response->headers->hasCacheControlDirective('private'));
$this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate'));
$this->assertSame('30', $response->headers->getCacheControlDirective('max-age'));
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST, $response));
$this->assertTrue($response->headers->hasCacheControlDirective('private'));
$this->assertTrue($response->headers->hasCacheControlDirective('must-revalidate'));
$this->assertSame('0', $response->headers->getCacheControlDirective('max-age'));
$this->assertTrue($response->headers->has('Expires'));
$this->assertLessThanOrEqual((new \DateTime('now', new \DateTimeZone('UTC'))), (new \DateTime($response->headers->get('Expires'))));
}
}

View File

@@ -0,0 +1,67 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\EventListener\SurrogateListener;
use Symfony\Component\HttpKernel\HttpCache\Esi;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
class SurrogateListenerTest extends TestCase
{
public function testFilterDoesNothingForSubRequests()
{
$dispatcher = new EventDispatcher();
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$response = new Response('foo <esi:include src="" />');
$listener = new SurrogateListener(new Esi());
$dispatcher->addListener(KernelEvents::RESPONSE, [$listener, 'onKernelResponse']);
$event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::SUB_REQUEST, $response);
$dispatcher->dispatch($event, KernelEvents::RESPONSE);
$this->assertEquals('', $event->getResponse()->headers->get('Surrogate-Control'));
}
public function testFilterWhenThereIsSomeEsiIncludes()
{
$dispatcher = new EventDispatcher();
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$response = new Response('foo <esi:include src="" />');
$listener = new SurrogateListener(new Esi());
$dispatcher->addListener(KernelEvents::RESPONSE, [$listener, 'onKernelResponse']);
$event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response);
$dispatcher->dispatch($event, KernelEvents::RESPONSE);
$this->assertEquals('content="ESI/1.0"', $event->getResponse()->headers->get('Surrogate-Control'));
}
public function testFilterWhenThereIsNoEsiIncludes()
{
$dispatcher = new EventDispatcher();
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$response = new Response('foo');
$listener = new SurrogateListener(new Esi());
$dispatcher->addListener(KernelEvents::RESPONSE, [$listener, 'onKernelResponse']);
$event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response);
$dispatcher->dispatch($event, KernelEvents::RESPONSE);
$this->assertEquals('', $event->getResponse()->headers->get('Surrogate-Control'));
}
}

View File

@@ -0,0 +1,221 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\EventListener\SessionListener;
use Symfony\Component\HttpKernel\EventListener\TestSessionListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
/**
* SessionListenerTest.
*
* Tests SessionListener.
*
* @author Bulat Shakirzyanov <mallluhuct@gmail.com>
*/
class TestSessionListenerTest extends TestCase
{
/**
* @var TestSessionListener
*/
private $listener;
/**
* @var SessionInterface
*/
private $session;
protected function setUp(): void
{
$this->listener = $this->getMockForAbstractClass('Symfony\Component\HttpKernel\EventListener\AbstractTestSessionListener');
$this->session = $this->getSession();
$this->listener->expects($this->any())
->method('getSession')
->willReturn($this->session);
}
public function testShouldSaveMasterRequestSession()
{
$this->sessionHasBeenStarted();
$this->sessionMustBeSaved();
$this->filterResponse(new Request());
}
public function testShouldNotSaveSubRequestSession()
{
$this->sessionMustNotBeSaved();
$this->filterResponse(new Request(), HttpKernelInterface::SUB_REQUEST);
}
public function testDoesNotDeleteCookieIfUsingSessionLifetime()
{
$this->sessionHasBeenStarted();
@ini_set('session.cookie_lifetime', 0);
$response = $this->filterResponse(new Request(), HttpKernelInterface::MASTER_REQUEST);
$cookies = $response->headers->getCookies();
$this->assertEquals(0, reset($cookies)->getExpiresTime());
}
/**
* @requires function \Symfony\Component\HttpFoundation\Session\Session::isEmpty
*/
public function testEmptySessionDoesNotSendCookie()
{
$this->sessionHasBeenStarted();
$this->sessionIsEmpty();
$response = $this->filterResponse(new Request(), HttpKernelInterface::MASTER_REQUEST);
$this->assertSame([], $response->headers->getCookies());
}
public function testEmptySessionWithNewSessionIdDoesSendCookie()
{
$this->sessionHasBeenStarted();
$this->sessionIsEmpty();
$this->fixSessionId('456');
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$request = Request::create('/', 'GET', [], ['MOCKSESSID' => '123']);
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
$this->listener->onKernelRequest($event);
$response = $this->filterResponse(new Request(), HttpKernelInterface::MASTER_REQUEST);
$this->assertNotEmpty($response->headers->getCookies());
}
/**
* @dataProvider anotherCookieProvider
*/
public function testSessionWithNewSessionIdAndNewCookieDoesNotSendAnotherCookie($existing, array $expected)
{
$this->sessionHasBeenStarted();
$this->sessionIsEmpty();
$this->fixSessionId('456');
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$request = Request::create('/', 'GET', [], ['MOCKSESSID' => '123']);
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
$this->listener->onKernelRequest($event);
$response = new Response('', 200, ['Set-Cookie' => $existing]);
$response = $this->filterResponse(new Request(), HttpKernelInterface::MASTER_REQUEST, $response);
$this->assertSame($expected, $response->headers->get('Set-Cookie', null, false));
}
public function anotherCookieProvider()
{
return [
'same' => ['MOCKSESSID=789; path=/', ['MOCKSESSID=789; path=/']],
'different domain' => ['MOCKSESSID=789; path=/; domain=example.com', ['MOCKSESSID=789; path=/; domain=example.com', 'MOCKSESSID=456; path=/']],
'different path' => ['MOCKSESSID=789; path=/foo', ['MOCKSESSID=789; path=/foo', 'MOCKSESSID=456; path=/']],
];
}
public function testUnstartedSessionIsNotSave()
{
$this->sessionHasNotBeenStarted();
$this->sessionMustNotBeSaved();
$this->filterResponse(new Request());
}
public function testDoesNotThrowIfRequestDoesNotHaveASession()
{
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$event = new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, new Response());
$this->listener->onKernelResponse($event);
$this->assertTrue(true);
}
private function filterResponse(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, Response $response = null)
{
$request->setSession($this->session);
$response = $response ?: new Response();
$kernel = $this->getMockBuilder(HttpKernelInterface::class)->getMock();
$event = new ResponseEvent($kernel, $request, $type, $response);
$this->listener->onKernelResponse($event);
$this->assertSame($response, $event->getResponse());
return $response;
}
private function sessionMustNotBeSaved()
{
$this->session->expects($this->never())
->method('save');
}
private function sessionMustBeSaved()
{
$this->session->expects($this->once())
->method('save');
}
private function sessionHasBeenStarted()
{
$this->session->expects($this->once())
->method('isStarted')
->willReturn(true);
}
private function sessionHasNotBeenStarted()
{
$this->session->expects($this->once())
->method('isStarted')
->willReturn(false);
}
private function sessionIsEmpty()
{
$this->session->expects($this->once())
->method('isEmpty')
->willReturn(true);
}
private function fixSessionId($sessionId)
{
$this->session->expects($this->any())
->method('getId')
->willReturn($sessionId);
}
private function getSession()
{
$mock = $this->getMockBuilder('Symfony\Component\HttpFoundation\Session\Session')
->disableOriginalConstructor()
->getMock();
// set return value for getName()
$mock->expects($this->any())->method('getName')->willReturn('MOCKSESSID');
return $mock;
}
}

View File

@@ -0,0 +1,122 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\FinishRequestEvent;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\EventListener\TranslatorListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Contracts\Translation\LocaleAwareInterface;
/**
* @group legacy
*/
class TranslatorListenerTest extends TestCase
{
private $listener;
private $translator;
private $requestStack;
protected function setUp(): void
{
$this->translator = $this->getMockBuilder(LocaleAwareInterface::class)->getMock();
$this->requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock();
$this->listener = new TranslatorListener($this->translator, $this->requestStack);
}
public function testLocaleIsSetInOnKernelRequest()
{
$this->translator
->expects($this->once())
->method('setLocale')
->with($this->equalTo('fr'));
$event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST);
$this->listener->onKernelRequest($event);
}
public function testDefaultLocaleIsUsedOnExceptionsInOnKernelRequest()
{
$this->translator
->expects($this->at(0))
->method('setLocale')
->willThrowException(new \InvalidArgumentException());
$this->translator
->expects($this->at(1))
->method('setLocale')
->with($this->equalTo('en'));
$event = new RequestEvent($this->createHttpKernel(), $this->createRequest('fr'), HttpKernelInterface::MASTER_REQUEST);
$this->listener->onKernelRequest($event);
}
public function testLocaleIsSetInOnKernelFinishRequestWhenParentRequestExists()
{
$this->translator
->expects($this->once())
->method('setLocale')
->with($this->equalTo('fr'));
$this->setMasterRequest($this->createRequest('fr'));
$event = new FinishRequestEvent($this->createHttpKernel(), $this->createRequest('de'), HttpKernelInterface::SUB_REQUEST);
$this->listener->onKernelFinishRequest($event);
}
public function testLocaleIsNotSetInOnKernelFinishRequestWhenParentRequestDoesNotExist()
{
$this->translator
->expects($this->never())
->method('setLocale');
$event = new FinishRequestEvent($this->createHttpKernel(), $this->createRequest('de'), HttpKernelInterface::SUB_REQUEST);
$this->listener->onKernelFinishRequest($event);
}
public function testDefaultLocaleIsUsedOnExceptionsInOnKernelFinishRequest()
{
$this->translator
->expects($this->at(0))
->method('setLocale')
->willThrowException(new \InvalidArgumentException());
$this->translator
->expects($this->at(1))
->method('setLocale')
->with($this->equalTo('en'));
$this->setMasterRequest($this->createRequest('fr'));
$event = new FinishRequestEvent($this->createHttpKernel(), $this->createRequest('de'), HttpKernelInterface::SUB_REQUEST);
$this->listener->onKernelFinishRequest($event);
}
private function createHttpKernel()
{
return $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
}
private function createRequest($locale)
{
$request = new Request();
$request->setLocale($locale);
return $request;
}
private function setMasterRequest($request)
{
$this->requestStack
->expects($this->any())
->method('getParentRequest')
->willReturn($request);
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\EventListener;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\EventListener\ValidateRequestListener;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\KernelEvents;
class ValidateRequestListenerTest extends TestCase
{
protected function tearDown(): void
{
Request::setTrustedProxies([], -1);
}
public function testListenerThrowsWhenMasterRequestHasInconsistentClientIps()
{
$this->expectException('Symfony\Component\HttpFoundation\Exception\ConflictingHeadersException');
$dispatcher = new EventDispatcher();
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$request = new Request();
$request->setTrustedProxies(['1.1.1.1'], Request::HEADER_X_FORWARDED_FOR | Request::HEADER_FORWARDED);
$request->server->set('REMOTE_ADDR', '1.1.1.1');
$request->headers->set('FORWARDED', 'for=2.2.2.2');
$request->headers->set('X_FORWARDED_FOR', '3.3.3.3');
$dispatcher->addListener(KernelEvents::REQUEST, [new ValidateRequestListener(), 'onKernelRequest']);
$event = new RequestEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
$dispatcher->dispatch($event, KernelEvents::REQUEST);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
class AccessDeniedHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new AccessDeniedHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
class BadRequestHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new BadRequestHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\ConflictHttpException;
class ConflictHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new ConflictHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\GoneHttpException;
class GoneHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new GoneHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,61 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpKernel\Exception\HttpException;
class HttpExceptionTest extends TestCase
{
public function headerDataProvider()
{
return [
[['X-Test' => 'Test']],
[['X-Test' => 1]],
[
[
['X-Test' => 'Test'],
['X-Test-2' => 'Test-2'],
],
],
];
}
public function testHeadersDefault()
{
$exception = $this->createException();
$this->assertSame([], $exception->getHeaders());
}
/**
* @dataProvider headerDataProvider
*/
public function testHeadersConstructor($headers)
{
$exception = new HttpException(200, null, null, $headers);
$this->assertSame($headers, $exception->getHeaders());
}
/**
* @dataProvider headerDataProvider
*/
public function testHeadersSetter($headers)
{
$exception = $this->createException();
$exception->setHeaders($headers);
$this->assertSame($headers, $exception->getHeaders());
}
public function testThrowableIsAllowedForPrevious()
{
$previous = new class('Error of PHP 7+') extends \Error {
};
$exception = $this->createException(null, $previous);
$this->assertSame($previous, $exception->getPrevious());
}
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new HttpException(200, $message, $previous, $headers, $code);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\LengthRequiredHttpException;
class LengthRequiredHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new LengthRequiredHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
class MethodNotAllowedHttpExceptionTest extends HttpExceptionTest
{
public function testHeadersDefault()
{
$exception = new MethodNotAllowedHttpException(['GET', 'PUT']);
$this->assertSame(['Allow' => 'GET, PUT'], $exception->getHeaders());
}
public function testWithHeaderConstruct()
{
$headers = [
'Cache-Control' => 'public, s-maxage=1200',
];
$exception = new MethodNotAllowedHttpException(['get'], null, null, null, $headers);
$headers['Allow'] = 'GET';
$this->assertSame($headers, $exception->getHeaders());
}
/**
* @dataProvider headerDataProvider
*/
public function testHeadersSetter($headers)
{
$exception = new MethodNotAllowedHttpException(['GET']);
$exception->setHeaders($headers);
$this->assertSame($headers, $exception->getHeaders());
}
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new MethodNotAllowedHttpException(['get'], $message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\NotAcceptableHttpException;
class NotAcceptableHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new NotAcceptableHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class NotFoundHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new NotFoundHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\PreconditionFailedHttpException;
class PreconditionFailedHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new PreconditionFailedHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\PreconditionRequiredHttpException;
class PreconditionRequiredHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new PreconditionRequiredHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
class ServiceUnavailableHttpExceptionTest extends HttpExceptionTest
{
public function testHeadersDefaultRetryAfter()
{
$exception = new ServiceUnavailableHttpException(10);
$this->assertSame(['Retry-After' => 10], $exception->getHeaders());
}
public function testWithHeaderConstruct()
{
$headers = [
'Cache-Control' => 'public, s-maxage=1337',
];
$exception = new ServiceUnavailableHttpException(1337, null, null, null, $headers);
$headers['Retry-After'] = 1337;
$this->assertSame($headers, $exception->getHeaders());
}
/**
* @dataProvider headerDataProvider
*/
public function testHeadersSetter($headers)
{
$exception = new ServiceUnavailableHttpException(10);
$exception->setHeaders($headers);
$this->assertSame($headers, $exception->getHeaders());
}
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new ServiceUnavailableHttpException(null, $message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
class TooManyRequestsHttpExceptionTest extends HttpExceptionTest
{
public function testHeadersDefaultRertyAfter()
{
$exception = new TooManyRequestsHttpException(10);
$this->assertSame(['Retry-After' => 10], $exception->getHeaders());
}
public function testWithHeaderConstruct()
{
$headers = [
'Cache-Control' => 'public, s-maxage=69',
];
$exception = new TooManyRequestsHttpException(69, null, null, null, $headers);
$headers['Retry-After'] = 69;
$this->assertSame($headers, $exception->getHeaders());
}
/**
* @dataProvider headerDataProvider
*/
public function testHeadersSetter($headers)
{
$exception = new TooManyRequestsHttpException(10);
$exception->setHeaders($headers);
$this->assertSame($headers, $exception->getHeaders());
}
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new TooManyRequestsHttpException(null, $message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,42 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;
class UnauthorizedHttpExceptionTest extends HttpExceptionTest
{
public function testHeadersDefault()
{
$exception = new UnauthorizedHttpException('Challenge');
$this->assertSame(['WWW-Authenticate' => 'Challenge'], $exception->getHeaders());
}
public function testWithHeaderConstruct()
{
$headers = [
'Cache-Control' => 'public, s-maxage=1200',
];
$exception = new UnauthorizedHttpException('Challenge', null, null, null, $headers);
$headers['WWW-Authenticate'] = 'Challenge';
$this->assertSame($headers, $exception->getHeaders());
}
/**
* @dataProvider headerDataProvider
*/
public function testHeadersSetter($headers)
{
$exception = new UnauthorizedHttpException('Challenge');
$exception->setHeaders($headers);
$this->assertSame($headers, $exception->getHeaders());
}
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new UnauthorizedHttpException('Challenge', $message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
class UnprocessableEntityHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new UnprocessableEntityHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Exception;
use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
class UnsupportedMediaTypeHttpExceptionTest extends HttpExceptionTest
{
protected function createException(string $message = null, \Throwable $previous = null, ?int $code = 0, array $headers = [])
{
return new UnsupportedMediaTypeHttpException($message, $previous, $code, $headers);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Fixtures;
class ClearableService
{
public static $counter = 0;
public function clear()
{
++self::$counter;
}
}

View File

@@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller;
class BasicTypesController
{
public function action(string $foo, int $bar, float $baz)
{
}
}

View File

@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller;
use Symfony\Component\HttpFoundation\Request;
class ExtendingRequest extends Request
{
}

View File

@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller;
use Symfony\Component\HttpFoundation\Session\Session;
class ExtendingSession extends Session
{
}

View File

@@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller;
class NullableController
{
public function action(?string $foo, ?\stdClass $bar, ?string $baz = 'value', $mandatory)
{
}
}

View File

@@ -0,0 +1,19 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller;
class VariadicController
{
public function action($foo, ...$bar)
{
}
}

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures\DataCollector;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
class CloneVarDataCollector extends DataCollector
{
private $varToClone;
public function __construct($varToClone)
{
$this->varToClone = $varToClone;
}
public function collect(Request $request, Response $response, \Exception $exception = null)
{
$this->data = $this->cloneVar($this->varToClone);
}
public function reset()
{
$this->data = [];
}
public function getData()
{
return $this->data;
}
public function getName()
{
return 'clone_var';
}
}

View File

@@ -0,0 +1,20 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionNotValidBundle\DependencyInjection;
class ExtensionNotValidExtension
{
public function getAlias()
{
return 'extension_not_valid';
}
}

View File

@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionNotValidBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ExtensionNotValidBundle extends Bundle
{
}

View File

@@ -0,0 +1,22 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
class ExtensionPresentExtension extends Extension
{
public function load(array $configs, ContainerBuilder $container)
{
}
}

View File

@@ -0,0 +1,18 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class ExtensionPresentBundle extends Bundle
{
}

View File

@@ -0,0 +1,28 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpKernel\Kernel;
class KernelForOverrideName extends Kernel
{
protected $name = 'overridden';
public function registerBundles()
{
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
}
}

View File

@@ -0,0 +1,42 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\HttpKernel\Kernel;
class KernelForTest extends Kernel
{
public function getBundleMap()
{
return $this->bundleMap;
}
public function registerBundles()
{
return [];
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
}
public function isBooted()
{
return $this->booted;
}
public function getProjectDir(): string
{
return __DIR__;
}
}

View File

@@ -0,0 +1,38 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;
class KernelWithoutBundles extends Kernel
{
public function registerBundles()
{
return [];
}
public function registerContainerConfiguration(LoaderInterface $loader)
{
}
public function getProjectDir()
{
return __DIR__;
}
protected function build(ContainerBuilder $container)
{
$container->setParameter('test_executed', true);
}
}

View File

@@ -0,0 +1,13 @@
<?php
namespace Symfony\Component\HttpKernel\Tests\Fixtures;
class ResettableService
{
public static $counter = 0;
public function reset()
{
++self::$counter;
}
}

View File

@@ -0,0 +1,31 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fixtures;
use Symfony\Component\HttpKernel\HttpKernelBrowser;
class TestClient extends HttpKernelBrowser
{
protected function getScript($request)
{
$script = parent::getScript($request);
$autoload = file_exists(__DIR__.'/../../vendor/autoload.php')
? __DIR__.'/../../vendor/autoload.php'
: __DIR__.'/../../../../../../vendor/autoload.php'
;
$script = preg_replace('/(\->register\(\);)/', "$0\nrequire_once '$autoload';\n", $script);
return $script;
}
}

View File

@@ -0,0 +1,102 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fragment;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Symfony\Component\HttpKernel\Fragment\EsiFragmentRenderer;
use Symfony\Component\HttpKernel\HttpCache\Esi;
use Symfony\Component\HttpKernel\UriSigner;
class EsiFragmentRendererTest extends TestCase
{
public function testRenderFallbackToInlineStrategyIfEsiNotSupported()
{
$strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(true));
$strategy->render('/', Request::create('/'));
}
public function testRenderFallbackWithScalar()
{
$strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(true), new UriSigner('foo'));
$request = Request::create('/');
$reference = new ControllerReference('main_controller', ['foo' => [true]], []);
$strategy->render($reference, $request);
}
public function testRender()
{
$strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy());
$request = Request::create('/');
$request->setLocale('fr');
$request->headers->set('Surrogate-Capability', 'ESI/1.0');
$this->assertEquals('<esi:include src="/" />', $strategy->render('/', $request)->getContent());
$this->assertEquals("<esi:comment text=\"This is a comment\" />\n<esi:include src=\"/\" />", $strategy->render('/', $request, ['comment' => 'This is a comment'])->getContent());
$this->assertEquals('<esi:include src="/" alt="foo" />', $strategy->render('/', $request, ['alt' => 'foo'])->getContent());
}
public function testRenderControllerReference()
{
$signer = new UriSigner('foo');
$strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy(), $signer);
$request = Request::create('/');
$request->setLocale('fr');
$request->headers->set('Surrogate-Capability', 'ESI/1.0');
$reference = new ControllerReference('main_controller', [], []);
$altReference = new ControllerReference('alt_controller', [], []);
$this->assertEquals(
'<esi:include src="/_fragment?_hash=Jz1P8NErmhKTeI6onI1EdAXTB85359MY3RIk5mSJ60w%3D&_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dmain_controller" alt="/_fragment?_hash=iPJEdRoUpGrM1ztqByiorpfMPtiW%2FOWwdH1DBUXHhEc%3D&_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dalt_controller" />',
$strategy->render($reference, $request, ['alt' => $altReference])->getContent()
);
}
public function testRenderControllerReferenceWithoutSignerThrowsException()
{
$this->expectException('LogicException');
$strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy());
$request = Request::create('/');
$request->setLocale('fr');
$request->headers->set('Surrogate-Capability', 'ESI/1.0');
$strategy->render(new ControllerReference('main_controller'), $request);
}
public function testRenderAltControllerReferenceWithoutSignerThrowsException()
{
$this->expectException('LogicException');
$strategy = new EsiFragmentRenderer(new Esi(), $this->getInlineStrategy());
$request = Request::create('/');
$request->setLocale('fr');
$request->headers->set('Surrogate-Capability', 'ESI/1.0');
$strategy->render('/', $request, ['alt' => new ControllerReference('alt_controller')]);
}
private function getInlineStrategy($called = false)
{
$inline = $this->getMockBuilder('Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer')->disableOriginalConstructor()->getMock();
if ($called) {
$inline->expects($this->once())->method('render');
}
return $inline;
}
}

View File

@@ -0,0 +1,93 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fragment;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
/**
* @group time-sensitive
*/
class FragmentHandlerTest extends TestCase
{
private $requestStack;
protected function setUp(): void
{
$this->requestStack = $this->getMockBuilder('Symfony\\Component\\HttpFoundation\\RequestStack')
->disableOriginalConstructor()
->getMock()
;
$this->requestStack
->expects($this->any())
->method('getCurrentRequest')
->willReturn(Request::create('/'))
;
}
public function testRenderWhenRendererDoesNotExist()
{
$this->expectException('InvalidArgumentException');
$handler = new FragmentHandler($this->requestStack);
$handler->render('/', 'foo');
}
public function testRenderWithUnknownRenderer()
{
$this->expectException('InvalidArgumentException');
$handler = $this->getHandler($this->returnValue(new Response('foo')));
$handler->render('/', 'bar');
}
public function testDeliverWithUnsuccessfulResponse()
{
$this->expectException('RuntimeException');
$this->expectExceptionMessage('Error when rendering "http://localhost/" (Status code is 404).');
$handler = $this->getHandler($this->returnValue(new Response('foo', 404)));
$handler->render('/', 'foo');
}
public function testRender()
{
$handler = $this->getHandler($this->returnValue(new Response('foo')), ['/', Request::create('/'), ['foo' => 'foo', 'ignore_errors' => true]]);
$this->assertEquals('foo', $handler->render('/', 'foo', ['foo' => 'foo']));
}
protected function getHandler($returnValue, $arguments = [])
{
$renderer = $this->getMockBuilder('Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface')->getMock();
$renderer
->expects($this->any())
->method('getName')
->willReturn('foo')
;
$e = $renderer
->expects($this->any())
->method('render')
->will($returnValue)
;
if ($arguments) {
$e->with(...$arguments);
}
$handler = new FragmentHandler($this->requestStack);
$handler->addRenderer($renderer);
return $handler;
}
}

View File

@@ -0,0 +1,99 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fragment;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Symfony\Component\HttpKernel\Fragment\HIncludeFragmentRenderer;
use Symfony\Component\HttpKernel\UriSigner;
use Twig\Environment;
use Twig\Loader\ArrayLoader;
class HIncludeFragmentRendererTest extends TestCase
{
public function testRenderExceptionWhenControllerAndNoSigner()
{
$this->expectException('LogicException');
$strategy = new HIncludeFragmentRenderer();
$strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'));
}
public function testRenderWithControllerAndSigner()
{
$strategy = new HIncludeFragmentRenderer(null, new UriSigner('foo'));
$this->assertEquals('<hx:include src="/_fragment?_hash=BP%2BOzCD5MRUI%2BHJpgPDOmoju00FnzLhP3TGcSHbbBLs%3D&amp;_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dmain_controller"></hx:include>', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent());
}
public function testRenderWithUri()
{
$strategy = new HIncludeFragmentRenderer();
$this->assertEquals('<hx:include src="/foo"></hx:include>', $strategy->render('/foo', Request::create('/'))->getContent());
$strategy = new HIncludeFragmentRenderer(null, new UriSigner('foo'));
$this->assertEquals('<hx:include src="/foo"></hx:include>', $strategy->render('/foo', Request::create('/'))->getContent());
}
public function testRenderWithDefault()
{
// only default
$strategy = new HIncludeFragmentRenderer();
$this->assertEquals('<hx:include src="/foo">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default'])->getContent());
// only global default
$strategy = new HIncludeFragmentRenderer(null, null, 'global_default');
$this->assertEquals('<hx:include src="/foo">global_default</hx:include>', $strategy->render('/foo', Request::create('/'), [])->getContent());
// global default and default
$strategy = new HIncludeFragmentRenderer(null, null, 'global_default');
$this->assertEquals('<hx:include src="/foo">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default'])->getContent());
}
public function testRenderWithAttributesOptions()
{
// with id
$strategy = new HIncludeFragmentRenderer();
$this->assertEquals('<hx:include src="/foo" id="bar">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default', 'id' => 'bar'])->getContent());
// with attributes
$strategy = new HIncludeFragmentRenderer();
$this->assertEquals('<hx:include src="/foo" p1="v1" p2="v2">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default', 'attributes' => ['p1' => 'v1', 'p2' => 'v2']])->getContent());
// with id & attributes
$strategy = new HIncludeFragmentRenderer();
$this->assertEquals('<hx:include src="/foo" p1="v1" p2="v2" id="bar">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default', 'id' => 'bar', 'attributes' => ['p1' => 'v1', 'p2' => 'v2']])->getContent());
}
public function testRenderWithTwigAndDefaultText()
{
$twig = new Environment($loader = new ArrayLoader());
$strategy = new HIncludeFragmentRenderer($twig);
$this->assertEquals('<hx:include src="/foo">loading...</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'loading...'])->getContent());
}
/**
* @group legacy
*/
public function testRenderWithDefaultTextLegacy()
{
$engine = $this->getMockBuilder('Symfony\\Component\\Templating\\EngineInterface')->getMock();
$engine->expects($this->once())
->method('exists')
->with('default')
->willThrowException(new \InvalidArgumentException());
// only default
$strategy = new HIncludeFragmentRenderer($engine);
$this->assertEquals('<hx:include src="/foo">default</hx:include>', $strategy->render('/foo', Request::create('/'), ['default' => 'default'])->getContent());
}
}

View File

@@ -0,0 +1,280 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fragment;
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer;
use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;
class InlineFragmentRendererTest extends TestCase
{
public function testRender()
{
$strategy = new InlineFragmentRenderer($this->getKernel($this->returnValue(new Response('foo'))));
$this->assertEquals('foo', $strategy->render('/', Request::create('/'))->getContent());
}
public function testRenderWithControllerReference()
{
$strategy = new InlineFragmentRenderer($this->getKernel($this->returnValue(new Response('foo'))));
$this->assertEquals('foo', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent());
}
public function testRenderWithObjectsAsAttributes()
{
$object = new \stdClass();
$subRequest = Request::create('/_fragment?_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dmain_controller');
$subRequest->attributes->replace(['object' => $object, '_format' => 'html', '_controller' => 'main_controller', '_locale' => 'en']);
$subRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
$subRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
$subRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$subRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($subRequest));
$this->assertSame('foo', $strategy->render(new ControllerReference('main_controller', ['object' => $object], []), Request::create('/'))->getContent());
}
public function testRenderWithTrustedHeaderDisabled()
{
Request::setTrustedProxies([], 0);
$expectedSubRequest = Request::create('/');
$expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
$this->assertSame('foo', $strategy->render('/', Request::create('/'))->getContent());
Request::setTrustedProxies([], -1);
}
public function testRenderExceptionNoIgnoreErrors()
{
$this->expectException('RuntimeException');
$dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock();
$dispatcher->expects($this->never())->method('dispatch');
$strategy = new InlineFragmentRenderer($this->getKernel($this->throwException(new \RuntimeException('foo'))), $dispatcher);
$this->assertEquals('foo', $strategy->render('/', Request::create('/'))->getContent());
}
public function testRenderExceptionIgnoreErrors()
{
$exception = new \RuntimeException('foo');
$kernel = $this->getKernel($this->throwException($exception));
$request = Request::create('/');
$expectedEvent = new ExceptionEvent($kernel, $request, $kernel::SUB_REQUEST, $exception);
$dispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMock();
$dispatcher->expects($this->once())->method('dispatch')->with($expectedEvent, KernelEvents::EXCEPTION);
$strategy = new InlineFragmentRenderer($kernel, $dispatcher);
$this->assertEmpty($strategy->render('/', $request, ['ignore_errors' => true])->getContent());
}
public function testRenderExceptionIgnoreErrorsWithAlt()
{
$strategy = new InlineFragmentRenderer($this->getKernel($this->onConsecutiveCalls(
$this->throwException(new \RuntimeException('foo')),
$this->returnValue(new Response('bar'))
)));
$this->assertEquals('bar', $strategy->render('/', Request::create('/'), ['ignore_errors' => true, 'alt' => '/foo'])->getContent());
}
private function getKernel($returnValue)
{
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$kernel
->expects($this->any())
->method('handle')
->will($returnValue)
;
return $kernel;
}
public function testExceptionInSubRequestsDoesNotMangleOutputBuffers()
{
$controllerResolver = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Controller\\ControllerResolverInterface')->getMock();
$controllerResolver
->expects($this->once())
->method('getController')
->willReturn(function () {
ob_start();
echo 'bar';
throw new \RuntimeException();
})
;
$argumentResolver = $this->getMockBuilder('Symfony\\Component\\HttpKernel\\Controller\\ArgumentResolverInterface')->getMock();
$argumentResolver
->expects($this->once())
->method('getArguments')
->willReturn([])
;
$kernel = new HttpKernel(new EventDispatcher(), $controllerResolver, new RequestStack(), $argumentResolver);
$renderer = new InlineFragmentRenderer($kernel);
// simulate a main request with output buffering
ob_start();
echo 'Foo';
// simulate a sub-request with output buffering and an exception
$renderer->render('/', Request::create('/'), ['ignore_errors' => true]);
$this->assertEquals('Foo', ob_get_clean());
}
public function testLocaleAndFormatAreIsKeptInSubrequest()
{
$expectedSubRequest = Request::create('/');
$expectedSubRequest->attributes->set('_format', 'foo');
$expectedSubRequest->setLocale('fr');
if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
$expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
}
$expectedSubRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
$expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
$request = Request::create('/');
$request->attributes->set('_format', 'foo');
$request->setLocale('fr');
$strategy->render('/', $request);
}
public function testESIHeaderIsKeptInSubrequest()
{
$expectedSubRequest = Request::create('/');
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
if (Request::HEADER_X_FORWARDED_FOR & Request::getTrustedHeaderSet()) {
$expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
}
$expectedSubRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
$expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
$request = Request::create('/');
$request->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
$strategy->render('/', $request);
}
public function testESIHeaderIsKeptInSubrequestWithTrustedHeaderDisabled()
{
Request::setTrustedProxies([], Request::HEADER_FORWARDED);
$this->testESIHeaderIsKeptInSubrequest();
Request::setTrustedProxies([], -1);
}
public function testHeadersPossiblyResultingIn304AreNotAssignedToSubrequest()
{
$expectedSubRequest = Request::create('/');
$expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
$expectedSubRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
$request = Request::create('/', 'GET', [], [], [], ['HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*']);
$strategy->render('/', $request);
}
public function testFirstTrustedProxyIsSetAsRemote()
{
Request::setTrustedProxies(['1.1.1.1'], -1);
$expectedSubRequest = Request::create('/');
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
$expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');
$expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
$expectedSubRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
$request = Request::create('/');
$request->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
$strategy->render('/', $request);
Request::setTrustedProxies([], -1);
}
public function testIpAddressOfRangedTrustedProxyIsSetAsRemote()
{
$expectedSubRequest = Request::create('/');
$expectedSubRequest->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
$expectedSubRequest->server->set('REMOTE_ADDR', '127.0.0.1');
$expectedSubRequest->headers->set('x-forwarded-for', ['127.0.0.1']);
$expectedSubRequest->headers->set('forwarded', ['for="127.0.0.1";host="localhost";proto=http']);
$expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1');
$expectedSubRequest->server->set('HTTP_FORWARDED', 'for="127.0.0.1";host="localhost";proto=http');
Request::setTrustedProxies(['1.1.1.1/24'], -1);
$strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest));
$request = Request::create('/');
$request->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
$strategy->render('/', $request);
Request::setTrustedProxies([], -1);
}
/**
* Creates a Kernel expecting a request equals to $request
* Allows delta in comparison in case REQUEST_TIME changed by 1 second.
*/
private function getKernelExpectingRequest(Request $request, $strict = false)
{
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$kernel
->expects($this->once())
->method('handle')
->with($this->equalTo($request, 1))
->willReturn(new Response('foo'));
return $kernel;
}
}
class Bar
{
public $bar = 'bar';
public function getBar()
{
return $this->bar;
}
}

View File

@@ -0,0 +1,94 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fragment;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
class RoutableFragmentRendererTest extends TestCase
{
/**
* @dataProvider getGenerateFragmentUriData
*/
public function testGenerateFragmentUri($uri, $controller)
{
$this->assertEquals($uri, $this->callGenerateFragmentUriMethod($controller, Request::create('/')));
}
/**
* @dataProvider getGenerateFragmentUriData
*/
public function testGenerateAbsoluteFragmentUri($uri, $controller)
{
$this->assertEquals('http://localhost'.$uri, $this->callGenerateFragmentUriMethod($controller, Request::create('/'), true));
}
public function getGenerateFragmentUriData()
{
return [
['/_fragment?_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', [], [])],
['/_fragment?_path=_format%3Dxml%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', ['_format' => 'xml'], [])],
['/_fragment?_path=foo%3Dfoo%26_format%3Djson%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', ['foo' => 'foo', '_format' => 'json'], [])],
['/_fragment?bar=bar&_path=foo%3Dfoo%26_format%3Dhtml%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', ['foo' => 'foo'], ['bar' => 'bar'])],
['/_fragment?foo=foo&_path=_format%3Dhtml%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', [], ['foo' => 'foo'])],
['/_fragment?_path=foo%255B0%255D%3Dfoo%26foo%255B1%255D%3Dbar%26_format%3Dhtml%26_locale%3Den%26_controller%3Dcontroller', new ControllerReference('controller', ['foo' => ['foo', 'bar']], [])],
];
}
public function testGenerateFragmentUriWithARequest()
{
$request = Request::create('/');
$request->attributes->set('_format', 'json');
$request->setLocale('fr');
$controller = new ControllerReference('controller', [], []);
$this->assertEquals('/_fragment?_path=_format%3Djson%26_locale%3Dfr%26_controller%3Dcontroller', $this->callGenerateFragmentUriMethod($controller, $request));
}
/**
* @dataProvider getGenerateFragmentUriDataWithNonScalar
*/
public function testGenerateFragmentUriWithNonScalar($controller)
{
$this->expectException('LogicException');
$this->callGenerateFragmentUriMethod($controller, Request::create('/'));
}
public function getGenerateFragmentUriDataWithNonScalar()
{
return [
[new ControllerReference('controller', ['foo' => new Foo(), 'bar' => 'bar'], [])],
[new ControllerReference('controller', ['foo' => ['foo' => 'foo'], 'bar' => ['bar' => new Foo()]], [])],
];
}
private function callGenerateFragmentUriMethod(ControllerReference $reference, Request $request, $absolute = false)
{
$renderer = $this->getMockForAbstractClass('Symfony\Component\HttpKernel\Fragment\RoutableFragmentRenderer');
$r = new \ReflectionObject($renderer);
$m = $r->getMethod('generateFragmentUri');
$m->setAccessible(true);
return $m->invoke($renderer, $reference, $request, $absolute);
}
}
class Foo
{
public $foo;
public function getFoo()
{
return $this->foo;
}
}

View File

@@ -0,0 +1,93 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\Fragment;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ControllerReference;
use Symfony\Component\HttpKernel\Fragment\SsiFragmentRenderer;
use Symfony\Component\HttpKernel\HttpCache\Ssi;
use Symfony\Component\HttpKernel\UriSigner;
class SsiFragmentRendererTest extends TestCase
{
public function testRenderFallbackToInlineStrategyIfSsiNotSupported()
{
$strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy(true));
$strategy->render('/', Request::create('/'));
}
public function testRender()
{
$strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy());
$request = Request::create('/');
$request->setLocale('fr');
$request->headers->set('Surrogate-Capability', 'SSI/1.0');
$this->assertEquals('<!--#include virtual="/" -->', $strategy->render('/', $request)->getContent());
$this->assertEquals('<!--#include virtual="/" -->', $strategy->render('/', $request, ['comment' => 'This is a comment'])->getContent(), 'Strategy options should not impact the ssi include tag');
}
public function testRenderControllerReference()
{
$signer = new UriSigner('foo');
$strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy(), $signer);
$request = Request::create('/');
$request->setLocale('fr');
$request->headers->set('Surrogate-Capability', 'SSI/1.0');
$reference = new ControllerReference('main_controller', [], []);
$altReference = new ControllerReference('alt_controller', [], []);
$this->assertEquals(
'<!--#include virtual="/_fragment?_hash=Jz1P8NErmhKTeI6onI1EdAXTB85359MY3RIk5mSJ60w%3D&_path=_format%3Dhtml%26_locale%3Dfr%26_controller%3Dmain_controller" -->',
$strategy->render($reference, $request, ['alt' => $altReference])->getContent()
);
}
public function testRenderControllerReferenceWithoutSignerThrowsException()
{
$this->expectException('LogicException');
$strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy());
$request = Request::create('/');
$request->setLocale('fr');
$request->headers->set('Surrogate-Capability', 'SSI/1.0');
$strategy->render(new ControllerReference('main_controller'), $request);
}
public function testRenderAltControllerReferenceWithoutSignerThrowsException()
{
$this->expectException('LogicException');
$strategy = new SsiFragmentRenderer(new Ssi(), $this->getInlineStrategy());
$request = Request::create('/');
$request->setLocale('fr');
$request->headers->set('Surrogate-Capability', 'SSI/1.0');
$strategy->render('/', $request, ['alt' => new ControllerReference('alt_controller')]);
}
private function getInlineStrategy($called = false)
{
$inline = $this->getMockBuilder('Symfony\Component\HttpKernel\Fragment\InlineFragmentRenderer')->disableOriginalConstructor()->getMock();
if ($called) {
$inline->expects($this->once())->method('render');
}
return $inline;
}
}

View File

@@ -0,0 +1,244 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\HttpCache;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpCache\Esi;
class EsiTest extends TestCase
{
public function testHasSurrogateEsiCapability()
{
$esi = new Esi();
$request = Request::create('/');
$request->headers->set('Surrogate-Capability', 'abc="ESI/1.0"');
$this->assertTrue($esi->hasSurrogateCapability($request));
$request = Request::create('/');
$request->headers->set('Surrogate-Capability', 'foobar');
$this->assertFalse($esi->hasSurrogateCapability($request));
$request = Request::create('/');
$this->assertFalse($esi->hasSurrogateCapability($request));
}
public function testAddSurrogateEsiCapability()
{
$esi = new Esi();
$request = Request::create('/');
$esi->addSurrogateCapability($request);
$this->assertEquals('symfony="ESI/1.0"', $request->headers->get('Surrogate-Capability'));
$esi->addSurrogateCapability($request);
$this->assertEquals('symfony="ESI/1.0", symfony="ESI/1.0"', $request->headers->get('Surrogate-Capability'));
}
public function testAddSurrogateControl()
{
$esi = new Esi();
$response = new Response('foo <esi:include src="" />');
$esi->addSurrogateControl($response);
$this->assertEquals('content="ESI/1.0"', $response->headers->get('Surrogate-Control'));
$response = new Response('foo');
$esi->addSurrogateControl($response);
$this->assertEquals('', $response->headers->get('Surrogate-Control'));
}
public function testNeedsEsiParsing()
{
$esi = new Esi();
$response = new Response();
$response->headers->set('Surrogate-Control', 'content="ESI/1.0"');
$this->assertTrue($esi->needsParsing($response));
$response = new Response();
$this->assertFalse($esi->needsParsing($response));
}
public function testRenderIncludeTag()
{
$esi = new Esi();
$this->assertEquals('<esi:include src="/" onerror="continue" alt="/alt" />', $esi->renderIncludeTag('/', '/alt', true));
$this->assertEquals('<esi:include src="/" alt="/alt" />', $esi->renderIncludeTag('/', '/alt', false));
$this->assertEquals('<esi:include src="/" onerror="continue" />', $esi->renderIncludeTag('/'));
$this->assertEquals('<esi:comment text="some comment" />'."\n".'<esi:include src="/" onerror="continue" alt="/alt" />', $esi->renderIncludeTag('/', '/alt', true, 'some comment'));
}
public function testProcessDoesNothingIfContentTypeIsNotHtml()
{
$esi = new Esi();
$request = Request::create('/');
$response = new Response();
$response->headers->set('Content-Type', 'text/plain');
$this->assertSame($response, $esi->process($request, $response));
$this->assertFalse($response->headers->has('x-body-eval'));
}
public function testMultilineEsiRemoveTagsAreRemoved()
{
$esi = new Esi();
$request = Request::create('/');
$response = new Response('<esi:remove> <a href="http://www.example.com">www.example.com</a> </esi:remove> Keep this'."<esi:remove>\n <a>www.example.com</a> </esi:remove> And this");
$this->assertSame($response, $esi->process($request, $response));
$this->assertEquals(' Keep this And this', $response->getContent());
}
public function testCommentTagsAreRemoved()
{
$esi = new Esi();
$request = Request::create('/');
$response = new Response('<esi:comment text="some comment &gt;" /> Keep this');
$this->assertSame($response, $esi->process($request, $response));
$this->assertEquals(' Keep this', $response->getContent());
}
public function testProcess()
{
$esi = new Esi();
$request = Request::create('/');
$response = new Response('foo <esi:comment text="some comment" /><esi:include src="..." alt="alt" onerror="continue" />');
$this->assertSame($response, $esi->process($request, $response));
$this->assertEquals('foo <?php echo $this->surrogate->handle($this, \'...\', \'alt\', true) ?>'."\n", $response->getContent());
$this->assertEquals('ESI', $response->headers->get('x-body-eval'));
$response = new Response('foo <esi:comment text="some comment" /><esi:include src="foo\'" alt="bar\'" onerror="continue" />');
$this->assertSame($response, $esi->process($request, $response));
$this->assertEquals('foo <?php echo $this->surrogate->handle($this, \'foo\\\'\', \'bar\\\'\', true) ?>'."\n", $response->getContent());
$response = new Response('foo <esi:include src="..." />');
$this->assertSame($response, $esi->process($request, $response));
$this->assertEquals('foo <?php echo $this->surrogate->handle($this, \'...\', \'\', false) ?>'."\n", $response->getContent());
$response = new Response('foo <esi:include src="..."></esi:include>');
$this->assertSame($response, $esi->process($request, $response));
$this->assertEquals('foo <?php echo $this->surrogate->handle($this, \'...\', \'\', false) ?>'."\n", $response->getContent());
}
public function testProcessEscapesPhpTags()
{
$esi = new Esi();
$request = Request::create('/');
$response = new Response('<?php <? <% <script language=php>');
$this->assertSame($response, $esi->process($request, $response));
$this->assertEquals('<?php echo "<?"; ?>php <?php echo "<?"; ?> <?php echo "<%"; ?> <?php echo "<s"; ?>cript language=php>', $response->getContent());
}
public function testProcessWhenNoSrcInAnEsi()
{
$this->expectException('RuntimeException');
$esi = new Esi();
$request = Request::create('/');
$response = new Response('foo <esi:include />');
$this->assertSame($response, $esi->process($request, $response));
}
public function testProcessRemoveSurrogateControlHeader()
{
$esi = new Esi();
$request = Request::create('/');
$response = new Response('foo <esi:include src="..." />');
$response->headers->set('Surrogate-Control', 'content="ESI/1.0"');
$this->assertSame($response, $esi->process($request, $response));
$this->assertEquals('ESI', $response->headers->get('x-body-eval'));
$response->headers->set('Surrogate-Control', 'no-store, content="ESI/1.0"');
$this->assertSame($response, $esi->process($request, $response));
$this->assertEquals('ESI', $response->headers->get('x-body-eval'));
$this->assertEquals('no-store', $response->headers->get('surrogate-control'));
$response->headers->set('Surrogate-Control', 'content="ESI/1.0", no-store');
$this->assertSame($response, $esi->process($request, $response));
$this->assertEquals('ESI', $response->headers->get('x-body-eval'));
$this->assertEquals('no-store', $response->headers->get('surrogate-control'));
}
public function testHandle()
{
$esi = new Esi();
$cache = $this->getCache(Request::create('/'), new Response('foo'));
$this->assertEquals('foo', $esi->handle($cache, '/', '/alt', true));
}
public function testHandleWhenResponseIsNot200()
{
$this->expectException('RuntimeException');
$esi = new Esi();
$response = new Response('foo');
$response->setStatusCode(404);
$cache = $this->getCache(Request::create('/'), $response);
$esi->handle($cache, '/', '/alt', false);
}
public function testHandleWhenResponseIsNot200AndErrorsAreIgnored()
{
$esi = new Esi();
$response = new Response('foo');
$response->setStatusCode(404);
$cache = $this->getCache(Request::create('/'), $response);
$this->assertEquals('', $esi->handle($cache, '/', '/alt', true));
}
public function testHandleWhenResponseIsNot200AndAltIsPresent()
{
$esi = new Esi();
$response1 = new Response('foo');
$response1->setStatusCode(404);
$response2 = new Response('bar');
$cache = $this->getCache(Request::create('/'), [$response1, $response2]);
$this->assertEquals('bar', $esi->handle($cache, '/', '/alt', false));
}
protected function getCache($request, $response)
{
$cache = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpCache\HttpCache')->setMethods(['getRequest', 'handle'])->disableOriginalConstructor()->getMock();
$cache->expects($this->any())
->method('getRequest')
->willReturn($request)
;
if (\is_array($response)) {
$cache->expects($this->any())
->method('handle')
->will($this->onConsecutiveCalls(...$response))
;
} else {
$cache->expects($this->any())
->method('handle')
->willReturn($response)
;
}
return $cache;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,187 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\HttpCache;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\HttpCache\Esi;
use Symfony\Component\HttpKernel\HttpCache\HttpCache;
use Symfony\Component\HttpKernel\HttpCache\Store;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class HttpCacheTestCase extends TestCase
{
protected $kernel;
protected $cache;
protected $caches;
protected $cacheConfig;
protected $request;
protected $response;
protected $responses;
protected $catch;
protected $esi;
/**
* @var Store
*/
protected $store;
protected function setUp(): void
{
$this->kernel = null;
$this->cache = null;
$this->esi = null;
$this->caches = [];
$this->cacheConfig = [];
$this->request = null;
$this->response = null;
$this->responses = [];
$this->catch = false;
$this->clearDirectory(sys_get_temp_dir().'/http_cache');
}
protected function tearDown(): void
{
if ($this->cache) {
$this->cache->getStore()->cleanup();
}
$this->kernel = null;
$this->cache = null;
$this->caches = null;
$this->request = null;
$this->response = null;
$this->responses = null;
$this->cacheConfig = null;
$this->catch = null;
$this->esi = null;
$this->clearDirectory(sys_get_temp_dir().'/http_cache');
}
public function assertHttpKernelIsCalled()
{
$this->assertTrue($this->kernel->hasBeenCalled());
}
public function assertHttpKernelIsNotCalled()
{
$this->assertFalse($this->kernel->hasBeenCalled());
}
public function assertResponseOk()
{
$this->assertEquals(200, $this->response->getStatusCode());
}
public function assertTraceContains($trace)
{
$traces = $this->cache->getTraces();
$traces = current($traces);
$this->assertRegExp('/'.$trace.'/', implode(', ', $traces));
}
public function assertTraceNotContains($trace)
{
$traces = $this->cache->getTraces();
$traces = current($traces);
$this->assertNotRegExp('/'.$trace.'/', implode(', ', $traces));
}
public function assertExceptionsAreCaught()
{
$this->assertTrue($this->kernel->isCatchingExceptions());
}
public function assertExceptionsAreNotCaught()
{
$this->assertFalse($this->kernel->isCatchingExceptions());
}
public function request($method, $uri = '/', $server = [], $cookies = [], $esi = false, $headers = [])
{
if (null === $this->kernel) {
throw new \LogicException('You must call setNextResponse() before calling request().');
}
$this->kernel->reset();
$this->store = new Store(sys_get_temp_dir().'/http_cache');
if (!isset($this->cacheConfig['debug'])) {
$this->cacheConfig['debug'] = true;
}
$this->esi = $esi ? new Esi() : null;
$this->cache = new HttpCache($this->kernel, $this->store, $this->esi, $this->cacheConfig);
$this->request = Request::create($uri, $method, [], $cookies, [], $server);
$this->request->headers->add($headers);
$this->response = $this->cache->handle($this->request, HttpKernelInterface::MASTER_REQUEST, $this->catch);
$this->responses[] = $this->response;
}
public function getMetaStorageValues()
{
$values = [];
foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(sys_get_temp_dir().'/http_cache/md', \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::LEAVES_ONLY) as $file) {
$values[] = file_get_contents($file);
}
return $values;
}
// A basic response with 200 status code and a tiny body.
public function setNextResponse($statusCode = 200, array $headers = [], $body = 'Hello World', \Closure $customizer = null)
{
$this->kernel = new TestHttpKernel($body, $statusCode, $headers, $customizer);
}
public function setNextResponses($responses)
{
$this->kernel = new TestMultipleHttpKernel($responses);
}
public function catchExceptions($catch = true)
{
$this->catch = $catch;
}
public static function clearDirectory($directory)
{
if (!is_dir($directory)) {
return;
}
$fp = opendir($directory);
while (false !== $file = readdir($fp)) {
if (!\in_array($file, ['.', '..'])) {
if (is_link($directory.'/'.$file)) {
unlink($directory.'/'.$file);
} elseif (is_dir($directory.'/'.$file)) {
self::clearDirectory($directory.'/'.$file);
rmdir($directory.'/'.$file);
} else {
unlink($directory.'/'.$file);
}
}
}
closedir($fp);
}
}

View File

@@ -0,0 +1,469 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This code is partially based on the Rack-Cache library by Ryan Tomayko,
* which is released under the MIT license.
* (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801)
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\HttpKernel\Tests\HttpCache;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpCache\ResponseCacheStrategy;
class ResponseCacheStrategyTest extends TestCase
{
public function testMinimumSharedMaxAgeWins()
{
$cacheStrategy = new ResponseCacheStrategy();
$response1 = new Response();
$response1->setSharedMaxAge(60);
$cacheStrategy->add($response1);
$response2 = new Response();
$response2->setSharedMaxAge(3600);
$cacheStrategy->add($response2);
$response = new Response();
$response->setSharedMaxAge(86400);
$cacheStrategy->update($response);
$this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage'));
}
public function testSharedMaxAgeNotSetIfNotSetInAnyEmbeddedRequest()
{
$cacheStrategy = new ResponseCacheStrategy();
$response1 = new Response();
$response1->setSharedMaxAge(60);
$cacheStrategy->add($response1);
$response2 = new Response();
$cacheStrategy->add($response2);
$response = new Response();
$response->setSharedMaxAge(86400);
$cacheStrategy->update($response);
$this->assertFalse($response->headers->hasCacheControlDirective('s-maxage'));
}
public function testSharedMaxAgeNotSetIfNotSetInMasterRequest()
{
$cacheStrategy = new ResponseCacheStrategy();
$response1 = new Response();
$response1->setSharedMaxAge(60);
$cacheStrategy->add($response1);
$response2 = new Response();
$response2->setSharedMaxAge(3600);
$cacheStrategy->add($response2);
$response = new Response();
$cacheStrategy->update($response);
$this->assertFalse($response->headers->hasCacheControlDirective('s-maxage'));
}
public function testMasterResponseNotCacheableWhenEmbeddedResponseRequiresValidation()
{
$cacheStrategy = new ResponseCacheStrategy();
$embeddedResponse = new Response();
$embeddedResponse->setLastModified(new \DateTime());
$cacheStrategy->add($embeddedResponse);
$masterResponse = new Response();
$masterResponse->setSharedMaxAge(3600);
$cacheStrategy->update($masterResponse);
$this->assertTrue($masterResponse->headers->hasCacheControlDirective('no-cache'));
$this->assertTrue($masterResponse->headers->hasCacheControlDirective('must-revalidate'));
$this->assertFalse($masterResponse->isFresh());
}
public function testValidationOnMasterResponseIsNotPossibleWhenItContainsEmbeddedResponses()
{
$cacheStrategy = new ResponseCacheStrategy();
// This master response uses the "validation" model
$masterResponse = new Response();
$masterResponse->setLastModified(new \DateTime());
$masterResponse->setEtag('foo');
// Embedded response uses "expiry" model
$embeddedResponse = new Response();
$masterResponse->setSharedMaxAge(3600);
$cacheStrategy->add($embeddedResponse);
$cacheStrategy->update($masterResponse);
$this->assertFalse($masterResponse->isValidateable());
$this->assertFalse($masterResponse->headers->has('Last-Modified'));
$this->assertFalse($masterResponse->headers->has('ETag'));
$this->assertTrue($masterResponse->headers->hasCacheControlDirective('no-cache'));
$this->assertTrue($masterResponse->headers->hasCacheControlDirective('must-revalidate'));
}
public function testMasterResponseWithValidationIsUnchangedWhenThereIsNoEmbeddedResponse()
{
$cacheStrategy = new ResponseCacheStrategy();
$masterResponse = new Response();
$masterResponse->setLastModified(new \DateTime());
$cacheStrategy->update($masterResponse);
$this->assertTrue($masterResponse->isValidateable());
}
public function testMasterResponseWithExpirationIsUnchangedWhenThereIsNoEmbeddedResponse()
{
$cacheStrategy = new ResponseCacheStrategy();
$masterResponse = new Response();
$masterResponse->setSharedMaxAge(3600);
$cacheStrategy->update($masterResponse);
$this->assertTrue($masterResponse->isFresh());
}
public function testMasterResponseIsNotCacheableWhenEmbeddedResponseIsNotCacheable()
{
$cacheStrategy = new ResponseCacheStrategy();
$masterResponse = new Response();
$masterResponse->setSharedMaxAge(3600); // Public, cacheable
/* This response has no validation or expiration information.
That makes it uncacheable, it is always stale.
(It does *not* make this private, though.) */
$embeddedResponse = new Response();
$this->assertFalse($embeddedResponse->isFresh()); // not fresh, as no lifetime is provided
$cacheStrategy->add($embeddedResponse);
$cacheStrategy->update($masterResponse);
$this->assertTrue($masterResponse->headers->hasCacheControlDirective('no-cache'));
$this->assertTrue($masterResponse->headers->hasCacheControlDirective('must-revalidate'));
$this->assertFalse($masterResponse->isFresh());
}
public function testEmbeddingPrivateResponseMakesMainResponsePrivate()
{
$cacheStrategy = new ResponseCacheStrategy();
$masterResponse = new Response();
$masterResponse->setSharedMaxAge(3600); // public, cacheable
// The embedded response might for example contain per-user data that remains valid for 60 seconds
$embeddedResponse = new Response();
$embeddedResponse->setPrivate();
$embeddedResponse->setMaxAge(60); // this would implicitly set "private" as well, but let's be explicit
$cacheStrategy->add($embeddedResponse);
$cacheStrategy->update($masterResponse);
$this->assertTrue($masterResponse->headers->hasCacheControlDirective('private'));
$this->assertFalse($masterResponse->headers->hasCacheControlDirective('public'));
}
public function testEmbeddingPublicResponseDoesNotMakeMainResponsePublic()
{
$cacheStrategy = new ResponseCacheStrategy();
$masterResponse = new Response();
$masterResponse->setPrivate(); // this is the default, but let's be explicit
$masterResponse->setMaxAge(100);
$embeddedResponse = new Response();
$embeddedResponse->setPublic();
$embeddedResponse->setSharedMaxAge(100);
$cacheStrategy->add($embeddedResponse);
$cacheStrategy->update($masterResponse);
$this->assertTrue($masterResponse->headers->hasCacheControlDirective('private'));
$this->assertFalse($masterResponse->headers->hasCacheControlDirective('public'));
}
public function testResponseIsExiprableWhenEmbeddedResponseCombinesExpiryAndValidation()
{
/* When "expiration wins over validation" (https://symfony.com/doc/current/http_cache/validation.html)
* and both the main and embedded response provide s-maxage, then the more restricting value of both
* should be fine, regardless of whether the embedded response can be validated later on or must be
* completely regenerated.
*/
$cacheStrategy = new ResponseCacheStrategy();
$masterResponse = new Response();
$masterResponse->setSharedMaxAge(3600);
$embeddedResponse = new Response();
$embeddedResponse->setSharedMaxAge(60);
$embeddedResponse->setEtag('foo');
$cacheStrategy->add($embeddedResponse);
$cacheStrategy->update($masterResponse);
$this->assertSame('60', $masterResponse->headers->getCacheControlDirective('s-maxage'));
}
public function testResponseIsExpirableButNotValidateableWhenMasterResponseCombinesExpirationAndValidation()
{
$cacheStrategy = new ResponseCacheStrategy();
$masterResponse = new Response();
$masterResponse->setSharedMaxAge(3600);
$masterResponse->setEtag('foo');
$masterResponse->setLastModified(new \DateTime());
$embeddedResponse = new Response();
$embeddedResponse->setSharedMaxAge(60);
$cacheStrategy->add($embeddedResponse);
$cacheStrategy->update($masterResponse);
$this->assertSame('60', $masterResponse->headers->getCacheControlDirective('s-maxage'));
$this->assertFalse($masterResponse->isValidateable());
}
/**
* @dataProvider cacheControlMergingProvider
*/
public function testCacheControlMerging(array $expects, array $master, array $surrogates)
{
$cacheStrategy = new ResponseCacheStrategy();
$buildResponse = function ($config) {
$response = new Response();
foreach ($config as $key => $value) {
switch ($key) {
case 'age':
$response->headers->set('Age', $value);
break;
case 'expires':
$expires = clone $response->getDate();
$expires->modify('+'.$value.' seconds');
$response->setExpires($expires);
break;
case 'max-age':
$response->setMaxAge($value);
break;
case 's-maxage':
$response->setSharedMaxAge($value);
break;
case 'private':
$response->setPrivate();
break;
case 'public':
$response->setPublic();
break;
default:
$response->headers->addCacheControlDirective($key, $value);
}
}
return $response;
};
foreach ($surrogates as $config) {
$cacheStrategy->add($buildResponse($config));
}
$response = $buildResponse($master);
$cacheStrategy->update($response);
foreach ($expects as $key => $value) {
if ('expires' === $key) {
$this->assertSame($value, $response->getExpires()->format('U') - $response->getDate()->format('U'));
} elseif ('age' === $key) {
$this->assertSame($value, $response->getAge());
} elseif (true === $value) {
$this->assertTrue($response->headers->hasCacheControlDirective($key), sprintf('Cache-Control header must have "%s" flag', $key));
} elseif (false === $value) {
$this->assertFalse(
$response->headers->hasCacheControlDirective($key),
sprintf('Cache-Control header must NOT have "%s" flag', $key)
);
} else {
$this->assertSame($value, $response->headers->getCacheControlDirective($key), sprintf('Cache-Control flag "%s" should be "%s"', $key, $value));
}
}
}
public function cacheControlMergingProvider()
{
yield 'result is public if all responses are public' => [
['private' => false, 'public' => true],
['public' => true],
[
['public' => true],
],
];
yield 'result is private by default' => [
['private' => true, 'public' => false],
['public' => true],
[
[],
],
];
yield 'combines public and private responses' => [
['must-revalidate' => false, 'private' => true, 'public' => false],
['public' => true],
[
['private' => true],
],
];
yield 'inherits no-cache from surrogates' => [
['no-cache' => true, 'public' => false],
['public' => true],
[
['no-cache' => true],
],
];
yield 'inherits no-store from surrogate' => [
['no-store' => true, 'public' => false],
['public' => true],
[
['no-store' => true],
],
];
yield 'resolve to lowest possible max-age' => [
['public' => false, 'private' => true, 's-maxage' => false, 'max-age' => '60'],
['public' => true, 'max-age' => 3600],
[
['private' => true, 'max-age' => 60],
],
];
yield 'resolves multiple max-age' => [
['public' => false, 'private' => true, 's-maxage' => false, 'max-age' => '60'],
['private' => true, 'max-age' => 100],
[
['private' => true, 'max-age' => 3600],
['public' => true, 'max-age' => 60, 's-maxage' => 60],
['private' => true, 'max-age' => 60],
],
];
yield 'merge max-age and s-maxage' => [
['public' => true, 's-maxage' => '60', 'max-age' => null],
['public' => true, 's-maxage' => 3600],
[
['public' => true, 'max-age' => 60],
],
];
yield 'result is private when combining private responses' => [
['no-cache' => false, 'must-revalidate' => false, 'private' => true],
['s-maxage' => 60, 'private' => true],
[
['s-maxage' => 60, 'private' => true],
],
];
yield 'result can have s-maxage and max-age' => [
['public' => true, 'private' => false, 's-maxage' => '60', 'max-age' => '30'],
['s-maxage' => 100, 'max-age' => 2000],
[
['s-maxage' => 1000, 'max-age' => 30],
['s-maxage' => 500, 'max-age' => 500],
['s-maxage' => 60, 'max-age' => 1000],
],
];
yield 'does not set headers without value' => [
['max-age' => null, 's-maxage' => null, 'public' => null],
['private' => true],
[
['private' => true],
],
];
yield 'max-age 0 is sent to the client' => [
['private' => true, 'max-age' => '0'],
['max-age' => 0, 'private' => true],
[
['max-age' => 60, 'private' => true],
],
];
yield 'max-age is relative to age' => [
['max-age' => '240', 'age' => 60],
['max-age' => 180],
[
['max-age' => 600, 'age' => 60],
],
];
yield 'retains lowest age of all responses' => [
['max-age' => '160', 'age' => 60],
['max-age' => 600, 'age' => 60],
[
['max-age' => 120, 'age' => 20],
],
];
yield 'max-age can be less than age, essentially expiring the response' => [
['age' => 120, 'max-age' => '90'],
['max-age' => 90, 'age' => 120],
[
['max-age' => 120, 'age' => 60],
],
];
yield 'max-age is 0 regardless of age' => [
['max-age' => '0'],
['max-age' => 60],
[
['max-age' => 0, 'age' => 60],
],
];
yield 'max-age is not negative' => [
['max-age' => '0'],
['max-age' => 0],
[
['max-age' => 0, 'age' => 60],
],
];
yield 'calculates lowest Expires header' => [
['expires' => 60],
['expires' => 60],
[
['expires' => 120],
],
];
yield 'calculates Expires header relative to age' => [
['expires' => 210, 'age' => 120],
['expires' => 90],
[
['expires' => 600, 'age' => '120'],
],
];
}
}

Some files were not shown because too many files have changed in this diff Show More