edde3f98220ae5b8b6d3e2b40786ef711694b7be
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Plugin / Context / ContextDefinitionIsSatisfiedTest.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\Context;
17 use Drupal\Core\Plugin\Context\ContextDefinition;
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\ContextDefinition
25  * @group Plugin
26  */
27 class ContextDefinitionIsSatisfiedTest 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\ContextDefinition $requirement
92    *   The requirement to check against.
93    * @param \Drupal\Core\Plugin\Context\ContextDefinition $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, ContextDefinition $requirement, ContextDefinition $definition, $value = NULL) {
99     $context = new Context($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, ContextDefinition $requirement, ContextDefinition $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     $this->entityManager->getDefinitions()->willReturn([
116       'test_config' => new EntityType(['id' => 'test_config']),
117       'test_content' => new EntityType(['id' => 'test_content']),
118     ]);
119     $this->entityTypeBundleInfo->getBundleInfo('test_config')->willReturn([
120       'test_config' => ['label' => 'test_config'],
121     ]);
122     $this->entityTypeBundleInfo->getBundleInfo('test_content')->willReturn([
123       'test_content' => ['label' => 'test_content'],
124     ]);
125
126     $this->assertRequirementIsSatisfied($expected, $requirement, $definition, $value);
127   }
128
129   /**
130    * Provides test data for ::testIsSatisfiedBy().
131    */
132   public function providerTestIsSatisfiedBy() {
133     $data = [];
134
135     // Simple data types.
136     $data['both any'] = [
137       TRUE,
138       new ContextDefinition('any'),
139       new ContextDefinition('any'),
140     ];
141     $data['requirement any'] = [
142       TRUE,
143       new ContextDefinition('any'),
144       new ContextDefinition('integer'),
145     ];
146     $data['integer, out of range'] = [
147       FALSE,
148       (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]),
149       new ContextDefinition('integer'),
150       20,
151     ];
152     $data['integer, within range'] = [
153       TRUE,
154       (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]),
155       new ContextDefinition('integer'),
156       5,
157     ];
158     $data['integer, no value'] = [
159       TRUE,
160       (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]),
161       new ContextDefinition('integer'),
162     ];
163     $data['non-integer, within range'] = [
164       FALSE,
165       (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]),
166       new ContextDefinition('any'),
167       5,
168     ];
169
170     // Entities without bundles.
171     $data['content entity, matching type, no value'] = [
172       TRUE,
173       new ContextDefinition('entity:test_content'),
174       new ContextDefinition('entity:test_content'),
175     ];
176     $entity = $this->prophesize(ContentEntityInterface::class)->willImplement(\IteratorAggregate::class);
177     $entity->getIterator()->willReturn(new \ArrayIterator([]));
178     $entity->getCacheContexts()->willReturn([]);
179     $entity->getCacheTags()->willReturn([]);
180     $entity->getCacheMaxAge()->willReturn(0);
181     $entity->getEntityTypeId()->willReturn('test_content');
182     $data['content entity, matching type, correct value'] = [
183       TRUE,
184       new ContextDefinition('entity:test_content'),
185       new ContextDefinition('entity:test_content'),
186       $entity->reveal(),
187     ];
188     $data['content entity, incorrect manual constraint'] = [
189       TRUE,
190       new ContextDefinition('entity:test_content'),
191       (new ContextDefinition('entity:test_content'))->addConstraint('EntityType', 'test_config'),
192     ];
193     $data['config entity, matching type, no value'] = [
194       TRUE,
195       new ContextDefinition('entity:test_config'),
196       new ContextDefinition('entity:test_config'),
197     ];
198
199     return $data;
200   }
201
202   /**
203    * @covers ::isSatisfiedBy
204    * @covers ::getSampleValues
205    * @covers ::getConstraintObjects
206    *
207    * @dataProvider providerTestIsSatisfiedByGenerateBundledEntity
208    */
209   public function testIsSatisfiedByGenerateBundledEntity($expected, array $requirement_bundles, array $candidate_bundles, array $bundles_to_instantiate = NULL) {
210     // If no bundles are explicitly specified, instantiate all bundles.
211     if (!$bundles_to_instantiate) {
212       $bundles_to_instantiate = $candidate_bundles;
213     }
214
215     $content_entity_storage = $this->prophesize(ContentEntityStorageInterface::class);
216     foreach ($bundles_to_instantiate as $bundle) {
217       $entity = $this->prophesize(ContentEntityInterface::class)->willImplement(\IteratorAggregate::class);
218       $entity->getEntityTypeId()->willReturn('test_content');
219       $entity->getIterator()->willReturn(new \ArrayIterator([]));
220       $entity->bundle()->willReturn($bundle);
221       $content_entity_storage->createWithSampleValues($bundle)
222         ->willReturn($entity->reveal())
223         ->shouldBeCalled();
224     }
225
226     $this->entityTypeManager->getStorage('test_content')->willReturn($content_entity_storage->reveal());
227     $this->entityManager->getDefinitions()->willReturn([
228       'test_content' => new EntityType(['id' => 'test_content']),
229     ]);
230
231     $this->entityTypeBundleInfo->getBundleInfo('test_content')->willReturn([
232       'first_bundle' => ['label' => 'First bundle'],
233       'second_bundle' => ['label' => 'Second bundle'],
234       'third_bundle' => ['label' => 'Third bundle'],
235     ]);
236
237     $requirement = new ContextDefinition('entity:test_content');
238     if ($requirement_bundles) {
239       $requirement->addConstraint('Bundle', $requirement_bundles);
240     }
241     $definition = (new ContextDefinition('entity:test_content'))->addConstraint('Bundle', $candidate_bundles);
242     $this->assertRequirementIsSatisfied($expected, $requirement, $definition);
243   }
244
245   /**
246    * Provides test data for ::testIsSatisfiedByGenerateBundledEntity().
247    */
248   public function providerTestIsSatisfiedByGenerateBundledEntity() {
249     $data = [];
250     $data['no requirement'] = [
251       TRUE,
252       [],
253       ['first_bundle'],
254     ];
255     $data['single requirement'] = [
256       TRUE,
257       ['first_bundle'],
258       ['first_bundle'],
259     ];
260     $data['single requirement, multiple candidates, satisfies last candidate'] = [
261       TRUE,
262       ['third_bundle'],
263       ['first_bundle', 'second_bundle', 'third_bundle'],
264     ];
265     $data['single requirement, multiple candidates, satisfies first candidate'] = [
266       TRUE,
267       ['first_bundle'],
268       ['first_bundle', 'second_bundle', 'third_bundle'],
269       // Once the first match is found, subsequent candidates are not checked.
270       ['first_bundle'],
271     ];
272     $data['unsatisfied requirement'] = [
273       FALSE,
274       ['second_bundle'],
275       ['first_bundle', 'third_bundle'],
276     ];
277     $data['multiple requirements'] = [
278       TRUE,
279       ['first_bundle', 'second_bundle'],
280       ['first_bundle'],
281     ];
282     return $data;
283   }
284
285   /**
286    * @covers ::isSatisfiedBy
287    * @covers ::getSampleValues
288    * @covers ::getConstraintObjects
289    *
290    * @dataProvider providerTestIsSatisfiedByPassBundledEntity
291    */
292   public function testIsSatisfiedByPassBundledEntity($expected, $requirement_constraint) {
293     $this->entityManager->getDefinitions()->willReturn([
294       'test_content' => new EntityType(['id' => 'test_content']),
295     ]);
296     $this->entityTypeManager->getStorage('test_content')->shouldNotBeCalled();
297
298     $this->entityTypeBundleInfo->getBundleInfo('test_content')->willReturn([
299       'first_bundle' => ['label' => 'First bundle'],
300       'second_bundle' => ['label' => 'Second bundle'],
301       'third_bundle' => ['label' => 'Third bundle'],
302     ]);
303
304     $entity = $this->prophesize(ContentEntityInterface::class)->willImplement(\IteratorAggregate::class);
305     $entity->getEntityTypeId()->willReturn('test_content');
306     $entity->getIterator()->willReturn(new \ArrayIterator([]));
307     $entity->getCacheContexts()->willReturn([]);
308     $entity->getCacheTags()->willReturn([]);
309     $entity->getCacheMaxAge()->willReturn(0);
310     $entity->bundle()->willReturn('third_bundle');
311
312     $requirement = new ContextDefinition('entity:test_content');
313     if ($requirement_constraint) {
314       $requirement->addConstraint('Bundle', $requirement_constraint);
315     }
316     $definition = new ContextDefinition('entity:test_content');
317     $this->assertRequirementIsSatisfied($expected, $requirement, $definition, $entity->reveal());
318   }
319
320   /**
321    * Provides test data for ::testIsSatisfiedByPassBundledEntity().
322    */
323   public function providerTestIsSatisfiedByPassBundledEntity() {
324     $data = [];
325     $data[] = [TRUE, []];
326     $data[] = [FALSE, ['first_bundle']];
327     $data[] = [FALSE, ['second_bundle']];
328     $data[] = [TRUE, ['third_bundle']];
329     $data[] = [TRUE, ['first_bundle', 'second_bundle', 'third_bundle']];
330     $data[] = [FALSE, ['first_bundle', 'second_bundle']];
331     $data[] = [TRUE, ['first_bundle', 'third_bundle']];
332     $data[] = [TRUE, ['second_bundle', 'third_bundle']];
333     return $data;
334   }
335
336 }
337
338 namespace Drupal\Core\Validation;
339
340 if (!function_exists('t')) {
341   function t($string, array $args = []) {
342     return strtr($string, $args);
343   }
344 }