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