updated core from 8.4 to 8.5 : bug with login_destination

This commit is contained in:
Bachir Soussi Chiadmi
2018-03-13 14:01:21 +01:00
parent 0d78da249b
commit e668535a4e
3486 changed files with 89604 additions and 33283 deletions
@@ -0,0 +1,40 @@
<?php
namespace Drupal\FunctionalJavascriptTests\Ajax;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
/**
* Tests the compatibility of the ajax.es6.js file.
*
* @group Ajax
*/
class BackwardCompatibilityTest extends JavascriptTestBase {
/**
* {@inheritdoc}
*/
public static $modules = [
'js_ajax_test',
];
/**
* Ensures Drupal.Ajax.element_settings BC layer.
*/
public function testAjaxBackwardCompatibility() {
$this->drupalGet('/js_ajax_test');
$this->click('#edit-test-button');
$this->assertSession()
->waitForElement('css', '#js_ajax_test_form_element');
$elements = $this->cssSelect('#js_ajax_test_form_element');
$this->assertCount(1, $elements);
$json = $elements[0]->getText();
$data = json_decode($json, TRUE);
$this->assertEquals([
'element_settings' => 'catbro',
'elementSettings' => 'catbro',
], $data);
}
}
@@ -0,0 +1,132 @@
<?php
namespace Drupal\FunctionalJavascriptTests\Core\Installer\Form;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\Language\Language;
use Drupal\Core\Session\UserSession;
use Drupal\Core\Test\HttpClientMiddleware\TestHttpClientMiddleware;
use Drupal\FunctionalJavascriptTests\JavascriptTestBase;
use GuzzleHttp\HandlerStack;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
/**
* Tests the select profile form.
*
* @group Installer
*/
class SelectProfileFormTest extends JavascriptTestBase {
/**
* {@inheritdoc}
*/
public function setUp() {
$this->setupBaseUrl();
$this->prepareDatabasePrefix();
// Install Drupal test site.
$this->prepareEnvironment();
// Define information about the user 1 account.
$this->rootUser = new UserSession([
'uid' => 1,
'name' => 'admin',
'mail' => 'admin@example.com',
'pass_raw' => $this->randomMachineName(),
]);
// If any $settings are defined for this test, copy and prepare an actual
// settings.php, so as to resemble a regular installation.
if (!empty($this->settings)) {
// Not using File API; a potential error must trigger a PHP warning.
copy(DRUPAL_ROOT . '/sites/default/default.settings.php', DRUPAL_ROOT . '/' . $this->siteDirectory . '/settings.php');
$this->writeSettings($this->settings);
}
// Note that FunctionalTestSetupTrait::installParameters() returns form
// input values suitable for a programmed
// \Drupal::formBuilder()->submitForm().
// @see InstallerTestBase::translatePostValues()
$this->parameters = $this->installParameters();
// Set up a minimal container (required by BrowserTestBase). Set cookie and
// server information so that XDebug works.
// @see install_begin_request()
$request = Request::create($GLOBALS['base_url'] . '/core/install.php', 'GET', [], $_COOKIE, [], $_SERVER);
$this->container = new ContainerBuilder();
$request_stack = new RequestStack();
$request_stack->push($request);
$this->container
->set('request_stack', $request_stack);
$this->container
->setParameter('language.default_values', Language::$defaultValues);
$this->container
->register('language.default', 'Drupal\Core\Language\LanguageDefault')
->addArgument('%language.default_values%');
$this->container
->register('string_translation', 'Drupal\Core\StringTranslation\TranslationManager')
->addArgument(new Reference('language.default'));
$this->container
->register('http_client', 'GuzzleHttp\Client')
->setFactory('http_client_factory:fromOptions');
$this->container
->register('http_client_factory', 'Drupal\Core\Http\ClientFactory')
->setArguments([new Reference('http_handler_stack')]);
$handler_stack = HandlerStack::create();
$test_http_client_middleware = new TestHttpClientMiddleware();
$handler_stack->push($test_http_client_middleware(), 'test.http_client.middleware');
$this->container
->set('http_handler_stack', $handler_stack);
$this->container
->set('app.root', DRUPAL_ROOT);
\Drupal::setContainer($this->container);
// Setup Mink.
$this->initMink();
}
/**
* {@inheritdoc}
*/
protected function initMink() {
// The temporary files directory doesn't exist yet, as install_base_system()
// has not run. We need to create the template cache directory recursively.
$path = $this->tempFilesDirectory . DIRECTORY_SEPARATOR . 'browsertestbase-templatecache';
if (!file_exists($path)) {
mkdir($path, 0777, TRUE);
}
parent::initMink();
}
/**
* {@inheritdoc}
*
* BrowserTestBase::refreshVariables() tries to operate on persistent storage,
* which is only available after the installer completed.
*/
protected function refreshVariables() {
// Intentionally empty as the site is not yet installed.
}
/**
* Tests a warning message is displayed when the Umami profile is selected.
*/
public function testUmamiProfileWarningMessage() {
$this->drupalGet($GLOBALS['base_url'] . '/core/install.php');
$edit = [
'langcode' => 'en',
];
$this->drupalPostForm(NULL, $edit, 'Save and continue');
$page = $this->getSession()->getPage();
$warning_message = $page->find('css', '.description .messages--warning');
$this->assertFalse($warning_message->isVisible());
$page->selectFieldOption('profile', 'demo_umami');
$this->assertTrue($warning_message->isVisible());
}
}
@@ -0,0 +1,35 @@
<?php
namespace Drupal\FunctionalJavascriptTests;
use Behat\Mink\Driver\Selenium2Driver;
/**
* Provides a driver for Selenium testing.
*/
class DrupalSelenium2Driver extends Selenium2Driver {
/**
* {@inheritdoc}
*/
public function setCookie($name, $value = NULL) {
if ($value === NULL) {
$this->getWebDriverSession()->deleteCookie($name);
return;
}
$cookieArray = [
'name' => $name,
'value' => urlencode($value),
'secure' => FALSE,
// Unlike \Behat\Mink\Driver\Selenium2Driver::setCookie we set a domain
// and an expire date, as otherwise cookies leak from one test site into
// another.
'domain' => parse_url($this->getWebDriverSession()->url(), PHP_URL_HOST),
'expires' => time() + 80000,
];
$this->getWebDriverSession()->setCookie($cookieArray);
}
}
@@ -172,7 +172,7 @@ JS;
}
/**
* Test that a node, or it's specific corner, is visible in the viewport.
* Test that a node, or its specific corner, is visible in the viewport.
*
* Note: Always set the viewport size. This can be done with a PhantomJS
* startup parameter or in your test with \Behat\Mink\Session->resizeWindow().
@@ -255,7 +255,7 @@ JS;
}
/**
* Check the visibility of a node, or it's specific corner.
* Check the visibility of a node, or its specific corner.
*
* @param \Behat\Mink\Element\NodeElement $node
* A valid node.
@@ -15,6 +15,9 @@ abstract class JavascriptTestBase extends BrowserTestBase {
/**
* {@inheritdoc}
*
* To use a webdriver based approach, please use DrupalSelenium2Driver::class.
* We will switch the default later.
*/
protected $minkDefaultDriverClass = PhantomJSDriver::class;
@@ -22,14 +25,19 @@ abstract class JavascriptTestBase extends BrowserTestBase {
* {@inheritdoc}
*/
protected function initMink() {
// Set up the template cache used by the PhantomJS mink driver.
$path = $this->tempFilesDirectory . DIRECTORY_SEPARATOR . 'browsertestbase-templatecache';
$this->minkDefaultDriverArgs = [
'http://127.0.0.1:8510',
$path,
];
if (!file_exists($path)) {
mkdir($path);
if ($this->minkDefaultDriverClass === DrupalSelenium2Driver::class) {
$this->minkDefaultDriverArgs = ['chrome', NULL, 'http://localhost:4444/'];
}
elseif ($this->minkDefaultDriverClass === PhantomJSDriver::class) {
// Set up the template cache used by the PhantomJS mink driver.
$path = $this->tempFilesDirectory . DIRECTORY_SEPARATOR . 'browsertestbase-templatecache';
$this->minkDefaultDriverArgs = [
'http://127.0.0.1:8510',
$path,
];
if (!file_exists($path)) {
mkdir($path);
}
}
try {
@@ -63,6 +71,19 @@ abstract class JavascriptTestBase extends BrowserTestBase {
parent::tearDown();
}
/**
* {@inheritdoc}
*/
protected function getMinkDriverArgs() {
if ($this->minkDefaultDriverClass === DrupalSelenium2Driver::class) {
return getenv('MINK_DRIVER_ARGS_WEBDRIVER') ?: getenv('MINK_DRIVER_ARGS_PHANTOMJS') ?: parent::getMinkDriverArgs();
}
elseif ($this->minkDefaultDriverClass === PhantomJSDriver::class) {
return getenv('MINK_DRIVER_ARGS_PHANTOMJS') ?: parent::getMinkDriverArgs();
}
return parent::getMinkDriverArgs();
}
/**
* Asserts that the element with the given CSS selector is visible.
*
@@ -169,4 +190,12 @@ EndOfScript;
return $this->getSession()->evaluateScript($script) ?: [];
}
/**
* {@inheritdoc}
*/
protected function getHtmlOutputHeaders() {
// The webdriver API does not support fetching headers.
return '';
}
}
@@ -2,6 +2,8 @@
namespace Drupal\FunctionalJavascriptTests;
use Zumba\Mink\Driver\PhantomJSDriver;
/**
* Runs a browser test using PhantomJS.
*
@@ -9,6 +11,11 @@ namespace Drupal\FunctionalJavascriptTests;
*/
abstract class LegacyJavascriptTestBase extends JavascriptTestBase {
/**
* {@inheritdoc}
*/
protected $minkDefaultDriverClass = PhantomJSDriver::class;
/**
* {@inheritdoc}
*/
@@ -0,0 +1,19 @@
<?php
namespace Drupal\FunctionalJavascriptTests\Tests;
use Drupal\FunctionalJavascriptTests\DrupalSelenium2Driver;
/**
* Tests for the JSWebAssert class using webdriver.
*
* @group javascript
*/
class JSWebWithWebDriverAssertTest extends JSWebAssertTest {
/**
* {@inheritdoc}
*/
protected $minkDefaultDriverClass = DrupalSelenium2Driver::class;
}
@@ -55,4 +55,56 @@ class WebDriverWebAssert extends JSWebAssert {
parent::responseHeaderNotEquals($name, $value);
}
/**
* The use of responseHeaderContains() is not available.
*
* @param string $name
* The name of the header.
* @param string $value
* The value to check the header against.
*/
public function responseHeaderContains($name, $value) {
@trigger_error('Support for responseHeaderContains is to be dropped from Javascript tests. See https://www.drupal.org/node/2857562.');
parent::responseHeaderContains($name, $value);
}
/**
* The use of responseHeaderNotContains() is not available.
*
* @param string $name
* The name of the header.
* @param string $value
* The value to check the header against.
*/
public function responseHeaderNotContains($name, $value) {
@trigger_error('Support for responseHeaderNotContains is to be dropped from Javascript tests. See https://www.drupal.org/node/2857562.');
parent::responseHeaderNotContains($name, $value);
}
/**
* The use of responseHeaderMatches() is not available.
*
* @param string $name
* The name of the header.
* @param string $regex
* The value to check the header against.
*/
public function responseHeaderMatches($name, $regex) {
@trigger_error('Support for responseHeaderMatches is to be dropped from Javascript tests. See https://www.drupal.org/node/2857562.');
parent::responseHeaderMatches($name, $regex);
}
/**
* The use of responseHeaderNotMatches() is not available.
*
* @param string $name
* The name of the header.
* @param string $regex
* The value to check the header against.
*/
public function responseHeaderNotMatches($name, $regex) {
@trigger_error('Support for responseHeaderNotMatches is to be dropped from Javascript tests. See https://www.drupal.org/node/2857562.');
parent::responseHeaderNotMatches($name, $regex);
}
}
@@ -188,7 +188,7 @@ class BrowserTestBaseTest extends BrowserTestBase {
/**
* Tests legacy text asserts.
*/
public function testLegacyTextAsserts() {
public function testTextAsserts() {
$this->drupalGet('test-encoded');
$dangerous = 'Bad html <script>alert(123);</script>';
$sanitized = Html::escape($dangerous);
@@ -202,7 +202,7 @@ class BrowserTestBaseTest extends BrowserTestBase {
/**
* Tests legacy field asserts which use xpath directly.
*/
public function testLegacyXpathAsserts() {
public function testXpathAsserts() {
$this->drupalGet('test-field-xpath');
$this->assertFieldsByValue($this->xpath("//h1[@class = 'page-title']"), NULL);
$this->assertFieldsByValue($this->xpath('//table/tbody/tr[2]/td[1]'), 'one');
@@ -245,7 +245,7 @@ class BrowserTestBaseTest extends BrowserTestBase {
/**
* Tests legacy field asserts using textfields.
*/
public function testLegacyFieldAssertsForTextfields() {
public function testFieldAssertsForTextfields() {
$this->drupalGet('test-field-xpath');
// *** 1. assertNoField().
@@ -387,7 +387,7 @@ class BrowserTestBaseTest extends BrowserTestBase {
/**
* Tests legacy field asserts for options field type.
*/
public function testLegacyFieldAssertsForOptions() {
public function testFieldAssertsForOptions() {
$this->drupalGet('test-field-xpath');
// Option field type.
@@ -443,7 +443,7 @@ class BrowserTestBaseTest extends BrowserTestBase {
/**
* Tests legacy field asserts for button field type.
*/
public function testLegacyFieldAssertsForButton() {
public function testFieldAssertsForButton() {
$this->drupalGet('test-field-xpath');
$this->assertFieldById('edit-save', NULL);
@@ -485,7 +485,7 @@ class BrowserTestBaseTest extends BrowserTestBase {
/**
* Tests legacy field asserts for checkbox field type.
*/
public function testLegacyFieldAssertsForCheckbox() {
public function testFieldAssertsForCheckbox() {
$this->drupalGet('test-field-xpath');
// Part 1 - Test by name.
@@ -0,0 +1,32 @@
<?php
namespace Drupal\FunctionalTests\Core\Test;
use Drupal\Core\Url;
use Drupal\Tests\BrowserTestBase;
/**
* Tests Drupal's integration with Symfony PHPUnit Bridge.
*
* @group Test
* @group legacy
*/
class PhpUnitBridgeTest extends BrowserTestBase {
protected static $modules = ['deprecation_test'];
/**
* @expectedDeprecation This is the deprecation message for deprecation_test_function().
*/
public function testSilencedError() {
$this->assertEquals('known_return_value', deprecation_test_function());
}
/**
* @expectedDeprecation This is the deprecation message for deprecation_test_function().
*/
public function testErrorOnSiteUnderTest() {
$this->drupalGet(Url::fromRoute('deprecation_test.route'));
}
}
@@ -138,7 +138,7 @@ class ContentEntityFormFieldValidationFilteringTest extends BrowserTestBase {
// \Drupal\file\Plugin\Field\FieldWidget\FileWidget::process().
$text_file = current($this->getTestFiles('text'));
$edit = [
'files[test_file_0]' => drupal_realpath($text_file->uri)
'files[test_file_0]' => \Drupal::service('file_system')->realpath($text_file->uri)
];
$assert_session->elementNotExists('css', 'input#edit-test-file-0-remove-button');
$this->drupalPostForm(NULL, $edit, 'Upload');
@@ -0,0 +1,186 @@
<?php
namespace Drupal\FunctionalTests\Routing;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\link\LinkItemInterface;
use Drupal\Tests\BrowserTestBase;
/**
* Tests that route lookup is cached by the current language.
*
* @group routing
*/
class RouteCachingLanguageTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['path', 'node', 'content_translation', 'link', 'block'];
/**
* An user with permissions to administer content types.
*
* @var \Drupal\user\UserInterface
*/
protected $webUser;
protected function setUp() {
parent::setUp();
$this->createContentType(['type' => 'page']);
$this->drupalPlaceBlock('local_tasks_block');
$this->drupalPlaceBlock('page_title_block');
$permissions = [
'access administration pages',
'administer content translation',
'administer content types',
'administer languages',
'administer url aliases',
'create content translations',
'create page content',
'create url aliases',
'edit any page content',
'translate any entity',
];
// Create and log in user.
$this->webUser = $this->drupalCreateUser($permissions);
$this->drupalLogin($this->webUser);
// Enable French language.
ConfigurableLanguage::createFromLangcode('fr')->save();
// Enable translation for page node.
$edit = [
'entity_types[node]' => 1,
'settings[node][page][translatable]' => 1,
'settings[node][page][fields][path]' => 1,
'settings[node][page][fields][body]' => 1,
'settings[node][page][settings][language][language_alterable]' => 1,
];
$this->drupalPostForm('admin/config/regional/content-language', $edit, t('Save configuration'));
// Create a field with settings to validate.
$field_storage = FieldStorageConfig::create([
'field_name' => 'field_link',
'entity_type' => 'node',
'type' => 'link',
]);
$field_storage->save();
$field = FieldConfig::create([
'field_storage' => $field_storage,
'bundle' => 'page',
'settings' => [
'title' => DRUPAL_OPTIONAL,
'link_type' => LinkItemInterface::LINK_GENERIC,
],
]);
$field->save();
entity_get_form_display('node', 'page', 'default')
->setComponent('field_link', [
'type' => 'link_default',
])
->save();
entity_get_display('node', 'page', 'full')
->setComponent('field_link', [
'type' => 'link',
])
->save();
// Enable URL language detection and selection and set a prefix for both
// languages.
$edit = ['language_interface[enabled][language-url]' => 1];
$this->drupalPostForm('admin/config/regional/language/detection', $edit, 'Save settings');
$edit = ['prefix[en]' => 'en'];
$this->drupalPostForm('admin/config/regional/language/detection/url', $edit, 'Save configuration');
// Reset the cache after changing the negotiation settings as that changes
// how links are built.
$this->resetAll();
$definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('node', 'page');
$this->assertTrue($definitions['path']->isTranslatable(), 'Node path is translatable.');
$this->assertTrue($definitions['body']->isTranslatable(), 'Node body is translatable.');
}
/**
* Creates content with a link field pointing to an alias of another language.
*
* @dataProvider providerLanguage
*/
public function testLinkTranslationWithAlias($source_langcode) {
$source_url_options = [
'language' => ConfigurableLanguage::load($source_langcode),
];
// Create a target node in the source language that is the link target.
$edit = [
'langcode[0][value]' => $source_langcode,
'title[0][value]' => 'Target page',
'path[0][alias]' => '/target-page',
];
$this->drupalPostForm('node/add/page', $edit, t('Save'), $source_url_options);
// Confirm that the alias works.
$assert_session = $this->assertSession();
$assert_session->addressEquals($source_langcode . '/target-page');
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains('Target page');
// Create a second node that links to the first through the link field.
$edit = [
'langcode[0][value]' => $source_langcode,
'title[0][value]' => 'Link page',
'field_link[0][uri]' => '/target-page',
'field_link[0][title]' => 'Target page',
'path[0][alias]' => '/link-page',
];
$this->drupalPostForm('node/add/page', $edit, t('Save'), $source_url_options);
// Make sure the link node is displayed with a working link.
$assert_session->pageTextContains('Link page');
$this->clickLink('Target page');
$assert_session->addressEquals($source_langcode . '/target-page');
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains('Target page');
// Clear all caches, then add a translation for the link node.
$this->resetAll();
$this->drupalGet('link-page', $source_url_options);
$this->clickLink('Translate');
$this->clickLink(t('Add'));
// Do not change the link field.
$edit = [
'title[0][value]' => 'Translated link page',
'path[0][alias]' => '/translated-link-page',
];
$this->drupalPostForm(NULL, $edit, 'Save (this translation)');
$assert_session->pageTextContains('Translated link page');
// @todo Clicking on the link does not include the language prefix.
$this->drupalGet('target-page', $source_url_options);
$assert_session->statusCodeEquals(200);
$assert_session->pageTextContains('Target page');
}
/**
* Data provider for testFromUri().
*/
public function providerLanguage() {
return [
['en'],
['fr'],
];
}
}
@@ -0,0 +1,95 @@
<?php
namespace Drupal\FunctionalTests\Routing;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Core\Language\LanguageInterface;
use Drupal\Tests\BrowserTestBase;
/**
* Tests the route cache when the language is not in the path.
*
* @group language
*/
class RouteCachingNonPathLanguageNegotiationTest extends BrowserTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['language', 'block'];
/**
* The admin user.
*
* @var \Drupal\user\UserInterface
*/
protected $adminUser;
protected function setUp() {
parent::setUp();
// Create and log in user.
$this->adminUser = $this->drupalCreateUser(['administer blocks', 'administer languages', 'access administration pages']);
$this->drupalLogin($this->adminUser);
// Add language.
ConfigurableLanguage::createFromLangcode('fr')->save();
// Enable session language detection and selection.
$edit = [
'language_interface[enabled][language-url]' => FALSE,
'language_interface[enabled][language-session]' => TRUE,
];
$this->drupalPostForm('admin/config/regional/language/detection', $edit, t('Save settings'));
// A more common scenario is domain-based negotiation but that can not be
// tested. Session negotiation by default is not considered by the URL
// language type that is used to resolve the alias. Explicitly enable
// that to be able to test this scenario.
// @todo Improve in https://www.drupal.org/project/drupal/issues/1125428.
$this->config('language.types')
->set('negotiation.language_url.enabled', ['language-session' => 0])
->save();
// Enable the language switching block.
$this->drupalPlaceBlock('language_block:' . LanguageInterface::TYPE_INTERFACE, [
'id' => 'test_language_block',
]);
}
/**
* Tests aliases when the negotiated language is not in the path.
*/
public function testAliases() {
// Switch to French and try to access the now inaccessible block.
$this->drupalGet('');
// Create an alias for user/UID just for en, make sure that this is a 404
// on the french page exist in english, no matter which language is
// checked first. Create the alias after visiting frontpage to make sure
// there is no existing cache entry for this that affects the tests.
\Drupal::service('path.alias_storage')->save('/user/' . $this->adminUser->id(), '/user-page', 'en');
$this->clickLink('French');
$this->drupalGet('user-page');
$this->assertSession()->statusCodeEquals(404);
// Switch to english, make sure it works now.
$this->clickLink('English');
$this->drupalGet('user-page');
$this->assertSession()->statusCodeEquals(200);
// Clear cache and repeat the check, this time with english first.
$this->resetAll();
$this->drupalGet('user-page');
$this->assertSession()->statusCodeEquals(200);
$this->clickLink('French');
$this->drupalGet('user-page');
$this->assertSession()->statusCodeEquals(404);
}
}
@@ -374,7 +374,6 @@ abstract class UpdatePathTestBase extends BrowserTestBase {
// Ensure that the update hooks updated all entity schema.
$needs_updates = \Drupal::entityDefinitionUpdateManager()->needsUpdates();
$this->assertFalse($needs_updates, 'After all updates ran, entity schema is up to date.');
if ($needs_updates) {
foreach (\Drupal::entityDefinitionUpdateManager()
->getChangeSummary() as $entity_type_id => $summary) {
@@ -382,6 +381,9 @@ abstract class UpdatePathTestBase extends BrowserTestBase {
$this->fail($message);
}
}
// The above calls to `fail()` should prevent this from ever being
// called, but it is here in case something goes really wrong.
$this->assertFalse($needs_updates, 'After all updates ran, entity schema is up to date.');
}
}
}
@@ -81,12 +81,6 @@ class DefaultConfigTest extends KernelTestBase {
/** @var \Drupal\Core\Extension\ModuleInstallerInterface $module_installer */
$module_installer = $this->container->get('module_installer');
// @todo https://www.drupal.org/node/2308745 Rest has an implicit dependency
// on the Node module remove once solved.
if (in_array($module, ['rest', 'hal'])) {
$module_installer->install(['node']);
}
// Work out any additional modules and themes that need installing to create
// an optional config.
$optional_config_storage = new FileStorage($module_path . InstallStorage::CONFIG_OPTIONAL_DIRECTORY, StorageInterface::DEFAULT_COLLECTION);
@@ -0,0 +1,80 @@
<?php
namespace Drupal\KernelTests\Core\Action;
use Drupal\Core\Action\Plugin\Action\Derivative\EntityPublishedActionDeriver;
use Drupal\entity_test\Entity\EntityTestMulRevPub;
use Drupal\KernelTests\KernelTestBase;
use Drupal\system\Entity\Action;
/**
* @group Action
*/
class PublishActionTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'entity_test', 'user'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test_mulrevpub');
}
/**
* @covers \Drupal\Core\Action\Plugin\Action\Derivative\EntityPublishedActionDeriver::getDerivativeDefinitions
*/
public function testGetDerivativeDefinitions() {
$deriver = new EntityPublishedActionDeriver(\Drupal::entityTypeManager());
$this->assertArraySubset([
'entity_test_mulrevpub' => [
'type' => 'entity_test_mulrevpub',
'label' => 'Save test entity - revisions, data table, and published interface',
'action_label' => 'Save',
],
], $deriver->getDerivativeDefinitions([
'action_label' => 'Save',
]));
}
/**
* @covers \Drupal\Core\Action\Plugin\Action\PublishAction::execute
*/
public function testPublishAction() {
$entity = EntityTestMulRevPub::create(['name' => 'test']);
$entity->setUnpublished()->save();
$action = Action::create([
'id' => 'entity_publish_action',
'plugin' => 'entity:publish_action:entity_test_mulrevpub',
]);
$action->save();
$this->assertFalse($entity->isPublished());
$action->execute([$entity]);
$this->assertTrue($entity->isPublished());
$this->assertArraySubset(['module' => ['entity_test']], $action->getDependencies());
}
/**
* @covers \Drupal\Core\Action\Plugin\Action\UnpublishAction::execute
*/
public function testUnpublishAction() {
$entity = EntityTestMulRevPub::create(['name' => 'test']);
$entity->setPublished()->save();
$action = Action::create([
'id' => 'entity_unpublish_action',
'plugin' => 'entity:unpublish_action:entity_test_mulrevpub',
]);
$action->save();
$this->assertTrue($entity->isPublished());
$action->execute([$entity]);
$this->assertFalse($entity->isPublished());
$this->assertArraySubset(['module' => ['entity_test']], $action->getDependencies());
}
}
@@ -0,0 +1,62 @@
<?php
namespace Drupal\KernelTests\Core\Action;
use Drupal\Core\Action\Plugin\Action\Derivative\EntityChangedActionDeriver;
use Drupal\entity_test\Entity\EntityTestMulChanged;
use Drupal\KernelTests\KernelTestBase;
use Drupal\system\Entity\Action;
/**
* @group Action
*/
class SaveActionTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'entity_test', 'user'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test_mul_changed');
}
/**
* @covers \Drupal\Core\Action\Plugin\Action\Derivative\EntityChangedActionDeriver::getDerivativeDefinitions
*/
public function testGetDerivativeDefinitions() {
$deriver = new EntityChangedActionDeriver(\Drupal::entityTypeManager());
$this->assertArraySubset([
'entity_test_mul_changed' => [
'type' => 'entity_test_mul_changed',
'label' => 'Save test entity - data table',
'action_label' => 'Save',
],
], $deriver->getDerivativeDefinitions([
'action_label' => 'Save',
]));
}
/**
* @covers \Drupal\Core\Action\Plugin\Action\SaveAction::execute
*/
public function testSaveAction() {
$entity = EntityTestMulChanged::create(['name' => 'test']);
$entity->save();
$saved_time = $entity->getChangedTime();
$action = Action::create([
'id' => 'entity_save_action',
'plugin' => 'entity:save_action:entity_test_mul_changed',
]);
$action->save();
$action->execute([$entity]);
$this->assertNotSame($saved_time, $entity->getChangedTime());
$this->assertArraySubset(['module' => ['entity_test']], $action->getDependencies());
}
}
@@ -108,6 +108,10 @@ class ResolvedLibraryDefinitionsFilesMatchTest extends KernelTestBase {
}
return TRUE;
});
// Remove demo_umami_content module as its install hook creates content
// that relies on the presence of entity tables and various other elements
// not present in a kernel test.
unset($all_modules['demo_umami_content']);
$this->allModules = array_keys($all_modules);
$this->allModules[] = 'system';
sort($this->allModules);
@@ -20,10 +20,4 @@ class DrupalSetMessageTest extends KernelTestBase {
$this->assertEquals('A message: bar', (string) $messages['status'][0]);
}
protected function tearDown() {
// Clear session to prevent global leakage.
unset($_SESSION['messages']);
parent::tearDown();
}
}
@@ -125,7 +125,7 @@ class ConfigFileContentTest extends KernelTestBase {
$this->assertIdentical($config->get('null'), NULL);
// Read false that had been nested in an array value.
$this->assertSame($config->get($casting_array_false_value_key), FALSE, "Nested boolean FALSE value returned FALSE.");
$this->assertSame(FALSE, $config->get($casting_array_false_value_key), "Nested boolean FALSE value returned FALSE.");
// Unset a top level value.
$config->clear($key);
@@ -67,9 +67,15 @@ class QueryTest extends DatabaseTestBase {
public function testConditionOperatorArgumentsSQLInjection() {
$injection = "IS NOT NULL) ;INSERT INTO {test} (name) VALUES ('test12345678'); -- ";
// Convert errors to exceptions for testing purposes below.
set_error_handler(function ($severity, $message, $filename, $lineno) {
throw new \ErrorException($message, 0, $severity, $filename, $lineno);
$previous_error_handler = set_error_handler(function ($severity, $message, $filename, $lineno, $context) use (&$previous_error_handler) {
// Normalize the filename to use UNIX directory separators.
if (preg_match('@core/lib/Drupal/Core/Database/Query/Condition.php$@', str_replace(DIRECTORY_SEPARATOR, '/', $filename))) {
// Convert errors to exceptions for testing purposes below.
throw new \ErrorException($message, 0, $severity, $filename, $lineno);
}
if ($previous_error_handler) {
return $previous_error_handler($severity, $message, $filename, $lineno, $context);
}
});
try {
$result = db_select('test', 't')
@@ -0,0 +1,28 @@
<?php
namespace Drupal\KernelTests\Core\Datetime;
use Drupal\KernelTests\KernelTestBase;
/**
* Tests timestamp schema.
*
* @group Common
*/
class TimestampSchemaTest extends KernelTestBase {
/**
* {@inheritdoc}
*/
protected static $modules = ['entity_test', 'field', 'field_timestamp_test'];
/**
* Tests if the timestamp field schema is validated.
*/
public function testTimestampSchema() {
$this->installConfig(['field_timestamp_test']);
// Make at least an assertion.
$this->assertTrue(TRUE);
}
}
@@ -297,7 +297,7 @@ class ContentEntityCloneTest extends EntityKernelTestBase {
// Retrieve the entity properties.
$reflection = new \ReflectionClass($entity);
$properties = $reflection->getProperties(~\ReflectionProperty::IS_STATIC);
$translation_unique_properties = ['activeLangcode', 'translationInitialize', 'fieldDefinitions', 'languages', 'langcodeKey', 'defaultLangcode', 'defaultLangcodeKey', 'validated', 'validationRequired', 'entityTypeId', 'typedData', 'cacheContexts', 'cacheTags', 'cacheMaxAge', '_serviceIds'];
$translation_unique_properties = ['activeLangcode', 'translationInitialize', 'fieldDefinitions', 'languages', 'langcodeKey', 'defaultLangcode', 'defaultLangcodeKey', 'revisionTranslationAffectedKey', 'validated', 'validationRequired', 'entityTypeId', 'typedData', 'cacheContexts', 'cacheTags', 'cacheMaxAge', '_serviceIds'];
foreach ($properties as $property) {
// Modify each entity property on the clone and assert that the change is
@@ -0,0 +1,89 @@
<?php
namespace Drupal\KernelTests\Core\Entity;
use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\NodeType;
use Drupal\taxonomy\Entity\Vocabulary;
/**
* Tests the ContentEntityStorageBase::createWithSampleValues method.
*
* @coversDefaultClass \Drupal\Core\Entity\ContentEntityStorageBase
* @group Entity
*/
class CreateSampleEntityTest extends KernelTestBase {
/**
* The entity type manager.
*
* @var \Drupal\Core\Entity\EntityTypeManagerInterface
*/
protected $entityTypeManager;
/**
* {@inheritdoc}
*/
public static $modules = ['system', 'field', 'filter', 'text', 'file', 'user', 'node', 'comment', 'taxonomy'];
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setup();
$this->installEntitySchema('file');
$this->installEntitySchema('user');
$this->installEntitySchema('node');
$this->installEntitySchema('node_type');
$this->installEntitySchema('file');
$this->installEntitySchema('comment');
$this->installEntitySchema('comment_type');
$this->installEntitySchema('taxonomy_vocabulary');
$this->installEntitySchema('taxonomy_term');
$this->entityTypeManager = $this->container->get('entity_type.manager');
NodeType::create(['type' => 'article', 'name' => 'Article'])->save();
NodeType::create(['type' => 'page', 'name' => 'Page'])->save();
Vocabulary::create(['name' => 'Tags', 'vid' => 'tags'])->save();
}
/**
* Tests sample value content entity creation of all types.
*
* @covers ::createWithSampleValues
*/
public function testSampleValueContentEntity() {
foreach ($this->entityTypeManager->getDefinitions() as $entity_type_id => $definition) {
if ($definition->entityClassImplements(FieldableEntityInterface::class)) {
$label = $definition->getKey('label');
$values = [];
if ($label) {
$title = $this->randomString();
$values[$label] = $title;
}
// Create sample entities with bundles.
if ($bundle_type = $definition->getBundleEntityType()) {
foreach ($this->entityTypeManager->getStorage($bundle_type)->loadMultiple() as $bundle) {
$entity = $this->entityTypeManager->getStorage($entity_type_id)->createWithSampleValues($bundle->id(), $values);
$violations = $entity->validate();
$this->assertCount(0, $violations);
if ($label) {
$this->assertEquals($title, $entity->label());
}
}
}
// Create sample entities without bundles.
else {
$entity = $this->entityTypeManager->getStorage($entity_type_id)->createWithSampleValues(FALSE, $values);
$violations = $entity->validate();
$this->assertCount(0, $violations);
if ($label) {
$this->assertEquals($title, $entity->label());
}
}
}
}
}
}
@@ -8,6 +8,7 @@ use Drupal\Core\Access\AccessibleInterface;
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Session\AnonymousUserSession;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestStringId;
use Drupal\entity_test\Entity\EntityTestDefaultAccess;
use Drupal\entity_test\Entity\EntityTestNoUuid;
use Drupal\entity_test\Entity\EntityTestLabel;
@@ -18,6 +19,7 @@ use Drupal\user\Entity\User;
/**
* Tests the entity access control handler.
*
* @coversDefaultClass \Drupal\Core\Entity\EntityAccessControlHandler
* @group Entity
*/
class EntityAccessControlHandlerTest extends EntityLanguageTestBase {
@@ -30,6 +32,7 @@ class EntityAccessControlHandlerTest extends EntityLanguageTestBase {
$this->installEntitySchema('entity_test_no_uuid');
$this->installEntitySchema('entity_test_rev');
$this->installEntitySchema('entity_test_string_id');
}
/**
@@ -293,4 +296,73 @@ class EntityAccessControlHandlerTest extends EntityLanguageTestBase {
$this->assertEqual($state->get('entity_test_entity_test_access'), TRUE);
}
/**
* Tests the default access handling for the ID and UUID fields.
*
* @covers ::fieldAccess
* @dataProvider providerTestFieldAccess
*/
public function testFieldAccess($entity_class, array $entity_create_values, $expected_id_create_access) {
// Set up a non-admin user that is allowed to create and update test
// entities.
\Drupal::currentUser()->setAccount($this->createUser(['uid' => 2], ['administer entity_test content']));
// Create the entity to test field access with.
$entity = $entity_class::create($entity_create_values);
// On newly-created entities, field access must allow setting the UUID
// field.
$this->assertTrue($entity->get('uuid')->access('edit'));
$this->assertTrue($entity->get('uuid')->access('edit', NULL, TRUE)->isAllowed());
// On newly-created entities, field access will not allow setting the ID
// field if the ID is of type serial. It will allow access if it is of type
// string.
$this->assertEquals($expected_id_create_access, $entity->get('id')->access('edit'));
$this->assertEquals($expected_id_create_access, $entity->get('id')->access('edit', NULL, TRUE)->isAllowed());
// Save the entity and check that we can not update the ID or UUID fields
// anymore.
$entity->save();
// If the ID has been set as part of the create ensure it has been set
// correctly.
if (isset($entity_create_values['id'])) {
$this->assertSame($entity_create_values['id'], $entity->id());
}
// The UUID is hard-coded by the data provider.
$this->assertSame('60e3a179-79ed-4653-ad52-5e614c8e8fbe', $entity->uuid());
$this->assertFalse($entity->get('uuid')->access('edit'));
$access_result = $entity->get('uuid')->access('edit', NULL, TRUE);
$this->assertTrue($access_result->isForbidden());
$this->assertEquals('The entity UUID cannot be changed', $access_result->getReason());
// Ensure the ID is still not allowed to be edited.
$this->assertFalse($entity->get('id')->access('edit'));
$access_result = $entity->get('id')->access('edit', NULL, TRUE);
$this->assertTrue($access_result->isForbidden());
$this->assertEquals('The entity ID cannot be changed', $access_result->getReason());
}
public function providerTestFieldAccess() {
return [
'serial ID entity' => [
EntityTest::class,
[
'name' => 'A test entity',
'uuid' => '60e3a179-79ed-4653-ad52-5e614c8e8fbe',
],
FALSE
],
'string ID entity' => [
EntityTestStringId::class,
[
'id' => 'a_test_entity',
'name' => 'A test entity',
'uuid' => '60e3a179-79ed-4653-ad52-5e614c8e8fbe',
],
TRUE
],
];
}
}
@@ -93,7 +93,7 @@ class EntityBundleFieldTest extends EntityKernelTestBase {
$entity->save();
entity_test_delete_bundle('custom');
$table = $table_mapping->getDedicatedDataTableName($entity->getFieldDefinition('custom_bundle_field'));
$table = $table_mapping->getDedicatedDataTableName($entity->getFieldDefinition('custom_bundle_field'), TRUE);
$result = $this->database->select($table, 'f')
->condition('f.entity_id', $entity->id())
->condition('deleted', 1)
@@ -105,9 +105,10 @@ class EntityBundleFieldTest extends EntityKernelTestBase {
$field_map = \Drupal::entityManager()->getFieldMap();
$this->assertFalse(isset($field_map['entity_test']['custom_bundle_field']));
// @todo Test field purge and table deletion once supported. See
// https://www.drupal.org/node/2282119.
// $this->assertFalse($this->database->schema()->tableExists($table), 'Custom field table was deleted');
// Purge field data, and check that the storage definition has been
// completely removed once the data is purged.
field_purge_batch(10);
$this->assertFalse($this->database->schema()->tableExists($table), 'Custom field table was deleted');
}
}
@@ -0,0 +1,591 @@
<?php
namespace Drupal\KernelTests\Core\Entity;
use Drupal\Core\Entity\ContentEntityInterface;
use Drupal\Core\Language\LanguageInterface;
use Drupal\entity_test\Entity\EntityTestMulRev;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\user\Entity\User;
/**
* Test decoupled translation revisions.
*
* @group entity
*
* @coversDefaultClass \Drupal\Core\Entity\ContentEntityStorageBase
*/
class EntityDecoupledTranslationRevisionsTest extends EntityKernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = [
'system',
'entity_test',
'language',
];
/**
* The entity type bundle info service.
*
* @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
*/
protected $bundleInfo;
/**
* The entity storage.
*
* @var \Drupal\Core\Entity\ContentEntityStorageInterface
*/
protected $storage;
/**
* The translations of the test entity.
*
* @var \Drupal\Core\Entity\ContentEntityInterface[]
*/
protected $translations;
/**
* The previous revision identifiers for the various revision translations.
*
* @var int[]
*/
protected $previousRevisionId = [];
/**
* The previous unstranslatable field value.
*
* @var string[]
*/
protected $previousUntranslatableFieldValue;
/**
* The current edit sequence step index.
*
* @var int
*/
protected $stepIndex;
/**
* The current edit sequence step info.
*
* @var array
*/
protected $stepInfo;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$entity_type_id = 'entity_test_mulrev';
$this->installEntitySchema($entity_type_id);
$this->storage = $this->container->get('entity_type.manager')
->getStorage($entity_type_id);
$this->installConfig(['language']);
$langcodes = ['it', 'fr'];
foreach ($langcodes as $langcode) {
ConfigurableLanguage::createFromLangcode($langcode)->save();
}
$values = [
'name' => $this->randomString(),
'status' => 1,
];
User::create($values)->save();
// Make sure entity bundles are translatable.
$this->state->set('entity_test.translation', TRUE);
$this->bundleInfo = \Drupal::service('entity_type.bundle.info');
$this->bundleInfo->clearCachedBundles();
}
/**
* Data provider for ::testDecoupledDefaultRevisions.
*/
public function dataTestDecoupledPendingRevisions() {
$sets = [];
$sets['Intermixed languages - No initial default translation'][] = [
['en', TRUE],
['en', FALSE],
['it', FALSE],
['en', FALSE],
['it', FALSE],
['en', TRUE],
['it', TRUE],
];
$sets['Intermixed languages - With initial default translation'][] = [
['en', TRUE],
['it', TRUE],
['en', FALSE],
['it', FALSE],
['en', TRUE],
['it', TRUE],
];
$sets['Alternate languages - No initial default translation'][] = [
['en', TRUE],
['en', FALSE],
['en', FALSE],
['en', TRUE],
['it', FALSE],
['en', TRUE],
['it', FALSE],
['it', FALSE],
['it', TRUE],
];
$sets['Alternate languages - With initial default translation'][] = [
['en', TRUE],
['it', TRUE],
['en', TRUE],
['en', FALSE],
['en', FALSE],
['en', TRUE],
['it', TRUE],
['it', FALSE],
['it', FALSE],
['it', TRUE],
];
$sets['Multiple languages - No initial default translation'][] = [
['en', TRUE],
['it', FALSE],
['fr', FALSE],
['en', FALSE],
['en', TRUE],
['it', TRUE],
['fr', FALSE],
['en', FALSE],
['it', FALSE],
['en', TRUE],
['fr', TRUE],
['it', TRUE],
['fr', TRUE],
];
$sets['Multiple languages - With initial default translation'][] = [
['en', TRUE],
['it', TRUE],
['fr', TRUE],
['en', FALSE],
['it', FALSE],
['en', TRUE],
['it', TRUE],
['fr', FALSE],
['en', FALSE],
['it', FALSE],
['en', TRUE],
['fr', TRUE],
['it', TRUE],
['fr', TRUE],
];
return $sets;
}
/**
* Test decoupled default revisions.
*
* @param array[] $sequence
* An array with arrays of arguments for the ::doSaveNewRevision() method as
* values. Every child array corresponds to a method invocation.
*
* @covers ::createRevision
*
* @dataProvider dataTestDecoupledPendingRevisions
*/
public function testDecoupledPendingRevisions($sequence) {
$revision_id = $this->doTestEditSequence($sequence);
$this->assertEquals(count($sequence), $revision_id);
}
/**
* Data provider for ::testUntranslatableFields.
*/
public function dataTestUntranslatableFields() {
$sets = [];
$sets['Default behavior - Untranslatable fields affect all revisions'] = [
[
['en', TRUE, TRUE],
['it', FALSE, TRUE, FALSE],
['en', FALSE, TRUE, FALSE],
['en', TRUE, TRUE],
['it', TRUE, TRUE],
['en', FALSE],
['it', FALSE],
['en', TRUE],
['it', TRUE],
],
FALSE,
];
$sets['Alternative behavior - Untranslatable fields affect only default translation'] = [
[
['en', TRUE, TRUE],
['it', FALSE, TRUE, FALSE],
['en', FALSE, TRUE],
['it', TRUE, TRUE, FALSE],
['it', FALSE],
['it', TRUE],
['en', TRUE, TRUE],
['it', FALSE],
['en', FALSE],
['it', TRUE],
['en', TRUE, TRUE],
],
TRUE,
];
return $sets;
}
/**
* Tests that untranslatable fields are handled correctly.
*
* @param array[] $sequence
* An array with arrays of arguments for the ::doSaveNewRevision() method as
* values. Every child array corresponds to a method invocation.
*
* @param bool $default_translation_affected
* Whether untranslatable field changes affect all revisions or only the
* default revision.
*
* @covers ::createRevision
* @covers \Drupal\Core\Entity\Plugin\Validation\Constraint\EntityUntranslatableFieldsConstraintValidator::validate
*
* @dataProvider dataTestUntranslatableFields
*/
public function testUntranslatableFields($sequence, $default_translation_affected) {
// Configure the untranslatable fields edit mode.
$this->state->set('entity_test.untranslatable_fields.default_translation_affected', $default_translation_affected);
$this->bundleInfo->clearCachedBundles();
// Test that a new entity is always valid.
$entity = EntityTestMulRev::create();
$entity->set('non_mul_field', 0);
$violations = $entity->validate();
$this->assertEmpty($violations);
// Test the specified sequence.
$this->doTestEditSequence($sequence);
}
/**
* Actually tests an edit step sequence.
*
* @param array[] $sequence
* An array of sequence steps.
*
* @return int
* The latest saved revision id.
*/
protected function doTestEditSequence($sequence) {
$revision_id = NULL;
foreach ($sequence as $index => $step) {
$this->stepIndex = $index;
$revision_id = call_user_func_array([$this, 'doEditStep'], $step);
}
return $revision_id;
}
/**
* Saves a new revision of the test entity.
*
* @param string $active_langcode
* The language of the translation for which a new revision will be saved.
* @param bool $default_revision
* Whether the revision should be flagged as the default revision.
* @param bool $untranslatable_update
* (optional) Whether an untranslatable field update should be performed.
* Defaults to FALSE.
* @param bool $valid
* (optional) Whether entity validation is expected to succeed. Defaults to
* TRUE.
*
* @return int
* The new revision identifier.
*
* @throws \Drupal\Core\Entity\EntityStorageException
*/
protected function doEditStep($active_langcode, $default_revision, $untranslatable_update = FALSE, $valid = TRUE) {
$this->stepInfo = [$active_langcode, $default_revision, $untranslatable_update, $valid];
// If changes to untranslatable fields affect only the default translation,
// we can different values for untranslatable fields in the various
// revision translations, so we need to track their previous value per
// language.
$all_translations_affected = !$this->state->get('entity_test.untranslatable_fields.default_translation_affected');
$previous_untranslatable_field_langcode = $all_translations_affected ? LanguageInterface::LANGCODE_DEFAULT : $active_langcode;
// Initialize previous data tracking.
if (!isset($this->translations)) {
$this->translations[$active_langcode] = EntityTestMulRev::create();
$this->previousRevisionId[$active_langcode] = 0;
$this->previousUntranslatableFieldValue[$previous_untranslatable_field_langcode] = NULL;
}
if (!isset($this->translations[$active_langcode])) {
$this->translations[$active_langcode] = reset($this->translations)->addTranslation($active_langcode);
$this->previousRevisionId[$active_langcode] = 0;
$this->previousUntranslatableFieldValue[$active_langcode] = NULL;
}
// We want to update previous data only if we expect a valid result,
// otherwise we would be just polluting it with invalid values.
if ($valid) {
$entity = &$this->translations[$active_langcode];
$previous_revision_id = &$this->previousRevisionId[$active_langcode];
$previous_untranslatable_field_value = &$this->previousUntranslatableFieldValue[$previous_untranslatable_field_langcode];
}
else {
$entity = clone $this->translations[$active_langcode];
$previous_revision_id = $this->previousRevisionId[$active_langcode];
$previous_untranslatable_field_value = $this->previousUntranslatableFieldValue[$previous_untranslatable_field_langcode];
}
// Check that after instantiating a new revision for the specified
// translation, we are resuming work from where we left the last time. If
// that is the case, the label generated for the previous revision should
// match the stored one.
if (!$entity->isNew()) {
$previous_label = NULL;
if (!$entity->isNewTranslation()) {
$previous_label = $this->generateNewEntityLabel($entity, $previous_revision_id);
$latest_affected_revision_id = $this->storage->getLatestTranslationAffectedRevisionId($entity->id(), $entity->language()->getId());
}
else {
// Normally it would make sense to load the default revision in this
// case, however that would mean simulating here the logic that we need
// to test, thus "masking" possible flaws. To avoid that, we simply
// pretend we are starting from an earlier non translated revision.
// This ensures that the we can check that the merging logic is applied
// also when adding a new translation.
$latest_affected_revision_id = 1;
}
$previous_revision_id = (int) $entity->getLoadedRevisionId();
/** @var \Drupal\Core\Entity\ContentEntityInterface $latest_affected_revision */
$latest_affected_revision = $this->storage->loadRevision($latest_affected_revision_id);
$translation = $latest_affected_revision->hasTranslation($active_langcode) ?
$latest_affected_revision->getTranslation($active_langcode) : $latest_affected_revision->addTranslation($active_langcode);
$entity = $this->storage->createRevision($translation, $default_revision);
$this->assertEquals($default_revision, $entity->isDefaultRevision());
$this->assertEquals($translation->getLoadedRevisionId(), $entity->getLoadedRevisionId());
$this->assertEquals($previous_label, $entity->label(), $this->formatMessage('Loaded translatable field value does not match the previous one.'));
}
// Check that the previous untranslatable field value is loaded in the new
// revision as expected. When we are dealing with a non default translation
// the expected value is always the one stored in the default revision, as
// untranslatable fields can only be changed in the default translation or
// in the default revision, depending on the configured mode.
$value = $entity->get('non_mul_field')->value;
if (isset($previous_untranslatable_field_value)) {
$this->assertEquals($previous_untranslatable_field_value, $value, $this->formatMessage('Loaded untranslatable field value does not match the previous one.'));
}
elseif (!$entity->isDefaultTranslation()) {
/** @var \Drupal\Core\Entity\ContentEntityInterface $default_revision */
$default_revision = $this->storage->loadUnchanged($entity->id());
$expected_value = $default_revision->get('non_mul_field')->value;
$this->assertEquals($expected_value, $value, $this->formatMessage('Loaded untranslatable field value does not match the previous one.'));
}
// Perform a change and store it.
$label = $this->generateNewEntityLabel($entity, $previous_revision_id, TRUE);
$entity->set('name', $label);
if ($untranslatable_update) {
// Store the revision ID of the previous untranslatable fields update in
// the new value, besides the upcoming revision ID. Useful to analyze test
// failures.
$prev = 0;
if (isset($previous_untranslatable_field_value)) {
preg_match('/^\d+ -> (\d+)$/', $previous_untranslatable_field_value, $matches);
$prev = $matches[1];
}
$value = $prev . ' -> ' . ($entity->getLoadedRevisionId() + 1);
$entity->set('non_mul_field', $value);
$previous_untranslatable_field_value = $value;
}
$violations = $entity->validate();
$messages = [];
foreach ($violations as $violation) {
/** \Symfony\Component\Validator\ConstraintViolationInterface */
$messages[] = $violation->getMessage();
}
$this->assertEquals($valid, !$violations->count(), $this->formatMessage('Validation does not match the expected result: %s', implode(', ', $messages)));
if ($valid) {
$entity->save();
// Reload the current revision translation and the default revision to
// make sure data was stored correctly.
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $this->storage->loadRevision($entity->getRevisionId());
$entity = $entity->getTranslation($active_langcode);
/** @var \Drupal\Core\Entity\ContentEntityInterface $default_entity */
$default_entity = $this->storage->loadUnchanged($entity->id());
// Verify that the values for the current revision translation match the
// expected ones, while for the other translations they match the default
// revision. We also need to verify that only the current revision
// translation was marked as affected.
foreach ($entity->getTranslationLanguages() as $langcode => $language) {
$translation = $entity->getTranslation($langcode);
$rta_expected = $langcode == $active_langcode || ($untranslatable_update && $all_translations_affected);
$this->assertEquals($rta_expected, $translation->isRevisionTranslationAffected(), $this->formatMessage("'$langcode' translation incorrectly affected"));
$label_expected = $label;
if ($langcode !== $active_langcode) {
$default_translation = $default_entity->hasTranslation($langcode) ? $default_entity->getTranslation($langcode) : $default_entity;
$label_expected = $default_translation->label();
}
$this->assertEquals($label_expected, $translation->label(), $this->formatMessage("Incorrect '$langcode' translation label"));
}
}
return $entity->getRevisionId();
}
/**
* Generates a new label for the specified revision.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $revision
* An entity object.
* @param int $previous_revision_id
* The previous revision identifier for this revision translation.
* @param bool $next
* (optional) Whether the label describes the current revision or the one
* to be created. Defaults to FALSE.
*
* @return string
* A revision label.
*/
protected function generateNewEntityLabel(ContentEntityInterface $revision, $previous_revision_id, $next = FALSE) {
$language_label = $revision->language()->getName();
$revision_type = $revision->isDefaultRevision() ? 'Default' : 'Pending';
$revision_id = $next ? $this->storage->getLatestRevisionId($revision->id()) + 1 : $revision->getLoadedRevisionId();
return sprintf('%s (%s %d -> %d)', $language_label, $revision_type, $previous_revision_id, $revision_id);
}
/**
* Formats an assertion message.
*
* @param string $message
* The human-readable message.
*
* @return string
* The formatted message.
*/
protected function formatMessage($message) {
$args = func_get_args();
array_shift($args);
$params = array_merge($args, $this->stepInfo);
array_unshift($params, $this->stepIndex + 1);
array_unshift($params, '[Step %d] ' . $message . ' (langcode: %s, default_revision: %d, untranslatable_update: %d, valid: %d)');
return call_user_func_array('sprintf', $params);
}
/**
* Checks that changes to multiple translations are handled correctly.
*
* @covers ::createRevision
* @covers \Drupal\Core\Entity\Plugin\Validation\Constraint\EntityUntranslatableFieldsConstraintValidator::validate
*/
public function testMultipleTranslationChanges() {
// Configure the untranslatable fields edit mode.
$this->state->set('entity_test.untranslatable_fields.default_translation_affected', TRUE);
$this->bundleInfo->clearCachedBundles();
$entity = EntityTestMulRev::create();
$entity->get('name')->value = 'Test 1.1 EN';
$entity->get('non_mul_field')->value = 'Test 1.1';
$this->storage->save($entity);
/** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
$revision = $this->storage->createRevision($entity->addTranslation('it'));
$revision->get('name')->value = 'Test 1.2 IT';
$this->storage->save($revision);
$revision = $this->storage->createRevision($revision->getTranslation('en'), FALSE);
$revision->get('non_mul_field')->value = 'Test 1.3';
$revision->getTranslation('it')->get('name')->value = 'Test 1.3 IT';
$violations = $revision->validate();
$this->assertCount(1, $violations);
$this->assertEquals('Non-translatable fields can only be changed when updating the original language.', $violations[0]->getMessage());
}
/**
* Tests that internal properties are preserved while creating a new revision.
*/
public function testInternalProperties() {
$entity = EntityTestMulRev::create();
$this->doTestInternalProperties($entity);
$entity = EntityTestMulRev::create();
$entity->save();
$this->doTestInternalProperties($entity);
/** @var \Drupal\entity_test\Entity\EntityTestMulRev $translation */
$translation = EntityTestMulRev::create()->addTranslation('it');
$translation->save();
$this->doTestInternalProperties($translation);
}
/**
* Checks that internal properties are preserved for the specified entity.
*
* @param \Drupal\Core\Entity\ContentEntityInterface $entity
* An entity object.
*/
protected function doTestInternalProperties(ContentEntityInterface $entity) {
$this->assertFalse($entity->isValidationRequired());
$entity->setValidationRequired(TRUE);
$this->assertTrue($entity->isValidationRequired());
$new_revision = $this->storage->createRevision($entity);
$this->assertTrue($new_revision->isValidationRequired());
}
/**
* Tests that deleted translations are not accidentally restored.
*
* @covers ::createRevision
*/
public function testRemovedTranslations() {
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = EntityTestMulRev::create(['name' => 'Test 1.1 EN']);
$this->storage->save($entity);
/** @var \Drupal\Core\Entity\ContentEntityInterface $it_revision */
$it_revision = $this->storage->createRevision($entity->addTranslation('it'));
$it_revision->set('name', 'Test 1.2 IT');
$this->storage->save($it_revision);
/** @var \Drupal\Core\Entity\ContentEntityInterface $en_revision */
$en_revision = $this->storage->createRevision($it_revision->getUntranslated(), FALSE);
$en_revision->set('name', 'Test 1.3 EN');
$this->storage->save($en_revision);
/** @var \Drupal\Core\Entity\ContentEntityInterface $en_revision */
$it_revision = $this->storage->createRevision($it_revision);
$en_revision = $it_revision->getUntranslated();
$en_revision->removeTranslation('it');
$this->storage->save($en_revision);
$revision_id = $this->storage->getLatestTranslationAffectedRevisionId($entity->id(), 'en');
$en_revision = $this->storage->loadRevision($revision_id);
$en_revision = $this->storage->createRevision($en_revision);
$en_revision->set('name', 'Test 1.5 EN');
$this->storage->save($en_revision);
$en_revision = $this->storage->loadRevision($en_revision->getRevisionId());
$this->assertFalse($en_revision->hasTranslation('it'));
}
}
@@ -113,6 +113,7 @@ class EntityDefinitionUpdateTest extends EntityKernelTestBase {
// The revision key is now defined, so the revision field needs to be
// created.
t('The %field_name field needs to be installed.', ['%field_name' => 'Revision ID']),
t('The %field_name field needs to be installed.', ['%field_name' => 'Default revision']),
],
];
$this->assertEqual($this->entityDefinitionUpdateManager->getChangeSummary(), $expected, 'EntityDefinitionUpdateManager reports the expected change summary.');
@@ -389,53 +390,247 @@ class EntityDefinitionUpdateTest extends EntityKernelTestBase {
/**
* Tests deleting a base field when it has existing data.
*
* @dataProvider baseFieldDeleteWithExistingDataTestCases
*/
public function testBaseFieldDeleteWithExistingData() {
public function testBaseFieldDeleteWithExistingData($entity_type_id, $create_entity_revision, $base_field_revisionable) {
/** @var \Drupal\Core\Entity\Sql\SqlEntityStorageInterface $storage */
$storage = $this->entityManager->getStorage($entity_type_id);
$schema_handler = $this->database->schema();
// Create an entity without the base field, to ensure NULL values are not
// added to the dedicated table storage to be purged.
$entity = $storage->create();
$entity->save();
// Add the base field and run the update.
$this->addBaseField();
$this->addBaseField('string', $entity_type_id, $base_field_revisionable);
$this->entityDefinitionUpdateManager->applyUpdates();
// Save an entity with the base field populated.
$this->entityManager->getStorage('entity_test_update')->create(['new_base_field' => 'foo'])->save();
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $storage->getTableMapping();
$storage_definition = $this->entityManager->getLastInstalledFieldStorageDefinitions($entity_type_id)['new_base_field'];
// Remove the base field and apply updates. It's expected to throw an
// exception.
// @todo Revisit that expectation once purging is implemented for
// all fields: https://www.drupal.org/node/2282119.
$this->removeBaseField();
try {
$this->entityDefinitionUpdateManager->applyUpdates();
$this->fail('FieldStorageDefinitionUpdateForbiddenException thrown when trying to apply an update that deletes a non-purgeable field with data.');
// Save an entity with the base field populated.
$entity = $storage->create(['new_base_field' => 'foo']);
$entity->save();
if ($create_entity_revision) {
$entity->setNewRevision(TRUE);
$entity->new_base_field = 'bar';
$entity->save();
}
catch (FieldStorageDefinitionUpdateForbiddenException $e) {
$this->pass('FieldStorageDefinitionUpdateForbiddenException thrown when trying to apply an update that deletes a non-purgeable field with data.');
// Remove the base field and apply updates.
$this->removeBaseField($entity_type_id);
$this->entityDefinitionUpdateManager->applyUpdates();
// Check that the base field's column is deleted.
$this->assertFalse($schema_handler->fieldExists($entity_type_id, 'new_base_field'), 'Column deleted from shared table for new_base_field.');
// Check that a dedicated 'deleted' table was created for the deleted base
// field.
$dedicated_deleted_table_name = $table_mapping->getDedicatedDataTableName($storage_definition, TRUE);
$this->assertTrue($schema_handler->tableExists($dedicated_deleted_table_name), 'A dedicated table was created for the deleted new_base_field.');
// Check that the deleted field's data is preserved in the dedicated
// 'deleted' table.
$result = $this->database->select($dedicated_deleted_table_name, 't')
->fields('t')
->execute()
->fetchAll();
$this->assertCount(1, $result);
$expected = [
'bundle' => $entity->bundle(),
'deleted' => '1',
'entity_id' => $entity->id(),
'revision_id' => $create_entity_revision ? $entity->getRevisionId() : $entity->id(),
'langcode' => $entity->language()->getId(),
'delta' => '0',
'new_base_field_value' => $entity->new_base_field->value,
];
// Use assertEquals and not assertSame here to prevent that a different
// sequence of the columns in the table will affect the check.
$this->assertEquals($expected, (array) $result[0]);
if ($create_entity_revision) {
$dedicated_deleted_revision_table_name = $table_mapping->getDedicatedRevisionTableName($storage_definition, TRUE);
$this->assertTrue($schema_handler->tableExists($dedicated_deleted_revision_table_name), 'A dedicated revision table was created for the deleted new_base_field.');
$result = $this->database->select($dedicated_deleted_revision_table_name, 't')
->fields('t')
->orderBy('revision_id', 'DESC')
->execute()
->fetchAll();
// Only one row will be created for non-revisionable base fields.
$this->assertCount($base_field_revisionable ? 2 : 1, $result);
// Use assertEquals and not assertSame here to prevent that a different
// sequence of the columns in the table will affect the check.
$this->assertEquals([
'bundle' => $entity->bundle(),
'deleted' => '1',
'entity_id' => $entity->id(),
'revision_id' => '3',
'langcode' => $entity->language()->getId(),
'delta' => '0',
'new_base_field_value' => 'bar',
], (array) $result[0]);
// Two rows only exist if the base field is revisionable.
if ($base_field_revisionable) {
// Use assertEquals and not assertSame here to prevent that a different
// sequence of the columns in the table will affect the check.
$this->assertEquals([
'bundle' => $entity->bundle(),
'deleted' => '1',
'entity_id' => $entity->id(),
'revision_id' => '2',
'langcode' => $entity->language()->getId(),
'delta' => '0',
'new_base_field_value' => 'foo',
], (array) $result[1]);
}
}
// Check that the field storage definition is marked for purging.
$deleted_storage_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldStorageDefinitions();
$this->assertArrayHasKey($storage_definition->getUniqueStorageIdentifier(), $deleted_storage_definitions, 'The base field is marked for purging.');
// Purge field data, and check that the storage definition has been
// completely removed once the data is purged.
field_purge_batch(10);
$deleted_storage_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldStorageDefinitions();
$this->assertEmpty($deleted_storage_definitions, 'The base field has been deleted.');
$this->assertFalse($schema_handler->tableExists($dedicated_deleted_table_name), 'A dedicated field table was deleted after new_base_field was purged.');
if (isset($dedicated_deleted_revision_table_name)) {
$this->assertFalse($schema_handler->tableExists($dedicated_deleted_revision_table_name), 'A dedicated field revision table was deleted after new_base_field was purged.');
}
}
/**
* Test cases for ::testBaseFieldDeleteWithExistingData.
*/
public function baseFieldDeleteWithExistingDataTestCases() {
return [
'Non-revisionable entity type' => [
'entity_test_update',
FALSE,
FALSE,
],
'Non-revisionable custom data table' => [
'entity_test_mul',
FALSE,
FALSE,
],
'Non-revisionable entity type, revisionable base field' => [
'entity_test_update',
FALSE,
TRUE,
],
'Non-revisionable custom data table, revisionable base field' => [
'entity_test_mul',
FALSE,
TRUE,
],
'Revisionable entity type, non revisionable base field' => [
'entity_test_mulrev',
TRUE,
FALSE,
],
'Revisionable entity type, revisionable base field' => [
'entity_test_mulrev',
TRUE,
TRUE,
],
'Non-translatable revisionable entity type, revisionable base field' => [
'entity_test_rev',
TRUE,
TRUE,
],
'Non-translatable revisionable entity type, non-revisionable base field' => [
'entity_test_rev',
TRUE,
FALSE,
],
];
}
/**
* Tests deleting a bundle field when it has existing data.
*/
public function testBundleFieldDeleteWithExistingData() {
/** @var \Drupal\Core\Entity\Sql\SqlEntityStorageInterface $storage */
$storage = $this->entityManager->getStorage('entity_test_update');
$schema_handler = $this->database->schema();
// Add the bundle field and run the update.
$this->addBundleField();
$this->entityDefinitionUpdateManager->applyUpdates();
/** @var \Drupal\Core\Entity\Sql\DefaultTableMapping $table_mapping */
$table_mapping = $storage->getTableMapping();
$storage_definition = $this->entityManager->getLastInstalledFieldStorageDefinitions('entity_test_update')['new_bundle_field'];
// Check that the bundle field has a dedicated table.
$dedicated_table_name = $table_mapping->getDedicatedDataTableName($storage_definition);
$this->assertTrue($schema_handler->tableExists($dedicated_table_name), 'The bundle field uses a dedicated table.');
// Save an entity with the bundle field populated.
entity_test_create_bundle('custom');
$this->entityManager->getStorage('entity_test_update')->create(['type' => 'test_bundle', 'new_bundle_field' => 'foo'])->save();
$entity = $storage->create(['type' => 'test_bundle', 'new_bundle_field' => 'foo']);
$entity->save();
// Remove the bundle field and apply updates. It's expected to throw an
// exception.
// @todo Revisit that expectation once purging is implemented for
// all fields: https://www.drupal.org/node/2282119.
// Remove the bundle field and apply updates.
$this->removeBundleField();
try {
$this->entityDefinitionUpdateManager->applyUpdates();
$this->fail('FieldStorageDefinitionUpdateForbiddenException thrown when trying to apply an update that deletes a non-purgeable field with data.');
}
catch (FieldStorageDefinitionUpdateForbiddenException $e) {
$this->pass('FieldStorageDefinitionUpdateForbiddenException thrown when trying to apply an update that deletes a non-purgeable field with data.');
}
$this->entityDefinitionUpdateManager->applyUpdates();
// Check that the table of the bundle field has been renamed to use a
// 'deleted' table name.
$this->assertFalse($schema_handler->tableExists($dedicated_table_name), 'The dedicated table of the bundle field no longer exists.');
$dedicated_deleted_table_name = $table_mapping->getDedicatedDataTableName($storage_definition, TRUE);
$this->assertTrue($schema_handler->tableExists($dedicated_deleted_table_name), 'The dedicated table of the bundle fields has been renamed to use the "deleted" name.');
// Check that the deleted field's data is preserved in the dedicated
// 'deleted' table.
$result = $this->database->select($dedicated_deleted_table_name, 't')
->fields('t')
->execute()
->fetchAll();
$this->assertCount(1, $result);
$expected = [
'bundle' => $entity->bundle(),
'deleted' => '1',
'entity_id' => $entity->id(),
'revision_id' => $entity->id(),
'langcode' => $entity->language()->getId(),
'delta' => '0',
'new_bundle_field_value' => $entity->new_bundle_field->value,
];
// Use assertEquals and not assertSame here to prevent that a different
// sequence of the columns in the table will affect the check.
$this->assertEquals($expected, (array) $result[0]);
// Check that the field definition is marked for purging.
$deleted_field_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldDefinitions();
$this->assertArrayHasKey($storage_definition->getUniqueIdentifier(), $deleted_field_definitions, 'The bundle field is marked for purging.');
// Check that the field storage definition is marked for purging.
$deleted_storage_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldStorageDefinitions();
$this->assertArrayHasKey($storage_definition->getUniqueStorageIdentifier(), $deleted_storage_definitions, 'The bundle field storage is marked for purging.');
// Purge field data, and check that the storage definition has been
// completely removed once the data is purged.
field_purge_batch(10);
$deleted_field_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldDefinitions();
$this->assertEmpty($deleted_field_definitions, 'The bundle field has been deleted.');
$deleted_storage_definitions = \Drupal::service('entity_field.deleted_fields_repository')->getFieldStorageDefinitions();
$this->assertEmpty($deleted_storage_definitions, 'The bundle field storage has been deleted.');
$this->assertFalse($schema_handler->tableExists($dedicated_deleted_table_name), 'The dedicated table of the bundle field has been removed.');
}
/**
@@ -2,6 +2,7 @@
namespace Drupal\KernelTests\Core\Entity;
use Drupal\entity_test\Entity\EntityTestMul;
use Drupal\entity_test\Entity\EntityTestMulRev;
use Drupal\language\Entity\ConfigurableLanguage;
@@ -23,9 +24,11 @@ class EntityRevisionTranslationTest extends EntityKernelTestBase {
protected function setUp() {
parent::setUp();
// Enable an additional language.
// Enable some additional languages.
ConfigurableLanguage::createFromLangcode('de')->save();
ConfigurableLanguage::createFromLangcode('it')->save();
$this->installEntitySchema('entity_test_mul');
$this->installEntitySchema('entity_test_mulrev');
}
@@ -157,4 +160,124 @@ class EntityRevisionTranslationTest extends EntityKernelTestBase {
$this->assertFalse($translation->isDefaultRevision());
}
/**
* @covers \Drupal\Core\Entity\RevisionableInterface::setNewRevision
*/
public function testSetNewRevision() {
$user = $this->createUser();
// All revisionable entity variations have to have the same results.
foreach (entity_test_entity_types(ENTITY_TEST_TYPES_REVISABLE) as $entity_type) {
$this->installEntitySchema($entity_type);
$entity = entity_create($entity_type, [
'name' => 'foo',
'user_id' => $user->id(),
]);
$entity->save();
$entity_id = $entity->id();
$entity_rev_id = $entity->getRevisionId();
$entity = entity_load($entity_type, $entity_id, TRUE);
$entity->setNewRevision(TRUE);
$entity->setNewRevision(FALSE);
$entity->save();
$entity = entity_load($entity_type, $entity_id, TRUE);
$this->assertEquals($entity_rev_id, $entity->getRevisionId(), 'A new entity revision was not created.');
}
}
/**
* Tests that revision translations are correctly detected.
*
* @covers \Drupal\Core\Entity\ContentEntityStorageBase::isAnyStoredRevisionTranslated
*/
public function testIsAnyStoredRevisionTranslated() {
/** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
$storage = $this->entityManager->getStorage('entity_test_mul');
$method = new \ReflectionMethod(get_class($storage), 'isAnyStoredRevisionTranslated');
$method->setAccessible(TRUE);
// Check that a non-revisionable new entity is handled correctly.
$entity = EntityTestMul::create();
$this->assertEmpty($entity->getTranslationLanguages(FALSE));
$this->assertFalse($method->invoke($storage, $entity));
$entity->addTranslation('it');
$this->assertNotEmpty($entity->getTranslationLanguages(FALSE));
$this->assertFalse($method->invoke($storage, $entity));
// Check that not yet stored translations are handled correctly.
$entity = EntityTestMul::create();
$entity->save();
$entity->addTranslation('it');
$this->assertNotEmpty($entity->getTranslationLanguages(FALSE));
$this->assertFalse($method->invoke($storage, $entity));
// Check that removed translations are handled correctly.
$entity->save();
$entity->removeTranslation('it');
$this->assertEmpty($entity->getTranslationLanguages(FALSE));
$this->assertTrue($method->invoke($storage, $entity));
$entity->save();
$this->assertEmpty($entity->getTranslationLanguages(FALSE));
$this->assertFalse($method->invoke($storage, $entity));
$entity->addTranslation('de');
$entity->removeTranslation('de');
$this->assertEmpty($entity->getTranslationLanguages(FALSE));
$this->assertFalse($method->invoke($storage, $entity));
// Check that a non-revisionable not translated entity is handled correctly.
$entity = EntityTestMul::create();
$entity->save();
$this->assertEmpty($entity->getTranslationLanguages(FALSE));
$this->assertFalse($method->invoke($storage, $entity));
// Check that a non-revisionable translated entity is handled correctly.
$entity->addTranslation('it');
$entity->save();
$this->assertNotEmpty($entity->getTranslationLanguages(FALSE));
$this->assertTrue($method->invoke($storage, $entity));
/** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
$storage = $this->entityManager->getStorage('entity_test_mulrev');
// Check that a revisionable new entity is handled correctly.
$entity = EntityTestMulRev::create();
$this->assertEmpty($entity->getTranslationLanguages(FALSE));
$this->assertFalse($method->invoke($storage, $entity));
$entity->addTranslation('it');
$this->assertNotEmpty($entity->getTranslationLanguages(FALSE));
$this->assertFalse($method->invoke($storage, $entity));
// Check that a revisionable not translated entity is handled correctly.
$entity = EntityTestMulRev::create();
$entity->save();
$this->assertEmpty($entity->getTranslationLanguages(FALSE));
$this->assertFalse($method->invoke($storage, $entity));
// Check that a revisionable translated pending revision is handled
// correctly.
/** @var \Drupal\Core\Entity\ContentEntityInterface $new_revision */
$new_revision = $storage->createRevision($entity, FALSE);
$new_revision->addTranslation('it');
$new_revision->save();
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $storage->loadUnchanged($entity->id());
$this->assertEmpty($entity->getTranslationLanguages(FALSE));
$this->assertNotEmpty($new_revision->getTranslationLanguages(FALSE));
$this->assertTrue($method->invoke($storage, $entity));
// Check that a revisionable translated default revision is handled
// correctly.
$new_revision->isDefaultRevision(TRUE);
$new_revision->save();
/** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
$entity = $storage->loadUnchanged($entity->id());
$this->assertNotEmpty($entity->getTranslationLanguages(FALSE));
$this->assertNotEmpty($new_revision->getTranslationLanguages(FALSE));
$this->assertTrue($method->invoke($storage, $entity));
}
}
@@ -8,9 +8,11 @@ use Drupal\language\Entity\ConfigurableLanguage;
/**
* Tests the loaded Revision of an entity.
*
* @coversDefaultClass \Drupal\Core\Entity\ContentEntityBase
*
* @group entity
*/
class EntityLoadedRevisionTest extends EntityKernelTestBase {
class EntityRevisionsTest extends EntityKernelTestBase {
/**
* Modules to enable.
@@ -164,7 +166,99 @@ class EntityLoadedRevisionTest extends EntityKernelTestBase {
$loadedRevisionId = \Drupal::state()->get('entity_test.loadedRevisionId');
$this->assertEquals($entity->getLoadedRevisionId(), $loadedRevisionId);
$this->assertEquals($entity->getRevisionId(), $entity->getLoadedRevisionId());
}
/**
* Tests that latest revisions are working as expected.
*
* @covers ::isLatestRevision
*/
public function testIsLatestRevision() {
// Create a basic EntityTestMulRev entity and save it.
$entity = EntityTestMulRev::create();
$entity->save();
$this->assertTrue($entity->isLatestRevision());
// Load the created entity and create a new pending revision.
$pending_revision = EntityTestMulRev::load($entity->id());
$pending_revision->setNewRevision(TRUE);
$pending_revision->isDefaultRevision(FALSE);
// The pending revision should still be marked as the latest one before it
// is saved.
$this->assertTrue($pending_revision->isLatestRevision());
$pending_revision->save();
$this->assertTrue($pending_revision->isLatestRevision());
// Load the default revision and check that it is not marked as the latest
// revision.
$default_revision = EntityTestMulRev::load($entity->id());
$this->assertFalse($default_revision->isLatestRevision());
}
/**
* Tests that latest affected revisions are working as expected.
*
* The latest revision affecting a particular translation behaves as the
* latest revision for monolingual entities.
*
* @covers ::isLatestTranslationAffectedRevision
* @covers \Drupal\Core\Entity\ContentEntityStorageBase::getLatestRevisionId
* @covers \Drupal\Core\Entity\ContentEntityStorageBase::getLatestTranslationAffectedRevisionId
*/
public function testIsLatestAffectedRevisionTranslation() {
ConfigurableLanguage::createFromLangcode('it')->save();
// Create a basic EntityTestMulRev entity and save it.
$entity = EntityTestMulRev::create();
$entity->setName($this->randomString());
$entity->save();
$this->assertTrue($entity->isLatestTranslationAffectedRevision());
// Load the created entity and create a new pending revision.
$pending_revision = EntityTestMulRev::load($entity->id());
$pending_revision->setName($this->randomString());
$pending_revision->setNewRevision(TRUE);
$pending_revision->isDefaultRevision(FALSE);
// Check that no revision affecting Italian is available, given that no
// Italian translation has been created yet.
/** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
$storage = $this->entityManager->getStorage($entity->getEntityTypeId());
$this->assertNull($storage->getLatestTranslationAffectedRevisionId($entity->id(), 'it'));
$this->assertEquals($pending_revision->getLoadedRevisionId(), $storage->getLatestRevisionId($entity->id()));
// The pending revision should still be marked as the latest affected one
// before it is saved.
$this->assertTrue($pending_revision->isLatestTranslationAffectedRevision());
$pending_revision->save();
$this->assertTrue($pending_revision->isLatestTranslationAffectedRevision());
// Load the default revision and check that it is not marked as the latest
// (translation-affected) revision.
$default_revision = EntityTestMulRev::load($entity->id());
$this->assertFalse($default_revision->isLatestRevision());
$this->assertFalse($default_revision->isLatestTranslationAffectedRevision());
// Add a translation in a new pending revision and verify that both the
// English and Italian revision translations are the latest affected
// revisions for their respective languages, while the English revision is
// not the latest revision.
/** @var \Drupal\entity_test\Entity\EntityTestMulRev $en_revision */
$en_revision = clone $pending_revision;
/** @var \Drupal\entity_test\Entity\EntityTestMulRev $it_revision */
$it_revision = $pending_revision->addTranslation('it');
$it_revision->setName($this->randomString());
$it_revision->setNewRevision(TRUE);
$it_revision->isDefaultRevision(FALSE);
// @todo Remove this once the "original" property works with revisions. See
// https://www.drupal.org/project/drupal/issues/2859042.
$it_revision->original = $storage->loadRevision($it_revision->getLoadedRevisionId());
$it_revision->save();
$this->assertTrue($it_revision->isLatestRevision());
$this->assertTrue($it_revision->isLatestTranslationAffectedRevision());
$this->assertFalse($en_revision->isLatestRevision());
$this->assertTrue($en_revision->isLatestTranslationAffectedRevision());
}
}
@@ -24,7 +24,11 @@ class EntityTypeConstraintsTest extends EntityKernelTestBase {
// Test reading the annotation. There should be two constraints, the defined
// constraint and the automatically added EntityChanged constraint.
$entity_type = $this->entityManager->getDefinition('entity_test_constraints');
$default_constraints = ['NotNull' => [], 'EntityChanged' => NULL];
$default_constraints = [
'NotNull' => [],
'EntityChanged' => NULL,
'EntityUntranslatableFields' => NULL,
];
$this->assertEqual($default_constraints, $entity_type->getConstraints());
// Enable our test module and test extending constraints.
@@ -2,6 +2,8 @@
namespace Drupal\KernelTests\Core\Entity;
use Drupal\Core\Entity\EntityManagerInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\Core\Entity\TypedData\EntityDataDefinition;
use Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface;
use Drupal\Core\Field\BaseFieldDefinition;
@@ -11,6 +13,7 @@ use Drupal\Core\TypedData\DataReferenceDefinition;
use Drupal\Core\TypedData\DataReferenceDefinitionInterface;
use Drupal\Core\TypedData\ListDataDefinitionInterface;
use Drupal\KernelTests\KernelTestBase;
use Drupal\node\Entity\NodeType;
/**
* Tests deriving metadata of entity and field data types.
@@ -31,10 +34,16 @@ class EntityTypedDataDefinitionTest extends KernelTestBase {
*
* @var array
*/
public static $modules = ['filter', 'text', 'node', 'user'];
public static $modules = ['system', 'filter', 'text', 'node', 'user'];
protected function setUp() {
parent::setup();
NodeType::create([
'type' => 'article',
'name' => 'Article',
])->save();
$this->typedDataManager = $this->container->get('typed_data_manager');
}
@@ -82,10 +91,15 @@ class EntityTypedDataDefinitionTest extends KernelTestBase {
*/
public function testEntities() {
$entity_definition = EntityDataDefinition::create('node');
$bundle_definition = EntityDataDefinition::create('node', 'article');
// Entities are complex data.
$this->assertFalse($entity_definition instanceof ListDataDefinitionInterface);
$this->assertTrue($entity_definition instanceof ComplexDataDefinitionInterface);
// Entity definitions should inherit their labels from the entity type.
$this->assertEquals('Content', $entity_definition->getLabel());
$this->assertEquals('Article', $bundle_definition->getLabel());
$field_definitions = $entity_definition->getPropertyDefinitions();
// Comparison should ignore the internal static cache, so compare the
// serialized objects instead.
@@ -126,4 +140,36 @@ class EntityTypedDataDefinitionTest extends KernelTestBase {
$this->assertEqual(serialize($reference_definition2), serialize($reference_definition));
}
/**
* Tests that an entity annotation can mark the data definition as internal.
*
* @dataProvider entityDefinitionIsInternalProvider
*/
public function testEntityDefinitionIsInternal($internal, $expected) {
$entity_type_id = $this->randomMachineName();
$entity_type = $this->prophesize(EntityTypeInterface::class);
$entity_type->getLabel()->willReturn($this->randomString());
$entity_type->getConstraints()->willReturn([]);
$entity_type->isInternal()->willReturn($internal);
$entity_manager = $this->prophesize(EntityManagerInterface::class);
$entity_manager->getDefinitions()->willReturn([$entity_type_id => $entity_type->reveal()]);
$this->container->set('entity.manager', $entity_manager->reveal());
$entity_data_definition = EntityDataDefinition::create($entity_type_id);
$this->assertSame($expected, $entity_data_definition->isInternal());
}
/**
* Provides test cases for testEntityDefinitionIsInternal.
*/
public function entityDefinitionIsInternalProvider() {
return [
'internal' => [TRUE, TRUE],
'external' => [FALSE, FALSE],
'undefined' => [NULL, FALSE],
];
}
}
@@ -15,7 +15,7 @@ use Drupal\KernelTests\KernelTestBase;
*/
class FieldWidgetConstraintValidatorTest extends KernelTestBase {
public static $modules = ['entity_test', 'field', 'user', 'system'];
public static $modules = ['entity_test', 'field', 'field_test', 'user', 'system'];
/**
* {@inheritdoc}
@@ -54,7 +54,8 @@ class FieldWidgetConstraintValidatorTest extends KernelTestBase {
$display->validateFormValues($entity, $form, $form_state);
$errors = $form_state->getErrors();
$this->assertEqual($errors['name'], 'Widget constraint has failed.', 'Constraint violation is generated correctly');
$this->assertEqual($errors['name'], 'Widget constraint has failed.', 'Constraint violation at the field items list level is generated correctly');
$this->assertEqual($errors['test_field'], 'Widget constraint has failed.', 'Constraint violation at the field items list level is generated correctly for an advanced widget');
}
/**
@@ -5,7 +5,6 @@ namespace Drupal\KernelTests\Core\Entity;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityTypeInterface;
use Drupal\entity_test_revlog\Entity\EntityTestMulWithRevisionLog;
use Drupal\KernelTests\KernelTestBase;
use Drupal\user\Entity\User;
use Drupal\user\UserInterface;
@@ -13,7 +12,7 @@ use Drupal\user\UserInterface;
* @coversDefaultClass \Drupal\Core\Entity\RevisionableContentEntityBase
* @group Entity
*/
class RevisionableContentEntityBaseTest extends KernelTestBase {
class RevisionableContentEntityBaseTest extends EntityKernelTestBase {
/**
* {@inheritdoc}
@@ -25,10 +24,7 @@ class RevisionableContentEntityBaseTest extends KernelTestBase {
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('entity_test_mul_revlog');
$this->installEntitySchema('user');
$this->installSchema('system', 'sequences');
}
/**
@@ -89,6 +85,74 @@ class RevisionableContentEntityBaseTest extends KernelTestBase {
$this->assertItemsTableCount(3, $definition);
}
/**
* Tests the behavior of the "revision_default" flag.
*
* @covers \Drupal\Core\Entity\ContentEntityBase::wasDefaultRevision
*/
public function testWasDefaultRevision() {
$entity_type_id = 'entity_test_mul_revlog';
$entity = EntityTestMulWithRevisionLog::create([
'type' => $entity_type_id,
]);
// Checks that in a new entity ::wasDefaultRevision() always matches
// ::isDefaultRevision().
$this->assertEquals($entity->isDefaultRevision(), $entity->wasDefaultRevision());
$entity->isDefaultRevision(FALSE);
$this->assertEquals($entity->isDefaultRevision(), $entity->wasDefaultRevision());
// Check that a new entity is always flagged as a default revision on save,
// regardless of its default revision status.
$entity->save();
$this->assertTrue($entity->wasDefaultRevision());
// Check that a pending revision is not flagged as default.
$entity->setNewRevision();
$entity->isDefaultRevision(FALSE);
$entity->save();
$this->assertFalse($entity->wasDefaultRevision());
// Check that a default revision is flagged as such.
$entity->setNewRevision();
$entity->isDefaultRevision(TRUE);
$entity->save();
$this->assertTrue($entity->wasDefaultRevision());
// Check that a manually set value for the "revision_default" flag is
// ignored on save.
$entity->setNewRevision();
$entity->isDefaultRevision(FALSE);
$entity->set('revision_default', TRUE);
$this->assertTrue($entity->wasDefaultRevision());
$entity->save();
$this->assertFalse($entity->wasDefaultRevision());
// Check that the default revision status was stored correctly.
$storage = $this->entityManager->getStorage($entity_type_id);
foreach ([TRUE, FALSE, TRUE, FALSE] as $index => $expected) {
/** @var \Drupal\entity_test_revlog\Entity\EntityTestMulWithRevisionLog $revision */
$revision = $storage->loadRevision($index + 1);
$this->assertEquals($expected, $revision->wasDefaultRevision());
}
// Check that the default revision is flagged correctly.
/** @var \Drupal\entity_test_revlog\Entity\EntityTestMulWithRevisionLog $entity */
$entity = $storage->loadUnchanged($entity->id());
$this->assertTrue($entity->wasDefaultRevision());
// Check that the "revision_default" flag cannot be changed once set.
/** @var \Drupal\entity_test_revlog\Entity\EntityTestMulWithRevisionLog $entity2 */
$entity2 = EntityTestMulWithRevisionLog::create([
'type' => $entity_type_id,
]);
$entity2->save();
$this->assertTrue($entity2->wasDefaultRevision());
$entity2->isDefaultRevision(FALSE);
$entity2->save();
$this->assertTrue($entity2->wasDefaultRevision());
}
/**
* Asserts the ammount of items on entity related tables.
*
@@ -0,0 +1,61 @@
<?php
namespace Drupal\KernelTests\Core\Extension;
use Drupal\KernelTests\KernelTestBase;
/**
* Test whether deprecated hook invocations trigger errors.
*
* @group Extension
* @group legacy
*
* @coversDefaultClass Drupal\Core\Extension\ModuleHandler
*/
class ModuleHandlerDeprecatedHookTest extends KernelTestBase {
protected static $modules = ['deprecation_test'];
/**
* @covers ::invokeDeprecated
* @expectedDeprecation The deprecated hook hook_deprecated_hook() is implemented in these functions: deprecation_test_deprecated_hook(). Use something else.
*/
public function testInvokeDeprecated() {
/* @var $module_handler \Drupal\Core\Extension\ModuleHandlerInterface */
$module_handler = $this->container->get('module_handler');
$arg = 'an_arg';
$this->assertEqual(
$arg,
$module_handler->invokeDeprecated('Use something else.', 'deprecation_test', 'deprecated_hook', [$arg])
);
}
/**
* @covers ::invokeAllDeprecated
* @expectedDeprecation The deprecated hook hook_deprecated_hook() is implemented in these functions: deprecation_test_deprecated_hook(). Use something else.
*/
public function testInvokeAllDeprecated() {
/* @var $module_handler \Drupal\Core\Extension\ModuleHandlerInterface */
$module_handler = $this->container->get('module_handler');
$arg = 'an_arg';
$this->assertEqual(
[$arg],
$module_handler->invokeAllDeprecated('Use something else.', 'deprecated_hook', [$arg])
);
}
/**
* @covers ::alterDeprecated
* @expectedDeprecation The deprecated alter hook hook_deprecated_alter_alter() is implemented in these functions: deprecation_test_deprecated_alter_alter. Alter something else.
*/
public function testAlterDeprecated() {
/* @var $module_handler \Drupal\Core\Extension\ModuleHandlerInterface */
$module_handler = $this->container->get('module_handler');
$data = [];
$context1 = 'test1';
$context2 = 'test2';
$module_handler->alterDeprecated('Alter something else.', 'deprecated_alter', $data, $context1, $context2);
$this->assertEqual([$context1, $context2], $data);
}
}
@@ -0,0 +1,33 @@
<?php
namespace Drupal\KernelTests\Core\Extension;
use Drupal\KernelTests\KernelTestBase;
/**
* Test whether unimplemented deprecated hook invocations trigger errors.
*
* @group Extension
*
* @coversDefaultClass Drupal\Core\Extension\ModuleHandler
*/
class ModuleHandlerDeprecatedHookUnimplementedTest extends KernelTestBase {
/**
* @covers ::alterDeprecated
* @covers ::invokeAllDeprecated
* @covers ::invokeDeprecated
*/
public function testUnimplementedHooks() {
$unimplemented_hook_name = 'unimplemented_hook_name';
/* @var $module_handler \Drupal\Core\Extension\ModuleHandlerInterface */
$module_handler = $this->container->get('module_handler');
$module_handler->invokeDeprecated('Use something else.', 'deprecation_test', $unimplemented_hook_name);
$module_handler->invokeAllDeprecated('Use something else.', $unimplemented_hook_name);
$data = [];
$module_handler->alterDeprecated('Alter something else.', $unimplemented_hook_name, $data);
}
}
@@ -85,4 +85,13 @@ class ModuleInstallerTest extends KernelTestBase {
$this->assertFalse($schema->tableExists($table));
}
/**
* Ensure that rebuilding the container in hook_install() works.
*/
public function testKernelRebuildDuringHookInstall() {
\Drupal::state()->set('module_test_install:rebuild_container', TRUE);
$module_installer = $this->container->get('module_installer');
$this->assertTrue($module_installer->install(['module_test']));
}
}
@@ -1,140 +0,0 @@
<?php
namespace Drupal\KernelTests\Core\Field;
use Drupal\Core\Extension\ModuleUninstallValidatorException;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\entity_test\FieldStorageDefinition;
use Drupal\KernelTests\Core\Entity\EntityKernelTestBase;
/**
* Tests FieldModuleUninstallValidator functionality.
*
* @group Field
*/
class FieldModuleUninstallValidatorTest extends EntityKernelTestBase {
/**
* The entity definition update manager.
*
* @var \Drupal\Core\Entity\EntityDefinitionUpdateManagerInterface
*/
protected $entityDefinitionUpdateManager;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installSchema('user', 'users_data');
$this->entityDefinitionUpdateManager = $this->container->get('entity.definition_update_manager');
// Setup some fields for entity_test_extra to create.
$definitions['extra_base_field'] = BaseFieldDefinition::create('string')
->setName('extra_base_field')
->setTargetEntityTypeId('entity_test')
->setTargetBundle('entity_test');
$this->state->set('entity_test.additional_base_field_definitions', $definitions);
$definitions['extra_bundle_field'] = FieldStorageDefinition::create('string')
->setName('extra_bundle_field')
->setTargetEntityTypeId('entity_test')
->setTargetBundle('entity_test');
$this->state->set('entity_test.additional_field_storage_definitions', $definitions);
$this->state->set('entity_test.entity_test.additional_bundle_field_definitions', $definitions);
$this->entityManager->clearCachedDefinitions();
}
/**
* Tests uninstall entity_test module with and without content for the field.
*/
public function testUninstallingModule() {
// Test uninstall works fine without content.
$this->assertModuleInstallUninstall('entity_test_extra');
// Test uninstalling works fine with content having no field values.
$entity = $this->entityManager->getStorage('entity_test')->create([
'name' => $this->randomString(),
]);
$entity->save();
$this->assertModuleInstallUninstall('entity_test_extra');
$entity->delete();
// Verify uninstall works fine without content again.
$this->assertModuleInstallUninstall('entity_test_extra');
// Verify uninstalling entity_test is not possible when there is content for
// the base field.
$this->enableModules(['entity_test_extra']);
$this->entityDefinitionUpdateManager->applyUpdates();
$entity = $this->entityManager->getStorage('entity_test')->create([
'name' => $this->randomString(),
'extra_base_field' => $this->randomString(),
]);
$entity->save();
try {
$message = 'Module uninstallation fails as the module provides a base field which has content.';
$this->getModuleInstaller()->uninstall(['entity_test_extra']);
$this->fail($message);
}
catch (ModuleUninstallValidatorException $e) {
$this->pass($message);
$this->assertEqual($e->getMessage(), 'The following reasons prevent the modules from being uninstalled: There is data for the field extra_base_field on entity type Test entity');
}
// Verify uninstalling entity_test is not possible when there is content for
// the bundle field.
$entity->delete();
$this->assertModuleInstallUninstall('entity_test_extra');
$this->enableModules(['entity_test_extra']);
$this->entityDefinitionUpdateManager->applyUpdates();
$entity = $this->entityManager->getStorage('entity_test')->create([
'name' => $this->randomString(),
'extra_bundle_field' => $this->randomString(),
]);
$entity->save();
try {
$this->getModuleInstaller()->uninstall(['entity_test_extra']);
$this->fail('Module uninstallation fails as the module provides a bundle field which has content.');
}
catch (ModuleUninstallValidatorException $e) {
$this->pass('Module uninstallation fails as the module provides a bundle field which has content.');
}
}
/**
* Asserts the given module can be installed and uninstalled.
*
* @param string $module_name
* The module to install and uninstall.
*/
protected function assertModuleInstallUninstall($module_name) {
// Install the module if it is not installed yet.
if (!\Drupal::moduleHandler()->moduleExists($module_name)) {
$this->enableModules([$module_name]);
}
$this->entityDefinitionUpdateManager->applyUpdates();
$this->assertTrue($this->getModuleHandler()->moduleExists($module_name), $module_name . ' module is enabled.');
$this->getModuleInstaller()->uninstall([$module_name]);
$this->entityDefinitionUpdateManager->applyUpdates();
$this->assertFalse($this->getModuleHandler()->moduleExists($module_name), $module_name . ' module is disabled.');
}
/**
* Returns the ModuleHandler.
*
* @return \Drupal\Core\Extension\ModuleHandlerInterface
*/
protected function getModuleHandler() {
return $this->container->get('module_handler');
}
/**
* Returns the ModuleInstaller.
*
* @return \Drupal\Core\Extension\ModuleInstallerInterface
*/
protected function getModuleInstaller() {
return $this->container->get('module_installer');
}
}
@@ -46,6 +46,34 @@ class FieldSettingsTest extends EntityKernelTestBase {
$this->assertEqual($base_field->getSettings(), $expected_settings);
}
/**
* Tests the base field settings on a cloned base field definition object.
*/
public function testBaseFieldSettingsOnClone() {
$base_field = BaseFieldDefinition::create('test_field');
// Check that the default settings have been populated.
$expected_settings = [
'test_field_storage_setting' => 'dummy test string',
'changeable' => 'a changeable field storage setting',
'unchangeable' => 'an unchangeable field storage setting',
'translatable_storage_setting' => 'a translatable field storage setting',
'test_field_setting' => 'dummy test string',
'translatable_field_setting' => 'a translatable field setting',
];
$this->assertEquals($expected_settings, $base_field->getSettings());
// Clone the base field object and change one single setting using
// setSettings() on the cloned base field and check that it has been
// changed only on the cloned object.
$clone_base_field = clone $base_field;
$expected_settings_clone = $expected_settings;
$expected_settings_clone['changeable'] = $expected_settings['changeable'] . ' (clone)';
$clone_base_field->setSetting('changeable', $expected_settings_clone['changeable']);
$this->assertEquals($expected_settings, $base_field->getSettings());
$this->assertEquals($expected_settings_clone, $clone_base_field->getSettings());
}
/**
* @covers \Drupal\field\Entity\FieldStorageConfig::getSettings
* @covers \Drupal\field\Entity\FieldStorageConfig::setSettings
@@ -45,7 +45,7 @@ class DirectoryTest extends FileTestBase {
$this->assertDirectoryPermissions($directory, $old_mode);
// Check creating a directory using an absolute path.
$absolute_path = drupal_realpath($directory) . DIRECTORY_SEPARATOR . $this->randomMachineName() . DIRECTORY_SEPARATOR . $this->randomMachineName();
$absolute_path = \Drupal::service('file_system')->realpath($directory) . DIRECTORY_SEPARATOR . $this->randomMachineName() . DIRECTORY_SEPARATOR . $this->randomMachineName();
$this->assertTrue(drupal_mkdir($absolute_path, 0775, TRUE), 'No error reported when creating new absolute directories.', 'File');
$this->assertDirectoryPermissions($absolute_path, 0775);
}
@@ -0,0 +1,137 @@
<?php
namespace Drupal\KernelTests\Core\Layout;
use Drupal\Core\Layout\Icon\SvgIconBuilder;
use Drupal\Core\Render\RenderContext;
use Drupal\KernelTests\KernelTestBase;
/**
* @coversDefaultClass \Drupal\Core\Layout\Icon\SvgIconBuilder
* @group Layout
*/
class IconBuilderTest extends KernelTestBase {
/**
* @covers ::build
* @covers ::buildRenderArray
* @covers ::calculateSvgValues
* @covers ::getLength
* @covers ::getOffset
*
* @dataProvider providerTestBuild
*/
public function testBuild(SvgIconBuilder $icon_builder, $icon_map, $expected) {
$renderer = $this->container->get('renderer');
$build = $icon_builder->build($icon_map);
$output = (string) $renderer->executeInRenderContext(new RenderContext(), function () use ($build, $renderer) {
return $renderer->render($build);
});
$this->assertSame($expected, $output);
}
public function providerTestBuild() {
$data = [];
$data['empty'][] = (new SvgIconBuilder());
$data['empty'][] = [];
$data['empty'][] = <<<'EOD'
<svg width="125" height="150" class="layout-icon"></svg>
EOD;
$data['two_column'][] = (new SvgIconBuilder())
->setId('two_column')
->setLabel('Two Column')
->setWidth(250)
->setHeight(300)
->setStrokeWidth(2);
$data['two_column'][] = [['left', 'right']];
$data['two_column'][] = <<<'EOD'
<svg width="250" height="300" class="layout-icon layout-icon--two-column"><title>Two Column</title>
<g><title>left</title>
<rect x="1" y="1" width="121" height="298" stroke-width="2" class="layout-icon__region layout-icon__region--left" />
</g>
<g><title>right</title>
<rect x="128" y="1" width="121" height="298" stroke-width="2" class="layout-icon__region layout-icon__region--right" />
</g>
</svg>
EOD;
$data['two_column_no_stroke'][] = (new SvgIconBuilder())
->setWidth(250)
->setHeight(300)
->setStrokeWidth(NULL);
$data['two_column_no_stroke'][] = [['left', 'right']];
$data['two_column_no_stroke'][] = <<<'EOD'
<svg width="250" height="300" class="layout-icon"><g><title>left</title>
<rect x="0" y="0" width="123" height="300" class="layout-icon__region layout-icon__region--left" />
</g>
<g><title>right</title>
<rect x="127" y="0" width="123" height="300" class="layout-icon__region layout-icon__region--right" />
</g>
</svg>
EOD;
$data['two_column_border_collapse'][] = (new SvgIconBuilder())
->setWidth(250)
->setHeight(300)
->setStrokeWidth(2)
->setPadding(-2);
$data['two_column_border_collapse'][] = [['left', 'right']];
$data['two_column_border_collapse'][] = <<<'EOD'
<svg width="250" height="300" class="layout-icon"><g><title>left</title>
<rect x="1" y="1" width="124" height="298" stroke-width="2" class="layout-icon__region layout-icon__region--left" />
</g>
<g><title>right</title>
<rect x="125" y="1" width="124" height="298" stroke-width="2" class="layout-icon__region layout-icon__region--right" />
</g>
</svg>
EOD;
$data['stacked'][] = (new SvgIconBuilder())
->setStrokeWidth(2);
$data['stacked'][] = [
['sidebar', 'top', 'top'],
['sidebar', 'left', 'right'],
['sidebar', 'middle', 'middle'],
['footer_left', 'footer_right'],
['footer_full'],
];
$data['stacked'][] = <<<'EOD'
<svg width="125" height="150" class="layout-icon"><g><title>sidebar</title>
<rect x="1" y="1" width="37" height="86.4" stroke-width="2" class="layout-icon__region layout-icon__region--sidebar" />
</g>
<g><title>top</title>
<rect x="44" y="1" width="80" height="24.8" stroke-width="2" class="layout-icon__region layout-icon__region--top" />
</g>
<g><title>left</title>
<rect x="44" y="31.8" width="37" height="24.8" stroke-width="2" class="layout-icon__region layout-icon__region--left" />
</g>
<g><title>right</title>
<rect x="87" y="31.8" width="37" height="24.8" stroke-width="2" class="layout-icon__region layout-icon__region--right" />
</g>
<g><title>middle</title>
<rect x="44" y="62.6" width="80" height="24.8" stroke-width="2" class="layout-icon__region layout-icon__region--middle" />
</g>
<g><title>footer_left</title>
<rect x="1" y="93.4" width="58.5" height="24.8" stroke-width="2" class="layout-icon__region layout-icon__region--footer-left" />
</g>
<g><title>footer_right</title>
<rect x="65.5" y="93.4" width="58.5" height="24.8" stroke-width="2" class="layout-icon__region layout-icon__region--footer-right" />
</g>
<g><title>footer_full</title>
<rect x="1" y="124.2" width="123" height="24.8" stroke-width="2" class="layout-icon__region layout-icon__region--footer-full" />
</g>
</svg>
EOD;
return $data;
}
}
@@ -0,0 +1,108 @@
<?php
namespace Drupal\KernelTests\Core\Messenger;
use Drupal\Core\Messenger\LegacyMessenger;
use Drupal\Core\Messenger\Messenger;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\KernelTests\KernelTestBase;
/**
* @group Messenger
* @coversDefaultClass \Drupal\Core\Messenger\LegacyMessenger
*
* Note: The Symphony PHPUnit Bridge automatically treats any test class that
* starts with "Legacy" as a deprecation. To subvert that, reverse it here.
*
* @see http://symfony.com/blog/new-in-symfony-2-7-phpunit-bridge
* @see https://www.drupal.org/node/2931598#comment-12395743
*/
class MessengerLegacyTest extends KernelTestBase {
/**
* Retrieves the Messenger service from LegacyMessenger.
*
* @param \Drupal\Core\Messenger\LegacyMessenger $legacy_messenger
* The legacy messenger.
*
* @return \Drupal\Core\Messenger\MessengerInterface|null
* A messenger implementation.
*/
protected function getMessengerService(LegacyMessenger $legacy_messenger) {
$method = new \ReflectionMethod($legacy_messenger, 'getMessengerService');
$method->setAccessible(TRUE);
return $method->invoke($legacy_messenger);
}
/**
* @covers \Drupal::messenger
* @covers ::getMessengerService
* @covers ::all
* @covers ::addMessage
* @covers ::addError
* @covers ::addStatus
* @covers ::addWarning
*/
public function testMessages() {
// Save the current container for later use.
$container = \Drupal::getContainer();
// Unset the container to mimic not having one.
\Drupal::unsetContainer();
/** @var \Drupal\Core\Messenger\LegacyMessenger $messenger */
// Verify that the Messenger service doesn't exists.
$messenger = \Drupal::messenger();
$this->assertNull($this->getMessengerService($messenger));
// Add messages.
$messenger->addMessage('Foobar', 'custom');
$messenger->addMessage('Foobar', 'custom', TRUE);
$messenger->addError('Foo');
$messenger->addError('Foo', TRUE);
// Verify that retrieving another instance and adding more messages works.
$messenger = \Drupal::messenger();
$messenger->addStatus('Bar');
$messenger->addStatus('Bar', TRUE);
$messenger->addWarning('Fiz');
$messenger->addWarning('Fiz', TRUE);
// Restore the container.
\Drupal::setContainer($container);
// Verify that the Messenger service exists.
$messenger = \Drupal::messenger();
$this->assertInstanceOf(Messenger::class, $this->getMessengerService($messenger));
// Add more messages.
$messenger->addMessage('Platypus', 'custom');
$messenger->addMessage('Platypus', 'custom', TRUE);
$messenger->addError('Rhinoceros');
$messenger->addError('Rhinoceros', TRUE);
$messenger->addStatus('Giraffe');
$messenger->addStatus('Giraffe', TRUE);
$messenger->addWarning('Cheetah');
$messenger->addWarning('Cheetah', TRUE);
// Verify all messages added via LegacyMessenger are accounted for.
$messages = $messenger->all();
$this->assertContains('Foobar', $messages['custom']);
$this->assertContains('Foo', $messages[MessengerInterface::TYPE_ERROR]);
$this->assertContains('Bar', $messages[MessengerInterface::TYPE_STATUS]);
$this->assertContains('Fiz', $messages[MessengerInterface::TYPE_WARNING]);
// Verify all messages added via Messenger service are accounted for.
$this->assertContains('Platypus', $messages['custom']);
$this->assertContains('Rhinoceros', $messages[MessengerInterface::TYPE_ERROR]);
$this->assertContains('Giraffe', $messages[MessengerInterface::TYPE_STATUS]);
$this->assertContains('Cheetah', $messages[MessengerInterface::TYPE_WARNING]);
// Verify repeat counts.
$this->assertCount(4, $messages['custom']);
$this->assertCount(4, $messages[MessengerInterface::TYPE_STATUS]);
$this->assertCount(4, $messages[MessengerInterface::TYPE_WARNING]);
$this->assertCount(4, $messages[MessengerInterface::TYPE_ERROR]);
}
}
@@ -0,0 +1,165 @@
<?php
namespace Drupal\KernelTests\Core\Messenger;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Render\Markup;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\KernelTests\KernelTestBase;
/**
* @group Messenger
* @coversDefaultClass \Drupal\Core\Messenger\Messenger
*/
class MessengerTest extends KernelTestBase {
/**
* The messenger under test.
*
* @var \Drupal\Core\Messenger\MessengerInterface
*/
protected $messenger;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->messenger = \Drupal::service('messenger');
}
/**
* @covers ::addStatus
* @covers ::deleteByType
* @covers ::messagesByType
*/
public function testRemoveSingleMessage() {
// Set two messages.
$this->messenger->addStatus('First message (removed).');
$this->messenger->addStatus(t('Second message with <em>markup!</em> (not removed).'));
$messages = $this->messenger->deleteByType(MessengerInterface::TYPE_STATUS);
// Remove the first.
unset($messages[0]);
// Re-add the second.
foreach ($messages as $message) {
$this->messenger->addStatus($message);
}
// Check we only have the second one.
$this->assertCount(1, $this->messenger->messagesByType(MessengerInterface::TYPE_STATUS));
$this->assertContains('Second message with <em>markup!</em> (not removed).', $this->messenger->deleteByType(MessengerInterface::TYPE_STATUS));
}
/**
* Tests we don't add duplicates.
*
* @covers ::all
* @covers ::addStatus
* @covers ::addWarning
* @covers ::addError
* @covers ::deleteByType
* @covers ::deleteAll
*/
public function testAddNoDuplicates() {
$this->messenger->addStatus('Non Duplicated status message');
$this->messenger->addStatus('Non Duplicated status message');
$this->assertCount(1, $this->messenger->messagesByType(MessengerInterface::TYPE_STATUS));
$this->messenger->addWarning('Non Duplicated warning message');
$this->messenger->addWarning('Non Duplicated warning message');
$this->assertCount(1, $this->messenger->messagesByType(MessengerInterface::TYPE_WARNING));
$this->messenger->addError('Non Duplicated error message');
$this->messenger->addError('Non Duplicated error message');
$messages = $this->messenger->messagesByType(MessengerInterface::TYPE_ERROR);
$this->assertCount(1, $messages);
// Check getting all messages.
$messages = $this->messenger->all();
$this->assertCount(3, $messages);
$this->assertArrayHasKey(MessengerInterface::TYPE_STATUS, $messages);
$this->assertArrayHasKey(MessengerInterface::TYPE_WARNING, $messages);
$this->assertArrayHasKey(MessengerInterface::TYPE_ERROR, $messages);
// Check deletion.
$this->messenger->deleteAll();
$this->assertCount(0, $this->messenger->messagesByType(MessengerInterface::TYPE_STATUS));
$this->assertCount(0, $this->messenger->messagesByType(MessengerInterface::TYPE_WARNING));
$this->assertCount(0, $this->messenger->messagesByType(MessengerInterface::TYPE_ERROR));
}
/**
* Tests we do add duplicates with repeat flag.
*
* @covers ::addStatus
* @covers ::addWarning
* @covers ::addError
* @covers ::deleteByType
*/
public function testAddWithDuplicates() {
$this->messenger->addStatus('Duplicated status message', TRUE);
$this->messenger->addStatus('Duplicated status message', TRUE);
$this->assertCount(2, $this->messenger->deleteByType(MessengerInterface::TYPE_STATUS));
$this->messenger->addWarning('Duplicated warning message', TRUE);
$this->messenger->addWarning('Duplicated warning message', TRUE);
$this->assertCount(2, $this->messenger->deleteByType(MessengerInterface::TYPE_WARNING));
$this->messenger->addError('Duplicated error message', TRUE);
$this->messenger->addError('Duplicated error message', TRUE);
$this->assertCount(2, $this->messenger->deleteByType(MessengerInterface::TYPE_ERROR));
}
/**
* Test adding markup.
*
* @covers ::addStatus
* @covers ::deleteByType
* @covers ::messagesByType
*/
public function testAddMarkup() {
// Add a Markup message.
$this->messenger->addStatus(Markup::create('Markup with <em>markup!</em>'));
// Test duplicate Markup messages.
$this->messenger->addStatus(Markup::create('Markup with <em>markup!</em>'));
$this->assertCount(1, $this->messenger->messagesByType(MessengerInterface::TYPE_STATUS));
// Ensure that multiple Markup messages work.
$this->messenger->addStatus(Markup::create('Markup2 with <em>markup!</em>'));
$this->assertCount(2, $this->messenger->deleteByType(MessengerInterface::TYPE_STATUS));
// Test mixing of types.
$this->messenger->addStatus(Markup::create('Non duplicate Markup / string.'));
$this->messenger->addStatus('Non duplicate Markup / string.');
$this->messenger->addStatus(Markup::create('Duplicate Markup / string.'), TRUE);
$this->messenger->addStatus('Duplicate Markup / string.', TRUE);
$this->assertCount(3, $this->messenger->deleteByType(MessengerInterface::TYPE_STATUS));
$this->messenger->deleteAll();
// Check translatable string is converted to Markup.
$this->messenger->addStatus(new TranslatableMarkup('Translatable message'));
$messages = $this->messenger->deleteByType(MessengerInterface::TYPE_STATUS);
$this->assertInstanceOf(Markup::class, $messages[0]);
}
}
@@ -0,0 +1,188 @@
<?php
namespace Drupal\KernelTests\Core\ParamConverter;
use Drupal\entity_test\Entity\EntityTest;
use Drupal\entity_test\Entity\EntityTestMulRev;
use Drupal\KernelTests\KernelTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
/**
* Tests the entity converter when the "load_latest_revision" flag is set.
*
* @group ParamConverter
* @coversDefaultClass \Drupal\Core\ParamConverter\EntityConverter
*/
class EntityConverterLatestRevisionTest extends KernelTestBase {
/**
* Modules to install.
*
* @var array
*/
public static $modules = [
'entity_test',
'user',
'language',
'system',
];
/**
* The entity converter service.
*
* @var \Drupal\Core\ParamConverter\EntityConverter
*/
protected $converter;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->installEntitySchema('user');
$this->installEntitySchema('entity_test_mulrev');
$this->installEntitySchema('entity_test');
$this->installConfig(['system', 'language']);
$this->converter = $this->container->get('paramconverter.entity');
ConfigurableLanguage::createFromLangcode('de')->save();
}
/**
* Tests with no matching entity.
*/
public function testNoEntity() {
$converted = $this->converter->convert(1, [
'load_latest_revision' => TRUE,
'type' => 'entity:entity_test_mulrev',
], 'foo', []);
$this->assertEquals(NULL, $converted);
}
/**
* Tests with no pending revision.
*/
public function testEntityNoPendingRevision() {
$entity = EntityTestMulRev::create();
$entity->save();
$converted = $this->converter->convert(1, [
'load_latest_revision' => TRUE,
'type' => 'entity:entity_test_mulrev',
], 'foo', []);
$this->assertEquals($entity->getLoadedRevisionId(), $converted->getLoadedRevisionId());
}
/**
* Tests with a pending revision.
*/
public function testEntityWithPendingRevision() {
$entity = EntityTestMulRev::create();
$entity->save();
$entity->isDefaultRevision(FALSE);
$entity->setNewRevision(TRUE);
$entity->save();
$converted = $this->converter->convert(1, [
'load_latest_revision' => TRUE,
'type' => 'entity:entity_test_mulrev',
], 'foo', []);
$this->assertEquals($entity->getLoadedRevisionId(), $converted->getLoadedRevisionId());
}
/**
* Tests with a translated pending revision.
*/
public function testWithTranslatedPendingRevision() {
// Enable translation for test entities.
$this->container->get('state')->set('entity_test.translation', TRUE);
$this->container->get('entity_type.bundle.info')->clearCachedBundles();
// Create a new English entity.
$entity = EntityTestMulRev::create();
$entity->save();
// Create a translated pending revision.
$entity_type_id = 'entity_test_mulrev';
/** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
$storage = $this->container->get('entity_type.manager')->getStorage($entity_type_id);
/** @var \Drupal\Core\Entity\ContentEntityInterface $translated_entity */
$translated_entity = $storage->createRevision($entity->addTranslation('de'), FALSE);
$translated_entity->save();
// Change the site language so the converters will attempt to load entities
// with language 'de'.
$this->config('system.site')->set('default_langcode', 'de')->save();
// The default loaded language is still 'en'.
EntityTestMulRev::load($entity->id());
$this->assertEquals('en', $entity->language()->getId());
// The converter will load the latest revision in the correct language.
$converted = $this->converter->convert(1, [
'load_latest_revision' => TRUE,
'type' => 'entity:entity_test_mulrev',
], 'foo', []);
$this->assertEquals('de', $converted->language()->getId());
$this->assertEquals($translated_entity->getLoadedRevisionId(), $converted->getLoadedRevisionId());
// Revert back to English as default language.
$this->config('system.site')->set('default_langcode', 'en')->save();
// The converter will load the latest revision in the correct language.
$converted = $this->converter->convert(1, [
'load_latest_revision' => TRUE,
'type' => 'entity:entity_test_mulrev',
], 'foo', []);
$this->assertEquals('en', $converted->language()->getId());
$this->assertEquals($entity->getLoadedRevisionId(), $converted->getLoadedRevisionId());
}
/**
* Tests that pending revisions are loaded only when needed.
*/
public function testOptimizedConvert() {
$entity = EntityTestMulRev::create();
$entity->save();
// Populate static cache for the current entity.
$entity = EntityTestMulRev::load($entity->id());
// Delete the base table entry for the current entity, however, since the
// storage will query the revision table to get the latest revision, the
// logic handling pending revisions will work correctly anyway.
/** @var \Drupal\Core\Database\Connection $database */
$database = $this->container->get('database');
$database->delete('entity_test_mulrev')
->condition('id', $entity->id())
->execute();
// If optimization works, converting a default revision should not trigger
// a storage load, thus making the following assertion pass.
$converted = $this->converter->convert(1, [
'load_latest_revision' => TRUE,
'type' => 'entity:entity_test_mulrev',
], 'foo', []);
$this->assertEquals($entity->getLoadedRevisionId(), $converted->getLoadedRevisionId());
}
/**
* Test the latest revision flag and non-revisionable entities.
*/
public function testConvertNonRevisionableEntityType() {
$entity = EntityTest::create();
$entity->save();
$converted = $this->converter->convert(1, [
'load_latest_revision' => TRUE,
'type' => 'entity:entity_test',
], 'foo', []);
$this->assertEquals($entity->id(), $converted->id());
}
}
@@ -63,7 +63,7 @@ class PathValidatorTest extends KernelTestBase {
$url = $pathValidator->getUrlIfValidWithoutAccessCheck($entity->toUrl()->toString(TRUE)->getGeneratedUrl());
$this->assertEquals($method, $requestContext->getMethod());
$this->assertInstanceOf(Url::class, $url);
$this->assertSame($url->getRouteParameters(), ['entity_test' => $entity->id()]);
$this->assertSame(['entity_test' => $entity->id()], $url->getRouteParameters());
}
}
@@ -18,6 +18,7 @@ use Drupal\Core\Routing\MatcherDumper;
use Drupal\Core\Routing\RouteProvider;
use Drupal\Core\State\State;
use Drupal\KernelTests\KernelTestBase;
use Drupal\language\Entity\ConfigurableLanguage;
use Drupal\Tests\Core\Routing\RoutingFixtures;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RequestStack;
@@ -36,7 +37,7 @@ class RouteProviderTest extends KernelTestBase {
/**
* Modules to enable.
*/
public static $modules = ['url_alter_test', 'system'];
public static $modules = ['url_alter_test', 'system', 'language'];
/**
* A collection of shared fixture data for tests.
@@ -544,7 +545,8 @@ class RouteProviderTest extends KernelTestBase {
*/
public function testRouteCaching() {
$connection = Database::getConnection();
$provider = new RouteProvider($connection, $this->state, $this->currentPath, $this->cache, $this->pathProcessor, $this->cacheTagsInvalidator, 'test_routes');
$language_manager = \Drupal::languageManager();
$provider = new RouteProvider($connection, $this->state, $this->currentPath, $this->cache, $this->pathProcessor, $this->cacheTagsInvalidator, 'test_routes', $language_manager);
$this->fixtures->createTables($connection);
@@ -558,7 +560,7 @@ class RouteProviderTest extends KernelTestBase {
$request = Request::create($path, 'GET');
$provider->getRouteCollectionForRequest($request);
$cache = $this->cache->get('route:/path/add/one:');
$cache = $this->cache->get('route:en:/path/add/one:');
$this->assertEqual('/path/add/one', $cache->data['path']);
$this->assertEqual([], $cache->data['query']);
$this->assertEqual(3, count($cache->data['routes']));
@@ -568,7 +570,7 @@ class RouteProviderTest extends KernelTestBase {
$request = Request::create($path, 'GET');
$provider->getRouteCollectionForRequest($request);
$cache = $this->cache->get('route:/path/add/one:foo=bar');
$cache = $this->cache->get('route:en:/path/add/one:foo=bar');
$this->assertEqual('/path/add/one', $cache->data['path']);
$this->assertEqual(['foo' => 'bar'], $cache->data['query']);
$this->assertEqual(3, count($cache->data['routes']));
@@ -578,7 +580,7 @@ class RouteProviderTest extends KernelTestBase {
$request = Request::create($path, 'GET');
$provider->getRouteCollectionForRequest($request);
$cache = $this->cache->get('route:/path/1/one:');
$cache = $this->cache->get('route:en:/path/1/one:');
$this->assertEqual('/path/1/one', $cache->data['path']);
$this->assertEqual([], $cache->data['query']);
$this->assertEqual(2, count($cache->data['routes']));
@@ -595,10 +597,25 @@ class RouteProviderTest extends KernelTestBase {
$request = Request::create($path, 'GET');
$provider->getRouteCollectionForRequest($request);
$cache = $this->cache->get('route:/path/add-one:');
$cache = $this->cache->get('route:en:/path/add-one:');
$this->assertEqual('/path/add/one', $cache->data['path']);
$this->assertEqual([], $cache->data['query']);
$this->assertEqual(3, count($cache->data['routes']));
// Test with a different current language by switching out the default
// language.
$swiss = ConfigurableLanguage::createFromLangcode('gsw-berne');
$language_manager->reset();
\Drupal::service('language.default')->set($swiss);
$path = '/path/add-one';
$request = Request::create($path, 'GET');
$provider->getRouteCollectionForRequest($request);
$cache = $this->cache->get('route:gsw-berne:/path/add-one:');
$this->assertEquals('/path/add/one', $cache->data['path']);
$this->assertEquals([], $cache->data['query']);
$this->assertEquals(3, count($cache->data['routes']));
}
/**
@@ -0,0 +1,139 @@
<?php
namespace Drupal\KernelTests\Core\TempStore;
use Drupal\Core\KeyValueStore\KeyValueExpirableFactory;
use Drupal\KernelTests\KernelTestBase;
use Drupal\Core\TempStore\SharedTempStoreFactory;
use Drupal\Core\Lock\DatabaseLockBackend;
use Drupal\Core\Database\Database;
/**
* Tests the temporary object storage system.
*
* @group TempStore
* @see \Drupal\Core\TempStore\SharedTempStore
*/
class TempStoreDatabaseTest extends KernelTestBase {
/**
* Modules to enable.
*
* @var array
*/
public static $modules = ['system'];
/**
* A key/value store factory.
*
* @var \Drupal\Core\TempStore\SharedTempStoreFactory
*/
protected $storeFactory;
/**
* The name of the key/value collection to set and retrieve.
*
* @var string
*/
protected $collection;
/**
* An array of random stdClass objects.
*
* @var array
*/
protected $objects = [];
protected function setUp() {
parent::setUp();
// Install system tables to test the key/value storage without installing a
// full Drupal environment.
$this->installSchema('system', ['key_value_expire']);
// Create several objects for testing.
for ($i = 0; $i <= 3; $i++) {
$this->objects[$i] = $this->randomObject();
}
}
/**
* Tests the SharedTempStore API.
*/
public function testSharedTempStore() {
// Create a key/value collection.
$factory = new SharedTempStoreFactory(new KeyValueExpirableFactory(\Drupal::getContainer()), new DatabaseLockBackend(Database::getConnection()), $this->container->get('request_stack'));
$collection = $this->randomMachineName();
// Create two mock users.
for ($i = 0; $i <= 1; $i++) {
$users[$i] = mt_rand(500, 5000000);
// Storing the SharedTempStore objects in a class member variable causes a
// fatal exception, because in that situation garbage collection is not
// triggered until the test class itself is destructed, after tearDown()
// has deleted the database tables. Store the objects locally instead.
$stores[$i] = $factory->get($collection, $users[$i]);
}
$key = $this->randomMachineName();
// Test that setIfNotExists() succeeds only the first time.
for ($i = 0; $i <= 1; $i++) {
// setIfNotExists() should be TRUE the first time (when $i is 0) and
// FALSE the second time (when $i is 1).
$this->assertEqual(!$i, $stores[0]->setIfNotExists($key, $this->objects[$i]));
$metadata = $stores[0]->getMetadata($key);
$this->assertEqual($users[0], $metadata->owner);
$this->assertIdenticalObject($this->objects[0], $stores[0]->get($key));
// Another user should get the same result.
$metadata = $stores[1]->getMetadata($key);
$this->assertEqual($users[0], $metadata->owner);
$this->assertIdenticalObject($this->objects[0], $stores[1]->get($key));
}
// Remove the item and try to set it again.
$stores[0]->delete($key);
$stores[0]->setIfNotExists($key, $this->objects[1]);
// This time it should succeed.
$this->assertIdenticalObject($this->objects[1], $stores[0]->get($key));
// This user can update the object.
$stores[0]->set($key, $this->objects[2]);
$this->assertIdenticalObject($this->objects[2], $stores[0]->get($key));
// The object is the same when another user loads it.
$this->assertIdenticalObject($this->objects[2], $stores[1]->get($key));
// This user should be allowed to get, update, delete.
$this->assertTrue($stores[0]->getIfOwner($key) instanceof \stdClass);
$this->assertTrue($stores[0]->setIfOwner($key, $this->objects[1]));
$this->assertTrue($stores[0]->deleteIfOwner($key));
// Another user can update the object and become the owner.
$stores[1]->set($key, $this->objects[3]);
$this->assertIdenticalObject($this->objects[3], $stores[0]->get($key));
$this->assertIdenticalObject($this->objects[3], $stores[1]->get($key));
$metadata = $stores[1]->getMetadata($key);
$this->assertEqual($users[1], $metadata->owner);
// The first user should be informed that the second now owns the data.
$metadata = $stores[0]->getMetadata($key);
$this->assertEqual($users[1], $metadata->owner);
// The first user should no longer be allowed to get, update, delete.
$this->assertNull($stores[0]->getIfOwner($key));
$this->assertFalse($stores[0]->setIfOwner($key, $this->objects[1]));
$this->assertFalse($stores[0]->deleteIfOwner($key));
// Now manually expire the item (this is not exposed by the API) and then
// assert it is no longer accessible.
db_update('key_value_expire')
->fields(['expire' => REQUEST_TIME - 1])
->condition('collection', "tempstore.shared.$collection")
->condition('name', $key)
->execute();
$this->assertFalse($stores[0]->get($key));
$this->assertFalse($stores[1]->get($key));
}
}
@@ -0,0 +1,33 @@
<?php
namespace Drupal\KernelTests\Core\Test;
use Drupal\KernelTests\KernelTestBase;
use Drupal\deprecation_test\Deprecation\FixtureDeprecatedClass;
/**
* Test how kernel tests interact with deprecation errors.
*
* @group Test
* @group legacy
*/
class PhpUnitBridgeTest extends KernelTestBase {
public static $modules = ['deprecation_test'];
/**
* @expectedDeprecation Drupal\deprecation_test\Deprecation\FixtureDeprecatedClass is deprecated.
*/
public function testDeprecatedClass() {
$deprecated = new FixtureDeprecatedClass();
$this->assertEquals('test', $deprecated->testFunction());
}
/**
* @expectedDeprecation This is the deprecation message for deprecation_test_function().
*/
public function testDeprecatedFunction() {
$this->assertEquals('known_return_value', \deprecation_test_function());
}
}
@@ -192,4 +192,23 @@ class RegistryTest extends KernelTestBase {
], $suggestions, 'Found expected page node suggestions.');
}
/**
* Tests theme-provided templates that are registered by modules.
*/
public function testThemeTemplatesRegisteredByModules() {
$theme_handler = \Drupal::service('theme_handler');
$theme_handler->install(['test_theme']);
$registry_theme = new Registry(\Drupal::root(), \Drupal::cache(), \Drupal::lock(), \Drupal::moduleHandler(), $theme_handler, \Drupal::service('theme.initialization'), 'test_theme');
$registry_theme->setThemeManager(\Drupal::theme());
$expected = [
'template_preprocess',
'template_preprocess_container',
'template_preprocess_theme_test_registered_by_module'
];
$registry = $registry_theme->get();
$this->assertEquals($expected, array_values($registry['theme_test_registered_by_module']['preprocess functions']));
}
}
@@ -24,7 +24,6 @@ class StableTemplateOverrideTest extends KernelTestBase {
*/
protected $templatesToSkip = [
'views-form-views-form',
'entity-moderation-form'
];
/**
@@ -57,7 +57,7 @@ class TwigMarkupInterfaceTest extends KernelTestBase {
'empty GeneratedLink' => ['', new GeneratedLink()],
'non-empty GeneratedLink' => ['<span><a hef="http://www.example.com">test</a></span>', (new GeneratedLink())->setGeneratedLink('<a hef="http://www.example.com">test</a>')],
// Test objects that do not implement \Countable.
'empty SafeMarkupTestMarkup' => ['<span></span>', SafeMarkupTestMarkup::create('')],
'empty SafeMarkupTestMarkup' => ['', SafeMarkupTestMarkup::create('')],
'non-empty SafeMarkupTestMarkup' => ['<span>test</span>', SafeMarkupTestMarkup::create('test')],
];
}
@@ -22,7 +22,7 @@ class UpdaterTest extends KernelTestBase {
* @see https://drupal.org/node/2409515
*/
public function testGetProjectTitleWithChild() {
// Get the project title from it's directory. If it can't find the title
// Get the project title from its directory. If it can't find the title
// it will choose the first project title in the directory.
$directory = \Drupal::root() . '/core/modules/system/tests/modules/module_handler_test_multiple';
$title = Updater::getProjectTitle($directory);
@@ -251,7 +251,7 @@ abstract class KernelTestBase extends TestCase implements ServiceProviderInterfa
* Should not be called by tests. Only visible for DrupalKernel integration
* tests.
*
* @see \Drupal\system\Tests\DrupalKernel\DrupalKernelTest
* @see \Drupal\KernelTests\Core\DrupalKernel\DrupalKernelTest
* @internal
*/
protected function bootEnvironment() {
@@ -137,6 +137,10 @@ class KernelTestBaseTest extends KernelTestBase {
$this->assertInstanceOf('Symfony\Component\HttpFoundation\Request', $new_request);
$this->assertSame($new_request, \Drupal::request());
$this->assertSame($request, $new_request);
// Ensure getting the router.route_provider does not trigger a deprecation
// message that errors.
$this->container->get('router.route_provider');
}
/**
+20 -3
View File
@@ -345,12 +345,12 @@ abstract class BrowserTestBase extends TestCase {
* When provided default Mink driver class can't be instantiated.
*/
protected function getDefaultDriverInstance() {
// Get default driver params from environment if availables.
if ($arg_json = getenv('MINK_DRIVER_ARGS')) {
// Get default driver params from environment if available.
if ($arg_json = $this->getMinkDriverArgs()) {
$this->minkDefaultDriverArgs = json_decode($arg_json, TRUE);
}
// Get and check default driver class from environment if availables.
// Get and check default driver class from environment if available.
if ($minkDriverClass = getenv('MINK_DRIVER_CLASS')) {
if (class_exists($minkDriverClass)) {
$this->minkDefaultDriverClass = $minkDriverClass;
@@ -395,6 +395,18 @@ abstract class BrowserTestBase extends TestCase {
}
}
/**
* Get the Mink driver args from an environment variable, if it is set. Can
* be overridden in a derived class so it is possible to use a different
* value for a subset of tests, e.g. the JavaScript tests.
*
* @return string|false
* The JSON-encoded argument string. False if it is not set.
*/
protected function getMinkDriverArgs() {
return getenv('MINK_DRIVER_ARGS');
}
/**
* Provides a Guzzle middleware handler to log every response received.
*
@@ -485,6 +497,11 @@ abstract class BrowserTestBase extends TestCase {
if ($disable_gc) {
gc_enable();
}
// Ensure that the test is not marked as risky because of no assertions. In
// PHPUnit 6 tests that only make assertions using $this->assertSession()
// can be marked as risky.
$this->addToAssertionCount(1);
}
/**
@@ -0,0 +1,66 @@
<?php
namespace Drupal\Tests\Component\Annotation;
use Drupal\Component\Annotation\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Component\FileCache\FileCacheFactory;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Drupal\Component\Annotation\Plugin\Discovery\AnnotatedClassDiscovery
* @group Annotation
*/
class AnnotatedClassDiscoveryCachedTest extends TestCase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Ensure FileCacheFactory::DISABLE_CACHE is *not* set, since we're testing
// integration with the file cache.
FileCacheFactory::setConfiguration([]);
// Ensure that FileCacheFactory has a prefix.
FileCacheFactory::setPrefix('prefix');
}
/**
* Test that getDefinitions() retrieves the file cache correctly.
*
* @covers ::getDefinitions
*/
public function testGetDefinitions() {
// Path to the classes which we'll discover and parse annotation.
$discovery_path = __DIR__ . '/Fixtures';
// File path that should be discovered within that directory.
$file_path = $discovery_path . '/PluginNamespace/DiscoveryTest1.php';
$discovery = new AnnotatedClassDiscovery(['com\example' => [$discovery_path]]);
$this->assertEquals([
'discovery_test_1' => [
'id' => 'discovery_test_1',
'class' => 'com\example\PluginNamespace\DiscoveryTest1',
],
], $discovery->getDefinitions());
// Gain access to the file cache so we can change it.
$ref_file_cache = new \ReflectionProperty($discovery, 'fileCache');
$ref_file_cache->setAccessible(TRUE);
/* @var $file_cache \Drupal\Component\FileCache\FileCacheInterface */
$file_cache = $ref_file_cache->getValue($discovery);
// The file cache is keyed by the file path, and we'll add some known
// content to test against.
$file_cache->set($file_path, [
'id' => 'wrong_id',
'content' => serialize(['an' => 'array']),
]);
// Now perform the same query and check for the cached results.
$this->assertEquals([
'wrong_id' => [
'an' => 'array',
],
], $discovery->getDefinitions());
}
}
@@ -0,0 +1,100 @@
<?php
namespace Drupal\Tests\Component\Annotation;
use Drupal\Component\Annotation\Plugin;
use Drupal\Component\Annotation\Plugin\Discovery\AnnotatedClassDiscovery;
use Drupal\Component\FileCache\FileCacheFactory;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Drupal\Component\Annotation\Plugin\Discovery\AnnotatedClassDiscovery
* @group Annotation
*/
class AnnotatedClassDiscoveryTest extends TestCase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Ensure the file cache is disabled.
FileCacheFactory::setConfiguration([FileCacheFactory::DISABLE_CACHE => TRUE]);
// Ensure that FileCacheFactory has a prefix.
FileCacheFactory::setPrefix('prefix');
}
/**
* @covers ::__construct
* @covers ::getPluginNamespaces
*/
public function testGetPluginNamespaces() {
$discovery = new AnnotatedClassDiscovery(['com/example' => [__DIR__]]);
$reflection = new \ReflectionMethod($discovery, 'getPluginNamespaces');
$reflection->setAccessible(TRUE);
$result = $reflection->invoke($discovery);
$this->assertEquals(['com/example' => [__DIR__]], $result);
}
/**
* @covers ::getDefinitions
* @covers ::prepareAnnotationDefinition
* @covers ::getAnnotationReader
*/
public function testGetDefinitions() {
$discovery = new AnnotatedClassDiscovery(['com\example' => [__DIR__ . '/Fixtures']]);
$this->assertEquals([
'discovery_test_1' => [
'id' => 'discovery_test_1',
'class' => 'com\example\PluginNamespace\DiscoveryTest1',
],
], $discovery->getDefinitions());
$custom_annotation_discovery = new AnnotatedClassDiscovery(['com\example' => [__DIR__ . '/Fixtures']], CustomPlugin::class, ['Drupal\Tests\Component\Annotation']);
$this->assertEquals([
'discovery_test_1' => [
'id' => 'discovery_test_1',
'class' => 'com\example\PluginNamespace\DiscoveryTest1',
'title' => 'Discovery test plugin',
],
], $custom_annotation_discovery->getDefinitions());
$empty_discovery = new AnnotatedClassDiscovery(['com\example' => [__DIR__ . '/Fixtures']], CustomPlugin2::class, ['Drupal\Tests\Component\Annotation']);
$this->assertEquals([], $empty_discovery->getDefinitions());
}
}
/**
* Custom plugin annotation.
*
* @Annotation
*/
class CustomPlugin extends Plugin {
/**
* The plugin ID.
*
* @var string
*/
public $id;
/**
* The plugin title.
*
* @var string
*
* @ingroup plugin_translatable
*/
public $title = '';
}
/**
* Custom plugin annotation.
*
* @Annotation
*/
class CustomPlugin2 extends Plugin {}
@@ -0,0 +1,55 @@
<?php
namespace Drupal\Tests\Component\Annotation;
use Drupal\Component\Annotation\AnnotationBase;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Drupal\Component\Annotation\AnnotationBase
* @group Annotation
*/
class AnnotationBaseTest extends TestCase {
/**
* @covers ::getProvider
* @covers ::setProvider
*/
public function testSetProvider() {
$plugin = new AnnotationBaseStub();
$plugin->setProvider('example');
$this->assertEquals('example', $plugin->getProvider());
}
/**
* @covers ::getId
*/
public function testGetId() {
$plugin = new AnnotationBaseStub();
// Doctrine sets the public prop directly.
$plugin->id = 'example';
$this->assertEquals('example', $plugin->getId());
}
/**
* @covers ::getClass
* @covers ::setClass
*/
public function testSetClass() {
$plugin = new AnnotationBaseStub();
$plugin->setClass('example');
$this->assertEquals('example', $plugin->getClass());
}
}
/**
* {@inheritdoc}
*/
class AnnotationBaseStub extends AnnotationBase {
/**
* {@inheritdoc}
*/
public function get() {}
}
@@ -0,0 +1,16 @@
<?php
namespace com\example\PluginNamespace;
/**
* Provides a custom test plugin.
*
* @Plugin(
* id = "discovery_test_1"
* )
* @CustomPlugin(
* id = "discovery_test_1",
* title = "Discovery test plugin"
* )
*/
class DiscoveryTest1 {}
@@ -0,0 +1,2 @@
# This should not be loaded by our annotated class discovery.
id:discovery_test_2
@@ -0,0 +1,24 @@
<?php
namespace Drupal\Tests\Component\Annotation;
use Drupal\Component\Annotation\Reflection\MockFileFinder;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Drupal\Component\Annotation\Reflection\MockFileFinder
* @group Annotation
*/
class MockFileFinderTest extends TestCase {
/**
* @covers ::create
* @covers ::findFile
*/
public function testFindFile() {
$tmp = MockFileFinder::create('testfilename.txt');
$this->assertEquals('testfilename.txt', $tmp->findFile('n/a'));
$this->assertEquals('testfilename.txt', $tmp->findFile('someclass'));
}
}
@@ -35,6 +35,9 @@ class AnnotationBridgeDecoratorTest extends TestCase {
}
/**
* {@inheritdoc}
*/
class TestAnnotation extends Plugin {
/**
@@ -45,12 +48,17 @@ class TestAnnotation extends Plugin {
}
}
/**
* {@inheritdoc}
*/
class ObjectDefinition extends PluginDefinition {
/**
* ObjectDefinition constructor.
*
* @param array $definition
* An array of definition values.
*/
public function __construct(array $definition) {
foreach ($definition as $property => $value) {
@@ -0,0 +1,55 @@
<?php
namespace Drupal\Tests\Component\Annotation;
use Drupal\Component\Annotation\PluginID;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Drupal\Component\Annotation\PluginId
* @group Annotation
*/
class PluginIdTest extends TestCase {
/**
* @covers ::get
*/
public function testGet() {
// Assert plugin starts empty regardless of constructor.
$plugin = new PluginID([
'foo' => 'bar',
'biz' => [
'baz' => 'boom',
],
'nestedAnnotation' => new PluginID([
'foo' => 'bar',
]),
'value' => 'biz',
]);
$this->assertEquals([
'id' => NULL,
'class' => NULL,
'provider' => NULL,
], $plugin->get());
// Set values and ensure we can retrieve them.
$plugin->value = 'foo';
$plugin->setClass('bar');
$plugin->setProvider('baz');
$this->assertEquals([
'id' => 'foo',
'class' => 'bar',
'provider' => 'baz',
], $plugin->get());
}
/**
* @covers ::getId
*/
public function testGetId() {
$plugin = new PluginID([]);
$plugin->value = 'example';
$this->assertEquals('example', $plugin->getId());
}
}
@@ -0,0 +1,98 @@
<?php
namespace Drupal\Tests\Component\Annotation;
use Drupal\Component\Annotation\Plugin;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Drupal\Component\Annotation\Plugin
* @group Annotation
*/
class PluginTest extends TestCase {
/**
* @covers ::__construct
* @covers ::parse
* @covers ::get
*/
public function testGet() {
// Assert all values are accepted through constructor and default value is
// used for non existent but defined property.
$plugin = new PluginStub([
'foo' => 'bar',
'biz' => [
'baz' => 'boom',
],
'nestedAnnotation' => new Plugin([
'foo' => 'bar',
]),
]);
$this->assertEquals([
// This property wasn't in our definition but is defined as a property on
// our plugin class.
'defaultProperty' => 'testvalue',
'foo' => 'bar',
'biz' => [
'baz' => 'boom',
],
'nestedAnnotation' => [
'foo' => 'bar',
],
], $plugin->get());
// Without default properties, we get a completely empty plugin definition.
$plugin = new Plugin([]);
$this->assertEquals([], $plugin->get());
}
/**
* @covers ::getProvider
*/
public function testGetProvider() {
$plugin = new Plugin(['provider' => 'example']);
$this->assertEquals('example', $plugin->getProvider());
}
/**
* @covers ::setProvider
*/
public function testSetProvider() {
$plugin = new Plugin([]);
$plugin->setProvider('example');
$this->assertEquals('example', $plugin->getProvider());
}
/**
* @covers ::getId
*/
public function testGetId() {
$plugin = new Plugin(['id' => 'example']);
$this->assertEquals('example', $plugin->getId());
}
/**
* @covers ::getClass
*/
public function testGetClass() {
$plugin = new Plugin(['class' => 'example']);
$this->assertEquals('example', $plugin->getClass());
}
/**
* @covers ::setClass
*/
public function testSetClass() {
$plugin = new Plugin([]);
$plugin->setClass('example');
$this->assertEquals('example', $plugin->getClass());
}
}
/**
* {@inheritdoc}
*/
class PluginStub extends Plugin {
protected $defaultProperty = 'testvalue';
}
@@ -87,7 +87,13 @@ class DateTimePlusTest extends TestCase {
* @dataProvider providerTestInvalidDateDiff
*/
public function testInvalidDateDiff($input1, $input2, $absolute) {
$this->setExpectedException(\BadMethodCallException::class, 'Method Drupal\Component\Datetime\DateTimePlus::diff expects parameter 1 to be a \DateTime or \Drupal\Component\Datetime\DateTimePlus object');
if (method_exists($this, 'expectException')) {
$this->expectException(\BadMethodCallException::class);
$this->expectExceptionMessage('Method Drupal\Component\Datetime\DateTimePlus::diff expects parameter 1 to be a \DateTime or \Drupal\Component\Datetime\DateTimePlus object');
}
else {
$this->setExpectedException(\BadMethodCallException::class, 'Method Drupal\Component\Datetime\DateTimePlus::diff expects parameter 1 to be a \DateTime or \Drupal\Component\Datetime\DateTimePlus object');
}
$interval = $input1->diff($input2, $absolute);
}
@@ -104,7 +110,12 @@ class DateTimePlusTest extends TestCase {
* @dataProvider providerTestInvalidDateArrays
*/
public function testInvalidDateArrays($input, $timezone, $class) {
$this->setExpectedException($class);
if (method_exists($this, 'expectException')) {
$this->expectException($class);
}
else {
$this->setExpectedException($class);
}
$this->assertInstanceOf(
'\Drupal\Component\DateTimePlus',
DateTimePlus::createFromArray($input, $timezone)
@@ -242,7 +253,12 @@ class DateTimePlusTest extends TestCase {
* @dataProvider providerTestInvalidDates
*/
public function testInvalidDates($input, $timezone, $format, $message, $class) {
$this->setExpectedException($class);
if (method_exists($this, 'expectException')) {
$this->expectException($class);
}
else {
$this->setExpectedException($class);
}
DateTimePlus::createFromFormat($format, $input, $timezone);
}
@@ -800,10 +816,27 @@ class DateTimePlusTest extends TestCase {
// Parse the same date with ['validate_format' => TRUE] and make sure we
// get the expected exception.
$this->setExpectedException(\UnexpectedValueException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(\UnexpectedValueException::class);
}
else {
$this->setExpectedException(\UnexpectedValueException::class);
}
$date = DateTimePlus::createFromFormat('Y-m-d H:i:s', '11-03-31 17:44:00', 'UTC', ['validate_format' => TRUE]);
}
/**
* Tests setting the default time for date-only objects.
*/
public function testDefaultDateTime() {
$utc = new \DateTimeZone('UTC');
$date = DateTimePlus::createFromFormat('Y-m-d H:i:s', '2017-05-23 22:58:00', $utc);
$this->assertEquals('22:58:00', $date->format('H:i:s'));
$date->setDefaultDateTime();
$this->assertEquals('12:00:00', $date->format('H:i:s'));
}
/**
* Tests that object methods are chainable.
*
@@ -847,7 +880,13 @@ class DateTimePlusTest extends TestCase {
* @covers ::__call
*/
public function testChainableNonCallable() {
$this->setExpectedException(\BadMethodCallException::class, 'Call to undefined method Drupal\Component\Datetime\DateTimePlus::nonexistent()');
if (method_exists($this, 'expectException')) {
$this->expectException(\BadMethodCallException::class);
$this->expectExceptionMessage('Call to undefined method Drupal\Component\Datetime\DateTimePlus::nonexistent()');
}
else {
$this->setExpectedException(\BadMethodCallException::class, 'Call to undefined method Drupal\Component\Datetime\DateTimePlus::nonexistent()');
}
$date = new DateTimePlus('now', 'Australia/Sydney');
$date->setTimezone(new \DateTimeZone('America/New_York'))->nonexistent();
}
@@ -37,8 +37,7 @@ class TimeTest extends TestCase {
protected function setUp() {
parent::setUp();
$this->requestStack = $this->getMock('Symfony\Component\HttpFoundation\RequestStack');
$this->requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->getMock();
$this->time = new Time($this->requestStack);
}
@@ -70,7 +70,12 @@ class ContainerTest extends TestCase {
public function testConstruct() {
$container_definition = $this->getMockContainerDefinition();
$container_definition['machine_format'] = !$this->machineFormat;
$this->setExpectedException(InvalidArgumentException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(InvalidArgumentException::class);
}
else {
$this->setExpectedException(InvalidArgumentException::class);
}
$container = new $this->containerClass($container_definition);
}
@@ -93,7 +98,12 @@ class ContainerTest extends TestCase {
* @covers ::getAlternatives
*/
public function testGetParameterIfNotFound() {
$this->setExpectedException(ParameterNotFoundException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(ParameterNotFoundException::class);
}
else {
$this->setExpectedException(ParameterNotFoundException::class);
}
$this->container->getParameter('parameter_that_does_not_exist');
}
@@ -103,7 +113,12 @@ class ContainerTest extends TestCase {
* @covers ::getParameter
*/
public function testGetParameterIfNotFoundBecauseNull() {
$this->setExpectedException(ParameterNotFoundException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(ParameterNotFoundException::class);
}
else {
$this->setExpectedException(ParameterNotFoundException::class);
}
$this->container->getParameter(NULL);
}
@@ -137,7 +152,12 @@ class ContainerTest extends TestCase {
*/
public function testSetParameterWithFrozenContainer() {
$this->container = new $this->containerClass($this->containerDefinition);
$this->setExpectedException(LogicException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(LogicException::class);
}
else {
$this->setExpectedException(LogicException::class);
}
$this->container->setParameter('some_config', 'new_value');
}
@@ -242,7 +262,12 @@ class ContainerTest extends TestCase {
* @covers ::createService
*/
public function testGetForCircularServices() {
$this->setExpectedException(ServiceCircularReferenceException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(ServiceCircularReferenceException::class);
}
else {
$this->setExpectedException(ServiceCircularReferenceException::class);
}
$this->container->get('circular_dependency');
}
@@ -255,7 +280,12 @@ class ContainerTest extends TestCase {
* @covers ::getServiceAlternatives
*/
public function testGetForNonExistantService() {
$this->setExpectedException(ServiceNotFoundException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(ServiceNotFoundException::class);
}
else {
$this->setExpectedException(ServiceNotFoundException::class);
}
$this->container->get('service_not_exists');
}
@@ -304,7 +334,12 @@ class ContainerTest extends TestCase {
// Reset the service.
$this->container->set('service_parameter_not_exists', NULL);
$this->setExpectedException(InvalidArgumentException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(InvalidArgumentException::class);
}
else {
$this->setExpectedException(InvalidArgumentException::class);
}
$this->container->get('service_parameter_not_exists');
}
@@ -316,7 +351,12 @@ class ContainerTest extends TestCase {
* @covers ::resolveServicesAndParameters
*/
public function testGetForNonExistantParameterDependencyWithException() {
$this->setExpectedException(InvalidArgumentException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(InvalidArgumentException::class);
}
else {
$this->setExpectedException(InvalidArgumentException::class);
}
$this->container->get('service_parameter_not_exists');
}
@@ -341,7 +381,12 @@ class ContainerTest extends TestCase {
* @covers ::getAlternatives
*/
public function testGetForNonExistantServiceDependencyWithException() {
$this->setExpectedException(ServiceNotFoundException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(ServiceNotFoundException::class);
}
else {
$this->setExpectedException(ServiceNotFoundException::class);
}
$this->container->get('service_dependency_not_exists');
}
@@ -361,7 +406,12 @@ class ContainerTest extends TestCase {
* @covers ::createService
*/
public function testGetForNonExistantNULLService() {
$this->setExpectedException(ServiceNotFoundException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(ServiceNotFoundException::class);
}
else {
$this->setExpectedException(ServiceNotFoundException::class);
}
$this->container->get(NULL);
}
@@ -387,7 +437,12 @@ class ContainerTest extends TestCase {
*/
public function testGetForNonExistantServiceWithExceptionOnSecondCall() {
$this->assertNull($this->container->get('service_not_exists', ContainerInterface::NULL_ON_INVALID_REFERENCE), 'Not found service does nto throw exception.');
$this->setExpectedException(ServiceNotFoundException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(ServiceNotFoundException::class);
}
else {
$this->setExpectedException(ServiceNotFoundException::class);
}
$this->container->get('service_not_exists');
}
@@ -423,7 +478,12 @@ class ContainerTest extends TestCase {
* @covers ::createService
*/
public function testGetForSyntheticServiceWithException() {
$this->setExpectedException(RuntimeException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(RuntimeException::class);
}
else {
$this->setExpectedException(RuntimeException::class);
}
$this->container->get('synthetic');
}
@@ -462,7 +522,12 @@ class ContainerTest extends TestCase {
* @covers ::createService
*/
public function testGetForWrongFactory() {
$this->setExpectedException(RuntimeException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(RuntimeException::class);
}
else {
$this->setExpectedException(RuntimeException::class);
}
$this->container->get('wrong_factory');
}
@@ -500,7 +565,12 @@ class ContainerTest extends TestCase {
* @covers ::createService
*/
public function testGetForConfiguratorWithException() {
$this->setExpectedException(InvalidArgumentException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(InvalidArgumentException::class);
}
else {
$this->setExpectedException(InvalidArgumentException::class);
}
$this->container->get('configurable_service_exception');
}
@@ -598,7 +668,12 @@ class ContainerTest extends TestCase {
* @covers ::resolveServicesAndParameters
*/
public function testResolveServicesAndParametersForInvalidArgument() {
$this->setExpectedException(InvalidArgumentException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(InvalidArgumentException::class);
}
else {
$this->setExpectedException(InvalidArgumentException::class);
}
$this->container->get('invalid_argument_service');
}
@@ -612,7 +687,12 @@ class ContainerTest extends TestCase {
public function testResolveServicesAndParametersForInvalidArguments() {
// In case the machine-optimized format is not used, we need to simulate the
// test failure.
$this->setExpectedException(InvalidArgumentException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(InvalidArgumentException::class);
}
else {
$this->setExpectedException(InvalidArgumentException::class);
}
if (!$this->machineFormat) {
throw new InvalidArgumentException('Simulating the test failure.');
}
@@ -68,7 +68,7 @@ namespace Drupal\Tests\Component\DependencyInjection\Dumper {
$this->containerBuilder->getAliases()->willReturn([]);
$this->containerBuilder->getParameterBag()->willReturn(new ParameterBag());
$this->containerBuilder->getDefinitions()->willReturn(NULL);
$this->containerBuilder->isFrozen()->willReturn(TRUE);
$this->containerBuilder->isCompiled()->willReturn(TRUE);
$definition = [];
$definition['aliases'] = [];
@@ -147,7 +147,7 @@ namespace Drupal\Tests\Component\DependencyInjection\Dumper {
$parameter_bag = new ParameterBag($parameters);
$this->containerBuilder->getParameterBag()->willReturn($parameter_bag);
$this->containerBuilder->isFrozen()->willReturn($is_frozen);
$this->containerBuilder->isCompiled()->willReturn($is_frozen);
if (isset($parameters['reference'])) {
$definition = new Definition('\stdClass');
@@ -545,7 +545,12 @@ namespace Drupal\Tests\Component\DependencyInjection\Dumper {
$services['bar'] = $bar_definition;
$this->containerBuilder->getDefinitions()->willReturn($services);
$this->setExpectedException(InvalidArgumentException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(InvalidArgumentException::class);
}
else {
$this->setExpectedException(InvalidArgumentException::class);
}
$this->dumper->getArray();
}
@@ -562,7 +567,12 @@ namespace Drupal\Tests\Component\DependencyInjection\Dumper {
$services['bar'] = $bar_definition;
$this->containerBuilder->getDefinitions()->willReturn($services);
$this->setExpectedException(RuntimeException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(RuntimeException::class);
}
else {
$this->setExpectedException(RuntimeException::class);
}
$this->dumper->getArray();
}
@@ -579,7 +589,12 @@ namespace Drupal\Tests\Component\DependencyInjection\Dumper {
$services['bar'] = $bar_definition;
$this->containerBuilder->getDefinitions()->willReturn($services);
$this->setExpectedException(RuntimeException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(RuntimeException::class);
}
else {
$this->setExpectedException(RuntimeException::class);
}
$this->dumper->getArray();
}
@@ -596,7 +611,12 @@ namespace Drupal\Tests\Component\DependencyInjection\Dumper {
$services['bar'] = $bar_definition;
$this->containerBuilder->getDefinitions()->willReturn($services);
$this->setExpectedException(RuntimeException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(RuntimeException::class);
}
else {
$this->setExpectedException(RuntimeException::class);
}
$this->dumper->getArray();
}
@@ -86,4 +86,21 @@ class DiffEngineTest extends TestCase {
}
}
/**
* Tests that two files can be successfully diffed.
*
* @covers ::diff
*/
public function testDiffInfiniteLoop() {
$from = explode("\n", file_get_contents(__DIR__ . '/fixtures/file1.txt'));
$to = explode("\n", file_get_contents(__DIR__ . '/fixtures/file2.txt'));
$diff_engine = new DiffEngine();
$diff = $diff_engine->diff($from, $to);
$this->assertCount(4, $diff);
$this->assertEquals($diff[0], new DiffOpDelete([' - image.style.max_650x650']));
$this->assertEquals($diff[1], new DiffOpCopy([' - image.style.max_325x325']));
$this->assertEquals($diff[2], new DiffOpAdd([' - image.style.max_650x650', '_core:', ' default_config_hash: 3mjM9p-kQ8syzH7N8T0L9OnCJDSPvHAZoi3q6jcXJKM']));
$this->assertEquals($diff[3], new DiffOpCopy(['fallback_image_style: max_325x325', '']));
}
}
@@ -4,6 +4,7 @@ namespace Drupal\Tests\Component\Diff\Engine;
use Drupal\Component\Diff\Engine\DiffOp;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Error\Error;
/**
* Test DiffOp base class.
@@ -24,7 +25,12 @@ class DiffOpTest extends TestCase {
* @covers ::reverse
*/
public function testReverse() {
$this->setExpectedException(\PHPUnit_Framework_Error::class);
if (method_exists($this, 'expectException')) {
$this->expectException(Error::class);
}
else {
$this->setExpectedException(\PHPUnit_Framework_Error::class);
}
$op = new DiffOp();
$result = $op->reverse();
}
@@ -0,0 +1,3 @@
- image.style.max_650x650
- image.style.max_325x325
fallback_image_style: max_325x325
@@ -0,0 +1,5 @@
- image.style.max_325x325
- image.style.max_650x650
_core:
default_config_hash: 3mjM9p-kQ8syzH7N8T0L9OnCJDSPvHAZoi3q6jcXJKM
fallback_image_style: max_325x325
@@ -124,7 +124,13 @@ class YamlDirectoryDiscoveryTest extends TestCase {
* @covers ::getIdentifier
*/
public function testDiscoveryNoIdException() {
$this->setExpectedException(DiscoveryException::class, 'The vfs://modules/test_1/item_1.test.yml contains no data in the identifier key \'id\'');
if (method_exists($this, 'expectException')) {
$this->expectException(DiscoveryException::class);
$this->expectExceptionMessage('The vfs://modules/test_1/item_1.test.yml contains no data in the identifier key \'id\'');
}
else {
$this->setExpectedException(DiscoveryException::class, 'The vfs://modules/test_1/item_1.test.yml contains no data in the identifier key \'id\'');
}
vfsStream::setup('modules', NULL, [
'test_1' => [
'item_1.test.yml' => "",
@@ -144,7 +150,13 @@ class YamlDirectoryDiscoveryTest extends TestCase {
* @covers ::findAll
*/
public function testDiscoveryInvalidYamlException() {
$this->setExpectedException(DiscoveryException::class, 'The vfs://modules/test_1/item_1.test.yml contains invalid YAML');
if (method_exists($this, 'expectException')) {
$this->expectException(DiscoveryException::class);
$this->expectExceptionMessage('The vfs://modules/test_1/item_1.test.yml contains invalid YAML');
}
else {
$this->setExpectedException(DiscoveryException::class, 'The vfs://modules/test_1/item_1.test.yml contains invalid YAML');
}
vfsStream::setup('modules', NULL, [
'test_1' => [
'item_1.test.yml' => "id: invalid\nfoo : [bar}",
@@ -32,6 +32,34 @@ class DrupalComponentTest extends TestCase {
}
}
/**
* Tests LICENSE.txt is present and has the correct content.
*
* @param $component_path
* The path to the component.
* @dataProvider \Drupal\Tests\Component\DrupalComponentTest::getComponents
*/
public function testComponentLicence($component_path) {
$this->assertFileExists($component_path . DIRECTORY_SEPARATOR . 'LICENSE.txt');
$this->assertSame('e84dac1d9fbb5a4a69e38654ce644cea769aa76b', hash_file('sha1', $component_path . DIRECTORY_SEPARATOR . 'LICENSE.txt'));
}
/**
* Data provider.
*
* @return array
*/
public function getComponents() {
$root_component_path = dirname(substr(__DIR__, 0, -strlen(__NAMESPACE__))) . '/lib/Drupal/Component';
$component_paths = [];
foreach (new \DirectoryIterator($root_component_path) as $file) {
if ($file->isDir() && !$file->isDot()) {
$component_paths[$file->getBasename()] = [$file->getPathname()];
}
}
return $component_paths;
}
/**
* Searches a directory recursively for PHP classes.
*
@@ -38,7 +38,7 @@ class ContainerAwareEventDispatcherTest extends SymfonyContainerAwareEventDispat
// When passing in callables exclusively as listeners into the event
// dispatcher constructor, the event dispatcher must not attempt to
// resolve any services.
$container = $this->getMock(ContainerInterface::class);
$container = $this->getMockBuilder(ContainerInterface::class)->getMock();
$container->expects($this->never())->method($this->anything());
$firstListener = new CallableClass();
@@ -73,7 +73,7 @@ class ContainerAwareEventDispatcherTest extends SymfonyContainerAwareEventDispat
// When passing in callables exclusively as listeners into the event
// dispatcher constructor, the event dispatcher must not attempt to
// resolve any services.
$container = $this->getMock(ContainerInterface::class);
$container = $this->getMockBuilder(ContainerInterface::class)->getMock();
$container->expects($this->never())->method($this->anything());
$firstListener = new CallableClass();
@@ -193,4 +193,59 @@ class ContainerAwareEventDispatcherTest extends SymfonyContainerAwareEventDispat
$this->assertSame(5, $actualPriority);
}
/**
* @expectedDeprecation The Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.
* @group legacy
*/
public function testAddAListenerService() {
parent::testAddAListenerService();
}
/**
* @expectedDeprecation The Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.
* @group legacy
*/
public function testPreventDuplicateListenerService() {
parent::testPreventDuplicateListenerService();
}
/**
* @expectedDeprecation The Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.
* @group legacy
*/
public function testAddASubscriberService() {
parent::testAddASubscriberService();
}
/**
* @expectedDeprecation The Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.
* @group legacy
*/
public function testHasListenersOnLazyLoad() {
parent::testHasListenersOnLazyLoad();
}
/**
* @expectedDeprecation The Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.
* @group legacy
*/
public function testGetListenersOnLazyLoad() {
parent::testGetListenersOnLazyLoad();
}
/**
* @expectedDeprecation The Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.
* @group legacy
*/
public function testRemoveAfterDispatch() {
parent::testRemoveAfterDispatch();
}
/**
* @expectedDeprecation The Symfony\Component\EventDispatcher\ContainerAwareEventDispatcher class is deprecated since Symfony 3.3 and will be removed in 4.0. Use EventDispatcher with closure factories instead.
* @group legacy
*/
public function testRemoveBeforeDispatch() {
parent::testRemoveBeforeDispatch();
}
}
@@ -59,7 +59,13 @@ class FileCacheFactoryTest extends TestCase {
*/
public function testGetNoPrefix() {
FileCacheFactory::setPrefix(NULL);
$this->setExpectedException(\InvalidArgumentException::class, 'Required prefix configuration is missing');
if (method_exists($this, 'expectException')) {
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Required prefix configuration is missing');
}
else {
$this->setExpectedException(\InvalidArgumentException::class, 'Required prefix configuration is missing');
}
FileCacheFactory::get('test_foo_settings', []);
}
@@ -0,0 +1,118 @@
<?php
namespace Drupal\Tests\Component\Gettext;
use Drupal\Component\Gettext\PoItem;
use Drupal\Component\Gettext\PoStreamWriter;
use org\bovigo\vfs\vfsStream;
use org\bovigo\vfs\vfsStreamFile;
use PHPUnit\Framework\TestCase;
/**
* @coversDefaultClass \Drupal\Component\Gettext\PoStreamWriter
* @group Gettext
*/
class PoStreamWriterTest extends TestCase {
/**
* The PO writer object under test.
*
* @var \Drupal\Component\Gettext\PoStreamWriter
*/
protected $poWriter;
/**
* The mock po file.
*
* @var \org\bovigo\vfs\vfsStreamFile
*/
protected $poFile;
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
$this->poWriter = new PoStreamWriter();
$root = vfsStream::setup();
$this->poFile = new vfsStreamFile('powriter.po');
$root->addChild($this->poFile);
}
/**
* @covers ::getURI
*/
public function testGetUriException() {
if (method_exists($this, 'expectException')) {
$this->expectException(\Exception::class, 'No URI set.');
}
else {
$this->setExpectedException(\Exception::class, 'No URI set.');
}
$this->poWriter->getURI();
}
/**
* @covers ::writeItem
* @dataProvider providerWriteData
*/
public function testWriteItem($poContent, $expected, $long) {
if ($long) {
if (method_exists($this, 'expectException')) {
$this->expectException(\Exception::class, 'Unable to write data:');
}
else {
$this->setExpectedException(\Exception::class, 'Unable to write data:');
}
}
// Limit the file system quota to make the write fail on long strings.
vfsStream::setQuota(10);
$this->poWriter->setURI($this->poFile->url());
$this->poWriter->open();
$poItem = $this->prophesize(PoItem::class);
$poItem->__toString()->willReturn($poContent);
$this->poWriter->writeItem($poItem->reveal());
$this->poWriter->close();
$this->assertEquals(file_get_contents($this->poFile->url()), $expected);
}
/**
* @return array
* - Content to write.
* - Written content.
* - Content longer than 10 bytes.
*/
public function providerWriteData() {
return [
['', '', FALSE],
["\r\n", "\r\n", FALSE],
['write this if you can', 'write this', TRUE],
['éáíó>&', 'éáíó>&', FALSE],
['éáíó>&<', 'éáíó>&', TRUE],
['中文 890', '中文 890', FALSE],
['中文 89012', '中文 890', TRUE],
];
}
/**
* @covers ::close
*/
public function testCloseException() {
if (method_exists($this, 'expectException')) {
$this->expectException(\Exception::class, 'Cannot close stream that is not open.');
}
else {
$this->setExpectedException(\Exception::class, 'Cannot close stream that is not open.');
}
$this->poWriter->close();
}
}
@@ -63,14 +63,14 @@ class FileStorageReadOnlyTest extends PhpStorageTestBase {
// Write out a PHP file and ensure it's successfully loaded.
$code = "<?php\n\$GLOBALS[$random] = TRUE;";
$success = $php->save($name, $code);
$this->assertSame($success, TRUE);
$this->assertSame(TRUE, $success);
$php_read = new FileReadOnlyStorage($this->readonlyStorage);
$php_read->load($name);
$this->assertTrue($GLOBALS[$random]);
// If the file was successfully loaded, it must also exist, but ensure the
// exists() method returns that correctly.
$this->assertSame($php_read->exists($name), TRUE);
$this->assertSame(TRUE, $php_read->exists($name));
// Saving and deleting should always fail.
$this->assertFalse($php_read->save($name, $code));
$this->assertFalse($php_read->delete($name));
@@ -5,7 +5,7 @@ namespace Drupal\Tests\Component\PhpStorage;
use Drupal\Component\PhpStorage\FileStorage;
use Drupal\Component\Utility\Random;
use org\bovigo\vfs\vfsStreamDirectory;
use PHPUnit_Framework_Error_Warning;
use PHPUnit\Framework\Error\Warning;
/**
* @coversDefaultClass \Drupal\Component\PhpStorage\FileStorage
@@ -99,7 +99,13 @@ class FileStorageTest extends PhpStorageTestBase {
'bin' => 'test',
]);
$code = "<?php\n echo 'here';";
$this->setExpectedException(PHPUnit_Framework_Error_Warning::class, 'mkdir(): Permission Denied');
if (method_exists($this, 'expectException')) {
$this->expectException(Warning::class);
$this->expectExceptionMessage('mkdir(): Permission Denied');
}
else {
$this->setExpectedException(\PHPUnit_Framework_Error_Warning::class, 'mkdir(): Permission Denied');
}
$storage->save('subdirectory/foo.php', $code);
}
@@ -89,8 +89,8 @@ abstract class MTimeProtectedFileStorageBase extends PhpStorageTestBase {
// minimal permissions. fileperms() can return high bits unrelated to
// permissions, so mask with 0777.
$this->assertTrue(file_exists($expected_filename));
$this->assertSame(fileperms($expected_filename) & 0777, 0444);
$this->assertSame(fileperms($expected_directory) & 0777, 0777);
$this->assertSame(0444, fileperms($expected_filename) & 0777);
$this->assertSame(0777, fileperms($expected_directory) & 0777);
// Ensure the root directory for the bin has a .htaccess file denying web
// access.
@@ -121,9 +121,9 @@ abstract class MTimeProtectedFileStorageBase extends PhpStorageTestBase {
chmod($expected_filename, 0400);
chmod($expected_directory, 0100);
$this->assertSame(file_get_contents($expected_filename), $untrusted_code);
$this->assertSame($php->exists($name), $this->expected[$i]);
$this->assertSame($php->load($name), $this->expected[$i]);
$this->assertSame($GLOBALS['hacked'], $this->expected[$i]);
$this->assertSame($this->expected[$i], $php->exists($name));
$this->assertSame($this->expected[$i], $php->load($name));
$this->assertSame($this->expected[$i], $GLOBALS['hacked']);
}
unset($GLOBALS['hacked']);
}
@@ -71,10 +71,16 @@ class ContextTest extends TestCase {
// Set expectation for exception.
if ($is_required) {
$this->setExpectedException(
'Drupal\Component\Plugin\Exception\ContextException',
sprintf("The %s context is required and not present.", $data_type)
);
if (method_exists($this, 'expectException')) {
$this->expectException('Drupal\Component\Plugin\Exception\ContextException');
$this->expectExceptionMessage(sprintf("The %s context is required and not present.", $data_type));
}
else {
$this->setExpectedException(
'Drupal\Component\Plugin\Exception\ContextException',
sprintf("The %s context is required and not present.", $data_type)
);
}
}
// Exercise getContextValue().
@@ -5,9 +5,9 @@ namespace Drupal\Tests\Component\Plugin;
use Drupal\Component\Plugin\Definition\PluginDefinitionInterface;
use Drupal\Component\Plugin\Exception\PluginException;
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\Component\Plugin\Fixtures\vegetable\Broccoli;
use Drupal\Tests\Component\Plugin\Fixtures\vegetable\Corn;
use Drupal\Tests\Component\Plugin\Fixtures\vegetable\VegetableInterface;
use PHPUnit\Framework\TestCase;
/**
@@ -22,8 +22,8 @@ class DefaultFactoryTest extends TestCase {
* @covers ::getPluginClass
*/
public function testGetPluginClassWithValidArrayPluginDefinition() {
$plugin_class = Cherry::class;
$class = DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class]);
$plugin_class = Corn::class;
$class = DefaultFactory::getPluginClass('corn', ['class' => $plugin_class]);
$this->assertEquals($plugin_class, $class);
}
@@ -34,12 +34,12 @@ class DefaultFactoryTest extends TestCase {
* @covers ::getPluginClass
*/
public function testGetPluginClassWithValidObjectPluginDefinition() {
$plugin_class = Cherry::class;
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
$plugin_class = Corn::class;
$plugin_definition = $this->getMockBuilder(PluginDefinitionInterface::class)->getMock();
$plugin_definition->expects($this->atLeastOnce())
->method('getClass')
->willReturn($plugin_class);
$class = DefaultFactory::getPluginClass('cherry', $plugin_definition);
$class = DefaultFactory::getPluginClass('corn', $plugin_definition);
$this->assertEquals($plugin_class, $class);
}
@@ -50,8 +50,14 @@ class DefaultFactoryTest extends TestCase {
* @covers ::getPluginClass
*/
public function testGetPluginClassWithMissingClassWithArrayPluginDefinition() {
$this->setExpectedException(PluginException::class, 'The plugin (cherry) did not specify an instance class.');
DefaultFactory::getPluginClass('cherry', []);
if (method_exists($this, 'expectException')) {
$this->expectException(PluginException::class);
$this->expectExceptionMessage('The plugin (corn) did not specify an instance class.');
}
else {
$this->setExpectedException(PluginException::class, 'The plugin (corn) did not specify an instance class.');
}
DefaultFactory::getPluginClass('corn', []);
}
/**
@@ -60,9 +66,15 @@ class DefaultFactoryTest extends TestCase {
* @covers ::getPluginClass
*/
public function testGetPluginClassWithMissingClassWithObjectPluginDefinition() {
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
$this->setExpectedException(PluginException::class, 'The plugin (cherry) did not specify an instance class.');
DefaultFactory::getPluginClass('cherry', $plugin_definition);
$plugin_definition = $this->getMockBuilder(PluginDefinitionInterface::class)->getMock();
if (method_exists($this, 'expectException')) {
$this->expectException(PluginException::class);
$this->expectExceptionMessage('The plugin (corn) did not specify an instance class.');
}
else {
$this->setExpectedException(PluginException::class, 'The plugin (corn) did not specify an instance class.');
}
DefaultFactory::getPluginClass('corn', $plugin_definition);
}
/**
@@ -71,8 +83,14 @@ class DefaultFactoryTest extends TestCase {
* @covers ::getPluginClass
*/
public function testGetPluginClassWithNotExistingClassWithArrayPluginDefinition() {
$this->setExpectedException(PluginException::class, 'Plugin (kiwifruit) instance class "\Drupal\plugin_test\Plugin\plugin_test\fruit\Kiwifruit" does not exist.');
DefaultFactory::getPluginClass('kiwifruit', ['class' => '\Drupal\plugin_test\Plugin\plugin_test\fruit\Kiwifruit']);
if (method_exists($this, 'expectException')) {
$this->expectException(PluginException::class);
$this->expectExceptionMessage('Plugin (carrot) instance class "Drupal\Tests\Component\Plugin\Fixtures\vegetable\Carrot" does not exist.');
}
else {
$this->setExpectedException(PluginException::class, 'Plugin (carrot) instance class "Drupal\Tests\Component\Plugin\Fixtures\vegetable\Carrot" does not exist.');
}
DefaultFactory::getPluginClass('carrot', ['class' => 'Drupal\Tests\Component\Plugin\Fixtures\vegetable\Carrot']);
}
/**
@@ -81,13 +99,18 @@ class DefaultFactoryTest extends TestCase {
* @covers ::getPluginClass
*/
public function testGetPluginClassWithNotExistingClassWithObjectPluginDefinition() {
$plugin_class = '\Drupal\plugin_test\Plugin\plugin_test\fruit\Kiwifruit';
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
$plugin_class = 'Drupal\Tests\Component\Plugin\Fixtures\vegetable\Carrot';
$plugin_definition = $this->getMockBuilder(PluginDefinitionInterface::class)->getMock();
$plugin_definition->expects($this->atLeastOnce())
->method('getClass')
->willReturn($plugin_class);
$this->setExpectedException(PluginException::class);
DefaultFactory::getPluginClass('kiwifruit', $plugin_definition);
if (method_exists($this, 'expectException')) {
$this->expectException(PluginException::class);
}
else {
$this->setExpectedException(PluginException::class);
}
DefaultFactory::getPluginClass('carrot', $plugin_definition);
}
/**
@@ -96,8 +119,8 @@ class DefaultFactoryTest extends TestCase {
* @covers ::getPluginClass
*/
public function testGetPluginClassWithInterfaceWithArrayPluginDefinition() {
$plugin_class = Cherry::class;
$class = DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class], FruitInterface::class);
$plugin_class = Corn::class;
$class = DefaultFactory::getPluginClass('corn', ['class' => $plugin_class], VegetableInterface::class);
$this->assertEquals($plugin_class, $class);
}
@@ -108,12 +131,12 @@ class DefaultFactoryTest extends TestCase {
* @covers ::getPluginClass
*/
public function testGetPluginClassWithInterfaceWithObjectPluginDefinition() {
$plugin_class = Cherry::class;
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
$plugin_class = Corn::class;
$plugin_definition = $this->getMockBuilder(PluginDefinitionInterface::class)->getMock();
$plugin_definition->expects($this->atLeastOnce())
->method('getClass')
->willReturn($plugin_class);
$class = DefaultFactory::getPluginClass('cherry', $plugin_definition, FruitInterface::class);
$class = DefaultFactory::getPluginClass('corn', $plugin_definition, VegetableInterface::class);
$this->assertEquals($plugin_class, $class);
}
@@ -124,9 +147,14 @@ class DefaultFactoryTest extends TestCase {
* @covers ::getPluginClass
*/
public function testGetPluginClassWithInterfaceAndInvalidClassWithArrayPluginDefinition() {
$plugin_class = Kale::class;
$this->setExpectedException(PluginException::class, 'Plugin "cherry" (Drupal\plugin_test\Plugin\plugin_test\fruit\Kale) must implement interface Drupal\plugin_test\Plugin\plugin_test\fruit\FruitInterface.');
DefaultFactory::getPluginClass('cherry', ['class' => $plugin_class, 'provider' => 'core'], FruitInterface::class);
if (method_exists($this, 'expectException')) {
$this->expectException(PluginException::class);
$this->expectExceptionMessage('Plugin "corn" (Drupal\Tests\Component\Plugin\Fixtures\vegetable\Broccoli) must implement interface Drupal\Tests\Component\Plugin\Fixtures\vegetable\VegetableInterface.');
}
else {
$this->setExpectedException(PluginException::class, 'Plugin "corn" (Drupal\Tests\Component\Plugin\Fixtures\vegetable\Broccoli) must implement interface Drupal\Tests\Component\Plugin\Fixtures\vegetable\VegetableInterface.');
}
DefaultFactory::getPluginClass('corn', ['class' => Broccoli::class], VegetableInterface::class);
}
/**
@@ -135,13 +163,18 @@ class DefaultFactoryTest extends TestCase {
* @covers ::getPluginClass
*/
public function testGetPluginClassWithInterfaceAndInvalidClassWithObjectPluginDefinition() {
$plugin_class = Kale::class;
$plugin_definition = $this->getMock(PluginDefinitionInterface::class);
$plugin_class = Broccoli::class;
$plugin_definition = $this->getMockBuilder(PluginDefinitionInterface::class)->getMock();
$plugin_definition->expects($this->atLeastOnce())
->method('getClass')
->willReturn($plugin_class);
$this->setExpectedException(PluginException::class);
DefaultFactory::getPluginClass('cherry', $plugin_definition, FruitInterface::class);
if (method_exists($this, 'expectException')) {
$this->expectException(PluginException::class);
}
else {
$this->setExpectedException(PluginException::class);
}
DefaultFactory::getPluginClass('corn', $plugin_definition, VegetableInterface::class);
}
}
@@ -69,7 +69,12 @@ class DiscoveryTraitTest extends TestCase {
$method_ref = new \ReflectionMethod($trait, 'doGetDefinition');
$method_ref->setAccessible(TRUE);
// Call doGetDefinition, with $exception_on_invalid always TRUE.
$this->setExpectedException(PluginNotFoundException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(PluginNotFoundException::class);
}
else {
$this->setExpectedException(PluginNotFoundException::class);
}
$method_ref->invoke($trait, $definitions, $plugin_id, TRUE);
}
@@ -106,7 +111,12 @@ class DiscoveryTraitTest extends TestCase {
->method('getDefinitions')
->willReturn($definitions);
// Call getDefinition(), with $exception_on_invalid always TRUE.
$this->setExpectedException(PluginNotFoundException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(PluginNotFoundException::class);
}
else {
$this->setExpectedException(PluginNotFoundException::class);
}
$trait->getDefinition($plugin_id, TRUE);
}
@@ -100,7 +100,12 @@ class StaticDiscoveryDecoratorTest extends TestCase {
$ref_decorated->setValue($mock_decorator, $mock_decorated);
if ($exception_on_invalid) {
$this->setExpectedException('Drupal\Component\Plugin\Exception\PluginNotFoundException');
if (method_exists($this, 'expectException')) {
$this->expectException('Drupal\Component\Plugin\Exception\PluginNotFoundException');
}
else {
$this->setExpectedException('Drupal\Component\Plugin\Exception\PluginNotFoundException');
}
}
// Exercise getDefinition(). It calls parent::getDefinition().
@@ -123,7 +123,12 @@ class ReflectionFactoryTest extends TestCase {
// us to use one data set for this test method as well as
// testCreateInstance().
if ($plugin_id == 'arguments_no_constructor') {
$this->setExpectedException('\ReflectionException');
if (method_exists($this, 'expectException')) {
$this->expectException('\ReflectionException');
}
else {
$this->setExpectedException('\ReflectionException');
}
}
// Finally invoke getInstanceArguments() on our mocked factory.
@@ -0,0 +1,12 @@
<?php
namespace Drupal\Tests\Component\Plugin\Fixtures\vegetable;
/**
* @Plugin(
* id = "broccoli",
* label = "Broccoli",
* color = "green"
* )
*/
class Broccoli {}
@@ -0,0 +1,12 @@
<?php
namespace Drupal\Tests\Component\Plugin\Fixtures\vegetable;
/**
* @Plugin(
* id = "corn",
* label = "Corn",
* color = "yellow"
* )
*/
class Corn implements VegetableInterface {}
@@ -0,0 +1,8 @@
<?php
namespace Drupal\Tests\Component\Plugin\Fixtures\vegetable;
/**
* Provides an interface for test plugins.
*/
interface VegetableInterface {}
@@ -58,7 +58,7 @@ class JsonTest extends TestCase {
*/
public function testEncodingAscii() {
// Verify there aren't character encoding problems with the source string.
$this->assertSame(strlen($this->string), 127, 'A string with the full ASCII table has the correct length.');
$this->assertSame(127, strlen($this->string), 'A string with the full ASCII table has the correct length.');
foreach ($this->htmlUnsafe as $char) {
$this->assertTrue(strpos($this->string, $char) > 0, sprintf('A string with the full ASCII table includes %s.', $char));
}
@@ -87,7 +87,12 @@ foo:
* @covers ::errorHandler
*/
public function testError() {
$this->setExpectedException(InvalidDataTypeException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(InvalidDataTypeException::class);
}
else {
$this->setExpectedException(InvalidDataTypeException::class);
}
YamlPecl::decode('foo: [ads');
}
@@ -59,7 +59,12 @@ class YamlSymfonyTest extends YamlTestBase {
* @covers ::decode
*/
public function testError() {
$this->setExpectedException(InvalidDataTypeException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(InvalidDataTypeException::class);
}
else {
$this->setExpectedException(InvalidDataTypeException::class);
}
YamlSymfony::decode('foo: [ads');
}
@@ -69,7 +74,13 @@ class YamlSymfonyTest extends YamlTestBase {
* @covers ::encode
*/
public function testObjectSupportDisabled() {
$this->setExpectedException(InvalidDataTypeException::class, 'Object support when dumping a YAML file has been disabled.');
if (method_exists($this, 'expectException')) {
$this->expectException(InvalidDataTypeException::class);
$this->expectExceptionMessage('Object support when dumping a YAML file has been disabled.');
}
else {
$this->setExpectedException(InvalidDataTypeException::class, 'Object support when dumping a YAML file has been disabled.');
}
$object = new \stdClass();
$object->foo = 'bar';
YamlSymfony::encode([$object]);
@@ -77,20 +77,46 @@ class YamlTest extends TestCase {
}
/**
* Ensures that decoding php objects is similar for PECL and Symfony.
* Ensures that decoding php objects does not work in PECL.
*
* @requires extension yaml
*
* @see \Drupal\Tests\Component\Serialization\YamlTest::testObjectSupportDisabledSymfony()
*/
public function testObjectSupportDisabled() {
public function testObjectSupportDisabledPecl() {
$object = new \stdClass();
$object->foo = 'bar';
// In core all Yaml encoding is done via Symfony and it does not support
// objects so in order to encode an object we hace to use the PECL
// objects so in order to encode an object we have to use the PECL
// extension.
// @see \Drupal\Component\Serialization\Yaml::encode()
$yaml = YamlPecl::encode([$object]);
$this->assertEquals(['O:8:"stdClass":1:{s:3:"foo";s:3:"bar";}'], YamlPecl::decode($yaml));
$this->assertEquals(['!php/object "O:8:\"stdClass\":1:{s:3:\"foo\";s:3:\"bar\";}"'], YamlSymfony::decode($yaml));
}
/**
* Ensures that decoding php objects does not work in Symfony.
*
* @requires extension yaml
*
* @see \Drupal\Tests\Component\Serialization\YamlTest::testObjectSupportDisabledPecl()
*/
public function testObjectSupportDisabledSymfony() {
if (method_exists($this, 'setExpectedExceptionRegExp')) {
$this->setExpectedExceptionRegExp(InvalidDataTypeException::class, '/^Object support when parsing a YAML file has been disabled/');
}
else {
$this->expectException(InvalidDataTypeException::class);
$this->expectExceptionMessageRegExp('/^Object support when parsing a YAML file has been disabled/');
}
$object = new \stdClass();
$object->foo = 'bar';
// In core all Yaml encoding is done via Symfony and it does not support
// objects so in order to encode an object we have to use the PECL
// extension.
// @see \Drupal\Component\Serialization\Yaml::encode()
$yaml = YamlPecl::encode([$object]);
YamlSymfony::decode($yaml);
}
/**
@@ -101,8 +127,8 @@ class YamlTest extends TestCase {
$dirs = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator(__DIR__ . '/../../../../../', \RecursiveDirectoryIterator::FOLLOW_SYMLINKS));
foreach ($dirs as $dir) {
$pathname = $dir->getPathname();
// Exclude vendor.
if ($dir->getExtension() == 'yml' && strpos($pathname, '/../../../../../vendor') === FALSE) {
// Exclude core/node_modules.
if ($dir->getExtension() == 'yml' && strpos($pathname, '/../../../../../node_modules') === FALSE) {
if (strpos($dir->getRealPath(), 'invalid_file') !== FALSE) {
// There are some intentionally invalid files provided for testing
// library API behaviours, ignore them.
@@ -182,7 +182,7 @@ class PhpTransliterationTest extends TestCase {
]);
$transliteration = new PhpTransliteration(vfsStream::url('transliteration/dir'));
$transliterated = $transliteration->transliterate(chr(0xC2) . chr(0x82), '../index');
$this->assertSame($transliterated, 'safe');
$this->assertSame('safe', $transliterated);
}
}
@@ -96,9 +96,9 @@ class ArgumentsResolverTest extends TestCase {
* Tests getArgument() with a Route, Request, and Account object.
*/
public function testGetArgumentOrder() {
$a1 = $this->getMock('\Drupal\Tests\Component\Utility\Test1Interface');
$a2 = $this->getMock('\Drupal\Tests\Component\Utility\TestClass');
$a3 = $this->getMock('\Drupal\Tests\Component\Utility\Test2Interface');
$a1 = $this->getMockBuilder('\Drupal\Tests\Component\Utility\Test1Interface')->getMock();
$a2 = $this->getMockBuilder('\Drupal\Tests\Component\Utility\TestClass')->getMock();
$a3 = $this->getMockBuilder('\Drupal\Tests\Component\Utility\Test2Interface')->getMock();
$objects = [
't1' => $a1,
@@ -123,12 +123,18 @@ class ArgumentsResolverTest extends TestCase {
* Without the typehint, the wildcard object will not be passed to the callable.
*/
public function testGetWildcardArgumentNoTypehint() {
$a = $this->getMock('\Drupal\Tests\Component\Utility\Test1Interface');
$a = $this->getMockBuilder('\Drupal\Tests\Component\Utility\Test1Interface')->getMock();
$wildcards = [$a];
$resolver = new ArgumentsResolver([], [], $wildcards);
$callable = function ($route) {};
$this->setExpectedException(\RuntimeException::class, 'requires a value for the "$route" argument.');
if (method_exists($this, 'expectException')) {
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('requires a value for the "$route" argument.');
}
else {
$this->setExpectedException(\RuntimeException::class, 'requires a value for the "$route" argument.');
}
$resolver->getArguments($callable);
}
@@ -156,7 +162,13 @@ class ArgumentsResolverTest extends TestCase {
$resolver = new ArgumentsResolver($scalars, $objects, []);
$callable = function (\stdClass $foo) {};
$this->setExpectedException(\RuntimeException::class, 'requires a value for the "$foo" argument.');
if (method_exists($this, 'expectException')) {
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('requires a value for the "$foo" argument.');
}
else {
$this->setExpectedException(\RuntimeException::class, 'requires a value for the "$foo" argument.');
}
$resolver->getArguments($callable);
}
@@ -167,7 +179,13 @@ class ArgumentsResolverTest extends TestCase {
*/
public function testHandleUnresolvedArgument($callable) {
$resolver = new ArgumentsResolver([], [], []);
$this->setExpectedException(\RuntimeException::class, 'requires a value for the "$foo" argument.');
if (method_exists($this, 'expectException')) {
$this->expectException(\RuntimeException::class);
$this->expectExceptionMessage('requires a value for the "$foo" argument.');
}
else {
$this->setExpectedException(\RuntimeException::class, 'requires a value for the "$foo" argument.');
}
$resolver->getArguments($callable);
}
@@ -26,7 +26,12 @@ class ColorTest extends TestCase {
*/
public function testHexToRgb($value, $expected, $invalid = FALSE) {
if ($invalid) {
$this->setExpectedException('InvalidArgumentException');
if (method_exists($this, 'expectException')) {
$this->expectException('InvalidArgumentException');
}
else {
$this->setExpectedException('InvalidArgumentException');
}
}
$this->assertSame($expected, Color::hexToRgb($value));
}
@@ -118,4 +123,42 @@ class ColorTest extends TestCase {
return $tests;
}
/**
* Data provider for testNormalizeHexLength().
*
* @see testNormalizeHexLength()
*
* @return array
* An array of arrays containing:
* - The hex color value.
* - The 6 character length hex color value.
*/
public function providerTestNormalizeHexLength() {
$data = [
['#000', '#000000'],
['#FFF', '#FFFFFF'],
['#abc', '#aabbcc'],
['cba', '#ccbbaa'],
['#000000', '#000000'],
['ffffff', '#ffffff'],
['#010203', '#010203'],
];
return $data;
}
/**
* Tests Color::normalizeHexLength().
*
* @param string $value
* The input hex color value.
* @param string $expected
* The expected normalized hex color value.
*
* @dataProvider providerTestNormalizeHexLength
*/
public function testNormalizeHexLength($value, $expected) {
$this->assertSame($expected, Color::normalizeHexLength($value));
}
}
@@ -77,7 +77,12 @@ class CryptTest extends TestCase {
* Key to use in hashing process.
*/
public function testHmacBase64Invalid($data, $key) {
$this->setExpectedException(\InvalidArgumentException::class);
if (method_exists($this, 'expectException')) {
$this->expectException('InvalidArgumentException');
}
else {
$this->setExpectedException('InvalidArgumentException');
}
Crypt::hmacBase64($data, $key);
}
@@ -343,7 +343,12 @@ class HtmlTest extends TestCase {
* @dataProvider providerTestTransformRootRelativeUrlsToAbsoluteAssertion
*/
public function testTransformRootRelativeUrlsToAbsoluteAssertion($scheme_and_host) {
$this->setExpectedException(\AssertionError::class);
if (method_exists($this, 'expectException')) {
$this->expectException(\AssertionError::class);
}
else {
$this->setExpectedException(\AssertionError::class);
}
Html::transformRootRelativeUrlsToAbsolute('', $scheme_and_host);
}
@@ -62,7 +62,12 @@ class RandomTest extends TestCase {
// There are fewer than 100 possibilities so an exception should occur to
// prevent infinite loops.
$random = new Random();
$this->setExpectedException(\RuntimeException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(\RuntimeException::class);
}
else {
$this->setExpectedException(\RuntimeException::class);
}
for ($i = 0; $i <= 100; $i++) {
$str = $random->name(1, TRUE);
$names[$str] = TRUE;
@@ -78,7 +83,12 @@ class RandomTest extends TestCase {
// There are fewer than 100 possibilities so an exception should occur to
// prevent infinite loops.
$random = new Random();
$this->setExpectedException(\RuntimeException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(\RuntimeException::class);
}
else {
$this->setExpectedException(\RuntimeException::class);
}
for ($i = 0; $i <= 100; $i++) {
$str = $random->string(1, TRUE);
$names[$str] = TRUE;
@@ -17,7 +17,12 @@ class RectangleTest extends TestCase {
* @covers ::rotate
*/
public function testWrongWidth() {
$this->setExpectedException(\InvalidArgumentException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(\InvalidArgumentException::class);
}
else {
$this->setExpectedException(\InvalidArgumentException::class);
}
$rect = new Rectangle(-40, 20);
}
@@ -27,7 +32,12 @@ class RectangleTest extends TestCase {
* @covers ::rotate
*/
public function testWrongHeight() {
$this->setExpectedException(\InvalidArgumentException::class);
if (method_exists($this, 'expectException')) {
$this->expectException(\InvalidArgumentException::class);
}
else {
$this->setExpectedException(\InvalidArgumentException::class);
}
$rect = new Rectangle(40, 0);
}
@@ -37,7 +37,7 @@ class SafeMarkupTest extends TestCase {
* @covers ::isSafe
*/
public function testIsSafe() {
$safe_string = $this->getMock('\Drupal\Component\Render\MarkupInterface');
$safe_string = $this->getMockBuilder('\Drupal\Component\Render\MarkupInterface')->getMock();
$this->assertTrue(SafeMarkup::isSafe($safe_string));
$string_object = new SafeMarkupTestString('test');
$this->assertFalse(SafeMarkup::isSafe($string_object));

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