updated core from 8.4 to 8.5 : bug with login_destination
This commit is contained in:
@@ -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');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+591
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+95
-1
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
+33
@@ -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]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+188
@@ -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');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user