5 * Contains \Drupal\Tests\Core\Config\Entity\ConfigEntityBaseUnitTest.
8 namespace Drupal\Tests\Core\Config\Entity;
10 use Drupal\Component\Plugin\PluginManagerInterface;
11 use Drupal\Core\Config\Schema\SchemaIncompleteException;
12 use Drupal\Core\DependencyInjection\ContainerBuilder;
13 use Drupal\Core\Entity\EntityTypeManagerInterface;
14 use Drupal\Core\Language\Language;
15 use Drupal\Core\Plugin\DefaultLazyPluginCollection;
16 use Drupal\Tests\Core\Config\Entity\Fixtures\ConfigEntityBaseWithPluginCollections;
17 use Drupal\Tests\Core\Plugin\Fixtures\TestConfigurablePlugin;
18 use Drupal\Tests\UnitTestCase;
21 * @coversDefaultClass \Drupal\Core\Config\Entity\ConfigEntityBase
24 class ConfigEntityBaseUnitTest extends UnitTestCase {
27 * The entity under test.
29 * @var \Drupal\Core\Config\Entity\ConfigEntityBase|\PHPUnit_Framework_MockObject_MockObject
34 * The entity type used for testing.
36 * @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject
38 protected $entityType;
41 * The entity type manager used for testing.
43 * @var \Drupal\Core\Entity\EntityTypeManagerInterface|\PHPUnit_Framework_MockObject_MockObject
45 protected $entityTypeManager;
48 * The ID of the type of the entity under test.
52 protected $entityTypeId;
55 * The UUID generator used for testing.
57 * @var \Drupal\Component\Uuid\UuidInterface|\PHPUnit_Framework_MockObject_MockObject
62 * The provider of the entity type.
69 * The language manager.
71 * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
73 protected $languageManager;
83 * The mocked cache backend.
85 * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject
87 protected $cacheTagsInvalidator;
90 * The mocked typed config manager.
92 * @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit_Framework_MockObject_MockObject
94 protected $typedConfigManager;
99 protected function setUp() {
100 $this->id = $this->randomMachineName();
104 'uuid' => '3bb9ee60-bea5-4622-b89b-a63319d10b3a',
106 $this->entityTypeId = $this->randomMachineName();
107 $this->provider = $this->randomMachineName();
108 $this->entityType = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityTypeInterface');
109 $this->entityType->expects($this->any())
110 ->method('getProvider')
111 ->will($this->returnValue($this->provider));
112 $this->entityType->expects($this->any())
113 ->method('getConfigPrefix')
114 ->willReturn('test_provider.' . $this->entityTypeId);
116 $this->entityTypeManager = $this->getMock(EntityTypeManagerInterface::class);
117 $this->entityTypeManager->expects($this->any())
118 ->method('getDefinition')
119 ->with($this->entityTypeId)
120 ->will($this->returnValue($this->entityType));
122 $this->uuid = $this->getMock('\Drupal\Component\Uuid\UuidInterface');
124 $this->languageManager = $this->getMock('\Drupal\Core\Language\LanguageManagerInterface');
125 $this->languageManager->expects($this->any())
126 ->method('getLanguage')
128 ->will($this->returnValue(new Language(['id' => 'en'])));
130 $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface');
132 $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface');
134 $container = new ContainerBuilder();
135 $container->set('entity_type.manager', $this->entityTypeManager);
136 $container->set('uuid', $this->uuid);
137 $container->set('language_manager', $this->languageManager);
138 $container->set('cache_tags.invalidator', $this->cacheTagsInvalidator);
139 $container->set('config.typed', $this->typedConfigManager);
140 \Drupal::setContainer($container);
142 $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', [$values, $this->entityTypeId]);
146 * @covers ::calculateDependencies
147 * @covers ::getDependencies
149 public function testCalculateDependencies() {
150 // Calculating dependencies will reset the dependencies array.
151 $this->entity->set('dependencies', ['module' => ['node']]);
152 $this->assertEmpty($this->entity->calculateDependencies()->getDependencies());
154 // Calculating dependencies will reset the dependencies array using enforced
156 $this->entity->set('dependencies', ['module' => ['node'], 'enforced' => ['module' => 'views']]);
157 $dependencies = $this->entity->calculateDependencies()->getDependencies();
158 $this->assertContains('views', $dependencies['module']);
159 $this->assertNotContains('node', $dependencies['module']);
165 public function testPreSaveDuringSync() {
166 $query = $this->getMock('\Drupal\Core\Entity\Query\QueryInterface');
167 $storage = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityStorageInterface');
169 $query->expects($this->any())
171 ->will($this->returnValue([]));
172 $query->expects($this->any())
173 ->method('condition')
174 ->will($this->returnValue($query));
175 $storage->expects($this->any())
177 ->will($this->returnValue($query));
178 $storage->expects($this->any())
179 ->method('loadUnchanged')
180 ->will($this->returnValue($this->entity));
182 // Saving an entity will not reset the dependencies array during config
184 $this->entity->set('dependencies', ['module' => ['node']]);
185 $this->entity->preSave($storage);
186 $this->assertEmpty($this->entity->getDependencies());
188 $this->entity->setSyncing(TRUE);
189 $this->entity->set('dependencies', ['module' => ['node']]);
190 $this->entity->preSave($storage);
191 $dependencies = $this->entity->getDependencies();
192 $this->assertContains('node', $dependencies['module']);
196 * @covers ::addDependency
198 public function testAddDependency() {
199 $method = new \ReflectionMethod('\Drupal\Core\Config\Entity\ConfigEntityBase', 'addDependency');
200 $method->setAccessible(TRUE);
201 $method->invoke($this->entity, 'module', $this->provider);
202 $method->invoke($this->entity, 'module', 'core');
203 $method->invoke($this->entity, 'module', 'node');
204 $dependencies = $this->entity->getDependencies();
205 $this->assertNotContains($this->provider, $dependencies['module']);
206 $this->assertNotContains('core', $dependencies['module']);
207 $this->assertContains('node', $dependencies['module']);
209 // Test sorting of dependencies.
210 $method->invoke($this->entity, 'module', 'action');
211 $dependencies = $this->entity->getDependencies();
212 $this->assertEquals(['action', 'node'], $dependencies['module']);
214 // Test sorting of dependency types.
215 $method->invoke($this->entity, 'entity', 'system.action.id');
216 $dependencies = $this->entity->getDependencies();
217 $this->assertEquals(['entity', 'module'], array_keys($dependencies));
221 * @covers ::getDependencies
222 * @covers ::calculateDependencies
224 * @dataProvider providerCalculateDependenciesWithPluginCollections
226 public function testCalculateDependenciesWithPluginCollections($definition, $expected_dependencies) {
228 $this->entity = $this->getMockBuilder('\Drupal\Tests\Core\Config\Entity\Fixtures\ConfigEntityBaseWithPluginCollections')
229 ->setConstructorArgs([$values, $this->entityTypeId])
230 ->setMethods(['getPluginCollections'])
233 // Create a configurable plugin that would add a dependency.
234 $instance_id = $this->randomMachineName();
235 $instance = new TestConfigurablePlugin([], $instance_id, $definition);
237 // Create a plugin collection to contain the instance.
238 $pluginCollection = $this->getMockBuilder('\Drupal\Core\Plugin\DefaultLazyPluginCollection')
239 ->disableOriginalConstructor()
240 ->setMethods(['get'])
242 $pluginCollection->expects($this->atLeastOnce())
245 ->will($this->returnValue($instance));
246 $pluginCollection->addInstanceId($instance_id);
248 // Return the mocked plugin collection.
249 $this->entity->expects($this->once())
250 ->method('getPluginCollections')
251 ->will($this->returnValue([$pluginCollection]));
253 $this->assertEquals($expected_dependencies, $this->entity->calculateDependencies()->getDependencies());
257 * Data provider for testCalculateDependenciesWithPluginCollections.
261 public function providerCalculateDependenciesWithPluginCollections() {
262 // Start with 'a' so that order of the dependency array is fixed.
263 $instance_dependency_1 = 'a' . $this->randomMachineName(10);
264 $instance_dependency_2 = 'a' . $this->randomMachineName(11);
267 // Tests that the plugin provider is a module dependency.
269 ['provider' => 'test'],
270 ['module' => ['test']],
272 // Tests that a plugin that is provided by the same module as the config
273 // entity is not added to the dependencies array.
275 ['provider' => $this->provider],
276 ['module' => [NULL]],
278 // Tests that a config entity that has a plugin which provides config
279 // dependencies in its definition has them.
282 'provider' => 'test',
283 'config_dependencies' => [
284 'config' => [$instance_dependency_1],
285 'module' => [$instance_dependency_2],
289 'config' => [$instance_dependency_1],
290 'module' => [$instance_dependency_2, 'test']
297 * @covers ::calculateDependencies
298 * @covers ::getDependencies
299 * @covers ::onDependencyRemoval
301 public function testCalculateDependenciesWithThirdPartySettings() {
302 $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', [[], $this->entityTypeId]);
303 $this->entity->setThirdPartySetting('test_provider', 'test', 'test');
304 $this->entity->setThirdPartySetting('test_provider2', 'test', 'test');
305 $this->entity->setThirdPartySetting($this->provider, 'test', 'test');
307 $this->assertEquals(['test_provider', 'test_provider2'], $this->entity->calculateDependencies()->getDependencies()['module']);
308 $changed = $this->entity->onDependencyRemoval(['module' => ['test_provider2']]);
309 $this->assertTrue($changed, 'Calling onDependencyRemoval with an existing third party dependency provider returns TRUE.');
310 $changed = $this->entity->onDependencyRemoval(['module' => ['test_provider3']]);
311 $this->assertFalse($changed, 'Calling onDependencyRemoval with a non-existing third party dependency provider returns FALSE.');
312 $this->assertEquals(['test_provider'], $this->entity->calculateDependencies()->getDependencies()['module']);
318 public function testSleepWithPluginCollections() {
319 $instance_id = 'the_instance_id';
320 $instance = new TestConfigurablePlugin([], $instance_id, []);
322 $plugin_manager = $this->prophesize(PluginManagerInterface::class);
323 $plugin_manager->createInstance($instance_id, ['id' => $instance_id])->willReturn($instance);
325 $entity_values = ['the_plugin_collection_config' => [$instance_id => ['foo' => 'original_value']]];
326 $entity = new TestConfigEntityWithPluginCollections($entity_values, $this->entityTypeId);
327 $entity->setPluginManager($plugin_manager->reveal());
329 // After creating the entity, change the plugin configuration.
330 $instance->setConfiguration(['foo' => 'new_value']);
332 // After changing the plugin configuration, the entity still has the
334 $expected_plugin_config = [$instance_id => ['foo' => 'original_value']];
335 $this->assertSame($expected_plugin_config, $entity->get('the_plugin_collection_config'));
337 // Ensure the plugin collection is not stored.
338 $this->assertNotContains('pluginCollection', $entity->__sleep());
340 $expected_plugin_config = [$instance_id => ['foo' => 'new_value']];
341 // Ensure the updated values are stored in the entity.
342 $this->assertSame($expected_plugin_config, $entity->get('the_plugin_collection_config'));
346 * @covers ::setOriginalId
347 * @covers ::getOriginalId
349 public function testGetOriginalId() {
350 $new_id = $this->randomMachineName();
351 $this->entity->set('id', $new_id);
352 $this->assertSame($this->id, $this->entity->getOriginalId());
353 $this->assertSame($this->entity, $this->entity->setOriginalId($new_id));
354 $this->assertSame($new_id, $this->entity->getOriginalId());
356 // Check that setOriginalId() does not change the entity "isNew" status.
357 $this->assertFalse($this->entity->isNew());
358 $this->entity->setOriginalId($this->randomMachineName());
359 $this->assertFalse($this->entity->isNew());
360 $this->entity->enforceIsNew();
361 $this->assertTrue($this->entity->isNew());
362 $this->entity->setOriginalId($this->randomMachineName());
363 $this->assertTrue($this->entity->isNew());
369 public function testIsNew() {
370 $this->assertFalse($this->entity->isNew());
371 $this->assertSame($this->entity, $this->entity->enforceIsNew());
372 $this->assertTrue($this->entity->isNew());
373 $this->entity->enforceIsNew(FALSE);
374 $this->assertFalse($this->entity->isNew());
381 public function testGet() {
383 $value = $this->randomMachineName();
384 $this->assertSame($this->id, $this->entity->get($name));
385 $this->assertSame($this->entity, $this->entity->set($name, $value));
386 $this->assertSame($value, $this->entity->get($name));
390 * @covers ::setStatus
393 public function testSetStatus() {
394 $this->assertTrue($this->entity->status());
395 $this->assertSame($this->entity, $this->entity->setStatus(FALSE));
396 $this->assertFalse($this->entity->status());
397 $this->entity->setStatus(TRUE);
398 $this->assertTrue($this->entity->status());
403 * @depends testSetStatus
405 public function testEnable() {
406 $this->entity->setStatus(FALSE);
407 $this->assertSame($this->entity, $this->entity->enable());
408 $this->assertTrue($this->entity->status());
413 * @depends testSetStatus
415 public function testDisable() {
416 $this->entity->setStatus(TRUE);
417 $this->assertSame($this->entity, $this->entity->disable());
418 $this->assertFalse($this->entity->status());
422 * @covers ::setSyncing
423 * @covers ::isSyncing
425 public function testIsSyncing() {
426 $this->assertFalse($this->entity->isSyncing());
427 $this->assertSame($this->entity, $this->entity->setSyncing(TRUE));
428 $this->assertTrue($this->entity->isSyncing());
429 $this->entity->setSyncing(FALSE);
430 $this->assertFalse($this->entity->isSyncing());
434 * @covers ::createDuplicate
436 public function testCreateDuplicate() {
437 $this->entityType->expects($this->at(0))
440 ->will($this->returnValue('id'));
442 $this->entityType->expects($this->at(1))
445 ->will($this->returnValue(TRUE));
447 $this->entityType->expects($this->at(2))
450 ->will($this->returnValue('uuid'));
452 $new_uuid = '8607ef21-42bc-4913-978f-8c06207b0395';
453 $this->uuid->expects($this->once())
455 ->will($this->returnValue($new_uuid));
457 $duplicate = $this->entity->createDuplicate();
458 $this->assertInstanceOf('\Drupal\Core\Entity\Entity', $duplicate);
459 $this->assertNotSame($this->entity, $duplicate);
460 $this->assertFalse($this->entity->isNew());
461 $this->assertTrue($duplicate->isNew());
462 $this->assertNull($duplicate->id());
463 $this->assertNull($duplicate->getOriginalId());
464 $this->assertNotEquals($this->entity->uuid(), $duplicate->uuid());
465 $this->assertSame($new_uuid, $duplicate->uuid());
471 public function testSort() {
472 $this->entityTypeManager->expects($this->any())
473 ->method('getDefinition')
474 ->with($this->entityTypeId)
475 ->will($this->returnValue([
481 $entity_a = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityInterface');
482 $entity_a->expects($this->atLeastOnce())
485 $entity_b = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityInterface');
486 $entity_b->expects($this->atLeastOnce())
490 // Test sorting by label.
491 $list = [$entity_a, $entity_b];
492 // Suppress errors because of https://bugs.php.net/bug.php?id=50688.
493 @usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
494 $this->assertSame($entity_b, $list[0]);
496 $list = [$entity_b, $entity_a];
497 // Suppress errors because of https://bugs.php.net/bug.php?id=50688.
498 @usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
499 $this->assertSame($entity_b, $list[0]);
501 // Test sorting by weight.
502 $entity_a->weight = 0;
503 $entity_b->weight = 1;
504 $list = [$entity_b, $entity_a];
505 // Suppress errors because of https://bugs.php.net/bug.php?id=50688.
506 @usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
507 $this->assertSame($entity_a, $list[0]);
509 $list = [$entity_a, $entity_b];
510 // Suppress errors because of https://bugs.php.net/bug.php?id=50688.
511 @usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
512 $this->assertSame($entity_a, $list[0]);
518 public function testToArray() {
519 $this->typedConfigManager->expects($this->never())
520 ->method('getDefinition');
521 $this->entityType->expects($this->any())
522 ->method('getPropertiesToExport')
523 ->willReturn(['id' => 'configId', 'dependencies' => 'dependencies']);
524 $properties = $this->entity->toArray();
525 $this->assertInternalType('array', $properties);
526 $this->assertEquals(['configId' => $this->entity->id(), 'dependencies' => []], $properties);
532 public function testToArrayIdKey() {
533 $entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', [[], $this->entityTypeId], '', TRUE, TRUE, TRUE, ['id', 'get']);
534 $entity->expects($this->atLeastOnce())
536 ->willReturn($this->id);
537 $entity->expects($this->once())
539 ->with('dependencies')
541 $this->typedConfigManager->expects($this->never())
542 ->method('getDefinition');
543 $this->entityType->expects($this->any())
544 ->method('getPropertiesToExport')
545 ->willReturn(['id' => 'configId', 'dependencies' => 'dependencies']);
546 $this->entityType->expects($this->once())
550 $properties = $entity->toArray();
551 $this->assertInternalType('array', $properties);
552 $this->assertEquals(['configId' => $entity->id(), 'dependencies' => []], $properties);
558 public function testToArraySchemaFallback() {
559 $this->typedConfigManager->expects($this->once())
560 ->method('getDefinition')
561 ->will($this->returnValue(['mapping' => ['id' => '', 'dependencies' => '']]));
562 $this->entityType->expects($this->any())
563 ->method('getPropertiesToExport')
565 $properties = $this->entity->toArray();
566 $this->assertInternalType('array', $properties);
567 $this->assertEquals(['id' => $this->entity->id(), 'dependencies' => []], $properties);
573 public function testToArrayFallback() {
574 $this->entityType->expects($this->any())
575 ->method('getPropertiesToExport')
577 $this->setExpectedException(SchemaIncompleteException::class);
578 $this->entity->toArray();
582 * @covers ::getThirdPartySetting
583 * @covers ::setThirdPartySetting
584 * @covers ::getThirdPartySettings
585 * @covers ::unsetThirdPartySetting
586 * @covers ::getThirdPartyProviders
588 public function testThirdPartySettings() {
590 $third_party = 'test_provider';
591 $value = $this->getRandomGenerator()->string();
593 // Test getThirdPartySetting() with no settings.
594 $this->assertEquals($value, $this->entity->getThirdPartySetting($third_party, $key, $value));
595 $this->assertNull($this->entity->getThirdPartySetting($third_party, $key));
597 // Test setThirdPartySetting().
598 $this->entity->setThirdPartySetting($third_party, $key, $value);
599 $this->assertEquals($value, $this->entity->getThirdPartySetting($third_party, $key));
600 $this->assertEquals($value, $this->entity->getThirdPartySetting($third_party, $key, $this->randomGenerator->string()));
602 // Test getThirdPartySettings().
603 $this->entity->setThirdPartySetting($third_party, 'test2', 'value2');
604 $this->assertEquals([$key => $value, 'test2' => 'value2'], $this->entity->getThirdPartySettings($third_party));
606 // Test getThirdPartyProviders().
607 $this->entity->setThirdPartySetting('test_provider2', $key, $value);
608 $this->assertEquals([$third_party, 'test_provider2'], $this->entity->getThirdPartyProviders());
610 // Test unsetThirdPartyProviders().
611 $this->entity->unsetThirdPartySetting('test_provider2', $key);
612 $this->assertEquals([$third_party], $this->entity->getThirdPartyProviders());
617 class TestConfigEntityWithPluginCollections extends ConfigEntityBaseWithPluginCollections {
619 protected $pluginCollection;
621 public function setPluginManager(PluginManagerInterface $plugin_manager) {
622 $this->pluginCollection = new DefaultLazyPluginCollection($plugin_manager, ['the_instance_id' => ['id' => 'the_instance_id']]);
628 public function getPluginCollections() {
629 return ['the_plugin_collection_config' => $this->pluginCollection];