69adfdd27154d0c8e64ad702f76cd4c3811967a5
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Plugin / Context / EntityContextDefinitionIsSatisfiedTest.php
1 <?php
2
3 namespace Drupal\Tests\Core\Plugin\Context;
4
5 use Drupal\Core\Cache\NullBackend;
6 use Drupal\Core\DependencyInjection\ClassResolverInterface;
7 use Drupal\Core\DependencyInjection\ContainerBuilder;
8 use Drupal\Core\Entity\ContentEntityInterface;
9 use Drupal\Core\Entity\ContentEntityStorageInterface;
10 use Drupal\Core\Entity\EntityManagerInterface;
11 use Drupal\Core\Entity\EntityStorageInterface;
12 use Drupal\Core\Entity\EntityType;
13 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
14 use Drupal\Core\Entity\EntityTypeManagerInterface;
15 use Drupal\Core\Extension\ModuleHandlerInterface;
16 use Drupal\Core\Plugin\Context\EntityContext;
17 use Drupal\Core\Plugin\Context\EntityContextDefinition;
18 use Drupal\Core\TypedData\TypedDataManager;
19 use Drupal\Core\Validation\ConstraintManager;
20 use Drupal\Tests\UnitTestCase;
21 use Prophecy\Argument;
22
23 /**
24  * @coversDefaultClass \Drupal\Core\Plugin\Context\EntityContextDefinition
25  * @group Plugin
26  */
27 class EntityContextDefinitionIsSatisfiedTest extends UnitTestCase {
28
29   /**
30    * The entity type manager.
31    *
32    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
33    */
34   protected $entityTypeManager;
35
36   /**
37    * The entity manager.
38    *
39    * @var \Drupal\Core\Entity\EntityManagerInterface
40    */
41   protected $entityManager;
42
43   /**
44    * The entity type bundle info.
45    *
46    * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
47    */
48   protected $entityTypeBundleInfo;
49
50   /**
51    * {@inheritdoc}
52    */
53   protected function setUp() {
54     parent::setUp();
55
56     $namespaces = new \ArrayObject([
57       'Drupal\\Core\\TypedData' => $this->root . '/core/lib/Drupal/Core/TypedData',
58       'Drupal\\Core\\Validation' => $this->root . '/core/lib/Drupal/Core/Validation',
59       'Drupal\\Core\\Entity' => $this->root . '/core/lib/Drupal/Core/Entity',
60     ]);
61     $cache_backend = new NullBackend('cache');
62     $module_handler = $this->prophesize(ModuleHandlerInterface::class);
63
64     $class_resolver = $this->prophesize(ClassResolverInterface::class);
65     $class_resolver->getInstanceFromDefinition(Argument::type('string'))->will(function ($arguments) {
66       $class_name = $arguments[0];
67       return new $class_name();
68     });
69
70     $type_data_manager = new TypedDataManager($namespaces, $cache_backend, $module_handler->reveal(), $class_resolver->reveal());
71     $type_data_manager->setValidationConstraintManager(new ConstraintManager($namespaces, $cache_backend, $module_handler->reveal()));
72
73     $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
74     $this->entityManager = $this->prophesize(EntityManagerInterface::class);
75
76     $this->entityTypeBundleInfo = $this->prophesize(EntityTypeBundleInfoInterface::class);
77
78     $container = new ContainerBuilder();
79     $container->set('typed_data_manager', $type_data_manager);
80     $container->set('entity_type.manager', $this->entityTypeManager->reveal());
81     $container->set('entity.manager', $this->entityManager->reveal());
82     $container->set('entity_type.bundle.info', $this->entityTypeBundleInfo->reveal());
83     \Drupal::setContainer($container);
84   }
85
86   /**
87    * Asserts that the requirement is satisfied as expected.
88    *
89    * @param bool $expected
90    *   The expected outcome.
91    * @param \Drupal\Core\Plugin\Context\EntityContextDefinition $requirement
92    *   The requirement to check against.
93    * @param \Drupal\Core\Plugin\Context\EntityContextDefinition $definition
94    *   The context definition to check.
95    * @param mixed $value
96    *   (optional) The value to set on the context, defaults to NULL.
97    */
98   protected function assertRequirementIsSatisfied($expected, EntityContextDefinition $requirement, EntityContextDefinition $definition, $value = NULL) {
99     $context = new EntityContext($definition, $value);
100     $this->assertSame($expected, $requirement->isSatisfiedBy($context));
101   }
102
103   /**
104    * @covers ::isSatisfiedBy
105    * @covers ::getSampleValues
106    * @covers ::getConstraintObjects
107    *
108    * @dataProvider providerTestIsSatisfiedBy
109    */
110   public function testIsSatisfiedBy($expected, EntityContextDefinition $requirement, EntityContextDefinition $definition, $value = NULL) {
111     $entity_storage = $this->prophesize(EntityStorageInterface::class);
112     $content_entity_storage = $this->prophesize(ContentEntityStorageInterface::class);
113     $this->entityTypeManager->getStorage('test_config')->willReturn($entity_storage->reveal());
114     $this->entityTypeManager->getStorage('test_content')->willReturn($content_entity_storage->reveal());
115
116     $config_entity_type = new EntityType(['id' => 'test_config']);
117     $content_entity_type = new EntityType(['id' => 'test_content']);
118     $this->entityTypeManager->getDefinition('test_config')->willReturn($config_entity_type);
119     $this->entityTypeManager->getDefinition('test_content')->willReturn($content_entity_type);
120     $this->entityManager->getDefinitions()->willReturn([
121       'test_config' => $config_entity_type,
122       'test_content' => $content_entity_type,
123     ]);
124
125     $this->entityTypeBundleInfo->getBundleInfo('test_config')->willReturn([
126       'test_config' => ['label' => 'test_config'],
127     ]);
128     $this->entityTypeBundleInfo->getBundleInfo('test_content')->willReturn([
129       'test_content' => ['label' => 'test_content'],
130     ]);
131
132     $this->assertRequirementIsSatisfied($expected, $requirement, $definition, $value);
133   }
134
135   /**
136    * Provides test data for ::testIsSatisfiedBy().
137    */
138   public function providerTestIsSatisfiedBy() {
139     $data = [];
140
141     $content = new EntityType(['id' => 'test_content']);
142     $config = new EntityType(['id' => 'test_config']);
143
144     // Entities without bundles.
145     $data['content entity, matching type, no value'] = [
146       TRUE,
147       EntityContextDefinition::fromEntityType($content),
148       EntityContextDefinition::fromEntityType($content),
149     ];
150     $entity = $this->prophesize(ContentEntityInterface::class)->willImplement(\IteratorAggregate::class);
151     $entity->getIterator()->willReturn(new \ArrayIterator([]));
152     $entity->getCacheContexts()->willReturn([]);
153     $entity->getCacheTags()->willReturn([]);
154     $entity->getCacheMaxAge()->willReturn(0);
155     $entity->getEntityTypeId()->willReturn('test_content');
156     $data['content entity, matching type, correct value'] = [
157       TRUE,
158       EntityContextDefinition::fromEntityType($content),
159       EntityContextDefinition::fromEntityType($content),
160       $entity->reveal(),
161     ];
162     $data['content entity, incorrect manual constraint'] = [
163       TRUE,
164       EntityContextDefinition::fromEntityType($content),
165       EntityContextDefinition::fromEntityType($content)->addConstraint('EntityType', 'test_config'),
166     ];
167     $data['config entity, matching type, no value'] = [
168       TRUE,
169       EntityContextDefinition::fromEntityType($config),
170       EntityContextDefinition::fromEntityType($config),
171     ];
172
173     return $data;
174   }
175
176   /**
177    * @covers ::isSatisfiedBy
178    * @covers ::getSampleValues
179    * @covers ::getConstraintObjects
180    *
181    * @dataProvider providerTestIsSatisfiedByGenerateBundledEntity
182    */
183   public function testIsSatisfiedByGenerateBundledEntity($expected, array $requirement_bundles, array $candidate_bundles, array $bundles_to_instantiate = NULL) {
184     // If no bundles are explicitly specified, instantiate all bundles.
185     if (!$bundles_to_instantiate) {
186       $bundles_to_instantiate = $candidate_bundles;
187     }
188
189     $content_entity_storage = $this->prophesize(ContentEntityStorageInterface::class);
190     foreach ($bundles_to_instantiate as $bundle) {
191       $entity = $this->prophesize(ContentEntityInterface::class)->willImplement(\IteratorAggregate::class);
192       $entity->getEntityTypeId()->willReturn('test_content');
193       $entity->getIterator()->willReturn(new \ArrayIterator([]));
194       $entity->bundle()->willReturn($bundle);
195       $content_entity_storage->create(['the_bundle_key' => $bundle])
196         ->willReturn($entity->reveal())
197         ->shouldBeCalled();
198     }
199
200     // Creating entities with sample values can lead to performance issues when
201     // called many times. Ensure that createWithSampleValues() is not called.
202     $content_entity_storage->createWithSampleValues(Argument::any())->shouldNotBeCalled();
203
204     $entity_type = new EntityType([
205       'id' => 'test_content',
206       'entity_keys' => [
207         'bundle' => 'the_bundle_key',
208       ],
209     ]);
210
211     $this->entityTypeManager->getStorage('test_content')->willReturn($content_entity_storage->reveal());
212
213     $this->entityTypeManager->getDefinition('test_content')->willReturn($entity_type);
214     $this->entityManager->getDefinitions()->willReturn([
215       'test_content' => $entity_type,
216     ]);
217
218     $this->entityTypeBundleInfo->getBundleInfo('test_content')->willReturn([
219       'first_bundle' => ['label' => 'First bundle'],
220       'second_bundle' => ['label' => 'Second bundle'],
221       'third_bundle' => ['label' => 'Third bundle'],
222     ]);
223
224     $requirement = EntityContextDefinition::fromEntityType($entity_type);
225     if ($requirement_bundles) {
226       $requirement->addConstraint('Bundle', $requirement_bundles);
227     }
228     $definition = EntityContextDefinition::fromEntityType($entity_type)->addConstraint('Bundle', $candidate_bundles);
229     $this->assertRequirementIsSatisfied($expected, $requirement, $definition);
230   }
231
232   /**
233    * Provides test data for ::testIsSatisfiedByGenerateBundledEntity().
234    */
235   public function providerTestIsSatisfiedByGenerateBundledEntity() {
236     $data = [];
237     $data['no requirement'] = [
238       TRUE,
239       [],
240       ['first_bundle'],
241     ];
242     $data['single requirement'] = [
243       TRUE,
244       ['first_bundle'],
245       ['first_bundle'],
246     ];
247     $data['single requirement, multiple candidates, satisfies last candidate'] = [
248       TRUE,
249       ['third_bundle'],
250       ['first_bundle', 'second_bundle', 'third_bundle'],
251     ];
252     $data['single requirement, multiple candidates, satisfies first candidate'] = [
253       TRUE,
254       ['first_bundle'],
255       ['first_bundle', 'second_bundle', 'third_bundle'],
256       // Once the first match is found, subsequent candidates are not checked.
257       ['first_bundle'],
258     ];
259     $data['unsatisfied requirement'] = [
260       FALSE,
261       ['second_bundle'],
262       ['first_bundle', 'third_bundle'],
263     ];
264     $data['multiple requirements'] = [
265       TRUE,
266       ['first_bundle', 'second_bundle'],
267       ['first_bundle'],
268     ];
269     return $data;
270   }
271
272   /**
273    * @covers ::isSatisfiedBy
274    * @covers ::getSampleValues
275    * @covers ::getConstraintObjects
276    *
277    * @dataProvider providerTestIsSatisfiedByPassBundledEntity
278    */
279   public function testIsSatisfiedByPassBundledEntity($expected, $requirement_constraint) {
280     $entity_type = new EntityType(['id' => 'test_content']);
281     $this->entityManager->getDefinitions()->willReturn([
282       'test_content' => $entity_type,
283     ]);
284     $this->entityTypeManager->getDefinition('test_content')->willReturn($entity_type);
285     $this->entityTypeManager->getStorage('test_content')->shouldNotBeCalled();
286
287     $this->entityTypeBundleInfo->getBundleInfo('test_content')->willReturn([
288       'first_bundle' => ['label' => 'First bundle'],
289       'second_bundle' => ['label' => 'Second bundle'],
290       'third_bundle' => ['label' => 'Third bundle'],
291     ]);
292
293     $entity = $this->prophesize(ContentEntityInterface::class)->willImplement(\IteratorAggregate::class);
294     $entity->getEntityTypeId()->willReturn('test_content');
295     $entity->getIterator()->willReturn(new \ArrayIterator([]));
296     $entity->getCacheContexts()->willReturn([]);
297     $entity->getCacheTags()->willReturn([]);
298     $entity->getCacheMaxAge()->willReturn(0);
299     $entity->bundle()->willReturn('third_bundle');
300
301     $requirement = EntityContextDefinition::fromEntityTypeId('test_content');
302     if ($requirement_constraint) {
303       $requirement->addConstraint('Bundle', $requirement_constraint);
304     }
305     $definition = EntityContextDefinition::fromEntityTypeId('test_content');
306     $this->assertRequirementIsSatisfied($expected, $requirement, $definition, $entity->reveal());
307   }
308
309   /**
310    * Provides test data for ::testIsSatisfiedByPassBundledEntity().
311    */
312   public function providerTestIsSatisfiedByPassBundledEntity() {
313     $data = [];
314     $data[] = [TRUE, []];
315     $data[] = [FALSE, ['first_bundle']];
316     $data[] = [FALSE, ['second_bundle']];
317     $data[] = [TRUE, ['third_bundle']];
318     $data[] = [TRUE, ['first_bundle', 'second_bundle', 'third_bundle']];
319     $data[] = [FALSE, ['first_bundle', 'second_bundle']];
320     $data[] = [TRUE, ['first_bundle', 'third_bundle']];
321     $data[] = [TRUE, ['second_bundle', 'third_bundle']];
322     return $data;
323   }
324
325 }