3 namespace Drupal\Tests\Core\Plugin\Context;
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;
24 * @coversDefaultClass \Drupal\Core\Plugin\Context\ContextDefinition
27 class ContextDefinitionIsSatisfiedTest extends UnitTestCase {
30 * The entity type manager.
32 * @var \Drupal\Core\Entity\EntityTypeManagerInterface
34 protected $entityTypeManager;
39 * @var \Drupal\Core\Entity\EntityManagerInterface
41 protected $entityManager;
44 * The entity type bundle info.
46 * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface
48 protected $entityTypeBundleInfo;
53 protected function setUp() {
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',
61 $cache_backend = new NullBackend('cache');
62 $module_handler = $this->prophesize(ModuleHandlerInterface::class);
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();
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()));
73 $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
74 $this->entityManager = $this->prophesize(EntityManagerInterface::class);
76 $this->entityTypeBundleInfo = $this->prophesize(EntityTypeBundleInfoInterface::class);
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);
87 * Asserts that the requirement is satisfied as expected.
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.
96 * (optional) The value to set on the context, defaults to NULL.
98 protected function assertRequirementIsSatisfied($expected, ContextDefinition $requirement, ContextDefinition $definition, $value = NULL) {
99 $context = new Context($definition, $value);
100 $this->assertSame($expected, $requirement->isSatisfiedBy($context));
104 * @covers ::isSatisfiedBy
105 * @covers ::getSampleValues
106 * @covers ::getConstraintObjects
108 * @dataProvider providerTestIsSatisfiedBy
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']),
119 $this->entityTypeBundleInfo->getBundleInfo('test_config')->willReturn([
120 'test_config' => ['label' => 'test_config'],
122 $this->entityTypeBundleInfo->getBundleInfo('test_content')->willReturn([
123 'test_content' => ['label' => 'test_content'],
126 $this->assertRequirementIsSatisfied($expected, $requirement, $definition, $value);
130 * Provides test data for ::testIsSatisfiedBy().
132 public function providerTestIsSatisfiedBy() {
135 // Simple data types.
136 $data['both any'] = [
138 new ContextDefinition('any'),
139 new ContextDefinition('any'),
141 $data['requirement any'] = [
143 new ContextDefinition('any'),
144 new ContextDefinition('integer'),
146 $data['integer, out of range'] = [
148 (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]),
149 new ContextDefinition('integer'),
152 $data['integer, within range'] = [
154 (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]),
155 new ContextDefinition('integer'),
158 $data['integer, no value'] = [
160 (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]),
161 new ContextDefinition('integer'),
163 $data['non-integer, within range'] = [
165 (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]),
166 new ContextDefinition('any'),
170 // Entities without bundles.
171 $data['content entity, matching type, no value'] = [
173 new ContextDefinition('entity:test_content'),
174 new ContextDefinition('entity:test_content'),
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'] = [
184 new ContextDefinition('entity:test_content'),
185 new ContextDefinition('entity:test_content'),
188 $data['content entity, incorrect manual constraint'] = [
190 new ContextDefinition('entity:test_content'),
191 (new ContextDefinition('entity:test_content'))->addConstraint('EntityType', 'test_config'),
193 $data['config entity, matching type, no value'] = [
195 new ContextDefinition('entity:test_config'),
196 new ContextDefinition('entity:test_config'),
203 * @covers ::isSatisfiedBy
204 * @covers ::getSampleValues
205 * @covers ::getConstraintObjects
207 * @dataProvider providerTestIsSatisfiedByGenerateBundledEntity
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;
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())
226 $this->entityTypeManager->getStorage('test_content')->willReturn($content_entity_storage->reveal());
227 $this->entityManager->getDefinitions()->willReturn([
228 'test_content' => new EntityType(['id' => 'test_content']),
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'],
237 $requirement = new ContextDefinition('entity:test_content');
238 if ($requirement_bundles) {
239 $requirement->addConstraint('Bundle', $requirement_bundles);
241 $definition = (new ContextDefinition('entity:test_content'))->addConstraint('Bundle', $candidate_bundles);
242 $this->assertRequirementIsSatisfied($expected, $requirement, $definition);
246 * Provides test data for ::testIsSatisfiedByGenerateBundledEntity().
248 public function providerTestIsSatisfiedByGenerateBundledEntity() {
250 $data['no requirement'] = [
255 $data['single requirement'] = [
260 $data['single requirement, multiple candidates, satisfies last candidate'] = [
263 ['first_bundle', 'second_bundle', 'third_bundle'],
265 $data['single requirement, multiple candidates, satisfies first candidate'] = [
268 ['first_bundle', 'second_bundle', 'third_bundle'],
269 // Once the first match is found, subsequent candidates are not checked.
272 $data['unsatisfied requirement'] = [
275 ['first_bundle', 'third_bundle'],
277 $data['multiple requirements'] = [
279 ['first_bundle', 'second_bundle'],
286 * @covers ::isSatisfiedBy
287 * @covers ::getSampleValues
288 * @covers ::getConstraintObjects
290 * @dataProvider providerTestIsSatisfiedByPassBundledEntity
292 public function testIsSatisfiedByPassBundledEntity($expected, $requirement_constraint) {
293 $this->entityManager->getDefinitions()->willReturn([
294 'test_content' => new EntityType(['id' => 'test_content']),
296 $this->entityTypeManager->getStorage('test_content')->shouldNotBeCalled();
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'],
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');
312 $requirement = new ContextDefinition('entity:test_content');
313 if ($requirement_constraint) {
314 $requirement->addConstraint('Bundle', $requirement_constraint);
316 $definition = new ContextDefinition('entity:test_content');
317 $this->assertRequirementIsSatisfied($expected, $requirement, $definition, $entity->reveal());
321 * Provides test data for ::testIsSatisfiedByPassBundledEntity().
323 public function providerTestIsSatisfiedByPassBundledEntity() {
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']];
338 namespace Drupal\Core\Validation;
340 if (!function_exists('t')) {
341 function t($string, array $args = []) {
342 return strtr($string, $args);