class EntityFieldTest

Same name in other branches
  1. 8.9.x core/tests/Drupal/KernelTests/Core/Entity/EntityFieldTest.php \Drupal\KernelTests\Core\Entity\EntityFieldTest
  2. 10 core/tests/Drupal/KernelTests/Core/Entity/EntityFieldTest.php \Drupal\KernelTests\Core\Entity\EntityFieldTest
  3. 11.x core/tests/Drupal/KernelTests/Core/Entity/EntityFieldTest.php \Drupal\KernelTests\Core\Entity\EntityFieldTest

Tests the Entity Field API.

@group Entity

Hierarchy

Expanded class hierarchy of EntityFieldTest

File

core/tests/Drupal/KernelTests/Core/Entity/EntityFieldTest.php, line 32

Namespace

Drupal\KernelTests\Core\Entity
View source
class EntityFieldTest extends EntityKernelTestBase {
    
    /**
     * Modules to enable.
     *
     * @var array
     */
    protected static $modules = [
        'filter',
        'text',
        'node',
        'user',
        'field_test',
    ];
    
    /**
     * @var string
     */
    protected $entityName;
    
    /**
     * @var \Drupal\user\Entity\User
     */
    protected $entityUser;
    
    /**
     * @var string
     */
    protected $entityFieldText;
    
    /**
     * {@inheritdoc}
     */
    protected function setUp() : void {
        parent::setUp();
        foreach (entity_test_entity_types() as $entity_type_id) {
            // The entity_test schema is installed by the parent.
            if ($entity_type_id != 'entity_test') {
                $this->installEntitySchema($entity_type_id);
            }
        }
        // Create the test field.
        $this->container
            ->get('module_handler')
            ->loadInclude('entity_test', 'install');
        entity_test_install();
        // Install required default configuration for filter module.
        $this->installConfig([
            'system',
            'filter',
        ]);
    }
    
    /**
     * Creates a test entity.
     *
     * @return \Drupal\Core\Entity\EntityInterface
     */
    protected function createTestEntity($entity_type) {
        $this->entityName = $this->randomMachineName();
        $this->entityUser = $this->createUser();
        $this->entityFieldText = $this->randomMachineName();
        // Pass in the value of the name field when creating. With the user
        // field we test setting a field after creation.
        $entity = $this->container
            ->get('entity_type.manager')
            ->getStorage($entity_type)
            ->create();
        $entity->user_id->target_id = $this->entityUser
            ->id();
        $entity->name->value = $this->entityName;
        // Set a value for the test field.
        $entity->field_test_text->value = $this->entityFieldText;
        return $entity;
    }
    
    /**
     * Tests reading and writing properties and field items.
     */
    public function testReadWrite() {
        // All entity variations have to have the same results.
        foreach (entity_test_entity_types() as $entity_type) {
            $this->doTestReadWrite($entity_type);
        }
    }
    
    /**
     * Executes the read write test set for a defined entity type.
     *
     * @param string $entity_type
     *   The entity type to run the tests with.
     */
    protected function doTestReadWrite($entity_type) {
        $entity = $this->createTestEntity($entity_type);
        $langcode = 'en';
        // Access the name field.
        $this->assertInstanceOf(FieldItemListInterface::class, $entity->name);
        $this->assertInstanceOf(FieldItemInterface::class, $entity->name[0]);
        $this->assertEquals($this->entityName, $entity->name->value, new FormattableMarkup('%entity_type: Name value can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($this->entityName, $entity->name[0]->value, new FormattableMarkup('%entity_type: Name value can be read through list access.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals([
            0 => [
                'value' => $this->entityName,
            ],
        ], $entity->name
            ->getValue(), new FormattableMarkup('%entity_type: Plain field value returned.', [
            '%entity_type' => $entity_type,
        ]));
        // Change the name.
        $new_name = $this->randomMachineName();
        $entity->name->value = $new_name;
        $this->assertEquals($new_name, $entity->name->value, new FormattableMarkup('%entity_type: Name can be updated and read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals([
            0 => [
                'value' => $new_name,
            ],
        ], $entity->name
            ->getValue(), new FormattableMarkup('%entity_type: Plain field value reflects the update.', [
            '%entity_type' => $entity_type,
        ]));
        $new_name = $this->randomMachineName();
        $entity->name[0]->value = $new_name;
        $this->assertEquals($new_name, $entity->name->value, new FormattableMarkup('%entity_type: Name can be updated and read through list access.', [
            '%entity_type' => $entity_type,
        ]));
        // Access the user field.
        $this->assertInstanceOf(FieldItemListInterface::class, $entity->user_id);
        $this->assertInstanceOf(FieldItemInterface::class, $entity->user_id[0]);
        $this->assertEquals($this->entityUser
            ->id(), $entity->user_id->target_id, new FormattableMarkup('%entity_type: User id can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($this->entityUser
            ->getAccountName(), $entity->user_id->entity->name->value, new FormattableMarkup('%entity_type: User name can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Change the assigned user by entity.
        $new_user1 = $this->createUser();
        $entity->user_id->entity = $new_user1;
        $this->assertEquals($new_user1->id(), $entity->user_id->target_id, new FormattableMarkup('%entity_type: Updated user id can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($new_user1->getAccountName(), $entity->user_id->entity->name->value, new FormattableMarkup('%entity_type: Updated username value can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Change the assigned user by id.
        $new_user2 = $this->createUser();
        $entity->user_id->target_id = $new_user2->id();
        $this->assertEquals($new_user2->id(), $entity->user_id->target_id, new FormattableMarkup('%entity_type: Updated user id can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($new_user2->getAccountName(), $entity->user_id->entity->name->value, new FormattableMarkup('%entity_type: Updated username value can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Try unsetting a field property.
        $entity->name->value = NULL;
        $entity->user_id->target_id = NULL;
        $this->assertNull($entity->name->value, new FormattableMarkup('%entity_type: Name field is not set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertNull($entity->user_id->target_id, new FormattableMarkup('%entity_type: User ID field is not set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertNull($entity->user_id->entity, new FormattableMarkup('%entity_type: User entity field is not set.', [
            '%entity_type' => $entity_type,
        ]));
        // Test setting the values via the typed data API works as well.
        // Change the assigned user by entity.
        $entity->user_id
            ->first()
            ->get('entity')
            ->setValue($new_user2);
        $this->assertEquals($new_user2->id(), $entity->user_id->target_id, new FormattableMarkup('%entity_type: Updated user id can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($new_user2->getAccountName(), $entity->user_id->entity->name->value, new FormattableMarkup('%entity_type: Updated user name value can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Change the assigned user by id.
        $entity->user_id
            ->first()
            ->get('target_id')
            ->setValue($new_user2->id());
        $this->assertEquals($new_user2->id(), $entity->user_id->target_id, new FormattableMarkup('%entity_type: Updated user id can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($new_user2->getAccountName(), $entity->user_id->entity->name->value, new FormattableMarkup('%entity_type: Updated user name value can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Try unsetting a field.
        $entity->name
            ->first()
            ->get('value')
            ->setValue(NULL);
        $entity->user_id
            ->first()
            ->get('target_id')
            ->setValue(NULL);
        $this->assertNull($entity->name->value, new FormattableMarkup('%entity_type: Name field is not set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertNull($entity->user_id->target_id, new FormattableMarkup('%entity_type: User ID field is not set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertNull($entity->user_id->entity, new FormattableMarkup('%entity_type: User entity field is not set.', [
            '%entity_type' => $entity_type,
        ]));
        // Create a fresh entity so target_id does not get its property object
        // instantiated, then verify setting a new value via typed data API works.
        $entity2 = $this->container
            ->get('entity_type.manager')
            ->getStorage($entity_type)
            ->create([
            'user_id' => [
                'target_id' => $new_user1->id(),
            ],
        ]);
        // Access the property object, and set a value.
        $entity2->user_id
            ->first()
            ->get('target_id')
            ->setValue($new_user2->id());
        $this->assertEquals($new_user2->id(), $entity2->user_id->target_id, new FormattableMarkup('%entity_type: Updated user id can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($new_user2->name->value, $entity2->user_id->entity->name->value, new FormattableMarkup('%entity_type: Updated user name value can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Test using isset(), empty() and unset().
        $entity->name->value = 'test unset';
        unset($entity->name->value);
        $this->assertFalse(isset($entity->name->value), new FormattableMarkup('%entity_type: Name is not set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertFalse(isset($entity->name[0]->value), new FormattableMarkup('%entity_type: Name is not set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEmpty($entity->name->value, new FormattableMarkup('%entity_type: Name is empty.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEmpty($entity->name[0]->value, new FormattableMarkup('%entity_type: Name is empty.', [
            '%entity_type' => $entity_type,
        ]));
        $entity->name->value = 'a value';
        $this->assertTrue(isset($entity->name->value), new FormattableMarkup('%entity_type: Name is set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertTrue(isset($entity->name[0]->value), new FormattableMarkup('%entity_type: Name is set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertNotEmpty($entity->name->value, new FormattableMarkup('%entity_type: Name is not empty.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertNotEmpty($entity->name[0]->value, new FormattableMarkup('%entity_type: Name is not empty.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertTrue(isset($entity->name[0]), new FormattableMarkup('%entity_type: Name string item is set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertFalse(isset($entity->name[1]), new FormattableMarkup('%entity_type: Second name string item is not set as it does not exist', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertTrue(isset($entity->name), new FormattableMarkup('%entity_type: Name field is set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertFalse(isset($entity->nameInvalid), new FormattableMarkup('%entity_type: Non-existent field is not set.', [
            '%entity_type' => $entity_type,
        ]));
        unset($entity->name[0]);
        $this->assertFalse(isset($entity->name[0]), new FormattableMarkup('%entity_type: Name field item is not set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertFalse(isset($entity->name[0]->value), new FormattableMarkup('%entity_type: Name is not set.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertFalse(isset($entity->name->value), new FormattableMarkup('%entity_type: Name is not set.', [
            '%entity_type' => $entity_type,
        ]));
        // Test emptying a field by assigning an empty value. NULL and array()
        // behave the same.
        foreach ([
            NULL,
            [],
            'unset',
        ] as $empty) {
            // Make sure a value is present
            $entity->name->value = 'a value';
            $this->assertTrue(isset($entity->name->value), new FormattableMarkup('%entity_type: Name is set.', [
                '%entity_type' => $entity_type,
            ]));
            // Now, empty the field.
            if ($empty === 'unset') {
                unset($entity->name);
            }
            else {
                $entity->name = $empty;
            }
            $this->assertTrue(isset($entity->name), new FormattableMarkup('%entity_type: Name field is set.', [
                '%entity_type' => $entity_type,
            ]));
            $this->assertTrue($entity->name
                ->isEmpty(), new FormattableMarkup('%entity_type: Name field is set.', [
                '%entity_type' => $entity_type,
            ]));
            $this->assertCount(0, $entity->name, new FormattableMarkup('%entity_type: Name field contains no items.', [
                '%entity_type' => $entity_type,
            ]));
            $this->assertSame([], $entity->name
                ->getValue(), new FormattableMarkup('%entity_type: Name field value is an empty array.', [
                '%entity_type' => $entity_type,
            ]));
            $this->assertFalse(isset($entity->name[0]), new FormattableMarkup('%entity_type: Name field item is not set.', [
                '%entity_type' => $entity_type,
            ]));
            $this->assertFalse(isset($entity->name[0]->value), new FormattableMarkup('%entity_type: First name item value is not set.', [
                '%entity_type' => $entity_type,
            ]));
            $this->assertFalse(isset($entity->name->value), new FormattableMarkup('%entity_type: Name value is not set.', [
                '%entity_type' => $entity_type,
            ]));
        }
        // Access the language field.
        $langcode_key = $this->entityTypeManager
            ->getDefinition($entity_type)
            ->getKey('langcode');
        $this->assertEquals($langcode, $entity->{$langcode_key}->value, new FormattableMarkup('%entity_type: Language code can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals(\Drupal::languageManager()->getLanguage($langcode), $entity->{$langcode_key}->language, new FormattableMarkup('%entity_type: Language object can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Change the language by code.
        $entity->{$langcode_key}->value = \Drupal::languageManager()->getDefaultLanguage()
            ->getId();
        $this->assertEquals(\Drupal::languageManager()->getDefaultLanguage()
            ->getId(), $entity->{$langcode_key}->value, new FormattableMarkup('%entity_type: Language code can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals(\Drupal::languageManager()->getDefaultLanguage(), $entity->{$langcode_key}->language, new FormattableMarkup('%entity_type: Language object can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Revert language by code then try setting it by language object.
        $entity->{$langcode_key}->value = $langcode;
        $entity->{$langcode_key}->language = \Drupal::languageManager()->getDefaultLanguage();
        $this->assertEquals(\Drupal::languageManager()->getDefaultLanguage()
            ->getId(), $entity->{$langcode_key}->value, new FormattableMarkup('%entity_type: Language code can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals(\Drupal::languageManager()->getDefaultLanguage(), $entity->{$langcode_key}->language, new FormattableMarkup('%entity_type: Language object can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Access the text field and test updating.
        $this->assertEquals($this->entityFieldText, $entity->field_test_text->value, new FormattableMarkup('%entity_type: Text field can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $new_text = $this->randomMachineName();
        $entity->field_test_text->value = $new_text;
        $this->assertEquals($new_text, $entity->field_test_text->value, new FormattableMarkup('%entity_type: Updated text field can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Test creating the entity by passing in plain values.
        $this->entityName = $this->randomMachineName();
        $name_item[0]['value'] = $this->entityName;
        $this->entityUser = $this->createUser();
        $user_item[0]['target_id'] = $this->entityUser
            ->id();
        $this->entityFieldText = $this->randomMachineName();
        $text_item[0]['value'] = $this->entityFieldText;
        $entity = $this->container
            ->get('entity_type.manager')
            ->getStorage($entity_type)
            ->create([
            'name' => $name_item,
            'user_id' => $user_item,
            'field_test_text' => $text_item,
        ]);
        $this->assertEquals($this->entityName, $entity->name->value, new FormattableMarkup('%entity_type: Name value can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($this->entityUser
            ->id(), $entity->user_id->target_id, new FormattableMarkup('%entity_type: User id can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($this->entityUser
            ->getAccountName(), $entity->user_id->entity->name->value, new FormattableMarkup('%entity_type: User name can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($this->entityFieldText, $entity->field_test_text->value, new FormattableMarkup('%entity_type: Text field can be read.', [
            '%entity_type' => $entity_type,
        ]));
        // Tests copying field values by assigning the TypedData objects.
        $entity2 = $this->createTestEntity($entity_type);
        $entity2->name = $entity->name;
        $entity2->user_id = $entity->user_id;
        $entity2->field_test_text = $entity->field_test_text;
        $this->assertNotSame($entity->name, $entity2->name, new FormattableMarkup('%entity_type: Copying properties results in a different field object.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($entity->name->value, $entity2->name->value, new FormattableMarkup('%entity_type: Name field copied.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($entity->user_id->target_id, $entity2->user_id->target_id, new FormattableMarkup('%entity_type: User id field copied.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($entity->field_test_text->value, $entity2->field_test_text->value, new FormattableMarkup('%entity_type: Text field copied.', [
            '%entity_type' => $entity_type,
        ]));
        // Tests that assigning TypedData objects to non-field properties keeps the
        // assigned value as is.
        $entity2 = $this->createTestEntity($entity_type);
        $entity2->_not_a_field = $entity->name;
        $this->assertSame($entity->name, $entity2->_not_a_field, new FormattableMarkup('%entity_type: Typed data objects can be copied to non-field properties as is.', [
            '%entity_type' => $entity_type,
        ]));
        // Tests adding a value to a field item list.
        $entity->name[] = 'Another name';
        $this->assertEquals('Another name', $entity->name[1]->value, new FormattableMarkup('%entity_type: List item added via [] and the first property.', [
            '%entity_type' => $entity_type,
        ]));
        $entity->name[] = [
            'value' => 'Third name',
        ];
        $this->assertEquals('Third name', $entity->name[2]->value, new FormattableMarkup('%entity_type: List item added via [] and an array of properties.', [
            '%entity_type' => $entity_type,
        ]));
        $entity->name[3] = [
            'value' => 'Fourth name',
        ];
        $this->assertEquals('Fourth name', $entity->name[3]->value, new FormattableMarkup('%entity_type: List item added via offset and an array of properties.', [
            '%entity_type' => $entity_type,
        ]));
        unset($entity->name[3]);
        // Test removing and empty-ing list items.
        $this->assertCount(3, $entity->name, new FormattableMarkup('%entity_type: List has 3 items.', [
            '%entity_type' => $entity_type,
        ]));
        unset($entity->name[1]);
        $this->assertCount(2, $entity->name, new FormattableMarkup('%entity_type: Second list item has been removed.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals('Third name', $entity->name[1]->value, new FormattableMarkup('%entity_type: The subsequent items have been shifted up.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals(1, $entity->name[1]
            ->getName(), new FormattableMarkup('%entity_type: The items names have been updated to their new delta.', [
            '%entity_type' => $entity_type,
        ]));
        $entity->name[1] = NULL;
        $this->assertCount(2, $entity->name, new FormattableMarkup('%entity_type: Assigning NULL does not reduce array count.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertTrue($entity->name[1]
            ->isEmpty(), new FormattableMarkup('%entity_type: Assigning NULL empties the item.', [
            '%entity_type' => $entity_type,
        ]));
        // Test using isEmpty().
        unset($entity->name[1]);
        $this->assertFalse($entity->name[0]
            ->isEmpty(), new FormattableMarkup('%entity_type: Name item is not empty.', [
            '%entity_type' => $entity_type,
        ]));
        $entity->name->value = NULL;
        $this->assertTrue($entity->name[0]
            ->isEmpty(), new FormattableMarkup('%entity_type: Name item is empty.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertTrue($entity->name
            ->isEmpty(), new FormattableMarkup('%entity_type: Name field is empty.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertCount(1, $entity->name, new FormattableMarkup('%entity_type: Empty item is considered when counting.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertCount(1, iterator_to_array($entity->name
            ->getIterator()), new FormattableMarkup('%entity_type: Count matches iterator count.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertSame([
            0 => [
                'value' => NULL,
            ],
        ], $entity->name
            ->getValue(), new FormattableMarkup('%entity_type: Name field value contains a NULL value.', [
            '%entity_type' => $entity_type,
        ]));
        // Test using filterEmptyItems().
        $entity->name = [
            NULL,
            'foo',
        ];
        $this->assertCount(2, $entity->name, new FormattableMarkup('%entity_type: List has 2 items.', [
            '%entity_type' => $entity_type,
        ]));
        $entity->name
            ->filterEmptyItems();
        $this->assertCount(1, $entity->name, new FormattableMarkup('%entity_type: The empty item was removed.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals('foo', $entity->name[0]->value, new FormattableMarkup('%entity_type: The items were renumbered.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals(0, $entity->name[0]
            ->getName(), new FormattableMarkup('%entity_type: The deltas were updated in the items.', [
            '%entity_type' => $entity_type,
        ]));
        // Test get and set field values.
        $entity->name = 'foo';
        $this->assertEquals([
            'value' => 'foo',
        ], $entity->name[0]
            ->toArray(), new FormattableMarkup('%entity_type: Field value has been retrieved via toArray()', [
            '%entity_type' => $entity_type,
        ]));
        $values = $entity->toArray();
        $this->assertEquals([
            0 => [
                'value' => 'foo',
            ],
        ], $values['name'], new FormattableMarkup('%entity_type: Field value has been retrieved via toArray() from an entity.', [
            '%entity_type' => $entity_type,
        ]));
        // Make sure the user id can be set to zero.
        $user_item[0]['target_id'] = 0;
        $entity = $this->container
            ->get('entity_type.manager')
            ->getStorage($entity_type)
            ->create([
            'name' => $name_item,
            'user_id' => $user_item,
            'field_test_text' => $text_item,
        ]);
        $this->assertNotNull($entity->user_id->target_id, new FormattableMarkup('%entity_type: User id is not NULL', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertSame(0, $entity->user_id->target_id, new FormattableMarkup('%entity_type: User id has been set to 0', [
            '%entity_type' => $entity_type,
        ]));
        // Test setting the ID with the value only.
        $entity = $this->container
            ->get('entity_type.manager')
            ->getStorage($entity_type)
            ->create([
            'name' => $name_item,
            'user_id' => 0,
            'field_test_text' => $text_item,
        ]);
        $this->assertNotNull($entity->user_id->target_id, new FormattableMarkup('%entity_type: User id is not NULL', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertSame(0, $entity->user_id->target_id, new FormattableMarkup('%entity_type: User id has been set to 0', [
            '%entity_type' => $entity_type,
        ]));
    }
    
    /**
     * Tries to save and load an entity again.
     */
    public function testSave() {
        // All entity variations have to have the same results.
        foreach (entity_test_entity_types() as $entity_type) {
            $this->doTestSave($entity_type);
        }
    }
    
    /**
     * Executes the save tests for the given entity type.
     *
     * @param string $entity_type
     *   The entity type to run the tests with.
     */
    protected function doTestSave($entity_type) {
        $langcode_key = $this->entityTypeManager
            ->getDefinition($entity_type)
            ->getKey('langcode');
        $entity = $this->createTestEntity($entity_type);
        $entity->save();
        $this->assertTrue((bool) $entity->id(), new FormattableMarkup('%entity_type: Entity has received an id.', [
            '%entity_type' => $entity_type,
        ]));
        $entity = $this->container
            ->get('entity_type.manager')
            ->getStorage($entity_type)
            ->load($entity->id());
        $this->assertTrue((bool) $entity->id(), new FormattableMarkup('%entity_type: Entity loaded.', [
            '%entity_type' => $entity_type,
        ]));
        // Access the name field.
        $this->assertEquals(1, $entity->id->value, new FormattableMarkup('%entity_type: ID value can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertIsString($entity->uuid->value);
        $this->assertEquals('en', $entity->{$langcode_key}->value, new FormattableMarkup('%entity_type: Language code can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals(\Drupal::languageManager()->getLanguage('en'), $entity->{$langcode_key}->language, new FormattableMarkup('%entity_type: Language object can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($this->entityUser
            ->id(), $entity->user_id->target_id, new FormattableMarkup('%entity_type: User id can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($this->entityUser
            ->getAccountName(), $entity->user_id->entity->name->value, new FormattableMarkup('%entity_type: User name can be read.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals($this->entityFieldText, $entity->field_test_text->value, new FormattableMarkup('%entity_type: Text field can be read.', [
            '%entity_type' => $entity_type,
        ]));
    }
    
    /**
     * Tests introspection and getting metadata upfront.
     */
    public function testIntrospection() {
        // All entity variations have to have the same results.
        foreach (entity_test_entity_types() as $entity_type) {
            $this->doTestIntrospection($entity_type);
        }
    }
    
    /**
     * Executes the introspection tests for the given entity type.
     *
     * @param string $entity_type
     *   The entity type to run the tests with.
     */
    protected function doTestIntrospection($entity_type) {
        // Test getting metadata upfront. The entity types used for this test have
        // a default bundle that is the same as the entity type.
        $definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type, $entity_type);
        $this->assertEquals('string', $definitions['name']->getType(), $entity_type . ': Name field found.');
        $this->assertEquals('entity_reference', $definitions['user_id']->getType(), $entity_type . ': User field found.');
        $this->assertEquals('text', $definitions['field_test_text']->getType(), $entity_type . ': Test-text-field field found.');
        // Test deriving further metadata.
        $this->assertInstanceOf(FieldDefinitionInterface::class, $definitions['name']);
        $field_item_definition = $definitions['name']->getItemDefinition();
        $this->assertInstanceOf(ComplexDataDefinitionInterface::class, $field_item_definition);
        $this->assertEquals('field_item:string', $field_item_definition->getDataType());
        $value_definition = $field_item_definition->getPropertyDefinition('value');
        $this->assertInstanceOf(DataDefinitionInterface::class, $value_definition);
        $this->assertEquals('string', $value_definition->getDataType());
        // Test deriving metadata from references.
        $entity_definition = EntityDataDefinition::create($entity_type);
        $langcode_key = $this->entityTypeManager
            ->getDefinition($entity_type)
            ->getKey('langcode');
        $reference_definition = $entity_definition->getPropertyDefinition($langcode_key)
            ->getPropertyDefinition('language')
            ->getTargetDefinition();
        $this->assertEquals('language', $reference_definition->getDataType());
        $reference_definition = $entity_definition->getPropertyDefinition('user_id')
            ->getPropertyDefinition('entity')
            ->getTargetDefinition();
        $this->assertInstanceOf(EntityDataDefinitionInterface::class, $reference_definition);
        $this->assertEquals('user', $reference_definition->getEntityTypeId(), 'Referenced entity is of type "user".');
        // Test propagating down.
        $name_definition = $reference_definition->getPropertyDefinition('name');
        $this->assertInstanceOf(FieldDefinitionInterface::class, $name_definition);
        $this->assertEquals('string', $name_definition->getPropertyDefinition('value')
            ->getDataType());
        // Test introspecting an entity object.
        // @todo: Add bundles and test bundles as well.
        $entity = $this->container
            ->get('entity_type.manager')
            ->getStorage($entity_type)
            ->create();
        $definitions = $entity->getFieldDefinitions();
        $this->assertEquals('string', $definitions['name']->getType(), $entity_type . ': Name field found.');
        $this->assertEquals('entity_reference', $definitions['user_id']->getType(), $entity_type . ': User field found.');
        $this->assertEquals('text', $definitions['field_test_text']->getType(), $entity_type . ': Test-text-field field found.');
        $name_properties = $entity->name
            ->getFieldDefinition()
            ->getPropertyDefinitions();
        $this->assertEquals('string', $name_properties['value']->getDataType(), $entity_type . ': String value property of the name found.');
        $userref_properties = $entity->user_id
            ->getFieldDefinition()
            ->getPropertyDefinitions();
        $this->assertEquals('integer', $userref_properties['target_id']->getDataType(), $entity_type . ': Entity id property of the user found.');
        $this->assertEquals('entity_reference', $userref_properties['entity']->getDataType(), $entity_type . ': Entity reference property of the user found.');
        $textfield_properties = $entity->field_test_text
            ->getFieldDefinition()
            ->getFieldStorageDefinition()
            ->getPropertyDefinitions();
        $this->assertEquals('string', $textfield_properties['value']->getDataType(), $entity_type . ': String value property of the test-text field found.');
        $this->assertEquals('filter_format', $textfield_properties['format']->getDataType(), $entity_type . ': String format field of the test-text field found.');
        $this->assertEquals('string', $textfield_properties['processed']->getDataType(), $entity_type . ': String processed property of the test-text field found.');
        // Make sure provided contextual information is right.
        $entity_adapter = $entity->getTypedData();
        $this->assertSame($entity_adapter->getRoot(), $entity_adapter, 'Entity is root object.');
        $this->assertEquals('', $entity_adapter->getPropertyPath());
        $this->assertEquals('', $entity_adapter->getName());
        $this->assertNull($entity_adapter->getParent());
        $field = $entity->user_id;
        $this->assertSame($field->getRoot()
            ->getValue(), $entity, 'Entity is root object.');
        $this->assertSame($field->getEntity(), $entity, 'getEntity() returns the entity.');
        $this->assertEquals('user_id', $field->getPropertyPath());
        $this->assertEquals('user_id', $field->getName());
        $this->assertSame($field->getParent()
            ->getValue(), $entity, 'Parent object matches.');
        $field_item = $field[0];
        $this->assertSame($field_item->getRoot()
            ->getValue(), $entity, 'Entity is root object.');
        $this->assertSame($field_item->getEntity(), $entity, 'getEntity() returns the entity.');
        $this->assertEquals('user_id.0', $field_item->getPropertyPath());
        $this->assertEquals('0', $field_item->getName());
        $this->assertSame($field_item->getParent(), $field, 'Parent object matches.');
        $item_value = $field_item->get('entity');
        $this->assertSame($item_value->getRoot()
            ->getValue(), $entity, 'Entity is root object.');
        $this->assertEquals('user_id.0.entity', $item_value->getPropertyPath());
        $this->assertEquals('entity', $item_value->getName());
        $this->assertSame($item_value->getParent(), $field_item, 'Parent object matches.');
    }
    
    /**
     * Tests iterating over properties.
     */
    public function testIterator() {
        // All entity variations have to have the same results.
        foreach (entity_test_entity_types() as $entity_type) {
            $this->doTestIterator($entity_type);
        }
    }
    
    /**
     * Executes the iterator tests for the given entity type.
     *
     * @param string $entity_type
     *   The entity type to run the tests with.
     */
    protected function doTestIterator($entity_type) {
        $entity = $this->createTestEntity($entity_type);
        foreach ($entity as $name => $field) {
            $this->assertInstanceOf(FieldItemListInterface::class, $field);
            foreach ($field as $delta => $item) {
                $this->assertInstanceOf(FieldItemInterface::class, $field[0]);
                foreach ($item as $value_name => $value_property) {
                    $this->assertInstanceOf(TypedDataInterface::class, $value_property);
                    $value = $value_property->getValue();
                    $this->assertTrue(!isset($value) || is_scalar($value) || $value instanceof EntityInterface, $entity_type . ": Value {$value_name} of item {$delta} of field {$name} is a primitive or an entity.");
                }
            }
        }
        $fields = $entity->getFields();
        $this->assertEquals(array_keys($entity->getTypedData()
            ->getDataDefinition()
            ->getPropertyDefinitions()), array_keys($fields), new FormattableMarkup('%entity_type: All fields returned.', [
            '%entity_type' => $entity_type,
        ]));
        $this->assertEquals(iterator_to_array($entity->getIterator()), $fields, new FormattableMarkup('%entity_type: Entity iterator iterates over all fields.', [
            '%entity_type' => $entity_type,
        ]));
    }
    
    /**
     * Tests working with the entity based upon the TypedData API.
     */
    public function testDataStructureInterfaces() {
        // All entity variations have to have the same results.
        foreach (entity_test_entity_types() as $entity_type) {
            $this->doTestDataStructureInterfaces($entity_type);
        }
    }
    
    /**
     * Executes the data structure interfaces tests for the given entity type.
     *
     * @param string $entity_type
     *   The entity type to run the tests with.
     */
    protected function doTestDataStructureInterfaces($entity_type) {
        $entity = $this->createTestEntity($entity_type);
        // Test using the whole tree of typed data by navigating through the tree of
        // contained properties and getting all contained strings, limited by a
        // certain depth.
        $strings = [];
        $this->getContainedStrings($entity->getTypedData(), 0, $strings);
        // @todo: Once the user entity has defined properties this should contain
        // the user name and other user entity strings as well.
        $target_strings = [
            $entity->uuid->value,
            'en',
            $this->entityName,
            // Bundle name.
$entity->bundle(),
            $this->entityFieldText,
            // Field format.
NULL,
        ];
        if ($entity instanceof RevisionLogInterface) {
            // Adding empty string for revision message.
            $target_strings[] = '';
        }
        asort($strings);
        asort($target_strings);
        $this->assertEquals(array_values($target_strings), array_values($strings), new FormattableMarkup('%entity_type: All contained strings found.', [
            '%entity_type' => $entity_type,
        ]));
    }
    
    /**
     * Gets all contained strings recursively.
     */
    public function getContainedStrings(TypedDataInterface $wrapper, $depth, array &$strings) {
        if ($wrapper instanceof StringInterface) {
            $strings[] = $wrapper->getValue();
        }
        // Recurse until a certain depth is reached if possible.
        if ($depth < 7) {
            if ($wrapper instanceof ListInterface) {
                foreach ($wrapper as $item) {
                    $this->getContainedStrings($item, $depth + 1, $strings);
                }
            }
            elseif ($wrapper instanceof ComplexDataInterface) {
                foreach ($wrapper as $property) {
                    $this->getContainedStrings($property, $depth + 1, $strings);
                }
            }
        }
    }
    
    /**
     * Makes sure data types are correctly derived for all entity types.
     */
    public function testDataTypes() {
        $types = \Drupal::typedDataManager()->getDefinitions();
        foreach (entity_test_entity_types() as $entity_type) {
            $this->assertNotEmpty($types['entity:' . $entity_type]['class'], 'Entity data type registered.');
        }
        // Check bundle types are provided as well.
        entity_test_create_bundle('bundle');
        $types = \Drupal::typedDataManager()->getDefinitions();
        $this->assertNotEmpty($types['entity:entity_test:bundle']['class'], 'Entity bundle data type registered.');
    }
    
    /**
     * Tests a base field override on a non-existing base field.
     *
     * @see entity_test_entity_base_field_info_alter()
     */
    public function testBaseFieldNonExistingBaseField() {
        $this->entityTypeManager
            ->getStorage('node_type')
            ->create([
            'type' => 'page',
            'name' => 'page',
        ])
            ->save();
        \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
        $fields = \Drupal::service('entity_field.manager')->getFieldDefinitions('node', 'page');
        $override = $fields['status']->getConfig('page');
        $override->setLabel($this->randomString())
            ->save();
        \Drupal::state()->set('entity_test.node_remove_status_field', TRUE);
        \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
        $fields = \Drupal::service('entity_field.manager')->getFieldDefinitions('node', 'page');
        // A base field override on a non-existing base field should not cause a
        // field definition to come into existence.
        $this->assertFalse(isset($fields['status']), 'Node\'s status base field does not exist.');
    }
    
    /**
     * Tests creating a field override config for a bundle field.
     *
     * @see entity_test_entity_base_field_info_alter()
     */
    public function testFieldOverrideBundleField() {
        // First make sure the bundle field override in code, which is provided by
        // the test entity works.
        entity_test_create_bundle('some_test_bundle', 'Some test bundle', 'entity_test_field_override');
        $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('entity_test_field_override', 'entity_test_field_override');
        $this->assertEquals('The default description.', $field_definitions['name']->getDescription());
        $this->assertNull($field_definitions['name']->getTargetBundle());
        $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('entity_test_field_override', 'some_test_bundle');
        $this->assertEquals('Custom description.', $field_definitions['name']->getDescription());
        $this->assertEquals('some_test_bundle', $field_definitions['name']->getTargetBundle());
        // Now create a config override of the bundle field.
        $field_config = $field_definitions['name']->getConfig('some_test_bundle');
        $field_config->setTranslatable(FALSE);
        $field_config->save();
        // Make sure both overrides are present.
        \Drupal::service('entity_field.manager')->clearCachedFieldDefinitions();
        $field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('entity_test_field_override', 'some_test_bundle');
        $this->assertEquals('Custom description.', $field_definitions['name']->getDescription());
        $this->assertEquals('some_test_bundle', $field_definitions['name']->getTargetBundle());
        $this->assertFalse($field_definitions['name']->isTranslatable());
    }
    
    /**
     * Tests validation constraints provided by the Entity API.
     */
    public function testEntityConstraintValidation() {
        $entity = $this->createTestEntity('entity_test');
        $entity->save();
        // Create a reference field item and let it reference the entity.
        $definition = BaseFieldDefinition::create('entity_reference')->setLabel('Test entity')
            ->setSetting('target_type', 'entity_test');
        $reference_field = \Drupal::typedDataManager()->create($definition);
        $reference = $reference_field->appendItem([
            'entity' => $entity,
        ])
            ->get('entity');
        // Test validation the typed data object.
        $violations = $reference->validate();
        $this->assertEquals(0, $violations->count());
        // Test validating an entity of the wrong type.
        $user = $this->createUser();
        $user->save();
        $node = $node = Node::create([
            'type' => 'page',
            'uid' => $user->id(),
            'title' => $this->randomString(),
        ]);
        $reference->setValue($node);
        $violations = $reference->validate();
        $this->assertEquals(1, $violations->count());
        // Test bundle validation.
        NodeType::create([
            'type' => 'article',
        ])->save();
        $definition = BaseFieldDefinition::create('entity_reference')->setLabel('Test entity')
            ->setSetting('target_type', 'node')
            ->setSetting('handler_settings', [
            'target_bundles' => [
                'article' => 'article',
            ],
        ]);
        $reference_field = \Drupal::TypedDataManager()->create($definition);
        $reference_field->appendItem([
            'entity' => $node,
        ]);
        $violations = $reference_field->validate();
        $this->assertEquals(1, $violations->count());
        $node = Node::create([
            'type' => 'article',
            'uid' => $user->id(),
            'title' => $this->randomString(),
        ]);
        $node->save();
        $reference_field->entity = $node;
        $violations = $reference_field->validate();
        $this->assertEquals(0, $violations->count());
    }
    
    /**
     * Tests getting processed property values via a computed property.
     */
    public function testComputedProperties() {
        // All entity variations have to have the same results.
        foreach (entity_test_entity_types() as $entity_type) {
            $this->doTestComputedProperties($entity_type);
        }
    }
    
    /**
     * Tests all the interaction points of a computed field.
     */
    public function testComputedFields() {
        $this->installEntitySchema('entity_test_computed_field');
        \Drupal::state()->set('entity_test_computed_field_item_list_value', [
            'foo computed',
        ]);
        // Check that the values are not computed unnecessarily during the lifecycle
        // of an entity when the field is not interacted with directly.
        \Drupal::state()->set('computed_test_field_execution', 0);
        $entity = EntityTestComputedField::create([]);
        $this->assertSame(0, \Drupal::state()->get('computed_test_field_execution', 0));
        $entity->name->value = $this->randomString();
        $this->assertSame(0, \Drupal::state()->get('computed_test_field_execution', 0));
        $entity->save();
        $this->assertSame(0, \Drupal::state()->get('computed_test_field_execution', 0));
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::getValue().
        \Drupal::state()->set('computed_test_field_execution', 0);
        $entity = EntityTestComputedField::create([]);
        $this->assertSame([
            [
                'value' => 'foo computed',
            ],
        ], $entity->computed_string_field
            ->getValue());
        // Check that the values are only computed once.
        $this->assertSame(1, \Drupal::state()->get('computed_test_field_execution', 0));
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::setValue(). This also
        // checks that a subsequent getter does not try to re-compute the value.
        \Drupal::state()->set('computed_test_field_execution', 0);
        $entity = EntityTestComputedField::create([]);
        $entity->computed_string_field
            ->setValue([
            [
                'value' => 'foo computed 1',
            ],
            [
                'value' => 'foo computed 2',
            ],
        ]);
        $this->assertSame([
            [
                'value' => 'foo computed 1',
            ],
            [
                'value' => 'foo computed 2',
            ],
        ], $entity->computed_string_field
            ->getValue());
        // Check that the values have not been computed when they were explicitly
        // set.
        $this->assertSame(0, \Drupal::state()->get('computed_test_field_execution', 0));
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::getString().
        $entity = EntityTestComputedField::create([]);
        $this->assertSame('foo computed', $entity->computed_string_field
            ->getString());
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::get().
        $entity = EntityTestComputedField::create([]);
        $this->assertSame('foo computed', $entity->computed_string_field
            ->get(0)->value);
        $this->assertEmpty($entity->computed_string_field
            ->get(1));
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::set().
        $entity = EntityTestComputedField::create([]);
        $entity->computed_string_field
            ->set(1, 'foo computed 1');
        $this->assertSame('foo computed', $entity->computed_string_field[0]->value);
        $this->assertSame('foo computed 1', $entity->computed_string_field[1]->value);
        $entity->computed_string_field
            ->set(0, 'foo computed 0');
        $this->assertSame('foo computed 0', $entity->computed_string_field[0]->value);
        $this->assertSame('foo computed 1', $entity->computed_string_field[1]->value);
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::appendItem().
        $entity = EntityTestComputedField::create([]);
        $entity->computed_string_field
            ->appendItem('foo computed 1');
        $this->assertSame('foo computed', $entity->computed_string_field[0]->value);
        $this->assertSame('foo computed 1', $entity->computed_string_field[1]->value);
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::removeItem().
        $entity = EntityTestComputedField::create([]);
        $entity->computed_string_field
            ->removeItem(0);
        $this->assertTrue($entity->computed_string_field
            ->isEmpty());
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::isEmpty().
        \Drupal::state()->set('entity_test_computed_field_item_list_value', []);
        $entity = EntityTestComputedField::create([]);
        $this->assertTrue($entity->computed_string_field
            ->isEmpty());
        \Drupal::state()->set('entity_test_computed_field_item_list_value', [
            'foo computed',
        ]);
        $entity = EntityTestComputedField::create([]);
        $this->assertFalse($entity->computed_string_field
            ->isEmpty());
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::filter().
        $filter_callback = function ($item) {
            return !$item->isEmpty();
        };
        $entity = EntityTestComputedField::create([]);
        $entity->computed_string_field
            ->filter($filter_callback);
        $this->assertCount(1, $entity->computed_string_field);
        // Add an empty item to the list and check that it is filtered out.
        $entity->computed_string_field
            ->appendItem();
        $entity->computed_string_field
            ->filter($filter_callback);
        $this->assertCount(1, $entity->computed_string_field);
        // Add a non-empty item to the list and check that it is not filtered out.
        $entity->computed_string_field
            ->appendItem('foo computed 1');
        $entity->computed_string_field
            ->filter($filter_callback);
        $this->assertCount(2, $entity->computed_string_field);
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::offsetExists().
        $entity = EntityTestComputedField::create([]);
        $this->assertTrue($entity->computed_string_field
            ->offsetExists(0));
        $this->assertFalse($entity->computed_string_field
            ->offsetExists(1));
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::getIterator().
        $entity = EntityTestComputedField::create([]);
        foreach ($entity->computed_string_field as $delta => $item) {
            $this->assertSame('foo computed', $item->value);
        }
        // Test \Drupal\Core\TypedData\ComputedItemListTrait::count().
        $entity = EntityTestComputedField::create([]);
        $this->assertCount(1, $entity->computed_string_field);
        // Check that computed items are not auto-created when they have no values.
        \Drupal::state()->set('entity_test_computed_field_item_list_value', []);
        $entity = EntityTestComputedField::create([]);
        $this->assertCount(0, $entity->computed_string_field);
        // Test \Drupal\Core\Field\FieldItemList::equals() for a computed field.
        \Drupal::state()->set('entity_test_computed_field_item_list_value', [
            'foo computed',
        ]);
        $entity = EntityTestComputedField::create([]);
        $computed_item_list1 = $entity->computed_string_field;
        $entity = EntityTestComputedField::create([]);
        $computed_item_list2 = $entity->computed_string_field;
        $this->assertTrue($computed_item_list1->equals($computed_item_list2));
        $computed_item_list2->value = 'foo computed 2';
        $this->assertFalse($computed_item_list1->equals($computed_item_list2));
    }
    
    /**
     * Tests an entity reference computed field.
     */
    public function testEntityReferenceComputedField() {
        $this->installEntitySchema('entity_test_computed_field');
        // Create 2 entities to be referenced.
        $ref1 = EntityTest::create([
            'name' => 'foo',
            'type' => 'bar',
        ]);
        $ref1->save();
        $ref2 = EntityTest::create([
            'name' => 'baz',
            'type' => 'bar',
        ]);
        $ref2->save();
        \Drupal::state()->set('entity_test_reference_computed_target_ids', [
            $ref1->id(),
            $ref2->id(),
        ]);
        $entity = EntityTestComputedField::create([]);
        $entity->save();
        
        /** @var \Drupal\entity_test\Plugin\Field\ComputedReferenceTestFieldItemList $field */
        $field = $entity->get('computed_reference_field');
        
        /** @var \Drupal\Core\Entity\EntityInterface[] $referenced_entities */
        $referenced_entities = $field->referencedEntities();
        // Check that ::referencedEntities() is working with computed fields.
        $this->assertEquals($ref1->id(), $referenced_entities[0]->id());
        $this->assertEquals($ref2->id(), $referenced_entities[1]->id());
    }
    
    /**
     * Executes the computed properties tests for the given entity type.
     *
     * @param string $entity_type
     *   The entity type to run the tests with.
     */
    protected function doTestComputedProperties($entity_type) {
        $entity = $this->createTestEntity($entity_type);
        $entity->field_test_text->value = "The <strong>text</strong> text to filter.";
        $entity->field_test_text->format = filter_default_format();
        $target = "<p>The &lt;strong&gt;text&lt;/strong&gt; text to filter.</p>\n";
        $this->assertEquals($target, $entity->field_test_text->processed, new FormattableMarkup('%entity_type: Text is processed with the default filter.', [
            '%entity_type' => $entity_type,
        ]));
        // Save and load entity and make sure it still works.
        $entity->save();
        $entity = $this->container
            ->get('entity_type.manager')
            ->getStorage($entity_type)
            ->load($entity->id());
        $this->assertEquals($target, $entity->field_test_text->processed, new FormattableMarkup('%entity_type: Text is processed with the default filter.', [
            '%entity_type' => $entity_type,
        ]));
    }
    
    /**
     * Tests explicit entity ID assignment.
     */
    public function testEntityIdAssignment() {
        $entity_type = 'entity_test';
        
        /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
        $storage = $this->container
            ->get('entity_type.manager')
            ->getStorage($entity_type);
        // Check that an ID can be explicitly assigned on creation.
        
        /** @var \Drupal\Core\Entity\ContentEntityInterface $entity */
        $entity = $this->createTestEntity($entity_type);
        $entity_id = 3;
        $entity->set('id', $entity_id);
        $this->assertSame($entity_id, $entity->id());
        $storage->save($entity);
        $entity = $storage->loadUnchanged($entity->id());
        $this->assertInstanceOf(ContentEntityInterface::class, $entity);
        // Check that an explicitly-assigned ID is preserved on update.
        $storage->save($entity);
        $entity = $storage->loadUnchanged($entity->id());
        $this->assertInstanceOf(ContentEntityInterface::class, $entity);
        // Check that an ID cannot be explicitly assigned on update.
        $this->expectException(EntityStorageException::class);
        $entity->set('id', $entity_id + 1);
        $storage->save($entity);
    }

}

Members

Title Sort descending Deprecated Modifiers Object type Summary Member alias Overriden Title Overrides
AssertContentTrait::$content protected property The current raw content.
AssertContentTrait::$drupalSettings protected property The drupalSettings value from the current raw $content.
AssertContentTrait::$elements protected property The XML structure parsed from the current raw $content. 1
AssertContentTrait::$plainTextContent protected property The plain-text content of raw $content (text nodes).
AssertContentTrait::assertEscaped protected function Passes if the raw text IS found escaped on the loaded page, fail otherwise.
AssertContentTrait::assertField protected function Asserts that a field exists with the given name or ID.
AssertContentTrait::assertFieldById protected function Asserts that a field exists with the given ID and value.
AssertContentTrait::assertFieldByName protected function Asserts that a field exists with the given name and value.
AssertContentTrait::assertFieldByXPath protected function Asserts that a field exists in the current page by the given XPath.
AssertContentTrait::assertFieldChecked protected function Asserts that a checkbox field in the current page is checked.
AssertContentTrait::assertFieldsByValue protected function Asserts that a field exists in the current page with a given Xpath result.
AssertContentTrait::assertLink protected function Passes if a link with the specified label is found.
AssertContentTrait::assertLinkByHref protected function Passes if a link containing a given href (part) is found.
AssertContentTrait::assertNoDuplicateIds protected function Asserts that each HTML ID is used for just a single element.
AssertContentTrait::assertNoEscaped protected function Passes if raw text IS NOT found escaped on loaded page, fail otherwise.
AssertContentTrait::assertNoField protected function Asserts that a field does not exist with the given name or ID.
AssertContentTrait::assertNoFieldById protected function Asserts that a field does not exist with the given ID and value.
AssertContentTrait::assertNoFieldByName protected function Asserts that a field does not exist with the given name and value.
AssertContentTrait::assertNoFieldByXPath protected function Asserts that a field does not exist or its value does not match, by XPath.
AssertContentTrait::assertNoFieldChecked protected function Asserts that a checkbox field in the current page is not checked.
AssertContentTrait::assertNoLink protected function Passes if a link with the specified label is not found.
AssertContentTrait::assertNoLinkByHref protected function Passes if a link containing a given href (part) is not found.
AssertContentTrait::assertNoLinkByHrefInMainRegion protected function Passes if a link containing a given href is not found in the main region.
AssertContentTrait::assertNoOption protected function Asserts that a select option in the current page does not exist.
AssertContentTrait::assertNoOptionSelected protected function Asserts that a select option in the current page is not checked.
AssertContentTrait::assertNoPattern protected function Triggers a pass if the perl regex pattern is not found in raw content.
AssertContentTrait::assertNoRaw protected function Passes if the raw text is NOT found on the loaded page, fail otherwise.
AssertContentTrait::assertNoText protected function Passes if the page (with HTML stripped) does not contains the text.
AssertContentTrait::assertNoTitle protected function Pass if the page title is not the given string.
AssertContentTrait::assertNoUniqueText protected function Passes if the text is found MORE THAN ONCE on the text version of the page.
AssertContentTrait::assertOption protected function Asserts that a select option in the current page exists.
AssertContentTrait::assertOptionByText protected function Asserts that a select option with the visible text exists.
AssertContentTrait::assertOptionSelected protected function Asserts that a select option in the current page is checked.
AssertContentTrait::assertOptionSelectedWithDrupalSelector protected function Asserts that a select option in the current page is checked.
AssertContentTrait::assertOptionWithDrupalSelector protected function Asserts that a select option in the current page exists.
AssertContentTrait::assertPattern protected function Triggers a pass if the Perl regex pattern is found in the raw content.
AssertContentTrait::assertRaw protected function Passes if the raw text IS found on the loaded page, fail otherwise.
AssertContentTrait::assertText protected function Passes if the page (with HTML stripped) contains the text.
AssertContentTrait::assertTextHelper protected function Helper for assertText and assertNoText.
AssertContentTrait::assertTextPattern protected function Asserts that a Perl regex pattern is found in the plain-text content.
AssertContentTrait::assertThemeOutput protected function Asserts themed output.
AssertContentTrait::assertTitle protected function Pass if the page title is the given string.
AssertContentTrait::assertUniqueText protected function Passes if the text is found ONLY ONCE on the text version of the page.
AssertContentTrait::assertUniqueTextHelper protected function Helper for assertUniqueText and assertNoUniqueText.
AssertContentTrait::buildXPathQuery protected function Builds an XPath query.
AssertContentTrait::constructFieldXpath protected function Helper: Constructs an XPath for the given set of attributes and value.
AssertContentTrait::cssSelect protected function Searches elements using a CSS selector in the raw content.
AssertContentTrait::getAllOptions protected function Get all option elements, including nested options, in a select.
AssertContentTrait::getDrupalSettings protected function Gets the value of drupalSettings for the currently-loaded page.
AssertContentTrait::getRawContent protected function Gets the current raw content.
AssertContentTrait::getSelectedItem protected function Get the selected value from a select field.
AssertContentTrait::getTextContent protected function Retrieves the plain-text content from the current raw content.
AssertContentTrait::getUrl protected function Get the current URL from the cURL handler. 1
AssertContentTrait::parse protected function Parse content returned from curlExec using DOM and SimpleXML.
AssertContentTrait::removeWhiteSpace protected function Removes all white-space between HTML tags from the raw content.
AssertContentTrait::setDrupalSettings protected function Sets the value of drupalSettings for the currently-loaded page.
AssertContentTrait::setRawContent protected function Sets the raw content (e.g. HTML).
AssertContentTrait::xpath protected function Performs an xpath search on the contents of the internal browser.
AssertLegacyTrait::assert Deprecated protected function
AssertLegacyTrait::assertEqual Deprecated protected function
AssertLegacyTrait::assertIdentical Deprecated protected function
AssertLegacyTrait::assertIdenticalObject Deprecated protected function
AssertLegacyTrait::assertNotEqual Deprecated protected function
AssertLegacyTrait::assertNotIdentical Deprecated protected function
AssertLegacyTrait::pass Deprecated protected function
AssertLegacyTrait::verbose Deprecated protected function
ConfigTestTrait::configImporter protected function Returns a ConfigImporter object to import test configuration.
ConfigTestTrait::copyConfig protected function Copies configuration objects from source storage to target storage.
EntityFieldTest::$entityFieldText protected property
EntityFieldTest::$entityName protected property
EntityFieldTest::$entityUser protected property
EntityFieldTest::$modules protected static property Modules to enable. Overrides EntityKernelTestBase::$modules
EntityFieldTest::createTestEntity protected function Creates a test entity.
EntityFieldTest::doTestComputedProperties protected function Executes the computed properties tests for the given entity type.
EntityFieldTest::doTestDataStructureInterfaces protected function Executes the data structure interfaces tests for the given entity type.
EntityFieldTest::doTestIntrospection protected function Executes the introspection tests for the given entity type.
EntityFieldTest::doTestIterator protected function Executes the iterator tests for the given entity type.
EntityFieldTest::doTestReadWrite protected function Executes the read write test set for a defined entity type.
EntityFieldTest::doTestSave protected function Executes the save tests for the given entity type.
EntityFieldTest::getContainedStrings public function Gets all contained strings recursively.
EntityFieldTest::setUp protected function Overrides EntityKernelTestBase::setUp
EntityFieldTest::testBaseFieldNonExistingBaseField public function Tests a base field override on a non-existing base field.
EntityFieldTest::testComputedFields public function Tests all the interaction points of a computed field.
EntityFieldTest::testComputedProperties public function Tests getting processed property values via a computed property.
EntityFieldTest::testDataStructureInterfaces public function Tests working with the entity based upon the TypedData API.
EntityFieldTest::testDataTypes public function Makes sure data types are correctly derived for all entity types.
EntityFieldTest::testEntityConstraintValidation public function Tests validation constraints provided by the Entity API.
EntityFieldTest::testEntityIdAssignment public function Tests explicit entity ID assignment.
EntityFieldTest::testEntityReferenceComputedField public function Tests an entity reference computed field.
EntityFieldTest::testFieldOverrideBundleField public function Tests creating a field override config for a bundle field.
EntityFieldTest::testIntrospection public function Tests introspection and getting metadata upfront.
EntityFieldTest::testIterator public function Tests iterating over properties.
EntityFieldTest::testReadWrite public function Tests reading and writing properties and field items.
EntityFieldTest::testSave public function Tries to save and load an entity again.
EntityKernelTestBase::$entityTypeManager protected property The entity type manager service. 1
EntityKernelTestBase::$generatedIds protected property A list of generated identifiers.
EntityKernelTestBase::$state protected property The state service.
EntityKernelTestBase::createUser protected function Creates a user.
EntityKernelTestBase::generateRandomEntityId protected function Generates a random ID avoiding collisions.
EntityKernelTestBase::getHooksInfo protected function Returns the entity_test hook invocation info.
EntityKernelTestBase::installModule protected function Installs a module and refreshes services.
EntityKernelTestBase::refreshServices protected function Refresh services. 1
EntityKernelTestBase::reloadEntity protected function Reloads the given entity from the storage and returns it.
EntityKernelTestBase::uninstallModule protected function Uninstalls a module and refreshes services.
ExtensionListTestTrait::getModulePath protected function Gets the path for the specified module.
ExtensionListTestTrait::getThemePath protected function Gets the path for the specified theme.
KernelTestBase::$backupGlobals protected property Back up and restore any global variables that may be changed by tests.
KernelTestBase::$backupStaticAttributes protected property Back up and restore static class properties that may be changed by tests.
KernelTestBase::$backupStaticAttributesBlacklist protected property Contains a few static class properties for performance.
KernelTestBase::$classLoader protected property
KernelTestBase::$configImporter protected property @todo Move into Config test base class. 6
KernelTestBase::$configSchemaCheckerExclusions protected static property An array of config object names that are excluded from schema checking.
KernelTestBase::$container protected property
KernelTestBase::$databasePrefix protected property
KernelTestBase::$keyValue protected property The key_value service that must persist between container rebuilds.
KernelTestBase::$preserveGlobalState protected property Do not forward any global state from the parent process to the processes
that run the actual tests.
KernelTestBase::$root protected property The app root.
KernelTestBase::$runTestInSeparateProcess protected property Kernel tests are run in separate processes because they allow autoloading
of code from extensions. Running the test in a separate process isolates
this behavior from other tests. Subclasses should not override this
property.
KernelTestBase::$siteDirectory protected property
KernelTestBase::$strictConfigSchema protected property Set to TRUE to strict check all configuration saved. 7
KernelTestBase::$vfsRoot protected property The virtual filesystem root directory.
KernelTestBase::assertPostConditions protected function 1
KernelTestBase::bootEnvironment protected function Bootstraps a basic test environment.
KernelTestBase::bootKernel private function Bootstraps a kernel for a test.
KernelTestBase::config protected function Configuration accessor for tests. Returns non-overridden configuration.
KernelTestBase::disableModules protected function Disables modules for this test.
KernelTestBase::enableModules protected function Enables modules for this test.
KernelTestBase::getConfigSchemaExclusions protected function Gets the config schema exclusions for this test.
KernelTestBase::getDatabaseConnectionInfo protected function Returns the Database connection info to be used for this test. 3
KernelTestBase::getDatabasePrefix public function
KernelTestBase::getExtensionsForModules private function Returns Extension objects for $modules to enable.
KernelTestBase::getModulesToEnable private static function Returns the modules to enable for this test.
KernelTestBase::initFileCache protected function Initializes the FileCache component.
KernelTestBase::installConfig protected function Installs default configuration for a given list of modules.
KernelTestBase::installEntitySchema protected function Installs the storage schema for a specific entity type.
KernelTestBase::installSchema protected function Installs database tables from a module schema definition.
KernelTestBase::register public function Registers test-specific services. Overrides ServiceProviderInterface::register 26
KernelTestBase::render protected function Renders a render array. 1
KernelTestBase::setInstallProfile protected function Sets the install profile and rebuilds the container to update it.
KernelTestBase::setSetting protected function Sets an in-memory Settings variable.
KernelTestBase::setUpBeforeClass public static function 1
KernelTestBase::setUpFilesystem protected function Sets up the filesystem, so things like the file directory. 3
KernelTestBase::stop protected function Stops test execution.
KernelTestBase::tearDown protected function 5
KernelTestBase::tearDownCloseDatabaseConnection public function @after
KernelTestBase::vfsDump protected function Dumps the current state of the virtual filesystem to STDOUT.
KernelTestBase::__sleep public function Prevents serializing any properties.
PhpUnitWarnings::$deprecationWarnings private static property Deprecation warnings from PHPUnit to raise with @trigger_error().
PhpUnitWarnings::addWarning public function Converts PHPUnit deprecation warnings to E_USER_DEPRECATED.
RandomGeneratorTrait::$randomGenerator protected property The random generator.
RandomGeneratorTrait::getRandomGenerator protected function Gets the random generator for the utility methods.
RandomGeneratorTrait::randomMachineName protected function Generates a unique random string containing letters and numbers. 1
RandomGeneratorTrait::randomObject public function Generates a random PHP object.
RandomGeneratorTrait::randomString public function Generates a pseudo-random string of ASCII characters of codes 32 to 126.
RandomGeneratorTrait::randomStringValidate public function Callback for random string validation.
StorageCopyTrait::replaceStorageContents protected static function Copy the configuration from one storage to another and remove stale items.
TestRequirementsTrait::checkModuleRequirements private function Checks missing module requirements.
TestRequirementsTrait::checkRequirements protected function Check module requirements for the Drupal use case.
TestRequirementsTrait::getDrupalRoot protected static function Returns the Drupal root directory.
UserCreationTrait::checkPermissions protected function Checks whether a given list of permission names is valid. Aliased as: drupalCheckPermissions
UserCreationTrait::createAdminRole protected function Creates an administrative role. Aliased as: drupalCreateAdminRole
UserCreationTrait::createRole protected function Creates a role with specified permissions. Aliased as: drupalCreateRole
UserCreationTrait::createUser protected function Create a user with a given set of permissions. Aliased as: drupalCreateUser
UserCreationTrait::grantPermissions protected function Grant permissions to a user role. Aliased as: drupalGrantPermissions
UserCreationTrait::setCurrentUser protected function Switch the current logged in user. Aliased as: drupalSetCurrentUser
UserCreationTrait::setUpCurrentUser protected function Creates a random user account and sets it as current user. Aliased as: drupalSetUpCurrentUser

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.