From 0c1de8e423dfba1d9e8cd8ebc3ee10233f46b4a6 Mon Sep 17 00:00:00 2001 From: Lee Rowlands Date: Mon, 8 Jan 2018 07:45:58 +1000 Subject: [PATCH] Issue #2671964 by EclipseGc, tim.plunkett, Jo Fitzgerald, larowlan, fago, dawehner, Berdir, phenaproxima: ContextHandler cannot validate constraints --- .../Core/Plugin/Context/ContextDefinition.php | 106 ++++++ .../Context/ContextDefinitionInterface.php | 12 + .../Core/Plugin/Context/ContextHandler.php | 18 +- .../ContextProvider/CurrentUserContext.php | 4 + .../ContextDefinitionIsSatisfiedTest.php | 344 ++++++++++++++++++ .../Tests/Core/Plugin/ContextHandlerTest.php | 55 ++- 6 files changed, 508 insertions(+), 31 deletions(-) create mode 100644 core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php index 63e4038abd..55336d55c9 100644 --- a/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php +++ b/core/lib/Drupal/Core/Plugin/Context/ContextDefinition.php @@ -3,6 +3,11 @@ namespace Drupal\Core\Plugin\Context; use Drupal\Core\DependencyInjection\DependencySerializationTrait; +use Drupal\Core\Entity\ContentEntityStorageInterface; +use Drupal\Core\Entity\Plugin\DataType\EntityAdapter; +use Drupal\Core\Entity\Plugin\Validation\Constraint\BundleConstraint; +use Drupal\Core\Entity\Plugin\Validation\Constraint\EntityTypeConstraint; +use Drupal\Core\Entity\TypedData\EntityDataDefinition; use Drupal\Core\TypedData\TypedDataTrait; /** @@ -252,4 +257,105 @@ public function getDataDefinition() { return $definition; } + /** + * {@inheritdoc} + */ + public function isSatisfiedBy(ContextInterface $context) { + $definition = $context->getContextDefinition(); + // If the data types do not match, this context is invalid unless the + // expected data type is any, which means all data types are supported. + if ($this->getDataType() != 'any' && $definition->getDataType() != $this->getDataType()) { + return FALSE; + } + + // Get the value for this context, either directly if possible or by + // introspecting the definition. + if ($context->hasContextValue()) { + $values = [$context->getContextData()]; + } + elseif ($definition instanceof static) { + $values = $definition->getSampleValues(); + } + else { + $values = []; + } + + $validator = $this->getTypedDataManager()->getValidator(); + foreach ($values as $value) { + $violations = $validator->validate($value, array_values($this->getConstraintObjects())); + // If a value has no violations then the requirement is satisfied. + if (!$violations->count()) { + return TRUE; + } + } + + return FALSE; + } + + /** + * Returns typed data objects representing this context definition. + * + * This should return as many objects as needed to reflect the variations of + * the constraints it supports. + * + * @yield \Drupal\Core\TypedData\TypedDataInterface + * The set of typed data object. + */ + protected function getSampleValues() { + // @todo Move the entity specific logic out of this class in + // https://www.drupal.org/node/2932462. + // Get the constraints from the context's definition. + $constraints = $this->getConstraintObjects(); + // If constraints include EntityType, we generate an entity or adapter. + if (!empty($constraints['EntityType']) && $constraints['EntityType'] instanceof EntityTypeConstraint) { + $entity_type_manager = \Drupal::entityTypeManager(); + $entity_type_id = $constraints['EntityType']->type; + $storage = $entity_type_manager->getStorage($entity_type_id); + // If the storage can generate a sample entity we might delegate to that. + if ($storage instanceof ContentEntityStorageInterface) { + if (!empty($constraints['Bundle']) && $constraints['Bundle'] instanceof BundleConstraint) { + foreach ($constraints['Bundle']->bundle as $bundle) { + // We have a bundle, we are bundleable and we can generate a sample. + yield EntityAdapter::createFromEntity($storage->createWithSampleValues($bundle)); + } + return; + } + } + + // Either no bundle, or not bundleable, so generate an entity adapter. + $definition = EntityDataDefinition::create($entity_type_id); + yield new EntityAdapter($definition); + return; + } + + // No entity related constraints, so generate a basic typed data object. + yield $this->getTypedDataManager()->create($this->getDataDefinition()); + } + + /** + * Extracts an array of constraints for a context definition object. + * + * @return \Symfony\Component\Validator\Constraint[] + * A list of applied constraints for the context definition. + */ + protected function getConstraintObjects() { + $constraint_definitions = $this->getConstraints(); + + // @todo Move the entity specific logic out of this class in + // https://www.drupal.org/node/2932462. + // If the data type is an entity, manually add one to the constraints array. + if (strpos($this->getDataType(), 'entity:') === 0) { + $entity_type_id = substr($this->getDataType(), 7); + $constraint_definitions['EntityType'] = ['type' => $entity_type_id]; + } + + $validation_constraint_manager = $this->getTypedDataManager()->getValidationConstraintManager(); + $constraints = []; + foreach ($constraint_definitions as $constraint_name => $constraint_definition) { + $constraints[$constraint_name] = $validation_constraint_manager->create($constraint_name, $constraint_definition); + } + + return $constraints; + } + } diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextDefinitionInterface.php b/core/lib/Drupal/Core/Plugin/Context/ContextDefinitionInterface.php index c60c6c7fcb..2f66fe9ef4 100644 --- a/core/lib/Drupal/Core/Plugin/Context/ContextDefinitionInterface.php +++ b/core/lib/Drupal/Core/Plugin/Context/ContextDefinitionInterface.php @@ -20,4 +20,16 @@ interface ContextDefinitionInterface extends ComponentContextDefinitionInterface */ public function getDataDefinition(); + /** + * Determines if this definition is satisfied by a context object. + * + * @param \Drupal\Core\Plugin\Context\ContextInterface $context + * The context object. + * + * @return bool + * TRUE if this definition is satisfiable by the context object, FALSE + * otherwise. + */ + public function isSatisfiedBy(ContextInterface $context); + } diff --git a/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php b/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php index 2a13d364d7..56dcdb2a1c 100644 --- a/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php +++ b/core/lib/Drupal/Core/Plugin/Context/ContextHandler.php @@ -43,23 +43,7 @@ public function checkRequirements(array $contexts, array $requirements) { */ public function getMatchingContexts(array $contexts, ContextDefinitionInterface $definition) { return array_filter($contexts, function (ContextInterface $context) use ($definition) { - $context_definition = $context->getContextDefinition(); - - // If the data types do not match, this context is invalid unless the - // expected data type is any, which means all data types are supported. - if ($definition->getDataType() != 'any' && $definition->getDataType() != $context_definition->getDataType()) { - return FALSE; - } - - // If any constraint does not match, this context is invalid. - foreach ($definition->getConstraints() as $constraint_name => $constraint) { - if ($context_definition->getConstraint($constraint_name) != $constraint) { - return FALSE; - } - } - - // All contexts with matching data type and contexts are valid. - return TRUE; + return $definition->isSatisfiedBy($context); }); } diff --git a/core/modules/user/src/ContextProvider/CurrentUserContext.php b/core/modules/user/src/ContextProvider/CurrentUserContext.php index e9eccd8190..73be2caa09 100644 --- a/core/modules/user/src/ContextProvider/CurrentUserContext.php +++ b/core/modules/user/src/ContextProvider/CurrentUserContext.php @@ -50,6 +50,10 @@ public function __construct(AccountInterface $account, EntityManagerInterface $e public function getRuntimeContexts(array $unqualified_context_ids) { $current_user = $this->userStorage->load($this->account->id()); + // @todo Do not validate protected fields to avoid bug in TypedData, remove + // this in https://www.drupal.org/project/drupal/issues/2934192. + $current_user->_skipProtectedUserFieldConstraint = TRUE; + $context = new Context(new ContextDefinition('entity:user', $this->t('Current user')), $current_user); $cacheability = new CacheableMetadata(); $cacheability->setCacheContexts(['user']); diff --git a/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php new file mode 100644 index 0000000000..edde3f9822 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Plugin/Context/ContextDefinitionIsSatisfiedTest.php @@ -0,0 +1,344 @@ + $this->root . '/core/lib/Drupal/Core/TypedData', + 'Drupal\\Core\\Validation' => $this->root . '/core/lib/Drupal/Core/Validation', + 'Drupal\\Core\\Entity' => $this->root . '/core/lib/Drupal/Core/Entity', + ]); + $cache_backend = new NullBackend('cache'); + $module_handler = $this->prophesize(ModuleHandlerInterface::class); + + $class_resolver = $this->prophesize(ClassResolverInterface::class); + $class_resolver->getInstanceFromDefinition(Argument::type('string'))->will(function ($arguments) { + $class_name = $arguments[0]; + return new $class_name(); + }); + + $type_data_manager = new TypedDataManager($namespaces, $cache_backend, $module_handler->reveal(), $class_resolver->reveal()); + $type_data_manager->setValidationConstraintManager(new ConstraintManager($namespaces, $cache_backend, $module_handler->reveal())); + + $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class); + $this->entityManager = $this->prophesize(EntityManagerInterface::class); + + $this->entityTypeBundleInfo = $this->prophesize(EntityTypeBundleInfoInterface::class); + + $container = new ContainerBuilder(); + $container->set('typed_data_manager', $type_data_manager); + $container->set('entity_type.manager', $this->entityTypeManager->reveal()); + $container->set('entity.manager', $this->entityManager->reveal()); + $container->set('entity_type.bundle.info', $this->entityTypeBundleInfo->reveal()); + \Drupal::setContainer($container); + } + + /** + * Asserts that the requirement is satisfied as expected. + * + * @param bool $expected + * The expected outcome. + * @param \Drupal\Core\Plugin\Context\ContextDefinition $requirement + * The requirement to check against. + * @param \Drupal\Core\Plugin\Context\ContextDefinition $definition + * The context definition to check. + * @param mixed $value + * (optional) The value to set on the context, defaults to NULL. + */ + protected function assertRequirementIsSatisfied($expected, ContextDefinition $requirement, ContextDefinition $definition, $value = NULL) { + $context = new Context($definition, $value); + $this->assertSame($expected, $requirement->isSatisfiedBy($context)); + } + + /** + * @covers ::isSatisfiedBy + * @covers ::getSampleValues + * @covers ::getConstraintObjects + * + * @dataProvider providerTestIsSatisfiedBy + */ + public function testIsSatisfiedBy($expected, ContextDefinition $requirement, ContextDefinition $definition, $value = NULL) { + $entity_storage = $this->prophesize(EntityStorageInterface::class); + $content_entity_storage = $this->prophesize(ContentEntityStorageInterface::class); + $this->entityTypeManager->getStorage('test_config')->willReturn($entity_storage->reveal()); + $this->entityTypeManager->getStorage('test_content')->willReturn($content_entity_storage->reveal()); + $this->entityManager->getDefinitions()->willReturn([ + 'test_config' => new EntityType(['id' => 'test_config']), + 'test_content' => new EntityType(['id' => 'test_content']), + ]); + $this->entityTypeBundleInfo->getBundleInfo('test_config')->willReturn([ + 'test_config' => ['label' => 'test_config'], + ]); + $this->entityTypeBundleInfo->getBundleInfo('test_content')->willReturn([ + 'test_content' => ['label' => 'test_content'], + ]); + + $this->assertRequirementIsSatisfied($expected, $requirement, $definition, $value); + } + + /** + * Provides test data for ::testIsSatisfiedBy(). + */ + public function providerTestIsSatisfiedBy() { + $data = []; + + // Simple data types. + $data['both any'] = [ + TRUE, + new ContextDefinition('any'), + new ContextDefinition('any'), + ]; + $data['requirement any'] = [ + TRUE, + new ContextDefinition('any'), + new ContextDefinition('integer'), + ]; + $data['integer, out of range'] = [ + FALSE, + (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]), + new ContextDefinition('integer'), + 20, + ]; + $data['integer, within range'] = [ + TRUE, + (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]), + new ContextDefinition('integer'), + 5, + ]; + $data['integer, no value'] = [ + TRUE, + (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]), + new ContextDefinition('integer'), + ]; + $data['non-integer, within range'] = [ + FALSE, + (new ContextDefinition('integer'))->addConstraint('Range', ['min' => 0, 'max' => 10]), + new ContextDefinition('any'), + 5, + ]; + + // Entities without bundles. + $data['content entity, matching type, no value'] = [ + TRUE, + new ContextDefinition('entity:test_content'), + new ContextDefinition('entity:test_content'), + ]; + $entity = $this->prophesize(ContentEntityInterface::class)->willImplement(\IteratorAggregate::class); + $entity->getIterator()->willReturn(new \ArrayIterator([])); + $entity->getCacheContexts()->willReturn([]); + $entity->getCacheTags()->willReturn([]); + $entity->getCacheMaxAge()->willReturn(0); + $entity->getEntityTypeId()->willReturn('test_content'); + $data['content entity, matching type, correct value'] = [ + TRUE, + new ContextDefinition('entity:test_content'), + new ContextDefinition('entity:test_content'), + $entity->reveal(), + ]; + $data['content entity, incorrect manual constraint'] = [ + TRUE, + new ContextDefinition('entity:test_content'), + (new ContextDefinition('entity:test_content'))->addConstraint('EntityType', 'test_config'), + ]; + $data['config entity, matching type, no value'] = [ + TRUE, + new ContextDefinition('entity:test_config'), + new ContextDefinition('entity:test_config'), + ]; + + return $data; + } + + /** + * @covers ::isSatisfiedBy + * @covers ::getSampleValues + * @covers ::getConstraintObjects + * + * @dataProvider providerTestIsSatisfiedByGenerateBundledEntity + */ + public function testIsSatisfiedByGenerateBundledEntity($expected, array $requirement_bundles, array $candidate_bundles, array $bundles_to_instantiate = NULL) { + // If no bundles are explicitly specified, instantiate all bundles. + if (!$bundles_to_instantiate) { + $bundles_to_instantiate = $candidate_bundles; + } + + $content_entity_storage = $this->prophesize(ContentEntityStorageInterface::class); + foreach ($bundles_to_instantiate as $bundle) { + $entity = $this->prophesize(ContentEntityInterface::class)->willImplement(\IteratorAggregate::class); + $entity->getEntityTypeId()->willReturn('test_content'); + $entity->getIterator()->willReturn(new \ArrayIterator([])); + $entity->bundle()->willReturn($bundle); + $content_entity_storage->createWithSampleValues($bundle) + ->willReturn($entity->reveal()) + ->shouldBeCalled(); + } + + $this->entityTypeManager->getStorage('test_content')->willReturn($content_entity_storage->reveal()); + $this->entityManager->getDefinitions()->willReturn([ + 'test_content' => new EntityType(['id' => 'test_content']), + ]); + + $this->entityTypeBundleInfo->getBundleInfo('test_content')->willReturn([ + 'first_bundle' => ['label' => 'First bundle'], + 'second_bundle' => ['label' => 'Second bundle'], + 'third_bundle' => ['label' => 'Third bundle'], + ]); + + $requirement = new ContextDefinition('entity:test_content'); + if ($requirement_bundles) { + $requirement->addConstraint('Bundle', $requirement_bundles); + } + $definition = (new ContextDefinition('entity:test_content'))->addConstraint('Bundle', $candidate_bundles); + $this->assertRequirementIsSatisfied($expected, $requirement, $definition); + } + + /** + * Provides test data for ::testIsSatisfiedByGenerateBundledEntity(). + */ + public function providerTestIsSatisfiedByGenerateBundledEntity() { + $data = []; + $data['no requirement'] = [ + TRUE, + [], + ['first_bundle'], + ]; + $data['single requirement'] = [ + TRUE, + ['first_bundle'], + ['first_bundle'], + ]; + $data['single requirement, multiple candidates, satisfies last candidate'] = [ + TRUE, + ['third_bundle'], + ['first_bundle', 'second_bundle', 'third_bundle'], + ]; + $data['single requirement, multiple candidates, satisfies first candidate'] = [ + TRUE, + ['first_bundle'], + ['first_bundle', 'second_bundle', 'third_bundle'], + // Once the first match is found, subsequent candidates are not checked. + ['first_bundle'], + ]; + $data['unsatisfied requirement'] = [ + FALSE, + ['second_bundle'], + ['first_bundle', 'third_bundle'], + ]; + $data['multiple requirements'] = [ + TRUE, + ['first_bundle', 'second_bundle'], + ['first_bundle'], + ]; + return $data; + } + + /** + * @covers ::isSatisfiedBy + * @covers ::getSampleValues + * @covers ::getConstraintObjects + * + * @dataProvider providerTestIsSatisfiedByPassBundledEntity + */ + public function testIsSatisfiedByPassBundledEntity($expected, $requirement_constraint) { + $this->entityManager->getDefinitions()->willReturn([ + 'test_content' => new EntityType(['id' => 'test_content']), + ]); + $this->entityTypeManager->getStorage('test_content')->shouldNotBeCalled(); + + $this->entityTypeBundleInfo->getBundleInfo('test_content')->willReturn([ + 'first_bundle' => ['label' => 'First bundle'], + 'second_bundle' => ['label' => 'Second bundle'], + 'third_bundle' => ['label' => 'Third bundle'], + ]); + + $entity = $this->prophesize(ContentEntityInterface::class)->willImplement(\IteratorAggregate::class); + $entity->getEntityTypeId()->willReturn('test_content'); + $entity->getIterator()->willReturn(new \ArrayIterator([])); + $entity->getCacheContexts()->willReturn([]); + $entity->getCacheTags()->willReturn([]); + $entity->getCacheMaxAge()->willReturn(0); + $entity->bundle()->willReturn('third_bundle'); + + $requirement = new ContextDefinition('entity:test_content'); + if ($requirement_constraint) { + $requirement->addConstraint('Bundle', $requirement_constraint); + } + $definition = new ContextDefinition('entity:test_content'); + $this->assertRequirementIsSatisfied($expected, $requirement, $definition, $entity->reveal()); + } + + /** + * Provides test data for ::testIsSatisfiedByPassBundledEntity(). + */ + public function providerTestIsSatisfiedByPassBundledEntity() { + $data = []; + $data[] = [TRUE, []]; + $data[] = [FALSE, ['first_bundle']]; + $data[] = [FALSE, ['second_bundle']]; + $data[] = [TRUE, ['third_bundle']]; + $data[] = [TRUE, ['first_bundle', 'second_bundle', 'third_bundle']]; + $data[] = [FALSE, ['first_bundle', 'second_bundle']]; + $data[] = [TRUE, ['first_bundle', 'third_bundle']]; + $data[] = [TRUE, ['second_bundle', 'third_bundle']]; + return $data; + } + +} + +namespace Drupal\Core\Validation; + +if (!function_exists('t')) { + function t($string, array $args = []) { + return strtr($string, $args); + } +} diff --git a/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php b/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php index 4ed5e6eb60..5cf8d9cc8b 100644 --- a/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php +++ b/core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php @@ -9,12 +9,19 @@ use Drupal\Component\Plugin\ConfigurablePluginInterface; use Drupal\Component\Plugin\Exception\ContextException; +use Drupal\Core\Cache\NullBackend; +use Drupal\Core\DependencyInjection\ClassResolverInterface; +use Drupal\Core\DependencyInjection\ContainerBuilder; +use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Plugin\Context\ContextDefinition; use Drupal\Core\Plugin\Context\ContextHandler; use Drupal\Core\Plugin\ContextAwarePluginInterface; use Drupal\Core\TypedData\DataDefinition; use Drupal\Core\TypedData\Plugin\DataType\StringData; +use Drupal\Core\TypedData\TypedDataManager; +use Drupal\Core\Validation\ConstraintManager; use Drupal\Tests\UnitTestCase; +use Prophecy\Argument; /** * @coversDefaultClass \Drupal\Core\Plugin\Context\ContextHandler @@ -36,6 +43,26 @@ protected function setUp() { parent::setUp(); $this->contextHandler = new ContextHandler(); + + $namespaces = new \ArrayObject([ + 'Drupal\\Core\\TypedData' => $this->root . '/core/lib/Drupal/Core/TypedData', + 'Drupal\\Core\\Validation' => $this->root . '/core/lib/Drupal/Core/Validation', + ]); + $cache_backend = new NullBackend('cache'); + $module_handler = $this->prophesize(ModuleHandlerInterface::class); + $class_resolver = $this->prophesize(ClassResolverInterface::class); + $class_resolver->getInstanceFromDefinition(Argument::type('string'))->will(function ($arguments) { + $class_name = $arguments[0]; + return new $class_name(); + }); + $type_data_manager = new TypedDataManager($namespaces, $cache_backend, $module_handler->reveal(), $class_resolver->reveal()); + $type_data_manager->setValidationConstraintManager( + new ConstraintManager($namespaces, $cache_backend, $module_handler->reveal()) + ); + + $container = new ContainerBuilder(); + $container->set('typed_data_manager', $type_data_manager); + \Drupal::setContainer($container); } /** @@ -60,10 +87,10 @@ public function providerTestCheckRequirements() { $context_any = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface'); $context_any->expects($this->atLeastOnce()) ->method('getContextDefinition') - ->will($this->returnValue(new ContextDefinition('empty'))); + ->will($this->returnValue(new ContextDefinition('any'))); - $requirement_specific = new ContextDefinition('specific'); - $requirement_specific->setConstraints(['bar' => 'baz']); + $requirement_specific = new ContextDefinition('string'); + $requirement_specific->setConstraints(['Blank' => []]); $context_constraint_mismatch = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface'); $context_constraint_mismatch->expects($this->atLeastOnce()) @@ -74,8 +101,8 @@ public function providerTestCheckRequirements() { ->method('getContextDefinition') ->will($this->returnValue(new ContextDefinition('fuzzy'))); - $context_definition_specific = new ContextDefinition('specific'); - $context_definition_specific->setConstraints(['bar' => 'baz']); + $context_definition_specific = new ContextDefinition('string'); + $context_definition_specific->setConstraints(['Blank' => []]); $context_specific = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface'); $context_specific->expects($this->atLeastOnce()) ->method('getContextDefinition') @@ -112,13 +139,13 @@ public function testGetMatchingContexts($contexts, $requirement, $expected = NUL public function providerTestGetMatchingContexts() { $requirement_any = new ContextDefinition(); - $requirement_specific = new ContextDefinition('specific'); - $requirement_specific->setConstraints(['bar' => 'baz']); + $requirement_specific = new ContextDefinition('string'); + $requirement_specific->setConstraints(['Blank' => []]); $context_any = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface'); $context_any->expects($this->atLeastOnce()) ->method('getContextDefinition') - ->will($this->returnValue(new ContextDefinition('empty'))); + ->will($this->returnValue(new ContextDefinition('any'))); $context_constraint_mismatch = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface'); $context_constraint_mismatch->expects($this->atLeastOnce()) ->method('getContextDefinition') @@ -127,8 +154,8 @@ public function providerTestGetMatchingContexts() { $context_datatype_mismatch->expects($this->atLeastOnce()) ->method('getContextDefinition') ->will($this->returnValue(new ContextDefinition('fuzzy'))); - $context_definition_specific = new ContextDefinition('specific'); - $context_definition_specific->setConstraints(['bar' => 'baz']); + $context_definition_specific = new ContextDefinition('string'); + $context_definition_specific->setConstraints(['Blank' => []]); $context_specific = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface'); $context_specific->expects($this->atLeastOnce()) ->method('getContextDefinition') @@ -158,7 +185,7 @@ public function providerTestGetMatchingContexts() { public function testFilterPluginDefinitionsByContexts($has_context, $definitions, $expected) { if ($has_context) { $context = $this->getMock('Drupal\Core\Plugin\Context\ContextInterface'); - $expected_context_definition = (new ContextDefinition('expected_data_type'))->setConstraints(['expected_constraint_name' => 'expected_constraint_value']); + $expected_context_definition = (new ContextDefinition('string'))->setConstraints(['Blank' => []]); $context->expects($this->atLeastOnce()) ->method('getContextDefinition') ->will($this->returnValue($expected_context_definition)); @@ -189,7 +216,7 @@ public function providerTestFilterPluginDefinitionsByContexts() { // No context, all plugins available. $data[] = [FALSE, $plugins, $plugins]; - $plugins = ['expected_plugin' => ['context' => ['context1' => new ContextDefinition('expected_data_type')]]]; + $plugins = ['expected_plugin' => ['context' => ['context1' => new ContextDefinition('string')]]]; // Missing context, no plugins available. $data[] = [FALSE, $plugins, []]; // Satisfied context, all plugins available. @@ -206,7 +233,7 @@ public function providerTestFilterPluginDefinitionsByContexts() { // Optional mismatched constraint, all plugins available. $data[] = [FALSE, $plugins, $plugins]; - $expected_context_definition = (new ContextDefinition('expected_data_type'))->setConstraints(['expected_constraint_name' => 'expected_constraint_value']); + $expected_context_definition = (new ContextDefinition('string'))->setConstraints(['Blank' => []]); $plugins = ['expected_plugin' => ['context' => ['context1' => $expected_context_definition]]]; // Satisfied context with constraint, all plugins available. $data[] = [TRUE, $plugins, $plugins]; @@ -220,7 +247,7 @@ public function providerTestFilterPluginDefinitionsByContexts() { $unexpected_context_definition = (new ContextDefinition('unexpected_data_type'))->setConstraints(['mismatched_constraint_name' => 'mismatched_constraint_value']); $plugins = [ 'unexpected_plugin' => ['context' => ['context1' => $unexpected_context_definition]], - 'expected_plugin' => ['context' => ['context2' => new ContextDefinition('expected_data_type')]], + 'expected_plugin' => ['context' => ['context2' => new ContextDefinition('string')]], ]; // Context only satisfies one plugin. $data[] = [TRUE, $plugins, ['expected_plugin' => $plugins['expected_plugin']]]; -- GitLab