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\Language\Language;
14 use Drupal\Core\Plugin\DefaultLazyPluginCollection;
15 use Drupal\Tests\Core\Config\Entity\Fixtures\ConfigEntityBaseWithPluginCollections;
16 use Drupal\Tests\Core\Plugin\Fixtures\TestConfigurablePlugin;
17 use Drupal\Tests\UnitTestCase;
20 * @coversDefaultClass \Drupal\Core\Config\Entity\ConfigEntityBase
23 class ConfigEntityBaseUnitTest extends UnitTestCase {
26 * The entity under test.
28 * @var \Drupal\Core\Config\Entity\ConfigEntityBase|\PHPUnit_Framework_MockObject_MockObject
33 * The entity type used for testing.
35 * @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject
37 protected $entityType;
40 * The entity manager used for testing.
42 * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
44 protected $entityManager;
47 * The ID of the type of the entity under test.
51 protected $entityTypeId;
54 * The UUID generator used for testing.
56 * @var \Drupal\Component\Uuid\UuidInterface|\PHPUnit_Framework_MockObject_MockObject
61 * The provider of the entity type.
68 * The language manager.
70 * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
72 protected $languageManager;
82 * The mocked cache backend.
84 * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject
86 protected $cacheTagsInvalidator;
89 * The mocked typed config manager.
91 * @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit_Framework_MockObject_MockObject
93 protected $typedConfigManager;
98 protected function setUp() {
99 $this->id = $this->randomMachineName();
103 'uuid' => '3bb9ee60-bea5-4622-b89b-a63319d10b3a',
105 $this->entityTypeId = $this->randomMachineName();
106 $this->provider = $this->randomMachineName();
107 $this->entityType = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityTypeInterface');
108 $this->entityType->expects($this->any())
109 ->method('getProvider')
110 ->will($this->returnValue($this->provider));
111 $this->entityType->expects($this->any())
112 ->method('getConfigPrefix')
113 ->willReturn('test_provider.' . $this->entityTypeId);
115 $this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
116 $this->entityManager->expects($this->any())
117 ->method('getDefinition')
118 ->with($this->entityTypeId)
119 ->will($this->returnValue($this->entityType));
121 $this->uuid = $this->getMock('\Drupal\Component\Uuid\UuidInterface');
123 $this->languageManager = $this->getMock('\Drupal\Core\Language\LanguageManagerInterface');
124 $this->languageManager->expects($this->any())
125 ->method('getLanguage')
127 ->will($this->returnValue(new Language(['id' => 'en'])));
129 $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface');
131 $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface');
133 $container = new ContainerBuilder();
134 $container->set('entity.manager', $this->entityManager);
135 $container->set('uuid', $this->uuid);
136 $container->set('language_manager', $this->languageManager);
137 $container->set('cache_tags.invalidator', $this->cacheTagsInvalidator);
138 $container->set('config.typed', $this->typedConfigManager);
139 \Drupal::setContainer($container);
141 $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', [$values, $this->entityTypeId]);
145 * @covers ::calculateDependencies
146 * @covers ::getDependencies
148 public function testCalculateDependencies() {
149 // Calculating dependencies will reset the dependencies array.
150 $this->entity->set('dependencies', ['module' => ['node']]);
151 $this->assertEmpty($this->entity->calculateDependencies()->getDependencies());
153 // Calculating dependencies will reset the dependencies array using enforced
155 $this->entity->set('dependencies', ['module' => ['node'], 'enforced' => ['module' => 'views']]);
156 $dependencies = $this->entity->calculateDependencies()->getDependencies();
157 $this->assertContains('views', $dependencies['module']);
158 $this->assertNotContains('node', $dependencies['module']);
164 public function testPreSaveDuringSync() {
165 $query = $this->getMock('\Drupal\Core\Entity\Query\QueryInterface');
166 $storage = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityStorageInterface');
168 $query->expects($this->any())
170 ->will($this->returnValue([]));
171 $query->expects($this->any())
172 ->method('condition')
173 ->will($this->returnValue($query));
174 $storage->expects($this->any())
176 ->will($this->returnValue($query));
177 $storage->expects($this->any())
178 ->method('loadUnchanged')
179 ->will($this->returnValue($this->entity));
181 // Saving an entity will not reset the dependencies array during config
183 $this->entity->set('dependencies', ['module' => ['node']]);
184 $this->entity->preSave($storage);
185 $this->assertEmpty($this->entity->getDependencies());
187 $this->entity->setSyncing(TRUE);
188 $this->entity->set('dependencies', ['module' => ['node']]);
189 $this->entity->preSave($storage);
190 $dependencies = $this->entity->getDependencies();
191 $this->assertContains('node', $dependencies['module']);
195 * @covers ::addDependency
197 public function testAddDependency() {
198 $method = new \ReflectionMethod('\Drupal\Core\Config\Entity\ConfigEntityBase', 'addDependency');
199 $method->setAccessible(TRUE);
200 $method->invoke($this->entity, 'module', $this->provider);
201 $method->invoke($this->entity, 'module', 'core');
202 $method->invoke($this->entity, 'module', 'node');
203 $dependencies = $this->entity->getDependencies();
204 $this->assertNotContains($this->provider, $dependencies['module']);
205 $this->assertNotContains('core', $dependencies['module']);
206 $this->assertContains('node', $dependencies['module']);
208 // Test sorting of dependencies.
209 $method->invoke($this->entity, 'module', 'action');
210 $dependencies = $this->entity->getDependencies();
211 $this->assertEquals(['action', 'node'], $dependencies['module']);
213 // Test sorting of dependency types.
214 $method->invoke($this->entity, 'entity', 'system.action.id');
215 $dependencies = $this->entity->getDependencies();
216 $this->assertEquals(['entity', 'module'], array_keys($dependencies));
220 * @covers ::getDependencies
221 * @covers ::calculateDependencies
223 * @dataProvider providerCalculateDependenciesWithPluginCollections
225 public function testCalculateDependenciesWithPluginCollections($definition, $expected_dependencies) {
227 $this->entity = $this->getMockBuilder('\Drupal\Tests\Core\Config\Entity\Fixtures\ConfigEntityBaseWithPluginCollections')
228 ->setConstructorArgs([$values, $this->entityTypeId])
229 ->setMethods(['getPluginCollections'])
232 // Create a configurable plugin that would add a dependency.
233 $instance_id = $this->randomMachineName();
234 $instance = new TestConfigurablePlugin([], $instance_id, $definition);
236 // Create a plugin collection to contain the instance.
237 $pluginCollection = $this->getMockBuilder('\Drupal\Core\Plugin\DefaultLazyPluginCollection')
238 ->disableOriginalConstructor()
239 ->setMethods(['get'])
241 $pluginCollection->expects($this->atLeastOnce())
244 ->will($this->returnValue($instance));
245 $pluginCollection->addInstanceId($instance_id);
247 // Return the mocked plugin collection.
248 $this->entity->expects($this->once())
249 ->method('getPluginCollections')
250 ->will($this->returnValue([$pluginCollection]));
252 $this->assertEquals($expected_dependencies, $this->entity->calculateDependencies()->getDependencies());
256 * Data provider for testCalculateDependenciesWithPluginCollections.
260 public function providerCalculateDependenciesWithPluginCollections() {
261 // Start with 'a' so that order of the dependency array is fixed.
262 $instance_dependency_1 = 'a' . $this->randomMachineName(10);
263 $instance_dependency_2 = 'a' . $this->randomMachineName(11);
266 // Tests that the plugin provider is a module dependency.
268 ['provider' => 'test'],
269 ['module' => ['test']],
271 // Tests that a plugin that is provided by the same module as the config
272 // entity is not added to the dependencies array.
274 ['provider' => $this->provider],
275 ['module' => [NULL]],
277 // Tests that a config entity that has a plugin which provides config
278 // dependencies in its definition has them.
281 'provider' => 'test',
282 'config_dependencies' => [
283 'config' => [$instance_dependency_1],
284 'module' => [$instance_dependency_2],
288 'config' => [$instance_dependency_1],
289 'module' => [$instance_dependency_2, 'test']
296 * @covers ::calculateDependencies
297 * @covers ::getDependencies
298 * @covers ::onDependencyRemoval
300 public function testCalculateDependenciesWithThirdPartySettings() {
301 $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', [[], $this->entityTypeId]);
302 $this->entity->setThirdPartySetting('test_provider', 'test', 'test');
303 $this->entity->setThirdPartySetting('test_provider2', 'test', 'test');
304 $this->entity->setThirdPartySetting($this->provider, 'test', 'test');
306 $this->assertEquals(['test_provider', 'test_provider2'], $this->entity->calculateDependencies()->getDependencies()['module']);
307 $changed = $this->entity->onDependencyRemoval(['module' => ['test_provider2']]);
308 $this->assertTrue($changed, 'Calling onDependencyRemoval with an existing third party dependency provider returns TRUE.');
309 $changed = $this->entity->onDependencyRemoval(['module' => ['test_provider3']]);
310 $this->assertFalse($changed, 'Calling onDependencyRemoval with a non-existing third party dependency provider returns FALSE.');
311 $this->assertEquals(['test_provider'], $this->entity->calculateDependencies()->getDependencies()['module']);
317 public function testSleepWithPluginCollections() {
318 $instance_id = 'the_instance_id';
319 $instance = new TestConfigurablePlugin([], $instance_id, []);
321 $plugin_manager = $this->prophesize(PluginManagerInterface::class);
322 $plugin_manager->createInstance($instance_id, ['id' => $instance_id])->willReturn($instance);
324 $entity_values = ['the_plugin_collection_config' => [$instance_id => ['foo' => 'original_value']]];
325 $entity = new TestConfigEntityWithPluginCollections($entity_values, $this->entityTypeId);
326 $entity->setPluginManager($plugin_manager->reveal());
328 // After creating the entity, change the plugin configuration.
329 $instance->setConfiguration(['foo' => 'new_value']);
331 // After changing the plugin configuration, the entity still has the
333 $expected_plugin_config = [$instance_id => ['foo' => 'original_value']];
334 $this->assertSame($expected_plugin_config, $entity->get('the_plugin_collection_config'));
336 // Ensure the plugin collection is not stored.
337 $this->assertNotContains('pluginCollection', $entity->__sleep());
339 $expected_plugin_config = [$instance_id => ['foo' => 'new_value']];
340 // Ensure the updated values are stored in the entity.
341 $this->assertSame($expected_plugin_config, $entity->get('the_plugin_collection_config'));
345 * @covers ::setOriginalId
346 * @covers ::getOriginalId
348 public function testGetOriginalId() {
349 $new_id = $this->randomMachineName();
350 $this->entity->set('id', $new_id);
351 $this->assertSame($this->id, $this->entity->getOriginalId());
352 $this->assertSame($this->entity, $this->entity->setOriginalId($new_id));
353 $this->assertSame($new_id, $this->entity->getOriginalId());
355 // Check that setOriginalId() does not change the entity "isNew" status.
356 $this->assertFalse($this->entity->isNew());
357 $this->entity->setOriginalId($this->randomMachineName());
358 $this->assertFalse($this->entity->isNew());
359 $this->entity->enforceIsNew();
360 $this->assertTrue($this->entity->isNew());
361 $this->entity->setOriginalId($this->randomMachineName());
362 $this->assertTrue($this->entity->isNew());
368 public function testIsNew() {
369 $this->assertFalse($this->entity->isNew());
370 $this->assertSame($this->entity, $this->entity->enforceIsNew());
371 $this->assertTrue($this->entity->isNew());
372 $this->entity->enforceIsNew(FALSE);
373 $this->assertFalse($this->entity->isNew());
380 public function testGet() {
382 $value = $this->randomMachineName();
383 $this->assertSame($this->id, $this->entity->get($name));
384 $this->assertSame($this->entity, $this->entity->set($name, $value));
385 $this->assertSame($value, $this->entity->get($name));
389 * @covers ::setStatus
392 public function testSetStatus() {
393 $this->assertTrue($this->entity->status());
394 $this->assertSame($this->entity, $this->entity->setStatus(FALSE));
395 $this->assertFalse($this->entity->status());
396 $this->entity->setStatus(TRUE);
397 $this->assertTrue($this->entity->status());
402 * @depends testSetStatus
404 public function testEnable() {
405 $this->entity->setStatus(FALSE);
406 $this->assertSame($this->entity, $this->entity->enable());
407 $this->assertTrue($this->entity->status());
412 * @depends testSetStatus
414 public function testDisable() {
415 $this->entity->setStatus(TRUE);
416 $this->assertSame($this->entity, $this->entity->disable());
417 $this->assertFalse($this->entity->status());
421 * @covers ::setSyncing
422 * @covers ::isSyncing
424 public function testIsSyncing() {
425 $this->assertFalse($this->entity->isSyncing());
426 $this->assertSame($this->entity, $this->entity->setSyncing(TRUE));
427 $this->assertTrue($this->entity->isSyncing());
428 $this->entity->setSyncing(FALSE);
429 $this->assertFalse($this->entity->isSyncing());
433 * @covers ::createDuplicate
435 public function testCreateDuplicate() {
436 $this->entityType->expects($this->at(0))
439 ->will($this->returnValue('id'));
441 $this->entityType->expects($this->at(1))
444 ->will($this->returnValue(TRUE));
446 $this->entityType->expects($this->at(2))
449 ->will($this->returnValue('uuid'));
451 $new_uuid = '8607ef21-42bc-4913-978f-8c06207b0395';
452 $this->uuid->expects($this->once())
454 ->will($this->returnValue($new_uuid));
456 $duplicate = $this->entity->createDuplicate();
457 $this->assertInstanceOf('\Drupal\Core\Entity\Entity', $duplicate);
458 $this->assertNotSame($this->entity, $duplicate);
459 $this->assertFalse($this->entity->isNew());
460 $this->assertTrue($duplicate->isNew());
461 $this->assertNull($duplicate->id());
462 $this->assertNull($duplicate->getOriginalId());
463 $this->assertNotEquals($this->entity->uuid(), $duplicate->uuid());
464 $this->assertSame($new_uuid, $duplicate->uuid());
470 public function testSort() {
471 $this->entityManager->expects($this->any())
472 ->method('getDefinition')
473 ->with($this->entityTypeId)
474 ->will($this->returnValue([
480 $entity_a = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityInterface');
481 $entity_a->expects($this->atLeastOnce())
484 $entity_b = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityInterface');
485 $entity_b->expects($this->atLeastOnce())
489 // Test sorting by label.
490 $list = [$entity_a, $entity_b];
491 // Suppress errors because of https://bugs.php.net/bug.php?id=50688.
492 @usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
493 $this->assertSame($entity_b, $list[0]);
495 $list = [$entity_b, $entity_a];
496 // Suppress errors because of https://bugs.php.net/bug.php?id=50688.
497 @usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
498 $this->assertSame($entity_b, $list[0]);
500 // Test sorting by weight.
501 $entity_a->weight = 0;
502 $entity_b->weight = 1;
503 $list = [$entity_b, $entity_a];
504 // Suppress errors because of https://bugs.php.net/bug.php?id=50688.
505 @usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
506 $this->assertSame($entity_a, $list[0]);
508 $list = [$entity_a, $entity_b];
509 // Suppress errors because of https://bugs.php.net/bug.php?id=50688.
510 @usort($list, '\Drupal\Core\Config\Entity\ConfigEntityBase::sort');
511 $this->assertSame($entity_a, $list[0]);
517 public function testToArray() {
518 $this->typedConfigManager->expects($this->never())
519 ->method('getDefinition');
520 $this->entityType->expects($this->any())
521 ->method('getPropertiesToExport')
522 ->willReturn(['id' => 'configId', 'dependencies' => 'dependencies']);
523 $properties = $this->entity->toArray();
524 $this->assertInternalType('array', $properties);
525 $this->assertEquals(['configId' => $this->entity->id(), 'dependencies' => []], $properties);
531 public function testToArrayIdKey() {
532 $entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', [[], $this->entityTypeId], '', TRUE, TRUE, TRUE, ['id', 'get']);
533 $entity->expects($this->atLeastOnce())
535 ->willReturn($this->id);
536 $entity->expects($this->once())
538 ->with('dependencies')
540 $this->typedConfigManager->expects($this->never())
541 ->method('getDefinition');
542 $this->entityType->expects($this->any())
543 ->method('getPropertiesToExport')
544 ->willReturn(['id' => 'configId', 'dependencies' => 'dependencies']);
545 $this->entityType->expects($this->once())
549 $properties = $entity->toArray();
550 $this->assertInternalType('array', $properties);
551 $this->assertEquals(['configId' => $entity->id(), 'dependencies' => []], $properties);
557 public function testToArraySchemaFallback() {
558 $this->typedConfigManager->expects($this->once())
559 ->method('getDefinition')
560 ->will($this->returnValue(['mapping' => ['id' => '', 'dependencies' => '']]));
561 $this->entityType->expects($this->any())
562 ->method('getPropertiesToExport')
564 $properties = $this->entity->toArray();
565 $this->assertInternalType('array', $properties);
566 $this->assertEquals(['id' => $this->entity->id(), 'dependencies' => []], $properties);
572 public function testToArrayFallback() {
573 $this->entityType->expects($this->any())
574 ->method('getPropertiesToExport')
576 $this->setExpectedException(SchemaIncompleteException::class);
577 $this->entity->toArray();
581 * @covers ::getThirdPartySetting
582 * @covers ::setThirdPartySetting
583 * @covers ::getThirdPartySettings
584 * @covers ::unsetThirdPartySetting
585 * @covers ::getThirdPartyProviders
587 public function testThirdPartySettings() {
589 $third_party = 'test_provider';
590 $value = $this->getRandomGenerator()->string();
592 // Test getThirdPartySetting() with no settings.
593 $this->assertEquals($value, $this->entity->getThirdPartySetting($third_party, $key, $value));
594 $this->assertNull($this->entity->getThirdPartySetting($third_party, $key));
596 // Test setThirdPartySetting().
597 $this->entity->setThirdPartySetting($third_party, $key, $value);
598 $this->assertEquals($value, $this->entity->getThirdPartySetting($third_party, $key));
599 $this->assertEquals($value, $this->entity->getThirdPartySetting($third_party, $key, $this->randomGenerator->string()));
601 // Test getThirdPartySettings().
602 $this->entity->setThirdPartySetting($third_party, 'test2', 'value2');
603 $this->assertEquals([$key => $value, 'test2' => 'value2'], $this->entity->getThirdPartySettings($third_party));
605 // Test getThirdPartyProviders().
606 $this->entity->setThirdPartySetting('test_provider2', $key, $value);
607 $this->assertEquals([$third_party, 'test_provider2'], $this->entity->getThirdPartyProviders());
609 // Test unsetThirdPartyProviders().
610 $this->entity->unsetThirdPartySetting('test_provider2', $key);
611 $this->assertEquals([$third_party], $this->entity->getThirdPartyProviders());
616 class TestConfigEntityWithPluginCollections extends ConfigEntityBaseWithPluginCollections {
618 protected $pluginCollection;
620 public function setPluginManager(PluginManagerInterface $plugin_manager) {
621 $this->pluginCollection = new DefaultLazyPluginCollection($plugin_manager, ['the_instance_id' => ['id' => 'the_instance_id']]);
627 public function getPluginCollections() {
628 return ['the_plugin_collection_config' => $this->pluginCollection];