Update to drupal 8.0.0-rc1. For more information, see https://www.drupal.org/node/2582663
This commit is contained in:
parent
eb34d130a8
commit
f32e58e4b1
8476 changed files with 211648 additions and 170042 deletions
92
core/tests/Drupal/KernelTests/AssertConfigTrait.php
Normal file
92
core/tests/Drupal/KernelTests/AssertConfigTrait.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\KernelTests\AssertConfigTrait.
|
||||
*/
|
||||
|
||||
namespace Drupal\KernelTests;
|
||||
|
||||
use Drupal\Component\Diff\Diff;
|
||||
|
||||
/**
|
||||
* Trait to help with diffing config.
|
||||
*/
|
||||
trait AssertConfigTrait {
|
||||
|
||||
/**
|
||||
* Ensures that a specific config diff does not contain unwanted changes.
|
||||
*
|
||||
* @param \Drupal\Component\Diff\Diff $result
|
||||
* The diff result for the passed in config name.
|
||||
* @param string $config_name
|
||||
* The config name to check.
|
||||
* @param array $skipped_config
|
||||
* An array of skipped config, keyed by string. If the value is TRUE, the
|
||||
* entire file will be ignored, otherwise it's an array of strings which are
|
||||
* ignored.
|
||||
*
|
||||
* @throws \Exception
|
||||
* Thrown when a configuration is different.
|
||||
*/
|
||||
protected function assertConfigDiff(Diff $result, $config_name, array $skipped_config) {
|
||||
foreach ($result->getEdits() as $op) {
|
||||
switch (get_class($op)) {
|
||||
case 'Drupal\Component\Diff\Engine\DiffOpCopy':
|
||||
// Nothing to do, a copy is what we expect.
|
||||
break;
|
||||
case 'Drupal\Component\Diff\Engine\DiffOpDelete':
|
||||
case 'Drupal\Component\Diff\Engine\DiffOpChange':
|
||||
// It is not part of the skipped config, so we can directly throw the
|
||||
// exception.
|
||||
if (!in_array($config_name, array_keys($skipped_config))) {
|
||||
throw new \Exception($config_name . ': ' . var_export($op, TRUE));
|
||||
}
|
||||
|
||||
// Allow to skip entire config files.
|
||||
if ($skipped_config[$config_name] === TRUE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Allow to skip some specific lines of imported config files.
|
||||
// Ensure that the only changed lines are the ones we marked as
|
||||
// skipped.
|
||||
$all_skipped = TRUE;
|
||||
|
||||
$changes = get_class($op) == 'Drupal\Component\Diff\Engine\DiffOpDelete' ? $op->orig : $op->closing;
|
||||
foreach ($changes as $closing) {
|
||||
// Skip some of the changes, as they are caused by module install
|
||||
// code.
|
||||
$found = FALSE;
|
||||
if (!empty($skipped_config[$config_name])) {
|
||||
foreach ($skipped_config[$config_name] as $line) {
|
||||
if (strpos($closing, $line) !== FALSE) {
|
||||
$found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$all_skipped = $all_skipped && $found;
|
||||
}
|
||||
|
||||
if (!$all_skipped) {
|
||||
throw new \Exception($config_name . ': ' . var_export($op, TRUE));
|
||||
}
|
||||
break;
|
||||
case 'Drupal\Component\Diff\Engine\DiffOpAdd':
|
||||
foreach ($op->closing as $closing) {
|
||||
// The UUIDs don't exist in the default config.
|
||||
if (strpos($closing, 'uuid: ') === 0) {
|
||||
continue;
|
||||
}
|
||||
throw new \Exception($config_name . ': ' . var_export($op, TRUE));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new \Exception($config_name . ': ' . var_export($op, TRUE));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\KernelTests\Component\Utility\SafeMarkupKernelTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\KernelTests\Component\Utility;
|
||||
|
||||
use Drupal\Component\FileCache\FileCacheFactory;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Provides a test covering integration of SafeMarkup with other systems.
|
||||
*
|
||||
* @group Utility
|
||||
*/
|
||||
class SafeMarkupKernelTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['system'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installSchema('system', 'router');
|
||||
$this->container->get('router.builder')->rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets arguments for SafeMarkup::format() based on Url::fromUri() parameters.
|
||||
*
|
||||
* @param string $uri
|
||||
* The URI of the resource.
|
||||
*
|
||||
* @param array $options
|
||||
* The options to pass to Url::fromUri().
|
||||
*
|
||||
* @return array
|
||||
* Array containing:
|
||||
* - ':url': A URL string.
|
||||
*/
|
||||
protected static function getSafeMarkupUriArgs($uri, $options = []) {
|
||||
$args[':url'] = Url::fromUri($uri, $options)->toString();
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests URL ":placeholders" in SafeMarkup::format().
|
||||
*
|
||||
* @dataProvider providerTestSafeMarkupUri
|
||||
*/
|
||||
public function testSafeMarkupUri($string, $uri, $options, $expected) {
|
||||
$args = self::getSafeMarkupUriArgs($uri, $options);
|
||||
$this->assertEquals($expected, SafeMarkup::format($string, $args));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function providerTestSafeMarkupUri() {
|
||||
$data = [];
|
||||
$data['routed-url'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
'route:system.admin',
|
||||
[],
|
||||
'Hey giraffe <a href="/admin">MUUUH</a>',
|
||||
];
|
||||
$data['routed-with-query'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
'route:system.admin',
|
||||
['query' => ['bar' => 'baz#']],
|
||||
'Hey giraffe <a href="/admin?bar=baz%23">MUUUH</a>',
|
||||
];
|
||||
$data['routed-with-fragment'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
'route:system.admin',
|
||||
['fragment' => 'bar<'],
|
||||
'Hey giraffe <a href="/admin#bar&lt;">MUUUH</a>',
|
||||
];
|
||||
$data['unrouted-url'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
'base://foo',
|
||||
[],
|
||||
'Hey giraffe <a href="/foo">MUUUH</a>',
|
||||
];
|
||||
$data['unrouted-with-query'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
'base://foo',
|
||||
['query' => ['bar' => 'baz#']],
|
||||
'Hey giraffe <a href="/foo?bar=baz%23">MUUUH</a>',
|
||||
];
|
||||
$data['unrouted-with-fragment'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
'base://foo',
|
||||
['fragment' => 'bar<'],
|
||||
'Hey giraffe <a href="/foo#bar&lt;">MUUUH</a>',
|
||||
];
|
||||
$data['mailto-protocol'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
'mailto:test@example.com',
|
||||
[],
|
||||
'Hey giraffe <a href="mailto:test@example.com">MUUUH</a>',
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerTestSafeMarkupUriWithException
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testSafeMarkupUriWithExceptionUri($string, $uri) {
|
||||
// Should throw an \InvalidArgumentException, due to Uri::toString().
|
||||
$args = self::getSafeMarkupUriArgs($uri);
|
||||
|
||||
SafeMarkup::format($string, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function providerTestSafeMarkupUriWithException() {
|
||||
$data = [];
|
||||
$data['js-protocol'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
"javascript:alert('xss')",
|
||||
];
|
||||
$data['js-with-fromCharCode'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
"javascript:alert(String.fromCharCode(88,83,83))",
|
||||
];
|
||||
$data['non-url-with-colon'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
"llamas: they are not URLs",
|
||||
];
|
||||
$data['non-url-with-html'] = [
|
||||
'Hey giraffe <a href=":url">MUUUH</a>',
|
||||
'<span>not a url</span>',
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
119
core/tests/Drupal/KernelTests/Config/DefaultConfigTest.php
Normal file
119
core/tests/Drupal/KernelTests/Config/DefaultConfigTest.php
Normal file
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\KernelTests\Config\DefaultConfigTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\KernelTests\Config;
|
||||
|
||||
use Drupal\Component\FileCache\FileCacheFactory;
|
||||
use Drupal\Core\Config\FileStorage;
|
||||
use Drupal\Core\Config\InstallStorage;
|
||||
use Drupal\Core\Config\StorageInterface;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\KernelTests\AssertConfigTrait;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests that the installed config matches the default config.
|
||||
*
|
||||
* @group Config
|
||||
*/
|
||||
class DefaultConfigTest extends KernelTestBase {
|
||||
|
||||
use AssertConfigTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected static $timeLimit = 500;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['system', 'user'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
// @todo ModuleInstaller calls system_rebuild_module_data which is part of
|
||||
// system.module, see https://www.drupal.org/node/2208429.
|
||||
include_once $this->root . '/core/modules/system/system.module';
|
||||
|
||||
// Set up the state values so we know where to find the files when running
|
||||
// drupal_get_filename().
|
||||
// @todo Remove as part of https://www.drupal.org/node/2186491
|
||||
system_rebuild_module_data();
|
||||
|
||||
$this->installSchema('system', 'router');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if installed config is equal to the exported config.
|
||||
*
|
||||
* @dataProvider providerTestModuleConfig
|
||||
*/
|
||||
public function testModuleConfig($module) {
|
||||
/** @var \Drupal\Core\Extension\ModuleInstallerInterface $module_installer */
|
||||
$module_installer = $this->container->get('module_installer');
|
||||
/** @var \Drupal\Core\Config\StorageInterface $active_config_storage */
|
||||
$active_config_storage = $this->container->get('config.storage');
|
||||
/** @var \Drupal\Core\Config\ConfigManagerInterface $config_manager */
|
||||
$config_manager = $this->container->get('config.manager');
|
||||
|
||||
$module_installer->install([$module]);
|
||||
|
||||
// System and user are required in order to be able to install some of the
|
||||
// other modules. Therefore they are put into static::$modules, which though
|
||||
// doesn't install config files, so import those config files explicitly.
|
||||
switch ($module) {
|
||||
case 'system':
|
||||
case 'user':
|
||||
$this->installConfig([$module]);
|
||||
break;
|
||||
}
|
||||
|
||||
$default_install_path = drupal_get_path('module', $module) . '/' . InstallStorage::CONFIG_INSTALL_DIRECTORY;
|
||||
$module_config_storage = new FileStorage($default_install_path, StorageInterface::DEFAULT_COLLECTION);
|
||||
|
||||
// The following config entries are changed on module install, so compare
|
||||
// them doesn't make sense.
|
||||
$skipped_config = [];
|
||||
$skipped_config['locale.settings'][] = 'path: ';
|
||||
$skipped_config['syslog.settings'][] = 'facility: ';
|
||||
// @todo Figure out why simpletest.settings is not installed.
|
||||
$skipped_config['simpletest.settings'] = TRUE;
|
||||
|
||||
// Compare the installed config with the one in the module directory.
|
||||
foreach ($module_config_storage->listAll() as $config_name) {
|
||||
$result = $config_manager->diff($module_config_storage, $active_config_storage, $config_name);
|
||||
$this->assertConfigDiff($result, $config_name, $skipped_config);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test data provider for ::testModuleConfig().
|
||||
*
|
||||
* @return array
|
||||
* An array of module names to test.
|
||||
*/
|
||||
public function providerTestModuleConfig() {
|
||||
$module_dirs = array_keys(iterator_to_array(new \FilesystemIterator(__DIR__ . '/../../../../modules/')));
|
||||
$module_names = array_map(function($path) {
|
||||
return str_replace(__DIR__ . '/../../../../modules/', '', $path);
|
||||
}, $module_dirs);
|
||||
$modules_keyed = array_combine($module_names, $module_names);
|
||||
|
||||
$data = array_map(function ($module) {
|
||||
return [$module];
|
||||
}, $modules_keyed);
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\KernelTests\Core\Common\DrupalSetMessageTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\KernelTests\Core\Common;
|
||||
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* @covers ::drupal_set_message
|
||||
* @group PHPUnit
|
||||
*/
|
||||
class DrupalSetMessageTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* The basic functionality of drupal_set_message().
|
||||
*/
|
||||
public function testDrupalSetMessage() {
|
||||
drupal_set_message(t('A message: @foo', ['@foo' => 'bar']));
|
||||
$messages = drupal_get_messages();
|
||||
$this->assertInstanceOf('Drupal\Core\Render\Markup', $messages['status'][0]);
|
||||
$this->assertEquals('A message: bar', (string) $messages['status'][0]);
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
// Clear session to prevent global leakage.
|
||||
unset($_SESSION['messages']);
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\KernelTests\Core\StringTranslation\TranslationStringTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\KernelTests\Core\StringTranslation;
|
||||
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
use Drupal\language\Entity\ConfigurableLanguage;
|
||||
|
||||
/**
|
||||
* Tests the TranslatableMarkup class.
|
||||
*
|
||||
* @group StringTranslation
|
||||
*/
|
||||
class TranslationStringTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = [
|
||||
'language'
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
ConfigurableLanguage::createFromLangcode('de')->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that TranslatableMarkup objects can be compared.
|
||||
*/
|
||||
public function testComparison() {
|
||||
$this->rebootAndPrepareSettings();
|
||||
$a = \Drupal::service('string_translation')->translate('Example @number', ['@number' => 42], ['langcode' => 'de']);
|
||||
|
||||
$this->rebootAndPrepareSettings();
|
||||
$b = \Drupal::service('string_translation')->translate('Example @number', ['@number' => 42], ['langcode' => 'de']);
|
||||
$c = \Drupal::service('string_translation')->translate('Example @number', ['@number' => 43], ['langcode' => 'de']);
|
||||
$d = \Drupal::service('string_translation')->translate('Example @number', ['@number' => 42], ['langcode' => 'en']);
|
||||
|
||||
// The two objects have the same settings so == comparison will work.
|
||||
$this->assertEquals($a, $b);
|
||||
// The two objects are not the same object.
|
||||
$this->assertNotSame($a, $b);
|
||||
// TranslationWrappers which have different settings are not equal.
|
||||
$this->assertNotEquals($a, $c);
|
||||
$this->assertNotEquals($a, $d);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reboots the kernel to set custom translations in Settings.
|
||||
*/
|
||||
protected function rebootAndPrepareSettings() {
|
||||
// Reboot the container so that different services are injected and the new
|
||||
// settings are picked.
|
||||
$kernel = $this->container->get('kernel');
|
||||
$kernel->shutdown();
|
||||
$kernel->boot();
|
||||
$settings = Settings::getAll();
|
||||
$settings['locale_custom_strings_de'] = ['' => ['Example @number' => 'Example @number translated']];
|
||||
// Recreate the settings static.
|
||||
new Settings($settings);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\KernelTests\Core\Theme\ThemeRenderAndAutoescapeTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\KernelTests\Core\Theme;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\Render\RenderContext;
|
||||
use Drupal\Core\Render\Markup;
|
||||
use Drupal\KernelTests\KernelTestBase;
|
||||
|
||||
/**
|
||||
* Tests the theme_render_and_autoescape() function.
|
||||
*
|
||||
* @group Theme
|
||||
*/
|
||||
class ThemeRenderAndAutoescapeTest extends KernelTestBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static $modules = ['system'];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installSchema('system', 'router');
|
||||
\Drupal::service('router.builder')->rebuild();
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerTestThemeRenderAndAutoescape
|
||||
*/
|
||||
public function testThemeRenderAndAutoescape($arg, $expected) {
|
||||
if (is_array($arg) && isset($arg['#type']) && $arg['#type'] === 'link') {
|
||||
$arg = Link::createFromRoute($arg['#title'], $arg['#url']);
|
||||
}
|
||||
|
||||
$context = new RenderContext();
|
||||
// Use a closure here since we need to render with a render context.
|
||||
$theme_render_and_autoescape = function () use ($arg) {
|
||||
return theme_render_and_autoescape($arg);
|
||||
};
|
||||
/** @var \Drupal\Core\Render\RendererInterface $renderer */
|
||||
$renderer = \Drupal::service('renderer');
|
||||
$output = $renderer->executeInRenderContext($context, $theme_render_and_autoescape);
|
||||
$this->assertEquals($expected, $output);
|
||||
$this-> assertInternalType('string', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide test examples.
|
||||
*/
|
||||
public function providerTestThemeRenderAndAutoescape() {
|
||||
return [
|
||||
'empty string unchanged' => ['', ''],
|
||||
'simple string unchanged' => ['ab', 'ab'],
|
||||
'int (scalar) cast to string' => [111, '111'],
|
||||
'float (scalar) cast to string' => [2.10, '2.10'],
|
||||
'> is escaped' => ['>', '>'],
|
||||
'Markup EM tag is unchanged' => [Markup::create('<em>hi</em>'), '<em>hi</em>'],
|
||||
'Markup SCRIPT tag is unchanged' => [Markup::create('<script>alert("hi");</script>'), '<script>alert("hi");</script>'],
|
||||
'EM tag in string is escaped' => ['<em>hi</em>', Html::escape('<em>hi</em>')],
|
||||
'type link render array is rendered' => [['#type' => 'link', '#title' => 'Text', '#url' => '<none>'], '<a href="">Text</a>'],
|
||||
'type markup with EM tags is rendered' => [['#markup' => '<em>hi</em>'], '<em>hi</em>'],
|
||||
'SCRIPT tag in string is escaped' => [
|
||||
'<script>alert(123)</script>',
|
||||
Html::escape('<script>alert(123)</script>')
|
||||
],
|
||||
'type plain_text render array EM tag is escaped' => [['#plain_text' => '<em>hi</em>'], Html::escape('<em>hi</em>')],
|
||||
'type hidden render array is rendered' => [['#type' => 'hidden', '#name' => 'foo', '#value' => 'bar'], "<input type=\"hidden\" name=\"foo\" value=\"bar\" />\n"],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures invalid content is handled correctly.
|
||||
*
|
||||
* @expectedException \Exception
|
||||
*/
|
||||
public function testThemeEscapeAndRenderNotPrintable() {
|
||||
theme_render_and_autoescape(new NonPrintable());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class NonPrintable { }
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
namespace Drupal\KernelTests;
|
||||
|
||||
use Drupal\Component\FileCache\ApcuFileCacheBackend;
|
||||
use Drupal\Component\FileCache\FileCache;
|
||||
use Drupal\Component\FileCache\FileCacheFactory;
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Config\ConfigImporter;
|
||||
|
@ -20,6 +23,7 @@ use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
|
|||
use Drupal\Core\Extension\ExtensionDiscovery;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\simpletest\AssertContentTrait;
|
||||
use Drupal\simpletest\AssertHelperTrait;
|
||||
use Drupal\simpletest\RandomGeneratorTrait;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -52,6 +56,7 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
|
||||
use AssertLegacyTrait;
|
||||
use AssertContentTrait;
|
||||
use AssertHelperTrait;
|
||||
use RandomGeneratorTrait;
|
||||
|
||||
/**
|
||||
|
@ -212,6 +217,7 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
parent::setUp();
|
||||
|
||||
$this->root = static::getDrupalRoot();
|
||||
$this->initFileCache();
|
||||
$this->bootEnvironment();
|
||||
$this->bootKernel();
|
||||
}
|
||||
|
@ -254,8 +260,7 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
$this->siteDirectory = vfsStream::url('root/sites/simpletest/' . $suffix);
|
||||
|
||||
mkdir($this->siteDirectory . '/files', 0775);
|
||||
mkdir($this->siteDirectory . '/files/config/' . CONFIG_ACTIVE_DIRECTORY, 0775, TRUE);
|
||||
mkdir($this->siteDirectory . '/files/config/' . CONFIG_STAGING_DIRECTORY, 0775, TRUE);
|
||||
mkdir($this->siteDirectory . '/files/config/' . CONFIG_SYNC_DIRECTORY, 0775, TRUE);
|
||||
|
||||
// Ensure that all code that relies on drupal_valid_test_ua() can still be
|
||||
// safely executed. This primarily affects the (test) site directory
|
||||
|
@ -273,8 +278,7 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
new Settings($settings);
|
||||
|
||||
$GLOBALS['config_directories'] = array(
|
||||
CONFIG_ACTIVE_DIRECTORY => $this->siteDirectory . '/files/config/active',
|
||||
CONFIG_STAGING_DIRECTORY => $this->siteDirectory . '/files/config/staging',
|
||||
CONFIG_SYNC_DIRECTORY => $this->siteDirectory . '/files/config/sync',
|
||||
);
|
||||
|
||||
foreach (Database::getAllConnectionInfo() as $key => $targets) {
|
||||
|
@ -343,6 +347,14 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
// register() is only called if a new container was built/compiled.
|
||||
$this->container = $kernel->getContainer();
|
||||
|
||||
// Ensure database tasks have been run.
|
||||
require_once __DIR__ . '/../../../includes/install.inc';
|
||||
$connection = Database::getConnection();
|
||||
$errors = db_installer_object($connection->driver())->runTasks();
|
||||
if (!empty($errors)) {
|
||||
$this->fail('Failed to run installer database tasks: ' . implode(', ', $errors));
|
||||
}
|
||||
|
||||
if ($modules) {
|
||||
$this->container->get('module_handler')->loadAll();
|
||||
}
|
||||
|
@ -394,17 +406,17 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
protected function getDatabaseConnectionInfo() {
|
||||
// If the test is run with argument dburl then use it.
|
||||
$db_url = getenv('SIMPLETEST_DB');
|
||||
if (!empty($db_url)) {
|
||||
if (empty($db_url)) {
|
||||
$this->markTestSkipped('There is no database connection so no tests can be run. You must provide a SIMPLETEST_DB environment variable to run PHPUnit based functional tests outside of run-tests.sh. See https://www.drupal.org/node/2116263#skipped-tests for more information.');
|
||||
}
|
||||
else {
|
||||
$database = Database::convertDbUrlToConnectionInfo($db_url, $this->root);
|
||||
Database::addConnectionInfo('default', 'default', $database);
|
||||
}
|
||||
|
||||
// Clone the current connection and replace the current prefix.
|
||||
$connection_info = Database::getConnectionInfo('default');
|
||||
if (is_null($connection_info)) {
|
||||
throw new \InvalidArgumentException('There is no database connection so no tests can be run. You must provide a SIMPLETEST_DB environment variable, like "sqlite://localhost//tmp/test.sqlite", to run PHPUnit based functional tests outside of run-tests.sh.');
|
||||
}
|
||||
else {
|
||||
if (!empty($connection_info)) {
|
||||
Database::renameConnection('default', 'simpletest_original_default');
|
||||
foreach ($connection_info as $target => $value) {
|
||||
// Replace the full table prefix definition to ensure that no table
|
||||
|
@ -479,6 +491,32 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
return $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the FileCache component.
|
||||
*
|
||||
* We can not use the Settings object in a component, that's why we have to do
|
||||
* it here instead of \Drupal\Component\FileCache\FileCacheFactory.
|
||||
*/
|
||||
protected function initFileCache() {
|
||||
$configuration = Settings::get('file_cache');
|
||||
|
||||
// Provide a default configuration, if not set.
|
||||
if (!isset($configuration['default'])) {
|
||||
$configuration['default'] = [
|
||||
'class' => FileCache::class,
|
||||
'cache_backend_class' => NULL,
|
||||
'cache_backend_configuration' => [],
|
||||
];
|
||||
// @todo Use extension_loaded('apcu') for non-testbot
|
||||
// https://www.drupal.org/node/2447753.
|
||||
if (function_exists('apc_fetch')) {
|
||||
$configuration['default']['cache_backend_class'] = ApcuFileCacheBackend::class;
|
||||
}
|
||||
}
|
||||
FileCacheFactory::setConfiguration($configuration);
|
||||
FileCacheFactory::setPrefix(Settings::getApcuPrefix('file_cache', $this->root));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Extension objects for $modules to enable.
|
||||
*
|
||||
|
@ -625,6 +663,9 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
}
|
||||
}
|
||||
|
||||
// Clean FileCache cache.
|
||||
FileCache::reset();
|
||||
|
||||
// Clean up statics, container, and settings.
|
||||
if (function_exists('drupal_static_reset')) {
|
||||
drupal_static_reset();
|
||||
|
@ -863,8 +904,14 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
* The rendered string output (typically HTML).
|
||||
*/
|
||||
protected function render(array &$elements) {
|
||||
$content = $this->container->get('renderer')->render($elements);
|
||||
drupal_process_attached($elements);
|
||||
// Use the bare HTML page renderer to render our links.
|
||||
$renderer = $this->container->get('bare_html_page_renderer');
|
||||
$response = $renderer->renderBarePage(
|
||||
$elements, '', $this->container->get('theme.manager')->getActiveTheme()->getName()
|
||||
);
|
||||
|
||||
// Glean the content from the response object.
|
||||
$content = $response->getContent();
|
||||
$this->setRawContent($content);
|
||||
$this->verbose('<pre style="white-space: pre-wrap">' . Html::escape($content));
|
||||
return $content;
|
||||
|
@ -896,7 +943,7 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
if (!$this->configImporter) {
|
||||
// Set up the ConfigImporter object for testing.
|
||||
$storage_comparer = new StorageComparer(
|
||||
$this->container->get('config.storage.staging'),
|
||||
$this->container->get('config.storage.sync'),
|
||||
$this->container->get('config.storage'),
|
||||
$this->container->get('config.manager')
|
||||
);
|
||||
|
@ -1025,7 +1072,7 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
trigger_error(sprintf("KernelTestBase::\$%s no longer exists. Use the regular API method to retrieve it instead (e.g., Settings).", $name), E_USER_DEPRECATED);
|
||||
switch ($name) {
|
||||
case 'public_files_directory':
|
||||
return Settings::get('file_public_path', conf_path() . '/files');
|
||||
return Settings::get('file_public_path', \Drupal::service('site.path') . '/files');
|
||||
|
||||
case 'private_files_directory':
|
||||
return $this->container->get('config.factory')->get('system.file')->get('path.private');
|
||||
|
@ -1034,15 +1081,14 @@ abstract class KernelTestBase extends \PHPUnit_Framework_TestCase implements Ser
|
|||
return file_directory_temp();
|
||||
|
||||
case 'translation_files_directory':
|
||||
return Settings::get('file_public_path', conf_path() . '/translations');
|
||||
return Settings::get('file_public_path', \Drupal::service('site.path') . '/translations');
|
||||
}
|
||||
}
|
||||
|
||||
if ($name === 'configDirectories') {
|
||||
trigger_error(sprintf("KernelTestBase::\$%s no longer exists. Use config_get_config_directory() directly instead.", $name), E_USER_DEPRECATED);
|
||||
return array(
|
||||
CONFIG_ACTIVE_DIRECTORY => config_get_config_directory(CONFIG_ACTIVE_DIRECTORY),
|
||||
CONFIG_STAGING_DIRECTORY => config_get_config_directory(CONFIG_STAGING_DIRECTORY),
|
||||
CONFIG_SYNC_DIRECTORY => config_get_config_directory(CONFIG_SYNC_DIRECTORY),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\KernelTests;
|
||||
|
||||
use Drupal\Component\FileCache\FileCacheFactory;
|
||||
use Drupal\Core\Database\Database;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
use org\bovigo\vfs\visitor\vfsStreamStructureVisitor;
|
||||
|
@ -38,8 +39,7 @@ class KernelTestBaseTest extends KernelTestBase {
|
|||
substr($this->databasePrefix, 10) => array(
|
||||
'files' => array(
|
||||
'config' => array(
|
||||
'active' => array(),
|
||||
'staging' => array(),
|
||||
'sync' => array(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -74,8 +74,8 @@ class KernelTestBaseTest extends KernelTestBase {
|
|||
$GLOBALS['destroy-me'] = TRUE;
|
||||
$this->assertArrayHasKey('destroy-me', $GLOBALS);
|
||||
|
||||
$schema = $this->container->get('database')->schema();
|
||||
$schema->createTable('foo', array(
|
||||
$database = $this->container->get('database');
|
||||
$database->schema()->createTable('foo', array(
|
||||
'fields' => array(
|
||||
'number' => array(
|
||||
'type' => 'int',
|
||||
|
@ -84,7 +84,16 @@ class KernelTestBaseTest extends KernelTestBase {
|
|||
),
|
||||
),
|
||||
));
|
||||
$this->assertTrue($schema->tableExists('foo'));
|
||||
$this->assertTrue($database->schema()->tableExists('foo'));
|
||||
|
||||
// Ensure that the database tasks have been run during set up. Neither MySQL
|
||||
// nor SQLite make changes that are testable.
|
||||
if ($database->driver() == 'pgsql') {
|
||||
$this->assertEquals('on', $database->query("SHOW standard_conforming_strings")->fetchField());
|
||||
$this->assertEquals('escape', $database->query("SHOW bytea_output")->fetchField());
|
||||
}
|
||||
|
||||
$this->assertNotNull(FileCacheFactory::getPrefix());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,12 +31,36 @@ class InspectorTest extends PHPUnit_Framework_TestCase {
|
|||
* Tests asserting all members are strings.
|
||||
*
|
||||
* @covers ::assertAllStrings
|
||||
* @dataProvider providerTestAssertAllStrings
|
||||
*/
|
||||
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()]));
|
||||
public function testAssertAllStrings($input, $expected) {
|
||||
$this->assertSame($expected, Inspector::assertAllStrings($input));
|
||||
}
|
||||
|
||||
public function providerTestAssertAllStrings() {
|
||||
$data = [
|
||||
'empty-array' => [[], TRUE],
|
||||
'array-with-strings' => [['foo', 'bar'], TRUE],
|
||||
'string' => ['foo', FALSE],
|
||||
'array-with-strings-with-colon' => [['foo', 'bar', 'llama:2001988', 'baz', 'llama:14031991'], TRUE],
|
||||
|
||||
'with-FALSE' => [[FALSE], FALSE],
|
||||
'with-TRUE' => [[TRUE], FALSE],
|
||||
'with-string-and-boolean' => [['foo', FALSE], FALSE],
|
||||
'with-NULL' => [[NULL], FALSE],
|
||||
'string-with-NULL' => [['foo', NULL], FALSE],
|
||||
'integer' => [[1337], FALSE],
|
||||
'string-and-integer' => [['foo', 1337], FALSE],
|
||||
'double' => [[3.14], FALSE],
|
||||
'string-and-double' => [['foo', 3.14], FALSE],
|
||||
'array' => [[[]], FALSE],
|
||||
'string-and-array' => [['foo', []], FALSE],
|
||||
'string-and-nested-array' => [['foo', ['bar']], FALSE],
|
||||
'object' => [[new \stdClass()], FALSE],
|
||||
'string-and-object' => [['foo', new StringObject()], FALSE],
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,7 +7,11 @@
|
|||
|
||||
namespace Drupal\Tests\Component\Plugin;
|
||||
|
||||
use Drupal\Component\Plugin\Definition\PluginDefinitionInterface;
|
||||
use Drupal\Component\Plugin\Factory\DefaultFactory;
|
||||
use Drupal\plugin_test\Plugin\plugin_test\fruit\Cherry;
|
||||
use Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface;
|
||||
use Drupal\plugin_test\Plugin\plugin_test\fruit\Kale;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -17,41 +21,110 @@ use Drupal\Tests\UnitTestCase;
|
|||
class DefaultFactoryTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Tests getPluginClass() with a valid plugin.
|
||||
* Tests getPluginClass() with a valid array plugin definition.
|
||||
*
|
||||
* @covers ::getPluginClass
|
||||
*/
|
||||
public function testGetPluginClassWithValidPlugin() {
|
||||
$plugin_class = 'Drupal\plugin_test\Plugin\plugin_test\fruit\Cherry';
|
||||
public function testGetPluginClassWithValidArrayPluginDefinition() {
|
||||
$plugin_class = Cherry::class;
|
||||
$class = DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class]);
|
||||
|
||||
$this->assertEquals($plugin_class, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getPluginClass() with a valid object plugin definition.
|
||||
*
|
||||
* @covers ::getPluginClass
|
||||
*/
|
||||
public function testGetPluginClassWithValidObjectPluginDefinition() {
|
||||
$plugin_class = Cherry::class;
|
||||
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
|
||||
$plugin_definition->expects($this->atLeastOnce())
|
||||
->method('getClass')
|
||||
->willReturn($plugin_class);
|
||||
$class = DefaultFactory::getPluginClass('cherry', $plugin_definition);
|
||||
|
||||
$this->assertEquals($plugin_class, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getPluginClass() with a missing class definition.
|
||||
*
|
||||
* @covers ::getPluginClass
|
||||
*
|
||||
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
|
||||
* @expectedExceptionMessage The plugin (cherry) did not specify an instance class.
|
||||
*/
|
||||
public function testGetPluginClassWithMissingClass() {
|
||||
public function testGetPluginClassWithMissingClassWithArrayPluginDefinition() {
|
||||
DefaultFactory::getPluginClass('cherry', []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getPluginClass() with a missing class definition.
|
||||
*
|
||||
* @covers ::getPluginClass
|
||||
*
|
||||
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
|
||||
* @expectedExceptionMessage The plugin (cherry) did not specify an instance class.
|
||||
*/
|
||||
public function testGetPluginClassWithMissingClassWithObjectPluginDefinition() {
|
||||
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
|
||||
DefaultFactory::getPluginClass('cherry', $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getPluginClass() with a not existing class definition.
|
||||
*
|
||||
* @covers ::getPluginClass
|
||||
*
|
||||
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
|
||||
* @expectedExceptionMessage Plugin (kiwifruit) instance class "\Drupal\plugin_test\Plugin\plugin_test\fruit\Kiwifruit" does not exist.
|
||||
*/
|
||||
public function testGetPluginClassWithNotExistingClass() {
|
||||
public function testGetPluginClassWithNotExistingClassWithArrayPluginDefinition() {
|
||||
DefaultFactory::getPluginClass('kiwifruit', ['class' => '\Drupal\plugin_test\Plugin\plugin_test\fruit\Kiwifruit']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getPluginClass() with a required interface.
|
||||
* Tests getPluginClass() with a not existing class definition.
|
||||
*
|
||||
* @covers ::getPluginClass
|
||||
*
|
||||
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
|
||||
*/
|
||||
public function testGetPluginClassWithInterface() {
|
||||
$plugin_class = 'Drupal\plugin_test\Plugin\plugin_test\fruit\Cherry';
|
||||
$class = DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class], '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
|
||||
public function testGetPluginClassWithNotExistingClassWithObjectPluginDefinition() {
|
||||
$plugin_class = '\Drupal\plugin_test\Plugin\plugin_test\fruit\Kiwifruit';
|
||||
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
|
||||
$plugin_definition->expects($this->atLeastOnce())
|
||||
->method('getClass')
|
||||
->willReturn($plugin_class);
|
||||
DefaultFactory::getPluginClass('kiwifruit', $plugin_definition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getPluginClass() with a required interface.
|
||||
*
|
||||
* @covers ::getPluginClass
|
||||
*/
|
||||
public function testGetPluginClassWithInterfaceWithArrayPluginDefinition() {
|
||||
$plugin_class = Cherry::class;
|
||||
$class = DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class], FruitInterface::class);
|
||||
|
||||
$this->assertEquals($plugin_class, $class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getPluginClass() with a required interface.
|
||||
*
|
||||
* @covers ::getPluginClass
|
||||
*/
|
||||
public function testGetPluginClassWithInterfaceWithObjectPluginDefinition() {
|
||||
$plugin_class = Cherry::class;
|
||||
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
|
||||
$plugin_definition->expects($this->atLeastOnce())
|
||||
->method('getClass')
|
||||
->willReturn($plugin_class);
|
||||
$class = DefaultFactory::getPluginClass('cherry', $plugin_definition, FruitInterface::class);
|
||||
|
||||
$this->assertEquals($plugin_class, $class);
|
||||
}
|
||||
|
@ -59,12 +132,30 @@ class DefaultFactoryTest extends UnitTestCase {
|
|||
/**
|
||||
* Tests getPluginClass() with a required interface but no implementation.
|
||||
*
|
||||
* @covers ::getPluginClass
|
||||
*
|
||||
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
|
||||
* @expectedExceptionMessage Plugin "cherry" (Drupal\plugin_test\Plugin\plugin_test\fruit\Kale) must implement interface \Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface.
|
||||
* @expectedExceptionMessage Plugin "cherry" (Drupal\plugin_test\Plugin\plugin_test\fruit\Kale) must implement interface Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface.
|
||||
*/
|
||||
public function testGetPluginClassWithInterfaceAndInvalidClass() {
|
||||
$plugin_class = 'Drupal\plugin_test\Plugin\plugin_test\fruit\Kale';
|
||||
DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class, 'provider' => 'core'], '\Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface');
|
||||
public function testGetPluginClassWithInterfaceAndInvalidClassWithArrayPluginDefinition() {
|
||||
$plugin_class = Kale::class;
|
||||
DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class, 'provider' => 'core'], FruitInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests getPluginClass() with a required interface but no implementation.
|
||||
*
|
||||
* @covers ::getPluginClass
|
||||
*
|
||||
* @expectedException \Drupal\Component\Plugin\Exception\PluginException
|
||||
*/
|
||||
public function testGetPluginClassWithInterfaceAndInvalidClassWithObjectPluginDefinition() {
|
||||
$plugin_class = Kale::class;
|
||||
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
|
||||
$plugin_definition->expects($this->atLeastOnce())
|
||||
->method('getClass')
|
||||
->willReturn($plugin_class);
|
||||
DefaultFactory::getPluginClass('cherry', $plugin_definition, FruitInterface::class);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Component\Render\FormattableMarkupTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Component\Render;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* Tests the TranslatableMarkup class.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\Component\Render\FormattableMarkup
|
||||
* @group utility
|
||||
*/
|
||||
class FormattableMarkupTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::__toString
|
||||
* @covers ::jsonSerialize
|
||||
*/
|
||||
public function testToString() {
|
||||
$string = 'Can I please have a @replacement';
|
||||
$formattable_string = new FormattableMarkup($string, ['@replacement' => 'kitten']);
|
||||
$text = (string) $formattable_string;
|
||||
$this->assertEquals('Can I please have a kitten', $text);
|
||||
$text = $formattable_string->jsonSerialize();
|
||||
$this->assertEquals('Can I please have a kitten', $text);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::count
|
||||
*/
|
||||
public function testCount() {
|
||||
$string = 'Can I please have a @replacement';
|
||||
$formattable_string = new FormattableMarkup($string, ['@replacement' => 'kitten']);
|
||||
$this->assertEquals(strlen($string), $formattable_string->count());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Component\Render\HtmlEscapedTextTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Component\Render;
|
||||
|
||||
use Drupal\Component\Render\HtmlEscapedText;
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* Tests the HtmlEscapedText class.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\Component\Render\HtmlEscapedText
|
||||
* @group utility
|
||||
*/
|
||||
class HtmlEscapedTextTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::__toString
|
||||
* @covers ::jsonSerialize
|
||||
*
|
||||
* @dataProvider providerToString
|
||||
*/
|
||||
public function testToString($text, $expected, $message) {
|
||||
$escapeable_string = new HtmlEscapedText($text);
|
||||
$this->assertEquals($expected, (string) $escapeable_string, $message);
|
||||
$this->assertEquals($expected, $escapeable_string->jsonSerialize());
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testToString().
|
||||
*
|
||||
* @see testToString()
|
||||
*/
|
||||
function providerToString() {
|
||||
// Checks that invalid multi-byte sequences are escaped.
|
||||
$tests[] = array("Foo\xC0barbaz", 'Foo<6F>barbaz', 'Escapes invalid sequence "Foo\xC0barbaz"');
|
||||
$tests[] = array("\xc2\"", '<27>"', 'Escapes invalid sequence "\xc2\""');
|
||||
$tests[] = array("Fooÿñ", "Fooÿñ", 'Does not escape valid sequence "Fooÿñ"');
|
||||
|
||||
// Checks that special characters are escaped.
|
||||
$script_tag = $this->prophesize(MarkupInterface::class);
|
||||
$script_tag->__toString()->willReturn('<script>');
|
||||
$script_tag = $script_tag->reveal();
|
||||
$tests[] = array($script_tag, '<script>', 'Escapes <script> even inside an object that implements MarkupInterface.');
|
||||
$tests[] = array("<script>", '<script>', 'Escapes <script>');
|
||||
$tests[] = array('<>&"\'', '<>&"'', 'Escapes reserved HTML characters.');
|
||||
$specialchars = $this->prophesize(MarkupInterface::class);
|
||||
$specialchars->__toString()->willReturn('<>&"\'');
|
||||
$specialchars = $specialchars->reveal();
|
||||
$tests[] = array($specialchars, '<>&"'', 'Escapes reserved HTML characters even inside an object that implements MarkupInterface.');
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::count
|
||||
*/
|
||||
public function testCount() {
|
||||
$string = 'Can I please have a <em>kitten</em>';
|
||||
$escapeable_string = new HtmlEscapedText($string);
|
||||
$this->assertEquals(strlen($string), $escapeable_string->count());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Component\Render\PlainTextOutputTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Component\Render;
|
||||
|
||||
use Drupal\Component\Render\PlainTextOutput;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Component\Render\PlainTextOutput
|
||||
* @group Utility
|
||||
*/
|
||||
class PlainTextOutputTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Tests ::renderFromHtml().
|
||||
*
|
||||
* @param $expected
|
||||
* The expected formatted value.
|
||||
* @param $string
|
||||
* A string to be formatted.
|
||||
* @param array $args
|
||||
* (optional) An associative array of replacements to make. Defaults to
|
||||
* none.
|
||||
*
|
||||
* @covers ::renderFromHtml
|
||||
* @dataProvider providerRenderFromHtml
|
||||
*/
|
||||
public function testRenderFromHtml($expected, $string, $args = []) {
|
||||
$markup = SafeMarkup::format($string, $args);
|
||||
$output = PlainTextOutput::renderFromHtml($markup);
|
||||
$this->assertSame($expected, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for ::testRenderFromHtml()
|
||||
*/
|
||||
public function providerRenderFromHtml() {
|
||||
$data = [];
|
||||
|
||||
$data['simple-text'] = ['Giraffes and wombats', 'Giraffes and wombats'];
|
||||
$data['simple-html'] = ['Giraffes and wombats', '<a href="/muh">Giraffes</a> and <strong>wombats</strong>'];
|
||||
$data['html-with-quote'] = ['Giraffes and quote"s', '<a href="/muh">Giraffes</a> and <strong>quote"s</strong>'];
|
||||
|
||||
$expected = 'The <em> tag makes your text look like "this".';
|
||||
$string = 'The <em> tag makes your text look like <em>"this"</em>.';
|
||||
$data['escaped-html-with-quotes'] = [$expected, $string];
|
||||
|
||||
$safe_string = $this->prophesize(MarkupInterface::class);
|
||||
$safe_string->__toString()->willReturn('<em>"this"</em>');
|
||||
$safe_string = $safe_string->reveal();
|
||||
$data['escaped-html-with-quotes-and-placeholders'] = [$expected, 'The @tag tag makes your text look like @result.', ['@tag' =>'<em>', '@result' => $safe_string]];
|
||||
|
||||
$safe_string = $this->prophesize(MarkupInterface::class);
|
||||
$safe_string->__toString()->willReturn($string);
|
||||
$safe_string = $safe_string->reveal();
|
||||
$data['safe-string'] = [$expected, $safe_string];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
|
@ -79,7 +79,9 @@ class HtmlTest extends UnitTestCase {
|
|||
// replaced.
|
||||
array('__cssidentifier', '-1cssidentifier', array()),
|
||||
// Verify that an identifier starting with two hyphens is replaced.
|
||||
array('__cssidentifier', '--cssidentifier', array())
|
||||
array('__cssidentifier', '--cssidentifier', array()),
|
||||
// Verify that passing double underscores as a filter is processed.
|
||||
array('_cssidentifier', '__cssidentifier', array('__' => '_')),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -231,7 +233,7 @@ class HtmlTest extends UnitTestCase {
|
|||
/**
|
||||
* Data provider for testDecodeEntities().
|
||||
*
|
||||
* @see testCheckPlain()
|
||||
* @see testDecodeEntities()
|
||||
*/
|
||||
public function providerDecodeEntities() {
|
||||
return array(
|
||||
|
@ -272,7 +274,7 @@ class HtmlTest extends UnitTestCase {
|
|||
/**
|
||||
* Data provider for testEscape().
|
||||
*
|
||||
* @see testCheckPlain()
|
||||
* @see testEscape()
|
||||
*/
|
||||
public function providerEscape() {
|
||||
return array(
|
||||
|
@ -310,4 +312,17 @@ class HtmlTest extends UnitTestCase {
|
|||
$this->assertSame('<em>répété</em>', $escaped);
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Tests Html::serialize().
|
||||
*
|
||||
* Resolves an issue by where an empty DOMDocument object sent to serialization would
|
||||
* cause errors in getElementsByTagName() in the serialization function.
|
||||
*
|
||||
* @covers ::serialize
|
||||
*/
|
||||
public function testSerialize() {
|
||||
$document = new \DOMDocument();
|
||||
$result = Html::serialize($document);
|
||||
$this->assertSame('', $result);
|
||||
}
|
||||
}
|
|
@ -7,9 +7,11 @@
|
|||
|
||||
namespace Drupal\Tests\Component\Utility;
|
||||
|
||||
use Drupal\Component\Render\HtmlEscapedText;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Utility\SafeStringInterface;
|
||||
use Drupal\Component\Utility\SafeStringTrait;
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\Component\Render\MarkupTrait;
|
||||
use Drupal\Component\Utility\UrlHelper;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -21,81 +23,12 @@ use Drupal\Tests\UnitTestCase;
|
|||
class SafeMarkupTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Helper function to add a string to the safe list for testing.
|
||||
*
|
||||
* @param string $string
|
||||
* The content to be marked as secure.
|
||||
* @param string $strategy
|
||||
* The escaping strategy used for this string. Two values are supported
|
||||
* by default:
|
||||
* - 'html': (default) The string is safe for use in HTML code.
|
||||
* - 'all': The string is safe for all use cases.
|
||||
* See the
|
||||
* @link http://twig.sensiolabs.org/doc/filters/escape.html Twig escape documentation @endlink
|
||||
* for more information on escaping strategies in Twig.
|
||||
*
|
||||
* @return string
|
||||
* The input string that was marked as safe.
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function safeMarkupSet($string, $strategy = 'html') {
|
||||
$reflected_class = new \ReflectionClass('\Drupal\Component\Utility\SafeMarkup');
|
||||
$reflected_property = $reflected_class->getProperty('safeStrings');
|
||||
$reflected_property->setAccessible(true);
|
||||
$current_value = $reflected_property->getValue();
|
||||
$current_value[$string][$strategy] = TRUE;
|
||||
$reflected_property->setValue($current_value);
|
||||
return $string;
|
||||
}
|
||||
protected function tearDown() {
|
||||
parent::tearDown();
|
||||
|
||||
/**
|
||||
* Tests SafeMarkup::isSafe() with different providers.
|
||||
*
|
||||
* @covers ::isSafe
|
||||
*/
|
||||
public function testStrategy() {
|
||||
$returned = $this->safeMarkupSet('string0', 'html');
|
||||
$this->assertTrue(SafeMarkup::isSafe($returned), 'String set with "html" provider is safe for default (html)');
|
||||
$returned = $this->safeMarkupSet('string1', 'all');
|
||||
$this->assertTrue(SafeMarkup::isSafe($returned), 'String set with "all" provider is safe for default (html)');
|
||||
$returned = $this->safeMarkupSet('string2', 'css');
|
||||
$this->assertFalse(SafeMarkup::isSafe($returned), 'String set with "css" provider is not safe for default (html)');
|
||||
$returned = $this->safeMarkupSet('string3');
|
||||
$this->assertFalse(SafeMarkup::isSafe($returned, 'all'), 'String set with "html" provider is not safe for "all"');
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testSet().
|
||||
*/
|
||||
public function providerSet() {
|
||||
// Checks that invalid multi-byte sequences are escaped.
|
||||
$tests[] = array(
|
||||
'Foo<6F>barbaz',
|
||||
'SafeMarkup::setMarkup() functions with valid sequence "Foo<6F>barbaz"',
|
||||
TRUE
|
||||
);
|
||||
$tests[] = array(
|
||||
"Fooÿñ",
|
||||
'SafeMarkup::setMarkup() functions with valid sequence "Fooÿñ"'
|
||||
);
|
||||
$tests[] = array("<div>", 'SafeMarkup::setMultiple() does not escape HTML');
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests SafeMarkup::setMultiple().
|
||||
* @dataProvider providerSet
|
||||
*
|
||||
* @param string $text
|
||||
* The text or object to provide to SafeMarkup::setMultiple().
|
||||
* @param string $message
|
||||
* The message to provide as output for the test.
|
||||
*
|
||||
* @covers ::setMultiple
|
||||
*/
|
||||
public function testSet($text, $message) {
|
||||
SafeMarkup::setMultiple([$text => ['html' => TRUE]]);
|
||||
$this->assertTrue(SafeMarkup::isSafe($text), $message);
|
||||
UrlHelper::setAllowedProtocols(['http', 'https']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -104,44 +37,12 @@ class SafeMarkupTest extends UnitTestCase {
|
|||
* @covers ::isSafe
|
||||
*/
|
||||
public function testIsSafe() {
|
||||
$safe_string = $this->getMock('\Drupal\Component\Utility\SafeStringInterface');
|
||||
$safe_string = $this->getMock('\Drupal\Component\Render\MarkupInterface');
|
||||
$this->assertTrue(SafeMarkup::isSafe($safe_string));
|
||||
$string_object = new SafeMarkupTestString('test');
|
||||
$this->assertFalse(SafeMarkup::isSafe($string_object));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests SafeMarkup::setMultiple().
|
||||
*
|
||||
* @covers ::setMultiple
|
||||
*/
|
||||
public function testSetMultiple() {
|
||||
$texts = array(
|
||||
'multistring0' => array('html' => TRUE),
|
||||
'multistring1' => array('all' => TRUE),
|
||||
);
|
||||
SafeMarkup::setMultiple($texts);
|
||||
foreach ($texts as $string => $providers) {
|
||||
$this->assertTrue(SafeMarkup::isSafe($string), 'The value has been marked as safe for html');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests SafeMarkup::setMultiple().
|
||||
*
|
||||
* Only TRUE may be passed in as the value.
|
||||
*
|
||||
* @covers ::setMultiple
|
||||
*
|
||||
* @expectedException \UnexpectedValueException
|
||||
*/
|
||||
public function testInvalidSetMultiple() {
|
||||
$texts = array(
|
||||
'invalidstring0' => array('html' => 1),
|
||||
);
|
||||
SafeMarkup::setMultiple($texts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests SafeMarkup::checkPlain().
|
||||
*
|
||||
|
@ -154,28 +55,49 @@ class SafeMarkupTest extends UnitTestCase {
|
|||
* The expected output from the function.
|
||||
* @param string $message
|
||||
* The message to provide as output for the test.
|
||||
* @param bool $ignorewarnings
|
||||
* Whether or not to ignore PHP 5.3+ invalid multibyte sequence warnings.
|
||||
*/
|
||||
function testCheckPlain($text, $expected, $message, $ignorewarnings = FALSE) {
|
||||
$result = $ignorewarnings ? @SafeMarkup::checkPlain($text) : SafeMarkup::checkPlain($text);
|
||||
function testCheckPlain($text, $expected, $message) {
|
||||
$result = SafeMarkup::checkPlain($text);
|
||||
$this->assertTrue($result instanceof HtmlEscapedText);
|
||||
$this->assertEquals($expected, $result, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testCheckPlain().
|
||||
* Tests Drupal\Component\Render\HtmlEscapedText.
|
||||
*
|
||||
* Verifies that the result of SafeMarkup::checkPlain() is the same as using
|
||||
* HtmlEscapedText directly.
|
||||
*
|
||||
* @dataProvider providerCheckPlain
|
||||
*
|
||||
* @param string $text
|
||||
* The text to provide to the HtmlEscapedText constructor.
|
||||
* @param string $expected
|
||||
* The expected output from the function.
|
||||
* @param string $message
|
||||
* The message to provide as output for the test.
|
||||
*/
|
||||
function testHtmlEscapedText($text, $expected, $message) {
|
||||
$result = new HtmlEscapedText($text);
|
||||
$this->assertEquals($expected, $result, $message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testCheckPlain() and testEscapeString().
|
||||
*
|
||||
* @see testCheckPlain()
|
||||
*/
|
||||
function providerCheckPlain() {
|
||||
// Checks that invalid multi-byte sequences are escaped.
|
||||
$tests[] = array("Foo\xC0barbaz", 'Foo<6F>barbaz', 'SafeMarkup::checkPlain() escapes invalid sequence "Foo\xC0barbaz"', TRUE);
|
||||
$tests[] = array("\xc2\"", '<27>"', 'SafeMarkup::checkPlain() escapes invalid sequence "\xc2\""', TRUE);
|
||||
$tests[] = array("Fooÿñ", "Fooÿñ", 'SafeMarkup::checkPlain() does not escape valid sequence "Fooÿñ"');
|
||||
$tests[] = array("Foo\xC0barbaz", 'Foo<6F>barbaz', 'Escapes invalid sequence "Foo\xC0barbaz"');
|
||||
$tests[] = array("\xc2\"", '<27>"', 'Escapes invalid sequence "\xc2\""');
|
||||
$tests[] = array("Fooÿñ", "Fooÿñ", 'Does not escape valid sequence "Fooÿñ"');
|
||||
|
||||
// Checks that special characters are escaped.
|
||||
$tests[] = array("<script>", '<script>', 'SafeMarkup::checkPlain() escapes <script>');
|
||||
$tests[] = array('<>&"\'', '<>&"'', 'SafeMarkup::checkPlain() escapes reserved HTML characters.');
|
||||
$tests[] = array(SafeMarkupTestMarkup::create("<script>"), '<script>', 'Escapes <script> even inside an object that implements MarkupInterface.');
|
||||
$tests[] = array("<script>", '<script>', 'Escapes <script>');
|
||||
$tests[] = array('<>&"\'', '<>&"'', 'Escapes reserved HTML characters.');
|
||||
$tests[] = array(SafeMarkupTestMarkup::create('<>&"\''), '<>&"'', 'Escapes reserved HTML characters even inside an object that implements MarkupInterface.');
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
@ -198,12 +120,14 @@ class SafeMarkupTest extends UnitTestCase {
|
|||
* Whether the result is expected to be safe for HTML display.
|
||||
*/
|
||||
public function testFormat($string, array $args, $expected, $message, $expected_is_safe) {
|
||||
UrlHelper::setAllowedProtocols(['http', 'https', 'mailto']);
|
||||
|
||||
$result = SafeMarkup::format($string, $args);
|
||||
$this->assertEquals($expected, $result, $message);
|
||||
$this->assertEquals($expected_is_safe, SafeMarkup::isSafe($result), 'SafeMarkup::format correctly sets the result as safe or not safe.');
|
||||
|
||||
foreach ($args as $arg) {
|
||||
$this->assertSame($arg instanceof SafeMarkupTestSafeString, SafeMarkup::isSafe($arg));
|
||||
$this->assertSame($arg instanceof SafeMarkupTestMarkup, SafeMarkup::isSafe($arg));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -215,11 +139,23 @@ class SafeMarkupTest extends UnitTestCase {
|
|||
function providerFormat() {
|
||||
$tests[] = array('Simple text', array(), 'Simple text', 'SafeMarkup::format leaves simple text alone.', TRUE);
|
||||
$tests[] = array('Escaped text: @value', array('@value' => '<script>'), 'Escaped text: <script>', 'SafeMarkup::format replaces and escapes string.', TRUE);
|
||||
$tests[] = array('Escaped text: @value', array('@value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Escaped text: <span>Safe HTML</span>', 'SafeMarkup::format does not escape an already safe string.', TRUE);
|
||||
$tests[] = array('Escaped text: @value', array('@value' => SafeMarkupTestMarkup::create('<span>Safe HTML</span>')), 'Escaped text: <span>Safe HTML</span>', 'SafeMarkup::format does not escape an already safe string.', TRUE);
|
||||
$tests[] = array('Placeholder text: %value', array('%value' => '<script>'), 'Placeholder text: <em class="placeholder"><script></em>', 'SafeMarkup::format replaces, escapes and themes string.', TRUE);
|
||||
$tests[] = array('Placeholder text: %value', array('%value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Placeholder text: <em class="placeholder"><span>Safe HTML</span></em>', 'SafeMarkup::format does not escape an already safe string themed as a placeholder.', TRUE);
|
||||
$tests[] = array('Verbatim text: !value', array('!value' => '<script>'), 'Verbatim text: <script>', 'SafeMarkup::format replaces verbatim string as-is.', FALSE);
|
||||
$tests[] = array('Verbatim text: !value', array('!value' => SafeMarkupTestSafeString::create('<span>Safe HTML</span>')), 'Verbatim text: <span>Safe HTML</span>', 'SafeMarkup::format replaces verbatim string as-is.', TRUE);
|
||||
$tests[] = array('Placeholder text: %value', array('%value' => SafeMarkupTestMarkup::create('<span>Safe HTML</span>')), 'Placeholder text: <em class="placeholder"><span>Safe HTML</span></em>', 'SafeMarkup::format does not escape an already safe string themed as a placeholder.', TRUE);
|
||||
|
||||
$tests['javascript-protocol-url'] = ['Simple text <a href=":url">giraffe</a>', [':url' => 'javascript://example.com?foo&bar'], 'Simple text <a href="//example.com?foo&bar">giraffe</a>', 'Support for filtering bad protocols', TRUE];
|
||||
$tests['external-url'] = ['Simple text <a href=":url">giraffe</a>', [':url' => 'http://example.com?foo&bar'], 'Simple text <a href="http://example.com?foo&bar">giraffe</a>', 'Support for filtering bad protocols', TRUE];
|
||||
$tests['relative-url'] = ['Simple text <a href=":url">giraffe</a>', [':url' => '/node/1?foo&bar'], 'Simple text <a href="/node/1?foo&bar">giraffe</a>', 'Support for filtering bad protocols', TRUE];
|
||||
$tests['fragment-with-special-chars'] = ['Simple text <a href=":url">giraffe</a>', [':url' => 'http://example.com/#<'], 'Simple text <a href="http://example.com/#&lt;">giraffe</a>', 'Support for filtering bad protocols', TRUE];
|
||||
$tests['mailto-protocol'] = ['Hey giraffe <a href=":url">MUUUH</a>', [':url' => 'mailto:test@example.com'], 'Hey giraffe <a href="mailto:test@example.com">MUUUH</a>', '', TRUE];
|
||||
$tests['js-with-fromCharCode'] = ['Hey giraffe <a href=":url">MUUUH</a>', [':url' => "javascript:alert(String.fromCharCode(88,83,83))"], 'Hey giraffe <a href="alert(String.fromCharCode(88,83,83))">MUUUH</a>', '', TRUE];
|
||||
|
||||
// Test some "URL" values that are not RFC 3986 compliant URLs. The result
|
||||
// of SafeMarkup::format() should still be valid HTML (other than the
|
||||
// value of the "href" attribute not being a valid URL), and not
|
||||
// vulnerable to XSS.
|
||||
$tests['non-url-with-colon'] = ['Hey giraffe <a href=":url">MUUUH</a>', [':url' => "llamas: they are not URLs"], 'Hey giraffe <a href=" they are not URLs">MUUUH</a>', '', TRUE];
|
||||
$tests['non-url-with-html'] = ['Hey giraffe <a href=":url">MUUUH</a>', [':url' => "<span>not a url</span>"], 'Hey giraffe <a href="<span>not a url</span>">MUUUH</a>', '', TRUE];
|
||||
|
||||
return $tests;
|
||||
}
|
||||
|
@ -241,11 +177,8 @@ class SafeMarkupTestString {
|
|||
}
|
||||
|
||||
/**
|
||||
* Marks text as safe.
|
||||
*
|
||||
* SafeMarkupTestSafeString is used to mark text as safe because
|
||||
* SafeMarkup::$safeStrings is a global static that affects all tests.
|
||||
* Marks an object's __toString() method as returning markup.
|
||||
*/
|
||||
class SafeMarkupTestSafeString implements SafeStringInterface {
|
||||
use SafeStringTrait;
|
||||
class SafeMarkupTestMarkup implements MarkupInterface {
|
||||
use MarkupTrait;
|
||||
}
|
||||
|
|
|
@ -291,6 +291,7 @@ class UnicodeTest extends UnitTestCase {
|
|||
return array(
|
||||
array('tHe QUIcK bRoWn', 15),
|
||||
array('ÜBER-åwesome', 12),
|
||||
array('以呂波耳・ほへとち。リヌルヲ。', 15),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -529,4 +530,46 @@ class UnicodeTest extends UnitTestCase {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests multibyte strpos.
|
||||
*
|
||||
* @dataProvider providerStrpos
|
||||
* @covers ::strpos
|
||||
*/
|
||||
public function testStrpos($haystack, $needle, $offset, $expected) {
|
||||
// Run through multibyte code path.
|
||||
Unicode::setStatus(Unicode::STATUS_MULTIBYTE);
|
||||
$this->assertEquals($expected, Unicode::strpos($haystack, $needle, $offset));
|
||||
// Run through singlebyte code path.
|
||||
Unicode::setStatus(Unicode::STATUS_SINGLEBYTE);
|
||||
$this->assertEquals($expected, Unicode::strpos($haystack, $needle, $offset));
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testStrpos().
|
||||
*
|
||||
* @see testStrpos()
|
||||
*
|
||||
* @return array
|
||||
* An array containing:
|
||||
* - The haystack string to be searched in.
|
||||
* - The needle string to search for.
|
||||
* - The offset integer to start at.
|
||||
* - The expected integer/FALSE result.
|
||||
*/
|
||||
public function providerStrpos() {
|
||||
return array(
|
||||
array('frànçAIS is über-åwesome', 'frànçAIS is über-åwesome', 0, 0),
|
||||
array('frànçAIS is über-åwesome', 'rànçAIS is über-åwesome', 0, 1),
|
||||
array('frànçAIS is über-åwesome', 'not in string', 0, FALSE),
|
||||
array('frànçAIS is über-åwesome', 'r', 0, 1),
|
||||
array('frànçAIS is über-åwesome', 'nçAIS', 0, 3),
|
||||
array('frànçAIS is über-åwesome', 'nçAIS', 2, 3),
|
||||
array('frànçAIS is über-åwesome', 'nçAIS', 3, 3),
|
||||
array('以呂波耳・ほへとち。リヌルヲ。', '波耳', 0, 2),
|
||||
array('以呂波耳・ほへとち。リヌルヲ。', '波耳', 1, 2),
|
||||
array('以呂波耳・ほへとち。リヌルヲ。', '波耳', 2, 2),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ class AccessResultTest extends UnitTestCase {
|
|||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->cacheContextsManager->method('assertValidTokens')->willReturn(TRUE);
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('cache_contexts_manager', $this->cacheContextsManager);
|
||||
\Drupal::setContainer($container);
|
||||
|
|
|
@ -45,9 +45,6 @@ class TranslationTest extends UnitTestCase {
|
|||
$options = isset($values['context']) ? array(
|
||||
'context' => $values['context'],
|
||||
) : array();
|
||||
$this->translationManager->expects($this->once())
|
||||
->method('translate')
|
||||
->with($values['value'], $arguments, $options);
|
||||
|
||||
$annotation = new Translation($values);
|
||||
|
||||
|
@ -69,9 +66,9 @@ class TranslationTest extends UnitTestCase {
|
|||
$random_html_entity = '&' . $random;
|
||||
$data[] = array(
|
||||
array(
|
||||
'value' => 'Foo !bar @baz %qux',
|
||||
'value' => 'Foo @bar @baz %qux',
|
||||
'arguments' => array(
|
||||
'!bar' => $random,
|
||||
'@bar' => $random,
|
||||
'@baz' => $random_html_entity,
|
||||
'%qux' => $random_html_entity,
|
||||
),
|
||||
|
|
|
@ -94,7 +94,7 @@ class LibraryDiscoveryCollectorTest extends UnitTestCase {
|
|||
$this->activeTheme = $this->getMockBuilder('Drupal\Core\Theme\ActiveTheme')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->themeManager->expects($this->once())
|
||||
$this->themeManager->expects($this->exactly(3))
|
||||
->method('getActiveTheme')
|
||||
->willReturn($this->activeTheme);
|
||||
$this->activeTheme->expects($this->once())
|
||||
|
@ -120,7 +120,7 @@ class LibraryDiscoveryCollectorTest extends UnitTestCase {
|
|||
$this->activeTheme = $this->getMockBuilder('Drupal\Core\Theme\ActiveTheme')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->themeManager->expects($this->once())
|
||||
$this->themeManager->expects($this->exactly(3))
|
||||
->method('getActiveTheme')
|
||||
->willReturn($this->activeTheme);
|
||||
$this->activeTheme->expects($this->once())
|
||||
|
|
|
@ -73,6 +73,15 @@ class LibraryDiscoveryParserTest extends UnitTestCase {
|
|||
|
||||
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
|
||||
$this->themeManager = $this->getMock('Drupal\Core\Theme\ThemeManagerInterface');
|
||||
$mock_active_theme = $this->getMockBuilder('Drupal\Core\Theme\ActiveTheme')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$mock_active_theme->expects($this->any())
|
||||
->method('getLibrariesOverride')
|
||||
->willReturn([]);
|
||||
$this->themeManager->expects($this->any())
|
||||
->method('getActiveTheme')
|
||||
->willReturn($mock_active_theme);
|
||||
$this->libraryDiscoveryParser = new TestLibraryDiscoveryParser($this->root, $this->moduleHandler, $this->themeManager);
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ namespace Drupal\Tests\Core\Breadcrumb;
|
|||
use Drupal\Core\Breadcrumb\Breadcrumb;
|
||||
use Drupal\Core\Breadcrumb\BreadcrumbManager;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\Context\CacheContextsManager;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -18,6 +20,13 @@ use Drupal\Tests\UnitTestCase;
|
|||
*/
|
||||
class BreadcrumbManagerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The dependency injection container.
|
||||
*
|
||||
* @var \Symfony\Component\DependencyInjection\ContainerBuilder
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* The breadcrumb object.
|
||||
*
|
||||
|
@ -46,6 +55,13 @@ class BreadcrumbManagerTest extends UnitTestCase {
|
|||
$this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
|
||||
$this->breadcrumbManager = new BreadcrumbManager($this->moduleHandler);
|
||||
$this->breadcrumb = new Breadcrumb();
|
||||
|
||||
$this->container = new ContainerBuilder();
|
||||
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
|
||||
$cache_contexts_manager->assertValidTokens()->willReturn(TRUE);
|
||||
$cache_contexts_manager->reveal();
|
||||
$this->container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
\Drupal::setContainer($this->container);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,7 +87,7 @@ class BreadcrumbManagerTest extends UnitTestCase {
|
|||
$builder = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
|
||||
$links = array('<a href="/example">Test</a>');
|
||||
$this->breadcrumb->setLinks($links);
|
||||
$this->breadcrumb->setCacheContexts(['foo'])->setCacheTags(['bar']);
|
||||
$this->breadcrumb->addCacheContexts(['foo'])->addCacheTags(['bar']);
|
||||
|
||||
$builder->expects($this->once())
|
||||
->method('applies')
|
||||
|
@ -108,7 +124,7 @@ class BreadcrumbManagerTest extends UnitTestCase {
|
|||
$builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
|
||||
$links2 = array('<a href="/example2">Test2</a>');
|
||||
$this->breadcrumb->setLinks($links2);
|
||||
$this->breadcrumb->setCacheContexts(['baz'])->setCacheTags(['qux']);
|
||||
$this->breadcrumb->addCacheContexts(['baz'])->addCacheTags(['qux']);
|
||||
$builder2->expects($this->once())
|
||||
->method('applies')
|
||||
->will($this->returnValue(TRUE));
|
||||
|
@ -146,7 +162,7 @@ class BreadcrumbManagerTest extends UnitTestCase {
|
|||
$builder2 = $this->getMock('Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface');
|
||||
$links2 = ['<a href="/example2">Test2</a>'];
|
||||
$this->breadcrumb->setLinks($links2);
|
||||
$this->breadcrumb->setCacheContexts(['baz'])->setCacheTags(['qux']);
|
||||
$this->breadcrumb->addCacheContexts(['baz'])->addCacheTags(['qux']);
|
||||
$builder2->expects($this->once())
|
||||
->method('applies')
|
||||
->will($this->returnValue(TRUE));
|
||||
|
|
|
@ -20,8 +20,7 @@ class CacheTagsInvalidatorTest extends UnitTestCase {
|
|||
/**
|
||||
* @covers ::invalidateTags
|
||||
*
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage Cache tags must be strings, array given.
|
||||
* @expectedException \AssertionError
|
||||
*/
|
||||
public function testInvalidateTagsWithInvalidTags() {
|
||||
$cache_tags_invalidator = new CacheTagsInvalidator();
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Cache;
|
||||
|
||||
use Drupal\Component\Assertion\Inspector;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
@ -59,6 +60,7 @@ class CacheTest extends UnitTestCase {
|
|||
$this->assertNull(Cache::validateTags($tags));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provides a list of pairs of cache tags arrays to be merged.
|
||||
*
|
||||
|
|
|
@ -35,6 +35,8 @@ class CacheableMetadataTest extends UnitTestCase {
|
|||
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
\Drupal::setContainer($container);
|
||||
|
@ -57,6 +59,7 @@ class CacheableMetadataTest extends UnitTestCase {
|
|||
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
\Drupal::setContainer($container);
|
||||
|
|
|
@ -106,8 +106,7 @@ class CacheContextsManagerTest extends UnitTestCase {
|
|||
/**
|
||||
* @covers ::convertTokensToKeys
|
||||
*
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage "non-cache-context" is not a valid cache context ID.
|
||||
* @expectedException \AssertionError
|
||||
*/
|
||||
public function testInvalidContext() {
|
||||
$container = $this->getMockContainer();
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace Drupal\Tests\Core\Config;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Render\Markup;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\Core\Config\Config;
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
|
@ -528,4 +529,26 @@ class ConfigTest extends UnitTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::setData
|
||||
* @covers ::set
|
||||
* @covers ::initWithData
|
||||
*/
|
||||
public function testSafeStringHandling() {
|
||||
// Safe strings are cast when using ::set().
|
||||
$safe_string = Markup::create('bar');
|
||||
$this->config->set('foo', $safe_string);
|
||||
$this->assertSame('bar', $this->config->get('foo'));
|
||||
$this->config->set('foo', ['bar' => $safe_string]);
|
||||
$this->assertSame('bar', $this->config->get('foo.bar'));
|
||||
|
||||
// Safe strings are cast when using ::setData().
|
||||
$this->config->setData(['bar' => $safe_string]);
|
||||
$this->assertSame('bar', $this->config->get('bar'));
|
||||
|
||||
// Safe strings are not cast when using ::initWithData().
|
||||
$this->config->initWithData(['bar' => $safe_string]);
|
||||
$this->assertSame($safe_string, $this->config->get('bar'));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -139,19 +139,19 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
|
|||
|
||||
/**
|
||||
* @covers ::calculateDependencies
|
||||
* @covers ::getDependencies
|
||||
*/
|
||||
public function testCalculateDependencies() {
|
||||
// Calculating dependencies will reset the dependencies array.
|
||||
$this->entity->set('dependencies', array('module' => array('node')));
|
||||
$this->assertEmpty($this->entity->calculateDependencies());
|
||||
$this->assertEmpty($this->entity->calculateDependencies()->getDependencies());
|
||||
|
||||
// Calculating dependencies will reset the dependencies array using enforced
|
||||
// dependencies.
|
||||
$this->entity->set('dependencies', array('module' => array('node'), 'enforced' => array('module' => 'views')));
|
||||
$dependencies = $this->entity->calculateDependencies();
|
||||
$dependencies = $this->entity->calculateDependencies()->getDependencies();
|
||||
$this->assertContains('views', $dependencies['module']);
|
||||
$this->assertNotContains('node', $dependencies['module']);
|
||||
$this->assertContains('views', $dependencies['enforced']['module']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,6 +213,7 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* @covers ::getDependencies
|
||||
* @covers ::calculateDependencies
|
||||
*
|
||||
* @dataProvider providerCalculateDependenciesWithPluginCollections
|
||||
|
@ -244,7 +245,7 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
|
|||
->method('getPluginCollections')
|
||||
->will($this->returnValue(array($pluginCollection)));
|
||||
|
||||
$this->assertEquals($expected_dependencies, $this->entity->calculateDependencies());
|
||||
$this->assertEquals($expected_dependencies, $this->entity->calculateDependencies()->getDependencies());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -289,6 +290,7 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
|
|||
|
||||
/**
|
||||
* @covers ::calculateDependencies
|
||||
* @covers ::getDependencies
|
||||
* @covers ::onDependencyRemoval
|
||||
*/
|
||||
public function testCalculateDependenciesWithThirdPartySettings() {
|
||||
|
@ -297,12 +299,12 @@ class ConfigEntityBaseUnitTest extends UnitTestCase {
|
|||
$this->entity->setThirdPartySetting('test_provider2', 'test', 'test');
|
||||
$this->entity->setThirdPartySetting($this->provider, 'test', 'test');
|
||||
|
||||
$this->assertEquals(array('test_provider', 'test_provider2'), $this->entity->calculateDependencies()['module']);
|
||||
$this->assertEquals(array('test_provider', 'test_provider2'), $this->entity->calculateDependencies()->getDependencies()['module']);
|
||||
$changed = $this->entity->onDependencyRemoval(['module' => ['test_provider2']]);
|
||||
$this->assertTrue($changed, 'Calling onDependencyRemoval with an existing third party dependency provider returns TRUE.');
|
||||
$changed = $this->entity->onDependencyRemoval(['module' => ['test_provider3']]);
|
||||
$this->assertFalse($changed, 'Calling onDependencyRemoval with a non-existing third party dependency provider returns FALSE.');
|
||||
$this->assertEquals(array('test_provider'), $this->entity->calculateDependencies()['module']);
|
||||
$this->assertEquals(array('test_provider'), $this->entity->calculateDependencies()->getDependencies()['module']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -98,7 +98,7 @@ class EntityDisplayModeBaseUnitTest extends UnitTestCase {
|
|||
->setMethods(array('getFilterFormat'))
|
||||
->getMock();
|
||||
|
||||
$dependencies = $this->entity->calculateDependencies();
|
||||
$dependencies = $this->entity->calculateDependencies()->getDependencies();
|
||||
$this->assertContains('test_module', $dependencies['module']);
|
||||
}
|
||||
|
||||
|
|
168
core/tests/Drupal/Tests/Core/Database/ConditionTest.php
Normal file
168
core/tests/Drupal/Tests/Core/Database/ConditionTest.php
Normal file
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Core\Database\ConditionTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\Database;
|
||||
|
||||
use Drupal\Core\Database\Connection;
|
||||
use Drupal\Core\Database\Query\Condition;
|
||||
use Drupal\Core\Database\Query\PlaceholderInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Prophecy\Argument;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Database\Query\Condition
|
||||
*
|
||||
* @group Database
|
||||
*/
|
||||
class ConditionTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::compile
|
||||
*/
|
||||
public function testSimpleCondition() {
|
||||
$connection = $this->prophesize(Connection::class);
|
||||
$connection->escapeField('name')->will(function ($args) {
|
||||
return preg_replace('/[^A-Za-z0-9_.]+/', '', $args[0]);
|
||||
});
|
||||
$connection->mapConditionOperator('=')->willReturn(['operator' => '=']);
|
||||
$connection = $connection->reveal();
|
||||
|
||||
$query_placeholder = $this->prophesize(PlaceholderInterface::class);
|
||||
|
||||
$counter = 0;
|
||||
$query_placeholder->nextPlaceholder()->will(function() use (&$counter) {
|
||||
return $counter++;
|
||||
});
|
||||
$query_placeholder->uniqueIdentifier()->willReturn(4);
|
||||
$query_placeholder = $query_placeholder->reveal();
|
||||
|
||||
$condition = new Condition('AND');
|
||||
$condition->condition('name', ['value']);
|
||||
$condition->compile($connection, $query_placeholder);
|
||||
|
||||
$this->assertEquals(' (name = :db_condition_placeholder_0) ', $condition->__toString());
|
||||
$this->assertEquals([':db_condition_placeholder_0' => 'value'], $condition->arguments());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::compile
|
||||
*
|
||||
* @dataProvider dataProviderTestCompileWithKnownOperators()
|
||||
*
|
||||
* @param string $expected
|
||||
* The expected generated SQL condition.
|
||||
* @param string $field
|
||||
* The field to pass into the condition() method.
|
||||
* @param mixed $value
|
||||
* The value to pass into the condition() method.
|
||||
* @param string $operator
|
||||
* The operator to pass into the condition() method.
|
||||
* @param mixed $expected_arguments
|
||||
* (optional) The expected set arguments.
|
||||
*/
|
||||
public function testCompileWithKnownOperators($expected, $field, $value, $operator, $expected_arguments = NULL) {
|
||||
$connection = $this->prophesize(Connection::class);
|
||||
$connection->escapeField(Argument::any())->will(function ($args) {
|
||||
return preg_replace('/[^A-Za-z0-9_.]+/', '', $args[0]);
|
||||
});
|
||||
$connection->mapConditionOperator(Argument::any())->willReturn(NULL);
|
||||
$connection = $connection->reveal();
|
||||
|
||||
$query_placeholder = $this->prophesize(PlaceholderInterface::class);
|
||||
|
||||
$counter = 0;
|
||||
$query_placeholder->nextPlaceholder()->will(function() use (&$counter) {
|
||||
return $counter++;
|
||||
});
|
||||
$query_placeholder->uniqueIdentifier()->willReturn(4);
|
||||
$query_placeholder = $query_placeholder->reveal();
|
||||
|
||||
$condition = new Condition('AND');
|
||||
$condition->condition($field, $value, $operator);
|
||||
$condition->compile($connection, $query_placeholder);
|
||||
|
||||
$this->assertEquals($expected, $condition->__toString());
|
||||
if (isset($expected_arguments)) {
|
||||
$this->assertEquals($expected_arguments, $condition->arguments());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of known operations and the expected output.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function dataProviderTestCompileWithKnownOperators() {
|
||||
// Below are a list of commented out test cases, which should work but
|
||||
// aren't directly supported by core, but instead need manual handling with
|
||||
// prefix/suffix at the moment.
|
||||
$data = [];
|
||||
$data[] = [' (name = :db_condition_placeholder_0) ', 'name', 'value', '='];
|
||||
$data[] = [' (name != :db_condition_placeholder_0) ', 'name', 'value', '!='];
|
||||
$data[] = [' (name <> :db_condition_placeholder_0) ', 'name', 'value', '<>'];
|
||||
$data[] = [' (name >= :db_condition_placeholder_0) ', 'name', 'value', '>='];
|
||||
$data[] = [' (name > :db_condition_placeholder_0) ', 'name', 'value', '>'];
|
||||
$data[] = [' (name <= :db_condition_placeholder_0) ', 'name', 'value', '<='];
|
||||
$data[] = [' (name < :db_condition_placeholder_0) ', 'name', 'value', '<'];
|
||||
// $data[] = [' ( GREATEST (1, 2, 3) ) ', '', [1, 2, 3], 'GREATEST'];
|
||||
$data[] = [' (name IN (:db_condition_placeholder_0, :db_condition_placeholder_1, :db_condition_placeholder_2)) ', 'name', ['1', '2', '3'], 'IN'];
|
||||
$data[] = [' (name NOT IN (:db_condition_placeholder_0, :db_condition_placeholder_1, :db_condition_placeholder_2)) ', 'name', ['1', '2', '3'], 'NOT IN'];
|
||||
// $data[] = [' ( INTERVAL (1, 2, 3) ) ', '', [1, 2, 3], 'INTERVAL'];
|
||||
$data[] = [' (name IS NULL ) ', 'name', NULL, 'IS NULL'];
|
||||
$data[] = [' (name IS NOT NULL ) ', 'name', NULL, 'IS NOT NULL'];
|
||||
$data[] = [' (name IS :db_condition_placeholder_0) ', 'name', 'TRUE', 'IS'];
|
||||
// $data[] = [' ( LEAST (1, 2, 3) ) ', '', [1, 2, 3], 'LEAST'];
|
||||
$data[] = [" (name LIKE :db_condition_placeholder_0 ESCAPE '\\\\') ", 'name', '%muh%', 'LIKE', [':db_condition_placeholder_0' => '%muh%']];
|
||||
$data[] = [" (name NOT LIKE :db_condition_placeholder_0 ESCAPE '\\\\') ", 'name', '%muh%', 'NOT LIKE', [':db_condition_placeholder_0' => '%muh%']];
|
||||
$data[] = [" (name BETWEEN :db_condition_placeholder_0 AND :db_condition_placeholder_1) ", 'name', [1, 2], 'BETWEEN', [':db_condition_placeholder_0' => 1, ':db_condition_placeholder_1' => 2]];
|
||||
// $data[] = [" (name NOT BETWEEN :db_condition_placeholder_0 AND :db_condition_placeholder_1) ", 'name', [1, 2], 'NOT BETWEEN', [':db_condition_placeholder_0' => 1, ':db_condition_placeholder_1' => 2]];
|
||||
// $data[] = [' ( STRCMP (name, :db_condition_placeholder_0) ) ', '', ['test-string'], 'STRCMP', [':db_condition_placeholder_0' => 'test-string']];
|
||||
// $data[] = [' (EXISTS ) ', '', NULL, 'EXISTS'];
|
||||
// $data[] = [' (name NOT EXISTS ) ', 'name', NULL, 'NOT EXISTS'];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::compile
|
||||
*
|
||||
* @expectedException \PHPUnit_Framework_Error
|
||||
* @dataProvider providerTestCompileWithSqlInjectionForOperator
|
||||
*/
|
||||
public function testCompileWithSqlInjectionForOperator($operator) {
|
||||
$connection = $this->prophesize(Connection::class);
|
||||
$connection->escapeField(Argument::any())->will(function ($args) {
|
||||
return preg_replace('/[^A-Za-z0-9_.]+/', '', $args[0]);
|
||||
});
|
||||
$connection->mapConditionOperator(Argument::any())->willReturn(NULL);
|
||||
$connection = $connection->reveal();
|
||||
|
||||
$query_placeholder = $this->prophesize(PlaceholderInterface::class);
|
||||
|
||||
$counter = 0;
|
||||
$query_placeholder->nextPlaceholder()->will(function() use (&$counter) {
|
||||
return $counter++;
|
||||
});
|
||||
$query_placeholder->uniqueIdentifier()->willReturn(4);
|
||||
$query_placeholder = $query_placeholder->reveal();
|
||||
|
||||
$condition = new Condition('AND');
|
||||
$condition->condition('name', 'value', $operator);
|
||||
$condition->compile($connection, $query_placeholder);
|
||||
}
|
||||
|
||||
public function providerTestCompileWithSqlInjectionForOperator() {
|
||||
$data = [];
|
||||
$data[] = ["IS NOT NULL) ;INSERT INTO {test} (name) VALUES ('test12345678'); -- "];
|
||||
$data[] = ["IS NOT NULL) UNION ALL SELECT name, pass FROM {users_field_data} -- "];
|
||||
$data[] = ["IS NOT NULL) UNION ALL SELECT name FROM {TEST_UPPERCASE} -- "];
|
||||
$data[] = ["= 1 UNION ALL SELECT password FROM user WHERE uid ="];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
|
@ -254,11 +254,11 @@ class ConnectionTest extends UnitTestCase {
|
|||
array(''),
|
||||
),
|
||||
array(
|
||||
'/* Exploit * / DROP TABLE node; -- */ ',
|
||||
'/* Exploit * / DROP TABLE node. -- */ ',
|
||||
array('Exploit * / DROP TABLE node; --'),
|
||||
),
|
||||
array(
|
||||
'/* Exploit * / DROP TABLE node; --; another comment */ ',
|
||||
'/* Exploit * / DROP TABLE node. --. another comment */ ',
|
||||
array('Exploit * / DROP TABLE node; --', 'another comment'),
|
||||
),
|
||||
);
|
||||
|
@ -286,8 +286,8 @@ class ConnectionTest extends UnitTestCase {
|
|||
public function providerFilterComments() {
|
||||
return array(
|
||||
array('', ''),
|
||||
array('Exploit * / DROP TABLE node; --', 'Exploit * / DROP TABLE node; --'),
|
||||
array('Exploit * / DROP TABLE node; --', 'Exploit */ DROP TABLE node; --'),
|
||||
array('Exploit * / DROP TABLE node. --', 'Exploit * / DROP TABLE node; --'),
|
||||
array('Exploit * / DROP TABLE node. --', 'Exploit */ DROP TABLE node; --'),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -196,7 +196,7 @@ class BaseFieldDefinitionTest extends UnitTestCase {
|
|||
|
||||
// Set default value with NULL.
|
||||
$definition->setDefaultValue(NULL);
|
||||
$this->assertEquals(NULL, $definition->getDefaultValue($entity));
|
||||
$this->assertEquals([], $definition->getDefaultValue($entity));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -35,7 +35,9 @@ class EntityCreateAccessCheckTest extends UnitTestCase {
|
|||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class)->reveal();
|
||||
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
|
||||
$cache_contexts_manager->assertValidTokens()->willReturn(TRUE);
|
||||
$cache_contexts_manager->reveal();
|
||||
$container = new Container();
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
\Drupal::setContainer($container);
|
||||
|
|
|
@ -9,6 +9,8 @@ namespace Drupal\Tests\Core\Entity;
|
|||
|
||||
use Drupal\Core\Entity\EntityType;
|
||||
use Drupal\Core\Entity\EntityTypeInterface;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -283,6 +285,44 @@ class EntityTypeTest extends UnitTestCase {
|
|||
$this->assertEquals($id, $entity_type->id());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getLabel
|
||||
*/
|
||||
public function testGetLabel() {
|
||||
$translatable_label = new TranslatableMarkup($this->randomMachineName());
|
||||
$entity_type = $this->setUpEntityType(array('label' => $translatable_label));
|
||||
$this->assertSame($translatable_label, $entity_type->getLabel());
|
||||
|
||||
$label = $this->randomMachineName();
|
||||
$entity_type = $this->setUpEntityType(array('label' => $label));
|
||||
$this->assertSame($label, $entity_type->getLabel());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getGroupLabel
|
||||
*/
|
||||
public function testGetGroupLabel() {
|
||||
$translatable_group_label = new TranslatableMarkup($this->randomMachineName());
|
||||
$entity_type = $this->setUpEntityType(array('group_label' => $translatable_group_label));
|
||||
$this->assertSame($translatable_group_label, $entity_type->getGroupLabel());
|
||||
|
||||
$default_label = $this->randomMachineName();
|
||||
$entity_type = $this->setUpEntityType(array('group_label' => $default_label));
|
||||
$this->assertSame($default_label, $entity_type->getGroupLabel());
|
||||
|
||||
$default_label = new TranslatableMarkup('Other', array(), array('context' => 'Entity type group'));
|
||||
$entity_type = $this->setUpEntityType([]);
|
||||
|
||||
$string_translation = $this->getMock(TranslationInterface::class);
|
||||
$string_translation->expects($this->atLeastOnce())
|
||||
->method('translate')
|
||||
->with('Other', array(), array('context' => 'Entity type group'))
|
||||
->willReturn($default_label);
|
||||
$entity_type->setStringTranslation($string_translation);
|
||||
|
||||
$this->assertSame($default_label, $entity_type->getGroupLabel());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a mock controller class name.
|
||||
*
|
||||
|
|
|
@ -518,6 +518,8 @@ class EntityUnitTest extends UnitTestCase {
|
|||
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
\Drupal::setContainer($container);
|
||||
|
|
|
@ -66,10 +66,13 @@ class EntityUrlTest extends UnitTestCase {
|
|||
$this->assertEquals($langcode, $uri->getOption('language')->getId());
|
||||
}
|
||||
else {
|
||||
// The expected langcode for a config entity is 'en', because it sets the
|
||||
// value as default property.
|
||||
$expected_langcode = $entity instanceof ConfigEntityInterface ? 'en' : LanguageInterface::LANGCODE_NOT_SPECIFIED;
|
||||
$this->assertEquals($expected_langcode, $uri->getOption('language')->getId());
|
||||
if ($entity instanceof ConfigEntityInterface) {
|
||||
// Config entities do not provide a language with their URIs.
|
||||
$this->assertEquals(NULL, $uri->getOption('language'));
|
||||
}
|
||||
else {
|
||||
$this->assertEquals(LanguageInterface::LANGCODE_NOT_SPECIFIED, $uri->getOption('language')->getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -326,6 +326,42 @@ class ActiveLinkResponseFilterTest extends UnitTestCase {
|
|||
5 => $front_special_link_active . ' ' . $front_path_link_active,
|
||||
];
|
||||
|
||||
// Test cases to verify that links to the front page do not get the
|
||||
// 'is-active' class when not on the front page.
|
||||
$other_link = '<a data-drupal-link-system-path="otherpage">Other page</a>';
|
||||
$other_link_active = '<a data-drupal-link-system-path="otherpage" class="is-active">Other page</a>';
|
||||
$data['<front>-and-other-link-on-other-path'] = [
|
||||
0 => $front_special_link . ' ' . $other_link,
|
||||
1 => 'otherpage',
|
||||
2 => FALSE,
|
||||
3 => 'en',
|
||||
4 => [],
|
||||
5 => $front_special_link . ' ' . $other_link_active,
|
||||
];
|
||||
$data['front-and-other-link-on-other-path'] = [
|
||||
0 => $front_path_link . ' ' . $other_link,
|
||||
1 => 'otherpage',
|
||||
2 => FALSE,
|
||||
3 => 'en',
|
||||
4 => [],
|
||||
5 => $front_path_link . ' ' . $other_link_active,
|
||||
];
|
||||
$data['other-and-<front>-link-on-other-path'] = [
|
||||
0 => $other_link . ' ' . $front_special_link,
|
||||
1 => 'otherpage',
|
||||
2 => FALSE,
|
||||
3 => 'en',
|
||||
4 => [],
|
||||
5 => $other_link_active . ' ' . $front_special_link,
|
||||
];
|
||||
$data['other-and-front-link-on-other-path'] = [
|
||||
0 => $other_link . ' ' . $front_path_link,
|
||||
1 => 'otherpage',
|
||||
2 => FALSE,
|
||||
3 => 'en',
|
||||
4 => [],
|
||||
5 => $other_link_active . ' ' . $front_path_link,
|
||||
];
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
namespace Drupal\Tests\Core\EventSubscriber;
|
||||
|
||||
use Drupal\Core\EventSubscriber\RedirectResponseSubscriber;
|
||||
use Drupal\Core\Routing\RequestContext;
|
||||
use Drupal\Core\Routing\TrustedRedirectResponse;
|
||||
use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\DependencyInjection\Container;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcher;
|
||||
|
@ -33,6 +33,13 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
|
|||
*/
|
||||
protected $requestContext;
|
||||
|
||||
/**
|
||||
* The mocked request context.
|
||||
*
|
||||
* @var \Drupal\Core\Utility\UnroutedUrlAssemblerInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $urlAssembler;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -46,6 +53,17 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
|
|||
->method('getCompleteBaseUrl')
|
||||
->willReturn('http://example.com/drupal');
|
||||
|
||||
$this->urlAssembler = $this->getMock(UnroutedUrlAssemblerInterface::class);
|
||||
$this->urlAssembler
|
||||
->expects($this->any())
|
||||
->method('assemble')
|
||||
->willReturnMap([
|
||||
['base:test', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/test'],
|
||||
['base:example.com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/example.com'],
|
||||
['base:example:com', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/example:com'],
|
||||
['base:javascript:alert(0)', ['query' => [], 'fragment' => '', 'absolute' => TRUE], FALSE, 'http://example.com/drupal/javascript:alert(0)'],
|
||||
]);
|
||||
|
||||
$container = new Container();
|
||||
$container->set('router.request_context', $this->requestContext);
|
||||
\Drupal::setContainer($container);
|
||||
|
@ -66,27 +84,9 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
|
|||
$dispatcher = new EventDispatcher();
|
||||
$kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
|
||||
$response = new RedirectResponse('http://example.com/drupal');
|
||||
$url_generator = $this->getMockBuilder('Drupal\Core\Routing\UrlGenerator')
|
||||
->disableOriginalConstructor()
|
||||
->setMethods(array('generateFromPath'))
|
||||
->getMock();
|
||||
|
||||
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'],
|
||||
]);
|
||||
}
|
||||
|
||||
$request->headers->set('HOST', 'example.com');
|
||||
|
||||
$listener = new RedirectResponseSubscriber($url_generator, $this->requestContext);
|
||||
$listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
|
||||
$dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
|
||||
$event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
|
||||
$dispatcher->dispatch(KernelEvents::RESPONSE, $event);
|
||||
|
@ -127,32 +127,8 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
|
|||
$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);
|
||||
$listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
|
||||
$dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
|
||||
$event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
|
||||
$dispatcher->dispatch(KernelEvents::RESPONSE, $event);
|
||||
|
@ -167,22 +143,10 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
|
|||
$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);
|
||||
$listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
|
||||
$dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
|
||||
$event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
|
||||
$dispatcher->dispatch(KernelEvents::RESPONSE, $event);
|
||||
|
@ -214,13 +178,8 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
|
|||
$dispatcher = new EventDispatcher();
|
||||
$kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
|
||||
$response = new RedirectResponse('http://example.com/drupal');
|
||||
$url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
|
||||
|
||||
$request_context = $this->getMockBuilder('Drupal\Core\Routing\RequestContext')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$listener = new RedirectResponseSubscriber($url_generator, $request_context);
|
||||
$listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
|
||||
$dispatcher->addListener(KernelEvents::RESPONSE, array($listener, 'checkRedirectUrl'));
|
||||
$event = new FilterResponseEvent($kernel, $request, HttpKernelInterface::SUB_REQUEST, $response);
|
||||
$dispatcher->dispatch(KernelEvents::RESPONSE, $event);
|
||||
|
@ -257,9 +216,7 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
|
|||
$request = new Request();
|
||||
$request->query->set('destination', $input);
|
||||
|
||||
$url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
|
||||
$request_context = new RequestContext();
|
||||
$listener = new RedirectResponseSubscriber($url_generator, $request_context);
|
||||
$listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
|
||||
$kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
|
||||
$event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
|
||||
|
||||
|
@ -283,9 +240,7 @@ class RedirectResponseSubscriberTest extends UnitTestCase {
|
|||
$request = new Request();
|
||||
$request->request->set('destination', $input);
|
||||
|
||||
$url_generator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
|
||||
$request_context = new RequestContext();
|
||||
$listener = new RedirectResponseSubscriber($url_generator, $request_context);
|
||||
$listener = new RedirectResponseSubscriber($this->urlAssembler, $this->requestContext);
|
||||
$kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface');
|
||||
$event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
|
||||
|
||||
|
|
|
@ -265,6 +265,11 @@ class ModuleHandlerTest extends UnitTestCase {
|
|||
|
||||
/**
|
||||
* @covers ::loadInclude
|
||||
*
|
||||
* Note we load code, so isolate the test.
|
||||
*
|
||||
* @runInSeparateProcess
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
public function testLoadInclude() {
|
||||
// Include exists.
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Extension;
|
||||
|
||||
use Drupal\simpletest\AssertHelperTrait;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -15,6 +16,8 @@ use Drupal\Tests\UnitTestCase;
|
|||
*/
|
||||
class RequiredModuleUninstallValidatorTest extends UnitTestCase {
|
||||
|
||||
use AssertHelperTrait;
|
||||
|
||||
/**
|
||||
* @var \Drupal\Core\Extension\RequiredModuleUninstallValidator|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
|
@ -73,7 +76,7 @@ class RequiredModuleUninstallValidatorTest extends UnitTestCase {
|
|||
|
||||
$expected = ["The $module module is required"];
|
||||
$reasons = $this->uninstallValidator->validate($module);
|
||||
$this->assertSame($expected, $reasons);
|
||||
$this->assertSame($expected, $this->castSafeStrings($reasons));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,30 +2,30 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Core\Field\FieldFilteredStringTest.
|
||||
* Contains \Drupal\Tests\Core\Field\FieldFilteredMarkupTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\Field;
|
||||
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\Core\Field\FieldFilteredString;
|
||||
use Drupal\Component\Utility\SafeStringInterface;
|
||||
use Drupal\Core\Field\FieldFilteredMarkup;
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Field\FieldFilteredString
|
||||
* @coversDefaultClass \Drupal\Core\Field\FieldFilteredMarkup
|
||||
* @group Field
|
||||
*/
|
||||
class FieldFilteredStringTest extends UnitTestCase {
|
||||
class FieldFilteredMarkupTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::create
|
||||
* @dataProvider providerTestCreate
|
||||
*/
|
||||
public function testCreate($string, $expected, $instance_of_check) {
|
||||
$filtered_string = FieldFilteredString::create($string);
|
||||
$filtered_string = FieldFilteredMarkup::create($string);
|
||||
|
||||
if ($instance_of_check) {
|
||||
$this->assertInstanceOf(FieldFilteredString::class, $filtered_string);
|
||||
$this->assertInstanceOf(FieldFilteredMarkup::class, $filtered_string);
|
||||
}
|
||||
$this->assertSame($expected, (string) $filtered_string);
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class FieldFilteredStringTest extends UnitTestCase {
|
|||
$data[] = ['<em>teststring', '<em>teststring</em>', TRUE];
|
||||
|
||||
// Even safe strings will be escaped.
|
||||
$safe_string = $this->prophesize(SafeStringInterface::class);
|
||||
$safe_string = $this->prophesize(MarkupInterface::class);
|
||||
$safe_string->__toString()->willReturn('<script>teststring</script>');
|
||||
$data[] = [$safe_string->reveal(), 'teststring', TRUE];
|
||||
|
||||
|
@ -57,7 +57,7 @@ class FieldFilteredStringTest extends UnitTestCase {
|
|||
public function testdisplayAllowedTags() {
|
||||
$expected = '<a> <b> <big> <code> <del> <em> <i> <ins> <pre> <q> <small> <span> <strong> <sub> <sup> <tt> <ol> <ul> <li> <p> <br> <img>';
|
||||
|
||||
$this->assertSame($expected, FieldFilteredString::displayAllowedTags());
|
||||
$this->assertSame($expected, FieldFilteredMarkup::displayAllowedTags());
|
||||
}
|
||||
|
||||
}
|
|
@ -8,8 +8,10 @@
|
|||
namespace Drupal\Tests\Core\Field;
|
||||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Field\FieldDefinitionInterface;
|
||||
use Drupal\Core\Field\FieldItemInterface;
|
||||
use Drupal\Core\Field\FieldItemList;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -155,4 +157,60 @@ class FieldItemListTest extends UnitTestCase {
|
|||
$this->assertEquals(TRUE, $field_list_a->equals($field_list_b));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::defaultValuesForm
|
||||
*/
|
||||
public function testDefaultValuesForm() {
|
||||
$field_definition = $this->getMock(FieldDefinitionInterface::class);
|
||||
$field_definition->expects($this->any())
|
||||
->method('getType')
|
||||
->willReturn('field_type');
|
||||
/** @var \Drupal\Core\Field\FieldItemList|\PHPUnit_Framework_MockObject_MockObject $field_list */
|
||||
$field_list = $this->getMock(FieldItemList::class, ['defaultValueWidget'], [$field_definition]);
|
||||
$field_list->expects($this->any())
|
||||
->method('defaultValueWidget')
|
||||
->willReturn(NULL);
|
||||
$form = [];
|
||||
$form_state = new FormState();
|
||||
$string_translation = $this->getStringTranslationStub();
|
||||
$field_list->setStringTranslation($string_translation);
|
||||
|
||||
$this->assertEquals('No widget available for: <em class="placeholder">field_type</em>.', $field_list->defaultValuesForm($form, $form_state)['#markup']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::defaultValuesFormValidate
|
||||
*/
|
||||
public function testDefaultValuesFormValidate() {
|
||||
$field_definition = $this->getMock(FieldDefinitionInterface::class);
|
||||
/** @var \Drupal\Core\Field\FieldItemList|\PHPUnit_Framework_MockObject_MockObject $field_list */
|
||||
$field_list = $this->getMock(FieldItemList::class, ['defaultValueWidget', 'validate'], [$field_definition]);
|
||||
$field_list->expects($this->any())
|
||||
->method('defaultValueWidget')
|
||||
->willReturn(NULL);
|
||||
$field_list->expects($this->never())
|
||||
->method('validate');
|
||||
$form = [];
|
||||
$form_state = new FormState();
|
||||
|
||||
$field_list->defaultValuesFormValidate([], $form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::defaultValuesFormSubmit
|
||||
*/
|
||||
public function testDefaultValuesFormSubmit() {
|
||||
$field_definition = $this->getMock(FieldDefinitionInterface::class);
|
||||
/** @var \Drupal\Core\Field\FieldItemList|\PHPUnit_Framework_MockObject_MockObject $field_list */
|
||||
$field_list = $this->getMock(FieldItemList::class, ['defaultValueWidget', 'getValue'], [$field_definition]);
|
||||
$field_list->expects($this->any())
|
||||
->method('defaultValueWidget')
|
||||
->willReturn(NULL);
|
||||
$form = [];
|
||||
$form_state = new FormState();
|
||||
$field_list->expects($this->never())
|
||||
->method('getValue');
|
||||
|
||||
$this->assertNull($field_list->defaultValuesFormSubmit([], $form, $form_state));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ class ConfirmFormHelperTest extends UnitTestCase {
|
|||
|
||||
$link = ConfirmFormHelper::buildCancelLink($form, new Request());
|
||||
$this->assertSame($cancel_text, $link['#title']);
|
||||
$this->assertSame(['contexts' => ['url.query_args:destination']], $link['#cache']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -49,6 +50,7 @@ class ConfirmFormHelperTest extends UnitTestCase {
|
|||
->will($this->returnValue($cancel_route));
|
||||
$link = ConfirmFormHelper::buildCancelLink($form, new Request());
|
||||
$this->assertEquals(Url::fromRoute($route_name), $link['#url']);
|
||||
$this->assertSame(['contexts' => ['url.query_args:destination']], $link['#cache']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,6 +66,7 @@ class ConfirmFormHelperTest extends UnitTestCase {
|
|||
->will($this->returnValue($expected));
|
||||
$link = ConfirmFormHelper::buildCancelLink($form, new Request());
|
||||
$this->assertEquals($expected, $link['#url']);
|
||||
$this->assertSame(['contexts' => ['url.query_args:destination']], $link['#cache']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -86,6 +89,7 @@ class ConfirmFormHelperTest extends UnitTestCase {
|
|||
->will($this->returnValue($cancel_route));
|
||||
$link = ConfirmFormHelper::buildCancelLink($form, new Request());
|
||||
$this->assertSame($cancel_route, $link['#url']);
|
||||
$this->assertSame(['contexts' => ['url.query_args:destination']], $link['#cache']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,6 +116,7 @@ class ConfirmFormHelperTest extends UnitTestCase {
|
|||
|
||||
$link = ConfirmFormHelper::buildCancelLink($form, new Request($query));
|
||||
$this->assertSame($url, $link['#url']);
|
||||
$this->assertSame(['contexts' => ['url.query_args:destination']], $link['#cache']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -7,9 +7,10 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Form;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Component\Utility\NestedArray;
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Access\AccessResultForbidden;
|
||||
use Drupal\Core\Cache\Context\CacheContextsManager;
|
||||
use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
||||
use Drupal\Core\Form\EnforcedResponseException;
|
||||
use Drupal\Core\Form\FormBuilder;
|
||||
|
@ -19,11 +20,10 @@ use Drupal\Core\Form\FormState;
|
|||
use Drupal\Core\Form\FormStateInterface;
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
use Drupal\Core\Session\AccountProxyInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Drupal\Core\Cache\Context\CacheContextsManager;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Form\FormBuilder
|
||||
|
@ -306,6 +306,53 @@ class FormBuilderTest extends FormTestBase {
|
|||
$this->assertArrayHasKey('#id', $form);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether the triggering element is properly identified.
|
||||
*
|
||||
* @param string $element_value
|
||||
* The input element "#value" value.
|
||||
* @param string $input_value
|
||||
* The corresponding submitted input value.
|
||||
*
|
||||
* @covers ::buildForm
|
||||
*
|
||||
* @dataProvider providerTestBuildFormWithTriggeringElement
|
||||
*/
|
||||
public function testBuildFormWithTriggeringElement($element_value, $input_value) {
|
||||
$form_id = 'test_form_id';
|
||||
$expected_form = $form_id();
|
||||
|
||||
$expected_form['actions']['other_submit'] = [
|
||||
'#type' => 'submit',
|
||||
'#value' => $element_value,
|
||||
];
|
||||
|
||||
$form_arg = $this->getMockForm($form_id, $expected_form, 2);
|
||||
$form_state = new FormState();
|
||||
$form_state->setProcessInput();
|
||||
$form_state->setUserInput(['form_id' => $form_id, 'op' => $input_value]);
|
||||
$this->request->setMethod('POST');
|
||||
$this->formBuilder->buildForm($form_arg, $form_state);
|
||||
|
||||
$this->assertEquals($expected_form['actions']['other_submit']['#value'], $form_state->getTriggeringElement()['#value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for ::testBuildFormWithTriggeringElement().
|
||||
*/
|
||||
public function providerTestBuildFormWithTriggeringElement() {
|
||||
$plain_text = 'Other submit value';
|
||||
$markup = 'Other submit <input> value';
|
||||
return [
|
||||
'plain-text' => [$plain_text, $plain_text],
|
||||
'markup' => [$markup, $markup],
|
||||
// Note: The input is always decoded, see
|
||||
// \Drupal\Core\Form\FormBuilder::buttonWasClicked, so we do not need to
|
||||
// escape the input.
|
||||
'escaped-markup' => [Html::escape($markup), $markup],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the rebuildForm() method for a POST submission.
|
||||
*/
|
||||
|
@ -736,10 +783,7 @@ class FormBuilderTest extends FormTestBase {
|
|||
->willReturnArgument(0);
|
||||
$this->csrfToken->expects($this->atLeastOnce())
|
||||
->method('validate')
|
||||
->will($this->returnValueMap([
|
||||
[$form_token, $form_id, $valid_token],
|
||||
[$form_id, $form_id, $valid_token],
|
||||
]));
|
||||
->willReturn($valid_token);
|
||||
}
|
||||
|
||||
$current_user = $this->prophesize(AccountInterface::class);
|
||||
|
@ -773,7 +817,7 @@ class FormBuilderTest extends FormTestBase {
|
|||
*
|
||||
* @dataProvider providerTestFormTokenCacheability
|
||||
*/
|
||||
function testFormTokenCacheability($token, $is_authenticated, $expected_form_cacheability, $expected_token_cacheability) {
|
||||
public function testFormTokenCacheability($token, $is_authenticated, $expected_form_cacheability, $expected_token_cacheability, $method) {
|
||||
$user = $this->prophesize(AccountProxyInterface::class);
|
||||
$user->isAuthenticated()
|
||||
->willReturn($is_authenticated);
|
||||
|
@ -782,6 +826,7 @@ class FormBuilderTest extends FormTestBase {
|
|||
|
||||
$form_id = 'test_form_id';
|
||||
$form = $form_id();
|
||||
$form['#method'] = $method;
|
||||
|
||||
if (isset($token)) {
|
||||
$form['#token'] = $token;
|
||||
|
@ -797,7 +842,7 @@ class FormBuilderTest extends FormTestBase {
|
|||
|
||||
$form_state = new FormState();
|
||||
$built_form = $this->formBuilder->buildForm($form_arg, $form_state);
|
||||
if (!isset($expected_form_cacheability)) {
|
||||
if (!isset($expected_form_cacheability) || ($method == 'get' && !is_string($token))) {
|
||||
$this->assertFalse(isset($built_form['#cache']));
|
||||
}
|
||||
else {
|
||||
|
@ -820,10 +865,12 @@ class FormBuilderTest extends FormTestBase {
|
|||
*/
|
||||
function providerTestFormTokenCacheability() {
|
||||
return [
|
||||
'token:none,authenticated:true' => [NULL, TRUE, ['contexts' => ['user.roles:authenticated']], ['max-age' => 0]],
|
||||
'token:false,authenticated:true' => [FALSE, TRUE, NULL, NULL],
|
||||
'token:none,authenticated:false' => [NULL, FALSE, ['contexts' => ['user.roles:authenticated']], NULL],
|
||||
'token:false,authenticated:false' => [FALSE, FALSE, NULL, NULL],
|
||||
'token:none,authenticated:true' => [NULL, TRUE, ['contexts' => ['user.roles:authenticated']], ['max-age' => 0], 'post'],
|
||||
'token:none,authenticated:false' => [NULL, FALSE, ['contexts' => ['user.roles:authenticated']], NULL, 'post'],
|
||||
'token:false,authenticated:false' => [FALSE, FALSE, NULL, NULL, 'post'],
|
||||
'token:false,authenticated:true' => [FALSE, TRUE, NULL, NULL, 'post'],
|
||||
'token:none,authenticated:false,method:get' => [NULL, FALSE, ['contexts' => ['user.roles:authenticated']], NULL, 'get'],
|
||||
'token:test_form_id,authenticated:false,method:get' => ['test_form_id', TRUE, ['contexts' => ['user.roles:authenticated']], ['max-age' => 0], 'get'],
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -321,34 +321,6 @@ class FormCacheTest extends UnitTestCase {
|
|||
$this->formCache->getCache($form_build_id, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::loadCachedFormState
|
||||
*/
|
||||
public function testLoadCachedFormStateWithSafeStrings() {
|
||||
$this->assertEmpty(SafeMarkup::getAll());
|
||||
$form_build_id = 'the_form_build_id';
|
||||
$form_state = new FormState();
|
||||
$cached_form = ['#cache_token' => NULL];
|
||||
|
||||
$this->formCacheStore->expects($this->once())
|
||||
->method('get')
|
||||
->with($form_build_id)
|
||||
->willReturn($cached_form);
|
||||
$this->account->expects($this->once())
|
||||
->method('isAnonymous')
|
||||
->willReturn(TRUE);
|
||||
|
||||
$cached_form_state = ['build_info' => ['safe_strings' => [
|
||||
'a_safe_string' => ['html' => TRUE],
|
||||
]]];
|
||||
$this->formStateCacheStore->expects($this->once())
|
||||
->method('get')
|
||||
->with($form_build_id)
|
||||
->willReturn($cached_form_state);
|
||||
|
||||
$this->formCache->getCache($form_build_id, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::setCache
|
||||
*/
|
||||
|
@ -364,7 +336,6 @@ class FormCacheTest extends UnitTestCase {
|
|||
->with($form_build_id, $form, $this->isType('int'));
|
||||
|
||||
$form_state_data = $form_state->getCacheableArray();
|
||||
$form_state_data['build_info']['safe_strings'] = [];
|
||||
$this->formStateCacheStore->expects($this->once())
|
||||
->method('setWithExpire')
|
||||
->with($form_build_id, $form_state_data, $this->isType('int'));
|
||||
|
@ -384,7 +355,6 @@ class FormCacheTest extends UnitTestCase {
|
|||
->method('setWithExpire');
|
||||
|
||||
$form_state_data = $form_state->getCacheableArray();
|
||||
$form_state_data['build_info']['safe_strings'] = [];
|
||||
$this->formStateCacheStore->expects($this->once())
|
||||
->method('setWithExpire')
|
||||
->with($form_build_id, $form_state_data, $this->isType('int'));
|
||||
|
@ -408,7 +378,6 @@ class FormCacheTest extends UnitTestCase {
|
|||
->with($form_build_id, $form_data, $this->isType('int'));
|
||||
|
||||
$form_state_data = $form_state->getCacheableArray();
|
||||
$form_state_data['build_info']['safe_strings'] = [];
|
||||
$this->formStateCacheStore->expects($this->once())
|
||||
->method('setWithExpire')
|
||||
->with($form_build_id, $form_state_data, $this->isType('int'));
|
||||
|
@ -423,34 +392,6 @@ class FormCacheTest extends UnitTestCase {
|
|||
$this->formCache->setCache($form_build_id, $form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::setCache
|
||||
*/
|
||||
public function testSetCacheWithSafeStrings() {
|
||||
// A call to SafeMarkup::format() is appropriate in this test as a way to
|
||||
// add a string to the safe list in the simplest way possible.
|
||||
SafeMarkup::format('@value', ['@value' => 'a_safe_string']);
|
||||
$form_build_id = 'the_form_build_id';
|
||||
$form = [
|
||||
'#form_id' => 'the_form_id'
|
||||
];
|
||||
$form_state = new FormState();
|
||||
|
||||
$this->formCacheStore->expects($this->once())
|
||||
->method('setWithExpire')
|
||||
->with($form_build_id, $form, $this->isType('int'));
|
||||
|
||||
$form_state_data = $form_state->getCacheableArray();
|
||||
$form_state_data['build_info']['safe_strings'] = [
|
||||
'a_safe_string' => ['html' => TRUE],
|
||||
];
|
||||
$this->formStateCacheStore->expects($this->once())
|
||||
->method('setWithExpire')
|
||||
->with($form_build_id, $form_state_data, $this->isType('int'));
|
||||
|
||||
$this->formCache->setCache($form_build_id, $form, $form_state);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::setCache
|
||||
*/
|
||||
|
|
|
@ -21,34 +21,28 @@ class FormErrorHandlerTest extends UnitTestCase {
|
|||
* @covers ::displayErrorMessages
|
||||
*/
|
||||
public function testDisplayErrorMessages() {
|
||||
$link_generator = $this->getMock('Drupal\Core\Utility\LinkGeneratorInterface');
|
||||
$link_generator->expects($this->any())
|
||||
->method('generate')
|
||||
->willReturnArgument(0);
|
||||
$renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
|
||||
$form_error_handler = $this->getMockBuilder('Drupal\Core\Form\FormErrorHandler')
|
||||
->setConstructorArgs([$this->getStringTranslationStub(), $link_generator, $renderer])
|
||||
->setMethods(['drupalSetMessage'])
|
||||
->getMock();
|
||||
|
||||
$form_error_handler->expects($this->at(0))
|
||||
->method('drupalSetMessage')
|
||||
->with('no title given', 'error');
|
||||
->with('invalid', 'error');
|
||||
$form_error_handler->expects($this->at(1))
|
||||
->method('drupalSetMessage')
|
||||
->with('element is invisible', 'error');
|
||||
->with('invalid', 'error');
|
||||
$form_error_handler->expects($this->at(2))
|
||||
->method('drupalSetMessage')
|
||||
->with('this missing element is invalid', 'error');
|
||||
->with('invalid', 'error');
|
||||
$form_error_handler->expects($this->at(3))
|
||||
->method('drupalSetMessage')
|
||||
->with('3 errors have been found: <ul-comma-list-mock><li-mock>Test 1</li-mock><li-mock>Test 2 & a half</li-mock><li-mock>Test 3</li-mock></ul-comma-list-mock>', 'error');
|
||||
|
||||
$renderer->expects($this->any())
|
||||
->method('renderPlain')
|
||||
->will($this->returnCallback(function ($render_array) {
|
||||
return $render_array[0]['#markup'] . '<ul-comma-list-mock><li-mock>' . implode(array_map('htmlspecialchars', $render_array[1]['#items']), '</li-mock><li-mock>') . '</li-mock></ul-comma-list-mock>';
|
||||
}));
|
||||
->with('no title given', 'error');
|
||||
$form_error_handler->expects($this->at(4))
|
||||
->method('drupalSetMessage')
|
||||
->with('element is invisible', 'error');
|
||||
$form_error_handler->expects($this->at(5))
|
||||
->method('drupalSetMessage')
|
||||
->with('this missing element is invalid', 'error');
|
||||
|
||||
$form = [
|
||||
'#parents' => [],
|
||||
|
@ -74,13 +68,6 @@ class FormErrorHandlerTest extends UnitTestCase {
|
|||
'#id' => 'edit-test3',
|
||||
],
|
||||
];
|
||||
$form['test4'] = [
|
||||
'#type' => 'textfield',
|
||||
'#title' => 'Test 4',
|
||||
'#parents' => ['test4'],
|
||||
'#id' => 'edit-test4',
|
||||
'#error_no_message' => TRUE,
|
||||
];
|
||||
$form['test5'] = [
|
||||
'#type' => 'textfield',
|
||||
'#parents' => ['test5'],
|
||||
|
@ -96,7 +83,6 @@ class FormErrorHandlerTest extends UnitTestCase {
|
|||
$form_state->setErrorByName('test1', 'invalid');
|
||||
$form_state->setErrorByName('test2', 'invalid');
|
||||
$form_state->setErrorByName('fieldset][test3', 'invalid');
|
||||
$form_state->setErrorByName('test4', 'no error message');
|
||||
$form_state->setErrorByName('test5', 'no title given');
|
||||
$form_state->setErrorByName('test6', 'element is invisible');
|
||||
$form_state->setErrorByName('missing_element', 'this missing element is invalid');
|
||||
|
@ -110,7 +96,6 @@ class FormErrorHandlerTest extends UnitTestCase {
|
|||
*/
|
||||
public function testSetElementErrorsFromFormState() {
|
||||
$form_error_handler = $this->getMockBuilder('Drupal\Core\Form\FormErrorHandler')
|
||||
->setConstructorArgs([$this->getStringTranslationStub(), $this->getMock('Drupal\Core\Utility\LinkGeneratorInterface'), $this->getMock('\Drupal\Core\Render\RendererInterface')])
|
||||
->setMethods(['drupalSetMessage'])
|
||||
->getMock();
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@ namespace Drupal\Tests\Core\Form;
|
|||
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Core\Routing\UrlGeneratorInterface;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Core\Utility\UnroutedUrlAssemblerInterface;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -28,12 +30,20 @@ class FormSubmitterTest extends UnitTestCase {
|
|||
*/
|
||||
protected $urlGenerator;
|
||||
|
||||
/**
|
||||
* The mocked unrouted URL assembler.
|
||||
*
|
||||
* @var \PHPUnit_Framework_MockObject_MockObject|\Drupal\Core\Utility\UnroutedUrlAssemblerInterface
|
||||
*/
|
||||
protected $unroutedUrlAssembler;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
$this->urlGenerator = $this->getMock('Drupal\Core\Routing\UrlGeneratorInterface');
|
||||
$this->urlGenerator = $this->getMock(UrlGeneratorInterface::class);
|
||||
$this->unroutedUrlAssembler = $this->getMock(UnroutedUrlAssemblerInterface::class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -186,10 +196,14 @@ class FormSubmitterTest extends UnitTestCase {
|
|||
*/
|
||||
public function testRedirectWithoutResult() {
|
||||
$form_submitter = $this->getFormSubmitter();
|
||||
$this->urlGenerator->expects($this->never())
|
||||
->method('generateFromPath');
|
||||
$this->urlGenerator->expects($this->never())
|
||||
->method('generateFromRoute');
|
||||
$this->unroutedUrlAssembler->expects($this->never())
|
||||
->method('assemble');
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('url_generator', $this->urlGenerator);
|
||||
$container->set('unrouted_url_assembler', $this->unroutedUrlAssembler);
|
||||
\Drupal::setContainer($container);
|
||||
$form_state = $this->getMock('Drupal\Core\Form\FormStateInterface');
|
||||
$form_state->expects($this->once())
|
||||
->method('getRedirect')
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
namespace Drupal\Tests\Core\Menu;
|
||||
|
||||
use Drupal\Core\Menu\ContextualLinkDefault;
|
||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -71,11 +71,10 @@ class ContextualLinkDefaultTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetTitle() {
|
||||
$title = 'Example';
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslatableMarkup($title, [], [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with($title, array(), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated'));
|
||||
|
||||
$this->setupContextualLinkDefault();
|
||||
|
@ -87,11 +86,10 @@ class ContextualLinkDefaultTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetTitleWithContext() {
|
||||
$title = 'Example';
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslatableMarkup($title, array(), array('context' => 'context'), $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with($title, array(), array('context' => 'context'))
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated with context'));
|
||||
|
||||
$this->setupContextualLinkDefault();
|
||||
|
@ -103,11 +101,10 @@ class ContextualLinkDefaultTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetTitleWithTitleArguments() {
|
||||
$title = 'Example @test';
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array('@test' => 'value')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslatableMarkup($title, array('@test' => 'value'), [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with($title, array('@test' => 'value'), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example value'));
|
||||
|
||||
$this->setupContextualLinkDefault();
|
||||
|
|
|
@ -73,13 +73,18 @@ class DefaultMenuLinkTreeManipulatorsTest extends UnitTestCase {
|
|||
|
||||
$this->accessManager = $this->getMock('\Drupal\Core\Access\AccessManagerInterface');
|
||||
$this->currentUser = $this->getMock('Drupal\Core\Session\AccountInterface');
|
||||
$this->currentUser->method('isAuthenticated')
|
||||
->willReturn(TRUE);
|
||||
$this->queryFactory = $this->getMockBuilder('Drupal\Core\Entity\Query\QueryFactory')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$this->defaultMenuTreeManipulators = new DefaultMenuLinkTreeManipulators($this->accessManager, $this->currentUser, $this->queryFactory);
|
||||
|
||||
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class)->reveal();
|
||||
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
|
||||
$cache_contexts_manager->assertValidTokens()->willReturn(TRUE);
|
||||
$cache_contexts_manager->reveal();
|
||||
|
||||
$container = new Container();
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
\Drupal::setContainer($container);
|
||||
|
@ -97,6 +102,7 @@ class DefaultMenuLinkTreeManipulatorsTest extends UnitTestCase {
|
|||
* - 7
|
||||
* - 6
|
||||
* - 8
|
||||
* - 9
|
||||
*
|
||||
* With link 6 being the only external link.
|
||||
*/
|
||||
|
@ -110,6 +116,7 @@ class DefaultMenuLinkTreeManipulatorsTest extends UnitTestCase {
|
|||
6 => MenuLinkMock::create(array('id' => 'test.example6', 'route_name' => '', 'url' => 'https://www.drupal.org/', 'title' => 'barbar', 'parent' => '')),
|
||||
7 => MenuLinkMock::create(array('id' => 'test.example7', 'route_name' => 'example7', 'title' => 'bazbaz', 'parent' => '')),
|
||||
8 => MenuLinkMock::create(array('id' => 'test.example8', 'route_name' => 'example8', 'title' => 'quxqux', 'parent' => '')),
|
||||
9 => DynamicMenuLinkMock::create(array('id' => 'test.example9', 'parent' => ''))->setCurrentUser($this->currentUser),
|
||||
);
|
||||
$this->originalTree = array();
|
||||
$this->originalTree[1] = new MenuLinkTreeElement($this->links[1], FALSE, 1, FALSE, array());
|
||||
|
@ -123,6 +130,7 @@ class DefaultMenuLinkTreeManipulatorsTest extends UnitTestCase {
|
|||
));
|
||||
$this->originalTree[6] = new MenuLinkTreeElement($this->links[6], FALSE, 1, FALSE, array());
|
||||
$this->originalTree[8] = new MenuLinkTreeElement($this->links[8], FALSE, 1, FALSE, array());
|
||||
$this->originalTree[9] = new MenuLinkTreeElement($this->links[9], FALSE, 1, FALSE, array());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -156,16 +164,17 @@ class DefaultMenuLinkTreeManipulatorsTest extends UnitTestCase {
|
|||
*/
|
||||
public function testCheckAccess() {
|
||||
// Those menu links that are non-external will have their access checks
|
||||
// performed. 8 routes, but 1 is external, 2 already have their 'access'
|
||||
// property set, and 1 is a child if an inaccessible menu link, so only 4
|
||||
// performed. 9 routes, but 1 is external, 2 already have their 'access'
|
||||
// property set, and 1 is a child if an inaccessible menu link, so only 5
|
||||
// calls will be made.
|
||||
$this->accessManager->expects($this->exactly(4))
|
||||
$this->accessManager->expects($this->exactly(5))
|
||||
->method('checkNamedRoute')
|
||||
->will($this->returnValueMap(array(
|
||||
array('example1', array(), $this->currentUser, TRUE, AccessResult::forbidden()),
|
||||
array('example2', array('foo' => 'bar'), $this->currentUser, TRUE, AccessResult::allowed()->cachePerPermissions()),
|
||||
array('example3', array('baz' => 'qux'), $this->currentUser, TRUE, AccessResult::neutral()),
|
||||
array('example5', array(), $this->currentUser, TRUE, AccessResult::allowed()),
|
||||
array('user.logout', array(), $this->currentUser, TRUE, AccessResult::allowed()),
|
||||
)));
|
||||
|
||||
$this->mockTree();
|
||||
|
@ -227,7 +236,7 @@ class DefaultMenuLinkTreeManipulatorsTest extends UnitTestCase {
|
|||
*/
|
||||
public function testCheckAccessWithLinkToAnyPagePermission() {
|
||||
$this->mockTree();
|
||||
$this->currentUser->expects($this->exactly(8))
|
||||
$this->currentUser->expects($this->exactly(9))
|
||||
->method('hasPermission')
|
||||
->with('link to any page')
|
||||
->willReturn(TRUE);
|
||||
|
@ -243,6 +252,7 @@ class DefaultMenuLinkTreeManipulatorsTest extends UnitTestCase {
|
|||
$this->assertEquals($expected_access_result, $this->originalTree[5]->subtree[7]->access);
|
||||
$this->assertEquals($expected_access_result, $this->originalTree[6]->access);
|
||||
$this->assertEquals($expected_access_result, $this->originalTree[8]->access);
|
||||
$this->assertEquals($expected_access_result, $this->originalTree[9]->access);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -253,8 +263,8 @@ class DefaultMenuLinkTreeManipulatorsTest extends UnitTestCase {
|
|||
public function testFlatten() {
|
||||
$this->mockTree();
|
||||
$tree = $this->defaultMenuTreeManipulators->flatten($this->originalTree);
|
||||
$this->assertEquals(array(1, 2, 5, 6, 8), array_keys($this->originalTree));
|
||||
$this->assertEquals(array(1, 2, 5, 6, 8, 3, 4, 7), array_keys($tree));
|
||||
$this->assertEquals(array(1, 2, 5, 6, 8, 9), array_keys($this->originalTree));
|
||||
$this->assertEquals(array(1, 2, 5, 6, 8, 9, 3, 4, 7), array_keys($tree));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
75
core/tests/Drupal/Tests/Core/Menu/DynamicMenuLinkMock.php
Normal file
75
core/tests/Drupal/Tests/Core/Menu/DynamicMenuLinkMock.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Core\Menu\DynamicMenuLinkMock.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\Menu;
|
||||
|
||||
use Drupal\Core\Session\AccountInterface;
|
||||
|
||||
/**
|
||||
* Defines a mock implementation of a dynamic menu link used in tests only.
|
||||
*
|
||||
* Has a dynamic route and title. This is rather contrived, but there are valid
|
||||
* use cases.
|
||||
*
|
||||
* @see \Drupal\user\Plugin\Menu\LoginLogoutMenuLink
|
||||
*/
|
||||
class DynamicMenuLinkMock extends MenuLinkMock {
|
||||
|
||||
/**
|
||||
* The current user.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface
|
||||
*/
|
||||
protected $currentUser;
|
||||
|
||||
/**
|
||||
* Sets the current user.
|
||||
*
|
||||
* Allows the menu link to return the right title and route.
|
||||
*
|
||||
* @param \Drupal\Core\Session\AccountInterface $current_user
|
||||
* The current user.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setCurrentUser(AccountInterface $current_user) {
|
||||
$this->currentUser = $current_user;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getTitle() {
|
||||
if ($this->currentUser->isAuthenticated()) {
|
||||
return 'Log out';
|
||||
}
|
||||
else {
|
||||
return 'Log in';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getRouteName() {
|
||||
if ($this->currentUser->isAuthenticated()) {
|
||||
return 'user.logout';
|
||||
}
|
||||
else {
|
||||
return 'user.login';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getCacheContexts() {
|
||||
return ['user.roles:authenticated'];
|
||||
}
|
||||
|
||||
}
|
|
@ -8,7 +8,7 @@
|
|||
namespace Drupal\Tests\Core\Menu;
|
||||
|
||||
use Drupal\Core\Menu\LocalActionDefault;
|
||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
@ -83,11 +83,10 @@ class LocalActionDefaultTest extends UnitTestCase {
|
|||
* @see \Drupal\Core\Menu\LocalTaskDefault::getTitle()
|
||||
*/
|
||||
public function testGetTitle() {
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example'))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslatableMarkup('Example', [], [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with('Example', array(), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated'));
|
||||
|
||||
$this->setupLocalActionDefault();
|
||||
|
@ -100,11 +99,10 @@ class LocalActionDefaultTest extends UnitTestCase {
|
|||
* @see \Drupal\Core\Menu\LocalTaskDefault::getTitle()
|
||||
*/
|
||||
public function testGetTitleWithContext() {
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example', array(), array('context' => 'context')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslatableMarkup('Example', array(), array('context' => 'context'), $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with('Example', array(), array('context' => 'context'))
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated with context'));
|
||||
|
||||
$this->setupLocalActionDefault();
|
||||
|
@ -115,11 +113,10 @@ class LocalActionDefaultTest extends UnitTestCase {
|
|||
* Tests the getTitle method with title arguments.
|
||||
*/
|
||||
public function testGetTitleWithTitleArguments() {
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslatableMarkup('Example @test', array('@test' => 'value'), [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with('Example @test', array('@test' => 'value'), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example value'));
|
||||
|
||||
$this->setupLocalActionDefault();
|
||||
|
|
|
@ -10,7 +10,7 @@ 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\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\Routing\Route;
|
||||
|
||||
|
@ -233,11 +233,10 @@ class LocalTaskDefaultTest extends UnitTestCase {
|
|||
* @covers ::getTitle
|
||||
*/
|
||||
public function testGetTitle() {
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example'))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslatableMarkup('Example', [], [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with('Example', array(), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated'));
|
||||
|
||||
$this->setupLocalTaskDefault();
|
||||
|
@ -249,11 +248,10 @@ class LocalTaskDefaultTest extends UnitTestCase {
|
|||
*/
|
||||
public function testGetTitleWithContext() {
|
||||
$title = 'Example';
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper($title, array(), array('context' => 'context')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslatableMarkup($title, array(), array('context' => 'context'), $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with($title, array(), array('context' => 'context'))
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example translated with context'));
|
||||
|
||||
$this->setupLocalTaskDefault();
|
||||
|
@ -264,12 +262,10 @@ class LocalTaskDefaultTest extends UnitTestCase {
|
|||
* @covers ::getTitle
|
||||
*/
|
||||
public function testGetTitleWithTitleArguments() {
|
||||
$title = 'Example @test';
|
||||
$this->pluginDefinition['title'] = (new TranslationWrapper('Example @test', array('@test' => 'value')))
|
||||
->setStringTranslation($this->stringTranslation);
|
||||
$this->pluginDefinition['title'] = (new TranslatableMarkup('Example @test', array('@test' => 'value'), [], $this->stringTranslation));
|
||||
$this->stringTranslation->expects($this->once())
|
||||
->method('translate')
|
||||
->with($title, array('@test' => 'value'), array())
|
||||
->method('translateString')
|
||||
->with($this->pluginDefinition['title'])
|
||||
->will($this->returnValue('Example value'));
|
||||
|
||||
$this->setupLocalTaskDefault();
|
||||
|
@ -301,6 +297,23 @@ class LocalTaskDefaultTest extends UnitTestCase {
|
|||
), $this->localTaskBase->getOptions($route_match));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getCacheContexts
|
||||
* @covers ::getCacheTags
|
||||
* @covers ::getCacheMaxAge
|
||||
*/
|
||||
public function testCacheabilityMetadata() {
|
||||
$this->pluginDefinition['cache_contexts'] = ['route'];
|
||||
$this->pluginDefinition['cache_tags'] = ['kitten'];
|
||||
$this->pluginDefinition['cache_max_age'] = 3600;
|
||||
|
||||
$this->setupLocalTaskDefault();
|
||||
|
||||
$this->assertEquals(['route'], $this->localTaskBase->getCacheContexts());
|
||||
$this->assertEquals(['kitten'], $this->localTaskBase->getCacheTags());
|
||||
$this->assertEquals(3600, $this->localTaskBase->getCacheMaxAge());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestLocalTaskDefault extends LocalTaskDefault {
|
||||
|
|
|
@ -7,10 +7,18 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Menu;
|
||||
|
||||
use Drupal\Core\Access\AccessResult;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Cache\CacheableDependencyInterface;
|
||||
use Drupal\Core\Cache\CacheableMetadata;
|
||||
use Drupal\Core\Cache\Context\CacheContextsManager;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Menu\LocalTaskInterface;
|
||||
use Drupal\Core\Menu\LocalTaskManager;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Prophecy\Argument;
|
||||
use Symfony\Component\HttpFoundation\ParameterBag;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestStack;
|
||||
use Zend\Stdlib\ArrayObject;
|
||||
|
@ -84,6 +92,13 @@ class LocalTaskManagerTest extends UnitTestCase {
|
|||
*/
|
||||
protected $routeMatch;
|
||||
|
||||
/**
|
||||
* The mocked account.
|
||||
*
|
||||
* @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
|
||||
*/
|
||||
protected $account;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
|
@ -98,8 +113,10 @@ class LocalTaskManagerTest extends UnitTestCase {
|
|||
$this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
|
||||
$this->accessManager = $this->getMock('Drupal\Core\Access\AccessManagerInterface');
|
||||
$this->routeMatch = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
|
||||
$this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
|
||||
|
||||
$this->setupLocalTaskManager();
|
||||
$this->setupNullCacheabilityMetadataValidation();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -249,8 +266,7 @@ class LocalTaskManagerTest extends UnitTestCase {
|
|||
->method('getCurrentLanguage')
|
||||
->will($this->returnValue(new Language(array('id' => 'en'))));
|
||||
|
||||
$account = $this->getMock('Drupal\Core\Session\AccountInterface');
|
||||
$this->manager = new LocalTaskManager($this->controllerResolver, $request_stack, $this->routeMatch, $this->routeProvider, $module_handler, $this->cacheBackend, $language_manager, $this->accessManager, $account);
|
||||
$this->manager = new LocalTaskManager($this->controllerResolver, $request_stack, $this->routeMatch, $this->routeProvider, $module_handler, $this->cacheBackend, $language_manager, $this->accessManager, $this->account);
|
||||
|
||||
$property = new \ReflectionProperty('Drupal\Core\Menu\LocalTaskManager', 'discovery');
|
||||
$property->setAccessible(TRUE);
|
||||
|
@ -393,5 +409,92 @@ class LocalTaskManagerTest extends UnitTestCase {
|
|||
return $local_tasks;
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getTasksBuild
|
||||
*/
|
||||
public function testGetTasksBuildWithCacheabilityMetadata() {
|
||||
$definitions = $this->getLocalTaskFixtures();
|
||||
|
||||
$this->pluginDiscovery->expects($this->once())
|
||||
->method('getDefinitions')
|
||||
->will($this->returnValue($definitions));
|
||||
|
||||
// Set up some cacheablity metadata and ensure its merged together.
|
||||
$definitions['menu_local_task_test_tasks_settings']['cache_tags'] = ['tag.example1'];
|
||||
$definitions['menu_local_task_test_tasks_settings']['cache_contexts'] = ['context.example1'];
|
||||
$definitions['menu_local_task_test_tasks_edit']['cache_tags'] = ['tag.example2'];
|
||||
$definitions['menu_local_task_test_tasks_edit']['cache_contexts'] = ['context.example2'];
|
||||
// Test the cacheability metadata of access checking.
|
||||
$definitions['menu_local_task_test_tasks_view_child1']['access'] = AccessResult::allowed()->addCacheContexts(['user.permissions']);
|
||||
|
||||
$this->setupFactoryAndLocalTaskPlugins($definitions, 'menu_local_task_test_tasks_view');
|
||||
$this->setupLocalTaskManager();
|
||||
|
||||
$this->controllerResolver->expects($this->any())
|
||||
->method('getArguments')
|
||||
->willReturn([]);
|
||||
|
||||
$this->routeMatch->expects($this->any())
|
||||
->method('getRouteName')
|
||||
->willReturn('menu_local_task_test_tasks_view');
|
||||
$this->routeMatch->expects($this->any())
|
||||
->method('getRawParameters')
|
||||
->willReturn(new ParameterBag());
|
||||
|
||||
$cacheability = new CacheableMetadata();
|
||||
$local_tasks = $this->manager->getTasksBuild('menu_local_task_test_tasks_view', $cacheability);
|
||||
|
||||
// Ensure that all cacheability metadata is merged together.
|
||||
$this->assertEquals(['tag.example1', 'tag.example2'], $cacheability->getCacheTags());
|
||||
$this->assertEquals(['context.example1', 'context.example2', 'route', 'user.permissions'], $cacheability->getCacheContexts());
|
||||
}
|
||||
|
||||
protected function setupFactoryAndLocalTaskPlugins(array $definitions, $active_plugin_id) {
|
||||
$map = [];
|
||||
$access_manager_map = [];
|
||||
|
||||
foreach ($definitions as $plugin_id => $info) {
|
||||
$info += ['access' => AccessResult::allowed()];
|
||||
|
||||
$mock = $this->prophesize(LocalTaskInterface::class);
|
||||
$mock->willImplement(CacheableDependencyInterface::class);
|
||||
$mock->getRouteName()->willReturn($info['route_name']);
|
||||
$mock->getTitle()->willReturn($info['title']);
|
||||
$mock->getRouteParameters(Argument::cetera())->willReturn([]);
|
||||
$mock->getOptions(Argument::cetera())->willReturn([]);
|
||||
$mock->getActive()->willReturn($plugin_id === $active_plugin_id);
|
||||
$mock->getWeight()->willReturn(isset($info['weight']) ? $info['weight'] : 0);
|
||||
$mock->getCacheContexts()->willReturn(isset($info['cache_contexts']) ? $info['cache_contexts'] : []);
|
||||
$mock->getCacheTags()->willReturn(isset($info['cache_tags']) ? $info['cache_tags'] : []);
|
||||
$mock->getCacheMaxAge()->willReturn(isset($info['cache_max_age']) ? $info['cache_max_age'] : Cache::PERMANENT);
|
||||
|
||||
|
||||
$access_manager_map[] = [$info['route_name'], [], $this->account, TRUE, $info['access']];
|
||||
|
||||
$map[] = [$info['id'], [], $mock->reveal()];
|
||||
}
|
||||
|
||||
$this->accessManager->expects($this->any())
|
||||
->method('checkNamedRoute')
|
||||
->willReturnMap($access_manager_map);
|
||||
|
||||
$this->factory->expects($this->any())
|
||||
->method('createInstance')
|
||||
->will($this->returnValueMap($map));
|
||||
}
|
||||
|
||||
protected function setupNullCacheabilityMetadataValidation() {
|
||||
$container = \Drupal::hasContainer() ? \Drupal::getContainer() : new ContainerBuilder();
|
||||
|
||||
$cache_context_manager = $this->prophesize(CacheContextsManager::class);
|
||||
|
||||
foreach ([NULL, ['user.permissions'], ['route'], ['route', 'context.example1'], ['context.example1', 'route'], ['context.example1', 'route', 'context.example2'], ['context.example1', 'context.example2', 'route'], ['context.example1', 'context.example2', 'route', 'user.permissions']] as $argument) {
|
||||
$cache_context_manager->assertValidTokens($argument)->willReturn(TRUE);
|
||||
}
|
||||
|
||||
$container->set('cache_contexts_manager', $cache_context_manager->reveal());
|
||||
\Drupal::setContainer($container);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -62,6 +62,7 @@ class PathProcessorTest extends UnitTestCase {
|
|||
$method_definitions = array(
|
||||
LanguageNegotiationUrl::METHOD_ID => array(
|
||||
'class' => '\Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl',
|
||||
'weight' => 9,
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -134,7 +135,10 @@ class PathProcessorTest extends UnitTestCase {
|
|||
->getMock();
|
||||
$negotiator->expects($this->any())
|
||||
->method('getNegotiationMethods')
|
||||
->will($this->returnValue(array(LanguageNegotiationUrl::METHOD_ID => array('class' => 'Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl'))));
|
||||
->will($this->returnValue(array(LanguageNegotiationUrl::METHOD_ID => array(
|
||||
'class' => 'Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl',
|
||||
'weight' => 9,
|
||||
))));
|
||||
$method = new LanguageNegotiationUrl();
|
||||
$method->setConfig($config_factory_stub);
|
||||
$method->setLanguageManager($this->languageManager);
|
||||
|
|
|
@ -83,10 +83,8 @@ class ContextTest extends UnitTestCase {
|
|||
->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);
|
||||
$context = new Context($this->contextDefinition, $typed_data);
|
||||
$this->assertSame($typed_data, $context->getContextData());
|
||||
}
|
||||
|
||||
|
@ -120,7 +118,7 @@ class ContextTest extends UnitTestCase {
|
|||
->method('getCacheMaxAge')
|
||||
->willReturn(60);
|
||||
|
||||
$context->setContextValue($cacheable_dependency);
|
||||
$context = Context::createFromContext($context, $cacheable_dependency);
|
||||
$this->assertSame($cacheable_dependency, $context->getContextData());
|
||||
$this->assertEquals(['node:1'], $context->getCacheTags());
|
||||
$this->assertEquals(['route'], $context->getCacheContexts());
|
||||
|
|
|
@ -50,11 +50,10 @@ class ContextTypedDataTest extends UnitTestCase {
|
|||
\Drupal::setContainer($container);
|
||||
|
||||
$definition = new ContextDefinition('any');
|
||||
$context = new Context($definition);
|
||||
$data_definition = DataDefinition::create('string');
|
||||
$this->typedData = new StringData($data_definition);
|
||||
$this->typedData->setValue('example string');
|
||||
$context->setContextData($this->typedData);
|
||||
$context = new Context($definition, $this->typedData);
|
||||
$value = $context->getContextValue();
|
||||
$this->assertSame($value, $this->typedData->getValue());
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ use Drupal\Component\Plugin\ConfigurablePluginInterface;
|
|||
use Drupal\Core\Plugin\Context\ContextDefinition;
|
||||
use Drupal\Core\Plugin\Context\ContextHandler;
|
||||
use Drupal\Core\Plugin\ContextAwarePluginInterface;
|
||||
use Drupal\Core\TypedData\DataDefinition;
|
||||
use Drupal\Core\TypedData\Plugin\DataType\StringData;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -229,16 +231,20 @@ class ContextHandlerTest extends UnitTestCase {
|
|||
* @covers ::applyContextMapping
|
||||
*/
|
||||
public function testApplyContextMapping() {
|
||||
$context_hit_data = StringData::createInstance(DataDefinition::create('string'));
|
||||
$context_hit_data->setValue('foo');
|
||||
$context_hit = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
|
||||
$context_hit->expects($this->atLeastOnce())
|
||||
->method('getContextValue')
|
||||
->will($this->returnValue(array('foo')));
|
||||
->method('getContextData')
|
||||
->will($this->returnValue($context_hit_data));
|
||||
$context_miss_data = StringData::createInstance(DataDefinition::create('string'));
|
||||
$context_miss_data->setValue('bar');
|
||||
$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');
|
||||
->method('getContextData');
|
||||
|
||||
$contexts = array(
|
||||
'hit' => $context_hit,
|
||||
|
@ -256,7 +262,7 @@ class ContextHandlerTest extends UnitTestCase {
|
|||
->will($this->returnValue(array('hit' => $context_definition)));
|
||||
$plugin->expects($this->once())
|
||||
->method('setContextValue')
|
||||
->with('hit', array('foo'));
|
||||
->with('hit', $context_hit_data);
|
||||
|
||||
// Make sure that the cacheability metadata is passed to the plugin context.
|
||||
$plugin_context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
|
||||
|
@ -416,10 +422,12 @@ class ContextHandlerTest extends UnitTestCase {
|
|||
* @covers ::applyContextMapping
|
||||
*/
|
||||
public function testApplyContextMappingConfigurableAssigned() {
|
||||
$context_data = StringData::createInstance(DataDefinition::create('string'));
|
||||
$context_data->setValue('foo');
|
||||
$context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
|
||||
$context->expects($this->atLeastOnce())
|
||||
->method('getContextValue')
|
||||
->will($this->returnValue(array('foo')));
|
||||
->method('getContextData')
|
||||
->will($this->returnValue($context_data));
|
||||
$context->expects($this->atLeastOnce())
|
||||
->method('hasContextValue')
|
||||
->willReturn(TRUE);
|
||||
|
@ -439,7 +447,7 @@ class ContextHandlerTest extends UnitTestCase {
|
|||
->will($this->returnValue(array('hit' => $context_definition)));
|
||||
$plugin->expects($this->once())
|
||||
->method('setContextValue')
|
||||
->with('hit', array('foo'));
|
||||
->with('hit', $context_data);
|
||||
|
||||
// Make sure that the cacheability metadata is passed to the plugin context.
|
||||
$plugin_context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface');
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Plugin\Discovery;
|
||||
|
||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\Core\Plugin\Discovery\YamlDiscovery;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
|
@ -104,9 +104,9 @@ EOS;
|
|||
$plugin_1 = $definitions['test_plugin'];
|
||||
$plugin_2 = $definitions['test_plugin2'];
|
||||
|
||||
$this->assertInstanceOf(TranslationWrapper::class, $plugin_1['title']);
|
||||
$this->assertInstanceOf(TranslatableMarkup::class, $plugin_1['title']);
|
||||
$this->assertEquals([], $plugin_1['title']->getOptions());
|
||||
$this->assertInstanceOf(TranslationWrapper::class, $plugin_2['title']);
|
||||
$this->assertInstanceOf(TranslatableMarkup::class, $plugin_2['title']);
|
||||
$this->assertEquals(['context' => 'test-context'], $plugin_2['title']->getOptions());
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ class BubbleableMetadataTest extends UnitTestCase {
|
|||
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
$container->set('renderer', $renderer);
|
||||
|
@ -664,6 +665,7 @@ class BubbleableMetadataTest extends UnitTestCase {
|
|||
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
\Drupal::setContainer($container);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Render\Element;
|
||||
|
||||
use Drupal\Core\Render\SafeString;
|
||||
use Drupal\Core\Render\Markup;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\Core\Render\Element\HtmlTag;
|
||||
|
||||
|
@ -86,7 +86,7 @@ class HtmlTagTest extends UnitTestCase {
|
|||
// Ensure that #value is not filtered if it is marked as safe.
|
||||
$element = array(
|
||||
'#tag' => 'p',
|
||||
'#value' => SafeString::create('<script>value</script>'),
|
||||
'#value' => Markup::create('<script>value</script>'),
|
||||
);
|
||||
$tags[] = array($element, "<p><script>value</script></p>\n");
|
||||
|
||||
|
@ -106,8 +106,8 @@ class HtmlTagTest extends UnitTestCase {
|
|||
*/
|
||||
public function testPreRenderConditionalComments($element, $expected, $set_safe = FALSE) {
|
||||
if ($set_safe) {
|
||||
$element['#prefix'] = SafeString::create($element['#prefix']);
|
||||
$element['#suffix'] = SafeString::create($element['#suffix']);
|
||||
$element['#prefix'] = Markup::create($element['#prefix']);
|
||||
$element['#suffix'] = Markup::create($element['#suffix']);
|
||||
}
|
||||
$this->assertEquals($expected, HtmlTag::preRenderConditionalComments($element));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Core\Render\Element\TableSelectTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\Render\Element;
|
||||
|
||||
use Drupal\Core\Form\FormState;
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\Render\Element\Tableselect;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Core\StringTranslation\TranslationWrapper;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Render\Element\Tableselect
|
||||
* @group Render
|
||||
*/
|
||||
class TableSelectTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::processTableselect
|
||||
*/
|
||||
public function testProcessTableselectWithLinkTitle() {
|
||||
$element = [];
|
||||
$form_state = new FormState();
|
||||
$complete_form = [];
|
||||
|
||||
$element_object = new Tableselect([], 'table_select', []);
|
||||
$info = $element_object->getInfo();
|
||||
$element += $info;
|
||||
|
||||
$element['#value'] = 0;
|
||||
|
||||
$element['#options'][] = [
|
||||
'title' => new Link('my-text', Url::fromRoute('<front>'))
|
||||
];
|
||||
|
||||
$element['#attributes'] = [];
|
||||
|
||||
Tableselect::processTableselect($element, $form_state, $complete_form);
|
||||
|
||||
$this->assertEquals('', $element[0]['#title']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::processTableselect
|
||||
*/
|
||||
public function testProcessTableselectWithStringTitle() {
|
||||
$element = [];
|
||||
$form_state = new FormState();
|
||||
$complete_form = [];
|
||||
|
||||
$element_object = new Tableselect([], 'table_select', []);
|
||||
$info = $element_object->getInfo();
|
||||
$element += $info;
|
||||
|
||||
$element['#value'] = 0;
|
||||
|
||||
$element['#options'][] = [
|
||||
'title' => ['data' => ['#title' => 'Static title']],
|
||||
];
|
||||
|
||||
$element['#attributes'] = [];
|
||||
|
||||
Tableselect::processTableselect($element, $form_state, $complete_form);
|
||||
|
||||
$this->assertEquals(new TranslatableMarkup('Update @title', ['@title' => 'Static title']), $element[0]['#title']);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,168 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Core\Render\Placeholder\ChainedPlaceholderStrategyTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\Render\Placeholder;
|
||||
|
||||
use Drupal\Core\Render\Placeholder\ChainedPlaceholderStrategy;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Render\Placeholder\ChainedPlaceholderStrategy
|
||||
* @group Render
|
||||
*/
|
||||
class ChainedPlaceholderStrategyTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* @covers ::addPlaceholderStrategy
|
||||
* @covers ::processPlaceholders
|
||||
*
|
||||
* @dataProvider providerProcessPlaceholders
|
||||
*/
|
||||
public function testProcessPlaceholders($strategies, $placeholders, $result) {
|
||||
$chained_placeholder_strategy = new ChainedPlaceholderStrategy();
|
||||
|
||||
foreach ($strategies as $strategy) {
|
||||
$chained_placeholder_strategy->addPlaceholderStrategy($strategy);
|
||||
}
|
||||
|
||||
$this->assertEquals($result, $chained_placeholder_strategy->processPlaceholders($placeholders));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a list of render strategies, placeholders and results.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerProcessPlaceholders() {
|
||||
$data = [];
|
||||
|
||||
// Empty placeholders.
|
||||
$data['empty placeholders'] = [[], [], []];
|
||||
|
||||
// Placeholder removing strategy.
|
||||
$placeholders = [
|
||||
'remove-me' => ['#markup' => 'I-am-a-llama-that-will-be-removed-sad-face.'],
|
||||
];
|
||||
|
||||
$prophecy = $this->prophesize('\Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface');
|
||||
$prophecy->processPlaceholders($placeholders)->willReturn([]);
|
||||
$dev_null_strategy = $prophecy->reveal();
|
||||
|
||||
$data['placeholder removing strategy'] = [[$dev_null_strategy], $placeholders, []];
|
||||
|
||||
// Fake Single Flush strategy.
|
||||
$placeholders = [
|
||||
'67890' => ['#markup' => 'special-placeholder'],
|
||||
];
|
||||
|
||||
$prophecy = $this->prophesize('\Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface');
|
||||
$prophecy->processPlaceholders($placeholders)->willReturn($placeholders);
|
||||
$single_flush_strategy = $prophecy->reveal();
|
||||
|
||||
$data['fake single flush strategy'] = [[$single_flush_strategy], $placeholders, $placeholders];
|
||||
|
||||
// Fake ESI strategy.
|
||||
$placeholders = [
|
||||
'12345' => ['#markup' => 'special-placeholder-for-esi'],
|
||||
];
|
||||
$result = [
|
||||
'12345' => ['#markup' => '<esi:include src="/fragment/12345" />'],
|
||||
];
|
||||
|
||||
$prophecy = $this->prophesize('\Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface');
|
||||
$prophecy->processPlaceholders($placeholders)->willReturn($result);
|
||||
$esi_strategy = $prophecy->reveal();
|
||||
|
||||
$data['fake esi strategy'] = [[$esi_strategy], $placeholders, $result];
|
||||
|
||||
// ESI + SingleFlush strategy (ESI replaces all).
|
||||
$prophecy = $this->prophesize('\Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface');
|
||||
$prophecy->processPlaceholders($placeholders)->willReturn($result);
|
||||
$esi_strategy = $prophecy->reveal();
|
||||
|
||||
$prophecy = $this->prophesize('\Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface');
|
||||
$prophecy->processPlaceholders($placeholders)->shouldNotBeCalled();
|
||||
$prophecy->processPlaceholders($result)->shouldNotBeCalled();
|
||||
$prophecy->processPlaceholders([])->shouldNotBeCalled();
|
||||
$single_flush_strategy = $prophecy->reveal();
|
||||
|
||||
$data['fake esi and single_flush strategy - esi replaces all'] = [[$esi_strategy, $single_flush_strategy], $placeholders, $result];
|
||||
|
||||
// ESI + SingleFlush strategy (mixed).
|
||||
$placeholders = [
|
||||
'12345' => ['#markup' => 'special-placeholder-for-ESI'],
|
||||
'67890' => ['#markup' => 'special-placeholder'],
|
||||
'foo' => ['#markup' => 'bar'],
|
||||
];
|
||||
|
||||
$esi_result = [
|
||||
'12345' => ['#markup' => '<esi:include src="/fragment/12345" />'],
|
||||
];
|
||||
|
||||
$normal_result = [
|
||||
'67890' => ['#markup' => 'special-placeholder'],
|
||||
'foo' => ['#markup' => 'bar'],
|
||||
];
|
||||
|
||||
$result = $esi_result + $normal_result;
|
||||
|
||||
$prophecy = $this->prophesize('\Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface');
|
||||
$prophecy->processPlaceholders($placeholders)->willReturn($esi_result);
|
||||
$esi_strategy = $prophecy->reveal();
|
||||
|
||||
$prophecy = $this->prophesize('\Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface');
|
||||
$prophecy->processPlaceholders($normal_result)->willReturn($normal_result);
|
||||
$single_flush_strategy = $prophecy->reveal();
|
||||
|
||||
$data['fake esi and single_flush strategy - mixed'] = [[$esi_strategy, $single_flush_strategy], $placeholders, $result];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::processPlaceholders
|
||||
*
|
||||
* @expectedException \AssertionError
|
||||
* @expectedExceptionMessage At least one placeholder strategy must be present; by default the fallback strategy \Drupal\Core\Render\Placeholder\SingleFlushStrategy is always present.
|
||||
*/
|
||||
public function testProcessPlaceholdersNoStrategies() {
|
||||
// Placeholders but no strategies defined.
|
||||
$placeholders = [
|
||||
'assert-me' => ['#markup' => 'I-am-a-llama-that-will-lead-to-an-assertion-by-the-chained-placeholder-strategy.'],
|
||||
];
|
||||
|
||||
$chained_placeholder_strategy = new ChainedPlaceholderStrategy();
|
||||
$chained_placeholder_strategy->processPlaceholders($placeholders);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::processPlaceholders
|
||||
*
|
||||
* @expectedException \AssertionError
|
||||
* @expectedExceptionMessage Processed placeholders must be a subset of all placeholders.
|
||||
*/
|
||||
public function testProcessPlaceholdersWithRoguePlaceholderStrategy() {
|
||||
// Placeholders but no strategies defined.
|
||||
$placeholders = [
|
||||
'assert-me' => ['#markup' => 'llama'],
|
||||
];
|
||||
|
||||
$result = [
|
||||
'assert-me' => ['#markup' => 'llama'],
|
||||
'new-placeholder' => ['#markup' => 'rogue llama'],
|
||||
];
|
||||
|
||||
$prophecy = $this->prophesize('\Drupal\Core\Render\Placeholder\PlaceholderStrategyInterface');
|
||||
$prophecy->processPlaceholders($placeholders)->willReturn($result);
|
||||
$rogue_strategy = $prophecy->reveal();
|
||||
|
||||
$chained_placeholder_strategy = new ChainedPlaceholderStrategy();
|
||||
$chained_placeholder_strategy->addPlaceholderStrategy($rogue_strategy);
|
||||
$chained_placeholder_strategy->processPlaceholders($placeholders);
|
||||
}
|
||||
|
||||
}
|
|
@ -10,7 +10,7 @@ namespace Drupal\Tests\Core\Render;
|
|||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Cache\Cache;
|
||||
use Drupal\Core\Render\SafeString;
|
||||
use Drupal\Core\Render\Markup;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Render\Renderer
|
||||
|
@ -50,11 +50,12 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
* tags in its subtree, i.e. via bubbling)
|
||||
* - B) manually generated placeholder
|
||||
*
|
||||
* So, in total 2*5 = 10 permutations.
|
||||
* So, in total 2*8 = 16 permutations. (On one axis: uncacheable vs.
|
||||
* uncacheable = 2; on the other axis: A1–7 and B = 8.)
|
||||
*
|
||||
* @todo Cases A5, A6 and A7 are not yet supported by core. So that makes for
|
||||
* only 10 permutations currently, instead of 16. That will be done in
|
||||
* https://www.drupal.org/node/2543334
|
||||
* @todo Case A5 is not yet supported by core. So that makes for only 14
|
||||
* permutations currently, instead of 16. That will be done in
|
||||
* https://www.drupal.org/node/2559847
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -69,10 +70,10 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$token_render_array['#cache']['keys'] = $cache_keys;
|
||||
}
|
||||
$token = hash('crc32b', serialize($token_render_array));
|
||||
// \Drupal\Core\Render\SafeString::create() is necessary as the render
|
||||
// \Drupal\Core\Render\Markup::create() is necessary as the render
|
||||
// system would mangle this markup. As this is exactly what happens at
|
||||
// runtime this is a valid use-case.
|
||||
return SafeString::create('<drupal-render-placeholder callback="Drupal\Tests\Core\Render\PlaceholdersTest::callback" arguments="' . '0=' . $args[0] . '" token="' . $token . '"></drupal-render-placeholder>');
|
||||
return Markup::create('<drupal-render-placeholder callback="Drupal\Tests\Core\Render\PlaceholdersTest::callback" arguments="' . '0=' . $args[0] . '" token="' . $token . '"></drupal-render-placeholder>');
|
||||
};
|
||||
|
||||
$extract_placeholder_render_array = function ($placeholder_render_array) {
|
||||
|
@ -141,6 +142,42 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
|
||||
],
|
||||
];
|
||||
// Note the absence of '#create_placeholder', presence of max-age=0 created
|
||||
// by the #lazy_builder callback.
|
||||
// @todo in https://www.drupal.org/node/2559847
|
||||
$base_element_a5 = [];
|
||||
// Note the absence of '#create_placeholder', presence of high cardinality
|
||||
// cache context created by the #lazy_builder callback.
|
||||
// @see \Drupal\Tests\Core\Render\PlaceholdersTest::callbackPerUser()
|
||||
$base_element_a6 = [
|
||||
'#attached' => [
|
||||
'drupalSettings' => [
|
||||
'foo' => 'bar',
|
||||
],
|
||||
],
|
||||
'placeholder' => [
|
||||
'#cache' => [
|
||||
'contexts' => [],
|
||||
],
|
||||
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callbackPerUser', $args],
|
||||
],
|
||||
];
|
||||
// Note the absence of '#create_placeholder', presence of high-invalidation
|
||||
// frequency cache tag created by the #lazy_builder callback.
|
||||
// @see \Drupal\Tests\Core\Render\PlaceholdersTest::callbackTagCurrentTemperature()
|
||||
$base_element_a7 = [
|
||||
'#attached' => [
|
||||
'drupalSettings' => [
|
||||
'foo' => 'bar',
|
||||
],
|
||||
],
|
||||
'placeholder' => [
|
||||
'#cache' => [
|
||||
'contexts' => [],
|
||||
],
|
||||
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callbackTagCurrentTemperature', $args],
|
||||
],
|
||||
];
|
||||
// Note the absence of '#create_placeholder', but the presence of
|
||||
// '#attached[placeholders]'.
|
||||
$base_element_b = [
|
||||
|
@ -172,6 +209,8 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$expected_placeholder_render_array,
|
||||
FALSE,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
];
|
||||
|
||||
// Case two: render array that has a placeholder that is:
|
||||
|
@ -185,6 +224,8 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$args,
|
||||
$expected_placeholder_render_array,
|
||||
$keys,
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'#markup' => '<p>This is a rendered placeholder!</p>',
|
||||
'#attached' => [
|
||||
|
@ -211,6 +252,8 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$expected_placeholder_render_array,
|
||||
FALSE,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
];
|
||||
|
||||
// Case four: render array that has a placeholder that is:
|
||||
|
@ -224,7 +267,9 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$args,
|
||||
$expected_placeholder_render_array,
|
||||
FALSE,
|
||||
[]
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
];
|
||||
|
||||
// Case five: render array that has a placeholder that is:
|
||||
|
@ -239,6 +284,8 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$expected_placeholder_render_array,
|
||||
FALSE,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
];
|
||||
|
||||
// Case six: render array that has a placeholder that is:
|
||||
|
@ -257,6 +304,8 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$args,
|
||||
$expected_placeholder_render_array,
|
||||
$cid_parts,
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'#markup' => '<p>This is a rendered placeholder!</p>',
|
||||
'#attached' => [
|
||||
|
@ -284,6 +333,8 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$expected_placeholder_render_array,
|
||||
FALSE,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
];
|
||||
|
||||
// Case eight: render array that has a placeholder that is:
|
||||
|
@ -298,6 +349,8 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$args,
|
||||
$expected_placeholder_render_array,
|
||||
$keys,
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'#markup' => '<p>This is a rendered placeholder!</p>',
|
||||
'#attached' => [
|
||||
|
@ -313,7 +366,109 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
],
|
||||
];
|
||||
|
||||
// Case nine: render array that has a placeholder that is:
|
||||
// Case nine: render array that DOES NOT have a placeholder that is:
|
||||
// - NOT created, despite max-age=0 that is bubbled
|
||||
// - uncacheable
|
||||
// (because the render element with #lazy_builder does not have #cache[keys]
|
||||
// and hence the max-age=0 bubbles up further)
|
||||
// @todo in https://www.drupal.org/node/2559847
|
||||
|
||||
// Case ten: render array that has a placeholder that is:
|
||||
// - automatically created, and automatically triggered due to max-age=0
|
||||
// that is bubbled
|
||||
// - cacheable
|
||||
// @todo in https://www.drupal.org/node/2559847
|
||||
|
||||
// Case eleven: render array that DOES NOT have a placeholder that is:
|
||||
// - NOT created, despite high cardinality cache contexts that are bubbled
|
||||
// - uncacheable
|
||||
$element_without_cache_keys = $base_element_a6;
|
||||
$expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a6['placeholder']);
|
||||
$cases[] = [
|
||||
$element_without_cache_keys,
|
||||
$args,
|
||||
$expected_placeholder_render_array,
|
||||
FALSE,
|
||||
['user'],
|
||||
[],
|
||||
[],
|
||||
];
|
||||
|
||||
// Case twelve: render array that has a placeholder that is:
|
||||
// - automatically created, and automatically triggered due to high
|
||||
// cardinality cache contexts that are bubbled
|
||||
// - cacheable
|
||||
$element_with_cache_keys = $base_element_a6;
|
||||
$element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
|
||||
$expected_placeholder_render_array['#cache']['keys'] = $keys;
|
||||
$cases[] = [
|
||||
$element_with_cache_keys,
|
||||
$args,
|
||||
$expected_placeholder_render_array,
|
||||
$keys,
|
||||
['user'],
|
||||
[],
|
||||
[
|
||||
'#markup' => '<p>This is a rendered placeholder!</p>',
|
||||
'#attached' => [
|
||||
'drupalSettings' => [
|
||||
'dynamic_animal' => $args[0],
|
||||
],
|
||||
],
|
||||
'#cache' => [
|
||||
'contexts' => ['user'],
|
||||
'tags' => [],
|
||||
'max-age' => Cache::PERMANENT,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// Case thirteen: render array that has a placeholder that is:
|
||||
// - automatically created, and automatically triggered due to high
|
||||
// invalidation frequency cache tags that are bubbled
|
||||
// - uncacheable
|
||||
$element_without_cache_keys = $base_element_a7;
|
||||
$expected_placeholder_render_array = $extract_placeholder_render_array($base_element_a7['placeholder']);
|
||||
$cases[] = [
|
||||
$element_without_cache_keys,
|
||||
$args,
|
||||
$expected_placeholder_render_array,
|
||||
FALSE,
|
||||
[],
|
||||
['current-temperature'],
|
||||
[],
|
||||
];
|
||||
|
||||
// Case fourteen: render array that has a placeholder that is:
|
||||
// - automatically created, and automatically triggered due to high
|
||||
// invalidation frequency cache tags that are bubbled
|
||||
// - cacheable
|
||||
$element_with_cache_keys = $base_element_a7;
|
||||
$element_with_cache_keys['placeholder']['#cache']['keys'] = $keys;
|
||||
$expected_placeholder_render_array['#cache']['keys'] = $keys;
|
||||
$cases[] = [
|
||||
$element_with_cache_keys,
|
||||
$args,
|
||||
$expected_placeholder_render_array,
|
||||
$keys,
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'#markup' => '<p>This is a rendered placeholder!</p>',
|
||||
'#attached' => [
|
||||
'drupalSettings' => [
|
||||
'dynamic_animal' => $args[0],
|
||||
],
|
||||
],
|
||||
'#cache' => [
|
||||
'contexts' => [],
|
||||
'tags' => ['current-temperature'],
|
||||
'max-age' => Cache::PERMANENT,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
// Case fifteen: render array that has a placeholder that is:
|
||||
// - manually created
|
||||
// - uncacheable
|
||||
$x = $base_element_b;
|
||||
|
@ -325,9 +480,11 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$expected_placeholder_render_array,
|
||||
FALSE,
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
];
|
||||
|
||||
// Case ten: render array that has a placeholder that is:
|
||||
// Case sixteen: render array that has a placeholder that is:
|
||||
// - manually created
|
||||
// - cacheable
|
||||
$x = $base_element_b;
|
||||
|
@ -345,6 +502,8 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
$args,
|
||||
$expected_placeholder_render_array,
|
||||
$keys,
|
||||
[],
|
||||
[],
|
||||
[
|
||||
'#markup' => '<p>This is a rendered placeholder!</p>',
|
||||
'#attached' => [
|
||||
|
@ -388,11 +547,28 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
* @param array $expected_data
|
||||
* FALSE if no render cache item is expected, a render array with the
|
||||
* expected values if a render cache item is expected.
|
||||
* @param string[] $bubbled_cache_contexts
|
||||
* Additional cache contexts that were bubbled when the placeholder was
|
||||
* rendered.
|
||||
*/
|
||||
protected function assertPlaceholderRenderCache($cid_parts, array $expected_data) {
|
||||
protected function assertPlaceholderRenderCache($cid_parts, array $bubbled_cache_contexts, array $expected_data) {
|
||||
if ($cid_parts !== FALSE) {
|
||||
if ($bubbled_cache_contexts) {
|
||||
// Verify render cached placeholder.
|
||||
$cached_element = $this->memoryCache->get(implode(':', $cid_parts))->data;
|
||||
$expected_redirect_element = [
|
||||
'#cache_redirect' => TRUE,
|
||||
'#cache' => $expected_data['#cache'] + [
|
||||
'keys' => $cid_parts,
|
||||
'bin' => 'render',
|
||||
],
|
||||
];
|
||||
$this->assertEquals($expected_redirect_element, $cached_element, 'The correct cache redirect exists.');
|
||||
}
|
||||
|
||||
// Verify render cached placeholder.
|
||||
$cached_element = $this->memoryCache->get(implode(':', $cid_parts))->data;
|
||||
$cached = $this->memoryCache->get(implode(':', array_merge($cid_parts, $bubbled_cache_contexts)));
|
||||
$cached_element = $cached->data;
|
||||
$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.');
|
||||
}
|
||||
}
|
||||
|
@ -402,7 +578,7 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
*
|
||||
* @dataProvider providerPlaceholders
|
||||
*/
|
||||
public function testUncacheableParent($element, $args, array $expected_placeholder_render_array, $placeholder_cid_parts, array $placeholder_expected_render_cache_array) {
|
||||
public function testUncacheableParent($element, $args, array $expected_placeholder_render_array, $placeholder_cid_parts, array $bubbled_cache_contexts, array $bubbled_cache_tags, array $placeholder_expected_render_cache_array) {
|
||||
if ($placeholder_cid_parts) {
|
||||
$this->setupMemoryCache();
|
||||
}
|
||||
|
@ -422,7 +598,7 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
'dynamic_animal' => $args[0],
|
||||
];
|
||||
$this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the one added by the placeholder #lazy_builder callback exist.');
|
||||
$this->assertPlaceholderRenderCache($placeholder_cid_parts, $placeholder_expected_render_cache_array);
|
||||
$this->assertPlaceholderRenderCache($placeholder_cid_parts, $bubbled_cache_contexts, $placeholder_expected_render_cache_array);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -434,14 +610,15 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
*
|
||||
* @dataProvider providerPlaceholders
|
||||
*/
|
||||
public function testCacheableParent($test_element, $args, array $expected_placeholder_render_array, $placeholder_cid_parts, array $placeholder_expected_render_cache_array) {
|
||||
public function testCacheableParent($test_element, $args, array $expected_placeholder_render_array, $placeholder_cid_parts, array $bubbled_cache_contexts, array $bubbled_cache_tags, array $placeholder_expected_render_cache_array) {
|
||||
$element = $test_element;
|
||||
$this->setupMemoryCache();
|
||||
|
||||
$this->setUpRequest('GET');
|
||||
|
||||
$token = hash('crc32b', serialize($expected_placeholder_render_array));
|
||||
$expected_placeholder_markup = '<drupal-render-placeholder callback="Drupal\Tests\Core\Render\PlaceholdersTest::callback" arguments="0=' . $args[0] . '" token="' . $token . '"></drupal-render-placeholder>';
|
||||
$placeholder_callback = $expected_placeholder_render_array['#lazy_builder'][0];
|
||||
$expected_placeholder_markup = '<drupal-render-placeholder callback="' . $placeholder_callback . '" arguments="0=' . $args[0] . '" token="' . $token . '"></drupal-render-placeholder>';
|
||||
$this->assertSame($expected_placeholder_markup, Html::normalize($expected_placeholder_markup), 'Placeholder unaltered by Html::normalize() which is used by FilterHtmlCorrector.');
|
||||
|
||||
// GET request: #cache enabled, cache miss.
|
||||
|
@ -456,30 +633,105 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
'dynamic_animal' => $args[0],
|
||||
];
|
||||
$this->assertSame($element['#attached']['drupalSettings'], $expected_js_settings, '#attached is modified; both the original JavaScript setting and the one added by the placeholder #lazy_builder callback exist.');
|
||||
$this->assertPlaceholderRenderCache($placeholder_cid_parts, $placeholder_expected_render_cache_array);
|
||||
$this->assertPlaceholderRenderCache($placeholder_cid_parts, $bubbled_cache_contexts, $placeholder_expected_render_cache_array);
|
||||
|
||||
// GET request: validate cached data.
|
||||
$cached_element = $this->memoryCache->get('placeholder_test_GET')->data;
|
||||
$expected_element = [
|
||||
'#markup' => '<p>#cache enabled, GET</p>' . $expected_placeholder_markup,
|
||||
'#attached' => [
|
||||
'drupalSettings' => [
|
||||
'foo' => 'bar',
|
||||
$cached = $this->memoryCache->get('placeholder_test_GET');
|
||||
// There are three edge cases, where the shape of the render cache item for
|
||||
// the parent (with CID 'placeholder_test_GET') is vastly different. These
|
||||
// are the cases where:
|
||||
// - the placeholder is uncacheable (because it has no #cache[keys]), and;
|
||||
// - cacheability metadata that meets auto_placeholder_conditions is bubbled
|
||||
$has_uncacheable_lazy_builder = !isset($test_element['placeholder']['#cache']['keys']) && isset($test_element['placeholder']['#lazy_builder']);
|
||||
// Edge cases: always where both bubbling of an auto-placeholdering
|
||||
// condition happens from within a #lazy_builder that is uncacheable.
|
||||
// - uncacheable + A5 (cache max-age)
|
||||
// @todo in https://www.drupal.org/node/2559847
|
||||
// - uncacheable + A6 (cache context)
|
||||
$edge_case_a6_uncacheable = $has_uncacheable_lazy_builder && $test_element['placeholder']['#lazy_builder'][0] === 'Drupal\Tests\Core\Render\PlaceholdersTest::callbackPerUser';
|
||||
// - uncacheable + A7 (cache tag)
|
||||
$edge_case_a7_uncacheable = $has_uncacheable_lazy_builder && $test_element['placeholder']['#lazy_builder'][0] === 'Drupal\Tests\Core\Render\PlaceholdersTest::callbackTagCurrentTemperature';
|
||||
// The redirect-cacheable edge case: a high-cardinality cache context is
|
||||
// bubbled from a #lazy_builder callback for an uncacheable placeholder. The
|
||||
// element containing the uncacheable placeholder has cache keys set, and
|
||||
// due to the bubbled cache contexts it creates a cache redirect.
|
||||
if ($edge_case_a6_uncacheable) {
|
||||
$cached_element = $cached->data;
|
||||
$expected_redirect = [
|
||||
'#cache_redirect' => TRUE,
|
||||
'#cache' => [
|
||||
'keys' => ['placeholder_test_GET'],
|
||||
'contexts' => ['user'],
|
||||
'tags' => [],
|
||||
'max-age' => Cache::PERMANENT,
|
||||
'bin' => 'render',
|
||||
],
|
||||
'placeholders' => [
|
||||
$expected_placeholder_markup => [
|
||||
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
|
||||
];
|
||||
$this->assertEquals($expected_redirect, $cached_element);
|
||||
// Follow the redirect.
|
||||
$cached_element = $this->memoryCache->get('placeholder_test_GET:' . implode(':', $bubbled_cache_contexts))->data;
|
||||
$expected_element = [
|
||||
'#markup' => '<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>',
|
||||
'#attached' => [
|
||||
'drupalSettings' => [
|
||||
'foo' => 'bar',
|
||||
'dynamic_animal' => $args[0],
|
||||
],
|
||||
],
|
||||
],
|
||||
'#cache' => [
|
||||
'contexts' => [],
|
||||
'tags' => [],
|
||||
'max-age' => Cache::PERMANENT,
|
||||
],
|
||||
];
|
||||
$expected_element['#attached']['placeholders'][$expected_placeholder_markup] = $expected_placeholder_render_array;
|
||||
$this->assertEquals($cached_element, $expected_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by placeholder #lazy_builder callbacks.');
|
||||
'#cache' => [
|
||||
'contexts' => $bubbled_cache_contexts,
|
||||
'tags' => [],
|
||||
'max-age' => Cache::PERMANENT,
|
||||
],
|
||||
];
|
||||
$this->assertEquals($expected_element, $cached_element, 'The parent is render cached with a redirect in ase a cache context is bubbled from an uncacheable child (no #cache[keys]) with a #lazy_builder.');
|
||||
}
|
||||
// The normally cacheable edge case: a high-invalidation frequency cache tag
|
||||
// is bubbled from a #lazy_builder callback for an uncacheable placeholder.
|
||||
// The element containing the uncacheable placeholder has cache keys set,
|
||||
// and also has the bubbled cache tags.
|
||||
elseif ($edge_case_a7_uncacheable) {
|
||||
$cached_element = $cached->data;
|
||||
$expected_element = [
|
||||
'#markup' => '<p>#cache enabled, GET</p><p>This is a rendered placeholder!</p>',
|
||||
'#attached' => [
|
||||
'drupalSettings' => [
|
||||
'foo' => 'bar',
|
||||
'dynamic_animal' => $args[0],
|
||||
],
|
||||
],
|
||||
'#cache' => [
|
||||
'contexts' => [],
|
||||
'tags' => $bubbled_cache_tags,
|
||||
'max-age' => Cache::PERMANENT,
|
||||
],
|
||||
];
|
||||
$this->assertEquals($expected_element, $cached_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by placeholder #lazy_builder callbacks.');
|
||||
}
|
||||
// The regular case.
|
||||
else {
|
||||
$cached_element = $cached->data;
|
||||
$expected_element = [
|
||||
'#markup' => '<p>#cache enabled, GET</p>' . $expected_placeholder_markup,
|
||||
'#attached' => [
|
||||
'drupalSettings' => [
|
||||
'foo' => 'bar',
|
||||
],
|
||||
'placeholders' => [
|
||||
$expected_placeholder_markup => [
|
||||
'#lazy_builder' => ['Drupal\Tests\Core\Render\PlaceholdersTest::callback', $args],
|
||||
],
|
||||
],
|
||||
],
|
||||
'#cache' => [
|
||||
'contexts' => [],
|
||||
'tags' => $bubbled_cache_tags,
|
||||
'max-age' => Cache::PERMANENT,
|
||||
],
|
||||
];
|
||||
$expected_element['#attached']['placeholders'][$expected_placeholder_markup] = $expected_placeholder_render_array;
|
||||
$this->assertEquals($expected_element, $cached_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by placeholder #lazy_builder callbacks.');
|
||||
}
|
||||
|
||||
// GET request: #cache enabled, cache hit.
|
||||
$element = $test_element;
|
||||
|
@ -527,7 +779,7 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
|
||||
// Even when the child element's placeholder is cacheable, it should not
|
||||
// generate a render cache item.
|
||||
$this->assertPlaceholderRenderCache(FALSE, []);
|
||||
$this->assertPlaceholderRenderCache(FALSE, [], []);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -600,7 +852,7 @@ class RendererPlaceholdersTest extends RendererTestBase {
|
|||
]];
|
||||
|
||||
$result = $this->renderer->renderRoot($element);
|
||||
$this->assertInstanceOf('\Drupal\Core\Render\SafeString', $result);
|
||||
$this->assertInstanceOf('\Drupal\Core\Render\Markup', $result);
|
||||
$this->assertEquals('<p>This is a rendered placeholder!</p>', (string) $result);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ 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\Render\Markup;
|
||||
use Drupal\Core\Template\Attribute;
|
||||
|
||||
/**
|
||||
|
@ -35,18 +35,6 @@ class RendererTest extends RendererTestBase {
|
|||
'#children' => '',
|
||||
];
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
// Reset the static list of SafeStrings to prevent bleeding between tests.
|
||||
$reflected_class = new \ReflectionClass('\Drupal\Component\Utility\SafeMarkup');
|
||||
$reflected_property = $reflected_class->getProperty('safeStrings');
|
||||
$reflected_property->setAccessible(true);
|
||||
$reflected_property->setValue([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::render
|
||||
* @covers ::doRender
|
||||
|
@ -111,7 +99,7 @@ class RendererTest extends RendererTestBase {
|
|||
], '<em>foo</em>'];
|
||||
// Safe strings in #plain_text are are still escaped.
|
||||
$data[] = [[
|
||||
'#plain_text' => SafeString::create('<em>foo</em>'),
|
||||
'#plain_text' => Markup::create('<em>foo</em>'),
|
||||
], '<em>foo</em>'];
|
||||
// Renderable child element.
|
||||
$data[] = [[
|
||||
|
@ -737,10 +725,10 @@ class RendererTest extends RendererTestBase {
|
|||
],
|
||||
// Collect expected property names.
|
||||
'#cache_properties' => array_keys(array_filter($expected_results)),
|
||||
'child1' => ['#markup' => SafeString::create('1')],
|
||||
'child2' => ['#markup' => SafeString::create('2')],
|
||||
'child1' => ['#markup' => Markup::create('1')],
|
||||
'child2' => ['#markup' => Markup::create('2')],
|
||||
// Mark the value as safe.
|
||||
'#custom_property' => SafeMarkup::checkPlain('custom_value'),
|
||||
'#custom_property' => Markup::create('custom_value'),
|
||||
'#custom_property_array' => ['custom value'],
|
||||
];
|
||||
|
||||
|
|
|
@ -12,7 +12,8 @@ use Drupal\Core\Cache\CacheableMetadata;
|
|||
use Drupal\Core\Cache\Context\ContextCacheKeys;
|
||||
use Drupal\Core\Cache\MemoryBackend;
|
||||
use Drupal\Core\Render\Element;
|
||||
use Drupal\Core\Render\RenderCache;
|
||||
use Drupal\Core\Render\PlaceholderGenerator;
|
||||
use Drupal\Core\Render\PlaceholderingRenderCache;
|
||||
use Drupal\Core\Render\Renderer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
|
@ -34,10 +35,17 @@ class RendererTestBase extends UnitTestCase {
|
|||
/**
|
||||
* The tested render cache.
|
||||
*
|
||||
* @var \Drupal\Core\Render\RenderCache
|
||||
* @var \Drupal\Core\Render\PlaceholderingRenderCache
|
||||
*/
|
||||
protected $renderCache;
|
||||
|
||||
/**
|
||||
* The tested placeholder generator.
|
||||
*
|
||||
* @var \Drupal\Core\Render\PlaceholderGenerator
|
||||
*/
|
||||
protected $placeholderGenerator;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\HttpFoundation\RequestStack
|
||||
*/
|
||||
|
@ -136,6 +144,7 @@ class RendererTestBase extends UnitTestCase {
|
|||
$this->cacheContextsManager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->cacheContextsManager->method('assertValidTokens')->willReturn(TRUE);
|
||||
$current_user_role = &$this->currentUserRole;
|
||||
$this->cacheContextsManager->expects($this->any())
|
||||
->method('convertTokensToKeys')
|
||||
|
@ -158,8 +167,9 @@ class RendererTestBase extends UnitTestCase {
|
|||
}
|
||||
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->requestStack, $this->rendererConfig);
|
||||
$this->placeholderGenerator = new PlaceholderGenerator($this->rendererConfig);
|
||||
$this->renderCache = new PlaceholderingRenderCache($this->requestStack, $this->cacheFactory, $this->cacheContextsManager, $this->placeholderGenerator);
|
||||
$this->renderer = new Renderer($this->controllerResolver, $this->themeManager, $this->elementInfo, $this->placeholderGenerator, $this->renderCache, $this->requestStack, $this->rendererConfig);
|
||||
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('cache_contexts_manager', $this->cacheContextsManager);
|
||||
|
@ -269,4 +279,34 @@ class PlaceholdersTest {
|
|||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* #lazy_builder callback; attaches setting, generates markup, user-specific.
|
||||
*
|
||||
* @param string $animal
|
||||
* An animal.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array.
|
||||
*/
|
||||
public static function callbackPerUser($animal) {
|
||||
$build = static::callback($animal);
|
||||
$build['#cache']['contexts'][] = 'user';
|
||||
return $build;
|
||||
}
|
||||
|
||||
/**
|
||||
* #lazy_builder callback; attaches setting, generates markup, cache tag.
|
||||
*
|
||||
* @param string $animal
|
||||
* An animal.
|
||||
*
|
||||
* @return array
|
||||
* A renderable array.
|
||||
*/
|
||||
public static function callbackTagCurrentTemperature($animal) {
|
||||
$build = static::callback($animal);
|
||||
$build['#cache']['tags'][] = 'current-temperature';
|
||||
return $build;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -145,7 +145,9 @@ class RoleAccessCheckTest extends UnitTestCase {
|
|||
* @dataProvider roleAccessProvider
|
||||
*/
|
||||
public function testRoleAccess($path, $grant_accounts, $deny_accounts) {
|
||||
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class)->reveal();
|
||||
$cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
|
||||
$cache_contexts_manager->assertValidTokens()->willReturn(TRUE);
|
||||
$cache_contexts_manager->reveal();
|
||||
$container = new Container();
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
\Drupal::setContainer($container);
|
||||
|
|
|
@ -63,6 +63,7 @@ class UrlGeneratorTest extends UnitTestCase {
|
|||
$cache_contexts_manager = $this->getMockBuilder('Drupal\Core\Cache\Context\CacheContextsManager')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$cache_contexts_manager->method('assertValidTokens')->willReturn(TRUE);
|
||||
$container = new ContainerBuilder();
|
||||
$container->set('cache_contexts_manager', $cache_contexts_manager);
|
||||
\Drupal::setContainer($container);
|
||||
|
@ -347,79 +348,6 @@ class UrlGeneratorTest extends UnitTestCase {
|
|||
$this->assertGenerateFromRoute('test_1', [], $options, 'https://localhost/hello/world', (new BubbleableMetadata())->setCacheMaxAge(Cache::PERMANENT)->setCacheContexts(['url.site']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests path-based URL generation.
|
||||
*/
|
||||
public function testPathBasedURLGeneration() {
|
||||
$base_path = '/subdir';
|
||||
$base_url = 'http://www.example.com' . $base_path;
|
||||
|
||||
foreach (array('', 'index.php/') as $script_path) {
|
||||
foreach (array(FALSE, TRUE) as $absolute) {
|
||||
// Setup a fake request which looks like a Drupal installed under the
|
||||
// subdir "subdir" on the domain www.example.com.
|
||||
// To reproduce the values install Drupal like that and use a debugger.
|
||||
$server = [
|
||||
'SCRIPT_NAME' => '/subdir/index.php',
|
||||
'SCRIPT_FILENAME' => $this->root . '/index.php',
|
||||
'SERVER_NAME' => 'http://www.example.com',
|
||||
];
|
||||
$request = Request::create('/subdir/' . $script_path, 'GET', [], [], [], $server);
|
||||
$request->headers->set('host', ['www.example.com']);
|
||||
$this->requestStack->push($request);
|
||||
|
||||
// Determine the expected bubbleable metadata.
|
||||
$expected_cacheability = (new BubbleableMetadata())
|
||||
->setCacheContexts($absolute ? ['url.site'] : [])
|
||||
->setCacheMaxAge(Cache::PERMANENT);
|
||||
|
||||
// Get the expected start of the path string.
|
||||
$base = ($absolute ? $base_url . '/' : $base_path . '/') . $script_path;
|
||||
$url = $base . 'node/123';
|
||||
$result = $this->generator->generateFromPath('node/123', array('absolute' => $absolute));
|
||||
$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, 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, 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, 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, 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, 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, BubbleableMetadata::createFromObject($generated_url));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests generating a relative URL with no path.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Core\StringTranslation\TranslatableMarkupTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\StringTranslation;
|
||||
|
||||
use Drupal\Component\Render\FormattableMarkup;
|
||||
use Drupal\Core\StringTranslation\TranslationInterface;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* Tests the TranslatableMarkup class.
|
||||
*
|
||||
* @coversDefaultClass \Drupal\Core\StringTranslation\TranslatableMarkup
|
||||
* @group StringTranslation
|
||||
*/
|
||||
class TranslatableMarkupTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* The error message of the last error in the error handler.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $lastErrorMessage;
|
||||
|
||||
/**
|
||||
* The error number of the last error in the error handler.
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $lastErrorNumber;
|
||||
|
||||
/**
|
||||
* Custom error handler that saves the last error.
|
||||
*
|
||||
* We need this custom error handler because we cannot rely on the error to
|
||||
* exception conversion as __toString is never allowed to leak any kind of
|
||||
* exception.
|
||||
*
|
||||
* @param int $error_number
|
||||
* The error number.
|
||||
* @param string $error_message
|
||||
* The error message.
|
||||
*/
|
||||
public function errorHandler($error_number, $error_message) {
|
||||
$this->lastErrorNumber = $error_number;
|
||||
$this->lastErrorMessage = $error_message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that errors are correctly handled when a __toString() fails.
|
||||
*
|
||||
* @covers ::__toString
|
||||
*/
|
||||
public function testToString() {
|
||||
$translation = $this->getMock(TranslationInterface::class);
|
||||
|
||||
$string = 'May I have an exception please?';
|
||||
$text = $this->getMockBuilder(TranslatableMarkup::class)
|
||||
->setConstructorArgs([$string, [], [], $translation])
|
||||
->setMethods(['_die'])
|
||||
->getMock();
|
||||
$text
|
||||
->expects($this->once())
|
||||
->method('_die')
|
||||
->willReturn('');
|
||||
|
||||
$translation
|
||||
->method('translateString')
|
||||
->with($text)
|
||||
->willReturnCallback(function () {
|
||||
throw new \Exception('Yes you may.');
|
||||
});
|
||||
|
||||
// We set a custom error handler because of https://github.com/sebastianbergmann/phpunit/issues/487
|
||||
set_error_handler([$this, 'errorHandler']);
|
||||
// We want this to trigger an error.
|
||||
(string) $text;
|
||||
restore_error_handler();
|
||||
|
||||
$this->assertEquals(E_USER_ERROR, $this->lastErrorNumber);
|
||||
$this->assertRegExp('/Exception thrown while calling __toString on a .*Mock_TranslatableMarkup_.* object in .*TranslatableMarkupTest.php on line [0-9]+: Yes you may./', $this->lastErrorMessage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage $string ("foo") must be a string.
|
||||
*
|
||||
* @covers ::__construct
|
||||
*/
|
||||
public function testIsStringAssertion() {
|
||||
$translation = $this->getStringTranslationStub();
|
||||
new TranslatableMarkup(new TranslatableMarkup('foo', [], [], $translation));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage $string ("foo") must be a string.
|
||||
*
|
||||
* @covers ::__construct
|
||||
*/
|
||||
public function testIsStringAssertionWithFormattableMarkup() {
|
||||
$translation = $this->getStringTranslationStub();
|
||||
$formattable_string = new FormattableMarkup('@bar', ['@bar' => 'foo']);
|
||||
new TranslatableMarkup($formattable_string);
|
||||
}
|
||||
|
||||
}
|
|
@ -5,9 +5,10 @@
|
|||
* Contains \Drupal\Tests\Core\StringTranslation\TranslationManagerTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\StringTranslation {
|
||||
namespace Drupal\Tests\Core\StringTranslation;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\Core\StringTranslation\TranslationManager;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
|
@ -24,6 +25,9 @@ class TranslationManagerTest extends UnitTestCase {
|
|||
*/
|
||||
protected $translationManager;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
$this->translationManager = new TestTranslationManager();
|
||||
}
|
||||
|
@ -34,19 +38,18 @@ class TranslationManagerTest extends UnitTestCase {
|
|||
*/
|
||||
public function providerTestFormatPlural() {
|
||||
return array(
|
||||
array(1, 'Singular', '@count plural', array(), array(), 'Singular', TRUE),
|
||||
array(2, 'Singular', '@count plural', array(), array(), '2 plural', TRUE),
|
||||
[1, 'Singular', '@count plural', array(), array(), 'Singular'],
|
||||
[2, 'Singular', '@count plural', array(), array(), '2 plural'],
|
||||
// @todo support locale_get_plural
|
||||
array(2, 'Singular', '@count @arg', array('@arg' => '<script>'), array(), '2 <script>', TRUE),
|
||||
array(2, 'Singular', '@count %arg', array('%arg' => '<script>'), array(), '2 <em class="placeholder"><script></em>', TRUE),
|
||||
array(2, 'Singular', '@count !arg', array('!arg' => '<script>'), array(), '2 <script>', FALSE),
|
||||
[2, 'Singular', '@count @arg', array('@arg' => '<script>'), array(), '2 <script>'],
|
||||
[2, 'Singular', '@count %arg', array('%arg' => '<script>'), array(), '2 <em class="placeholder"><script></em>'],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerTestFormatPlural
|
||||
*/
|
||||
public function testFormatPlural($count, $singular, $plural, array $args = array(), array $options = array(), $expected, $safe) {
|
||||
public function testFormatPlural($count, $singular, $plural, array $args = array(), array $options = array(), $expected) {
|
||||
$translator = $this->getMock('\Drupal\Core\StringTranslation\Translator\TranslatorInterface');
|
||||
$translator->expects($this->once())
|
||||
->method('getStringTranslation')
|
||||
|
@ -56,9 +59,40 @@ class TranslationManagerTest extends UnitTestCase {
|
|||
$this->translationManager->addTranslator($translator);
|
||||
$result = $this->translationManager->formatPlural($count, $singular, $plural, $args, $options);
|
||||
$this->assertEquals($expected, $result);
|
||||
$this->assertEquals(SafeMarkup::isSafe($result), $safe);
|
||||
$this->assertTrue(SafeMarkup::isSafe($result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests translation using placeholders.
|
||||
*
|
||||
* @param string $string
|
||||
* A string containing the English string to translate.
|
||||
* @param array $args
|
||||
* An associative array of replacements to make after translation.
|
||||
* @param string $expected_string
|
||||
* The expected translated string value.
|
||||
*
|
||||
* @dataProvider providerTestTranslatePlaceholder
|
||||
*/
|
||||
public function testTranslatePlaceholder($string, array $args = array(), $expected_string) {
|
||||
$actual = $this->translationManager->translate($string, $args);
|
||||
$this->assertInstanceOf(MarkupInterface::class, $actual);
|
||||
$this->assertEquals($expected_string, (string) $actual);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test data for translate().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function providerTestTranslatePlaceholder() {
|
||||
return [
|
||||
['foo @bar', ['@bar' => 'bar'], 'foo bar'],
|
||||
['bar %baz', ['%baz' => 'baz'], 'bar <em class="placeholder">baz</em>'],
|
||||
['bar @bar %baz', ['@bar' => 'bar', '%baz' => 'baz'], 'bar bar <em class="placeholder">baz</em>'],
|
||||
['bar %baz @bar', ['%baz' => 'baz', '@bar' => 'bar'], 'bar <em class="placeholder">baz</em> bar'],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class TestTranslationManager extends TranslationManager {
|
||||
|
@ -67,11 +101,3 @@ class TestTranslationManager extends TranslationManager {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
if (!defined('LOCALE_PLURAL_DELIMITER')) {
|
||||
define('LOCALE_PLURAL_DELIMITER', "\03");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Template;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Render\Markup;
|
||||
use Drupal\Core\Template\Attribute;
|
||||
use Drupal\Core\Template\AttributeArray;
|
||||
use Drupal\Core\Template\AttributeString;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Template\Attribute
|
||||
|
@ -30,6 +33,18 @@ class AttributeTest extends UnitTestCase {
|
|||
$attribute = new Attribute(['selected' => TRUE, 'checked' => FALSE]);
|
||||
$this->assertTrue($attribute['selected']->value());
|
||||
$this->assertFalse($attribute['checked']->value());
|
||||
|
||||
// Test that non-array values with name "class" are cast to array.
|
||||
$attribute = new Attribute(array('class' => 'example-class'));
|
||||
$this->assertTrue(isset($attribute['class']));
|
||||
$this->assertEquals(new AttributeArray('class', array('example-class')), $attribute['class']);
|
||||
|
||||
// Test that safe string objects work correctly.
|
||||
$safe_string = $this->prophesize(MarkupInterface::class);
|
||||
$safe_string->__toString()->willReturn('example-class');
|
||||
$attribute = new Attribute(array('class' => $safe_string->reveal()));
|
||||
$this->assertTrue(isset($attribute['class']));
|
||||
$this->assertEquals(new AttributeArray('class', array('example-class')), $attribute['class']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -340,6 +355,27 @@ class AttributeTest extends UnitTestCase {
|
|||
$this->assertTrue(strpos($html, 'enabled') !== FALSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::createAttributeValue
|
||||
* @dataProvider providerTestAttributeValues
|
||||
*/
|
||||
public function testAttributeValues(array $attributes, $expected) {
|
||||
$this->assertEquals($expected, (new Attribute($attributes))->__toString());
|
||||
}
|
||||
|
||||
public function providerTestAttributeValues() {
|
||||
$data = [];
|
||||
|
||||
$string = '"> <script>alert(123)</script>"';
|
||||
$data['safe-object-xss1'] = [['title' => Markup::create($string)], ' title=""> alert(123)""'];
|
||||
$data['non-safe-object-xss1'] = [['title' => $string], ' title="' . Html::escape($string) . '"'];
|
||||
$string = '"><script>alert(123)</script>';
|
||||
$data['safe-object-xss2'] = [['title' => Markup::create($string)], ' title="">alert(123)"'];
|
||||
$data['non-safe-object-xss2'] = [['title' => $string], ' title="' . Html::escape($string) . '"'];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the given CSS class is present in the given HTML snippet.
|
||||
*
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Template;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Render\RenderableInterface;
|
||||
use Drupal\Core\Render\RendererInterface;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Core\Template\Loader\StringLoader;
|
||||
use Drupal\Core\Template\TwigEnvironment;
|
||||
use Drupal\Core\Template\TwigExtension;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
@ -32,7 +34,7 @@ class TwigExtensionTest extends UnitTestCase {
|
|||
$twig = new \Twig_Environment(NULL, array(
|
||||
'debug' => TRUE,
|
||||
'cache' => FALSE,
|
||||
'autoescape' => TRUE,
|
||||
'autoescape' => 'html',
|
||||
'optimizations' => 0
|
||||
));
|
||||
$twig->addExtension((new TwigExtension($renderer))->setUrlGenerator($this->getMock('Drupal\Core\Routing\UrlGeneratorInterface')));
|
||||
|
@ -103,7 +105,55 @@ class TwigExtensionTest extends UnitTestCase {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests the escaping of objects implementing SafeStringInterface.
|
||||
* Tests the format_date filter.
|
||||
*/
|
||||
public function testFormatDate() {
|
||||
$date_formatter = $this->getMockBuilder('\Drupal\Core\Datetime\DateFormatter')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$date_formatter->expects($this->exactly(2))
|
||||
->method('format')
|
||||
->willReturn('1978-11-19');
|
||||
$renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
|
||||
$extension = new TwigExtension($renderer);
|
||||
$extension->setDateFormatter($date_formatter);
|
||||
|
||||
$loader = new StringLoader();
|
||||
$twig = new \Twig_Environment($loader);
|
||||
$twig->addExtension($extension);
|
||||
$result = $twig->render('{{ time|format_date("html_date") }}');
|
||||
$this->assertEquals($date_formatter->format('html_date'), $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the active_theme_path function.
|
||||
*/
|
||||
public function testActiveThemePath() {
|
||||
$renderer = $this->getMock('\Drupal\Core\Render\RendererInterface');
|
||||
$extension = new TwigExtension($renderer);
|
||||
$theme_manager = $this->getMock('\Drupal\Core\Theme\ThemeManagerInterface');
|
||||
$active_theme = $this->getMockBuilder('\Drupal\Core\Theme\ActiveTheme')
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$active_theme
|
||||
->expects($this->once())
|
||||
->method('getPath')
|
||||
->willReturn('foo/bar');
|
||||
$theme_manager
|
||||
->expects($this->once())
|
||||
->method('getActiveTheme')
|
||||
->willReturn($active_theme);
|
||||
$extension->setThemeManager($theme_manager);
|
||||
|
||||
$loader = new \Twig_Loader_String();
|
||||
$twig = new \Twig_Environment($loader);
|
||||
$twig->addExtension($extension);
|
||||
$result = $twig->render('{{ active_theme_path() }}');
|
||||
$this->assertEquals('foo/bar', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the escaping of objects implementing MarkupInterface.
|
||||
*
|
||||
* @covers ::escapeFilter
|
||||
*/
|
||||
|
@ -112,17 +162,17 @@ class TwigExtensionTest extends UnitTestCase {
|
|||
$twig = new \Twig_Environment(NULL, array(
|
||||
'debug' => TRUE,
|
||||
'cache' => FALSE,
|
||||
'autoescape' => TRUE,
|
||||
'autoescape' => 'html',
|
||||
'optimizations' => 0
|
||||
));
|
||||
$twig_extension = new TwigExtension($renderer);
|
||||
|
||||
// By default, TwigExtension will attempt to cast objects to strings.
|
||||
// Ensure objects that implement SafeStringInterface are unchanged.
|
||||
$safe_string = $this->getMock('\Drupal\Component\Utility\SafeStringInterface');
|
||||
// Ensure objects that implement MarkupInterface are unchanged.
|
||||
$safe_string = $this->getMock('\Drupal\Component\Render\MarkupInterface');
|
||||
$this->assertSame($safe_string, $twig_extension->escapeFilter($twig, $safe_string, 'html', 'UTF-8', TRUE));
|
||||
|
||||
// Ensure objects that do not implement SafeStringInterface are escaped.
|
||||
// Ensure objects that do not implement MarkupInterface are escaped.
|
||||
$string_object = new TwigExtensionTestString("<script>alert('here');</script>");
|
||||
$this->assertSame('<script>alert('here');</script>', $twig_extension->escapeFilter($twig, $string_object, 'html', 'UTF-8', TRUE));
|
||||
}
|
||||
|
@ -138,20 +188,44 @@ class TwigExtensionTest extends UnitTestCase {
|
|||
$twig_extension = new TwigExtension($renderer);
|
||||
$twig_environment = $this->prophesize(TwigEnvironment::class)->reveal();
|
||||
|
||||
|
||||
// Simulate t().
|
||||
$string = '<em>will be markup</em>';
|
||||
SafeMarkup::setMultiple([$string => ['html' => TRUE]]);
|
||||
$markup = $this->prophesize(TranslatableMarkup::class);
|
||||
$markup->__toString()->willReturn('<em>will be markup</em>');
|
||||
$markup = $markup->reveal();
|
||||
|
||||
$items = [
|
||||
'<em>will be escaped</em>',
|
||||
$string,
|
||||
$markup,
|
||||
['#markup' => '<strong>will be rendered</strong>']
|
||||
];
|
||||
$result = $twig_extension->safeJoin($twig_environment, $items, '<br/>');
|
||||
$this->assertEquals('<em>will be escaped</em><br/><em>will be markup</em><br/><strong>will be rendered</strong>', $result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerTestRenderVar
|
||||
*/
|
||||
public function testRenderVar($result, $input) {
|
||||
$renderer = $this->prophesize(RendererInterface::class);
|
||||
$renderer->render($result += ['#printed' => FALSE])->willReturn('Rendered output');
|
||||
|
||||
$renderer = $renderer->reveal();
|
||||
$twig_extension = new TwigExtension($renderer);
|
||||
|
||||
$this->assertEquals('Rendered output', $twig_extension->renderVar($input));
|
||||
}
|
||||
|
||||
public function providerTestRenderVar() {
|
||||
$data = [];
|
||||
|
||||
$renderable = $this->prophesize(RenderableInterface::class);
|
||||
$render_array = ['#type' => 'test', '#var' => 'giraffe'];
|
||||
$renderable->toRenderable()->willReturn($render_array);
|
||||
$data['renderable'] = [$render_array, $renderable->reveal()];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TwigExtensionTestString {
|
||||
|
|
|
@ -93,7 +93,8 @@ class RegistryTest extends UnitTestCase {
|
|||
'engine' => 'twig',
|
||||
'owner' => 'twig',
|
||||
'stylesheets_remove' => [],
|
||||
'stylesheets_override' => [],
|
||||
'libraries_override' => [],
|
||||
'libraries_extend' => [],
|
||||
'libraries' => [],
|
||||
'extension' => '.twig',
|
||||
'base_themes' => [],
|
||||
|
|
|
@ -16,10 +16,8 @@ use Drupal\Core\TypedData\Validation\ExecutionContextFactory;
|
|||
use Drupal\Core\TypedData\Validation\RecursiveValidator;
|
||||
use Drupal\Core\Validation\ConstraintManager;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use Symfony\Component\Translation\IdentityTranslator;
|
||||
use Symfony\Component\Validator\ConstraintValidatorFactory;
|
||||
use Symfony\Component\Validator\Context\ExecutionContextInterface;
|
||||
use Symfony\Component\Validator\DefaultTranslator;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\TypedData\Validation\RecursiveContextualValidator
|
||||
|
@ -82,7 +80,12 @@ class RecursiveContextualValidatorTest extends UnitTestCase {
|
|||
$container->set('typed_data_manager', $this->typedDataManager);
|
||||
\Drupal::setContainer($container);
|
||||
|
||||
$translator = new IdentityTranslator();
|
||||
$translator = $this->getMock('Drupal\Core\Validation\TranslatorInterface');
|
||||
$translator->expects($this->any())
|
||||
->method('trans')
|
||||
->willReturnCallback(function($id) {
|
||||
return $id;
|
||||
});
|
||||
$this->contextFactory = new ExecutionContextFactory($translator);
|
||||
$this->validatorFactory = new ConstraintValidatorFactory();
|
||||
$this->recursiveValidator = new RecursiveValidator($this->contextFactory, $this->validatorFactory, $this->typedDataManager);
|
||||
|
|
302
core/tests/Drupal/Tests/Core/Update/UpdateRegistryTest.php
Normal file
302
core/tests/Drupal/Tests/Core/Update/UpdateRegistryTest.php
Normal file
|
@ -0,0 +1,302 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Core\Update\UpdateRegistryTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Core\Update;
|
||||
|
||||
use Drupal\Core\KeyValueStore\KeyValueStoreInterface;
|
||||
use Drupal\Core\Site\Settings;
|
||||
use Drupal\Core\Update\UpdateRegistry;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Core\Update\UpdateRegistry
|
||||
* @group Update
|
||||
*
|
||||
* Note we load code, so isolate the tests.
|
||||
*
|
||||
* @runTestsInSeparateProcesses
|
||||
* @preserveGlobalState disabled
|
||||
*/
|
||||
class UpdateRegistryTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$settings = [];
|
||||
$settings['extension_discovery_scan_tests'] = TRUE;
|
||||
new Settings($settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up some modules with some update functions.
|
||||
*/
|
||||
protected function setupBasicModules() {
|
||||
$info_a = <<<'EOS'
|
||||
type: module
|
||||
name: Module A
|
||||
core: 8.x
|
||||
EOS;
|
||||
|
||||
$info_b = <<<'EOS'
|
||||
type: module
|
||||
name: Module B
|
||||
core: 8.x
|
||||
EOS;
|
||||
|
||||
$module_a = <<<'EOS'
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Module A update A.
|
||||
*/
|
||||
function module_a_post_update_a() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Module A update B.
|
||||
*/
|
||||
function module_a_post_update_b() {
|
||||
}
|
||||
|
||||
EOS;
|
||||
$module_b = <<<'EOS'
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Module B update A.
|
||||
*/
|
||||
function module_b_post_update_a() {
|
||||
}
|
||||
|
||||
EOS;
|
||||
vfsStream::setup('drupal');
|
||||
vfsStream::create([
|
||||
'sites' => [
|
||||
'default' => [
|
||||
'modules' => [
|
||||
'module_a' => [
|
||||
'module_a.post_update.php' => $module_a,
|
||||
'module_a.info.yml' => $info_a
|
||||
],
|
||||
'module_b' => [
|
||||
'module_b.post_update.php' => $module_b,
|
||||
'module_b.info.yml' => $info_b
|
||||
],
|
||||
]
|
||||
]
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getPendingUpdateFunctions
|
||||
*/
|
||||
public function testGetPendingUpdateFunctionsNoExistingUpdates() {
|
||||
$this->setupBasicModules();
|
||||
|
||||
$key_value = $this->prophesize(KeyValueStoreInterface::class);
|
||||
$key_value->get('existing_updates', [])->willReturn([]);
|
||||
$key_value = $key_value->reveal();
|
||||
|
||||
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
|
||||
'module_a',
|
||||
'module_b'
|
||||
], $key_value, FALSE);
|
||||
|
||||
$this->assertEquals([
|
||||
'module_a_post_update_a',
|
||||
'module_a_post_update_b',
|
||||
'module_b_post_update_a'
|
||||
], $update_registry->getPendingUpdateFunctions());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getPendingUpdateFunctions
|
||||
*/
|
||||
public function testGetPendingUpdateFunctionsWithLoadedModulesButNotEnabled() {
|
||||
$this->setupBasicModules();
|
||||
|
||||
$key_value = $this->prophesize(KeyValueStoreInterface::class);
|
||||
$key_value->get('existing_updates', [])->willReturn([]);
|
||||
$key_value = $key_value->reveal();
|
||||
|
||||
// Preload modules to ensure that ::getAvailableUpdateFunctions filters out
|
||||
// not enabled modules.
|
||||
include_once 'vfs://drupal/sites/default/modules/module_a/module_a.post_update.php';
|
||||
include_once 'vfs://drupal/sites/default/modules/module_b/module_b.post_update.php';
|
||||
|
||||
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
|
||||
'module_a',
|
||||
], $key_value, FALSE);
|
||||
|
||||
$this->assertEquals([
|
||||
'module_a_post_update_a',
|
||||
'module_a_post_update_b',
|
||||
], $update_registry->getPendingUpdateFunctions());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getPendingUpdateFunctions
|
||||
*/
|
||||
public function testGetPendingUpdateFunctionsExistingUpdates() {
|
||||
$this->setupBasicModules();
|
||||
|
||||
$key_value = $this->prophesize(KeyValueStoreInterface::class);
|
||||
$key_value->get('existing_updates', [])->willReturn(['module_a_post_update_a']);
|
||||
$key_value = $key_value->reveal();
|
||||
|
||||
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
|
||||
'module_a',
|
||||
'module_b'
|
||||
], $key_value, FALSE);
|
||||
|
||||
$this->assertEquals(array_values([
|
||||
'module_a_post_update_b',
|
||||
'module_b_post_update_a'
|
||||
]), array_values($update_registry->getPendingUpdateFunctions()));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getPendingUpdateInformation
|
||||
*/
|
||||
public function testGetPendingUpdateInformation() {
|
||||
$this->setupBasicModules();
|
||||
|
||||
$key_value = $this->prophesize(KeyValueStoreInterface::class);
|
||||
$key_value->get('existing_updates', [])->willReturn([]);
|
||||
$key_value = $key_value->reveal();
|
||||
|
||||
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
|
||||
'module_a',
|
||||
'module_b'
|
||||
], $key_value, FALSE);
|
||||
|
||||
$expected = [];
|
||||
$expected['module_a']['pending']['a'] = 'Module A update A.';
|
||||
$expected['module_a']['pending']['b'] = 'Module A update B.';
|
||||
$expected['module_a']['start'] = 'a';
|
||||
$expected['module_b']['pending']['a'] = 'Module B update A.';
|
||||
$expected['module_b']['start'] = 'a';
|
||||
|
||||
$this->assertEquals($expected, $update_registry->getPendingUpdateInformation());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getPendingUpdateInformation
|
||||
*/
|
||||
public function testGetPendingUpdateInformationWithExistingUpdates() {
|
||||
$this->setupBasicModules();
|
||||
|
||||
$key_value = $this->prophesize(KeyValueStoreInterface::class);
|
||||
$key_value->get('existing_updates', [])->willReturn(['module_a_post_update_a']);
|
||||
$key_value = $key_value->reveal();
|
||||
|
||||
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
|
||||
'module_a',
|
||||
'module_b'
|
||||
], $key_value, FALSE);
|
||||
|
||||
$expected = [];
|
||||
$expected['module_a']['pending']['b'] = 'Module A update B.';
|
||||
$expected['module_a']['start'] = 'b';
|
||||
$expected['module_b']['pending']['a'] = 'Module B update A.';
|
||||
$expected['module_b']['start'] = 'a';
|
||||
|
||||
$this->assertEquals($expected, $update_registry->getPendingUpdateInformation());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getModuleUpdateFunctions
|
||||
*/
|
||||
public function testGetModuleUpdateFunctions() {
|
||||
$this->setupBasicModules();
|
||||
$key_value = $this->prophesize(KeyValueStoreInterface::class)->reveal();
|
||||
|
||||
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
|
||||
'module_a',
|
||||
'module_b'
|
||||
], $key_value, FALSE);
|
||||
|
||||
$this->assertEquals(['module_a_post_update_a', 'module_a_post_update_b'], array_values($update_registry->getModuleUpdateFunctions('module_a')));
|
||||
$this->assertEquals(['module_b_post_update_a'], array_values($update_registry->getModuleUpdateFunctions('module_b')));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::registerInvokedUpdates
|
||||
*/
|
||||
public function testRegisterInvokedUpdatesWithoutExistingUpdates() {
|
||||
$this->setupBasicModules();
|
||||
$key_value = $this->prophesize(KeyValueStoreInterface::class);
|
||||
$key_value->get('existing_updates', [])->willReturn([]);
|
||||
$key_value->set('existing_updates', ['module_a_post_update_a'])->willReturn(NULL);
|
||||
$key_value = $key_value->reveal();
|
||||
|
||||
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
|
||||
'module_a',
|
||||
'module_b'
|
||||
], $key_value, FALSE);
|
||||
$update_registry->registerInvokedUpdates(['module_a_post_update_a']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::registerInvokedUpdates
|
||||
*/
|
||||
public function testRegisterInvokedUpdatesWithMultiple() {
|
||||
$this->setupBasicModules();
|
||||
$key_value = $this->prophesize(KeyValueStoreInterface::class);
|
||||
$key_value->get('existing_updates', [])->willReturn([]);
|
||||
$key_value->set('existing_updates', ['module_a_post_update_a', 'module_a_post_update_b'])->willReturn(NULL);
|
||||
$key_value = $key_value->reveal();
|
||||
|
||||
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
|
||||
'module_a',
|
||||
'module_b'
|
||||
], $key_value, FALSE);
|
||||
$update_registry->registerInvokedUpdates(['module_a_post_update_a', 'module_a_post_update_b']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::registerInvokedUpdates
|
||||
*/
|
||||
public function testRegisterInvokedUpdatesWithExistingUpdates() {
|
||||
$this->setupBasicModules();
|
||||
$key_value = $this->prophesize(KeyValueStoreInterface::class);
|
||||
$key_value->get('existing_updates', [])->willReturn(['module_a_post_update_b']);
|
||||
$key_value->set('existing_updates', ['module_a_post_update_b', 'module_a_post_update_a'])->willReturn(NULL);
|
||||
$key_value = $key_value->reveal();
|
||||
|
||||
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
|
||||
'module_a',
|
||||
'module_b'
|
||||
], $key_value, FALSE);
|
||||
$update_registry->registerInvokedUpdates(['module_a_post_update_a']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::filterOutInvokedUpdatesByModule
|
||||
*/
|
||||
public function testFilterOutInvokedUpdatesByModule() {
|
||||
$this->setupBasicModules();
|
||||
$key_value = $this->prophesize(KeyValueStoreInterface::class);
|
||||
$key_value->get('existing_updates', [])->willReturn(['module_a_post_update_b', 'module_a_post_update_a', 'module_b_post_update_a']);
|
||||
$key_value->set('existing_updates', ['module_b_post_update_a'])->willReturn(NULL);
|
||||
$key_value = $key_value->reveal();
|
||||
|
||||
$update_registry = new UpdateRegistry('vfs://drupal', 'sites/default', [
|
||||
'module_a',
|
||||
'module_b'
|
||||
], $key_value, FALSE);
|
||||
|
||||
$update_registry->filterOutInvokedUpdatesByModule('module_a');
|
||||
}
|
||||
|
||||
}
|
|
@ -7,10 +7,11 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Utility {
|
||||
|
||||
use Drupal\Component\Render\MarkupInterface;
|
||||
use Drupal\Core\GeneratedUrl;
|
||||
use Drupal\Core\Language\Language;
|
||||
use Drupal\Core\Link;
|
||||
use Drupal\Core\Render\SafeString;
|
||||
use Drupal\Core\Render\Markup;
|
||||
use Drupal\Core\Url;
|
||||
use Drupal\Core\Utility\LinkGenerator;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
@ -111,8 +112,7 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->urlGenerator->expects($this->once())
|
||||
->method('generateFromRoute')
|
||||
->with($route_name, $parameters, array('absolute' => $absolute) + $this->defaultOptions)
|
||||
->will($this->returnValue($expected_url));
|
||||
|
||||
->willReturn((new GeneratedUrl())->setGeneratedUrl($expected_url));
|
||||
$this->moduleHandler->expects($this->once())
|
||||
->method('alter');
|
||||
|
||||
|
@ -133,7 +133,7 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->urlGenerator->expects($this->once())
|
||||
->method('generateFromRoute')
|
||||
->with('test_route_1', array(), array('fragment' => 'the-fragment') + $this->defaultOptions)
|
||||
->will($this->returnValue('/test-route-1#the-fragment'));
|
||||
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-1#the-fragment'));
|
||||
|
||||
$this->moduleHandler->expects($this->once())
|
||||
->method('alter')
|
||||
|
@ -197,7 +197,7 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->urlAssembler->expects($this->once())
|
||||
->method('assemble')
|
||||
->with('base:example', array('query' => array('foo' => '"bar"', 'zoo' => 'baz')) + $this->defaultOptions)
|
||||
->will($this->returnValue('/example?foo=%22bar%22&zoo=baz'));
|
||||
->willReturn((new GeneratedUrl())->setGeneratedUrl('/example?foo=%22bar%22&zoo=baz'));
|
||||
|
||||
$path_validator = $this->getMock('Drupal\Core\Path\PathValidatorInterface');
|
||||
$container_builder = new ContainerBuilder();
|
||||
|
@ -228,9 +228,7 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->urlGenerator->expects($this->once())
|
||||
->method('generateFromRoute')
|
||||
->with('test_route_1', array(), $this->defaultOptions)
|
||||
->will($this->returnValue(
|
||||
'/test-route-1'
|
||||
));
|
||||
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-1'));
|
||||
|
||||
// Test that HTML attributes are added to the anchor.
|
||||
$url = new Url('test_route_1', array(), array(
|
||||
|
@ -255,9 +253,7 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->urlGenerator->expects($this->once())
|
||||
->method('generateFromRoute')
|
||||
->with('test_route_1', array(), array('query' => array('test' => 'value')) + $this->defaultOptions)
|
||||
->will($this->returnValue(
|
||||
'/test-route-1?test=value'
|
||||
));
|
||||
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-1?test=value'));
|
||||
|
||||
$url = new Url('test_route_1', array(), array(
|
||||
'query' => array('test' => 'value'),
|
||||
|
@ -280,9 +276,7 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->urlGenerator->expects($this->once())
|
||||
->method('generateFromRoute')
|
||||
->with('test_route_1', array('test' => 'value'), $this->defaultOptions)
|
||||
->will($this->returnValue(
|
||||
'/test-route-1?test=value'
|
||||
));
|
||||
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-1?test=value'));
|
||||
|
||||
$url = new Url('test_route_1', array('test' => 'value'), array());
|
||||
$url->setUrlGenerator($this->urlGenerator);
|
||||
|
@ -303,10 +297,7 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->urlGenerator->expects($this->once())
|
||||
->method('generateFromRoute')
|
||||
->with('test_route_1', array(), array('key' => 'value') + $this->defaultOptions)
|
||||
->will($this->returnValue(
|
||||
'/test-route-1?test=value'
|
||||
));
|
||||
|
||||
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-1?test=value'));
|
||||
$url = new Url('test_route_1', array(), array(
|
||||
'key' => 'value',
|
||||
));
|
||||
|
@ -328,9 +319,7 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->urlGenerator->expects($this->once())
|
||||
->method('generateFromRoute')
|
||||
->with('test_route_4', array(), $this->defaultOptions)
|
||||
->will($this->returnValue(
|
||||
'/test-route-4'
|
||||
));
|
||||
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-4'));
|
||||
|
||||
// Test that HTML link text is escaped by default.
|
||||
$url = new Url('test_route_4');
|
||||
|
@ -348,15 +337,11 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->urlGenerator->expects($this->at(0))
|
||||
->method('generateFromRoute')
|
||||
->with('test_route_5', array(), $this->defaultOptions)
|
||||
->will($this->returnValue(
|
||||
'/test-route-5'
|
||||
));
|
||||
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-5'));
|
||||
$this->urlGenerator->expects($this->at(1))
|
||||
->method('generateFromRoute')
|
||||
->with('test_route_5', array(), $this->defaultOptions)
|
||||
->will($this->returnValue(
|
||||
'/test-route-5'
|
||||
));
|
||||
->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-5'));
|
||||
|
||||
// Test that HTML tags are stripped from the 'title' attribute.
|
||||
$url = new Url('test_route_5', array(), array(
|
||||
|
@ -372,11 +357,11 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
), $result);
|
||||
|
||||
// Test that safe HTML is output inside the anchor tag unescaped. The
|
||||
// SafeString::create() call is an intentional unit test for the interaction
|
||||
// between SafeStringInterface and the LinkGenerator.
|
||||
// Markup::create() call is an intentional unit test for the interaction
|
||||
// between MarkupInterface and the LinkGenerator.
|
||||
$url = new Url('test_route_5', array());
|
||||
$url->setUrlGenerator($this->urlGenerator);
|
||||
$result = $this->linkGenerator->generate(SafeString::create('<em>HTML output</em>'), $url);
|
||||
$result = $this->linkGenerator->generate(Markup::create('<em>HTML output</em>'), $url);
|
||||
$this->assertLink(array(
|
||||
'attributes' => array('href' => '/test-route-5'),
|
||||
'child' => array(
|
||||
|
@ -394,11 +379,18 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
public function testGenerateActive() {
|
||||
$this->urlGenerator->expects($this->exactly(5))
|
||||
->method('generateFromRoute')
|
||||
->will($this->returnValueMap(array(
|
||||
array('test_route_1', array(), FALSE, '/test-route-1'),
|
||||
array('test_route_3', array(), FALSE, '/test-route-3'),
|
||||
array('test_route_4', array('object' => '1'), FALSE, '/test-route-4/1'),
|
||||
)));
|
||||
->willReturnCallback(function($name, $parameters = array(), $options = array(), $collect_bubbleable_metadata = FALSE) {
|
||||
switch ($name) {
|
||||
case 'test_route_1':
|
||||
return (new GeneratedUrl())->setGeneratedUrl('/test-route-1');
|
||||
case 'test_route_3':
|
||||
return (new GeneratedUrl())->setGeneratedUrl('/test-route-3');
|
||||
case 'test_route_4':
|
||||
if ($parameters['object'] == '1') {
|
||||
return (new GeneratedUrl())->setGeneratedUrl('/test-route-4/1');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$this->urlGenerator->expects($this->exactly(4))
|
||||
->method('getPathFromRoute')
|
||||
|
@ -479,7 +471,6 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$this->urlGenerator->expects($this->any())
|
||||
->method('generateFromRoute')
|
||||
->will($this->returnValueMap([
|
||||
['test_route_1', [], $options, FALSE, '/test-route-1'],
|
||||
['test_route_1', [], $options, TRUE, (new GeneratedUrl())->setGeneratedUrl('/test-route-1')],
|
||||
]));
|
||||
|
||||
|
@ -488,16 +479,16 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
$expected_link_markup = '<a href="/test-route-1">Test</a>';
|
||||
|
||||
// Test ::generate().
|
||||
$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->assertSame($expected_link_markup, (string) $this->linkGenerator->generate('Test', $url));
|
||||
$generated_link = $this->linkGenerator->generate('Test', $url);
|
||||
$this->assertSame($expected_link_markup, (string) $generated_link->getGeneratedLink());
|
||||
$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->assertSame($expected_link_markup, (string) $this->linkGenerator->generateFromLink($link));
|
||||
$generated_link = $this->linkGenerator->generateFromLink($link);
|
||||
$this->assertSame($expected_link_markup, (string) $generated_link->getGeneratedLink());
|
||||
$this->assertInstanceOf('\Drupal\Core\Render\BubbleableMetadata', $generated_link);
|
||||
}
|
||||
|
||||
|
@ -508,12 +499,12 @@ class LinkGeneratorTest extends UnitTestCase {
|
|||
* An associative array of link properties, with the following keys:
|
||||
* - attributes: optional array of HTML attributes that should be present.
|
||||
* - content: optional link content.
|
||||
* @param string $html
|
||||
* @param \Drupal\Component\Render\MarkupInterface $html
|
||||
* The HTML to check.
|
||||
* @param int $count
|
||||
* How many times the link should be present in the HTML. Defaults to 1.
|
||||
*/
|
||||
public static function assertLink(array $properties, $html, $count = 1) {
|
||||
public static function assertLink(array $properties, MarkupInterface $html, $count = 1) {
|
||||
// Provide default values.
|
||||
$properties += array('attributes' => array());
|
||||
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
|
||||
namespace Drupal\Tests\Core\Utility;
|
||||
|
||||
use Drupal\Component\Utility\Html;
|
||||
use Drupal\Core\Cache\Context\CacheContextsManager;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\Language\LanguageInterface;
|
||||
use Drupal\Core\Render\BubbleableMetadata;
|
||||
use Drupal\Core\Render\Markup;
|
||||
use Drupal\Core\Utility\Token;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
|
@ -262,4 +264,39 @@ class TokenTest extends UnitTestCase {
|
|||
$this->token->resetInfo();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::replace
|
||||
* @dataProvider providerTestReplaceEscaping
|
||||
*/
|
||||
public function testReplaceEscaping($string, array $tokens, $expected) {
|
||||
$this->moduleHandler->expects($this->any())
|
||||
->method('invokeAll')
|
||||
->willReturnCallback(function ($type, $args) {
|
||||
return $args[2]['tokens'];
|
||||
});
|
||||
|
||||
$result = $this->token->replace($string, ['tokens' => $tokens]);
|
||||
$this->assertInternalType('string', $result);
|
||||
$this->assertEquals($expected, $result);
|
||||
}
|
||||
|
||||
public function providerTestReplaceEscaping() {
|
||||
$data = [];
|
||||
|
||||
// No tokens. The first argument to Token::replace() should not be escaped.
|
||||
$data['no-tokens'] = ['muh', [], 'muh'];
|
||||
$data['html-in-string'] = ['<h1>Giraffe</h1>', [], '<h1>Giraffe</h1>'];
|
||||
$data['html-in-string-quote'] = ['<h1>Giraffe"</h1>', [], '<h1>Giraffe"</h1>'];
|
||||
|
||||
$data['simple-placeholder-with-plain-text'] = ['<h1>[token:meh]</h1>', ['[token:meh]' => 'Giraffe"'], '<h1>' . Html::escape('Giraffe"') . '</h1>'];
|
||||
|
||||
$data['simple-placeholder-with-safe-html'] = [
|
||||
'<h1>[token:meh]</h1>',
|
||||
['[token:meh]' => Markup::create('<em>Emphasized</em>')],
|
||||
'<h1><em>Emphasized</em></h1>',
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ use Drupal\Core\TypedData\Plugin\DataType\Uri;
|
|||
use Drupal\Core\TypedData\PrimitiveInterface;
|
||||
use Drupal\Core\Validation\Plugin\Validation\Constraint\PrimitiveTypeConstraint;
|
||||
use Drupal\Core\Validation\Plugin\Validation\Constraint\PrimitiveTypeConstraintValidator;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
|
@ -63,6 +64,7 @@ class PrimitiveTypeConstraintValidatorTest extends UnitTestCase {
|
|||
$data[] = [new IntegerData(DataDefinition::create('integer')), 1.5, FALSE];
|
||||
$data[] = [new IntegerData(DataDefinition::create('integer')), 'test', FALSE];
|
||||
$data[] = [new StringData(DataDefinition::create('string')), 'test', TRUE];
|
||||
$data[] = [new StringData(DataDefinition::create('string')), new TranslatableMarkup('test'), TRUE];
|
||||
// It is odd that 1 is a valid string.
|
||||
// $data[] = [$this->getMock('Drupal\Core\TypedData\Type\StringInterface'), 1, FALSE];
|
||||
$data[] = [new StringData(DataDefinition::create('string')), [], FALSE];
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\Tests\Listeners\SafeMarkupSideEffects.
|
||||
*
|
||||
* Listener for PHPUnit tests, to enforce that data providers don't add to the
|
||||
* SafeMarkup static safe string list.
|
||||
*/
|
||||
|
||||
namespace Drupal\Tests\Listeners;
|
||||
|
||||
use Drupal\Component\Utility\SafeMarkup;
|
||||
|
||||
/**
|
||||
* Listens for PHPUnit tests and fails those with SafeMarkup side effects.
|
||||
*/
|
||||
class SafeMarkupSideEffects extends \PHPUnit_Framework_BaseTestListener {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function startTestSuite(\PHPUnit_Framework_TestSuite $suite) {
|
||||
// Use a static so we only do this test once after all the data providers
|
||||
// have run.
|
||||
static $tested = FALSE;
|
||||
if ($suite->getName() !== '' && !$tested) {
|
||||
$tested = TRUE;
|
||||
if (!empty(SafeMarkup::getAll())) {
|
||||
throw new \RuntimeException('SafeMarkup string list polluted by data providers');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -12,6 +12,9 @@ use Drupal\Component\Utility\Random;
|
|||
use Drupal\Component\Utility\SafeMarkup;
|
||||
use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
|
||||
use Drupal\Core\DependencyInjection\ContainerBuilder;
|
||||
use Drupal\Core\StringTranslation\TranslatableMarkup;
|
||||
use Drupal\Core\StringTranslation\PluralTranslatableMarkup;
|
||||
|
||||
|
||||
/**
|
||||
* Provides a base class and helpers for Drupal unit tests.
|
||||
|
@ -48,12 +51,6 @@ abstract class UnitTestCase extends \PHPUnit_Framework_TestCase {
|
|||
FileCacheFactory::setConfiguration(['default' => ['class' => '\Drupal\Component\FileCache\NullFileCache']]);
|
||||
|
||||
$this->root = dirname(dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))));
|
||||
|
||||
// Reset the static list of SafeStrings to prevent bleeding between tests.
|
||||
$reflected_class = new \ReflectionClass('\Drupal\Component\Utility\SafeMarkup');
|
||||
$reflected_property = $reflected_class->getProperty('safeStrings');
|
||||
$reflected_property->setAccessible(true);
|
||||
$reflected_property->setValue([]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -214,11 +211,19 @@ abstract class UnitTestCase extends \PHPUnit_Framework_TestCase {
|
|||
$translation = $this->getMock('Drupal\Core\StringTranslation\TranslationInterface');
|
||||
$translation->expects($this->any())
|
||||
->method('translate')
|
||||
->will($this->returnCallback('Drupal\Component\Utility\SafeMarkup::format'));
|
||||
->willReturnCallback(function ($string, array $args = array(), array $options = array()) use ($translation) {
|
||||
return new TranslatableMarkup($string, $args, $options, $translation);
|
||||
});
|
||||
$translation->expects($this->any())
|
||||
->method('translateString')
|
||||
->willReturnCallback(function (TranslatableMarkup $wrapper) {
|
||||
return $wrapper->getUntranslatedString();
|
||||
});
|
||||
$translation->expects($this->any())
|
||||
->method('formatPlural')
|
||||
->willReturnCallback(function ($count, $singular, $plural, array $args = [], array $options = []) {
|
||||
return $count === 1 ? SafeMarkup::format($singular, $args) : SafeMarkup::format($plural, $args + ['@count' => $count]);
|
||||
->willReturnCallback(function ($count, $singular, $plural, array $args = [], array $options = []) use ($translation) {
|
||||
$wrapper = new PluralTranslatableMarkup($count, $singular, $plural, $args, $options, $translation);
|
||||
return $wrapper;
|
||||
});
|
||||
return $translation;
|
||||
}
|
||||
|
|
Reference in a new issue