diff --git a/core/modules/views/tests/src/Kernel/Entity/EntityViewsDataTest.php b/core/modules/views/tests/src/Kernel/Entity/EntityViewsDataTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..6bab4cfdbdec1756c16a56aa2bf30df6f42f098a
--- /dev/null
+++ b/core/modules/views/tests/src/Kernel/Entity/EntityViewsDataTest.php
@@ -0,0 +1,821 @@
+<?php
+
+namespace Drupal\Tests\views\Kernel\Entity;
+
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Config\Entity\ConfigEntityBase;
+use Drupal\Core\Config\Entity\ConfigEntityType;
+use Drupal\Core\Entity\ContentEntityBase;
+use Drupal\Core\Entity\ContentEntityType;
+use Drupal\Core\Entity\EntityTypeInterface;
+use Drupal\Core\Field\BaseFieldDefinition;
+use Drupal\KernelTests\KernelTestBase;
+use Drupal\views\EntityViewsData;
+
+/**
+ * Tests entity views data.
+ *
+ * @coversDefaultClass \Drupal\views\EntityViewsData
+ * @group views
+ */
+class EntityViewsDataTest extends KernelTestBase {
+
+  /**
+   * The entity type manager.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
+   */
+  protected $entityTypeManager;
+
+  /**
+   * The base entity type definition, which some tests modify.
+   *
+   * Uses a custom class which allows changing entity keys.
+   *
+   * @var \Drupal\Tests\views\Kernel\Entity\TestEntityType
+   */
+  protected $baseEntityType;
+
+  /**
+   * The common base fields for test entity types.
+   *
+   * @var \Drupal\Core\Field\BaseFieldDefinition[]
+   */
+  protected $commonBaseFields;
+
+  /**
+   * Modules to enable.
+   *
+   * @var array
+   */
+  protected static $modules = [
+    'user',
+    'system',
+    'field',
+    'text',
+    'filter',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+
+    $this->entityTypeManager = $this->container->get('entity_type.manager');
+
+    // A common entity type definition. Tests may change this prior to passing
+    // it to setUpEntityType().
+    $this->baseEntityType = new TestEntityType([
+      // A normal entity type would have its class picked up during discovery,
+      // but as we're mocking this without an annotation we have to specify it.
+      'class' => ViewsTestEntity::class,
+      'base_table' => 'entity_test',
+      'id' => 'entity_test',
+      'label' => 'Entity test',
+      'entity_keys' => [
+        'uuid' => 'uuid',
+        'id' => 'id',
+        'langcode' => 'langcode',
+        'bundle' => 'type',
+        'revision' => 'revision_id',
+      ],
+      'handlers' => [
+        'views_data' => EntityViewsData::class,
+      ],
+      'provider' => 'entity_test',
+      'list_cache_contexts' => ['entity_test_list_cache_context'],
+    ]);
+
+    // Base fields for the test entity types.
+    $this->commonBaseFields['name'] = BaseFieldDefinition::create('string')
+      ->setLabel(t('Name'))
+      ->setDescription(t('The name of the test entity.'))
+      ->setTranslatable(TRUE)
+      ->setSetting('max_length', 32);
+
+    $this->commonBaseFields['created'] = BaseFieldDefinition::create('created')
+      ->setLabel(t('Authored on'))
+      ->setDescription(t('Time the entity was created'))
+      ->setTranslatable(TRUE);
+
+    $this->commonBaseFields['user_id'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel(t('User ID'))
+      ->setDescription(t('The ID of the associated user.'))
+      ->setSetting('target_type', 'user')
+      ->setSetting('handler', 'default')
+      // Default EntityTest entities to have the root user as the owner, to
+      // simplify testing.
+      ->setDefaultValue([0 => ['target_id' => 1]])
+      ->setTranslatable(TRUE);
+
+    // Add a description field. This example comes from the taxonomy Term
+    // entity.
+    $this->commonBaseFields['description'] = BaseFieldDefinition::create('text_long')
+      ->setLabel('Description')
+      ->setDescription('A description of the term.')
+      ->setTranslatable(TRUE);
+
+    // Add a URL field; this example is from the Comment entity.
+    $this->commonBaseFields['homepage'] = BaseFieldDefinition::create('uri')
+      ->setLabel('Homepage')
+      ->setDescription("The comment author's home page address.")
+      ->setTranslatable(TRUE)
+      ->setSetting('max_length', 255);
+
+    // A base field with cardinality > 1
+    $this->commonBaseFields['string'] = BaseFieldDefinition::create('string')
+      ->setLabel('Strong')
+      ->setTranslatable(TRUE)
+      ->setCardinality(2);
+
+    // Set up the basic 'entity_test' entity type. This is used by several
+    // tests; others customize it and the base fields.
+    $this->setUpEntityType($this->baseEntityType, $this->commonBaseFields);
+  }
+
+  /**
+   * Mocks an entity type and its base fields.
+   *
+   * This works by:
+   * - inserting the entity type definition into the entity type manager's cache
+   * - setting the base fields on the ViewsTestEntity class as a static property
+   *   for its baseFieldsDefinitions() method to use.
+   *
+   * @param \Drupal\Core\Entity\EntityTypeInterface $definition
+   *   An entity type definition to add to the entity type manager.
+   * @param \Drupal\Core\Field\BaseFieldDefinition[] $base_fields
+   *   An array of base field definitions
+   */
+  protected function setUpEntityType(EntityTypeInterface $definition, array $base_fields = []) {
+    // Replace the cache backend in the entity type manager so it returns
+    // our test entity type in addition to the existing ones.
+    $definitions = $this->entityTypeManager->getDefinitions();
+    $definitions[$definition->id()] = $definition;
+
+    $cache_backend = $this->prophesize(CacheBackendInterface::class);
+    $cache_data = new \StdClass();
+    $cache_data->data = $definitions;
+    $cache_backend->get('entity_type')->willReturn($cache_data);
+    $this->entityTypeManager->setCacheBackend($cache_backend->reveal(), 'entity_type', ['entity_types']);
+    $this->entityTypeManager->clearCachedDefinitions();
+
+    if ($base_fields) {
+      ViewsTestEntity::setMockedBaseFieldDefinitions($definition->id(), $base_fields);
+    }
+  }
+
+  /**
+   * Tests base tables.
+   */
+  public function testBaseTables() {
+    $data = $this->entityTypeManager->getHandler('entity_test', 'views_data')->getViewsData();
+
+    $this->assertEquals('entity_test', $data['entity_test']['table']['entity type']);
+    $this->assertEquals(FALSE, $data['entity_test']['table']['entity revision']);
+    $this->assertEquals('Entity test', $data['entity_test']['table']['group']);
+    $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
+
+    $this->assertEquals('id', $data['entity_test']['table']['base']['field']);
+    $this->assertEquals(['entity_test_list_cache_context'], $data['entity_test']['table']['base']['cache_contexts']);
+    $this->assertEquals('Entity test', $data['entity_test']['table']['base']['title']);
+
+    // TODO: change these to assertArrayNotHasKey().
+    $this->assertFalse(isset($data['entity_test']['table']['defaults']));
+
+    $this->assertFalse(isset($data['entity_test_mul_property_data']));
+    $this->assertFalse(isset($data['revision_table']));
+    $this->assertFalse(isset($data['revision_data_table']));
+  }
+
+  /**
+   * Tests data_table support.
+   */
+  public function testDataTable() {
+    $entity_type = $this->baseEntityType
+      ->set('data_table', 'entity_test_mul_property_data')
+      ->set('id', 'entity_test_mul')
+      ->set('translatable', TRUE)
+      ->setKey('label', 'label');
+
+    $this->setUpEntityType($entity_type);
+
+    // Tests the join definition between the base and the data table.
+    $data = $this->entityTypeManager->getHandler('entity_test_mul', 'views_data')->getViewsData();
+    // TODO: change the base table in the entity type definition to match the
+    // changed entity ID.
+    $base_views_data = $data['entity_test'];
+
+    // Ensure that the base table is set to the data table.
+    $this->assertEquals('id', $data['entity_test_mul_property_data']['table']['base']['field']);
+    $this->assertEquals('Entity test', $data['entity_test_mul_property_data']['table']['base']['title']);
+    $this->assertFalse(isset($data['entity_test']['table']['base']));
+
+    $this->assertEquals('entity_test_mul', $data['entity_test_mul_property_data']['table']['entity type']);
+    $this->assertEquals(FALSE, $data['entity_test_mul_property_data']['table']['entity revision']);
+    $this->assertEquals('Entity test', $data['entity_test_mul_property_data']['table']['group']);
+    $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
+    $this->assertEquals(['field' => 'label', 'table' => 'entity_test_mul_property_data'], $data['entity_test_mul_property_data']['table']['base']['defaults']);
+
+    // Ensure the join information is set up properly.
+    $this->assertCount(1, $base_views_data['table']['join']);
+    $this->assertEquals(['entity_test_mul_property_data' => ['left_field' => 'id', 'field' => 'id', 'type' => 'INNER']], $base_views_data['table']['join']);
+    $this->assertFalse(isset($data['revision_table']));
+    $this->assertFalse(isset($data['revision_data_table']));
+  }
+
+  /**
+   * Tests revision table without data table support.
+   */
+  public function testRevisionTableWithoutDataTable() {
+    $entity_type = $this->baseEntityType
+      ->set('revision_table', 'entity_test_mulrev_revision')
+      ->set('revision_data_table', NULL)
+      ->set('id', 'entity_test_mulrev')
+      ->setKey('revision', 'revision_id');
+
+    $this->setUpEntityType($entity_type);
+
+    $data = $this->entityTypeManager->getHandler('entity_test_mulrev', 'views_data')->getViewsData();
+
+    $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_revision']['table']['base']['title']);
+    $this->assertEquals('revision_id', $data['entity_test_mulrev_revision']['table']['base']['field']);
+
+    $this->assertEquals(FALSE, $data['entity_test']['table']['entity revision']);
+    $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_revision']['table']['entity type']);
+    $this->assertEquals(TRUE, $data['entity_test_mulrev_revision']['table']['entity revision']);
+    $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_revision']['table']['entity type']);
+    $this->assertEquals(TRUE, $data['entity_test_mulrev_revision']['table']['entity revision']);
+
+    $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
+    $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
+
+    // Ensure the join information is set up properly.
+    // Tests the join definition between the base and the revision table.
+    $revision_data = $data['entity_test_mulrev_revision'];
+    $this->assertCount(1, $revision_data['table']['join']);
+    $this->assertEquals(['entity_test' => ['left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER']], $revision_data['table']['join']);
+    $this->assertFalse(isset($data['data_table']));
+  }
+
+  /**
+   * Tests revision table with data table support.
+   */
+  public function testRevisionTableWithRevisionDataTableAndDataTable() {
+    $entity_type = $this->baseEntityType
+      ->set('data_table', 'entity_test_mul_property_data')
+      ->set('revision_table', 'entity_test_mulrev_revision')
+      ->set('revision_data_table', 'entity_test_mulrev_property_revision')
+      ->set('id', 'entity_test_mulrev')
+      ->set('translatable', TRUE)
+      ->setKey('revision', 'revision_id');
+    $this->setUpEntityType($entity_type);
+
+    $data = $this->entityTypeManager->getHandler('entity_test_mulrev', 'views_data')->getViewsData();
+
+    $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_property_revision']['table']['base']['title']);
+    $this->assertEquals('revision_id', $data['entity_test_mulrev_property_revision']['table']['base']['field']);
+    $this->assertFalse(isset($data['entity_test_mulrev_revision']['table']['base']));
+
+    $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_property_revision']['table']['entity type']);
+    $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
+    $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
+
+    // Ensure the join information is set up properly.
+    // Tests the join definition between the base and the revision table.
+    $revision_field_data = $data['entity_test_mulrev_property_revision'];
+    $this->assertCount(1, $revision_field_data['table']['join']);
+    $this->assertEquals([
+      'entity_test_mul_property_data' => [
+        'left_field' => 'revision_id',
+        'field' => 'revision_id',
+        'type' => 'INNER',
+      ],
+    ], $revision_field_data['table']['join']);
+
+    $revision_base_data = $data['entity_test_mulrev_revision'];
+    $this->assertCount(1, $revision_base_data['table']['join']);
+    $this->assertEquals([
+      'entity_test_mulrev_property_revision' => [
+        'left_field' => 'revision_id',
+        'field' => 'revision_id',
+        'type' => 'INNER',
+      ],
+    ], $revision_base_data['table']['join']);
+
+    $this->assertFalse(isset($data['data_table']));
+  }
+
+  /**
+   * Tests revision table with data table support.
+   */
+  public function testRevisionTableWithRevisionDataTable() {
+    $entity_type = $this->baseEntityType
+      ->set('revision_table', 'entity_test_mulrev_revision')
+      ->set('revision_data_table', 'entity_test_mulrev_property_revision')
+      ->set('id', 'entity_test_mulrev')
+      ->set('translatable', TRUE)
+      ->setKey('revision', 'revision_id');
+    $this->setUpEntityType($entity_type);
+
+    $data = $this->entityTypeManager->getHandler('entity_test_mulrev', 'views_data')->getViewsData();
+
+    $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_property_revision']['table']['base']['title']);
+    $this->assertEquals('revision_id', $data['entity_test_mulrev_property_revision']['table']['base']['field']);
+    $this->assertFalse(isset($data['entity_test_mulrev_revision']['table']['base']));
+
+    $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_property_revision']['table']['entity type']);
+    $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
+    $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
+
+    // Ensure the join information is set up properly.
+    // Tests the join definition between the base and the revision table.
+    $revision_field_data = $data['entity_test_mulrev_property_revision'];
+    $this->assertCount(1, $revision_field_data['table']['join']);
+    $this->assertEquals([
+      'entity_test_mulrev_field_data' => [
+        'left_field' => 'revision_id',
+        'field' => 'revision_id',
+        'type' => 'INNER',
+      ],
+    ], $revision_field_data['table']['join']);
+
+    $revision_base_data = $data['entity_test_mulrev_revision'];
+    $this->assertCount(1, $revision_base_data['table']['join']);
+    $this->assertEquals([
+      'entity_test_mulrev_property_revision' => [
+        'left_field' => 'revision_id',
+        'field' => 'revision_id',
+        'type' => 'INNER',
+      ],
+    ], $revision_base_data['table']['join']);
+    $this->assertFalse(isset($data['data_table']));
+  }
+
+  /**
+   * Tests fields on the base table.
+   */
+  public function testBaseTableFields() {
+    $data = $this->entityTypeManager->getHandler('entity_test', 'views_data')->getViewsData();
+
+    $this->assertNumericField($data['entity_test']['id']);
+    $this->assertViewsDataField($data['entity_test']['id'], 'id');
+    $this->assertUuidField($data['entity_test']['uuid']);
+    $this->assertViewsDataField($data['entity_test']['uuid'], 'uuid');
+    $this->assertStringField($data['entity_test']['type']);
+    $this->assertEquals('type', $data['entity_test']['type']['entity field']);
+
+    $this->assertLanguageField($data['entity_test']['langcode']);
+    $this->assertViewsDataField($data['entity_test']['langcode'], 'langcode');
+    $this->assertEquals('Original language', $data['entity_test']['langcode']['title']);
+
+    $this->assertStringField($data['entity_test']['name']);
+    $this->assertViewsDataField($data['entity_test']['name'], 'name');
+
+    $this->assertLongTextField($data['entity_test'], 'description');
+    $this->assertViewsDataField($data['entity_test']['description__value'], 'description');
+    $this->assertViewsDataField($data['entity_test']['description__format'], 'description');
+
+    $this->assertUriField($data['entity_test']['homepage']);
+    $this->assertViewsDataField($data['entity_test']['homepage'], 'homepage');
+
+    $this->assertEntityReferenceField($data['entity_test']['user_id']);
+    $this->assertViewsDataField($data['entity_test']['user_id'], 'user_id');
+
+    $relationship = $data['entity_test']['user_id']['relationship'];
+    $this->assertEquals('users_field_data', $relationship['base']);
+    $this->assertEquals('uid', $relationship['base field']);
+
+    // The string field name should be used as the 'entity field' but the actual
+    // field should reflect what the column mapping is using for multi-value
+    // base fields NOT just the field name. The actual column name returned from
+    // mappings in the test mocks is 'value'.
+    $this->assertStringField($data['entity_test__string']['string_value']);
+    $this->assertViewsDataField($data['entity_test__string']['string_value'], 'string');
+    $this->assertEquals([
+      'left_field' => 'id',
+      'field' => 'entity_id',
+      'extra' => [[
+          'field' => 'deleted',
+          'value' => 0,
+          'numeric' => TRUE,
+        ],
+      ],
+    ], $data['entity_test__string']['table']['join']['entity_test']);
+  }
+
+  /**
+   * Tests fields on the data table.
+   */
+  public function testDataTableFields() {
+    $entity_test_type = new ConfigEntityType([
+      'class' => ConfigEntityBase::class,
+      'id' => 'entity_test_bundle',
+      'entity_keys' => [
+        'id' => 'type',
+        'label' => 'name',
+      ],
+    ]);
+    $this->setUpEntityType($entity_test_type);
+
+    $entity_type = $this->baseEntityType
+      ->set('data_table', 'entity_test_mul_property_data')
+      ->set('base_table', 'entity_test_mul')
+      ->set('translatable', TRUE)
+      ->set('id', 'entity_test_mul')
+      ->set('bundle_entity_type', 'entity_test_bundle')
+      ->setKey('bundle', 'type');
+
+    $base_field_definitions = $this->commonBaseFields;
+    $base_field_definitions['type'] = BaseFieldDefinition::create('entity_reference')
+      ->setLabel('entity test type')
+      ->setSetting('target_type', 'entity_test_bundle');
+
+    $this->setUpEntityType($entity_type, $base_field_definitions);
+
+    $data = $this->entityTypeManager->getHandler('entity_test_mul', 'views_data')->getViewsData();
+
+    // Check the base fields.
+    $this->assertFalse(isset($data['entity_test_mul']['id']));
+    $this->assertFalse(isset($data['entity_test_mul']['type']));
+    $this->assertUuidField($data['entity_test_mul']['uuid']);
+    $this->assertViewsDataField($data['entity_test_mul']['uuid'], 'uuid');
+
+    $this->assertFalse(isset($data['entity_test_mul']['type']['relationship']));
+
+    // Also ensure that field_data only fields don't appear on the base table.
+    $this->assertFalse(isset($data['entity_test_mul']['name']));
+    $this->assertFalse(isset($data['entity_test_mul']['description']));
+    $this->assertFalse(isset($data['entity_test_mul']['description__value']));
+    $this->assertFalse(isset($data['entity_test_mul']['description__format']));
+    $this->assertFalse(isset($data['entity_test_mul']['user_id']));
+    $this->assertFalse(isset($data['entity_test_mul']['homepage']));
+
+    // Check the data fields.
+    $this->assertNumericField($data['entity_test_mul_property_data']['id']);
+    $this->assertViewsDataField($data['entity_test_mul_property_data']['id'], 'id');
+
+    $this->assertBundleField($data['entity_test_mul_property_data']['type']);
+    $this->assertViewsDataField($data['entity_test_mul_property_data']['type'], 'type');
+
+    $this->assertLanguageField($data['entity_test_mul_property_data']['langcode']);
+    $this->assertViewsDataField($data['entity_test_mul_property_data']['langcode'], 'langcode');
+    $this->assertEquals('Translation language', $data['entity_test_mul_property_data']['langcode']['title']);
+
+    $this->assertStringField($data['entity_test_mul_property_data']['name']);
+    $this->assertViewsDataField($data['entity_test_mul_property_data']['name'], 'name');
+
+    $this->assertLongTextField($data['entity_test_mul_property_data'], 'description');
+    $this->assertViewsDataField($data['entity_test_mul_property_data']['description__value'], 'description');
+    $this->assertViewsDataField($data['entity_test_mul_property_data']['description__format'], 'description');
+
+    $this->assertUriField($data['entity_test_mul_property_data']['homepage']);
+    $this->assertViewsDataField($data['entity_test_mul_property_data']['homepage'], 'homepage');
+
+    $this->assertEntityReferenceField($data['entity_test_mul_property_data']['user_id']);
+    $this->assertViewsDataField($data['entity_test_mul_property_data']['user_id'], 'user_id');
+    $relationship = $data['entity_test_mul_property_data']['user_id']['relationship'];
+    $this->assertEquals('users_field_data', $relationship['base']);
+    $this->assertEquals('uid', $relationship['base field']);
+
+    $this->assertStringField($data['entity_test_mul__string']['string_value']);
+    $this->assertViewsDataField($data['entity_test_mul__string']['string_value'], 'string');
+    $this->assertEquals([
+      'left_field' => 'id',
+      'field' => 'entity_id',
+      'extra' => [[
+          'field' => 'deleted',
+          'value' => 0,
+          'numeric' => TRUE,
+        ],
+      ],
+    ], $data['entity_test_mul__string']['table']['join']['entity_test_mul_property_data']);
+  }
+
+  /**
+   * Tests fields on the revision table.
+   */
+  public function testRevisionTableFields() {
+    $entity_type = $this->baseEntityType
+      ->set('id', 'entity_test_mulrev')
+      ->set('base_table', 'entity_test_mulrev')
+      ->set('revision_table', 'entity_test_mulrev_revision')
+      ->set('data_table', 'entity_test_mulrev_property_data')
+      ->set('revision_data_table', 'entity_test_mulrev_property_revision')
+      ->set('translatable', TRUE);
+
+    $base_field_definitions = $this->commonBaseFields;
+
+    $base_field_definitions['name']->setRevisionable(TRUE);
+    $base_field_definitions['description']->setRevisionable(TRUE);
+    $base_field_definitions['homepage']->setRevisionable(TRUE);
+    $base_field_definitions['user_id']->setRevisionable(TRUE);
+
+    $base_field_definitions['non_rev_field'] = BaseFieldDefinition::create('string')
+      ->setLabel(t('Non Revisionable Field'))
+      ->setDescription(t('A non-revisionable test field.'))
+      ->setRevisionable(FALSE)
+      ->setTranslatable(TRUE)
+      ->setCardinality(1)
+      ->setReadOnly(TRUE);
+
+    $base_field_definitions['non_mul_field'] = BaseFieldDefinition::create('string')
+      ->setLabel(t('Non translatable'))
+      ->setDescription(t('A non-translatable string field'))
+      ->setRevisionable(TRUE);
+
+    $this->setUpEntityType($entity_type, $base_field_definitions);
+
+    $data = $this->entityTypeManager->getHandler('entity_test_mulrev', 'views_data')->getViewsData();
+
+    // Check the base fields.
+    $this->assertFalse(isset($data['entity_test_mulrev']['id']));
+    $this->assertFalse(isset($data['entity_test_mulrev']['type']));
+    $this->assertFalse(isset($data['entity_test_mulrev']['revision_id']));
+    $this->assertUuidField($data['entity_test_mulrev']['uuid']);
+    $this->assertViewsDataField($data['entity_test_mulrev']['uuid'], 'uuid');
+
+    // Also ensure that field_data only fields don't appear on the base table.
+    $this->assertFalse(isset($data['entity_test_mulrev']['name']));
+    $this->assertFalse(isset($data['entity_test_mul']['description']));
+    $this->assertFalse(isset($data['entity_test_mul']['description__value']));
+    $this->assertFalse(isset($data['entity_test_mul']['description__format']));
+    $this->assertFalse(isset($data['entity_test_mul']['homepage']));
+    // $this->assertFalse(isset($data['entity_test_mulrev']['langcode']));
+    $this->assertFalse(isset($data['entity_test_mulrev']['user_id']));
+
+    // Check the revision fields. The revision ID should only appear in the data
+    // table.
+    $this->assertFalse(isset($data['entity_test_mulrev_revision']['revision_id']));
+
+    // Also ensure that field_data only fields don't appear on the revision table.
+    $this->assertFalse(isset($data['entity_test_mulrev_revision']['id']));
+    $this->assertFalse(isset($data['entity_test_mulrev_revision']['name']));
+    $this->assertFalse(isset($data['entity_test_mulrev_revision']['description']));
+    $this->assertFalse(isset($data['entity_test_mulrev_revision']['description__value']));
+    $this->assertFalse(isset($data['entity_test_mulrev_revision']['description__format']));
+    $this->assertFalse(isset($data['entity_test_mulrev_revision']['homepage']));
+    $this->assertFalse(isset($data['entity_test_mulrev_revision']['user_id']));
+
+    // Check the data fields.
+    $this->assertNumericField($data['entity_test_mulrev_property_data']['id']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_data']['id'], 'id');
+    $this->assertNumericField($data['entity_test_mulrev_property_data']['revision_id']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_data']['revision_id'], 'revision_id');
+    $this->assertLanguageField($data['entity_test_mulrev_property_data']['langcode']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_data']['langcode'], 'langcode');
+    $this->assertStringField($data['entity_test_mulrev_property_data']['name']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_data']['name'], 'name');
+
+    $this->assertLongTextField($data['entity_test_mulrev_property_data'], 'description');
+    $this->assertViewsDataField($data['entity_test_mulrev_property_data']['description__value'], 'description');
+    $this->assertViewsDataField($data['entity_test_mulrev_property_data']['description__format'], 'description');
+    $this->assertUriField($data['entity_test_mulrev_property_data']['homepage']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_data']['homepage'], 'homepage');
+
+    $this->assertEntityReferenceField($data['entity_test_mulrev_property_data']['user_id']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_data']['user_id'], 'user_id');
+    $relationship = $data['entity_test_mulrev_property_data']['user_id']['relationship'];
+    $this->assertEquals('users_field_data', $relationship['base']);
+    $this->assertEquals('uid', $relationship['base field']);
+
+    // Check the property data fields.
+    $this->assertNumericField($data['entity_test_mulrev_property_revision']['id']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_revision']['id'], 'id');
+
+    $this->assertLanguageField($data['entity_test_mulrev_property_revision']['langcode']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_revision']['langcode'], 'langcode');
+    $this->assertEquals('Translation language', $data['entity_test_mulrev_property_revision']['langcode']['title']);
+
+    $this->assertStringField($data['entity_test_mulrev_property_revision']['name']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_revision']['name'], 'name');
+
+    $this->assertLongTextField($data['entity_test_mulrev_property_revision'], 'description');
+    $this->assertViewsDataField($data['entity_test_mulrev_property_revision']['description__value'], 'description');
+    $this->assertViewsDataField($data['entity_test_mulrev_property_revision']['description__format'], 'description');
+
+    $this->assertUriField($data['entity_test_mulrev_property_revision']['homepage']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_revision']['homepage'], 'homepage');
+
+    $this->assertEntityReferenceField($data['entity_test_mulrev_property_revision']['user_id']);
+    $this->assertViewsDataField($data['entity_test_mulrev_property_revision']['user_id'], 'user_id');
+    $relationship = $data['entity_test_mulrev_property_revision']['user_id']['relationship'];
+    $this->assertEquals('users_field_data', $relationship['base']);
+    $this->assertEquals('uid', $relationship['base field']);
+
+    $this->assertStringField($data['entity_test_mulrev__string']['string_value']);
+    $this->assertViewsDataField($data['entity_test_mulrev__string']['string_value'], 'string');
+    $this->assertEquals([
+      'left_field' => 'id',
+      'field' => 'entity_id',
+      'extra' => [[
+          'field' => 'deleted',
+          'value' => 0,
+          'numeric' => TRUE,
+        ],
+      ],
+    ], $data['entity_test_mulrev__string']['table']['join']['entity_test_mulrev_property_data']);
+
+    $this->assertStringField($data['entity_test_mulrev_revision__string']['string_value']);
+    $this->assertViewsDataField($data['entity_test_mulrev_revision__string']['string_value'], 'string');
+    $this->assertEquals([
+      'left_field' => 'revision_id',
+      'field' => 'entity_id',
+      'extra' => [[
+          'field' => 'deleted',
+          'value' => 0,
+          'numeric' => TRUE,
+        ],
+      ],
+    ], $data['entity_test_mulrev_revision__string']['table']['join']['entity_test_mulrev_property_revision']);
+  }
+
+  /**
+   * Tests generic stuff per field.
+   *
+   * @param array $data
+   *   The views data to check.
+   * @param string $field_name
+   *   The entity field name.
+   */
+  protected function assertViewsDataField($data, $field_name) {
+    $this->assertEquals($field_name, $data['entity field']);
+  }
+
+  /**
+   * Tests views data for a string field.
+   *
+   * @param $data
+   *   The views data to check.
+   */
+  protected function assertStringField($data) {
+    $this->assertEquals('field', $data['field']['id']);
+    $this->assertEquals('string', $data['filter']['id']);
+    $this->assertEquals('string', $data['argument']['id']);
+    $this->assertEquals('standard', $data['sort']['id']);
+  }
+
+  /**
+   * Tests views data for a URI field.
+   *
+   * @param $data
+   *   The views data to check.
+   */
+  protected function assertUriField($data) {
+    $this->assertEquals('field', $data['field']['id']);
+    $this->assertEquals('string', $data['field']['default_formatter']);
+    $this->assertEquals('string', $data['filter']['id']);
+    $this->assertEquals('string', $data['argument']['id']);
+    $this->assertEquals('standard', $data['sort']['id']);
+  }
+
+  /**
+   * Tests views data for a long text field.
+   *
+   * @param $data
+   *   The views data for the table this field is in.
+   * @param $field_name
+   *   The name of the field being checked.
+   */
+  protected function assertLongTextField($data, $field_name) {
+    $value_field = $data[$field_name . '__value'];
+    $this->assertEquals('field', $value_field['field']['id']);
+    $this->assertEquals($field_name . '__format', $value_field['field']['format']);
+    $this->assertEquals('string', $value_field['filter']['id']);
+    $this->assertEquals('string', $value_field['argument']['id']);
+    $this->assertEquals('standard', $value_field['sort']['id']);
+
+    $this->assertStringField($data[$field_name . '__format']);
+  }
+
+  /**
+   * Tests views data for a UUID field.
+   *
+   * @param array $data
+   *   The views data to check.
+   */
+  protected function assertUuidField($data) {
+    // @todo Can we provide additional support for UUIDs in views?
+    $this->assertEquals('field', $data['field']['id']);
+    $this->assertFalse($data['field']['click sortable']);
+    $this->assertEquals('string', $data['filter']['id']);
+    $this->assertEquals('string', $data['argument']['id']);
+    $this->assertEquals('standard', $data['sort']['id']);
+  }
+
+  /**
+   * Tests views data for a numeric field.
+   *
+   * @param array $data
+   *   The views data to check.
+   */
+  protected function assertNumericField($data) {
+    $this->assertEquals('field', $data['field']['id']);
+    $this->assertEquals('numeric', $data['filter']['id']);
+    $this->assertEquals('numeric', $data['argument']['id']);
+    $this->assertEquals('standard', $data['sort']['id']);
+  }
+
+  /**
+   * Tests views data for a language field.
+   *
+   * @param array $data
+   *   The views data to check.
+   */
+  protected function assertLanguageField($data) {
+    $this->assertEquals('field', $data['field']['id']);
+    $this->assertEquals('language', $data['filter']['id']);
+    $this->assertEquals('language', $data['argument']['id']);
+    $this->assertEquals('standard', $data['sort']['id']);
+  }
+
+  /**
+   * Tests views data for an entity reference field.
+   */
+  protected function assertEntityReferenceField($data) {
+    $this->assertEquals('field', $data['field']['id']);
+    $this->assertEquals('numeric', $data['filter']['id']);
+    $this->assertEquals('numeric', $data['argument']['id']);
+    $this->assertEquals('standard', $data['sort']['id']);
+  }
+
+  /**
+   * Tests views data for a bundle field.
+   */
+  protected function assertBundleField($data) {
+    $this->assertEquals('field', $data['field']['id']);
+    $this->assertEquals('bundle', $data['filter']['id']);
+    $this->assertEquals('string', $data['argument']['id']);
+    $this->assertEquals('standard', $data['sort']['id']);
+  }
+
+}
+
+/**
+ * Entity type class which allows changing the entity keys.
+ */
+class TestEntityType extends ContentEntityType {
+
+  /**
+   * Sets a specific entity key.
+   *
+   * @param string $key
+   *   The name of the entity key.
+   * @param string $value
+   *   The new value of the key.
+   *
+   * @return $this
+   */
+  public function setKey($key, $value) {
+    $this->entity_keys[$key] = $value;
+    return $this;
+  }
+
+}
+
+/**
+ * Generic entity class for our test entity types.
+ *
+ * Allows mocked base field definitions.
+ */
+class ViewsTestEntity extends ContentEntityBase {
+
+  /**
+   * The mocked base fields for test entity types.
+   *
+   * An array keyed by entity type ID, whose values are arrays of base field
+   * definitions.
+   *
+   * @var array
+   */
+  protected static $mockedBaseFieldDefinitions = [];
+
+  /**
+   * Sets up the mocked base field definitions.
+   *
+   * @param string $entity_type_id
+   *   The entity type ID.
+   * @param array $definitions
+   *   The array of base field definitions to mock. These are added to the
+   *   defaults ones from the parent class.
+   */
+  public static function setMockedBaseFieldDefinitions(string $entity_type_id, array $definitions) {
+    static::$mockedBaseFieldDefinitions[$entity_type_id] = $definitions;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function baseFieldDefinitions(EntityTypeInterface $entity_type) {
+    $fields = parent::baseFieldDefinitions($entity_type);
+
+    if (isset(static::$mockedBaseFieldDefinitions[$entity_type->id()])) {
+      $mocked_fields = static::$mockedBaseFieldDefinitions[$entity_type->id()];
+      // Mocked fields take priority over ones from the base class.
+      $fields = $mocked_fields + $fields;
+    }
+
+    return $fields;
+  }
+
+}
diff --git a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php b/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
deleted file mode 100644
index 6e0621e40fde5b6d0b9b87e9c4343ce4360b0576..0000000000000000000000000000000000000000
--- a/core/modules/views/tests/src/Unit/EntityViewsDataTest.php
+++ /dev/null
@@ -1,1197 +0,0 @@
-<?php
-
-/**
- * @file
- * Contains \Drupal\Tests\views\Unit\EntityViewsDataTest.
- */
-
-namespace Drupal\Tests\views\Unit;
-
-use Drupal\Core\Config\Entity\ConfigEntityType;
-use Drupal\Core\Entity\ContentEntityType;
-use Drupal\Core\Entity\EntityFieldManagerInterface;
-use Drupal\Core\Entity\EntityTypeInterface;
-use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Entity\Sql\DefaultTableMapping;
-use Drupal\Core\Field\BaseFieldDefinition;
-use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
-use Drupal\Core\Field\Plugin\Field\FieldType\IntegerItem;
-use Drupal\Core\Field\Plugin\Field\FieldType\LanguageItem;
-use Drupal\Core\Field\Plugin\Field\FieldType\StringItem;
-use Drupal\Core\Field\Plugin\Field\FieldType\UriItem;
-use Drupal\Core\Field\Plugin\Field\FieldType\UuidItem;
-use Drupal\Core\State\StateInterface;
-use Drupal\Core\TypedData\TypedDataManagerInterface;
-use Drupal\text\Plugin\Field\FieldType\TextLongItem;
-use Drupal\entity_test\Entity\EntityTest;
-use Drupal\entity_test\Entity\EntityTestMul;
-use Drupal\entity_test\Entity\EntityTestMulRev;
-use Drupal\Tests\UnitTestCase;
-use Drupal\views\EntityViewsData;
-use Prophecy\Argument;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
-
-/**
- * @coversDefaultClass \Drupal\views\EntityViewsData
- * @group Views
- */
-class EntityViewsDataTest extends UnitTestCase {
-
-  /**
-   * Entity info to use in this test.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeInterface|\Drupal\Tests\views\Unit\TestEntityType
-   */
-  protected $baseEntityType;
-
-  /**
-   * The mocked entity storage.
-   *
-   * @var \Drupal\Core\Entity\Sql\SqlContentEntityStorage|\PHPUnit\Framework\MockObject\MockObject
-   */
-  protected $entityStorage;
-
-  /**
-   * The mocked entity field manager.
-   *
-   * @var \Drupal\Core\Entity\EntityFieldManagerInterface|\PHPUnit\Framework\MockObject\MockObject
-   */
-  protected $entityFieldManager;
-
-
-  /**
-   * The mocked entity type manager.
-   *
-   * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit\Framework\MockObject\MockObject
-   */
-  protected $entityTypeManager;
-
-  /**
-   * The mocked module handler.
-   *
-   * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit\Framework\MockObject\MockObject
-   */
-  protected $moduleHandler;
-
-  /**
-   * The mocked translation manager.
-   *
-   * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit\Framework\MockObject\MockObject
-   */
-  protected $translationManager;
-
-  /**
-   * The tested entity views controller.
-   *
-   * @var \Drupal\Tests\views\Unit\TestEntityViewsData
-   */
-  protected $viewsData;
-
-  /**
-   * {@inheritdoc}
-   */
-  protected function setUp(): void {
-    $this->entityStorage = $this->getMockBuilder('Drupal\Core\Entity\Sql\SqlContentEntityStorage')
-      ->disableOriginalConstructor()
-      ->getMock();
-    $this->entityTypeManager = $this->createMock(EntityTypeManagerInterface::class);
-    $this->entityFieldManager = $this->createMock(EntityFieldManagerInterface::class);
-
-    $typed_data_manager = $this->createMock(TypedDataManagerInterface::class);
-    $typed_data_manager->expects($this->any())
-      ->method('createDataDefinition')
-      ->willReturn($this->createMock('Drupal\Core\TypedData\DataDefinitionInterface'));
-
-    $typed_data_manager->expects($this->any())
-      ->method('getDefinition')
-      ->will($this->returnValueMap([
-        'entity:user' => ['class' => '\Drupal\Core\TypedData\DataDefinitionInterface'],
-        'field_item:string_long' => ['class' => '\Drupal\Core\Field\Plugin\Field\FieldType\StringLongItem'],
-      ]));
-
-    $this->baseEntityType = new TestEntityType([
-      'base_table' => 'entity_test',
-      'id' => 'entity_test',
-      'label' => 'Entity test',
-      'entity_keys' => [
-        'uuid' => 'uuid',
-        'id' => 'id',
-        'langcode' => 'langcode',
-        'bundle' => 'type',
-        'revision' => 'revision_id',
-      ],
-      'provider' => 'entity_test',
-      'list_cache_contexts' => ['entity_test_list_cache_context'],
-    ]);
-
-    $this->translationManager = $this->getStringTranslationStub();
-    $this->baseEntityType->setStringTranslation($this->translationManager);
-    $this->moduleHandler = $this->createMock('Drupal\Core\Extension\ModuleHandlerInterface');
-
-    $this->viewsData = new TestEntityViewsData($this->baseEntityType, $this->entityStorage, $this->entityTypeManager, $this->moduleHandler, $this->translationManager, $this->entityFieldManager);
-
-    $field_type_manager = $this->getMockBuilder('Drupal\Core\Field\FieldTypePluginManager')
-      ->disableOriginalConstructor()
-      ->getMock();
-    $field_type_manager->expects($this->any())
-      ->method('getDefaultStorageSettings')
-      ->willReturn([]);
-    $field_type_manager->expects($this->any())
-      ->method('getDefaultFieldSettings')
-      ->willReturn([]);
-
-    $state = $this->prophesize(StateInterface::class);
-    $state->get(Argument::any(), [])->willReturn([]);
-
-    $container = new ContainerBuilder();
-    $container->set('plugin.manager.field.field_type', $field_type_manager);
-    $container->set('entity_type.manager', $this->entityTypeManager);
-    $container->set('entity_field.manager', $this->entityFieldManager);
-    $container->set('typed_data_manager', $typed_data_manager);
-    $container->set('state', $state->reveal());
-    \Drupal::setContainer($container);
-  }
-
-  /**
-   * Helper method to setup base fields.
-   *
-   * @param \Drupal\Core\Field\BaseFieldDefinition[] $base_fields
-   *   The base fields which are adapted.
-   *
-   * @return \Drupal\Core\Field\BaseFieldDefinition[]
-   *   The setup base fields.
-   */
-  protected function setupBaseFields(array $base_fields) {
-    // Add a description field to the fields supplied by the EntityTest
-    // classes. This example comes from the taxonomy Term entity.
-    $base_fields['description'] = BaseFieldDefinition::create('text_long')
-      ->setLabel('Description')
-      ->setDescription('A description of the term.')
-      ->setTranslatable(TRUE)
-      ->setDisplayOptions('view', [
-          'label' => 'hidden',
-          'type' => 'text_default',
-          'weight' => 0,
-        ])
-      ->setDisplayConfigurable('view', TRUE)
-      ->setDisplayOptions('form', [
-          'type' => 'text_textfield',
-          'weight' => 0,
-        ])
-      ->setDisplayConfigurable('form', TRUE);
-
-    // Add a URL field; this example is from the Comment entity.
-    $base_fields['homepage'] = BaseFieldDefinition::create('uri')
-      ->setLabel('Homepage')
-      ->setDescription("The comment author's home page address.")
-      ->setTranslatable(TRUE)
-      ->setSetting('max_length', 255);
-
-    // A base field with cardinality > 1
-    $base_fields['string'] = BaseFieldDefinition::create('string')
-      ->setLabel('Strong')
-      ->setTranslatable(TRUE)
-      ->setCardinality(2);
-
-    foreach ($base_fields as $name => $base_field) {
-      $base_field->setName($name);
-    }
-    return $base_fields;
-  }
-
-  /**
-   * Tests base tables.
-   */
-  public function testBaseTables() {
-    $data = $this->viewsData->getViewsData();
-
-    $this->assertEquals('entity_test', $data['entity_test']['table']['entity type']);
-    $this->assertEquals(FALSE, $data['entity_test']['table']['entity revision']);
-    $this->assertEquals('Entity test', $data['entity_test']['table']['group']);
-    $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
-
-    $this->assertEquals('id', $data['entity_test']['table']['base']['field']);
-    $this->assertEquals(['entity_test_list_cache_context'], $data['entity_test']['table']['base']['cache_contexts']);
-    $this->assertEquals('Entity test', $data['entity_test']['table']['base']['title']);
-
-    $this->assertFalse(isset($data['entity_test']['table']['defaults']));
-
-    $this->assertFalse(isset($data['entity_test_mul_property_data']));
-    $this->assertFalse(isset($data['revision_table']));
-    $this->assertFalse(isset($data['revision_data_table']));
-  }
-
-  /**
-   * Tests data_table support.
-   */
-  public function testDataTable() {
-    $entity_type = $this->baseEntityType
-      ->set('data_table', 'entity_test_mul_property_data')
-      ->set('id', 'entity_test_mul')
-      ->set('translatable', TRUE)
-      ->setKey('label', 'label');
-
-    $this->viewsData->setEntityType($entity_type);
-
-    // Tests the join definition between the base and the data table.
-    $data = $this->viewsData->getViewsData();
-    $base_views_data = $data['entity_test'];
-
-    // Ensure that the base table is set to the data table.
-    $this->assertEquals('id', $data['entity_test_mul_property_data']['table']['base']['field']);
-    $this->assertEquals('Entity test', $data['entity_test_mul_property_data']['table']['base']['title']);
-    $this->assertFalse(isset($data['entity_test']['table']['base']));
-
-    $this->assertEquals('entity_test_mul', $data['entity_test_mul_property_data']['table']['entity type']);
-    $this->assertEquals(FALSE, $data['entity_test_mul_property_data']['table']['entity revision']);
-    $this->assertEquals('Entity test', $data['entity_test_mul_property_data']['table']['group']);
-    $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
-    $this->assertEquals(['field' => 'label', 'table' => 'entity_test_mul_property_data'], $data['entity_test_mul_property_data']['table']['base']['defaults']);
-
-    // Ensure the join information is set up properly.
-    $this->assertCount(1, $base_views_data['table']['join']);
-    $this->assertEquals(['entity_test_mul_property_data' => ['left_field' => 'id', 'field' => 'id', 'type' => 'INNER']], $base_views_data['table']['join']);
-    $this->assertFalse(isset($data['revision_table']));
-    $this->assertFalse(isset($data['revision_data_table']));
-  }
-
-  /**
-   * Tests revision table without data table support.
-   */
-  public function testRevisionTableWithoutDataTable() {
-    $entity_type = $this->baseEntityType
-      ->set('revision_table', 'entity_test_mulrev_revision')
-      ->set('revision_data_table', NULL)
-      ->set('id', 'entity_test_mulrev')
-      ->setKey('revision', 'revision_id');
-    $this->viewsData->setEntityType($entity_type);
-
-    $data = $this->viewsData->getViewsData();
-
-    $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_revision']['table']['base']['title']);
-    $this->assertEquals('revision_id', $data['entity_test_mulrev_revision']['table']['base']['field']);
-
-    $this->assertEquals(FALSE, $data['entity_test']['table']['entity revision']);
-    $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_revision']['table']['entity type']);
-    $this->assertEquals(TRUE, $data['entity_test_mulrev_revision']['table']['entity revision']);
-    $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_revision']['table']['entity type']);
-    $this->assertEquals(TRUE, $data['entity_test_mulrev_revision']['table']['entity revision']);
-
-    $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
-    $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
-
-    // Ensure the join information is set up properly.
-    // Tests the join definition between the base and the revision table.
-    $revision_data = $data['entity_test_mulrev_revision'];
-    $this->assertCount(1, $revision_data['table']['join']);
-    $this->assertEquals(['entity_test' => ['left_field' => 'revision_id', 'field' => 'revision_id', 'type' => 'INNER']], $revision_data['table']['join']);
-    $this->assertFalse(isset($data['data_table']));
-  }
-
-  /**
-   * Tests revision table with data table support.
-   */
-  public function testRevisionTableWithRevisionDataTableAndDataTable() {
-    $entity_type = $this->baseEntityType
-      ->set('data_table', 'entity_test_mul_property_data')
-      ->set('revision_table', 'entity_test_mulrev_revision')
-      ->set('revision_data_table', 'entity_test_mulrev_property_revision')
-      ->set('id', 'entity_test_mulrev')
-      ->set('translatable', TRUE)
-      ->setKey('revision', 'revision_id');
-    $this->viewsData->setEntityType($entity_type);
-
-    $data = $this->viewsData->getViewsData();
-
-    $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_property_revision']['table']['base']['title']);
-    $this->assertEquals('revision_id', $data['entity_test_mulrev_property_revision']['table']['base']['field']);
-    $this->assertFalse(isset($data['entity_test_mulrev_revision']['table']['base']));
-
-    $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_property_revision']['table']['entity type']);
-    $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
-    $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
-
-    // Ensure the join information is set up properly.
-    // Tests the join definition between the base and the revision table.
-    $revision_field_data = $data['entity_test_mulrev_property_revision'];
-    $this->assertCount(1, $revision_field_data['table']['join']);
-    $this->assertEquals([
-      'entity_test_mul_property_data' => [
-        'left_field' => 'revision_id',
-        'field' => 'revision_id',
-        'type' => 'INNER',
-      ],
-    ], $revision_field_data['table']['join']);
-
-    $revision_base_data = $data['entity_test_mulrev_revision'];
-    $this->assertCount(1, $revision_base_data['table']['join']);
-    $this->assertEquals([
-      'entity_test_mulrev_property_revision' => [
-        'left_field' => 'revision_id',
-        'field' => 'revision_id',
-        'type' => 'INNER',
-      ],
-    ], $revision_base_data['table']['join']);
-
-    $this->assertFalse(isset($data['data_table']));
-  }
-
-  /**
-   * Tests revision table with data table support.
-   */
-  public function testRevisionTableWithRevisionDataTable() {
-    $entity_type = $this->baseEntityType
-      ->set('revision_table', 'entity_test_mulrev_revision')
-      ->set('revision_data_table', 'entity_test_mulrev_property_revision')
-      ->set('id', 'entity_test_mulrev')
-      ->set('translatable', TRUE)
-      ->setKey('revision', 'revision_id');
-    $this->viewsData->setEntityType($entity_type);
-
-    $data = $this->viewsData->getViewsData();
-
-    $this->assertEquals('Entity test revisions', $data['entity_test_mulrev_property_revision']['table']['base']['title']);
-    $this->assertEquals('revision_id', $data['entity_test_mulrev_property_revision']['table']['base']['field']);
-    $this->assertFalse(isset($data['entity_test_mulrev_revision']['table']['base']));
-
-    $this->assertEquals('entity_test_mulrev', $data['entity_test_mulrev_property_revision']['table']['entity type']);
-    $this->assertEquals('Entity test revision', $data['entity_test_mulrev_revision']['table']['group']);
-    $this->assertEquals('entity_test', $data['entity_test']['table']['provider']);
-
-    // Ensure the join information is set up properly.
-    // Tests the join definition between the base and the revision table.
-    $revision_field_data = $data['entity_test_mulrev_property_revision'];
-    $this->assertCount(1, $revision_field_data['table']['join']);
-    $this->assertEquals([
-      'entity_test_mulrev_field_data' => [
-        'left_field' => 'revision_id',
-        'field' => 'revision_id',
-        'type' => 'INNER',
-      ],
-    ], $revision_field_data['table']['join']);
-
-    $revision_base_data = $data['entity_test_mulrev_revision'];
-    $this->assertCount(1, $revision_base_data['table']['join']);
-    $this->assertEquals([
-      'entity_test_mulrev_property_revision' => [
-        'left_field' => 'revision_id',
-        'field' => 'revision_id',
-        'type' => 'INNER',
-      ],
-    ], $revision_base_data['table']['join']);
-    $this->assertFalse(isset($data['data_table']));
-  }
-
-  /**
-   * Helper method to mock all store definitions.
-   */
-  protected function setupFieldStorageDefinition() {
-    $id_field_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
-    $id_field_storage_definition->expects($this->any())
-      ->method('getSchema')
-      ->willReturn(IntegerItem::schema($id_field_storage_definition));
-    $uuid_field_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
-    $uuid_field_storage_definition->expects($this->any())
-      ->method('getSchema')
-      ->willReturn(UuidItem::schema($uuid_field_storage_definition));
-    $type_field_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
-    $type_field_storage_definition->expects($this->any())
-      ->method('getSchema')
-      ->willReturn(StringItem::schema($type_field_storage_definition));
-    $langcode_field_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
-    $langcode_field_storage_definition->expects($this->any())
-      ->method('getSchema')
-      ->willReturn(LanguageItem::schema($langcode_field_storage_definition));
-    $name_field_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
-    $name_field_storage_definition->expects($this->any())
-      ->method('getSchema')
-      ->willReturn(StringItem::schema($name_field_storage_definition));
-    $description_field_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
-    $description_field_storage_definition->expects($this->any())
-      ->method('getSchema')
-      ->willReturn(TextLongItem::schema($description_field_storage_definition));
-    $homepage_field_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
-    $homepage_field_storage_definition->expects($this->any())
-      ->method('getSchema')
-      ->willReturn(UriItem::schema($homepage_field_storage_definition));
-    $string_field_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
-    $string_field_storage_definition->expects($this->any())
-      ->method('getSchema')
-      ->willReturn(StringItem::schema($string_field_storage_definition));
-
-    // Setup the user_id entity reference field.
-    $this->entityTypeManager->expects($this->any())
-      ->method('getDefinition')
-      ->willReturnMap([
-          ['user', TRUE, static::userEntityInfo()],
-        ]
-      );
-    $this->entityTypeManager->expects($this->any())
-      ->method('getDefinition')
-      ->willReturnMap([
-          ['user', TRUE, static::userEntityInfo()],
-        ]
-      );
-    $user_id_field_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
-    $user_id_field_storage_definition->expects($this->any())
-      ->method('getSetting')
-      ->with('target_type')
-      ->willReturn('user');
-    $user_id_field_storage_definition->expects($this->any())
-      ->method('getSettings')
-      ->willReturn(['target_type' => 'user']);
-    $user_id_field_storage_definition->expects($this->any())
-      ->method('getSchema')
-      ->willReturn(EntityReferenceItem::schema($user_id_field_storage_definition));
-
-    $revision_id_field_storage_definition = $this->createMock('Drupal\Core\Field\FieldStorageDefinitionInterface');
-    $revision_id_field_storage_definition->expects($this->any())
-      ->method('getSchema')
-      ->willReturn(IntegerItem::schema($revision_id_field_storage_definition));
-
-    $this->entityFieldManager->expects($this->any())
-      ->method('getFieldStorageDefinitions')
-      ->willReturn([
-        'id' => $id_field_storage_definition,
-        'uuid' => $uuid_field_storage_definition,
-        'type' => $type_field_storage_definition,
-        'langcode' => $langcode_field_storage_definition,
-        'name' => $name_field_storage_definition,
-        'description' => $description_field_storage_definition,
-        'homepage' => $homepage_field_storage_definition,
-        'string' => $string_field_storage_definition,
-        'user_id' => $user_id_field_storage_definition,
-        'revision_id' => $revision_id_field_storage_definition,
-      ]);
-  }
-
-  /**
-   * Tests fields on the base table.
-   */
-  public function testBaseTableFields() {
-    $base_field_definitions = $this->setupBaseFields(EntityTest::baseFieldDefinitions($this->baseEntityType));
-    $user_base_field_definitions = [
-      'uid' => BaseFieldDefinition::create('integer')
-        ->setLabel('ID')
-        ->setDescription('The ID of the user entity.')
-        ->setReadOnly(TRUE)
-        ->setSetting('unsigned', TRUE),
-    ];
-    $this->entityFieldManager->expects($this->any())
-      ->method('getBaseFieldDefinitions')
-      ->will($this->returnValueMap([
-        ['user', $user_base_field_definitions],
-        ['entity_test', $base_field_definitions],
-      ]));
-    $this->entityFieldManager->expects($this->any())
-      ->method('getBaseFieldDefinitions')
-      ->will($this->returnValueMap([
-        ['user', $user_base_field_definitions],
-        ['entity_test', $base_field_definitions],
-      ]));
-    // Setup the table mapping.
-    $table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
-      ->disableOriginalConstructor()
-      ->getMock();
-    $table_mapping->expects($this->any())
-      ->method('getTableNames')
-      ->willReturn(['entity_test', 'entity_test__string']);
-    $table_mapping->expects($this->any())
-      ->method('getColumnNames')
-      ->willReturnMap([
-        ['id', ['value' => 'id']],
-        ['uuid', ['value' => 'uuid']],
-        ['type', ['value' => 'type']],
-        ['langcode', ['value' => 'langcode']],
-        ['name', ['value' => 'name']],
-        ['description', ['value' => 'description__value', 'format' => 'description__format']],
-        ['homepage', ['value' => 'homepage']],
-        ['user_id', ['target_id' => 'user_id']],
-        ['string', ['value' => 'string_value']],
-      ]);
-    $table_mapping->expects($this->any())
-      ->method('getFieldNames')
-      ->willReturnMap([
-        ['entity_test', ['id', 'uuid', 'type', 'langcode', 'name', 'description', 'homepage', 'user_id']],
-        ['entity_test__string', ['string']],
-      ]);
-    $table_mapping->expects($this->any())
-      ->method('requiresDedicatedTableStorage')
-      ->willReturnCallback(function (BaseFieldDefinition $base_field) {
-        return $base_field->getName() === 'string';
-      });
-    $table_mapping->expects($this->any())
-      ->method('getDedicatedDataTableName')
-      ->willReturnCallback(function (BaseFieldDefinition $base_field) {
-        if ($base_field->getName() === 'string') {
-          return 'entity_test__string';
-        }
-      });
-
-    $this->entityStorage->expects($this->once())
-      ->method('getTableMapping')
-      ->willReturn($table_mapping);
-
-    $this->setupFieldStorageDefinition();
-
-    $data = $this->viewsData->getViewsData();
-
-    $this->assertNumericField($data['entity_test']['id']);
-    $this->assertField($data['entity_test']['id'], 'id');
-    $this->assertUuidField($data['entity_test']['uuid']);
-    $this->assertField($data['entity_test']['uuid'], 'uuid');
-    $this->assertStringField($data['entity_test']['type']);
-    $this->assertEquals('type', $data['entity_test']['type']['entity field']);
-
-    $this->assertLanguageField($data['entity_test']['langcode']);
-    $this->assertField($data['entity_test']['langcode'], 'langcode');
-    $this->assertEquals('Original language', $data['entity_test']['langcode']['title']);
-
-    $this->assertStringField($data['entity_test']['name']);
-    $this->assertField($data['entity_test']['name'], 'name');
-
-    $this->assertLongTextField($data['entity_test'], 'description');
-    $this->assertField($data['entity_test']['description__value'], 'description');
-    $this->assertField($data['entity_test']['description__format'], 'description');
-
-    $this->assertUriField($data['entity_test']['homepage']);
-    $this->assertField($data['entity_test']['homepage'], 'homepage');
-
-    $this->assertEntityReferenceField($data['entity_test']['user_id']);
-    $this->assertField($data['entity_test']['user_id'], 'user_id');
-
-    $relationship = $data['entity_test']['user_id']['relationship'];
-    $this->assertEquals('users_field_data', $relationship['base']);
-    $this->assertEquals('uid', $relationship['base field']);
-
-    // The string field name should be used as the 'entity field' but the actual
-    // field should reflect what the column mapping is using for multi-value
-    // base fields NOT just the field name. The actual column name returned from
-    // mappings in the test mocks is 'value'.
-    $this->assertStringField($data['entity_test__string']['string_value']);
-    $this->assertField($data['entity_test__string']['string_value'], 'string');
-    $this->assertEquals([
-      'left_field' => 'id',
-      'field' => 'entity_id',
-      'extra' => [[
-          'field' => 'deleted',
-          'value' => 0,
-          'numeric' => TRUE,
-        ],
-      ],
-    ], $data['entity_test__string']['table']['join']['entity_test']);
-  }
-
-  /**
-   * Tests fields on the data table.
-   */
-  public function testDataTableFields() {
-    $entity_type = $this->baseEntityType
-      ->set('data_table', 'entity_test_mul_property_data')
-      ->set('base_table', 'entity_test_mul')
-      ->set('id', 'entity_test_mul')
-      ->setKey('bundle', 'type');
-    $base_field_definitions = $this->setupBaseFields(EntityTestMul::baseFieldDefinitions($this->baseEntityType));
-    $base_field_definitions['type'] = BaseFieldDefinition::create('entity_reference')
-      ->setLabel('entity test type')
-      ->setSetting('target_type', 'entity_test_bundle')
-      ->setTranslatable(TRUE);
-    $base_field_definitions = $this->setupBaseFields($base_field_definitions);
-    $user_base_field_definitions = [
-      'uid' => BaseFieldDefinition::create('integer')
-        ->setLabel('ID')
-        ->setDescription('The ID of the user entity.')
-        ->setReadOnly(TRUE)
-        ->setSetting('unsigned', TRUE),
-    ];
-    $entity_test_type = new ConfigEntityType(['id' => 'entity_test_bundle']);
-
-    $this->entityFieldManager->expects($this->any())
-      ->method('getBaseFieldDefinitions')
-      ->will($this->returnValueMap([
-        ['user', $user_base_field_definitions],
-        ['entity_test_mul', $base_field_definitions],
-      ]));
-    $this->entityFieldManager->expects($this->any())
-      ->method('getBaseFieldDefinitions')
-      ->will($this->returnValueMap([
-        ['user', $user_base_field_definitions],
-        ['entity_test_mul', $base_field_definitions],
-      ]));
-
-    $this->viewsData->setEntityType($entity_type);
-
-    // Setup the table mapping.
-    $table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
-      ->disableOriginalConstructor()
-      ->getMock();
-    $table_mapping->expects($this->any())
-      ->method('getTableNames')
-      ->willReturn(['entity_test_mul', 'entity_test_mul_property_data', 'entity_test_mul__string']);
-    $table_mapping->expects($this->any())
-      ->method('getColumnNames')
-      ->willReturnMap([
-        ['id', ['value' => 'id']],
-        ['uuid', ['value' => 'uuid']],
-        ['type', ['value' => 'type']],
-        ['langcode', ['value' => 'langcode']],
-        ['name', ['value' => 'name']],
-        ['description', ['value' => 'description__value', 'format' => 'description__format']],
-        ['homepage', ['value' => 'homepage']],
-        ['user_id', ['target_id' => 'user_id']],
-        ['string', ['value' => 'string_value']],
-      ]);
-    $table_mapping->expects($this->any())
-      ->method('getFieldNames')
-      ->willReturnMap([
-        ['entity_test_mul', ['uuid']],
-        ['entity_test_mul_property_data', ['id', 'type', 'langcode', 'name', 'description', 'homepage', 'user_id']],
-        ['entity_test_mul__string', ['string']],
-      ]);
-
-    $table_mapping->expects($this->any())
-      ->method('getFieldTableName')
-      ->willReturnCallback(function ($field) {
-        if ($field == 'uuid') {
-          return 'entity_test_mul';
-        }
-        return 'entity_test_mul_property_data';
-      });
-    $table_mapping->expects($this->any())
-      ->method('requiresDedicatedTableStorage')
-      ->willReturnCallback(function (BaseFieldDefinition $base_field) {
-        return $base_field->getName() === 'string';
-      });
-    $table_mapping->expects($this->any())
-      ->method('getDedicatedDataTableName')
-      ->willReturnCallback(function (BaseFieldDefinition $base_field) {
-        if ($base_field->getName() === 'string') {
-          return 'entity_test_mul__string';
-        }
-      });
-
-    $this->entityStorage->expects($this->once())
-      ->method('getTableMapping')
-      ->willReturn($table_mapping);
-
-    $this->setupFieldStorageDefinition();
-
-    $user_entity_type = static::userEntityInfo();
-    $this->entityTypeManager->expects($this->any())
-      ->method('getDefinition')
-      ->will($this->returnValueMap([
-        ['user', TRUE, $user_entity_type],
-        ['entity_test_bundle', TRUE, $entity_test_type],
-      ]));
-
-    $data = $this->viewsData->getViewsData();
-
-    // Check the base fields.
-    $this->assertFalse(isset($data['entity_test_mul']['id']));
-    $this->assertFalse(isset($data['entity_test_mul']['type']));
-    $this->assertUuidField($data['entity_test_mul']['uuid']);
-    $this->assertField($data['entity_test_mul']['uuid'], 'uuid');
-
-    $this->assertFalse(isset($data['entity_test_mul']['type']['relationship']));
-
-    // Also ensure that field_data only fields don't appear on the base table.
-    $this->assertFalse(isset($data['entity_test_mul']['name']));
-    $this->assertFalse(isset($data['entity_test_mul']['description']));
-    $this->assertFalse(isset($data['entity_test_mul']['description__value']));
-    $this->assertFalse(isset($data['entity_test_mul']['description__format']));
-    $this->assertFalse(isset($data['entity_test_mul']['user_id']));
-    $this->assertFalse(isset($data['entity_test_mul']['homepage']));
-
-    // Check the data fields.
-    $this->assertNumericField($data['entity_test_mul_property_data']['id']);
-    $this->assertField($data['entity_test_mul_property_data']['id'], 'id');
-
-    $this->assertBundleField($data['entity_test_mul_property_data']['type']);
-    $this->assertField($data['entity_test_mul_property_data']['type'], 'type');
-
-    $this->assertLanguageField($data['entity_test_mul_property_data']['langcode']);
-    $this->assertField($data['entity_test_mul_property_data']['langcode'], 'langcode');
-    $this->assertEquals('Translation language', $data['entity_test_mul_property_data']['langcode']['title']);
-
-    $this->assertStringField($data['entity_test_mul_property_data']['name']);
-    $this->assertField($data['entity_test_mul_property_data']['name'], 'name');
-
-    $this->assertLongTextField($data['entity_test_mul_property_data'], 'description');
-    $this->assertField($data['entity_test_mul_property_data']['description__value'], 'description');
-    $this->assertField($data['entity_test_mul_property_data']['description__format'], 'description');
-
-    $this->assertUriField($data['entity_test_mul_property_data']['homepage']);
-    $this->assertField($data['entity_test_mul_property_data']['homepage'], 'homepage');
-
-    $this->assertEntityReferenceField($data['entity_test_mul_property_data']['user_id']);
-    $this->assertField($data['entity_test_mul_property_data']['user_id'], 'user_id');
-    $relationship = $data['entity_test_mul_property_data']['user_id']['relationship'];
-    $this->assertEquals('users_field_data', $relationship['base']);
-    $this->assertEquals('uid', $relationship['base field']);
-
-    $this->assertStringField($data['entity_test_mul__string']['string_value']);
-    $this->assertField($data['entity_test_mul__string']['string_value'], 'string');
-    $this->assertEquals([
-      'left_field' => 'id',
-      'field' => 'entity_id',
-      'extra' => [[
-          'field' => 'deleted',
-          'value' => 0,
-          'numeric' => TRUE,
-        ],
-      ],
-    ], $data['entity_test_mul__string']['table']['join']['entity_test_mul']);
-  }
-
-  /**
-   * Tests fields on the revision table.
-   */
-  public function testRevisionTableFields() {
-    $entity_type = $this->baseEntityType
-      ->set('base_table', 'entity_test_mulrev')
-      ->set('revision_table', 'entity_test_mulrev_revision')
-      ->set('data_table', 'entity_test_mulrev_property_data')
-      ->set('revision_data_table', 'entity_test_mulrev_property_revision')
-      ->set('id', 'entity_test_mulrev')
-      ->set('translatable', TRUE);
-    $base_field_definitions = $this->setupBaseFields(EntityTestMulRev::baseFieldDefinitions($this->baseEntityType));
-    $user_base_field_definitions = [
-      'uid' => BaseFieldDefinition::create('integer')
-        ->setLabel('ID')
-        ->setDescription('The ID of the user entity.')
-        ->setReadOnly(TRUE)
-        ->setSetting('unsigned', TRUE),
-    ];
-    $this->entityFieldManager->expects($this->any())
-      ->method('getBaseFieldDefinitions')
-      ->will($this->returnValueMap([
-        ['user', $user_base_field_definitions],
-        ['entity_test_mulrev', $base_field_definitions],
-      ]));
-    $this->entityFieldManager->expects($this->any())
-      ->method('getBaseFieldDefinitions')
-      ->will($this->returnValueMap([
-        ['user', $user_base_field_definitions],
-        ['entity_test_mulrev', $base_field_definitions],
-      ]));
-
-    $this->viewsData->setEntityType($entity_type);
-
-    // Setup the table mapping.
-    $table_mapping = $this->getMockBuilder(DefaultTableMapping::class)
-      ->disableOriginalConstructor()
-      ->getMock();
-    $table_mapping->expects($this->any())
-      ->method('getTableNames')
-      ->willReturn(['entity_test_mulrev', 'entity_test_mulrev_revision', 'entity_test_mulrev_property_data', 'entity_test_mulrev_property_revision', 'entity_test_mulrev__string', 'entity_test_mulrev_revision__string']);
-    $table_mapping->expects($this->any())
-      ->method('getColumnNames')
-      ->willReturnMap([
-        ['id', ['value' => 'id']],
-        ['uuid', ['value' => 'uuid']],
-        ['type', ['value' => 'type']],
-        ['langcode', ['value' => 'langcode']],
-        ['name', ['value' => 'name']],
-        ['description', ['value' => 'description__value', 'format' => 'description__format']],
-        ['homepage', ['value' => 'homepage']],
-        ['user_id', ['target_id' => 'user_id']],
-        ['revision_id', ['value' => 'revision_id']],
-        ['string', ['value' => 'string_value']],
-      ]);
-    $table_mapping->expects($this->any())
-      ->method('getFieldNames')
-      ->willReturnMap([
-        ['entity_test_mulrev', ['id', 'revision_id', 'uuid', 'type']],
-        ['entity_test_mulrev_revision', ['id', 'revision_id', 'langcode']],
-        ['entity_test_mulrev_property_data', ['id', 'revision_id', 'langcode', 'name', 'description', 'homepage', 'user_id']],
-        ['entity_test_mulrev_property_revision', ['id', 'revision_id', 'langcode', 'name', 'description', 'homepage', 'user_id']],
-        ['entity_test_mulrev__string', ['string']],
-        ['entity_test_mulrev_revision__string', ['string']],
-      ]);
-    $table_mapping->expects($this->any())
-      ->method('requiresDedicatedTableStorage')
-      ->willReturnCallback(function (BaseFieldDefinition $base_field) {
-        return $base_field->getName() === 'string';
-      });
-    $table_mapping->expects($this->any())
-      ->method('getDedicatedDataTableName')
-      ->willReturnCallback(function (BaseFieldDefinition $base_field) {
-        if ($base_field->getName() === 'string') {
-          return 'entity_test_mulrev__string';
-        }
-      });
-
-    $table_mapping->expects($this->any())
-      ->method('getDedicatedRevisionTableName')
-      ->willReturnCallback(function (BaseFieldDefinition $base_field) {
-        if ($base_field->getName() === 'string') {
-          return 'entity_test_mulrev_revision__string';
-        }
-      });
-
-    $table_mapping->expects($this->any())
-      ->method('getFieldTableName')
-      ->willReturnCallback(function ($field) {
-        if ($field == 'uuid') {
-          return 'entity_test_mulrev';
-        }
-        return 'entity_test_mulrev_property_data';
-      });
-
-    $this->entityStorage->expects($this->once())
-      ->method('getTableMapping')
-      ->willReturn($table_mapping);
-
-    $this->setupFieldStorageDefinition();
-
-    $data = $this->viewsData->getViewsData();
-
-    // Check the base fields.
-    $this->assertFalse(isset($data['entity_test_mulrev']['id']));
-    $this->assertFalse(isset($data['entity_test_mulrev']['type']));
-    $this->assertFalse(isset($data['entity_test_mulrev']['revision_id']));
-    $this->assertUuidField($data['entity_test_mulrev']['uuid']);
-    $this->assertField($data['entity_test_mulrev']['uuid'], 'uuid');
-
-    // Also ensure that field_data only fields don't appear on the base table.
-    $this->assertFalse(isset($data['entity_test_mulrev']['name']));
-    $this->assertFalse(isset($data['entity_test_mul']['description']));
-    $this->assertFalse(isset($data['entity_test_mul']['description__value']));
-    $this->assertFalse(isset($data['entity_test_mul']['description__format']));
-    $this->assertFalse(isset($data['entity_test_mul']['homepage']));
-    $this->assertFalse(isset($data['entity_test_mulrev']['langcode']));
-    $this->assertFalse(isset($data['entity_test_mulrev']['user_id']));
-
-    // Check the revision fields. The revision ID should only appear in the data
-    // table.
-    $this->assertFalse(isset($data['entity_test_mulrev_revision']['revision_id']));
-
-    // Also ensure that field_data only fields don't appear on the revision table.
-    $this->assertFalse(isset($data['entity_test_mulrev_revision']['id']));
-    $this->assertFalse(isset($data['entity_test_mulrev_revision']['name']));
-    $this->assertFalse(isset($data['entity_test_mulrev_revision']['description']));
-    $this->assertFalse(isset($data['entity_test_mulrev_revision']['description__value']));
-    $this->assertFalse(isset($data['entity_test_mulrev_revision']['description__format']));
-    $this->assertFalse(isset($data['entity_test_mulrev_revision']['homepage']));
-    $this->assertFalse(isset($data['entity_test_mulrev_revision']['user_id']));
-
-    // Check the data fields.
-    $this->assertNumericField($data['entity_test_mulrev_property_data']['id']);
-    $this->assertField($data['entity_test_mulrev_property_data']['id'], 'id');
-    $this->assertNumericField($data['entity_test_mulrev_property_data']['revision_id']);
-    $this->assertField($data['entity_test_mulrev_property_data']['revision_id'], 'revision_id');
-    $this->assertLanguageField($data['entity_test_mulrev_property_data']['langcode']);
-    $this->assertField($data['entity_test_mulrev_property_data']['langcode'], 'langcode');
-    $this->assertStringField($data['entity_test_mulrev_property_data']['name']);
-    $this->assertField($data['entity_test_mulrev_property_data']['name'], 'name');
-
-    $this->assertLongTextField($data['entity_test_mulrev_property_data'], 'description');
-    $this->assertField($data['entity_test_mulrev_property_data']['description__value'], 'description');
-    $this->assertField($data['entity_test_mulrev_property_data']['description__format'], 'description');
-    $this->assertUriField($data['entity_test_mulrev_property_data']['homepage']);
-    $this->assertField($data['entity_test_mulrev_property_data']['homepage'], 'homepage');
-
-    $this->assertEntityReferenceField($data['entity_test_mulrev_property_data']['user_id']);
-    $this->assertField($data['entity_test_mulrev_property_data']['user_id'], 'user_id');
-    $relationship = $data['entity_test_mulrev_property_data']['user_id']['relationship'];
-    $this->assertEquals('users_field_data', $relationship['base']);
-    $this->assertEquals('uid', $relationship['base field']);
-
-    // Check the property data fields.
-    $this->assertNumericField($data['entity_test_mulrev_property_revision']['id']);
-    $this->assertField($data['entity_test_mulrev_property_revision']['id'], 'id');
-
-    $this->assertLanguageField($data['entity_test_mulrev_property_revision']['langcode']);
-    $this->assertField($data['entity_test_mulrev_property_revision']['langcode'], 'langcode');
-    $this->assertEquals('Translation language', $data['entity_test_mulrev_property_revision']['langcode']['title']);
-
-    $this->assertStringField($data['entity_test_mulrev_property_revision']['name']);
-    $this->assertField($data['entity_test_mulrev_property_revision']['name'], 'name');
-
-    $this->assertLongTextField($data['entity_test_mulrev_property_revision'], 'description');
-    $this->assertField($data['entity_test_mulrev_property_revision']['description__value'], 'description');
-    $this->assertField($data['entity_test_mulrev_property_revision']['description__format'], 'description');
-
-    $this->assertUriField($data['entity_test_mulrev_property_revision']['homepage']);
-    $this->assertField($data['entity_test_mulrev_property_revision']['homepage'], 'homepage');
-
-    $this->assertEntityReferenceField($data['entity_test_mulrev_property_revision']['user_id']);
-    $this->assertField($data['entity_test_mulrev_property_revision']['user_id'], 'user_id');
-    $relationship = $data['entity_test_mulrev_property_revision']['user_id']['relationship'];
-    $this->assertEquals('users_field_data', $relationship['base']);
-    $this->assertEquals('uid', $relationship['base field']);
-
-    $this->assertStringField($data['entity_test_mulrev__string']['string_value']);
-    $this->assertField($data['entity_test_mulrev__string']['string_value'], 'string');
-    $this->assertEquals([
-      'left_field' => 'id',
-      'field' => 'entity_id',
-      'extra' => [[
-          'field' => 'deleted',
-          'value' => 0,
-          'numeric' => TRUE,
-        ],
-      ],
-    ], $data['entity_test_mulrev__string']['table']['join']['entity_test_mulrev_property_data']);
-
-    $this->assertStringField($data['entity_test_mulrev_revision__string']['string_value']);
-    $this->assertField($data['entity_test_mulrev_revision__string']['string_value'], 'string');
-    $this->assertEquals([
-      'left_field' => 'revision_id',
-      'field' => 'entity_id',
-      'extra' => [[
-          'field' => 'deleted',
-          'value' => 0,
-          'numeric' => TRUE,
-        ],
-      ],
-    ], $data['entity_test_mulrev_revision__string']['table']['join']['entity_test_mulrev_property_revision']);
-  }
-
-  /**
-   * Tests generic stuff per field.
-   *
-   * @param array $data
-   *   The views data to check.
-   * @param string $field_name
-   *   The entity field name.
-   */
-  protected function assertField($data, $field_name) {
-    $this->assertEquals($field_name, $data['entity field']);
-  }
-
-  /**
-   * Tests add link types.
-   */
-  public function testEntityLinks() {
-    $this->baseEntityType->setLinkTemplate('canonical', '/entity_test/{entity_test}');
-    $this->baseEntityType->setLinkTemplate('edit-form', '/entity_test/{entity_test}/edit');
-    $this->baseEntityType->setLinkTemplate('delete-form', '/entity_test/{entity_test}/delete');
-
-    $data = $this->viewsData->getViewsData();
-    foreach (['entity_test', 'entity_test_revision'] as $table_name) {
-      $this->assertEquals('entity_link', $data[$table_name]['view_entity_test']['field']['id']);
-      $this->assertEquals('entity_link_edit', $data[$table_name]['edit_entity_test']['field']['id']);
-      $this->assertEquals('entity_link_delete', $data[$table_name]['delete_entity_test']['field']['id']);
-    }
-  }
-
-  /**
-   * Tests additional edit links.
-   */
-  public function testEntityLinksJustEditForm() {
-    $this->baseEntityType->setLinkTemplate('edit-form', '/entity_test/{entity_test}/edit');
-
-    $data = $this->viewsData->getViewsData();
-
-    foreach (['entity_test', 'entity_test_revision'] as $table_name) {
-      $this->assertFalse(isset($data[$table_name]['view_entity_test']));
-      $this->assertFalse(isset($data[$table_name]['delete_entity_test']));
-
-      $this->assertEquals('entity_link_edit', $data[$table_name]['edit_entity_test']['field']['id']);
-    }
-  }
-
-  /**
-   * @covers ::getViewsData
-   */
-  public function testGetViewsDataWithoutEntityOperations() {
-    // Make sure there is no list builder. The API does not document is
-    // supports resetting entity handlers, so this might break in the future.
-    $this->baseEntityType->setListBuilderClass(NULL);
-    $data = $this->viewsData->getViewsData();
-    $this->assertArrayNotHasKey('operations', $data[$this->baseEntityType->getBaseTable()]);
-  }
-
-  /**
-   * @covers ::getViewsData
-   */
-  public function testGetViewsDataWithEntityOperations() {
-    $this->baseEntityType->setListBuilderClass('\Drupal\Core\Entity\EntityListBuilder');
-    $data = $this->viewsData->getViewsData();
-
-    $tables = ['entity_test', 'entity_test_revision'];
-    $this->assertSame($tables, array_keys($data));
-    foreach ($tables as $table_name) {
-      $this->assertSame('entity_operations', $data[$table_name]['operations']['field']['id']);
-    }
-  }
-
-  /**
-   * @covers ::getViewsData
-   */
-  public function testGetViewsDataWithNonRevisionableEntityOperations() {
-    $this->baseEntityType->setListBuilderClass('\Drupal\Core\Entity\EntityListBuilder');
-
-    $entity_type_without_revisions = $this->baseEntityType;
-    $views_data = $this->viewsData;
-
-    $entity_type_keys = $entity_type_without_revisions->getKeys();
-    unset($entity_type_keys['revision']);
-
-    $entity_type_without_revisions->set('entity_keys', $entity_type_keys);
-    $views_data->setEntityType($entity_type_without_revisions);
-
-    $data = $views_data->getViewsData();
-
-    $tables = ['entity_test'];
-    $this->assertSame($tables, array_keys($data));
-    foreach ($tables as $table_name) {
-      $this->assertSame('entity_operations', $data[$table_name]['operations']['field']['id']);
-    }
-  }
-
-  /**
-   * Tests views data for a string field.
-   *
-   * @param $data
-   *   The views data to check.
-   */
-  protected function assertStringField($data) {
-    $this->assertEquals('field', $data['field']['id']);
-    $this->assertEquals('string', $data['filter']['id']);
-    $this->assertEquals('string', $data['argument']['id']);
-    $this->assertEquals('standard', $data['sort']['id']);
-  }
-
-  /**
-   * Tests views data for a URI field.
-   *
-   * @param $data
-   *   The views data to check.
-   */
-  protected function assertUriField($data) {
-    $this->assertEquals('field', $data['field']['id']);
-    $this->assertEquals('string', $data['field']['default_formatter']);
-    $this->assertEquals('string', $data['filter']['id']);
-    $this->assertEquals('string', $data['argument']['id']);
-    $this->assertEquals('standard', $data['sort']['id']);
-  }
-
-  /**
-   * Tests views data for a long text field.
-   *
-   * @param $data
-   *   The views data for the table this field is in.
-   * @param $field_name
-   *   The name of the field being checked.
-   */
-  protected function assertLongTextField($data, $field_name) {
-    $value_field = $data[$field_name . '__value'];
-    $this->assertEquals('field', $value_field['field']['id']);
-    $this->assertEquals($field_name . '__format', $value_field['field']['format']);
-    $this->assertEquals('string', $value_field['filter']['id']);
-    $this->assertEquals('string', $value_field['argument']['id']);
-    $this->assertEquals('standard', $value_field['sort']['id']);
-
-    $this->assertStringField($data[$field_name . '__format']);
-  }
-
-  /**
-   * Tests views data for a UUID field.
-   *
-   * @param array $data
-   *   The views data to check.
-   */
-  protected function assertUuidField($data) {
-    // @todo Can we provide additional support for UUIDs in views?
-    $this->assertEquals('field', $data['field']['id']);
-    $this->assertFalse($data['field']['click sortable']);
-    $this->assertEquals('string', $data['filter']['id']);
-    $this->assertEquals('string', $data['argument']['id']);
-    $this->assertEquals('standard', $data['sort']['id']);
-  }
-
-  /**
-   * Tests views data for a numeric field.
-   *
-   * @param array $data
-   *   The views data to check.
-   */
-  protected function assertNumericField($data) {
-    $this->assertEquals('field', $data['field']['id']);
-    $this->assertEquals('numeric', $data['filter']['id']);
-    $this->assertEquals('numeric', $data['argument']['id']);
-    $this->assertEquals('standard', $data['sort']['id']);
-  }
-
-  /**
-   * Tests views data for a language field.
-   *
-   * @param array $data
-   *   The views data to check.
-   */
-  protected function assertLanguageField($data) {
-    $this->assertEquals('field', $data['field']['id']);
-    $this->assertEquals('language', $data['filter']['id']);
-    $this->assertEquals('language', $data['argument']['id']);
-    $this->assertEquals('standard', $data['sort']['id']);
-  }
-
-  /**
-   * Tests views data for an entity reference field.
-   */
-  protected function assertEntityReferenceField($data) {
-    $this->assertEquals('field', $data['field']['id']);
-    $this->assertEquals('numeric', $data['filter']['id']);
-    $this->assertEquals('numeric', $data['argument']['id']);
-    $this->assertEquals('standard', $data['sort']['id']);
-  }
-
-  /**
-   * Tests views data for a bundle field.
-   */
-  protected function assertBundleField($data) {
-    $this->assertEquals('field', $data['field']['id']);
-    $this->assertEquals('bundle', $data['filter']['id']);
-    $this->assertEquals('string', $data['argument']['id']);
-    $this->assertEquals('standard', $data['sort']['id']);
-  }
-
-  /**
-   * Returns entity info for the user entity.
-   *
-   * @return array
-   */
-  protected static function userEntityInfo() {
-    return new ContentEntityType([
-      'id' => 'user',
-      'class' => 'Drupal\user\Entity\User',
-      'label' => 'User',
-      'base_table' => 'users',
-      'data_table' => 'users_field_data',
-      'entity_keys' => [
-        'id' => 'uid',
-        'uuid' => 'uuid',
-      ],
-    ]);
-  }
-
-}
-
-class TestEntityViewsData extends EntityViewsData {
-
-  public function setEntityType(EntityTypeInterface $entity_type) {
-    $this->entityType = $entity_type;
-  }
-
-}
-
-class TestEntityType extends ContentEntityType {
-
-  /**
-   * Sets a specific entity key.
-   *
-   * @param string $key
-   *   The name of the entity key.
-   * @param string $value
-   *   The new value of the key.
-   *
-   * @return $this
-   */
-  public function setKey($key, $value) {
-    $this->entity_keys[$key] = $value;
-    return $this;
-  }
-
-}