0a5d3d3e3824c6fb98af9e048a88625bc22828d6
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Config / Entity / ConfigEntityBaseUnitTest.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\Tests\Core\Config\Entity\ConfigEntityBaseUnitTest.
6  */
7
8 namespace Drupal\Tests\Core\Config\Entity;
9
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;
18
19 /**
20  * @coversDefaultClass \Drupal\Core\Config\Entity\ConfigEntityBase
21  * @group Config
22  */
23 class ConfigEntityBaseUnitTest extends UnitTestCase {
24
25   /**
26    * The entity under test.
27    *
28    * @var \Drupal\Core\Config\Entity\ConfigEntityBase|\PHPUnit_Framework_MockObject_MockObject
29    */
30   protected $entity;
31
32   /**
33    * The entity type used for testing.
34    *
35    * @var \Drupal\Core\Config\Entity\ConfigEntityTypeInterface|\PHPUnit_Framework_MockObject_MockObject
36    */
37   protected $entityType;
38
39   /**
40    * The entity manager used for testing.
41    *
42    * @var \Drupal\Core\Entity\EntityManagerInterface|\PHPUnit_Framework_MockObject_MockObject
43    */
44   protected $entityManager;
45
46   /**
47    * The ID of the type of the entity under test.
48    *
49    * @var string
50    */
51   protected $entityTypeId;
52
53   /**
54    * The UUID generator used for testing.
55    *
56    * @var \Drupal\Component\Uuid\UuidInterface|\PHPUnit_Framework_MockObject_MockObject
57    */
58   protected $uuid;
59
60   /**
61    * The provider of the entity type.
62    *
63    * @var string
64    */
65   protected $provider;
66
67   /**
68    * The language manager.
69    *
70    * @var \Drupal\Core\Language\LanguageManagerInterface|\PHPUnit_Framework_MockObject_MockObject
71    */
72   protected $languageManager;
73
74   /**
75    * The entity ID.
76    *
77    * @var string
78    */
79   protected $id;
80
81   /**
82    * The mocked cache backend.
83    *
84    * @var \Drupal\Core\Cache\CacheTagsInvalidatorInterface|\PHPUnit_Framework_MockObject_MockObject
85    */
86   protected $cacheTagsInvalidator;
87
88   /**
89    * The mocked typed config manager.
90    *
91    * @var \Drupal\Core\Config\TypedConfigManagerInterface|\PHPUnit_Framework_MockObject_MockObject
92    */
93   protected $typedConfigManager;
94
95   /**
96    * {@inheritdoc}
97    */
98   protected function setUp() {
99     $this->id = $this->randomMachineName();
100     $values = [
101       'id' => $this->id,
102       'langcode' => 'en',
103       'uuid' => '3bb9ee60-bea5-4622-b89b-a63319d10b3a',
104     ];
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);
114
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));
120
121     $this->uuid = $this->getMock('\Drupal\Component\Uuid\UuidInterface');
122
123     $this->languageManager = $this->getMock('\Drupal\Core\Language\LanguageManagerInterface');
124     $this->languageManager->expects($this->any())
125       ->method('getLanguage')
126       ->with('en')
127       ->will($this->returnValue(new Language(['id' => 'en'])));
128
129     $this->cacheTagsInvalidator = $this->getMock('Drupal\Core\Cache\CacheTagsInvalidatorInterface');
130
131     $this->typedConfigManager = $this->getMock('Drupal\Core\Config\TypedConfigManagerInterface');
132
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);
140
141     $this->entity = $this->getMockForAbstractClass('\Drupal\Core\Config\Entity\ConfigEntityBase', [$values, $this->entityTypeId]);
142   }
143
144   /**
145    * @covers ::calculateDependencies
146    * @covers ::getDependencies
147    */
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());
152
153     // Calculating dependencies will reset the dependencies array using enforced
154     // dependencies.
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']);
159   }
160
161   /**
162    * @covers ::preSave
163    */
164   public function testPreSaveDuringSync() {
165     $query = $this->getMock('\Drupal\Core\Entity\Query\QueryInterface');
166     $storage = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityStorageInterface');
167
168     $query->expects($this->any())
169       ->method('execute')
170       ->will($this->returnValue([]));
171     $query->expects($this->any())
172       ->method('condition')
173       ->will($this->returnValue($query));
174     $storage->expects($this->any())
175       ->method('getQuery')
176       ->will($this->returnValue($query));
177     $storage->expects($this->any())
178       ->method('loadUnchanged')
179       ->will($this->returnValue($this->entity));
180
181     // Saving an entity will not reset the dependencies array during config
182     // synchronization.
183     $this->entity->set('dependencies', ['module' => ['node']]);
184     $this->entity->preSave($storage);
185     $this->assertEmpty($this->entity->getDependencies());
186
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']);
192   }
193
194   /**
195    * @covers ::addDependency
196    */
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']);
207
208     // Test sorting of dependencies.
209     $method->invoke($this->entity, 'module', 'action');
210     $dependencies = $this->entity->getDependencies();
211     $this->assertEquals(['action', 'node'], $dependencies['module']);
212
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));
217   }
218
219   /**
220    * @covers ::getDependencies
221    * @covers ::calculateDependencies
222    *
223    * @dataProvider providerCalculateDependenciesWithPluginCollections
224    */
225   public function testCalculateDependenciesWithPluginCollections($definition, $expected_dependencies) {
226     $values = [];
227     $this->entity = $this->getMockBuilder('\Drupal\Tests\Core\Config\Entity\Fixtures\ConfigEntityBaseWithPluginCollections')
228       ->setConstructorArgs([$values, $this->entityTypeId])
229       ->setMethods(['getPluginCollections'])
230       ->getMock();
231
232     // Create a configurable plugin that would add a dependency.
233     $instance_id = $this->randomMachineName();
234     $instance = new TestConfigurablePlugin([], $instance_id, $definition);
235
236     // Create a plugin collection to contain the instance.
237     $pluginCollection = $this->getMockBuilder('\Drupal\Core\Plugin\DefaultLazyPluginCollection')
238       ->disableOriginalConstructor()
239       ->setMethods(['get'])
240       ->getMock();
241     $pluginCollection->expects($this->atLeastOnce())
242       ->method('get')
243       ->with($instance_id)
244       ->will($this->returnValue($instance));
245     $pluginCollection->addInstanceId($instance_id);
246
247     // Return the mocked plugin collection.
248     $this->entity->expects($this->once())
249       ->method('getPluginCollections')
250       ->will($this->returnValue([$pluginCollection]));
251
252     $this->assertEquals($expected_dependencies, $this->entity->calculateDependencies()->getDependencies());
253   }
254
255   /**
256    * Data provider for testCalculateDependenciesWithPluginCollections.
257    *
258    * @return array
259    */
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);
264
265     return [
266       // Tests that the plugin provider is a module dependency.
267       [
268         ['provider' => 'test'],
269         ['module' => ['test']],
270       ],
271       // Tests that a plugin that is provided by the same module as the config
272       // entity is not added to the dependencies array.
273       [
274         ['provider' => $this->provider],
275         ['module' => [NULL]],
276       ],
277       // Tests that a config entity that has a plugin which provides config
278       // dependencies in its definition has them.
279       [
280         [
281           'provider' => 'test',
282           'config_dependencies' => [
283             'config' => [$instance_dependency_1],
284             'module' => [$instance_dependency_2],
285           ]
286         ],
287         [
288           'config' => [$instance_dependency_1],
289           'module' => [$instance_dependency_2, 'test']
290         ]
291       ]
292     ];
293   }
294
295   /**
296    * @covers ::calculateDependencies
297    * @covers ::getDependencies
298    * @covers ::onDependencyRemoval
299    */
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');
305
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']);
312   }
313
314   /**
315    * @covers ::__sleep
316    */
317   public function testSleepWithPluginCollections() {
318     $instance_id = 'the_instance_id';
319     $instance = new TestConfigurablePlugin([], $instance_id, []);
320
321     $plugin_manager = $this->prophesize(PluginManagerInterface::class);
322     $plugin_manager->createInstance($instance_id, ['id' => $instance_id])->willReturn($instance);
323
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());
327
328     // After creating the entity, change the plugin configuration.
329     $instance->setConfiguration(['foo' => 'new_value']);
330
331     // After changing the plugin configuration, the entity still has the
332     // original value.
333     $expected_plugin_config = [$instance_id => ['foo' => 'original_value']];
334     $this->assertSame($expected_plugin_config, $entity->get('the_plugin_collection_config'));
335
336     // Ensure the plugin collection is not stored.
337     $this->assertNotContains('pluginCollection', $entity->__sleep());
338
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'));
342   }
343
344   /**
345    * @covers ::setOriginalId
346    * @covers ::getOriginalId
347    */
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());
354
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());
363   }
364
365   /**
366    * @covers ::isNew
367    */
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());
374   }
375
376   /**
377    * @covers ::set
378    * @covers ::get
379    */
380   public function testGet() {
381     $name = 'id';
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));
386   }
387
388   /**
389    * @covers ::setStatus
390    * @covers ::status
391    */
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());
398   }
399
400   /**
401    * @covers ::enable
402    * @depends testSetStatus
403    */
404   public function testEnable() {
405     $this->entity->setStatus(FALSE);
406     $this->assertSame($this->entity, $this->entity->enable());
407     $this->assertTrue($this->entity->status());
408   }
409
410   /**
411    * @covers ::disable
412    * @depends testSetStatus
413    */
414   public function testDisable() {
415     $this->entity->setStatus(TRUE);
416     $this->assertSame($this->entity, $this->entity->disable());
417     $this->assertFalse($this->entity->status());
418   }
419
420   /**
421    * @covers ::setSyncing
422    * @covers ::isSyncing
423    */
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());
430   }
431
432   /**
433    * @covers ::createDuplicate
434    */
435   public function testCreateDuplicate() {
436     $this->entityType->expects($this->at(0))
437       ->method('getKey')
438       ->with('id')
439       ->will($this->returnValue('id'));
440
441     $this->entityType->expects($this->at(1))
442       ->method('hasKey')
443       ->with('uuid')
444       ->will($this->returnValue(TRUE));
445
446     $this->entityType->expects($this->at(2))
447       ->method('getKey')
448       ->with('uuid')
449       ->will($this->returnValue('uuid'));
450
451     $new_uuid = '8607ef21-42bc-4913-978f-8c06207b0395';
452     $this->uuid->expects($this->once())
453       ->method('generate')
454       ->will($this->returnValue($new_uuid));
455
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());
465   }
466
467   /**
468    * @covers ::sort
469    */
470   public function testSort() {
471     $this->entityManager->expects($this->any())
472       ->method('getDefinition')
473       ->with($this->entityTypeId)
474       ->will($this->returnValue([
475         'entity_keys' => [
476           'label' => 'label',
477         ],
478       ]));
479
480     $entity_a = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityInterface');
481     $entity_a->expects($this->atLeastOnce())
482       ->method('label')
483       ->willReturn('foo');
484     $entity_b = $this->getMock('\Drupal\Core\Config\Entity\ConfigEntityInterface');
485     $entity_b->expects($this->atLeastOnce())
486       ->method('label')
487       ->willReturn('bar');
488
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]);
494
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]);
499
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]);
507
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]);
512   }
513
514   /**
515    * @covers ::toArray
516    */
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);
526   }
527
528   /**
529    * @covers ::toArray
530    */
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())
534       ->method('id')
535       ->willReturn($this->id);
536     $entity->expects($this->once())
537       ->method('get')
538       ->with('dependencies')
539       ->willReturn([]);
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())
546       ->method('getKey')
547       ->with('id')
548       ->willReturn('id');
549     $properties = $entity->toArray();
550     $this->assertInternalType('array', $properties);
551     $this->assertEquals(['configId' => $entity->id(), 'dependencies' => []], $properties);
552   }
553
554   /**
555    * @covers ::toArray
556    */
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')
563       ->willReturn([]);
564     $properties = $this->entity->toArray();
565     $this->assertInternalType('array', $properties);
566     $this->assertEquals(['id' => $this->entity->id(), 'dependencies' => []], $properties);
567   }
568
569   /**
570    * @covers ::toArray
571    */
572   public function testToArrayFallback() {
573     $this->entityType->expects($this->any())
574       ->method('getPropertiesToExport')
575       ->willReturn([]);
576     $this->setExpectedException(SchemaIncompleteException::class);
577     $this->entity->toArray();
578   }
579
580   /**
581    * @covers ::getThirdPartySetting
582    * @covers ::setThirdPartySetting
583    * @covers ::getThirdPartySettings
584    * @covers ::unsetThirdPartySetting
585    * @covers ::getThirdPartyProviders
586    */
587   public function testThirdPartySettings() {
588     $key = 'test';
589     $third_party = 'test_provider';
590     $value = $this->getRandomGenerator()->string();
591
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));
595
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()));
600
601     // Test getThirdPartySettings().
602     $this->entity->setThirdPartySetting($third_party, 'test2', 'value2');
603     $this->assertEquals([$key => $value, 'test2' => 'value2'], $this->entity->getThirdPartySettings($third_party));
604
605     // Test getThirdPartyProviders().
606     $this->entity->setThirdPartySetting('test_provider2', $key, $value);
607     $this->assertEquals([$third_party, 'test_provider2'], $this->entity->getThirdPartyProviders());
608
609     // Test unsetThirdPartyProviders().
610     $this->entity->unsetThirdPartySetting('test_provider2', $key);
611     $this->assertEquals([$third_party], $this->entity->getThirdPartyProviders());
612   }
613
614 }
615
616 class TestConfigEntityWithPluginCollections extends ConfigEntityBaseWithPluginCollections {
617
618   protected $pluginCollection;
619
620   public function setPluginManager(PluginManagerInterface $plugin_manager) {
621     $this->pluginCollection = new DefaultLazyPluginCollection($plugin_manager, ['the_instance_id' => ['id' => 'the_instance_id']]);
622   }
623
624   /**
625    * {@inheritdoc}
626    */
627   public function getPluginCollections() {
628     return ['the_plugin_collection_config' => $this->pluginCollection];
629   }
630
631 }