Update to Drupal 8.0.0 beta 14. For more information, see https://drupal.org/node/2544542

This commit is contained in:
Pantheon Automation 2015-08-27 12:03:05 -07:00 committed by Greg Anderson
parent 3b2511d96d
commit 81ccda77eb
2155 changed files with 54307 additions and 46870 deletions

View file

@ -0,0 +1,241 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Component\InspectorTest.
*/
namespace Drupal\Tests\Component\Assertion;
use PHPUnit_Framework_TestCase;
use Drupal\Component\Assertion\Inspector;
/**
* @coversDefaultClass \Drupal\Component\Assertion\Inspector
* @group Inspector
*/
class InspectorTest extends PHPUnit_Framework_TestCase {
/**
* Tests asserting argument is an array or traversable object.
*
* @covers ::assertTraversable
*/
public function testAssertTraversable() {
$this->assertTrue(Inspector::assertTraversable([]));
$this->assertTrue(Inspector::assertTraversable(new \ArrayObject()));
$this->assertFalse(Inspector::assertTraversable(new \stdClass()));
$this->assertFalse(Inspector::assertTraversable('foo'));
}
/**
* Tests asserting all members are strings.
*
* @covers ::assertAllStrings
*/
public function testAssertAllStrings() {
$this->assertTrue(Inspector::assertAllStrings([]));
$this->assertTrue(Inspector::assertAllStrings(['foo', 'bar']));
$this->assertFalse(Inspector::assertAllStrings('foo'));
$this->assertFalse(Inspector::assertAllStrings(['foo', new StringObject()]));
}
/**
* Tests asserting all members are strings or objects with __toString().
*
* @covers ::assertAllStringable
*/
public function testAssertAllStringable() {
$this->assertTrue(Inspector::assertAllStringable([]));
$this->assertTrue(Inspector::assertAllStringable(['foo', 'bar']));
$this->assertFalse(Inspector::assertAllStringable('foo'));
$this->assertTrue(Inspector::assertAllStringable(['foo', new StringObject()]));
}
/**
* Tests asserting all members are arrays.
*
* @covers ::assertAllArrays
*/
public function testAssertAllArrays() {
$this->assertTrue(Inspector::assertAllArrays([]));
$this->assertTrue(Inspector::assertAllArrays([[], []]));
$this->assertFalse(Inspector::assertAllArrays([[], 'foo']));
}
/**
* Tests asserting array is 0-indexed - the strict definition of array.
*
* @covers ::assertStrictArray
*/
public function testAssertStrictArray() {
$this->assertTrue(Inspector::assertStrictArray([]));
$this->assertTrue(Inspector::assertStrictArray(['bar', 'foo']));
$this->assertFalse(Inspector::assertStrictArray(['foo' => 'bar', 'bar' => 'foo']));
}
/**
* Tests asserting all members are strict arrays.
*
* @covers ::assertAllStrictArrays
*/
public function testAssertAllStrictArrays() {
$this->assertTrue(Inspector::assertAllStrictArrays([]));
$this->assertTrue(Inspector::assertAllStrictArrays([[], []]));
$this->assertFalse(Inspector::assertAllStrictArrays([['foo' => 'bar', 'bar' => 'foo']]));
}
/**
* Tests asserting all members have specified keys.
*
* @covers ::assertAllHaveKey
*/
public function testAssertAllHaveKey() {
$this->assertTrue(Inspector::assertAllHaveKey([]));
$this->assertTrue(Inspector::assertAllHaveKey([['foo' => 'bar', 'bar' => 'foo']]));
$this->assertTrue(Inspector::assertAllHaveKey([['foo' => 'bar', 'bar' => 'foo']], 'foo'));
$this->assertTrue(Inspector::assertAllHaveKey([['foo' => 'bar', 'bar' => 'foo']], 'bar', 'foo'));
$this->assertFalse(Inspector::assertAllHaveKey([['foo' => 'bar', 'bar' => 'foo']], 'bar', 'foo', 'moo'));
}
/**
* Tests asserting all members are integers.
*
* @covers ::assertAllIntegers
*/
public function testAssertAllIntegers() {
$this->assertTrue(Inspector::assertAllIntegers([]));
$this->assertTrue(Inspector::assertAllIntegers([1, 2, 3]));
$this->assertFalse(Inspector::assertAllIntegers([1, 2, 3.14]));
$this->assertFalse(Inspector::assertAllIntegers([1, '2', 3]));
}
/**
* Tests asserting all members are floating point variables.
*
* @covers ::assertAllFloat
*/
public function testAssertAllFloat() {
$this->assertTrue(Inspector::assertAllFloat([]));
$this->assertTrue(Inspector::assertAllFloat([1.0, 2.1, 3.14]));
$this->assertFalse(Inspector::assertAllFloat([1, 2.1, 3.14]));
$this->assertFalse(Inspector::assertAllFloat([1.0, '2', 3]));
$this->assertFalse(Inspector::assertAllFloat(['Titanic']));
}
/**
* Tests asserting all members are callable.
*
* @covers ::assertAllCallable
*/
public function testAllCallable() {
$this->assertTrue(Inspector::assertAllCallable([
'strchr',
[$this, 'callMe'],
[__CLASS__, 'callMeStatic'],
function() {
return TRUE;
}
]));
$this->assertFalse(Inspector::assertAllCallable([
'strchr',
[$this, 'callMe'],
[__CLASS__, 'callMeStatic'],
function() {
return TRUE;
},
"I'm not callable"
]));
}
/**
* Tests asserting all members are !empty().
*
* @covers ::assertAllNotEmpty
*/
public function testAllNotEmpty() {
$this->assertTrue(Inspector::assertAllNotEmpty([1, 'two']));
$this->assertFalse(Inspector::assertAllNotEmpty(['']));
}
/**
* Tests asserting all arguments are numbers or strings castable to numbers.
*
* @covers ::assertAllNumeric
*/
public function testAssertAllNumeric() {
$this->assertTrue(Inspector::assertAllNumeric([1, '2', 3.14]));
$this->assertFalse(Inspector::assertAllNumeric([1, 'two', 3.14]));
}
/**
* Tests asserting strstr() or stristr() match.
*
* @covers ::assertAllMatch
*/
public function testAssertAllMatch() {
$this->assertTrue(Inspector::assertAllMatch('f', ['fee', 'fi', 'fo']));
$this->assertTrue(Inspector::assertAllMatch('F', ['fee', 'fi', 'fo']));
$this->assertTrue(Inspector::assertAllMatch('f', ['fee', 'fi', 'fo'], TRUE));
$this->assertFalse(Inspector::assertAllMatch('F', ['fee', 'fi', 'fo'], TRUE));
$this->assertFalse(Inspector::assertAllMatch('e', ['fee', 'fi', 'fo']));
$this->assertFalse(Inspector::assertAllMatch('1', [12]));
}
/**
* Tests asserting regular expression match.
*
* @covers ::assertAllRegularExpressionMatch
*/
public function testAssertAllRegularExpressionMatch() {
$this->assertTrue(Inspector::assertAllRegularExpressionMatch('/f/i', ['fee', 'fi', 'fo']));
$this->assertTrue(Inspector::assertAllRegularExpressionMatch('/F/i', ['fee', 'fi', 'fo']));
$this->assertTrue(Inspector::assertAllRegularExpressionMatch('/f/', ['fee', 'fi', 'fo']));
$this->assertFalse(Inspector::assertAllRegularExpressionMatch('/F/', ['fee', 'fi', 'fo']));
$this->assertFalse(Inspector::assertAllRegularExpressionMatch('/e/', ['fee', 'fi', 'fo']));
$this->assertFalse(Inspector::assertAllRegularExpressionMatch('/1/', [12]));
}
/**
* Tests asserting all members are objects.
*
* @covers ::assertAllObjects
*/
public function testAssertAllObjects() {
$this->assertTrue(Inspector::assertAllObjects([new \ArrayObject(), new \ArrayObject()]));
$this->assertFalse(Inspector::assertAllObjects([new \ArrayObject(), new \ArrayObject(), 'foo']));
$this->assertTrue(Inspector::assertAllObjects([new \ArrayObject(), new \ArrayObject()], '\\Traversable'));
$this->assertFalse(Inspector::assertAllObjects([new \ArrayObject(), new \ArrayObject(), 'foo'], '\\Traversable'));
$this->assertFalse(Inspector::assertAllObjects([new \ArrayObject(), new StringObject()], '\\Traversable'));
$this->assertTrue(Inspector::assertAllObjects([new \ArrayObject(), new StringObject()], '\\Traversable', '\\Drupal\\Tests\\Component\\Assertion\\StringObject'));
$this->assertFalse(Inspector::assertAllObjects([new \ArrayObject(), new StringObject(), new \stdClass()], '\\ArrayObject', '\\Drupal\\Tests\\Component\\Assertion\\StringObject'));
}
/**
* Test method referenced by ::testAllCallable().
*/
public function callMe() {
return TRUE;
}
/**
* Test method referenced by ::testAllCallable().
*/
public static function callMeStatic() {
return TRUE;
}
}
/**
* Quick class for testing for objects with __toString.
*/
class StringObject {
/**
* {@inheritdoc}
*/
public function __toString() {
return 'foo';
}
}

View file

@ -37,7 +37,23 @@ class ProxyBuilderTest extends UnitTestCase {
*/
public function testBuildProxyClassName() {
$class_name = $this->proxyBuilder->buildProxyClassName('Drupal\Tests\Component\ProxyBuilder\TestServiceNoMethod');
$this->assertEquals('Drupal_Tests_Component_ProxyBuilder_TestServiceNoMethod_Proxy', $class_name);
$this->assertEquals('Drupal\Tests\ProxyClass\Component\ProxyBuilder\TestServiceNoMethod', $class_name);
}
/**
* @covers ::buildProxyClassName
*/
public function testBuildProxyClassNameForModule() {
$class_name = $this->proxyBuilder->buildProxyClassName('Drupal\views_ui\ParamConverter\ViewUIConverter');
$this->assertEquals('Drupal\views_ui\ProxyClass\ParamConverter\ViewUIConverter', $class_name);
}
/**
* @covers ::buildProxyNamespace
*/
public function testBuildProxyNamespace() {
$class_name = $this->proxyBuilder->buildProxyNamespace('Drupal\Tests\Component\ProxyBuilder\TestServiceNoMethod');
$this->assertEquals('Drupal\Tests\ProxyClass\Component\ProxyBuilder', $class_name);
}
/**
@ -65,10 +81,13 @@ class ProxyBuilderTest extends UnitTestCase {
$method_body = <<<'EOS'
public function method()
{
return $this->lazyLoadItself()->method();
}
/**
* {@inheritdoc}
*/
public function method()
{
return $this->lazyLoadItself()->method();
}
EOS;
$this->assertEquals($this->buildExpectedClass($class, $method_body), $result);
@ -86,10 +105,13 @@ EOS;
$method_body = <<<'EOS'
public function methodWithParameter($parameter)
{
return $this->lazyLoadItself()->methodWithParameter($parameter);
}
/**
* {@inheritdoc}
*/
public function methodWithParameter($parameter)
{
return $this->lazyLoadItself()->methodWithParameter($parameter);
}
EOS;
$this->assertEquals($this->buildExpectedClass($class, $method_body), $result);
@ -108,11 +130,14 @@ EOS;
// @todo Solve the silly linebreak for array()
$method_body = <<<'EOS'
public function complexMethod($parameter, callable $function, \Drupal\Tests\Component\ProxyBuilder\TestServiceNoMethod $test_service = NULL, array &$elements = array (
))
{
return $this->lazyLoadItself()->complexMethod($parameter, $function, $test_service, $elements);
}
/**
* {@inheritdoc}
*/
public function complexMethod($parameter, callable $function, \Drupal\Tests\Component\ProxyBuilder\TestServiceNoMethod $test_service = NULL, array &$elements = array (
))
{
return $this->lazyLoadItself()->complexMethod($parameter, $function, $test_service, $elements);
}
EOS;
@ -131,10 +156,13 @@ EOS;
// @todo Solve the silly linebreak for array()
$method_body = <<<'EOS'
public function &returnReference()
{
return $this->lazyLoadItself()->returnReference();
}
/**
* {@inheritdoc}
*/
public function &returnReference()
{
return $this->lazyLoadItself()->returnReference();
}
EOS;
@ -153,10 +181,13 @@ EOS;
$method_body = <<<'EOS'
public function testMethod($parameter)
{
return $this->lazyLoadItself()->testMethod($parameter);
}
/**
* {@inheritdoc}
*/
public function testMethod($parameter)
{
return $this->lazyLoadItself()->testMethod($parameter);
}
EOS;
@ -189,10 +220,13 @@ EOS;
$method_body = <<<'EOS'
public function testMethod($parameter)
{
return $this->lazyLoadItself()->testMethod($parameter);
}
/**
* {@inheritdoc}
*/
public function testMethod($parameter)
{
return $this->lazyLoadItself()->testMethod($parameter);
}
EOS;
@ -212,10 +246,13 @@ $this->assertEquals($this->buildExpectedClass($class, $method_body), $result);
// Ensure that the static method is not wrapped.
$method_body = <<<'EOS'
public static function testMethod($parameter)
{
\Drupal\Tests\Component\ProxyBuilder\TestServiceWithPublicStaticMethod::testMethod($parameter);
}
/**
* {@inheritdoc}
*/
public static function testMethod($parameter)
{
\Drupal\Tests\Component\ProxyBuilder\TestServiceWithPublicStaticMethod::testMethod($parameter);
}
EOS;
@ -232,53 +269,87 @@ EOS;
* The code of the entire proxy.
*/
protected function buildExpectedClass($class, $expected_methods_body, $interface_string = '') {
$proxy_class = $this->proxyBuilder->buildProxyClassName($class);
$namespace = ProxyBuilder::buildProxyNamespace($class);
$reflection = new \ReflectionClass($class);
$proxy_class = $reflection->getShortName();
$expected_string = <<<'EOS'
/**
* Provides a proxy class for \{{ class }}.
*
* @see \Drupal\Component\ProxyBuilder
*/
class {{ proxy_class }}{{ interface_string }}
{
namespace {{ namespace }} {
/**
* @var string
*/
protected $serviceId;
/**
* @var \{{ class }}
*/
protected $service;
/**
* The service container.
* Provides a proxy class for \{{ class }}.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
* @see \Drupal\Component\ProxyBuilder
*/
protected $container;
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $serviceId)
class {{ proxy_class }}{{ interface_string }}
{
$this->container = $container;
$this->serviceId = $serviceId;
}
protected function lazyLoadItself()
{
if (!isset($this->service)) {
$method_name = 'get' . Container::camelize($this->serviceId) . 'Service';
$this->service = $this->container->$method_name(false);
/**
* The id of the original proxied service.
*
* @var string
*/
protected $drupalProxyOriginalServiceId;
/**
* The real proxied service, after it was lazy loaded.
*
* @var \{{ class }}
*/
protected $service;
/**
* The service container.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* Constructs a ProxyClass Drupal proxy object.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The container.
* @param string $drupal_proxy_original_service_id
* The service ID of the original service.
*/
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
{
$this->container = $container;
$this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
}
return $this->service;
}
/**
* Lazy loads the real service from the container.
*
* @return object
* Returns the constructed real service.
*/
protected function lazyLoadItself()
{
if (!isset($this->service)) {
$this->service = $this->container->get($this->drupalProxyOriginalServiceId);
}
return $this->service;
}
{{ expected_methods_body }}
}
}
EOS;
$expected_methods_body = implode("\n", array_map(function ($value) {
if ($value === '') {
return $value;
}
return " $value";
}, explode("\n", $expected_methods_body)));
$expected_string = str_replace('{{ proxy_class }}', $proxy_class, $expected_string);
$expected_string = str_replace('{{ namespace }}', $namespace, $expected_string);
$expected_string = str_replace('{{ class }}', $class, $expected_string);
$expected_string = str_replace('{{ expected_methods_body }}', $expected_methods_body, $expected_string);
$expected_string = str_replace('{{ interface_string }}', $interface_string, $expected_string);

View file

@ -1,129 +0,0 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Component\ProxyBuilder\ProxyDumperTest.
*/
namespace Drupal\Tests\Component\ProxyBuilder;
use Drupal\Component\ProxyBuilder\ProxyDumper;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\Definition;
/**
* @coversDefaultClass \Drupal\Component\ProxyBuilder\ProxyDumper
* @group proxy_builder
*/
class ProxyDumperTest extends UnitTestCase {
/**
* The mocked proxy builder.
*
* @var \Drupal\Component\ProxyBuilder\ProxyBuilder|\PHPUnit_Framework_MockObject_MockObject
*/
protected $proxyBuilder;
/**
* The tested proxy dumper.
*
* @var \Drupal\Component\ProxyBuilder\ProxyDumper
*/
protected $proxyDumper;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->proxyBuilder = $this->getMockBuilder('Drupal\Component\ProxyBuilder\ProxyBuilder')
->disableOriginalConstructor()
->setMethods(['build'])
->getMock();
$this->proxyDumper = new ProxyDumper($this->proxyBuilder);
}
/**
* @dataProvider providerTestIsProxyCandidate
* @covers ::isProxyCandidate
*/
public function testIsProxyCandidate(Definition $definition, $expected) {
$this->assertSame($expected, $this->proxyDumper->isProxyCandidate($definition));
}
public function providerTestIsProxyCandidate() {
// Not lazy service.
$data = [];
$definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestService');
$data[] = [$definition, FALSE];
// Not existing service.
$definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestNotExistingService');
$definition->setLazy(TRUE);
$data[] = [$definition, FALSE];
// Existing and lazy service.
$definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestService');
$definition->setLazy(TRUE);
$data[] = [$definition, TRUE];
return $data;
}
public function testGetProxyFactoryCode() {
$definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestService');
$definition->setLazy(TRUE);
$result = $this->proxyDumper->getProxyFactoryCode($definition, 'test_service');
$expected = <<<'EOS'
if ($lazyLoad) {
return $this->services['test_service'] = new Drupal_Tests_Component_ProxyBuilder_TestService_Proxy($this, 'test_service');
}
EOS;
$this->assertEquals($expected, $result);
}
/**
* @covers ::getProxyCode
*/
public function testGetProxyCode() {
$definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestService');
$definition->setLazy(TRUE);
$class = 'class Drupal_Tests_Component_ProxyBuilder_TestService_Proxy {}';
$this->proxyBuilder->expects($this->once())
->method('build')
->with('Drupal\Tests\Component\ProxyBuilder\TestService')
->willReturn($class);
$result = $this->proxyDumper->getProxyCode($definition);
$this->assertEquals($class, $result);
}
/**
* @covers ::getProxyCode
*/
public function testGetProxyCodeWithSameClassMultipleTimes() {
$definition = new Definition('Drupal\Tests\Component\ProxyBuilder\TestService');
$definition->setLazy(TRUE);
$class = 'class Drupal_Tests_Component_ProxyBuilder_TestService_Proxy {}';
$this->proxyBuilder->expects($this->once())
->method('build')
->with('Drupal\Tests\Component\ProxyBuilder\TestService')
->willReturn($class);
$result = $this->proxyDumper->getProxyCode($definition);
$this->assertEquals($class, $result);
$result = $this->proxyDumper->getProxyCode($definition);
$this->assertEquals('', $result);
}
}
class TestService {
}

View file

@ -8,6 +8,7 @@
namespace Drupal\Tests\Component\Utility;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Component\Utility\Xss;
use Drupal\Tests\UnitTestCase;
/**
@ -212,6 +213,41 @@ class SafeMarkupTest extends UnitTestCase {
$this->assertEquals($is_safe, SafeMarkup::isSafe($result));
}
/**
* Tests the interaction between the safe list and XSS filtering.
*
* @covers ::xssFilter
* @covers ::escape
*/
public function testAdminXss() {
// Use the predefined XSS admin tag list. This strips the <marquee> tags.
$this->assertEquals('text', SafeMarkup::xssFilter('<marquee>text</marquee>', Xss::getAdminTagList()));
$this->assertTrue(SafeMarkup::isSafe('text'), 'The string \'text\' is marked as safe.');
// This won't strip the <marquee> tags and the string with HTML will be
// marked as safe.
$filtered = SafeMarkup::xssFilter('<marquee>text</marquee>', array('marquee'));
$this->assertEquals('<marquee>text</marquee>', $filtered);
$this->assertTrue(SafeMarkup::isSafe('<marquee>text</marquee>'), 'The string \'<marquee>text</marquee>\' is marked as safe.');
// SafeMarkup::xssFilter() with the default tag list will strip the
// <marquee> tag even though the string was marked safe above.
$this->assertEquals('text', SafeMarkup::xssFilter('<marquee>text</marquee>'));
// SafeMarkup::escape() will not escape the markup tag since the string was
// marked safe above.
$this->assertEquals('<marquee>text</marquee>', SafeMarkup::escape($filtered));
// SafeMarkup::checkPlain() will escape the markup tag even though the
// string was marked safe above.
$this->assertEquals('&lt;marquee&gt;text&lt;/marquee&gt;', SafeMarkup::checkPlain($filtered));
// Ensure that SafeMarkup::xssFilter strips all tags when passed an empty
// array and uses the default tag list when not passed a tag list.
$this->assertEquals('text', SafeMarkup::xssFilter('<em>text</em>', []));
$this->assertEquals('<em>text</em>', SafeMarkup::xssFilter('<em>text</em>'));
}
/**
* Data provider for testReplace().
*

View file

@ -48,6 +48,7 @@ class ComposerIntegrationTest extends UnitTestCase {
return [
$this->root,
$this->root . '/core',
$this->root . '/core/lib/Drupal/Component/Gettext',
$this->root . '/core/lib/Drupal/Component/Plugin',
$this->root . '/core/lib/Drupal/Component/ProxyBuilder',
$this->root . '/core/lib/Drupal/Component/Utility',

View file

@ -12,6 +12,7 @@ use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Access\AccessResultNeutral;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Tests\UnitTestCase;
/**
@ -20,6 +21,28 @@ use Drupal\Tests\UnitTestCase;
*/
class AccessResultTest extends UnitTestCase {
/**
* The cache contexts manager.
*
* @var \Drupal\Core\Cache\Context\CacheContextsManager|\PHPUnit_Framework_MockObject_MockObject
*/
protected $cacheContextsManager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->cacheContextsManager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
->disableOriginalConstructor()
->getMock();
$container = new ContainerBuilder();
$container->set('cache_contexts_manager', $this->cacheContextsManager);
\Drupal::setContainer($container);
}
protected function assertDefaultCacheability(AccessResult $access) {
$this->assertSame([], $access->getCacheContexts());
$this->assertSame([], $access->getCacheTags());
@ -382,18 +405,17 @@ class AccessResultTest extends UnitTestCase {
/**
* @covers ::addCacheTags
* @covers ::resetCacheTags
* @covers ::addCacheableDependency
* @covers ::getCacheTags
* @covers ::cacheUntilEntityChanges
* @covers ::cacheUntilConfigurationChanges
* @covers ::resetCacheTags
*/
public function testCacheTags() {
$verify = function (AccessResult $access, array $tags) {
$verify = function (AccessResult $access, array $tags, array $contexts = [], $max_age = Cache::PERMANENT) {
$this->assertFalse($access->isAllowed());
$this->assertFalse($access->isForbidden());
$this->assertTrue($access->isNeutral());
$this->assertSame(Cache::PERMANENT, $access->getCacheMaxAge());
$this->assertSame([], $access->getCacheContexts());
$this->assertSame($max_age, $access->getCacheMaxAge());
$this->assertSame($contexts, $access->getCacheContexts());
$this->assertSame($tags, $access->getCacheTags());
};
@ -420,29 +442,26 @@ class AccessResultTest extends UnitTestCase {
->addCacheTags(['bar:baz']);
$verify($access, ['bar:baz', 'bar:qux', 'foo:bar', 'foo:baz']);
// ::cacheUntilEntityChanges() convenience method.
// ::addCacheableDependency() convenience method.
$node = $this->getMock('\Drupal\node\NodeInterface');
$node->expects($this->any())
->method('getCacheTags')
->will($this->returnValue(array('node:20011988')));
$node->expects($this->any())
->method('getCacheMaxAge')
->willReturn(600);
$node->expects($this->any())
->method('getCacheContexts')
->willReturn(['user']);
$tags = array('node:20011988');
$a = AccessResult::neutral()->addCacheTags($tags);
$verify($a, $tags);
$b = AccessResult::neutral()->cacheUntilEntityChanges($node);
$verify($b, $tags);
$this->assertEquals($a, $b);
$b = AccessResult::neutral()->addCacheableDependency($node);
$verify($b, $tags, ['user'], 600);
// ::cacheUntilConfigurationChanges() convenience method.
$configuration = $this->getMock('\Drupal\Core\Config\ConfigBase');
$configuration->expects($this->any())
->method('getCacheTags')
->will($this->returnValue(array('config:foo.bar.baz')));
$tags = array('config:foo.bar.baz');
$a = AccessResult::neutral()->addCacheTags($tags);
$verify($a, $tags);
$b = AccessResult::neutral()->cacheUntilConfigurationChanges($configuration);
$verify($b, $tags);
$this->assertEquals($a, $b);
$non_cacheable_dependency = new \stdClass();
$non_cacheable = AccessResult::neutral()->addCacheableDependency($non_cacheable_dependency);
$verify($non_cacheable, [], [], 0);
}
/**

View file

@ -7,7 +7,7 @@
namespace Drupal\Tests\Core\Access;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Tests\UnitTestCase;
use Drupal\Core\Access\RouteProcessorCsrf;
use Symfony\Component\Routing\Route;
@ -50,71 +50,73 @@ class RouteProcessorCsrfTest extends UnitTestCase {
$route = new Route('/test-path');
$parameters = array();
$cacheable_metadata = new CacheableMetadata();
$this->processor->processOutbound('test', $route, $parameters, $cacheable_metadata);
$bubbleable_metadata = new BubbleableMetadata();
$this->processor->processOutbound('test', $route, $parameters, $bubbleable_metadata);
// No parameters should be added to the parameters array.
$this->assertEmpty($parameters);
// Cacheability of routes without a _csrf_token route requirement is
// unaffected.
$this->assertEquals((new CacheableMetadata()), $cacheable_metadata);
$this->assertEquals((new BubbleableMetadata()), $bubbleable_metadata);
}
/**
* Tests the processOutbound() method with a _csrf_token route requirement.
*/
public function testProcessOutbound() {
$this->csrfToken->expects($this->once())
->method('get')
// The leading '/' will be stripped from the path.
->with('test-path')
->will($this->returnValue('test_token'));
$route = new Route('/test-path', array(), array('_csrf_token' => 'TRUE'));
$parameters = array();
$cacheable_metadata = new CacheableMetadata();
$this->processor->processOutbound('test', $route, $parameters, $cacheable_metadata);
$bubbleable_metadata = new BubbleableMetadata();
$this->processor->processOutbound('test', $route, $parameters, $bubbleable_metadata);
// 'token' should be added to the parameters array.
$this->assertArrayHasKey('token', $parameters);
$this->assertSame($parameters['token'], 'test_token');
// Cacheability of routes with a _csrf_token route requirement is max-age=0.
$this->assertEquals((new CacheableMetadata())->setCacheMaxAge(0), $cacheable_metadata);
// Bubbleable metadata of routes with a _csrf_token route requirement is a
// placeholder.
$path = 'test-path';
$placeholder = hash('sha1', $path);
$placeholder_render_array = [
'#lazy_builder' => ['route_processor_csrf:renderPlaceholderCsrfToken', [$path]],
];
$this->assertSame($parameters['token'], $placeholder);
$this->assertEquals((new BubbleableMetadata())->setAttachments(['placeholders' => [$placeholder => $placeholder_render_array]]), $bubbleable_metadata);
}
/**
* Tests the processOutbound() method with a dynamic path and one replacement.
*/
public function testProcessOutboundDynamicOne() {
$this->csrfToken->expects($this->once())
->method('get')
->with('test-path/100')
->will($this->returnValue('test_token'));
$route = new Route('/test-path/{slug}', array(), array('_csrf_token' => 'TRUE'));
$parameters = array('slug' => 100);
$cacheable_metadata = new CacheableMetadata();
$this->processor->processOutbound('test', $route, $parameters, $cacheable_metadata);
// Cacheability of routes with a _csrf_token route requirement is max-age=0.
$this->assertEquals((new CacheableMetadata())->setCacheMaxAge(0), $cacheable_metadata);
$bubbleable_metadata = new BubbleableMetadata();
$this->processor->processOutbound('test', $route, $parameters, $bubbleable_metadata);
// Bubbleable metadata of routes with a _csrf_token route requirement is a
// placeholder.
$path = 'test-path/100';
$placeholder = hash('sha1', $path);
$placeholder_render_array = [
'#lazy_builder' => ['route_processor_csrf:renderPlaceholderCsrfToken', [$path]],
];
$this->assertEquals((new BubbleableMetadata())->setAttachments(['placeholders' => [$placeholder => $placeholder_render_array]]), $bubbleable_metadata);
}
/**
* Tests the processOutbound() method with two parameter replacements.
*/
public function testProcessOutboundDynamicTwo() {
$this->csrfToken->expects($this->once())
->method('get')
->with('100/test-path/test')
->will($this->returnValue('test_token'));
$route = new Route('{slug_1}/test-path/{slug_2}', array(), array('_csrf_token' => 'TRUE'));
$parameters = array('slug_1' => 100, 'slug_2' => 'test');
$cacheable_metadata = new CacheableMetadata();
$this->processor->processOutbound('test', $route, $parameters, $cacheable_metadata);
// Cacheability of routes with a _csrf_token route requirement is max-age=0.
$this->assertEquals((new CacheableMetadata())->setCacheMaxAge(0), $cacheable_metadata);
$bubbleable_metadata = new BubbleableMetadata();
$this->processor->processOutbound('test', $route, $parameters, $bubbleable_metadata);
// Bubbleable metadata of routes with a _csrf_token route requirement is a
// placeholder.
$path = '100/test-path/test';
$placeholder = hash('sha1', $path);
$placeholder_render_array = [
'#lazy_builder' => ['route_processor_csrf:renderPlaceholderCsrfToken', [$path]],
];
$this->assertEquals((new BubbleableMetadata())->setAttachments(['placeholders' => [$placeholder => $placeholder_render_array]]), $bubbleable_metadata);
}
}

View file

@ -71,7 +71,7 @@ class CssOptimizerUnitTest extends UnitTestCase {
// - Stripped comments and white-space.
// - Retain white-space in selectors. (https://www.drupal.org/node/472820)
// - Retain pseudo-selectors. (https://www.drupal.org/node/460448)
0 => array(
array(
array(
'group' => -100,
'every_page' => TRUE,
@ -92,7 +92,7 @@ class CssOptimizerUnitTest extends UnitTestCase {
// file_create_url(). (https://www.drupal.org/node/1961340)
// - Imported files that are external (protocol-relative URL or not)
// should not be expanded. (https://www.drupal.org/node/2014851)
1 => array(
array(
array(
'group' => -100,
'every_page' => TRUE,
@ -108,7 +108,7 @@ class CssOptimizerUnitTest extends UnitTestCase {
),
// File. Tests:
// - Retain comment hacks.
2 => array(
array(
array(
'group' => -100,
'every_page' => TRUE,
@ -126,7 +126,7 @@ class CssOptimizerUnitTest extends UnitTestCase {
// - CSS import path is properly interpreted.
// (https://www.drupal.org/node/1198904)
// - Don't adjust data URIs (https://www.drupal.org/node/2142441)
5 => array(
array(
array(
'group' => -100,
'every_page' => TRUE,
@ -143,7 +143,7 @@ class CssOptimizerUnitTest extends UnitTestCase {
// File. Tests:
// - Any @charaset declaration at the beginning of a file should be
// removed without breaking subsequent CSS.
6 => array(
array(
array(
'group' => -100,
'every_page' => TRUE,
@ -157,7 +157,7 @@ class CssOptimizerUnitTest extends UnitTestCase {
),
file_get_contents($path . 'charset.css.optimized.css'),
),
7 => array(
array(
array(
'group' => -100,
'every_page' => TRUE,
@ -171,7 +171,7 @@ class CssOptimizerUnitTest extends UnitTestCase {
),
file_get_contents($path . 'charset.css.optimized.css'),
),
6 => array(
array(
array(
'group' => -100,
'every_page' => TRUE,
@ -185,7 +185,7 @@ class CssOptimizerUnitTest extends UnitTestCase {
),
'.byte-order-mark-test{content:"☃";}'. "\n",
),
7 => array(
array(
array(
'group' => -100,
'every_page' => TRUE,
@ -199,7 +199,7 @@ class CssOptimizerUnitTest extends UnitTestCase {
),
'.charset-test{content:"€";}' . "\n",
),
8 => array(
array(
array(
'group' => -100,
'every_page' => TRUE,
@ -213,7 +213,7 @@ class CssOptimizerUnitTest extends UnitTestCase {
),
'.byte-order-mark-charset-test{content:"☃";}' . "\n",
),
9 => array(
array(
array(
'group' => -100,
'every_page' => TRUE,

View file

@ -0,0 +1,95 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Authentication\AuthenticationCollectorTest.
*/
namespace Drupal\Tests\Core\Authentication;
use Drupal\Core\Authentication\AuthenticationCollector;
use Drupal\Core\Authentication\AuthenticationProviderInterface;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
/**
* @coversDefaultClass \Drupal\Core\Authentication\AuthenticationCollector
* @group Authentication
*/
class AuthenticationCollectorTest extends UnitTestCase {
/**
* Tests adding, getting, and order of priorities.
*
* @covers ::addProvider
* @covers ::getSortedProviders
* @covers ::getProvider
* @covers ::isGlobal
*/
public function testAuthenticationCollector() {
$providers = [];
$global = [];
$authentication_collector = new AuthenticationCollector();
$priorities = [2, 0, -8, 10, 1, 3, -5, 0, 6, -10, -4];
foreach ($priorities as $priority) {
$provider_id = $this->randomMachineName();
$provider = new TestAuthenticationProvider($provider_id);
$providers[$priority][$provider_id] = $provider;
$global[$provider_id] = rand(0, 1) > 0.5;
$authentication_collector->addProvider($provider, $provider_id, $priority, $global[$provider_id]);
}
// Sort the $providers array by priority (highest number is lowest priority)
// and compare with AuthenticationCollector::getSortedProviders().
krsort($providers);
// Merge nested providers from $providers into $sorted_providers.
$sorted_providers = [];
foreach ($providers as $providers_priority) {
$sorted_providers = array_merge($sorted_providers, $providers_priority);
}
$this->assertEquals($sorted_providers, $authentication_collector->getSortedProviders());
// Test AuthenticationCollector::getProvider() and
// AuthenticationCollector::isGlobal().
foreach ($sorted_providers as $provider) {
$this->assertEquals($provider, $authentication_collector->getProvider($provider->providerId));
$this->assertEquals($global[$provider->providerId], $authentication_collector->isGlobal($provider->providerId));
}
}
}
/**
* A simple provider for unit testing AuthenticationCollector.
*/
class TestAuthenticationProvider implements AuthenticationProviderInterface {
/**
* The provider id.
*
* @var string
*/
public $providerId;
/**
* Constructor.
*/
public function __construct($provider_id) {
$this->providerId = $provider_id;
}
/**
* {@inheritdoc}
*/
public function applies(Request $request) {
return TRUE;
}
/**
* {@inheritdoc}
*/
public function authenticate(Request $request) {
return NULL;
}
}

View file

@ -7,6 +7,7 @@
namespace Drupal\Tests\Core\Authentication;
use Drupal\Core\Authentication\AuthenticationCollector;
use Drupal\Core\Authentication\AuthenticationManager;
use Drupal\Core\Authentication\AuthenticationProviderFilterInterface;
use Drupal\Core\Authentication\AuthenticationProviderInterface;
@ -28,9 +29,10 @@ class AuthenticationManagerTest extends UnitTestCase {
* @dataProvider providerTestDefaultFilter
*/
public function testDefaultFilter($applies, $has_route, $auth_option, $provider_id, $global) {
$authentication_manager = new AuthenticationManager();
$auth_provider = $this->getMock('Drupal\Core\Authentication\AuthenticationProviderInterface');
$authentication_manager->addProvider($auth_provider, $provider_id, 0, $global);
$auth_collector = new AuthenticationCollector();
$auth_collector->addProvider($auth_provider, $provider_id, 0, $global);
$authentication_manager = new AuthenticationManager($auth_collector);
$request = new Request();
if ($has_route) {
@ -48,14 +50,16 @@ class AuthenticationManagerTest extends UnitTestCase {
* @covers ::applyFilter
*/
public function testApplyFilterWithFilterprovider() {
$authentication_manager = new AuthenticationManager();
$auth_provider = $this->getMock('Drupal\Tests\Core\Authentication\TestAuthenticationProviderInterface');
$authentication_manager->addProvider($auth_provider, 'filtered', 0);
$auth_provider->expects($this->once())
->method('appliesToRoutedRequest')
->willReturn(TRUE);
$authentication_collector = new AuthenticationCollector();
$authentication_collector->addProvider($auth_provider, 'filtered', 0);
$authentication_manager = new AuthenticationManager($authentication_collector);
$request = new Request();
$this->assertTrue($authentication_manager->appliesToRoutedRequest($request, FALSE));
}

View file

@ -42,6 +42,28 @@ class CacheableMetadataTest extends UnitTestCase {
$this->assertEquals($expected, $a->merge($b));
}
/**
* @covers ::addCacheableDependency
* @dataProvider providerTestMerge
*
* This only tests at a high level, because it reuses existing logic. Detailed
* tests exist for the existing logic:
*
* @see \Drupal\Tests\Core\Cache\CacheTest::testMergeTags()
* @see \Drupal\Tests\Core\Cache\CacheTest::testMergeMaxAges()
* @see \Drupal\Tests\Core\Cache\CacheContextsTest
*/
public function testAddCacheableDependency(CacheableMetadata $a, CacheableMetadata $b, CacheableMetadata $expected) {
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
->disableOriginalConstructor()
->getMock();
$container = new ContainerBuilder();
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
$this->assertEquals($expected, $a->addCacheableDependency($b));
}
/**
* Provides test data for testMerge().
*

View file

@ -7,6 +7,7 @@
namespace Drupal\Tests\Core\Cache\Context;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\Cache\Context\CacheContextInterface;
use Drupal\Core\Cache\Context\CalculatedCacheContextInterface;
@ -32,10 +33,11 @@ class CacheContextsManagerTest extends UnitTestCase {
$container->expects($this->any())
->method('get')
->will($this->returnValueMap([
['a', Container::EXCEPTION_ON_INVALID_REFERENCE, new FooCacheContext()],
['a.b', Container::EXCEPTION_ON_INVALID_REFERENCE, new FooCacheContext()],
['a.b.c', Container::EXCEPTION_ON_INVALID_REFERENCE, new BazCacheContext()],
['x', Container::EXCEPTION_ON_INVALID_REFERENCE, new BazCacheContext()],
['cache_context.a', Container::EXCEPTION_ON_INVALID_REFERENCE, new FooCacheContext()],
['cache_context.a.b', Container::EXCEPTION_ON_INVALID_REFERENCE, new FooCacheContext()],
['cache_context.a.b.c', Container::EXCEPTION_ON_INVALID_REFERENCE, new BazCacheContext()],
['cache_context.x', Container::EXCEPTION_ON_INVALID_REFERENCE, new BazCacheContext()],
['cache_context.a.b.no-optimize', Container::EXCEPTION_ON_INVALID_REFERENCE, new NoOptimizeCacheContext()],
]));
$cache_contexts_manager = new CacheContextsManager($container, $this->getContextsFixture());
@ -74,6 +76,9 @@ class CacheContextsManagerTest extends UnitTestCase {
[['a', 'a.b.c:foo'], ['a']],
[['a.b.c:foo', 'a'], ['a']],
[['a.b.c:foo', 'a.b.c'], ['a.b.c']],
// max-age 0 is treated as non-optimizable.
[['a.b.no-optimize', 'a.b', 'a'], ['a.b.no-optimize', 'a']],
];
}
@ -91,17 +96,17 @@ class CacheContextsManagerTest extends UnitTestCase {
]);
$expected = [
'baz.cnenzrgreN',
'baz.cnenzrgreO',
'bar',
'[baz:parameterA]=cnenzrgreN',
'[baz:parameterB]=cnenzrgreO',
'[foo]=bar',
];
$this->assertEquals($expected, $new_keys);
$this->assertEquals($expected, $new_keys->getKeys());
}
/**
* @covers ::convertTokensToKeys
*
* @expectedException \InvalidArgumentException
* @expectedException \LogicException
* @expectedExceptionMessage "non-cache-context" is not a valid cache context ID.
*/
public function testInvalidContext() {
@ -234,6 +239,13 @@ class FooCacheContext implements CacheContextInterface {
return 'bar';
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
return new CacheableMetadata();
}
}
/**
@ -255,7 +267,43 @@ class BazCacheContext implements CalculatedCacheContextInterface {
if (!is_string($parameter) || strlen($parameter) === 0) {
throw new \Exception();
}
return 'baz.' . str_rot13($parameter);
return str_rot13($parameter);
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata($parameter = NULL) {
return new CacheableMetadata();
}
}
/**
* Non-optimizable context class.
*/
class NoOptimizeCacheContext implements CacheContextInterface {
/**
* {@inheritdoc}
*/
public static function getLabel() {
return 'Foo';
}
/**
* {@inheritdoc}
*/
public function getContext() {
return 'bar';
}
/**
* {@inheritdoc}
*/
public function getCacheableMetadata() {
$cacheable_metadata = new CacheableMetadata();
return $cacheable_metadata->setCacheMaxAge(0);
}
}

View file

@ -413,17 +413,12 @@ class ConfigTest extends UnitTestCase {
// Name missing namespace (dot).
array(
'MissingNamespace',
SafeMarkup::format('Missing namespace in Config object name MissingNamespace.', array(
'@name' => 'MissingNamespace',
)),
'Missing namespace in Config object name MissingNamespace.',
),
// Exceeds length (max length plus an extra dot).
array(
str_repeat('a', Config::MAX_NAME_LENGTH) . ".",
SafeMarkup::format('Config object name @name exceeds maximum allowed length of @length characters.', array(
'@name' => str_repeat('a', Config::MAX_NAME_LENGTH) . ".",
'@length' => Config::MAX_NAME_LENGTH,
)),
'Config object name ' . str_repeat('a', Config::MAX_NAME_LENGTH) . '. exceeds maximum allowed length of ' . Config::MAX_NAME_LENGTH . ' characters.',
),
);
// Name must not contain : ? * < > " ' / \
@ -431,9 +426,7 @@ class ConfigTest extends UnitTestCase {
$name = 'name.' . $char;
$return[] = array(
$name,
SafeMarkup::format('Invalid character in Config object name @name.', array(
'@name' => $name,
)),
"Invalid character in Config object name $name.",
);
}
return $return;

View file

@ -376,10 +376,6 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
* @depends testSetStatus
*/
public function testDisable() {
$this->cacheTagsInvalidator->expects($this->once())
->method('invalidateTags')
->with(array('config:test_provider.' . $this->entityTypeId . '.' . $this->id));
$this->entity->setStatus(TRUE);
$this->assertSame($this->entity, $this->entity->disable());
$this->assertFalse($this->entity->status());
@ -444,18 +440,38 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
'label' => 'label',
),
)));
$entity_a = $this->entity;
$entity_a->label = 'foo';
$entity_b = clone $this->entity;
$entity_b->label = 'bar';
$entity_a = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityInterface');
$entity_a->expects($this->atLeastOnce())
->method('label')
->willReturn('foo');
$entity_b = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityInterface');
$entity_b->expects($this->atLeastOnce())
->method('label')
->willReturn('bar');
// Test sorting by label.
$list = array($entity_a, $entity_b);
// Suppress errors because of https://bugs.php.net/bug.php?id=50688.
@usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
$this->assertSame($entity_b, $list[0]);
$list = array($entity_b, $entity_a);
// Suppress errors because of https://bugs.php.net/bug.php?id=50688.
@usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
$this->assertSame($entity_b, $list[0]);
// Test sorting by weight.
$entity_a->weight = 0;
$entity_b->weight = 1;
$list = array($entity_b, $entity_a);
// Suppress errors because of https://bugs.php.net/bug.php?id=50688.
@usort($list, array($entity_a, 'sort'));
@usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
$this->assertSame($entity_a, $list[0]);
$list = array($entity_a, $entity_b);
// Suppress errors because of https://bugs.php.net/bug.php?id=50688.
@usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
$this->assertSame($entity_a, $list[0]);
}

View file

@ -7,6 +7,7 @@
namespace Drupal\Tests\Core\Config\Entity {
use Drupal\Core\Cache\Cache;
use Drupal\Core\Config\Entity\ConfigEntityInterface;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Language\Language;
@ -103,6 +104,13 @@ class ConfigEntityStorageTest extends UnitTestCase {
*/
protected $configManager;
/**
* The cache contexts manager.
*
* @var \Drupal\Core\Cache\Context\CacheContextsManager|\PHPUnit_Framework_MockObject_MockObject
*/
protected $cacheContextsManager;
/**
* {@inheritdoc}
*
@ -170,12 +178,17 @@ class ConfigEntityStorageTest extends UnitTestCase {
$this->configManager = $this->getMock('Drupal\Core\Config\ConfigManagerInterface');
$this->cacheContextsManager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
->disableOriginalConstructor()
->getMock();
$container = new ContainerBuilder();
$container->set('entity.manager', $this->entityManager);
$container->set('config.typed', $this->typedConfigManager);
$container->set('cache_tags.invalidator', $this->cacheTagsInvalidator);
$container->set('config.manager', $this->configManager);
$container->set('language_manager', $this->languageManager);
$container->set('cache_contexts_manager', $this->cacheContextsManager);
\Drupal::setContainer($container);
}
@ -611,6 +624,18 @@ class ConfigEntityStorageTest extends UnitTestCase {
array('', array('id' => 'foo')),
array('id', 'foo'),
)));
$config_object->expects($this->exactly(1))
->method('getCacheContexts')
->willReturn([]);
$config_object->expects($this->exactly(1))
->method('getCacheTags')
->willReturn(['config:foo']);
$config_object->expects($this->exactly(1))
->method('getCacheMaxAge')
->willReturn(Cache::PERMANENT);
$config_object->expects($this->exactly(1))
->method('getName')
->willReturn('foo');
$this->cacheTagsInvalidator->expects($this->never())
->method('invalidateTags');
@ -664,6 +689,18 @@ class ConfigEntityStorageTest extends UnitTestCase {
array('', array('id' => 'foo')),
array('id', 'foo'),
)));
$config_object->expects($this->exactly(1))
->method('getCacheContexts')
->willReturn([]);
$config_object->expects($this->exactly(1))
->method('getCacheTags')
->willReturn(['config:foo']);
$config_object->expects($this->exactly(1))
->method('getCacheMaxAge')
->willReturn(Cache::PERMANENT);
$config_object->expects($this->exactly(1))
->method('getName')
->willReturn('foo');
$this->configFactory->expects($this->once())
->method('loadMultiple')
@ -694,6 +731,19 @@ class ConfigEntityStorageTest extends UnitTestCase {
array('', array('id' => 'foo')),
array('id', 'foo'),
)));
$foo_config_object->expects($this->exactly(1))
->method('getCacheContexts')
->willReturn([]);
$foo_config_object->expects($this->exactly(1))
->method('getCacheTags')
->willReturn(['config:foo']);
$foo_config_object->expects($this->exactly(1))
->method('getCacheMaxAge')
->willReturn(Cache::PERMANENT);
$foo_config_object->expects($this->exactly(1))
->method('getName')
->willReturn('foo');
$bar_config_object = $this->getMockBuilder('Drupal\Core\Config\Config')
->disableOriginalConstructor()
->getMock();
@ -703,6 +753,18 @@ class ConfigEntityStorageTest extends UnitTestCase {
array('', array('id' => 'bar')),
array('id', 'bar'),
)));
$bar_config_object->expects($this->exactly(1))
->method('getCacheContexts')
->willReturn([]);
$bar_config_object->expects($this->exactly(1))
->method('getCacheTags')
->willReturn(['config:bar']);
$bar_config_object->expects($this->exactly(1))
->method('getCacheMaxAge')
->willReturn(Cache::PERMANENT);
$bar_config_object->expects($this->exactly(1))
->method('getName')
->willReturn('foo');
$this->configFactory->expects($this->once())
->method('listAll')
@ -742,6 +804,18 @@ class ConfigEntityStorageTest extends UnitTestCase {
array('', array('id' => 'foo')),
array('id', 'foo'),
)));
$config_object->expects($this->exactly(1))
->method('getCacheContexts')
->willReturn([]);
$config_object->expects($this->exactly(1))
->method('getCacheTags')
->willReturn(['config:foo']);
$config_object->expects($this->exactly(1))
->method('getCacheMaxAge')
->willReturn(Cache::PERMANENT);
$config_object->expects($this->exactly(1))
->method('getName')
->willReturn('foo');
$this->configFactory->expects($this->once())
->method('loadMultiple')

View file

@ -9,7 +9,6 @@ namespace Drupal\Tests\Core\Config\Entity;
use Drupal\Tests\UnitTestCase;
use Drupal\Core\Config\Entity\ConfigEntityType;
use Drupal\Component\Utility\SafeMarkup;
/**
* @coversDefaultClass \Drupal\Core\Config\Entity\ConfigEntityType
@ -41,8 +40,6 @@ class ConfigEntityTypeTest extends UnitTestCase {
* @covers ::getConfigPrefix
*/
public function testConfigPrefixLengthExceeds() {
$message_text = 'The configuration file name prefix @config_prefix exceeds the maximum character limit of @max_char.';
// A provider length of 24 and config_prefix length of 59 (+1 for the .)
// results in a config length of 84, which is too long.
$definition = array(
@ -50,10 +47,10 @@ class ConfigEntityTypeTest extends UnitTestCase {
'config_prefix' => $this->randomMachineName(59),
);
$config_entity = $this->setUpConfigEntityType($definition);
$this->setExpectedException('\Drupal\Core\Config\ConfigPrefixLengthException', SafeMarkup::format($message_text, array(
'@config_prefix' => $definition['provider'] . '.' . $definition['config_prefix'],
'@max_char' => ConfigEntityType::PREFIX_LENGTH,
)));
$this->setExpectedException(
'\Drupal\Core\Config\ConfigPrefixLengthException',
"The configuration file name prefix {$definition['provider']}.{$definition['config_prefix']} exceeds the maximum character limit of " . ConfigEntityType::PREFIX_LENGTH
);
$this->assertEmpty($config_entity->getConfigPrefix());
}

View file

@ -73,7 +73,7 @@ class ContentNegotiationTest extends UnitTestCase {
$request = new Request();
$request->headers->set('X-Requested-With', 'XMLHttpRequest');
$this->assertSame('ajax', $this->contentNegotiation->getContentType($request));
$this->assertSame('html', $this->contentNegotiation->getContentType($request));
}
}

View file

@ -131,7 +131,7 @@ class DateTest extends UnitTestCase {
array(121, 2, '2 min 1 sec'),
// Check for hours with minutes and seconds.
array(3601, 1, '1 hour'),
array(3601, 2, '1 hour 1 sec'),
array(3601, 2, '1 hour'),
// Check for higher units.
array(86401, 1, '1 day'),
array(604800, 1, '1 week'),
@ -310,8 +310,8 @@ class DateTest extends UnitTestCase {
// Checks for hours and possibly minutes or seconds.
array('1 hour', $this->createTimestamp('2013-12-11 09:09:08'), $request_time),
array('1 hour', $this->createTimestamp('2013-12-11 09:09:08'), $request_time),
array('1 hour 1 second', $this->createTimestamp('2013-12-11 09:09:07'), $request_time),
array('1 hour 2 seconds', $this->createTimestamp('2013-12-11 09:09:06'), $request_time),
array('1 hour', $this->createTimestamp('2013-12-11 09:09:07'), $request_time),
array('1 hour', $this->createTimestamp('2013-12-11 09:09:06'), $request_time),
array('1 hour 1 minute', $this->createTimestamp('2013-12-11 09:08:08'), $request_time),
array('1 hour 1 minute 1 second', $this->createTimestamp('2013-12-11 09:08:07'), $request_time, $granularity_3),
array('1 hour 1 minute 2 seconds', $this->createTimestamp('2013-12-11 09:08:06'), $request_time, $granularity_4),
@ -321,13 +321,13 @@ class DateTest extends UnitTestCase {
// Checks for days and possibly hours, minutes or seconds.
array('1 day', $this->createTimestamp('2013-12-10 10:09:08'), $request_time),
array('1 day 1 second', $this->createTimestamp('2013-12-10 10:09:07'), $request_time),
array('1 day', $this->createTimestamp('2013-12-10 10:09:07'), $request_time),
array('1 day 1 hour', $this->createTimestamp('2013-12-10 09:09:08'), $request_time),
array('1 day 1 hour 1 minute', $this->createTimestamp('2013-12-10 09:08:07'), $request_time, $granularity_3 + $langcode_en),
array('1 day 1 hour 1 minute 1 second', $this->createTimestamp('2013-12-10 09:08:07'), $request_time, $granularity_4 + $langcode_lolspeak),
array('1 day 2 hours 2 minutes 2 seconds', $this->createTimestamp('2013-12-10 08:07:06'), $request_time, $granularity_4),
array('2 days', $this->createTimestamp('2013-12-09 10:09:08'), $request_time),
array('2 days 2 minutes', $this->createTimestamp('2013-12-09 10:07:08'), $request_time),
array('2 days', $this->createTimestamp('2013-12-09 10:07:08'), $request_time),
array('2 days 2 hours', $this->createTimestamp('2013-12-09 08:09:08'), $request_time),
array('2 days 2 hours 2 minutes', $this->createTimestamp('2013-12-09 08:07:06'), $request_time, $granularity_3 + $langcode_en),
array('2 days 2 hours 2 minutes 2 seconds', $this->createTimestamp('2013-12-09 08:07:06'), $request_time, $granularity_4 + $langcode_lolspeak),
@ -343,33 +343,33 @@ class DateTest extends UnitTestCase {
// Checks for months and possibly days, hours, minutes or seconds.
array('1 month', $this->createTimestamp('2013-11-11 10:09:08'), $request_time),
array('1 month 1 second', $this->createTimestamp('2013-11-11 10:09:07'), $request_time),
array('1 month 1 hour', $this->createTimestamp('2013-11-11 09:09:08'), $request_time),
array('1 month 1 hour 1 minute', $this->createTimestamp('2013-11-11 09:08:07'), $request_time, $granularity_3),
array('1 month 1 hour 1 minute 1 second', $this->createTimestamp('2013-11-11 09:08:07'), $request_time, $granularity_4),
array('1 month', $this->createTimestamp('2013-11-11 10:09:07'), $request_time),
array('1 month', $this->createTimestamp('2013-11-11 09:09:08'), $request_time),
array('1 month', $this->createTimestamp('2013-11-11 09:08:07'), $request_time, $granularity_3),
array('1 month', $this->createTimestamp('2013-11-11 09:08:07'), $request_time, $granularity_4),
array('1 month 4 weeks', $this->createTimestamp('2013-10-13 10:09:08'), $request_time),
array('1 month 4 weeks 1 day', $this->createTimestamp('2013-10-13 10:09:08'), $request_time, $granularity_3),
array('1 month 4 weeks', $this->createTimestamp('2013-10-12 10:09:08'), $request_time),
array('1 month 4 weeks 2 days', $this->createTimestamp('2013-10-12 10:09:08'), $request_time, $granularity_3),
array('2 months', $this->createTimestamp('2013-10-11 10:09:08'), $request_time),
array('2 months 1 day', $this->createTimestamp('2013-10-10 10:09:08'), $request_time),
array('2 months 2 days', $this->createTimestamp('2013-10-09 08:07:06'), $request_time),
array('2 months 2 days 2 hours', $this->createTimestamp('2013-10-09 08:07:06'), $request_time, $granularity_3),
array('2 months 2 days 2 hours 2 minutes', $this->createTimestamp('2013-10-09 08:07:06'), $request_time, $granularity_4),
array('6 months 2 days', $this->createTimestamp('2013-06-09 10:09:08'), $request_time),
array('11 months 3 hours', $this->createTimestamp('2013-01-11 07:09:08'), $request_time),
array('2 months', $this->createTimestamp('2013-10-10 10:09:08'), $request_time),
array('2 months', $this->createTimestamp('2013-10-09 08:07:06'), $request_time),
array('2 months', $this->createTimestamp('2013-10-09 08:07:06'), $request_time, $granularity_3),
array('2 months', $this->createTimestamp('2013-10-09 08:07:06'), $request_time, $granularity_4),
array('6 months', $this->createTimestamp('2013-06-09 10:09:08'), $request_time),
array('11 months', $this->createTimestamp('2013-01-11 07:09:08'), $request_time),
array('11 months 4 weeks', $this->createTimestamp('2012-12-12 10:09:08'), $request_time),
array('11 months 4 weeks 2 days', $this->createTimestamp('2012-12-12 10:09:08'), $request_time, $granularity_3),
// Checks for years and possibly months, days, hours, minutes or seconds.
array('1 year', $this->createTimestamp('2012-12-11 10:09:08'), $request_time),
array('1 year 1 minute', $this->createTimestamp('2012-12-11 10:08:08'), $request_time),
array('1 year 1 day', $this->createTimestamp('2012-12-10 10:09:08'), $request_time),
array('1 year', $this->createTimestamp('2012-12-11 10:08:08'), $request_time),
array('1 year', $this->createTimestamp('2012-12-10 10:09:08'), $request_time),
array('2 years', $this->createTimestamp('2011-12-11 10:09:08'), $request_time),
array('2 years 2 minutes', $this->createTimestamp('2011-12-11 10:07:08'), $request_time),
array('2 years 2 days', $this->createTimestamp('2011-12-09 10:09:08'), $request_time),
array('2 years 2 months 2 days', $this->createTimestamp('2011-10-09 08:07:06'), $request_time, $granularity_3),
array('2 years 2 months 2 days 2 hours', $this->createTimestamp('2011-10-09 08:07:06'), $request_time, $granularity_4),
array('2 years', $this->createTimestamp('2011-12-11 10:07:08'), $request_time),
array('2 years', $this->createTimestamp('2011-12-09 10:09:08'), $request_time),
array('2 years 2 months', $this->createTimestamp('2011-10-09 08:07:06'), $request_time, $granularity_3),
array('2 years 2 months', $this->createTimestamp('2011-10-09 08:07:06'), $request_time, $granularity_4),
array('10 years', $this->createTimestamp('2003-12-11 10:09:08'), $request_time),
array('100 years', $this->createTimestamp('1913-12-11 10:09:08'), $request_time),

View file

@ -7,6 +7,7 @@
namespace Drupal\Tests\Core\DependencyInjection\Compiler;
use Drupal\Core\Database\Driver\sqlite\Connection;
use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\Alias;
@ -48,7 +49,7 @@ class BackendCompilerPassTest extends UnitTestCase {
public function testProcess($expected_class, ContainerBuilder $container) {
$this->backendPass->process($container);
$this->assertInstanceOf($expected_class, $container->get('service'));
$this->assertEquals($expected_class, get_class($container->get('service')));
}
/**
@ -59,28 +60,70 @@ class BackendCompilerPassTest extends UnitTestCase {
public function providerTestProcess() {
$data = array();
// Add a container with no set default_backend.
$container = new ContainerBuilder();
$prefix = '\\' . __NAMESPACE__ . '\\';
$container->setDefinition('service', (new Definition($prefix . 'ServiceClassDefault'))->addTag('backend_overridable'));
$container->setDefinition('mysql.service', new Definition($prefix . 'ServiceClassMysql'));
$prefix = __NAMESPACE__ . '\\ServiceClass';
$service = (new Definition($prefix . 'Default'))->addTag('backend_overridable');
$container = $this->getMysqlContainer($service);
$data[] = array($prefix . 'ServiceClassDefault', $container);
$data[] = array($prefix . 'Default', $container);
// Set the default_backend so the mysql service should be used.
$container = clone $container;
$container = $this->getMysqlContainer($service);
$container->setParameter('default_backend', 'mysql');
$data[] = array($prefix . 'ServiceClassMysql', $container);
$data[] = array($prefix . 'Mysql', $container);
// Configure a manual alias for the service, so ensure that it is not
// overridden by the default backend.
$container = clone $container;
$container->setDefinition('mariadb.service', new Definition($prefix . 'ServiceClassMariaDb'));
$container->setDefinition('mariadb.service', new Definition($prefix . 'MariaDb'));
$container->setAlias('service', new Alias('mariadb.service'));
$data[] = array($prefix . 'ServiceClassMariaDb', $container);
$data[] = array($prefix . 'MariaDb', $container);
// Check the database driver is the default.
$container = $this->getSqliteContainer($service);
$data[] = array($prefix . 'Sqlite', $container);
// Test the opt out.
$container = $this->getSqliteContainer($service);
$container->setParameter('default_backend', '');
$data[] = array($prefix . 'Default', $container);
return $data;
}
/**
* Creates a container with a sqlite database service in it.
*
* This is necessary because the container clone does not clone the parameter
* bag so the setParameter() call effects the parent container as well.
*
* @param $service
* @return ContainerBuilder
*/
protected function getSqliteContainer($service) {
$container = new ContainerBuilder();
$container->setDefinition('service', $service);
$container->setDefinition('sqlite.service', new Definition(__NAMESPACE__ . '\\ServiceClassSqlite'));
$mock = $this->getMockBuilder('Drupal\Core\Database\Driver\sqlite\Connection')->setMethods(NULL)->disableOriginalConstructor()->getMock();
$container->set('database', $mock);
return $container;
}
/**
* Creates a container with a mysql database service definition in it.
*
* This is necessary because the container clone does not clone the parameter
* bag so the setParameter() call effects the parent container as well.
*
* @param $service
* @return ContainerBuilder
*/
protected function getMysqlContainer($service) {
$container = new ContainerBuilder();
$container->setDefinition('service', $service);
$container->setDefinition('mysql.service', new Definition(__NAMESPACE__ . '\\ServiceClassMysql'));
return $container;
}
}
class ServiceClassDefault {
@ -91,3 +134,6 @@ class ServiceClassMysql extends ServiceClassDefault {
class ServiceClassMariaDb extends ServiceClassMysql {
}
class ServiceClassSqlite extends ServiceClassDefault {
}

View file

@ -0,0 +1,85 @@
<?php
/**
* @file
* Contains
* \Drupal\Tests\Core\DependencyInjection\Compiler\ProxyServicesPassTest.
*/
namespace Drupal\Tests\Core\DependencyInjection\Compiler;
use Drupal\Core\DependencyInjection\Compiler\ProxyServicesPass;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\Reference;
/**
* @coversDefaultClass \Drupal\Core\DependencyInjection\Compiler\ProxyServicesPass
* @group DependencyInjection
*/
class ProxyServicesPassTest extends UnitTestCase {
/**
* The tested proxy services pass.
*
* @var \Drupal\Core\DependencyInjection\Compiler\ProxyServicesPass
*/
protected $proxyServicesPass;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->proxyServicesPass = new ProxyServicesPass();
}
/**
* @covers ::process
*/
public function testContainerWithoutLazyServices() {
$container = new ContainerBuilder();
$container->register('plugin_cache_clearer', 'Drupal\Core\Plugin\CachedDiscoveryClearer');
$this->proxyServicesPass->process($container);
$this->assertCount(1, $container->getDefinitions());
$this->assertEquals('Drupal\Core\Plugin\CachedDiscoveryClearer', $container->getDefinition('plugin_cache_clearer')->getClass());
}
/**
* @covers ::process
*/
public function testContainerWithLazyServices() {
$container = new ContainerBuilder();
$container->register('plugin_cache_clearer', 'Drupal\Core\Plugin\CachedDiscoveryClearer')
->setLazy(TRUE);
$this->proxyServicesPass->process($container);
$this->assertCount(2, $container->getDefinitions());
$non_proxy_definition = $container->getDefinition('drupal.proxy_original_service.plugin_cache_clearer');
$this->assertEquals('Drupal\Core\Plugin\CachedDiscoveryClearer', $non_proxy_definition->getClass());
$this->assertFalse($non_proxy_definition->isLazy());
$this->assertTrue($non_proxy_definition->isPublic());
$this->assertEquals('Drupal\Core\ProxyClass\Plugin\CachedDiscoveryClearer', $container->getDefinition('plugin_cache_clearer')->getClass());
}
/**
* @covers ::process
*
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
*/
public function testContainerWithLazyServicesWithoutProxyClass() {
$container = new ContainerBuilder();
$container->register('alias_whitelist', 'Drupal\Core\Path\AliasWhitelist')
->setLazy(TRUE);
$this->proxyServicesPass->process($container);
}
}

View file

@ -9,6 +9,7 @@ namespace Drupal\Tests\Core\Entity;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Tests\UnitTestCase;
@ -349,6 +350,64 @@ class ContentEntityBaseUnitTest extends UnitTestCase {
$this->assertSame(1, count($this->entity->validate()));
}
/**
* Tests required validation.
*
* @covers ::validate
* @covers ::isValidationRequired
* @covers ::setValidationRequired
* @covers ::save
* @covers ::preSave
*
* @expectedException \LogicException
* @expectedExceptionMessage Entity validation was skipped.
*/
public function testRequiredValidation() {
$validator = $this->getMock('\Symfony\Component\Validator\ValidatorInterface');
/** @var \Symfony\Component\Validator\ConstraintViolationList|\PHPUnit_Framework_MockObject_MockObject $empty_violation_list */
$empty_violation_list = $this->getMockBuilder('\Symfony\Component\Validator\ConstraintViolationList')
->setMethods(NULL)
->getMock();
$validator->expects($this->at(0))
->method('validate')
->with($this->entity->getTypedData())
->will($this->returnValue($empty_violation_list));
$this->typedDataManager->expects($this->any())
->method('getValidator')
->will($this->returnValue($validator));
/** @var \Drupal\Core\Entity\EntityStorageInterface|\PHPUnit_Framework_MockObject_MockObject $storage */
$storage = $this->getMock('\Drupal\Core\Entity\EntityStorageInterface');
$storage->expects($this->any())
->method('save')
->willReturnCallback(function (ContentEntityInterface $entity) use ($storage) {
$entity->preSave($storage);
});
$this->entityManager->expects($this->any())
->method('getStorage')
->with($this->entityTypeId)
->will($this->returnValue($storage));
// Check that entities can be saved normally when validation is not
// required.
$this->assertFalse($this->entity->isValidationRequired());
$this->entity->save();
// Make validation required and check that if the entity is validated, it
// can be saved normally.
$this->entity->setValidationRequired(TRUE);
$this->assertTrue($this->entity->isValidationRequired());
$this->entity->validate();
$this->entity->save();
// Check that the "validated" status is reset after saving the entity and
// that trying to save a non-validated entity when validation is required
// results in an exception.
$this->assertTrue($this->entity->isValidationRequired());
$this->entity->save();
}
/**
* @covers ::bundle
*/

View file

@ -265,6 +265,25 @@ class EntityManagerTest extends UnitTestCase {
$this->entityManager->clearCachedDefinitions();
}
/**
* Tests the processDefinition() method.
*
* @covers ::processDefinition
*
* @expectedException \Drupal\Core\Entity\Exception\InvalidLinkTemplateException
* @expectedExceptionMessage Link template 'canonical' for entity type 'apple' must start with a leading slash, the current link template is 'path/to/apple'
*/
public function testProcessDefinition() {
$apple = $this->getMock('Drupal\Core\Entity\EntityTypeInterface');
$apple->expects($this->once())
->method('getLinkTemplates')
->willReturn(['canonical' => 'path/to/apple']);
$this->setUpEntityManager(array('apple' => $apple));
$this->entityManager->processDefinition($apple, 'apple');
}
/**
* Tests the getDefinition() method.
*

View file

@ -8,6 +8,7 @@
namespace Drupal\Tests\Core\Entity;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\Cache;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Entity\Entity;
use Drupal\Core\Entity\Exception\NoCorrespondingEntityClassException;
@ -486,4 +487,62 @@ class EntityUnitTest extends UnitTestCase {
public function testReferencedEntities() {
$this->assertSame(array(), $this->entity->referencedEntities());
}
/**
* @covers ::getCacheTags
* @covers ::getCacheTagsToInvalidate
* @covers ::addCacheTags
*/
public function testCacheTags() {
// Ensure that both methods return the same by default.
$this->assertEquals([$this->entityTypeId . ':' . 1], $this->entity->getCacheTags());
$this->assertEquals([$this->entityTypeId . ':' . 1], $this->entity->getCacheTagsToInvalidate());
// Add an additional cache tag and make sure only getCacheTags() returns
// that.
$this->entity->addCacheTags(['additional_cache_tag']);
// EntityTypeId is random so it can shift order. We need to duplicate the
// sort from \Drupal\Core\Cache\Cache::mergeTags().
$tags = ['additional_cache_tag', $this->entityTypeId . ':' . 1];
sort($tags);
$this->assertEquals($tags, $this->entity->getCacheTags());
$this->assertEquals([$this->entityTypeId . ':' . 1], $this->entity->getCacheTagsToInvalidate());
}
/**
* @covers ::getCacheContexts
* @covers ::addCacheContexts
*/
public function testCacheContexts() {
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
->disableOriginalConstructor()
->getMock();
$container = new ContainerBuilder();
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
// There are no cache contexts by default.
$this->assertEquals([], $this->entity->getCacheContexts());
// Add an additional cache context.
$this->entity->addCacheContexts(['user']);
$this->assertEquals(['user'], $this->entity->getCacheContexts());
}
/**
* @covers ::getCacheMaxAge
* @covers ::mergeCacheMaxAge
*/
public function testCacheMaxAge() {
// Cache max age is permanent by default.
$this->assertEquals(Cache::PERMANENT, $this->entity->getCacheMaxAge());
// Set two cache max ages, the lower value is the one that needs to be
// returned.
$this->entity->mergeCacheMaxAge(600);
$this->entity->mergeCacheMaxAge(1800);
$this->assertEquals(600, $this->entity->getCacheMaxAge());
}
}

View file

@ -110,7 +110,7 @@ class EntityUrlTest extends UnitTestCase {
* @covers ::urlInfo
*
* @expectedException \Drupal\Core\Entity\Exception\UndefinedLinkTemplateException
* @expectedExceptionMessage No link template "canonical" found for the "test_entity_type" entity type
* @expectedExceptionMessage No link template 'canonical' found for the 'test_entity_type' entity type
*
* @dataProvider providerTestUrlInfoForInvalidLinkTemplate
*/

View file

@ -466,7 +466,7 @@ class KeyValueEntityStorageTest extends UnitTestCase {
* @covers ::doSave
*
* @expectedException \Drupal\Core\Entity\EntityStorageException
* @expectedExceptionMessage test_entity_type entity with ID foo already exists
* @expectedExceptionMessage 'test_entity_type' entity with ID 'foo' already exists
*/
public function testSaveDuplicate() {
$this->setUpKeyValueEntityStorage();

View file

@ -291,7 +291,7 @@ class DefaultTableMappingTest extends UnitTestCase {
* The name of the column to be processed.
*
* @expectedException \Drupal\Core\Entity\Sql\SqlContentEntityStorageException
* @expectedExceptionMessage Column information not available for the "test" field.
* @expectedExceptionMessage Column information not available for the 'test' field.
*
* @covers ::getFieldColumnName
*
@ -437,7 +437,7 @@ class DefaultTableMappingTest extends UnitTestCase {
* Tests DefaultTableMapping::getFieldTableName() with an invalid parameter.
*
* @expectedException \Drupal\Core\Entity\Sql\SqlContentEntityStorageException
* @expectedExceptionMessage Table information not available for the "invalid_field_name" field.
* @expectedExceptionMessage Table information not available for the 'invalid_field_name' field.
*
* @covers ::getFieldTableName
*/

View file

@ -502,6 +502,15 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
),
));
$this->setUpStorageDefinition('default_langcode', array(
'columns' => array(
'value' => array(
'type' => 'int',
'size' => 'tiny',
),
),
));
$expected = array(
'entity_test' => array(
'description' => 'The base table for entity_test entities.',
@ -531,10 +540,21 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
'type' => 'varchar',
'not null' => TRUE,
),
'default_langcode' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
),
),
'primary key' => array('id', 'langcode'),
'unique keys' => array(),
'indexes' => array(),
'indexes' => array(
'entity_test__id__default_langcode__langcode' => array(
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
),
),
'foreign keys' => array(
'entity_test' => array(
'table' => 'entity_test',
@ -547,7 +567,9 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
$this->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$non_data_fields = array_keys($this->storageDefinitions);
unset($non_data_fields[array_search('default_langcode', $non_data_fields)]);
$table_mapping->setFieldNames('entity_test', $non_data_fields);
$table_mapping->setFieldNames('entity_test_field_data', array_keys($this->storageDefinitions));
$this->storage->expects($this->any())
@ -604,6 +626,14 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
),
),
));
$this->setUpStorageDefinition('default_langcode', array(
'columns' => array(
'value' => array(
'type' => 'int',
'size' => 'tiny',
),
),
));
$expected = array(
'entity_test' => array(
@ -677,11 +707,21 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
'type' => 'varchar',
'not null' => TRUE,
),
'default_langcode' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
),
),
'primary key' => array('id', 'langcode'),
'unique keys' => array(),
'indexes' => array(
'entity_test__revision_id' => array('revision_id'),
'entity_test__id__default_langcode__langcode' => array(
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
),
),
'foreign keys' => array(
'entity_test' => array(
@ -705,10 +745,21 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
'type' => 'varchar',
'not null' => TRUE,
),
'default_langcode' => array(
'type' => 'int',
'size' => 'tiny',
'not null' => true,
),
),
'primary key' => array('revision_id', 'langcode'),
'unique keys' => array(),
'indexes' => array(),
'indexes' => array(
'entity_test__id__default_langcode__langcode' => array(
0 => 'id',
1 => 'default_langcode',
2 => 'langcode',
),
),
'foreign keys' => array(
'entity_test' => array(
'table' => 'entity_test',
@ -725,8 +776,10 @@ class SqlContentEntityStorageSchemaTest extends UnitTestCase {
$this->setUpStorageSchema($expected);
$table_mapping = new DefaultTableMapping($this->entityType, $this->storageDefinitions);
$table_mapping->setFieldNames('entity_test', array_keys($this->storageDefinitions));
$table_mapping->setFieldNames('entity_test_revision', array_keys($this->storageDefinitions));
$non_data_fields = array_keys($this->storageDefinitions);
unset($non_data_fields[array_search('default_langcode', $non_data_fields)]);
$table_mapping->setFieldNames('entity_test', $non_data_fields);
$table_mapping->setFieldNames('entity_test_revision', $non_data_fields);
$table_mapping->setFieldNames('entity_test_field_data', array_keys($this->storageDefinitions));
$table_mapping->setFieldNames('entity_test_revision_field_data', array_keys($this->storageDefinitions));

View file

@ -1130,8 +1130,10 @@ class SqlContentEntityStorageTest extends UnitTestCase {
$entity_storage = $this->getMockBuilder('Drupal\Core\Entity\Sql\SqlContentEntityStorage')
->setConstructorArgs(array($this->entityType, $this->connection, $this->entityManager, $this->cache, $this->languageManager))
->setMethods(array('getFromStorage'))
->setMethods(array('getFromStorage', 'invokeStorageLoadHook'))
->getMock();
$entity_storage->method('invokeStorageLoadHook')
->willReturn(NULL);
$entity_storage->expects($this->once())
->method('getFromStorage')
->with(array($id))
@ -1180,8 +1182,10 @@ class SqlContentEntityStorageTest extends UnitTestCase {
$entity_storage = $this->getMockBuilder('Drupal\Core\Entity\Sql\SqlContentEntityStorage')
->setConstructorArgs(array($this->entityType, $this->connection, $this->entityManager, $this->cache, $this->languageManager))
->setMethods(array('getFromStorage'))
->setMethods(array('getFromStorage', 'invokeStorageLoadHook'))
->getMock();
$entity_storage->method('invokeStorageLoadHook')
->willReturn(NULL);
$entity_storage->expects($this->once())
->method('getFromStorage')
->with(array($id))

View file

@ -0,0 +1,99 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\EventSubscriber\PsrResponseSubscriberTest.
*/
namespace Drupal\Tests\Core\EventSubscriber;
use Drupal\Tests\UnitTestCase;
use \Drupal\Core\EventSubscriber\PsrResponseSubscriber;
/**
* @coversDefaultClass \Drupal\Core\EventSubscriber\PsrResponseSubscriber
* @group EventSubscriber
*/
class PsrResponseSubscriberTest extends UnitTestCase {
/**
* The tested path root subscriber.
*
* @var \Drupal\Core\EventSubscriber\PsrResponseSubscriber
*/
protected $psrResponseSubscriber;
/**
* The tested path root subscriber.
*
* @var \Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $httpFoundationFactoryMock;
/**
* {@inheritdoc}
*/
public function setUp() {
$factory = $this->getMock('Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface', [], [], '', NULL);
$factory
->expects($this->any())
->method('createResponse')
->willReturn($this->getMock('Symfony\Component\HttpFoundation\Response'));
$this->httpFoundationFactoryMock = $factory;
$this->psrResponseSubscriber = new PsrResponseSubscriber($this->httpFoundationFactoryMock);
}
/**
* Tests altering and finished event.
*
* @covers ::onKernelView
*/
public function testConvertsControllerResult() {
$event = $this->createEventMock($this->getMock('Psr\Http\Message\ResponseInterface'));
$event
->expects($this->once())
->method('setResponse')
->with($this->isInstanceOf('Symfony\Component\HttpFoundation\Response'));
$this->psrResponseSubscriber->onKernelView($event);
}
/**
* Tests altering and finished event.
*
* @covers ::onKernelView
*/
public function testDoesNotConvertControllerResult() {
$event = $this->createEventMock([]);
$event
->expects($this->never())
->method('setResponse');
$this->psrResponseSubscriber->onKernelView($event);
$event = $this->createEventMock(NULL);
$event
->expects($this->never())
->method('setResponse');
$this->psrResponseSubscriber->onKernelView($event);
}
/**
* Sets up an alias event that return $controllerResult.
*
* @param mixed $controller_result
* The return Object.
*
* @return \Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent|\PHPUnit_Framework_MockObject_MockObject
* A mock object to test.
*/
protected function createEventMock($controller_result) {
$event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent', [], [], '', NULL);
$event
->expects($this->once())
->method('getControllerResult')
->willReturn($controller_result);
return $event;
}
}

View file

@ -9,7 +9,9 @@ namespace Drupal\Tests\Core\EventSubscriber;
use Drupal\Core\EventSubscriber\RedirectResponseSubscriber;
use Drupal\Core\Routing\RequestContext;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
@ -24,6 +26,31 @@ use Symfony\Component\HttpKernel\KernelEvents;
*/
class RedirectResponseSubscriberTest extends UnitTestCase {
/**
* The mocked request context.
*
* @var \Drupal\Core\Routing\RequestContext|\PHPUnit_Framework_MockObject_MockObject
*/
protected $requestContext;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->requestContext = $this->getMockBuilder('Drupal\Core\Routing\RequestContext')
->disableOriginalConstructor()
->getMock();
$this->requestContext->expects($this->any())
->method('getCompleteBaseUrl')
->willReturn('http://example.com/drupal');
$container = new Container();
$container->set('router.request_context', $this->requestContext);
\Drupal::setContainer($container);
}
/**
* Test destination detection and redirection.
*
@ -57,15 +84,9 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
]);
}
$request_context = $this->getMockBuilder('Drupal\Core\Routing\RequestContext')
->disableOriginalConstructor()
->getMock();
$request_context->expects($this->any())
->method('getCompleteBaseUrl')
->willReturn('http://example.com/drupal');
$request->headers->set('HOST', 'example.com');
$listener = new RedirectResponseSubscriber($url_generator, $request_context);
$listener = new RedirectResponseSubscriber($url_generator, $this->requestContext);
$dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
$event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
$dispatcher->dispatch(KernelEvents::RESPONSE, $event);
@ -87,12 +108,9 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
public static function providerTestDestinationRedirect() {
return array(
array(new Request(), FALSE),
array(new Request(array('destination' => 'http://example.com')), FALSE),
array(new Request(array('destination' => 'http://example.com/foobar')), FALSE),
array(new Request(array('destination' => 'http://example.ca/drupal')), FALSE),
array(new Request(array('destination' => 'test')), 'http://example.com/drupal/test'),
array(new Request(array('destination' => '/test')), 'http://example.com/test'),
array(new Request(array('destination' => '/example.com')), 'http://example.com/example.com'),
array(new Request(array('destination' => '/drupal/test')), 'http://example.com/drupal/test'),
array(new Request(array('destination' => 'example.com')), 'http://example.com/drupal/example.com'),
array(new Request(array('destination' => 'example:com')), 'http://example.com/drupal/example:com'),
array(new Request(array('destination' => 'javascript:alert(0)')), 'http://example.com/drupal/javascript:alert(0)'),
array(new Request(array('destination' => 'http://example.com/drupal/')), 'http://example.com/drupal/'),
@ -101,7 +119,94 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
}
/**
* @expectedException \InvalidArgumentException
* @dataProvider providerTestDestinationRedirectToExternalUrl
*
* @expectedException \PHPUnit_Framework_Error
*/
public function testDestinationRedirectToExternalUrl($request, $expected) {
$dispatcher = new EventDispatcher();
$kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
$response = new RedirectResponse('http://other-example.com');
$url_generator = $this->getMockBuilder('Drupal\Core\Routing\UrlGenerator')
->disableOriginalConstructor()
->setMethods(array('generateFromPath'))
->getMock();
$request_context = $this->getMockBuilder('Drupal\Core\Routing\RequestContext')
->disableOriginalConstructor()
->getMock();
$request_context->expects($this->any())
->method('getCompleteBaseUrl')
->willReturn('http://example.com/drupal');
if ($expected) {
$url_generator
->expects($this->any())
->method('generateFromPath')
->willReturnMap([
['test', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/test'],
['example.com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/example.com'],
['example:com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/example:com'],
['javascript:alert(0)', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/javascript:alert(0)'],
['/test', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/test'],
]);
}
$listener = new RedirectResponseSubscriber($url_generator, $request_context);
$dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
$event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
$dispatcher->dispatch(KernelEvents::RESPONSE, $event);
$this->assertEquals(400, $event->getResponse()->getStatusCode());
}
/**
* @covers ::checkRedirectUrl
*/
public function testRedirectWithOptInExternalUrl() {
$dispatcher = new EventDispatcher();
$kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
$response = new TrustedRedirectResponse('http://external-url.com');
$url_generator = $this->getMockBuilder('Drupal\Core\Routing\UrlGenerator')
->disableOriginalConstructor()
->setMethods(array('generateFromPath'))
->getMock();
$request_context = $this->getMockBuilder('Drupal\Core\Routing\RequestContext')
->disableOriginalConstructor()
->getMock();
$request_context->expects($this->any())
->method('getCompleteBaseUrl')
->willReturn('http://example.com/drupal');
$request = Request::create('');
$request->headers->set('HOST', 'example.com');
$listener = new RedirectResponseSubscriber($url_generator, $request_context);
$dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
$event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
$dispatcher->dispatch(KernelEvents::RESPONSE, $event);
$target_url = $event->getResponse()->getTargetUrl();
$this->assertEquals('http://external-url.com', $target_url);
}
/**
* Data provider for testDestinationRedirectToExternalUrl().
*/
public function providerTestDestinationRedirectToExternalUrl() {
return [
'absolute external url' => [new Request(['destination' => 'http://example.com']), 'http://example.com'],
'absolute external url with folder' => [new Request(['destination' => 'http://example.com/foobar']), 'http://example.com/foobar'],
'absolute external url with folder2' => [new Request(['destination' => 'http://example.ca/drupal']), 'http://example.ca/drupal'],
'path without drupal basepath' => [new Request(['destination' => '/test']), 'http://example.com/test'],
'path with URL' => [new Request(['destination' => '/example.com']), 'http://example.com/example.com'],
'path with URL and two slashes' => [new Request(['destination' => '//example.com']), 'http://example.com//example.com'],
];
}
/**
* @expectedException \PHPUnit_Framework_Error
*
* @dataProvider providerTestDestinationRedirectWithInvalidUrl
*/
@ -119,6 +224,8 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
$dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
$event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
$dispatcher->dispatch(KernelEvents::RESPONSE, $event);
$this->assertEquals(400, $event->getResponse()->getStatusCode());
}
/**
@ -128,6 +235,11 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
$data = [];
$data[] = [new Request(array('destination' => '//example:com'))];
$data[] = [new Request(array('destination' => '//example:com/test'))];
$data['absolute external url'] = [new Request(['destination' => 'http://example.com'])];
$data['absolute external url with folder'] = [new Request(['destination' => 'http://example.ca/drupal'])];
$data['path without drupal basepath'] = [new Request(['destination' => '/test'])];
$data['path with URL'] = [new Request(['destination' => '/example.com'])];
$data['path with URL and two slashes'] = [new Request(['destination' => '//example.com'])];
return $data;
}

View file

@ -9,6 +9,7 @@ namespace Drupal\Tests\Core\File;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\File\MimeType\MimeTypeGuesser;
use Drupal\Core\StreamWrapper\StreamWrapperManager;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\File\MimeType\MimeTypeGuesser as SymfonyMimeTypeGuesser;
@ -34,10 +35,23 @@ class MimeTypeGuesserTest extends UnitTestCase {
$this->assertNotInstanceOf('Drupal\Core\File\MimeType\MimeTypeGuesser', $guessers[0]);
}
$container = new ContainerBuilder();
$container->set('file.mime_type.guesser', new MimeTypeGuesser());
$container->set('file.mime_type.guesser', new MimeTypeGuesser(new StreamWrapperManager()));
MimeTypeGuesser::registerWithSymfonyGuesser($container);
$symfony_guesser = SymfonyMimeTypeGuesser::getInstance();
$guessers = $this->readAttribute($symfony_guesser, 'guessers');
$this->assertSame($container->get('file.mime_type.guesser'), $guessers[0]);
$this->assertInstanceOf('Drupal\Core\File\MimeType\MimeTypeGuesser', $guessers[0]);
$count = count($guessers);
$container = new ContainerBuilder();
$container->set('file.mime_type.guesser', new MimeTypeGuesser(new StreamWrapperManager()));
MimeTypeGuesser::registerWithSymfonyGuesser($container);
$symfony_guesser = SymfonyMimeTypeGuesser::getInstance();
$guessers = $this->readAttribute($symfony_guesser, 'guessers');
$this->assertSame($container->get('file.mime_type.guesser'), $guessers[0]);
$this->assertInstanceOf('Drupal\Core\File\MimeType\MimeTypeGuesser', $guessers[0]);
$new_count = count($guessers);
$this->assertEquals($count, $new_count, 'The count of mime type guessers remains the same after container re-init.');
}
}

View file

@ -7,6 +7,9 @@
namespace Drupal\Tests\Core\Form;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultForbidden;
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
use Drupal\Core\Form\EnforcedResponseException;
use Drupal\Core\Form\FormBuilderInterface;
@ -280,7 +283,7 @@ class FormBuilderTest extends FormTestBase {
}
/**
* Tests the rebuildForm() method.
* Tests the rebuildForm() method for a POST submission.
*/
public function testRebuildForm() {
$form_id = 'test_form_id';
@ -300,6 +303,9 @@ class FormBuilderTest extends FormTestBase {
$form = $this->formBuilder->buildForm($form_arg, $form_state);
$original_build_id = $form['#build_id'];
$this->request->setMethod('POST');
$form_state->setRequestMethod('POST');
// Rebuild the form, and assert that the build ID has not changed.
$form_state->setRebuild();
$input['form_id'] = $form_id;
@ -307,11 +313,51 @@ class FormBuilderTest extends FormTestBase {
$form_state->addRebuildInfo('copy', ['#build_id' => TRUE]);
$this->formBuilder->processForm($form_id, $form, $form_state);
$this->assertSame($original_build_id, $form['#build_id']);
$this->assertTrue($form_state->isCached());
// Rebuild the form again, and assert that there is a new build ID.
$form_state->setRebuildInfo([]);
$form = $this->formBuilder->buildForm($form_arg, $form_state);
$this->assertNotSame($original_build_id, $form['#build_id']);
$this->assertTrue($form_state->isCached());
}
/**
* Tests the rebuildForm() method for a GET submission.
*/
public function testRebuildFormOnGetRequest() {
$form_id = 'test_form_id';
$expected_form = $form_id();
// The form will be built four times.
$form_arg = $this->getMock('Drupal\Core\Form\FormInterface');
$form_arg->expects($this->exactly(2))
->method('getFormId')
->will($this->returnValue($form_id));
$form_arg->expects($this->exactly(4))
->method('buildForm')
->will($this->returnValue($expected_form));
// Do an initial build of the form and track the build ID.
$form_state = new FormState();
$form_state->setMethod('GET');
$form = $this->formBuilder->buildForm($form_arg, $form_state);
$original_build_id = $form['#build_id'];
// Rebuild the form, and assert that the build ID has not changed.
$form_state->setRebuild();
$input['form_id'] = $form_id;
$form_state->setUserInput($input);
$form_state->addRebuildInfo('copy', ['#build_id' => TRUE]);
$this->formBuilder->processForm($form_id, $form, $form_state);
$this->assertSame($original_build_id, $form['#build_id']);
$this->assertFalse($form_state->isCached());
// Rebuild the form again, and assert that there is a new build ID.
$form_state->setRebuildInfo([]);
$form = $this->formBuilder->buildForm($form_arg, $form_state);
$this->assertNotSame($original_build_id, $form['#build_id']);
$this->assertFalse($form_state->isCached());
}
/**
@ -335,6 +381,7 @@ class FormBuilderTest extends FormTestBase {
// Do an initial build of the form and track the build ID.
$form_state = (new FormState())
->addBuildInfo('files', [['module' => 'node', 'type' => 'pages.inc']])
->setRequestMethod('POST')
->setCached();
$form = $this->formBuilder->buildForm($form_arg, $form_state);
@ -404,6 +451,7 @@ class FormBuilderTest extends FormTestBase {
->with($form_build_id);
$form_state = new FormState();
$form_state->setRequestMethod('POST');
$form_state->setCached();
$this->simulateFormSubmission($form_id, $form_arg, $form_state);
}
@ -449,6 +497,171 @@ class FormBuilderTest extends FormTestBase {
$this->formBuilder->buildForm($form_arg, $form_state);
}
/**
* @covers ::buildForm
*
* @dataProvider providerTestChildAccessInheritance
*/
public function testChildAccessInheritance($element, $access_checks) {
$form_arg = new TestFormWithPredefinedForm();
$form_arg->setForm($element);
$form_state = new FormState();
$form = $this->formBuilder->buildForm($form_arg, $form_state);
$actual_access_structure = [];
$expected_access_structure = [];
// Ensure that the expected access checks are set.
foreach ($access_checks as $access_check) {
$parents = $access_check[0];
$parents[] = '#access';
$actual_access = NestedArray::getValue($form, $parents);
$actual_access_structure[] = [$parents, $actual_access];
$expected_access_structure[] = [$parents, $access_check[1]];
}
$this->assertEquals($expected_access_structure, $actual_access_structure);
}
/**
* Data provider for testChildAccessInheritance.
*
* @return array
*/
public function providerTestChildAccessInheritance() {
$data = [];
$element = [
'child0' => [
'#type' => 'checkbox',
],
'child1' => [
'#type' => 'checkbox',
],
'child2' => [
'#type' => 'fieldset',
'child2.0' => [
'#type' => 'checkbox',
],
'child2.1' => [
'#type' => 'checkbox',
],
'child2.2' => [
'#type' => 'checkbox',
],
],
];
// Sets access FALSE on the root level, this should be inherited completely.
$clone = $element;
$clone['#access'] = FALSE;
$expected_access = [];
$expected_access[] = [[], FALSE];
$expected_access[] = [['child0'], FALSE];
$expected_access[] = [['child1'], FALSE];
$expected_access[] = [['child2'], FALSE];
$expected_access[] = [['child2', 'child2.0'], FALSE];
$expected_access[] = [['child2', 'child2.1'], FALSE];
$expected_access[] = [['child2', 'child2.2'], FALSE];
$data['access-false-root'] = [$clone, $expected_access];
$clone = $element;
$access_result = AccessResult::forbidden()->addCacheContexts(['user']);
$clone['#access'] = $access_result;
$expected_access = [];
$expected_access[] = [[], $access_result];
$expected_access[] = [['child0'], $access_result];
$expected_access[] = [['child1'], $access_result];
$expected_access[] = [['child2'], $access_result];
$expected_access[] = [['child2', 'child2.0'], $access_result];
$expected_access[] = [['child2', 'child2.1'], $access_result];
$expected_access[] = [['child2', 'child2.2'], $access_result];
$data['access-forbidden-root'] = [$clone, $expected_access];
// Allow access on the most outer level but set FALSE otherwise.
$clone = $element;
$clone['#access'] = TRUE;
$clone['child0']['#access'] = FALSE;
$expected_access = [];
$expected_access[] = [[], TRUE];
$expected_access[] = [['child0'], FALSE];
$expected_access[] = [['child1'], NULL];
$expected_access[] = [['child2'], NULL];
$expected_access[] = [['child2', 'child2.0'], NULL];
$expected_access[] = [['child2', 'child2.1'], NULL];
$expected_access[] = [['child2', 'child2.2'], NULL];
$data['access-true-root'] = [$clone, $expected_access];
// Allow access on the most outer level but forbid otherwise.
$clone = $element;
$access_result_allowed = AccessResult::allowed()
->addCacheContexts(['user']);
$clone['#access'] = $access_result_allowed;
$access_result_forbidden = AccessResult::forbidden()
->addCacheContexts(['user']);
$clone['child0']['#access'] = $access_result_forbidden;
$expected_access = [];
$expected_access[] = [[], $access_result_allowed];
$expected_access[] = [['child0'], $access_result_forbidden];
$expected_access[] = [['child1'], NULL];
$expected_access[] = [['child2'], NULL];
$expected_access[] = [['child2', 'child2.0'], NULL];
$expected_access[] = [['child2', 'child2.1'], NULL];
$expected_access[] = [['child2', 'child2.2'], NULL];
$data['access-allowed-root'] = [$clone, $expected_access];
// Allow access on the most outer level, deny access on a parent, and allow
// on a child. The denying should be inherited.
$clone = $element;
$clone['#access'] = TRUE;
$clone['child2']['#access'] = FALSE;
$clone['child2.0']['#access'] = TRUE;
$clone['child2.1']['#access'] = TRUE;
$clone['child2.2']['#access'] = TRUE;
$expected_access = [];
$expected_access[] = [[], TRUE];
$expected_access[] = [['child0'], NULL];
$expected_access[] = [['child1'], NULL];
$expected_access[] = [['child2'], FALSE];
$expected_access[] = [['child2', 'child2.0'], FALSE];
$expected_access[] = [['child2', 'child2.1'], FALSE];
$expected_access[] = [['child2', 'child2.2'], FALSE];
$data['access-mixed-parents'] = [$clone, $expected_access];
$clone = $element;
$clone['#access'] = $access_result_allowed;
$clone['child2']['#access'] = $access_result_forbidden;
$clone['child2.0']['#access'] = $access_result_allowed;
$clone['child2.1']['#access'] = $access_result_allowed;
$clone['child2.2']['#access'] = $access_result_allowed;
$expected_access = [];
$expected_access[] = [[], $access_result_allowed];
$expected_access[] = [['child0'], NULL];
$expected_access[] = [['child1'], NULL];
$expected_access[] = [['child2'], $access_result_forbidden];
$expected_access[] = [['child2', 'child2.0'], $access_result_forbidden];
$expected_access[] = [['child2', 'child2.1'], $access_result_forbidden];
$expected_access[] = [['child2', 'child2.2'], $access_result_forbidden];
$data['access-mixed-parents-object'] = [$clone, $expected_access];
return $data;
}
}
class TestForm implements FormInterface {
@ -467,3 +680,21 @@ class TestFormInjected extends TestForm implements ContainerInjectionInterface {
return new static();
}
}
class TestFormWithPredefinedForm extends TestForm {
/**
* @var array
*/
protected $form;
public function setForm($form) {
$this->form = $form;
}
public function buildForm(array $form, FormStateInterface $form_state) {
return $this->form;
}
}

View file

@ -427,6 +427,8 @@ class FormCacheTest extends UnitTestCase {
* @covers ::setCache
*/
public function testSetCacheWithSafeStrings() {
// A call to SafeMarkup::set() is appropriate in this test as a way to add a
// string to the safe list in the simplest way possible. Normally, avoid it.
SafeMarkup::set('a_safe_string');
$form_build_id = 'the_form_build_id';
$form = [

View file

@ -422,6 +422,11 @@ class FormStateTest extends UnitTestCase {
'cache' => $cache_key,
'no_cache' => $no_cache_key,
]);
$form_state->setMethod('POST');
$this->assertSame($expected, $form_state->isCached());
$form_state->setMethod('GET');
$this->assertSame($expected, $form_state->isCached());
}
@ -463,6 +468,28 @@ class FormStateTest extends UnitTestCase {
return $data;
}
/**
* @covers ::setCached
*/
public function testSetCachedPost() {
$form_state = new FormState();
$form_state->setRequestMethod('POST');
$form_state->setCached();
$this->assertTrue($form_state->isCached());
}
/**
* @covers ::setCached
*
* @expectedException \LogicException
* @expectedExceptionMessage Form state caching on GET requests is not allowed.
*/
public function testSetCachedGet() {
$form_state = new FormState();
$form_state->setRequestMethod('GET');
$form_state->setCached();
}
/**
* @covers ::isMethodType
* @covers ::setMethod

View file

@ -0,0 +1,74 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Http\ClientFactoryTest.
*/
namespace Drupal\Tests\Core\Http;
use Drupal\Core\Http\ClientFactory;
use Drupal\Core\Site\Settings;
use Drupal\Tests\UnitTestCase;
/**
* @coversDefaultClass \Drupal\Core\Http\ClientFactory
* @group Http
*/
class ClientFactoryTest extends UnitTestCase {
/**
* The client factory under test.
*
* @var \Drupal\Core\Http\ClientFactory
*/
protected $factory;
/**
* {@inheritdoc}
*/
public function setUp() {
$stack = $this->getMockBuilder('GuzzleHttp\HandlerStack')
->disableOriginalConstructor()
->getMock();
$this->factory = new ClientFactory($stack);
}
/**
* @covers ::fromOptions
* @dataProvider providerTestCreateFromOptions
*
* @param array $settings_config
* @param array $parameter_config
* @param array $expected_config_keys
*/
public function testCreateFromOptions($settings_config, $parameter_config, $expected_config_keys) {
if ($settings_config) {
new Settings(['http_client_config' => $settings_config]);
}
else {
new Settings([]);
}
$client = $this->factory->fromOptions($parameter_config);
foreach ($expected_config_keys as $key => $expected) {
$this->assertSame($expected, $client->getConfig($key));
}
}
/**
* Data provider for testCreateFromOptions
*
* @return array
*/
public function providerTestCreateFromOptions() {
return [
[[], [], ['verify' => TRUE, 'timeout' => 30]],
[['timeout' => 40], [], ['verify' => TRUE, 'timeout' => 40]],
[[], ['timeout' => 50], ['verify' => TRUE, 'timeout' => 50]],
[['timeout' => 40], ['timeout' => 50], ['verify' => TRUE, 'timeout' => 50]],
];
}
}

View file

@ -8,6 +8,7 @@
namespace Drupal\Tests\Core\Menu;
use Drupal\Core\Menu\ContextualLinkDefault;
use Drupal\Core\StringTranslation\TranslationWrapper;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
@ -63,17 +64,18 @@ class ContextualLinkDefaultTest extends UnitTestCase {
protected function setupContextualLinkDefault() {
$this->contextualLinkDefault = new ContextualLinkDefault($this->config, $this->pluginId, $this->pluginDefinition);
$this->contextualLinkDefault->setStringTranslation($this->stringTranslation);
}
/**
* @covers ::getTitle
*/
public function testGetTitle($title = 'Example') {
$this->pluginDefinition['title'] = $title;
public function testGetTitle() {
$title = 'Example';
$this->pluginDefinition['title'] = (new TranslationWrapper($title))
->setStringTranslation($this->stringTranslation);
$this->stringTranslation->expects($this->once())
->method('translate')
->with($this->pluginDefinition['title'], array(), array())
->with($title, array(), array())
->will($this->returnValue('Example translated'));
$this->setupContextualLinkDefault();
@ -84,11 +86,12 @@ class ContextualLinkDefaultTest extends UnitTestCase {
* @covers ::getTitle
*/
public function testGetTitleWithContext() {
$this->pluginDefinition['title'] = 'Example';
$this->pluginDefinition['title_context'] = 'context';
$title = 'Example';
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context')))
->setStringTranslation($this->stringTranslation);
$this->stringTranslation->expects($this->once())
->method('translate')
->with($this->pluginDefinition['title'], array(), array('context' => $this->pluginDefinition['title_context']))
->with($title, array(), array('context' => 'context'))
->will($this->returnValue('Example translated with context'));
$this->setupContextualLinkDefault();
@ -99,11 +102,12 @@ class ContextualLinkDefaultTest extends UnitTestCase {
* @covers ::getTitle
*/
public function testGetTitleWithTitleArguments() {
$this->pluginDefinition['title'] = 'Example @test';
$this->pluginDefinition['title_arguments'] = array('@test' => 'value');
$title = 'Example @test';
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array('@test' => 'value')))
->setStringTranslation($this->stringTranslation);
$this->stringTranslation->expects($this->once())
->method('translate')
->with($this->pluginDefinition['title'], $this->arrayHasKey('@test'), array())
->with($title, array('@test' => 'value'), array())
->will($this->returnValue('Example value'));
$this->setupContextualLinkDefault();

View file

@ -8,6 +8,7 @@
namespace Drupal\Tests\Core\Menu;
use Drupal\Core\Menu\LocalActionDefault;
use Drupal\Core\StringTranslation\TranslationWrapper;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\ParameterBag;
use Symfony\Component\HttpFoundation\Request;
@ -74,7 +75,6 @@ class LocalActionDefaultTest extends UnitTestCase {
*/
protected function setupLocalActionDefault() {
$this->localActionDefault = new LocalActionDefault($this->config, $this->pluginId, $this->pluginDefinition, $this->routeProvider);
$this->localActionDefault->setStringTranslation($this->stringTranslation);
}
/**
@ -83,10 +83,11 @@ class LocalActionDefaultTest extends UnitTestCase {
* @see \Drupal\Core\Menu\LocalTaskDefault::getTitle()
*/
public function testGetTitle() {
$this->pluginDefinition['title'] = 'Example';
$this->pluginDefinition['title'] = (new TranslationWrapper('Example'))
->setStringTranslation($this->stringTranslation);
$this->stringTranslation->expects($this->once())
->method('translate')
->with($this->pluginDefinition['title'], array(), array())
->with('Example', array(), array())
->will($this->returnValue('Example translated'));
$this->setupLocalActionDefault();
@ -99,11 +100,11 @@ class LocalActionDefaultTest extends UnitTestCase {
* @see \Drupal\Core\Menu\LocalTaskDefault::getTitle()
*/
public function testGetTitleWithContext() {
$this->pluginDefinition['title'] = 'Example';
$this->pluginDefinition['title_context'] = 'context';
$this->pluginDefinition['title'] = (new TranslationWrapper('Example', array(), array('context' => 'context')))
->setStringTranslation($this->stringTranslation);
$this->stringTranslation->expects($this->once())
->method('translate')
->with($this->pluginDefinition['title'], array(), array('context' => 'context'))
->with('Example', array(), array('context' => 'context'))
->will($this->returnValue('Example translated with context'));
$this->setupLocalActionDefault();
@ -114,11 +115,11 @@ class LocalActionDefaultTest extends UnitTestCase {
* Tests the getTitle method with title arguments.
*/
public function testGetTitleWithTitleArguments() {
$this->pluginDefinition['title'] = 'Example @test';
$this->pluginDefinition['title_arguments'] = array('@test' => 'value');
$this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value')))
->setStringTranslation($this->stringTranslation);
$this->stringTranslation->expects($this->once())
->method('translate')
->with($this->pluginDefinition['title'], $this->arrayHasKey('@test'), array())
->with('Example @test', array('@test' => 'value'), array())
->will($this->returnValue('Example value'));
$this->setupLocalActionDefault();

View file

@ -10,8 +10,8 @@ namespace Drupal\Tests\Core\Menu;
use Drupal\Core\Menu\LocalTaskDefault;
use Drupal\Core\Routing\RouteMatch;
use Drupal\Core\Routing\RouteProviderInterface;
use Drupal\Core\StringTranslation\TranslationWrapper;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Route;
/**
@ -77,9 +77,7 @@ class LocalTaskDefaultTest extends UnitTestCase {
protected function setupLocalTaskDefault() {
$this->localTaskBase = new TestLocalTaskDefault($this->config, $this->pluginId, $this->pluginDefinition);
$this->localTaskBase
->setRouteProvider($this->routeProvider)
->setStringTranslation($this->stringTranslation);
->setRouteProvider($this->routeProvider);
}
/**
@ -234,11 +232,12 @@ class LocalTaskDefaultTest extends UnitTestCase {
/**
* @covers ::getTitle
*/
public function testGetTitleWithoutContext() {
$this->pluginDefinition['title'] = 'Example';
public function testGetTitle() {
$this->pluginDefinition['title'] = (new TranslationWrapper('Example'))
->setStringTranslation($this->stringTranslation);
$this->stringTranslation->expects($this->once())
->method('translate')
->with($this->pluginDefinition['title'], array(), array())
->with('Example', array(), array())
->will($this->returnValue('Example translated'));
$this->setupLocalTaskDefault();
@ -249,11 +248,12 @@ class LocalTaskDefaultTest extends UnitTestCase {
* @covers ::getTitle
*/
public function testGetTitleWithContext() {
$this->pluginDefinition['title'] = 'Example';
$this->pluginDefinition['title_context'] = 'context';
$title = 'Example';
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context')))
->setStringTranslation($this->stringTranslation);
$this->stringTranslation->expects($this->once())
->method('translate')
->with($this->pluginDefinition['title'], array(), array('context' => 'context'))
->with($title, array(), array('context' => 'context'))
->will($this->returnValue('Example translated with context'));
$this->setupLocalTaskDefault();
@ -264,16 +264,16 @@ class LocalTaskDefaultTest extends UnitTestCase {
* @covers ::getTitle
*/
public function testGetTitleWithTitleArguments() {
$this->pluginDefinition['title'] = 'Example @test';
$this->pluginDefinition['title_arguments'] = array('@test' => 'value');
$title = 'Example @test';
$this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value')))
->setStringTranslation($this->stringTranslation);
$this->stringTranslation->expects($this->once())
->method('translate')
->with($this->pluginDefinition['title'], $this->arrayHasKey('@test'), array())
->with($title, array('@test' => 'value'), array())
->will($this->returnValue('Example value'));
$this->setupLocalTaskDefault();
$request = new Request();
$this->assertEquals('Example value', $this->localTaskBase->getTitle($request));
$this->assertEquals('Example value', $this->localTaskBase->getTitle());
}
/**

View file

@ -8,8 +8,8 @@
namespace Drupal\Tests\Core\PathProcessor;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\PathProcessor\PathProcessorAlias;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
@ -70,11 +70,11 @@ class PathProcessorAliasTest extends UnitTestCase {
array('url', NULL, 'url'),
)));
$cacheable_metadata = new CacheableMetadata();
$this->assertEquals($expected_path, $this->pathProcessor->processOutbound($path, $options, NULL, $cacheable_metadata));
$bubbleable_metadata = new BubbleableMetadata();
$this->assertEquals($expected_path, $this->pathProcessor->processOutbound($path, $options, NULL, $bubbleable_metadata));
// Cacheability of paths replaced with path aliases is permanent.
// @todo https://www.drupal.org/node/2480077
$this->assertEquals((new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT), $cacheable_metadata);
$this->assertEquals((new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT), $bubbleable_metadata);
}
/**

View file

@ -7,8 +7,11 @@
namespace Drupal\Tests\Core\Plugin\Context;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\TypedData\TypedDataInterface;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\Container;
/**
* @coversDefaultClass \Drupal\Core\Plugin\Context\Context
@ -43,6 +46,91 @@ class ContextTest extends UnitTestCase {
public function setUp() {
parent::setUp();
$this->typedDataManager = $this->getMockBuilder('Drupal\Core\TypedData\TypedDataManager')
->disableOriginalConstructor()
->setMethods(array('create'))
->getMock();
}
/**
* @covers ::getContextValue
*/
public function testDefaultValue() {
$this->setUpDefaultValue();
$context = new Context($this->contextDefinition);
$context->setTypedDataManager($this->typedDataManager);
$this->assertEquals('test', $context->getContextValue());
}
/**
* @covers ::getContextData
*/
public function testDefaultDataValue() {
$this->setUpDefaultValue();
$context = new Context($this->contextDefinition);
$context->setTypedDataManager($this->typedDataManager);
$this->assertEquals($this->typedData, $context->getContextData());
}
/**
* @covers ::setContextValue
*/
public function testSetContextValueTypedData() {
$this->contextDefinition = $this->getMockBuilder('Drupal\Core\Plugin\Context\ContextDefinitionInterface')
->setMethods(array('getDefaultValue', 'getDataDefinition'))
->getMockForAbstractClass();
$context = new Context($this->contextDefinition);
$context->setTypedDataManager($this->typedDataManager);
$typed_data = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
$context->setContextValue($typed_data);
$this->assertSame($typed_data, $context->getContextData());
}
/**
* @covers ::setContextValue
*/
public function testSetContextValueCacheableDependency() {
$container = new Container();
$cache_context_manager = $this->getMockBuilder('Drupal\Core\Cache\CacheContextsManager')
->disableOriginalConstructor()
->getMock();
$container->set('cache_contexts_manager', $cache_context_manager);
$cache_context_manager->expects($this->any())
->method('validateTokens')
->with(['route'])
->willReturn(['route']);
\Drupal::setContainer($container);
$this->contextDefinition = $this->getMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
$context = new Context($this->contextDefinition);
$context->setTypedDataManager($this->typedDataManager);
$cacheable_dependency = $this->getMock('Drupal\Tests\Core\Plugin\Context\TypedDataCacheableDependencyInterface');
$cacheable_dependency->expects($this->once())
->method('getCacheTags')
->willReturn(['node:1']);
$cacheable_dependency->expects($this->once())
->method('getCacheContexts')
->willReturn(['route']);
$cacheable_dependency->expects($this->once())
->method('getCacheMaxAge')
->willReturn(60);
$context->setContextValue($cacheable_dependency);
$this->assertSame($cacheable_dependency, $context->getContextData());
$this->assertEquals(['node:1'], $context->getCacheTags());
$this->assertEquals(['route'], $context->getCacheContexts());
$this->assertEquals(60, $context->getCacheMaxAge());
}
/**
* Set up mocks for the getDefaultValue() method call.
*/
protected function setUpDefaultValue() {
$mock_data_definition = $this->getMock('Drupal\Core\TypedData\DataDefinitionInterface');
$this->contextDefinition = $this->getMockBuilder('Drupal\Core\Plugin\Context\ContextDefinitionInterface')
@ -59,33 +147,14 @@ class ContextTest extends UnitTestCase {
$this->typedData = $this->getMock('Drupal\Core\TypedData\TypedDataInterface');
$this->typedDataManager = $this->getMockBuilder('Drupal\Core\TypedData\TypedDataManager')
->disableOriginalConstructor()
->setMethods(array('create'))
->getMock();
$this->typedDataManager->expects($this->once())
->method('create')
->with($mock_data_definition, 'test')
->willReturn($this->typedData);
}
/**
* @covers ::getContextValue
*/
public function testDefaultValue() {
$context = new Context($this->contextDefinition);
$context->setTypedDataManager($this->typedDataManager);
$this->assertEquals('test', $context->getContextValue());
}
/**
* @covers ::getContextData
*/
public function testDefaultDataValue() {
$context = new Context($this->contextDefinition);
$context->setTypedDataManager($this->typedDataManager);
$this->assertEquals($this->typedData, $context->getContextData());
}
}
/**
* Test interface used for mocking.
*/
interface TypedDataCacheableDependencyInterface extends CacheableDependencyInterface, TypedDataInterface { }

View file

@ -0,0 +1,152 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Plugin\Context\LazyContextRepositoryTest.
*/
namespace Drupal\Tests\Core\Plugin\Context;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
use Drupal\Core\Plugin\Context\LazyContextRepository;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* @coversDefaultClass \Drupal\Core\Plugin\Context\LazyContextRepository
* @group context
*/
class LazyContextRepositoryTest extends UnitTestCase {
/**
* The container.
*
* @var \Symfony\Component\DependencyInjection\ContainerBuilder
*/
protected $container;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->container = new ContainerBuilder();
}
/**
* @covers ::getRuntimeContexts
*/
public function testGetRuntimeContextsSingle() {
$contexts = $this->setupContextAndProvider('test_provider', ['test_context']);
$lazy_context_repository = new LazyContextRepository($this->container, ['test_provider']);
$run_time_contexts = $lazy_context_repository->getRuntimeContexts(['@test_provider:test_context']);
$this->assertEquals(['@test_provider:test_context' => $contexts[0]], $run_time_contexts);
}
/**
* @covers ::getRuntimeContexts
*/
public function testGetRuntimeMultipleContextsPerService() {
$contexts = $this->setupContextAndProvider('test_provider', ['test_context0', 'test_context1']);
$lazy_context_repository = new LazyContextRepository($this->container, ['test_provider']);
$run_time_contexts = $lazy_context_repository->getRuntimeContexts(['@test_provider:test_context0', '@test_provider:test_context1']);
$this->assertEquals(['@test_provider:test_context0' => $contexts[0], '@test_provider:test_context1' => $contexts[1]], $run_time_contexts);
}
/**
* @covers ::getRuntimeContexts
*/
public function testGetRuntimeMultipleContextProviders() {
$contexts0 = $this->setupContextAndProvider('test_provider', ['test_context0', 'test_context1'], ['test_context0']);
$contexts1 = $this->setupContextAndProvider('test_provider2', ['test1_context0', 'test1_context1'], ['test1_context0']);
$lazy_context_repository = new LazyContextRepository($this->container, ['test_provider']);
$run_time_contexts = $lazy_context_repository->getRuntimeContexts(['@test_provider:test_context0', '@test_provider2:test1_context0']);
$this->assertEquals(['@test_provider:test_context0' => $contexts0[0], '@test_provider2:test1_context0' => $contexts1[1]], $run_time_contexts);
}
/**
* @covers ::getRuntimeContexts
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage You must provide the context IDs in the @{service_id}:{unqualified_context_id} format.
*/
public function testInvalidContextId() {
$lazy_context_repository = new LazyContextRepository($this->container, ['test_provider']);
$lazy_context_repository->getRuntimeContexts(['test_context', '@test_provider:test_context1']);
}
/**
* @covers ::getRuntimeContexts
*/
public function testGetRuntimeStaticCache() {
$context0 = new Context(new ContextDefinition('example'));
$context1 = new Context(new ContextDefinition('example'));
$context_provider = $this->prophesize('\Drupal\Core\Plugin\Context\ContextProviderInterface');
$context_provider->getRuntimeContexts(['test_context0', 'test_context1'])
->shouldBeCalledTimes(1)
->willReturn(['test_context0' => $context0, 'test_context1' => $context1]);
$context_provider = $context_provider->reveal();
$this->container->set('test_provider', $context_provider);
$lazy_context_repository = new LazyContextRepository($this->container, ['test_provider']);
$lazy_context_repository->getRuntimeContexts(['@test_provider:test_context0', '@test_provider:test_context1']);
$lazy_context_repository->getRuntimeContexts(['@test_provider:test_context0', '@test_provider:test_context1']);
}
/**
* @covers ::getAvailableContexts
*/
public function testGetAvailableContexts() {
$contexts0 = $this->setupContextAndProvider('test_provider0', ['test0_context0', 'test0_context1']);
$contexts1 = $this->setupContextAndProvider('test_provider1', ['test1_context0', 'test1_context1']);
$lazy_context_repository = new LazyContextRepository($this->container, ['test_provider0', 'test_provider1']);
$contexts = $lazy_context_repository->getAvailableContexts();
$this->assertEquals([
'@test_provider0:test0_context0' => $contexts0[0],
'@test_provider0:test0_context1' => $contexts0[1],
'@test_provider1:test1_context0' => $contexts1[0],
'@test_provider1:test1_context1' => $contexts1[1],
], $contexts);
}
/**
* Sets up contexts and context providers.
*
* @param string $service_id
* The service ID of the service provider.
* @param string[] $unqualified_context_ids
* An array of context slot names.
* @param string[] $expected_unqualified_context_ids
* The expected unqualified context IDs passed to getRuntimeContexts.
*
* @return array
* An array of set up contexts.
*/
protected function setupContextAndProvider($service_id, array $unqualified_context_ids, array $expected_unqualified_context_ids = []) {
$contexts = [];
for ($i = 0; $i < count($unqualified_context_ids); $i++) {
$contexts[] = new Context(new ContextDefinition('example'));
}
$expected_unqualified_context_ids = $expected_unqualified_context_ids ?: $unqualified_context_ids;
$context_provider = $this->prophesize('\Drupal\Core\Plugin\Context\ContextProviderInterface');
$context_provider->getRuntimeContexts($expected_unqualified_context_ids)
->willReturn(array_combine($unqualified_context_ids, $contexts));
$context_provider->getAvailableContexts()
->willReturn(array_combine($unqualified_context_ids, $contexts));
$context_provider = $context_provider->reveal();
$this->container->set($service_id, $context_provider);
return $contexts;
}
}

View file

@ -233,6 +233,9 @@ class ContextHandlerTest extends UnitTestCase {
$context_hit->expects($this->atLeastOnce())
->method('getContextValue')
->will($this->returnValue(array('foo')));
$context_hit->expects($this->atLeastOnce())
->method('hasContextValue')
->willReturn(TRUE);
$context_miss = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
$context_miss->expects($this->never())
->method('getContextValue');
@ -242,24 +245,39 @@ class ContextHandlerTest extends UnitTestCase {
'miss' => $context_miss,
);
$context_definition = $this->getMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
$plugin = $this->getMock('Drupal\Core\Plugin\ContextAwarePluginInterface');
$plugin->expects($this->once())
->method('getContextMapping')
->willReturn([]);
$plugin->expects($this->once())
->method('getContextDefinitions')
->will($this->returnValue(array('hit' => 'hit')));
->will($this->returnValue(array('hit' => $context_definition)));
$plugin->expects($this->once())
->method('setContextValue')
->with('hit', array('foo'));
// Make sure that the cacheability metadata is passed to the plugin context.
$plugin_context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
$plugin_context->expects($this->once())
->method('addCacheableDependency')
->with($context_hit);
$plugin->expects($this->once())
->method('getContext')
->with('hit')
->willReturn($plugin_context);
$this->contextHandler->applyContextMapping($plugin, $contexts);
}
/**
* @covers ::applyContextMapping
*
* @expectedException \Drupal\Component\Plugin\Exception\ContextException
* @expectedExceptionMessage Required contexts without a value: hit.
*/
public function testApplyContextMappingConfigurable() {
public function testApplyContextMappingMissingRequired() {
$context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
$context->expects($this->never())
->method('getContextValue');
@ -268,13 +286,126 @@ class ContextHandlerTest extends UnitTestCase {
'name' => $context,
);
$context_definition = $this->getMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
$context_definition->expects($this->atLeastOnce())
->method('isRequired')
->willReturn(TRUE);
$plugin = $this->getMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
$plugin->expects($this->once())
->method('getContextMapping')
->willReturn([]);
$plugin->expects($this->once())
->method('getContextDefinitions')
->will($this->returnValue(array('hit' => 'hit')));
->will($this->returnValue(array('hit' => $context_definition)));
$plugin->expects($this->never())
->method('setContextValue');
// No context, so no cacheability metadata can be passed along.
$plugin->expects($this->never())
->method('getContext');
$this->contextHandler->applyContextMapping($plugin, $contexts);
}
/**
* @covers ::applyContextMapping
*/
public function testApplyContextMappingMissingNotRequired() {
$context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
$context->expects($this->never())
->method('getContextValue');
$contexts = array(
'name' => $context,
);
$context_definition = $this->getMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
$context_definition->expects($this->atLeastOnce())
->method('isRequired')
->willReturn(FALSE);
$plugin = $this->getMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
$plugin->expects($this->once())
->method('getContextMapping')
->willReturn(['optional' => 'missing']);
$plugin->expects($this->once())
->method('getContextDefinitions')
->will($this->returnValue(array('optional' => $context_definition)));
$plugin->expects($this->never())
->method('setContextValue');
// No context, so no cacheability metadata can be passed along.
$plugin->expects($this->never())
->method('getContext');
$this->contextHandler->applyContextMapping($plugin, $contexts);
}
/**
* @covers ::applyContextMapping
*
* @expectedException \Drupal\Component\Plugin\Exception\ContextException
* @expectedExceptionMessage Required contexts without a value: hit.
*/
public function testApplyContextMappingNoValueRequired() {
$context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
$context->expects($this->never())
->method('getContextValue');
$context->expects($this->atLeastOnce())
->method('hasContextValue')
->willReturn(FALSE);
$contexts = array(
'hit' => $context,
);
$context_definition = $this->getMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
$context_definition->expects($this->atLeastOnce())
->method('isRequired')
->willReturn(TRUE);
$plugin = $this->getMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
$plugin->expects($this->once())
->method('getContextMapping')
->willReturn([]);
$plugin->expects($this->once())
->method('getContextDefinitions')
->will($this->returnValue(array('hit' => $context_definition)));
$plugin->expects($this->never())
->method('setContextValue');
$this->contextHandler->applyContextMapping($plugin, $contexts);
}
/**
* @covers ::applyContextMapping
*/
public function testApplyContextMappingNoValueNonRequired() {
$context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
$context->expects($this->never())
->method('getContextValue');
$context->expects($this->atLeastOnce())
->method('hasContextValue')
->willReturn(FALSE);
$contexts = array(
'hit' => $context,
);
$context_definition = $this->getMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
$context_definition->expects($this->atLeastOnce())
->method('isRequired')
->willReturn(FALSE);
$plugin = $this->getMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
$plugin->expects($this->once())
->method('getContextMapping')
->willReturn([]);
$plugin->expects($this->once())
->method('getContextDefinitions')
->will($this->returnValue(array('hit' => $context_definition)));
$plugin->expects($this->never())
->method('setContextValue');
@ -289,22 +420,37 @@ class ContextHandlerTest extends UnitTestCase {
$context->expects($this->atLeastOnce())
->method('getContextValue')
->will($this->returnValue(array('foo')));
$context->expects($this->atLeastOnce())
->method('hasContextValue')
->willReturn(TRUE);
$contexts = array(
'name' => $context,
);
$context_definition = $this->getMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
$plugin = $this->getMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
$plugin->expects($this->once())
->method('getContextMapping')
->willReturn([]);
$plugin->expects($this->once())
->method('getContextDefinitions')
->will($this->returnValue(array('hit' => 'hit')));
->will($this->returnValue(array('hit' => $context_definition)));
$plugin->expects($this->once())
->method('setContextValue')
->with('hit', array('foo'));
// Make sure that the cacheability metadata is passed to the plugin context.
$plugin_context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
$plugin_context->expects($this->once())
->method('addCacheableDependency')
->with($context);
$plugin->expects($this->once())
->method('getContext')
->with('hit')
->willReturn($plugin_context);
$this->contextHandler->applyContextMapping($plugin, $contexts, ['hit' => 'name']);
}
@ -323,13 +469,15 @@ class ContextHandlerTest extends UnitTestCase {
'name' => $context,
);
$context_definition = $this->getMock('Drupal\Core\Plugin\Context\ContextDefinitionInterface');
$plugin = $this->getMock('Drupal\Tests\Core\Plugin\TestConfigurableContextAwarePluginInterface');
$plugin->expects($this->once())
->method('getContextMapping')
->willReturn([]);
$plugin->expects($this->once())
->method('getContextDefinitions')
->will($this->returnValue(array('hit' => 'hit')));
->will($this->returnValue(array('hit' => $context_definition)));
$plugin->expects($this->never())
->method('setContextValue');

View file

@ -7,8 +7,10 @@
namespace Drupal\Tests\Core\Plugin\Discovery;
use Drupal\Core\StringTranslation\TranslationWrapper;
use Drupal\Tests\UnitTestCase;
use Drupal\Core\Plugin\Discovery\YamlDiscovery;
use org\bovigo\vfs\vfsStream;
/**
* @coversDefaultClass \Drupal\Core\Plugin\Discovery\YamlDiscovery
@ -70,6 +72,44 @@ class YamlDiscoveryTest extends UnitTestCase {
}
}
/**
* @covers ::getDefinitions
*/
public function testGetDefinitionsWithTranslatableDefinitions() {
vfsStream::setup('root');
$file_1 = <<<'EOS'
test_plugin:
title: test title
EOS;
$file_2 = <<<'EOS'
test_plugin2:
title: test title2
title_context: 'test-context'
EOS;
vfsStream::create([
'test_1' => [
'test_1.test.yml' => $file_1,
],
'test_2' => [
'test_2.test.yml' => $file_2,
]]
);
$discovery = new YamlDiscovery('test', ['test_1' => vfsStream::url('root/test_1'), 'test_2' => vfsStream::url('root/test_2')]);
$discovery->addTranslatableProperty('title', 'title_context');
$definitions = $discovery->getDefinitions();
$this->assertCount(2, $definitions);
$plugin_1 = $definitions['test_plugin'];
$plugin_2 = $definitions['test_plugin2'];
$this->assertInstanceOf(TranslationWrapper::class, $plugin_1['title']);
$this->assertEquals([], $plugin_1['title']->getOptions());
$this->assertInstanceOf(TranslationWrapper::class, $plugin_2['title']);
$this->assertEquals(['context' => 'test-context'], $plugin_2['title']->getOptions());
}
/**
* Tests the getDefinition() method.
*/

View file

@ -44,11 +44,14 @@ class ProxyBuilderTest extends UnitTestCase {
// @todo Solve the silly linebreak for array()
$method_body = <<<'EOS'
public function complexMethod($parameter, callable $function, \Drupal\Tests\Core\ProxyBuilder\TestServiceNoMethod $test_service = NULL, array &$elements = array (
))
{
return $this->lazyLoadItself()->complexMethod($parameter, $function, $test_service, $elements);
}
/**
* {@inheritdoc}
*/
public function complexMethod($parameter, callable $function, \Drupal\Tests\Core\ProxyBuilder\TestServiceNoMethod $test_service = NULL, array &$elements = array (
))
{
return $this->lazyLoadItself()->complexMethod($parameter, $function, $test_service, $elements);
}
EOS;
@ -65,55 +68,88 @@ EOS;
* The code of the entire proxy.
*/
protected function buildExpectedClass($class, $expected_methods_body, $interface_string = '') {
$proxy_class = $this->proxyBuilder->buildProxyClassName($class);
$reflection = new \ReflectionClass($class);
$namespace = ProxyBuilder::buildProxyNamespace($class);
$proxy_class = $reflection->getShortName();
$expected_string = <<<'EOS'
/**
* Provides a proxy class for \{{ class }}.
*
* @see \Drupal\Component\ProxyBuilder
*/
class {{ proxy_class }}{{ interface_string }}
{
use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
namespace {{ namespace }} {
/**
* @var string
*/
protected $serviceId;
/**
* @var \{{ class }}
*/
protected $service;
/**
* The service container.
* Provides a proxy class for \{{ class }}.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
* @see \Drupal\Component\ProxyBuilder
*/
protected $container;
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $serviceId)
class {{ proxy_class }}{{ interface_string }}
{
$this->container = $container;
$this->serviceId = $serviceId;
}
protected function lazyLoadItself()
{
if (!isset($this->service)) {
$method_name = 'get' . Container::camelize($this->serviceId) . 'Service';
$this->service = $this->container->$method_name(false);
use \Drupal\Core\DependencyInjection\DependencySerializationTrait;
/**
* The id of the original proxied service.
*
* @var string
*/
protected $drupalProxyOriginalServiceId;
/**
* The real proxied service, after it was lazy loaded.
*
* @var \{{ class }}
*/
protected $service;
/**
* The service container.
*
* @var \Symfony\Component\DependencyInjection\ContainerInterface
*/
protected $container;
/**
* Constructs a ProxyClass Drupal proxy object.
*
* @param \Symfony\Component\DependencyInjection\ContainerInterface $container
* The container.
* @param string $drupal_proxy_original_service_id
* The service ID of the original service.
*/
public function __construct(\Symfony\Component\DependencyInjection\ContainerInterface $container, $drupal_proxy_original_service_id)
{
$this->container = $container;
$this->drupalProxyOriginalServiceId = $drupal_proxy_original_service_id;
}
return $this->service;
}
/**
* Lazy loads the real service from the container.
*
* @return object
* Returns the constructed real service.
*/
protected function lazyLoadItself()
{
if (!isset($this->service)) {
$this->service = $this->container->get($this->drupalProxyOriginalServiceId);
}
return $this->service;
}
{{ expected_methods_body }}
}
}
EOS;
$expected_methods_body = implode("\n", array_map(function ($value) {
if ($value === '') {
return $value;
}
return " $value";
}, explode("\n", $expected_methods_body)));
$expected_string = str_replace('{{ proxy_class }}', $proxy_class, $expected_string);
$expected_string = str_replace('{{ namespace }}', $namespace, $expected_string);
$expected_string = str_replace('{{ class }}', $class, $expected_string);
$expected_string = str_replace('{{ expected_methods_body }}', $expected_methods_body, $expected_string);
$expected_string = str_replace('{{ interface_string }}', $interface_string, $expected_string);

View file

@ -648,4 +648,52 @@ class BubbleableMetadataTest extends UnitTestCase {
];
}
/**
* @covers ::addCacheableDependency
* @dataProvider providerTestMerge
*
* This only tests at a high level, because it reuses existing logic. Detailed
* tests exist for the existing logic:
*
* @see \Drupal\Tests\Core\Cache\CacheTest::testMergeTags()
* @see \Drupal\Tests\Core\Cache\CacheTest::testMergeMaxAges()
* @see \Drupal\Tests\Core\Cache\CacheContextsTest
*/
public function testAddCacheableDependency(BubbleableMetadata $a, $b, BubbleableMetadata $expected) {
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
->disableOriginalConstructor()
->getMock();
$container = new ContainerBuilder();
$container->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
$this->assertEquals($expected, $a->addCacheableDependency($b));
}
/**
* Provides test data for testMerge().
*
* @return array
*/
public function providerTestAddCachableDependency() {
return [
// Merge in a cacheable metadata.
'merge-cacheable-metadata' => [
(new BubbleableMetadata())->setCacheContexts(['foo'])->setCacheTags(['foo'])->setCacheMaxAge(20),
(new CacheableMetadata())->setCacheContexts(['bar'])->setCacheTags(['bar'])->setCacheMaxAge(60),
(new BubbleableMetadata())->setCacheContexts(['foo', 'bar'])->setCacheTags(['foo', 'bar'])->setCacheMaxAge(20)
],
'merge-bubbleable-metadata' => [
(new BubbleableMetadata())->setCacheContexts(['foo'])->setCacheTags(['foo'])->setCacheMaxAge(20)->setAttachments(['foo' => []]),
(new BubbleableMetadata())->setCacheContexts(['bar'])->setCacheTags(['bar'])->setCacheMaxAge(60)->setAttachments(['bar' => []]),
(new BubbleableMetadata())->setCacheContexts(['foo', 'bar'])->setCacheTags(['foo', 'bar'])->setCacheMaxAge(20)->setAttachments(['foo' => [], 'bar' => []])
],
'merge-attachments-metadata' => [
(new BubbleableMetadata())->setAttachments(['foo' => []]),
(new BubbleableMetadata())->setAttachments(['baro' => []]),
(new BubbleableMetadata())->setAttachments(['foo' => [], 'bar' => []])
],
];
}
}

View file

@ -0,0 +1,117 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Render\Element\RenderElementTest.
*/
namespace Drupal\Tests\Core\Render\Element;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Form\FormBuilderInterface;
use Drupal\Core\GeneratedUrl;
use Drupal\Core\Render\Element\RenderElement;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* @coversDefaultClass \Drupal\Core\Render\Element\RenderElement
* @group Render
*/
class RenderElementTest extends UnitTestCase {
/**
* The request stack.
*
* @var \Symfony\Component\HttpFoundation\RequestStack
*/
protected $requestStack;
/**
* The container.
*
* @var \Drupal\Core\DependencyInjection\ContainerBuilder
*/
protected $container;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->requestStack = new RequestStack();
$this->container = new ContainerBuilder();
$this->container->set('request_stack', $this->requestStack);
\Drupal::setContainer($this->container);
}
/**
* @covers ::preRenderAjaxForm
*/
public function testPreRenderAjaxForm() {
$request = Request::create('/test');
$request->query->set('foo', 'bar');
$this->requestStack->push($request);
$prophecy = $this->prophesize('Drupal\Core\Routing\UrlGeneratorInterface');
$url = '/test?foo=bar&ajax_form=1';
$prophecy->generateFromRoute('<current>', [], ['query' => ['foo' => 'bar', FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]], TRUE)
->willReturn((new GeneratedUrl())->setCacheContexts(['route'])->setGeneratedUrl($url));
$url_generator = $prophecy->reveal();
$this->container->set('url_generator', $url_generator);
$element = [
'#type' => 'select',
'#id' => 'test',
'#ajax' => [
'wrapper' => 'foo',
'callback' => 'test-callback',
],
];
$element = RenderElement::preRenderAjaxForm($element);
$this->assertTrue($element['#ajax_processed']);
$this->assertEquals($url, $element['#attached']['drupalSettings']['ajax']['test']['url']);
}
/**
* @covers ::preRenderAjaxForm
*/
public function testPreRenderAjaxFormWithQueryOptions() {
$request = Request::create('/test');
$request->query->set('foo', 'bar');
$this->requestStack->push($request);
$prophecy = $this->prophesize('Drupal\Core\Routing\UrlGeneratorInterface');
$url = '/test?foo=bar&other=query&ajax_form=1';
$prophecy->generateFromRoute('<current>', [], ['query' => ['foo' => 'bar', 'other' => 'query', FormBuilderInterface::AJAX_FORM_REQUEST => TRUE]], TRUE)
->willReturn((new GeneratedUrl())->setCacheContexts(['route'])->setGeneratedUrl($url));
$url_generator = $prophecy->reveal();
$this->container->set('url_generator', $url_generator);
$element = [
'#type' => 'select',
'#id' => 'test',
'#ajax' => [
'wrapper' => 'foo',
'callback' => 'test-callback',
'options' => [
'query' => [
'other' => 'query',
],
],
],
];
$element = RenderElement::preRenderAjaxForm($element);
$this->assertTrue($element['#ajax_processed']);
$this->assertEquals($url, $element['#attached']['drupalSettings']['ajax']['test']['url']);
}
}

View file

@ -7,6 +7,7 @@
namespace Drupal\Tests\Core\Render;
use Drupal\Core\Access\AccessResult;
use Drupal\Tests\UnitTestCase;
use Drupal\Core\Render\Element;
@ -151,6 +152,8 @@ class ElementTest extends UnitTestCase {
array(array('#property1' => '', 'child1' => array()), array('child1')),
array(array('#property1' => '', 'child1' => array(), 'child2' => array('#access' => TRUE)), array('child1', 'child2')),
array(array('#property1' => '', 'child1' => array(), 'child2' => array('#access' => FALSE)), array('child1')),
'access_result_object_allowed' => array(array('#property1' => '', 'child1' => array(), 'child2' => array('#access' => AccessResult::allowed())), array('child1', 'child2')),
'access_result_object_forbidden' => array(array('#property1' => '', 'child1' => array(), 'child2' => array('#access' => AccessResult::forbidden())), array('child1')),
array(array('#property1' => '', 'child1' => array(), 'child2' => array('#type' => 'textfield')), array('child1', 'child2')),
array(array('#property1' => '', 'child1' => array(), 'child2' => array('#type' => 'value')), array('child1')),
array(array('#property1' => '', 'child1' => array(), 'child2' => array('#type' => 'hidden')), array('child1')),

View file

@ -0,0 +1,84 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Render\MetadataBubblingUrlGeneratorTest.
*/
namespace Drupal\Tests\Core\Render;
use Drupal\Core\Render\MetadataBubblingUrlGenerator;
use Drupal\Core\Url;
use Drupal\Tests\Core\Routing\UrlGeneratorTest;
/**
* Confirm that the MetadataBubblingUrlGenerator is functioning properly.
*
* @coversDefaultClass \Drupal\Core\Render\MetadataBubblingUrlGenerator
*
* @group Render
*/
class MetadataBubblingUrlGeneratorTest extends UrlGeneratorTest {
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $renderer;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
$this->renderer->expects($this->any())
->method('hasRenderContext')
->willReturn(TRUE);
$this->generator = new MetadataBubblingUrlGenerator($this->generator, $this->renderer);
}
/**
* Tests bubbling of cacheable metadata for URLs.
*
* @param bool $collect_bubbleable_metadata
* Whether bubbleable metadata should be collected.
* @param int $invocations
* The expected amount of invocations for the ::bubble() method.
* @param array $options
* The URL options.
*
* @covers ::bubble
*
* @dataProvider providerUrlBubbleableMetadataBubbling
*/
public function testUrlBubbleableMetadataBubbling($collect_bubbleable_metadata, $invocations, array $options) {
$self = $this;
$this->renderer->expects($this->exactly($invocations))
->method('render')
->willReturnCallback(function ($build) use ($self) {
$self->assertTrue(!empty($build['#cache']));
});
$url = new Url('test_1', [], $options);
$url->setUrlGenerator($this->generator);
$url->toString($collect_bubbleable_metadata);
}
/**
* Data provider for ::testUrlBubbleableMetadataBubbling().
*/
public function providerUrlBubbleableMetadataBubbling() {
return [
// No bubbling when bubbleable metadata is collected.
[TRUE, 0, []],
// Bubbling when bubbleable metadata is not collected.
[FALSE, 1, []],
];
}
}

View file

@ -125,6 +125,7 @@ class RendererBubblingTest extends RendererTestBase {
'contexts' => ['bar', 'foo'],
'tags' => [],
'bin' => $bin,
'max-age' => 3600,
],
], $bin);
}
@ -279,6 +280,7 @@ class RendererBubblingTest extends RendererTestBase {
'contexts' => ['bar', 'foo'],
'tags' => ['dee', 'fiddle', 'har', 'yar'],
'bin' => 'render',
'max-age' => Cache::PERMANENT,
],
],
'parent:bar:foo' => [
@ -325,6 +327,8 @@ class RendererBubblingTest extends RendererTestBase {
'#cache' => [
'contexts' => ['foo'],
'tags' => ['c'],
// A lower max-age; the redirecting cache item should be updated.
'max-age' => 1800,
],
'grandgrandchild' => [
'#access_callback' => function () {
@ -335,6 +339,8 @@ class RendererBubblingTest extends RendererTestBase {
'#cache' => [
'contexts' => ['bar'],
'tags' => ['d'],
// A lower max-age; the redirecting cache item should be updated.
'max-age' => 300,
],
],
],
@ -353,6 +359,7 @@ class RendererBubblingTest extends RendererTestBase {
'contexts' => ['user.roles'],
'tags' => ['a', 'b'],
'bin' => 'render',
'max-age' => Cache::PERMANENT,
],
]);
$this->assertRenderCacheItem('parent:r.A', [
@ -366,7 +373,7 @@ class RendererBubblingTest extends RendererTestBase {
]);
// Request 2: role B, the grandchild is accessible => bubbled cache
// contexts: foo, user.roles.
// contexts: foo, user.roles + merged max-age: 1800.
$element = $test_element;
$current_user_role = 'B';
$this->renderer->renderRoot($element);
@ -377,6 +384,7 @@ class RendererBubblingTest extends RendererTestBase {
'contexts' => ['foo', 'user.roles'],
'tags' => ['a', 'b', 'c'],
'bin' => 'render',
'max-age' => 1800,
],
]);
$this->assertRenderCacheItem('parent:foo:r.B', [
@ -384,7 +392,7 @@ class RendererBubblingTest extends RendererTestBase {
'#cache' => [
'contexts' => ['foo', 'user.roles'],
'tags' => ['a', 'b', 'c'],
'max-age' => Cache::PERMANENT,
'max-age' => 1800,
],
'#markup' => 'parent',
]);
@ -409,6 +417,7 @@ class RendererBubblingTest extends RendererTestBase {
'contexts' => ['foo', 'user.roles'],
'tags' => ['a', 'b', 'c'],
'bin' => 'render',
'max-age' => 1800,
],
]);
$this->assertRenderCacheItem('parent:foo:r.A', [
@ -416,13 +425,17 @@ class RendererBubblingTest extends RendererTestBase {
'#cache' => [
'contexts' => ['foo', 'user.roles'],
'tags' => ['a', 'b'],
// Note that the max-age here is unaffected. When role A, the grandchild
// is never rendered, so neither is its max-age of 1800 present here,
// despite 1800 being the max-age of the redirecting cache item.
'max-age' => Cache::PERMANENT,
],
'#markup' => 'parent',
]);
// Request 4: role C, both the grandchild and the grandgrandchild are
// accessible => bubbled cache contexts: foo, bar, user.roles.
// accessible => bubbled cache contexts: foo, bar, user.roles + merged
// max-age: 300.
$element = $test_element;
$current_user_role = 'C';
$this->renderer->renderRoot($element);
@ -433,6 +446,7 @@ class RendererBubblingTest extends RendererTestBase {
'contexts' => ['bar', 'foo', 'user.roles'],
'tags' => ['a', 'b', 'c', 'd'],
'bin' => 'render',
'max-age' => 300,
],
];
$this->assertRenderCacheItem('parent', $final_parent_cache_item);
@ -441,7 +455,7 @@ class RendererBubblingTest extends RendererTestBase {
'#cache' => [
'contexts' => ['bar', 'foo', 'user.roles'],
'tags' => ['a', 'b', 'c', 'd'],
'max-age' => Cache::PERMANENT,
'max-age' => 300,
],
'#markup' => 'parent',
]);
@ -456,6 +470,10 @@ class RendererBubblingTest extends RendererTestBase {
'#cache' => [
'contexts' => ['bar', 'foo', 'user.roles'],
'tags' => ['a', 'b'],
// Note that the max-age here is unaffected. When role A, the grandchild
// is never rendered, so neither is its max-age of 1800 present here,
// nor the grandgrandchild's max-age of 300, despite 300 being the
// max-age of the redirecting cache item.
'max-age' => Cache::PERMANENT,
],
'#markup' => 'parent',
@ -471,7 +489,11 @@ class RendererBubblingTest extends RendererTestBase {
'#cache' => [
'contexts' => ['bar', 'foo', 'user.roles'],
'tags' => ['a', 'b', 'c'],
'max-age' => Cache::PERMANENT,
// Note that the max-age here is unaffected. When role B, the
// grandgrandchild is never rendered, so neither is its max-age of 300
// present here, despite 300 being the max-age of the redirecting cache
// item.
'max-age' => 1800,
],
'#markup' => 'parent',
]);

View file

@ -215,7 +215,7 @@ class RendererPlaceholdersTest extends RendererTestBase {
if ($cid_parts !== FALSE) {
// Verify render cached placeholder.
$cached_element = $this->memoryCache->get(implode(':', $cid_parts))->data;
$this->assertSame($expected_data, $cached_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by the placeholder being replaced.');
$this->assertEquals($expected_data, $cached_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by the placeholder being replaced.');
}
}
/**
@ -237,8 +237,8 @@ class RendererPlaceholdersTest extends RendererTestBase {
// No #cache on parent element.
$element['#prefix'] = '<p>#cache disabled</p>';
$output = $this->renderer->renderRoot($element);
$this->assertSame('<p>#cache disabled</p><p>This is a rendered placeholder!</p>', $output, 'Output is overridden.');
$this->assertSame('<p>#cache disabled</p><p>This is a rendered placeholder!</p>', $element['#markup'], '#markup is overridden.');
$this->assertSame('<p>#cache disabled</p><p>This is a rendered placeholder!</p>', (string) $output, 'Output is overridden.');
$this->assertSame('<p>#cache disabled</p><p>This is a rendered placeholder!</p>', (string) $element['#markup'], '#markup is overridden.');
$expected_js_settings = [
'foo' => 'bar',
'dynamic_animal' => $args[0],
@ -283,9 +283,9 @@ class RendererPlaceholdersTest extends RendererTestBase {
$element['#cache'] = ['keys' => ['placeholder_test_GET']];
$element['#prefix'] = '<p>#cache enabled, GET</p>';
$output = $this->renderer->renderRoot($element);
$this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', $output, 'Output is overridden.');
$this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $output, 'Output is overridden.');
$this->assertTrue(isset($element['#printed']), 'No cache hit');
$this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', $element['#markup'], '#markup is overridden.');
$this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $element['#markup'], '#markup is overridden.');
$expected_js_settings = [
'foo' => 'bar',
'dynamic_animal' => $args[0],
@ -321,9 +321,9 @@ class RendererPlaceholdersTest extends RendererTestBase {
$element['#cache'] = ['keys' => ['placeholder_test_GET']];
$element['#prefix'] = '<p>#cache enabled, GET</p>';
$output = $this->renderer->renderRoot($element);
$this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', $output, 'Output is overridden.');
$this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $output, 'Output is overridden.');
$this->assertFalse(isset($element['#printed']), 'Cache hit');
$this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', $element['#markup'], '#markup is overridden.');
$this->assertSame('<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>', (string) $element['#markup'], '#markup is overridden.');
$expected_js_settings = [
'foo' => 'bar',
'dynamic_animal' => $args[0],
@ -351,9 +351,9 @@ class RendererPlaceholdersTest extends RendererTestBase {
$element['#cache'] = ['keys' => ['placeholder_test_POST']];
$element['#prefix'] = '<p>#cache enabled, POST</p>';
$output = $this->renderer->renderRoot($element);
$this->assertSame('<p>#cache enabled, POST</p><p>This is a rendered placeholder!</p>', $output, 'Output is overridden.');
$this->assertSame('<p>#cache enabled, POST</p><p>This is a rendered placeholder!</p>', (string) $output, 'Output is overridden.');
$this->assertTrue(isset($element['#printed']), 'No cache hit');
$this->assertSame('<p>#cache enabled, POST</p><p>This is a rendered placeholder!</p>', $element['#markup'], '#markup is overridden.');
$this->assertSame('<p>#cache enabled, POST</p><p>This is a rendered placeholder!</p>', (string) $element['#markup'], '#markup is overridden.');
$expected_js_settings = [
'foo' => 'bar',
'dynamic_animal' => $args[0],
@ -383,7 +383,7 @@ class RendererPlaceholdersTest extends RendererTestBase {
$output = $this->renderer->renderRoot($element);
$this->assertEquals('<p>This is a rendered placeholder!</p>', $output, 'The output has been modified by the indirect, recursive placeholder #lazy_builder callback.');
$this->assertSame($element['#markup'], '<p>This is a rendered placeholder!</p>', '#markup is overridden by the indirect, recursive placeholder #lazy_builder callback.');
$this->assertSame((string) $element['#markup'], '<p>This is a rendered placeholder!</p>', '#markup is overridden by the indirect, recursive placeholder #lazy_builder callback.');
$expected_js_settings = [
'dynamic_animal' => $args[0],
];
@ -546,9 +546,9 @@ class RendererPlaceholdersTest extends RendererTestBase {
</details></div>
</details>
HTML;
$this->assertSame($expected_output, $output, 'Output is not overridden.');
$this->assertSame($expected_output, (string) $output, 'Output is not overridden.');
$this->assertTrue(isset($element['#printed']), 'No cache hit');
$this->assertSame($expected_output, $output, '#markup is not overridden.');
$this->assertSame($expected_output, (string) $element['#markup'], '#markup is not overridden.');
$expected_js_settings = [
'foo' => 'bar',
'dynamic_animal' => [$args_1[0] => TRUE, $args_2[0] => TRUE, $args_3[0] => TRUE],
@ -595,7 +595,7 @@ HTML;
// GET request: #cache enabled, cache hit.
$element = $test_element;
$output = $this->renderer->renderRoot($element);
$this->assertSame($expected_output, $output, 'Output is not overridden.');
$this->assertSame($expected_output, (string) $output, 'Output is not overridden.');
$this->assertFalse(isset($element['#printed']), 'Cache hit');
$this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the ones added by each placeholder #lazy_builder callback exist.');
@ -604,8 +604,8 @@ HTML;
unset($test_element['#cache']);
$element = $test_element;
$output = $this->renderer->renderRoot($element);
$this->assertSame($expected_output, $output, 'Output is not overridden.');
$this->assertSame($expected_output, $output, '#markup is not overridden.');
$this->assertSame($expected_output, (string) $output, 'Output is not overridden.');
$this->assertSame($expected_output, (string) $element['#markup'], '#markup is not overridden.');
$this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the ones added by each #lazy_builder callback exist.');
}

View file

@ -7,9 +7,13 @@
namespace Drupal\Tests\Core\Render;
use Drupal\Component\Utility\SafeMarkup;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableDependencyInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\SafeString;
use Drupal\Core\Template\Attribute;
/**
@ -43,7 +47,7 @@ class RendererTest extends RendererTestBase {
$setup_code();
}
$this->assertSame($expected, $this->renderer->renderRoot($build));
$this->assertSame($expected, (string) $this->renderer->renderRoot($build));
}
/**
@ -367,7 +371,7 @@ class RendererTest extends RendererTestBase {
* @covers ::render
* @covers ::doRender
*
* @dataProvider providerBoolean
* @dataProvider providerAccessValues
*/
public function testRenderWithPresetAccess($access) {
$build = [
@ -381,7 +385,7 @@ class RendererTest extends RendererTestBase {
* @covers ::render
* @covers ::doRender
*
* @dataProvider providerBoolean
* @dataProvider providerAccessValues
*/
public function testRenderWithAccessCallbackCallable($access) {
$build = [
@ -399,7 +403,7 @@ class RendererTest extends RendererTestBase {
* @covers ::render
* @covers ::doRender
*
* @dataProvider providerBoolean
* @dataProvider providerAccessValues
*/
public function testRenderWithAccessPropertyAndCallback($access) {
$build = [
@ -416,16 +420,49 @@ class RendererTest extends RendererTestBase {
* @covers ::render
* @covers ::doRender
*
* @dataProvider providerBoolean
* @dataProvider providerAccessValues
*/
public function testRenderWithAccessControllerResolved($access) {
switch ($access) {
case AccessResult::allowed():
$method = 'accessResultAllowed';
break;
case AccessResult::forbidden():
$method = 'accessResultForbidden';
break;
case FALSE:
$method = 'accessFalse';
break;
case TRUE:
$method = 'accessTrue';
break;
}
$build = [
'#access_callback' => 'Drupal\Tests\Core\Render\TestAccessClass::' . ($access ? 'accessTrue' : 'accessFalse'),
'#access_callback' => 'Drupal\Tests\Core\Render\TestAccessClass::' . $method,
];
$this->assertAccess($build, $access);
}
/**
* @covers ::render
* @covers ::doRender
*/
public function testRenderAccessCacheablityDependencyInheritance() {
$build = [
'#access' => AccessResult::allowed()->addCacheContexts(['user']),
];
$this->renderer->renderPlain($build);
$this->assertEquals(['languages:language_interface', 'theme', 'user'], $build['#cache']['contexts']);
}
/**
* Tests that a first render returns the rendered output and a second doesn't.
*
@ -451,10 +488,12 @@ class RendererTest extends RendererTestBase {
*
* @return array
*/
public function providerBoolean() {
public function providerAccessValues() {
return [
[FALSE],
[TRUE]
[TRUE],
[AccessResult::forbidden()],
[AccessResult::allowed()],
];
}
@ -469,11 +508,11 @@ class RendererTest extends RendererTestBase {
protected function assertAccess($build, $access) {
$sensitive_content = $this->randomContextValue();
$build['#markup'] = $sensitive_content;
if ($access) {
$this->assertSame($sensitive_content, $this->renderer->renderRoot($build));
if (($access instanceof AccessResultInterface && $access->isAllowed()) || $access === TRUE) {
$this->assertSame($sensitive_content, (string) $this->renderer->renderRoot($build));
}
else {
$this->assertSame('', $this->renderer->renderRoot($build));
$this->assertSame('', (string) $this->renderer->renderRoot($build));
}
}
@ -653,10 +692,13 @@ class RendererTest extends RendererTestBase {
],
// Collect expected property names.
'#cache_properties' => array_keys(array_filter($expected_results)),
'child1' => ['#markup' => 1],
'child2' => ['#markup' => 2],
'#custom_property' => ['custom_value'],
'child1' => ['#markup' => SafeString::create('1')],
'child2' => ['#markup' => SafeString::create('2')],
// Mark the value as safe.
'#custom_property' => SafeMarkup::checkPlain('custom_value'),
'#custom_property_array' => ['custom value'],
];
$this->renderer->renderRoot($element);
$cache = $this->cacheFactory->get('render');
@ -671,9 +713,14 @@ class RendererTest extends RendererTestBase {
$this->assertEquals($cached, (bool) $expected);
// Check that only the #markup key is preserved for children.
if ($cached) {
$this->assertArrayEquals($data[$property], $original[$property]);
$this->assertEquals($data[$property], $original[$property]);
}
}
// #custom_property_array can not be a safe_cache_property.
$safe_cache_properties = array_diff(Element::properties(array_filter($expected_results)), ['#custom_property_array']);
foreach ($safe_cache_properties as $cache_property) {
$this->assertTrue(SafeMarkup::isSafe($data[$cache_property]), "$cache_property is marked as a safe string");
}
}
/**
@ -686,14 +733,15 @@ class RendererTest extends RendererTestBase {
public function providerTestRenderCacheProperties() {
return [
[[]],
[['child1' => 0, 'child2' => 0, '#custom_property' => 0]],
[['child1' => 0, 'child2' => 0, '#custom_property' => 1]],
[['child1' => 0, 'child2' => 1, '#custom_property' => 0]],
[['child1' => 0, 'child2' => 1, '#custom_property' => 1]],
[['child1' => 1, 'child2' => 0, '#custom_property' => 0]],
[['child1' => 1, 'child2' => 0, '#custom_property' => 1]],
[['child1' => 1, 'child2' => 1, '#custom_property' => 0]],
[['child1' => 1, 'child2' => 1, '#custom_property' => 1]],
[['child1' => 0, 'child2' => 0, '#custom_property' => 0, '#custom_property_array' => 0]],
[['child1' => 0, 'child2' => 0, '#custom_property' => 1, '#custom_property_array' => 0]],
[['child1' => 0, 'child2' => 1, '#custom_property' => 0, '#custom_property_array' => 0]],
[['child1' => 0, 'child2' => 1, '#custom_property' => 1, '#custom_property_array' => 0]],
[['child1' => 1, 'child2' => 0, '#custom_property' => 0, '#custom_property_array' => 0]],
[['child1' => 1, 'child2' => 0, '#custom_property' => 1, '#custom_property_array' => 0]],
[['child1' => 1, 'child2' => 1, '#custom_property' => 0, '#custom_property_array' => 0]],
[['child1' => 1, 'child2' => 1, '#custom_property' => 1, '#custom_property_array' => 0]],
[['child1' => 1, 'child2' => 1, '#custom_property' => 1, '#custom_property_array' => 1]],
];
}
@ -784,6 +832,14 @@ class TestAccessClass {
return FALSE;
}
public static function accessResultAllowed() {
return AccessResult::allowed();
}
public static function accessResultForbidden() {
return AccessResult::forbidden();
}
}
class TestCallables {

View file

@ -8,11 +8,12 @@
namespace Drupal\Tests\Core\Render;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Cache\Context\ContextCacheKeys;
use Drupal\Core\Cache\MemoryBackend;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\Renderer;
use Drupal\Core\Render\RenderCache;
use Drupal\Core\Render\Renderer;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpFoundation\Request;
@ -100,6 +101,9 @@ class RendererTestBase extends UnitTestCase {
$this->themeManager = $this->getMock('Drupal\Core\Theme\ThemeManagerInterface');
$this->elementInfo = $this->getMock('Drupal\Core\Render\ElementInfoManagerInterface');
$this->requestStack = new RequestStack();
$request = new Request();
$request->server->set('REQUEST_TIME', $_SERVER['REQUEST_TIME']);
$this->requestStack->push($request);
$this->cacheFactory = $this->getMock('Drupal\Core\Cache\CacheFactoryInterface');
$this->cacheContextsManager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
->disableOriginalConstructor()
@ -124,10 +128,10 @@ class RendererTestBase extends UnitTestCase {
$keys[] = $context_id;
}
}
return $keys;
return new ContextCacheKeys($keys, new CacheableMetadata());
});
$this->renderCache = new RenderCache($this->requestStack, $this->cacheFactory, $this->cacheContextsManager);
$this->renderer = new Renderer($this->controllerResolver, $this->themeManager, $this->elementInfo, $this->renderCache, $this->rendererConfig);
$this->renderer = new Renderer($this->controllerResolver, $this->themeManager, $this->elementInfo, $this->renderCache, $this->requestStack, $this->rendererConfig);
$container = new ContainerBuilder();
$container->set('cache_contexts_manager', $this->cacheContextsManager);

View file

@ -8,7 +8,7 @@
namespace Drupal\Tests\Core\RouteProcessor;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\RouteProcessor\RouteProcessorManager;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\Routing\Route;
@ -49,10 +49,10 @@ class RouteProcessorManagerTest extends UnitTestCase {
$this->processorManager->addOutbound($processor, $priority);
}
$cacheable_metadata = new CacheableMetadata();
$this->processorManager->processOutbound($route_name, $route, $parameters, $cacheable_metadata);
$bubbleable_metadata = new BubbleableMetadata();
$this->processorManager->processOutbound($route_name, $route, $parameters, $bubbleable_metadata);
// Default cacheability is: permanently cacheable, no cache tags/contexts.
$this->assertEquals((new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT), $cacheable_metadata);
$this->assertEquals((new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT), $bubbleable_metadata);
}
/**

View file

@ -0,0 +1,57 @@
<?php
/**
* @file
* Contains \Drupal\Tests\Core\Routing\TrustedRedirectResponseTest.
*/
namespace Drupal\Tests\Core\Routing;
use Drupal\Core\Routing\RequestContext;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* @coversDefaultClass \Drupal\Core\Routing\TrustedRedirectResponse
* @group Routing
*/
class TrustedRedirectResponseTest extends UnitTestCase {
/**
* @covers ::setTargetUrl
*/
public function testSetTargetUrlWithInternalUrl() {
$redirect_response = new TrustedRedirectResponse('/example');
$redirect_response->setTargetUrl('/example2');
$this->assertEquals('/example2', $redirect_response->getTargetUrl());
}
/**
* @covers ::setTargetUrl
* @expectedException \InvalidArgumentException
*/
public function testSetTargetUrlWithUntrustedUrl() {
$request_context = new RequestContext();
$request_context->setCompleteBaseUrl('https://www.drupal.org');
$container = new ContainerBuilder();
$container->set('router.request_context', $request_context);
\Drupal::setContainer($container);
$redirect_response = new TrustedRedirectResponse('/example');
$redirect_response->setTargetUrl('http://evil-url.com/example');
}
/**
* @covers ::setTargetUrl
*/
public function testSetTargetUrlWithTrustedUrl() {
$redirect_response = new TrustedRedirectResponse('/example');
$redirect_response->setTrustedTargetUrl('http://good-external-url.com/example');
$this->assertEquals('http://good-external-url.com/example', $redirect_response->getTargetUrl());
}
}

View file

@ -8,10 +8,10 @@
namespace Drupal\Tests\Core\Routing;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\PathProcessor\PathProcessorAlias;
use Drupal\Core\PathProcessor\PathProcessorManager;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Routing\RequestContext;
use Drupal\Core\Routing\UrlGenerator;
use Drupal\Tests\UnitTestCase;
@ -23,6 +23,7 @@ use Symfony\Component\Routing\RouteCollection;
/**
* Confirm that the UrlGenerator is functioning properly.
*
* @coversDefaultClass \Drupal\Core\Routing\UrlGenerator
* @group Routing
*/
class UrlGeneratorTest extends UnitTestCase {
@ -70,11 +71,14 @@ class UrlGeneratorTest extends UnitTestCase {
$first_route = new Route('/test/one');
$second_route = new Route('/test/two/{narf}');
$third_route = new Route('/test/two/');
$fourth_route = new Route('/test/four', array(), array(), array(), '', ['https']);
$fourth_route = new Route('/test/four', [], [], [], '', ['https']);
$none_route = new Route('', [], [], ['_no_path' => TRUE]);
$routes->add('test_1', $first_route);
$routes->add('test_2', $second_route);
$routes->add('test_3', $third_route);
$routes->add('test_4', $fourth_route);
$routes->add('<none>', $none_route);
// Create a route provider stub.
$provider = $this->getMockBuilder('Drupal\Core\Routing\RouteProvider')
@ -85,22 +89,26 @@ class UrlGeneratorTest extends UnitTestCase {
// are not passed in and default to an empty array.
$route_name_return_map = $routes_names_return_map = array();
$return_map_values = array(
array(
[
'route_name' => 'test_1',
'return' => $first_route,
),
array(
],
[
'route_name' => 'test_2',
'return' => $second_route,
),
array(
],
[
'route_name' => 'test_3',
'return' => $third_route,
),
array(
],
[
'route_name' => 'test_4',
'return' => $fourth_route,
),
],
[
'route_name' => '<none>',
'return' => $none_route,
],
);
foreach ($return_map_values as $values) {
$route_name_return_map[] = array($values['route_name'], $values['return']);
@ -139,9 +147,7 @@ class UrlGeneratorTest extends UnitTestCase {
->disableOriginalConstructor()
->getMock();
$config_factory_stub = $this->getConfigFactoryStub(array('system.filter' => array('protocols' => array('http', 'https'))));
$generator = new UrlGenerator($provider, $processor_manager, $this->routeProcessorManager, $config_factory_stub, $this->requestStack);
$generator = new UrlGenerator($provider, $processor_manager, $this->routeProcessorManager, $this->requestStack, ['http', 'https']);
$generator->setContext($context);
$this->generator = $generator;
}
@ -185,7 +191,7 @@ class UrlGeneratorTest extends UnitTestCase {
// Check that the two generate methods return the same result.
$this->assertGenerateFromRoute('test_1', [], [], $url, (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$this->assertGenerateFromRoute('test_1', [], [], $url, (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$path = $this->generator->getPathFromRoute('test_1');
$this->assertEquals('test/one', $path);
@ -217,13 +223,13 @@ class UrlGeneratorTest extends UnitTestCase {
$options = array('fragment' => 'top');
// Extra parameters should appear in the query string.
$this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, '/hello/world?zoo=5#top', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, '/hello/world?zoo=5#top', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$options = array('query' => array('page' => '1'), 'fragment' => 'bottom');
$this->assertGenerateFromRoute('test_2', ['narf' => 5], $options, '/goodbye/cruel/world?page=1#bottom', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$this->assertGenerateFromRoute('test_2', ['narf' => 5], $options, '/goodbye/cruel/world?page=1#bottom', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
// Changing the parameters, the route still matches but there is no alias.
$this->assertGenerateFromRoute('test_2', ['narf' => 7], $options, '/test/two/7?page=1#bottom', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$this->assertGenerateFromRoute('test_2', ['narf' => 7], $options, '/test/two/7?page=1#bottom', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$path = $this->generator->getPathFromRoute('test_2', array('narf' => '5'));
$this->assertEquals('test/two/5', $path);
@ -235,7 +241,7 @@ class UrlGeneratorTest extends UnitTestCase {
* @dataProvider providerTestAliasGenerationWithOptions
*/
public function testAliasGenerationWithOptions($route_name, $route_parameters, $options, $expected) {
$this->assertGenerateFromRoute($route_name, $route_parameters, $options, $expected, (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$this->assertGenerateFromRoute($route_name, $route_parameters, $options, $expected, (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
}
/**
@ -299,7 +305,7 @@ class UrlGeneratorTest extends UnitTestCase {
$options = array('absolute' => TRUE, 'fragment' => 'top');
// Extra parameters should appear in the query string.
$this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, 'http://localhost/hello/world?zoo=5#top', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT)->setCacheContexts(['url.site']));
$this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, 'http://localhost/hello/world?zoo=5#top', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)->setCacheContexts(['url.site']));
}
/**
@ -307,13 +313,13 @@ class UrlGeneratorTest extends UnitTestCase {
*/
public function testBaseURLGeneration() {
$options = array('base_url' => 'http://www.example.com:8888');
$this->assertGenerateFromRoute('test_1', [], $options, 'http://www.example.com:8888/hello/world', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$this->assertGenerateFromRoute('test_1', [], $options, 'http://www.example.com:8888/hello/world', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$options = array('base_url' => 'http://www.example.com:8888', 'https' => TRUE);
$this->assertGenerateFromRoute('test_1', [], $options, 'https://www.example.com:8888/hello/world', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$this->assertGenerateFromRoute('test_1', [], $options, 'https://www.example.com:8888/hello/world', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$options = array('base_url' => 'https://www.example.com:8888', 'https' => FALSE);
$this->assertGenerateFromRoute('test_1', [], $options, 'http://www.example.com:8888/hello/world', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$this->assertGenerateFromRoute('test_1', [], $options, 'http://www.example.com:8888/hello/world', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$this->routeProcessorManager->expects($this->exactly(2))
->method('processOutbound')
@ -321,7 +327,7 @@ class UrlGeneratorTest extends UnitTestCase {
$options = array('base_url' => 'http://www.example.com:8888', 'fragment' => 'top');
// Extra parameters should appear in the query string.
$this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, 'http://www.example.com:8888/hello/world?zoo=5#top', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT));
$this->assertGenerateFromRoute('test_1', ['zoo' => 5], $options, 'http://www.example.com:8888/hello/world?zoo=5#top', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT));
}
/**
@ -338,7 +344,7 @@ class UrlGeneratorTest extends UnitTestCase {
->with($this->anything());
$options = array('absolute' => TRUE, 'https' => TRUE);
$this->assertGenerateFromRoute('test_1', [], $options, 'https://localhost/hello/world', (new CacheableMetadata())->setCacheMaxAge(Cache::PERMANENT)->setCacheContexts(['url.site']));
$this->assertGenerateFromRoute('test_1', [], $options, 'https://localhost/hello/world', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)->setCacheContexts(['url.site']));
}
/**
@ -362,8 +368,8 @@ class UrlGeneratorTest extends UnitTestCase {
$request->headers->set('host', ['www.example.com']);
$this->requestStack->push($request);
// Determine the expected cacheability.
$expected_cacheability = (new CacheableMetadata())
// Determine the expected bubbleable metadata.
$expected_cacheability = (new BubbleableMetadata())
->setCacheContexts($absolute ? ['url.site'] : [])
->setCacheMaxAge(Cache::PERMANENT);
@ -374,46 +380,83 @@ class UrlGeneratorTest extends UnitTestCase {
$this->assertEquals($url, $result, "$url == $result");
$generated_url = $this->generator->generateFromPath('node/123', array('absolute' => $absolute), TRUE);
$this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
$this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
$this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
$url = $base . 'node/123#foo';
$result = $this->generator->generateFromPath('node/123', array('fragment' => 'foo', 'absolute' => $absolute));
$this->assertEquals($url, $result, "$url == $result");
$generated_url = $this->generator->generateFromPath('node/123', array('fragment' => 'foo', 'absolute' => $absolute), TRUE);
$this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
$this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
$this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
$url = $base . 'node/123?foo';
$result = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute));
$this->assertEquals($url, $result, "$url == $result");
$generated_url = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'absolute' => $absolute), TRUE);
$this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
$this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
$this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
$url = $base . 'node/123?foo=bar&bar=baz';
$result = $this->generator->generateFromPath('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute));
$this->assertEquals($url, $result, "$url == $result");
$generated_url = $this->generator->generateFromPath('node/123', array('query' => array('foo' => 'bar', 'bar' => 'baz'), 'absolute' => $absolute), TRUE);
$this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
$this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
$this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
$url = $base . 'node/123?foo#bar';
$result = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute));
$this->assertEquals($url, $result, "$url == $result");
$generated_url = $this->generator->generateFromPath('node/123', array('query' => array('foo' => NULL), 'fragment' => 'bar', 'absolute' => $absolute), TRUE);
$this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
$this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
$this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
$url = $base;
$result = $this->generator->generateFromPath('<front>', array('absolute' => $absolute));
$this->assertEquals($url, $result, "$url == $result");
$generated_url = $this->generator->generateFromPath('<front>', array('absolute' => $absolute), TRUE);
$this->assertEquals($url, $generated_url->getGeneratedUrl(), "$url == $result");
$this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
$this->assertEquals($expected_cacheability, BubbleableMetadata::createFromObject($generated_url));
}
}
}
/**
* Tests generating a relative URL with no path.
*
* @param array $options
* An array of URL options.
* @param string $expected_url
* The expected relative URL.
*
* @covers ::generateFromRoute
*
* @dataProvider providerTestNoPath
*/
public function testNoPath($options, $expected_url) {
$url = $this->generator->generateFromRoute('<none>', [], $options);
$this->assertEquals($expected_url, $url);
}
/**
* Data provider for ::testNoPath().
*/
public function providerTestNoPath() {
return [
// Empty options.
[[], ''],
// Query parameters only.
[['query' => ['foo' => 'bar']], '?foo=bar'],
// Multiple query parameters.
[['query' => ['foo' => 'bar', 'baz' => '']], '?foo=bar&baz='],
// Fragment only.
[['fragment' => 'foo'], '#foo'],
// Query parameters and fragment.
[['query' => ['bar' => 'baz'], 'fragment' => 'foo'], '?bar=baz#foo'],
// Multiple query parameters and fragment.
[['query' => ['bar' => 'baz', 'foo' => 'bar'], 'fragment' => 'foo'], '?bar=baz&foo=bar#foo'],
];
}
/**
* Asserts \Drupal\Core\Routing\UrlGenerator::generateFromRoute()'s output.
*
@ -425,10 +468,10 @@ class UrlGeneratorTest extends UnitTestCase {
* The options to test.
* @param $expected_url
* The expected generated URL string.
* @param \Drupal\Core\Cache\CacheableMetadata $expected_cacheability
* The expected generated cacheability metadata.
* @param \Drupal\Core\Render\BubbleableMetadata $expected_bubbleable_metadata
* The expected generated bubbleable metadata.
*/
protected function assertGenerateFromRoute($route_name, array $route_parameters, array $options, $expected_url, CacheableMetadata $expected_cacheability) {
protected function assertGenerateFromRoute($route_name, array $route_parameters, array $options, $expected_url, BubbleableMetadata $expected_bubbleable_metadata) {
// First, test with $collect_cacheability_metadata set to the default value.
$url = $this->generator->generateFromRoute($route_name, $route_parameters, $options);
$this->assertSame($expected_url, $url);
@ -436,7 +479,7 @@ class UrlGeneratorTest extends UnitTestCase {
// Second, test with it set to TRUE.
$generated_url = $this->generator->generateFromRoute($route_name, $route_parameters, $options, TRUE);
$this->assertSame($expected_url, $generated_url->getGeneratedUrl());
$this->assertEquals($expected_cacheability, CacheableMetadata::createFromObject($generated_url));
$this->assertEquals($expected_bubbleable_metadata, BubbleableMetadata::createFromObject($generated_url));
}
}

View file

@ -51,7 +51,7 @@ class SessionConfigurationTest extends UnitTestCase {
public function providerTestGeneratedCookieDomain() {
return [
['http://example.com/path/index.php', '.example.com'],
['http://www.example.com/path/index.php', '.example.com'],
['http://www.example.com/path/index.php', '.www.example.com'],
['http://subdomain.example.com/path/index.php', '.subdomain.example.com'],
['http://example.com:8080/path/index.php', '.example.com'],
['https://example.com/path/index.php', '.example.com'],

View file

@ -118,4 +118,17 @@ class SettingsTest extends UnitTestCase {
serialize(new Settings([]));
}
/**
* Tests Settings::getApcuPrefix().
*
* @covers ::getApcuPrefix
*/
public function testGetApcuPrefix() {
$settings = new Settings(array('hash_salt' => 123));
$this->assertNotEquals($settings::getApcuPrefix('cache_test', '/test/a'), $settings::getApcuPrefix('cache_test', '/test/b'));
$settings = new Settings(array('hash_salt' => 123, 'apcu_ensure_unique_prefix' => FALSE));
$this->assertNotEquals($settings::getApcuPrefix('cache_test', '/test/a'), $settings::getApcuPrefix('cache_test', '/test/b'));
}
}

View file

@ -89,8 +89,8 @@ class UrlTest extends UnitTestCase {
array('non-existent', NULL, FALSE, 'non-existent'),
);
// $this->map has $collect_cacheability_metadata = FALSE; also generate the
// $collect_cacheability_metadata = TRUE case for ::generateFromRoute().
// $this->map has $collect_bubbleable_metadata = FALSE; also generate the
// $collect_bubbleable_metadata = TRUE case for ::generateFromRoute().
$generate_from_route_map = [];
foreach ($this->map as $values) {
$generate_from_route_map[] = $values;
@ -382,7 +382,7 @@ class UrlTest extends UnitTestCase {
$this->assertSame($path, $url->toString());
$generated_url = $url->toString(TRUE);
$this->assertSame($path, $generated_url->getGeneratedUrl());
$this->assertInstanceOf('\Drupal\Core\Cache\CacheableMetadata', $generated_url);
$this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_url);
}
}
@ -779,7 +779,7 @@ class UrlTest extends UnitTestCase {
/**
* @expectedException \InvalidArgumentException
* @expectedExceptionMessage The route URI "route:" is invalid.
* @expectedExceptionMessage The route URI 'route:' is invalid.
*/
public function testFromRouteUriWithMissingRouteName() {
Url::fromUri('route:');

View file

@ -43,6 +43,13 @@ class LinkGeneratorTest extends UnitTestCase {
*/
protected $moduleHandler;
/**
* The mocked renderer service.
*
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Render\RendererInterface
*/
protected $renderer;
/**
* The mocked URL Assembler service.
*
@ -68,8 +75,8 @@ class LinkGeneratorTest extends UnitTestCase {
$this->urlGenerator = $this->getMock('\Drupal\Core\Routing\UrlGenerator', array(), array(), '', FALSE);
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
$this->linkGenerator = new LinkGenerator($this->urlGenerator, $this->moduleHandler);
$this->renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
$this->linkGenerator = new LinkGenerator($this->urlGenerator, $this->moduleHandler, $this->renderer);
$this->urlAssembler = $this->getMock('\Drupal\Core\Utility\UnroutedUrlAssemblerInterface');
}
@ -462,12 +469,12 @@ class LinkGeneratorTest extends UnitTestCase {
}
/**
* Tests the LinkGenerator's support for collecting cacheability metadata.
* Tests the LinkGenerator's support for collecting bubbleable metadata.
*
* @see \Drupal\Core\Utility\LinkGenerator::generate()
* @see \Drupal\Core\Utility\LinkGenerator::generateFromLink()
*/
public function testGenerateCacheability() {
public function testGenerateBubbleableMetadata() {
$options = ['query' => [], 'language' => NULL, 'set_active_class' => FALSE, 'absolute' => FALSE];
$this->urlGenerator->expects($this->any())
->method('generateFromRoute')
@ -484,14 +491,14 @@ class LinkGeneratorTest extends UnitTestCase {
$this->assertSame($expected_link_markup, $this->linkGenerator->generate('Test', $url));
$generated_link = $this->linkGenerator->generate('Test', $url, TRUE);
$this->assertSame($expected_link_markup, $generated_link->getGeneratedLink());
$this->assertInstanceOf('\Drupal\Core\Cache\CacheableMetadata', $generated_link);
$this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_link);
// Test ::generateFromLink().
$link = new Link('Test', $url);
$this->assertSame($expected_link_markup, $this->linkGenerator->generateFromLink($link));
$generated_link = $this->linkGenerator->generateFromLink($link, TRUE);
$this->assertSame($expected_link_markup, $generated_link->getGeneratedLink());
$this->assertInstanceOf('\Drupal\Core\Cache\CacheableMetadata', $generated_link);
$this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_link);
}
/**

View file

@ -7,7 +7,10 @@
namespace Drupal\Tests\Core\Utility;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Utility\Token;
use Drupal\Tests\UnitTestCase;
@ -59,6 +62,20 @@ class TokenTest extends UnitTestCase {
*/
protected $cacheTagsInvalidator;
/**
* The cache contexts manager.
*
* @var \Drupal\Core\Cache\Context\CacheContextsManager
*/
protected $cacheContextManager;
/**
* The renderer.
*
* @var \Drupal\Core\Render\RendererInterface|\PHPUnit_Framework_MockObject_MockObject
*/
protected $renderer;
/**
* {@inheritdoc}
*/
@ -73,7 +90,17 @@ class TokenTest extends UnitTestCase {
$this->cacheTagsInvalidator = $this->getMock('\Drupal\Core\Cache\CacheTagsInvalidatorInterface');
$this->token = new Token($this->moduleHandler, $this->cache, $this->languageManager, $this->cacheTagsInvalidator);
$this->renderer = $this->getMock('Drupal\Core\Render\RendererInterface');
$this->token = new Token($this->moduleHandler, $this->cache, $this->languageManager, $this->cacheTagsInvalidator, $this->renderer);
$container = new ContainerBuilder();
$this->cacheContextManager = new CacheContextsManager($container, [
'current_user',
'custom_context'
]);
$container->set('cache_contexts_manager', $this->cacheContextManager);
\Drupal::setContainer($container);
}
/**
@ -122,6 +149,108 @@ class TokenTest extends UnitTestCase {
$this->token->getInfo();
}
/**
* @covers ::replace
*/
public function testReplaceWithBubbleableMetadataObject() {
$this->moduleHandler->expects($this->any())
->method('invokeAll')
->willReturn(['[node:title]' => 'hello world']);
$bubbleable_metadata = new BubbleableMetadata();
$bubbleable_metadata->setCacheContexts(['current_user']);
$bubbleable_metadata->setCacheMaxAge(12);
$node = $this->prophesize('Drupal\node\NodeInterface');
$node->getCacheTags()->willReturn(['node:1']);
$node->getCacheContexts()->willReturn(['custom_context']);
$node->getCacheMaxAge()->willReturn(10);
$node = $node->reveal();
$result = $this->token->replace('[node:title]', ['node' => $node], [], $bubbleable_metadata);
$this->assertEquals('hello world', $result);
$this->assertEquals(['node:1'], $bubbleable_metadata->getCacheTags());
$this->assertEquals([
'current_user',
'custom_context'
], $bubbleable_metadata->getCacheContexts());
$this->assertEquals(10, $bubbleable_metadata->getCacheMaxAge());
}
/**
* @covers ::replace
*/
public function testReplaceWithHookTokensWithBubbleableMetadata() {
$this->moduleHandler->expects($this->any())
->method('invokeAll')
->willReturnCallback(function ($hook_name, $args) {
$cacheable_metadata = $args[4];
$cacheable_metadata->addCacheContexts(['custom_context']);
$cacheable_metadata->addCacheTags(['node:1']);
$cacheable_metadata->setCacheMaxAge(10);
return ['[node:title]' => 'hello world'];
});
$node = $this->prophesize('Drupal\node\NodeInterface');
$node->getCacheContexts()->willReturn([]);
$node->getCacheTags()->willReturn([]);
$node->getCacheMaxAge()->willReturn(14);
$node = $node->reveal();
$bubbleable_metadata = new BubbleableMetadata();
$bubbleable_metadata->setCacheContexts(['current_user']);
$bubbleable_metadata->setCacheMaxAge(12);
$result = $this->token->replace('[node:title]', ['node' => $node], [], $bubbleable_metadata);
$this->assertEquals('hello world', $result);
$this->assertEquals(['node:1'], $bubbleable_metadata->getCacheTags());
$this->assertEquals([
'current_user',
'custom_context'
], $bubbleable_metadata->getCacheContexts());
$this->assertEquals(10, $bubbleable_metadata->getCacheMaxAge());
}
/**
* @covers ::replace
* @covers ::replace
*/
public function testReplaceWithHookTokensAlterWithBubbleableMetadata() {
$this->moduleHandler->expects($this->any())
->method('invokeAll')
->willReturn([]);
$this->moduleHandler->expects($this->any())
->method('alter')
->willReturnCallback(function ($hook_name, array &$replacements, array $context, BubbleableMetadata $bubbleable_metadata) {
$replacements['[node:title]'] = 'hello world';
$bubbleable_metadata->addCacheContexts(['custom_context']);
$bubbleable_metadata->addCacheTags(['node:1']);
$bubbleable_metadata->setCacheMaxAge(10);
});
$node = $this->prophesize('Drupal\node\NodeInterface');
$node->getCacheContexts()->willReturn([]);
$node->getCacheTags()->willReturn([]);
$node->getCacheMaxAge()->willReturn(14);
$node = $node->reveal();
$bubbleable_metadata = new BubbleableMetadata();
$bubbleable_metadata->setCacheContexts(['current_user']);
$bubbleable_metadata->setCacheMaxAge(12);
$result = $this->token->replace('[node:title]', ['node' => $node], [], $bubbleable_metadata);
$this->assertEquals('hello world', $result);
$this->assertEquals(['node:1'], $bubbleable_metadata->getCacheTags());
$this->assertEquals([
'current_user',
'custom_context'
], $bubbleable_metadata->getCacheContexts());
$this->assertEquals(10, $bubbleable_metadata->getCacheMaxAge());
}
/**
* @covers ::resetInfo
*/

View file

@ -7,8 +7,8 @@
namespace Drupal\Tests\Core\Utility;
use Drupal\Core\Cache\CacheableMetadata;
use Drupal\Core\GeneratedUrl;
use Drupal\Core\Render\BubbleableMetadata;
use Drupal\Core\Utility\UnroutedUrlAssembler;
use Drupal\Tests\UnitTestCase;
use Symfony\Component\HttpFoundation\Request;
@ -55,9 +55,8 @@ class UnroutedUrlAssemblerTest extends UnitTestCase {
parent::setUp();
$this->requestStack = new RequestStack();
$this->configFactory = $this->getConfigFactoryStub(['system.filter' => []]);
$this->pathProcessor = $this->getMock('Drupal\Core\PathProcessor\OutboundPathProcessorInterface');
$this->unroutedUrlAssembler = new UnroutedUrlAssembler($this->requestStack, $this->configFactory, $this->pathProcessor);
$this->unroutedUrlAssembler = new UnroutedUrlAssembler($this->requestStack, $this->pathProcessor);
}
/**
@ -87,7 +86,7 @@ class UnroutedUrlAssemblerTest extends UnitTestCase {
$this->assertEquals($expected, $this->unroutedUrlAssembler->assemble($uri, $options));
$generated_url = $this->unroutedUrlAssembler->assemble($uri, $options, TRUE);
$this->assertEquals($expected, $generated_url->getGeneratedUrl());
$this->assertInstanceOf('\Drupal\Core\Cache\CacheableMetadata', $generated_url);
$this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_url);
}
/**
@ -153,9 +152,9 @@ class UnroutedUrlAssemblerTest extends UnitTestCase {
$this->setupRequestStack(FALSE);
$this->pathProcessor->expects($this->exactly(2))
->method('processOutbound')
->willReturnCallback(function($path, &$options = [], Request $request = NULL, CacheableMetadata $cacheable_metadata = NULL) {
if ($cacheable_metadata) {
$cacheable_metadata->setCacheContexts(['some-cache-context']);
->willReturnCallback(function($path, &$options = [], Request $request = NULL, BubbleableMetadata $bubbleable_metadata = NULL) {
if ($bubbleable_metadata) {
$bubbleable_metadata->setCacheContexts(['some-cache-context']);
}
return 'test-other-uri';
});