class ContextHandlerTest

Same name in other branches
  1. 9 core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php \Drupal\KernelTests\Core\Plugin\ContextHandlerTest
  2. 9 core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php \Drupal\Tests\Core\Plugin\ContextHandlerTest
  3. 8.9.x core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php \Drupal\KernelTests\Core\Plugin\ContextHandlerTest
  4. 8.9.x core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php \Drupal\Tests\Core\Plugin\ContextHandlerTest
  5. 10 core/tests/Drupal/KernelTests/Core/Plugin/ContextHandlerTest.php \Drupal\KernelTests\Core\Plugin\ContextHandlerTest
  6. 10 core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php \Drupal\Tests\Core\Plugin\ContextHandlerTest

@coversDefaultClass \Drupal\Core\Plugin\Context\ContextHandler @group Plugin

Hierarchy

Expanded class hierarchy of ContextHandlerTest

File

core/tests/Drupal/Tests/Core/Plugin/ContextHandlerTest.php, line 30

Namespace

Drupal\Tests\Core\Plugin
View source
class ContextHandlerTest extends UnitTestCase {
    
    /**
     * The context handler.
     *
     * @var \Drupal\Core\Plugin\Context\ContextHandler
     */
    protected $contextHandler;
    
    /**
     * {@inheritdoc}
     */
    protected function setUp() : void {
        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 = TestKernel::setContainerWithKernel();
        $container->set('typed_data_manager', $type_data_manager);
        \Drupal::setContainer($container);
    }
    
    /**
     * @covers ::checkRequirements
     *
     * @dataProvider providerTestCheckRequirements
     */
    public function testCheckRequirements($contexts, $requirements, $expected) : void {
        $contexts = array_map(function ($context) {
            $mock = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
            $mock->expects($this->atLeastOnce())
                ->method('getContextDefinition')
                ->willReturn($context);
            return $mock;
        }, $contexts);
        $this->assertSame($expected, $this->contextHandler
            ->checkRequirements($contexts, $requirements));
    }
    
    /**
     * Provides data for testCheckRequirements().
     */
    public static function providerTestCheckRequirements() {
        $requirement_optional = new ContextDefinition();
        $requirement_optional->setRequired(FALSE);
        $requirement_any = new ContextDefinition();
        $requirement_any->setRequired(TRUE);
        $context_any = new ContextDefinition('any');
        $requirement_specific = new ContextDefinition('string');
        $requirement_specific->setConstraints([
            'Blank' => [],
        ]);
        $context_constraint_mismatch = new ContextDefinition('foo');
        $context_datatype_mismatch = new ContextDefinition('fuzzy');
        $context_specific = new ContextDefinition('string');
        $context_specific->setConstraints([
            'Blank' => [],
        ]);
        $data = [];
        $data[] = [
            [],
            [],
            TRUE,
        ];
        $data[] = [
            [],
            [
                $requirement_any,
            ],
            FALSE,
        ];
        $data[] = [
            [],
            [
                $requirement_optional,
            ],
            TRUE,
        ];
        $data[] = [
            [],
            [
                $requirement_any,
                $requirement_optional,
            ],
            FALSE,
        ];
        $data[] = [
            [
                $context_any,
            ],
            [
                $requirement_any,
            ],
            TRUE,
        ];
        $data[] = [
            [
                $context_constraint_mismatch,
            ],
            [
                $requirement_specific,
            ],
            FALSE,
        ];
        $data[] = [
            [
                $context_datatype_mismatch,
            ],
            [
                $requirement_specific,
            ],
            FALSE,
        ];
        $data[] = [
            [
                $context_specific,
            ],
            [
                $requirement_specific,
            ],
            TRUE,
        ];
        return $data;
    }
    
    /**
     * @covers ::getMatchingContexts
     *
     * @dataProvider providerTestGetMatchingContexts
     */
    public function testGetMatchingContexts($contexts, $requirement, $expected = NULL) : void {
        $contexts = array_map(function ($context) {
            $mock = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
            $mock->expects($this->atLeastOnce())
                ->method('getContextDefinition')
                ->willReturn($context);
            return $mock;
        }, $contexts);
        if (is_null($expected)) {
            $expected = $contexts;
        }
        $this->assertSame($expected, $this->contextHandler
            ->getMatchingContexts($contexts, $requirement));
    }
    
    /**
     * Provides data for testGetMatchingContexts().
     */
    public static function providerTestGetMatchingContexts() {
        $requirement_any = new ContextDefinition();
        $requirement_specific = new ContextDefinition('string');
        $requirement_specific->setConstraints([
            'Blank' => [],
        ]);
        $context_any = new ContextDefinition('any');
        $context_constraint_mismatch = new ContextDefinition('foo');
        $context_datatype_mismatch = new ContextDefinition('fuzzy');
        $context_specific = new ContextDefinition('string');
        $context_specific->setConstraints([
            'Blank' => [],
        ]);
        $data = [];
        // No context will return no valid contexts.
        $data[] = [
            [],
            $requirement_any,
        ];
        // A context with a generic matching requirement is valid.
        $data[] = [
            [
                $context_any,
            ],
            $requirement_any,
        ];
        // A context with a specific matching requirement is valid.
        $data[] = [
            [
                $context_specific,
            ],
            $requirement_specific,
        ];
        // A context with a mismatched constraint is invalid.
        $data[] = [
            [
                $context_constraint_mismatch,
            ],
            $requirement_specific,
            [],
        ];
        // A context with a mismatched datatype is invalid.
        $data[] = [
            [
                $context_datatype_mismatch,
            ],
            $requirement_specific,
            [],
        ];
        return $data;
    }
    
    /**
     * @covers ::filterPluginDefinitionsByContexts
     *
     * @dataProvider providerTestFilterPluginDefinitionsByContexts
     */
    public function testFilterPluginDefinitionsByContexts($has_context, $definitions, $expected) : void {
        if ($has_context) {
            $context = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
            $expected_context_definition = (new ContextDefinition('string'))->setConstraints([
                'Blank' => [],
            ]);
            $context->expects($this->atLeastOnce())
                ->method('getContextDefinition')
                ->willReturn($expected_context_definition);
            $contexts = [
                $context,
            ];
        }
        else {
            $contexts = [];
        }
        $this->assertSame($expected, $this->contextHandler
            ->filterPluginDefinitionsByContexts($contexts, $definitions));
    }
    
    /**
     * Provides data for testFilterPluginDefinitionsByContexts().
     */
    public static function providerTestFilterPluginDefinitionsByContexts() {
        $data = [];
        $plugins = [];
        // No context and no plugins, no plugins available.
        $data[] = [
            FALSE,
            $plugins,
            [],
        ];
        $plugins = [
            'expected_array_plugin' => [],
            'expected_object_plugin' => new ContextAwarePluginDefinition(),
        ];
        // No context, all plugins available.
        $data[] = [
            FALSE,
            $plugins,
            $plugins,
        ];
        $plugins = [
            'expected_array_plugin' => [
                'context_definitions' => [],
            ],
            'expected_object_plugin' => new ContextAwarePluginDefinition(),
        ];
        // No context, all plugins available.
        $data[] = [
            FALSE,
            $plugins,
            $plugins,
        ];
        $plugins = [
            'expected_array_plugin' => [
                'context_definitions' => [
                    'context1' => new ContextDefinition('string'),
                ],
            ],
            'expected_object_plugin' => (new ContextAwarePluginDefinition())->addContextDefinition('context1', new ContextDefinition('string')),
        ];
        // Missing context, no plugins available.
        $data[] = [
            FALSE,
            $plugins,
            [],
        ];
        // Satisfied context, all plugins available.
        $data[] = [
            TRUE,
            $plugins,
            $plugins,
        ];
        $mismatched_context_definition = (new ContextDefinition('expected_data_type'))->setConstraints([
            'mismatched_constraint_name' => 'mismatched_constraint_value',
        ]);
        $plugins = [
            'expected_array_plugin' => [
                'context_definitions' => [
                    'context1' => $mismatched_context_definition,
                ],
            ],
            'expected_object_plugin' => (new ContextAwarePluginDefinition())->addContextDefinition('context1', $mismatched_context_definition),
        ];
        // Mismatched constraints, no plugins available.
        $data[] = [
            TRUE,
            $plugins,
            [],
        ];
        $optional_mismatched_context_definition = clone $mismatched_context_definition;
        $optional_mismatched_context_definition->setRequired(FALSE);
        $plugins = [
            'expected_array_plugin' => [
                'context_definitions' => [
                    'context1' => $optional_mismatched_context_definition,
                ],
            ],
            'expected_object_plugin' => (new ContextAwarePluginDefinition())->addContextDefinition('context1', $optional_mismatched_context_definition),
        ];
        // Optional mismatched constraint, all plugins available.
        $data[] = [
            FALSE,
            $plugins,
            $plugins,
        ];
        $expected_context_definition = (new ContextDefinition('string'))->setConstraints([
            'Blank' => [],
        ]);
        $plugins = [
            'expected_array_plugin' => [
                'context_definitions' => [
                    'context1' => $expected_context_definition,
                ],
            ],
            'expected_object_plugin' => (new ContextAwarePluginDefinition())->addContextDefinition('context1', $expected_context_definition),
        ];
        // Satisfied context with constraint, all plugins available.
        $data[] = [
            TRUE,
            $plugins,
            $plugins,
        ];
        $optional_expected_context_definition = clone $expected_context_definition;
        $optional_expected_context_definition->setRequired(FALSE);
        $plugins = [
            'expected_array_plugin' => [
                'context_definitions' => [
                    'context1' => $optional_expected_context_definition,
                ],
            ],
            'expected_object_plugin' => (new ContextAwarePluginDefinition())->addContextDefinition('context1', $optional_expected_context_definition),
        ];
        // Optional unsatisfied context, all plugins available.
        $data[] = [
            FALSE,
            $plugins,
            $plugins,
        ];
        $unexpected_context_definition = (new ContextDefinition('unexpected_data_type'))->setConstraints([
            'mismatched_constraint_name' => 'mismatched_constraint_value',
        ]);
        $plugins = [
            'unexpected_array_plugin' => [
                'context_definitions' => [
                    'context1' => $unexpected_context_definition,
                ],
            ],
            'expected_array_plugin' => [
                'context_definitions' => [
                    'context2' => new ContextDefinition('string'),
                ],
            ],
            'unexpected_object_plugin' => (new ContextAwarePluginDefinition())->addContextDefinition('context1', $unexpected_context_definition),
            'expected_object_plugin' => (new ContextAwarePluginDefinition())->addContextDefinition('context2', new ContextDefinition('string')),
        ];
        // Context only satisfies two plugins.
        $data[] = [
            TRUE,
            $plugins,
            [
                'expected_array_plugin' => $plugins['expected_array_plugin'],
                'expected_object_plugin' => $plugins['expected_object_plugin'],
            ],
        ];
        return $data;
    }
    
    /**
     * @covers ::applyContextMapping
     */
    public function testApplyContextMapping() : void {
        $context_hit = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
        $context_hit->expects($this->atLeastOnce())
            ->method('hasContextValue')
            ->willReturn(TRUE);
        $context_miss = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
        $contexts = [
            'hit' => $context_hit,
            'miss' => $context_miss,
        ];
        $context_definition = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextDefinitionInterface');
        $plugin = $this->createMock('Drupal\\Core\\Plugin\\ContextAwarePluginInterface');
        $plugin->expects($this->once())
            ->method('getContextMapping')
            ->willReturn([]);
        $plugin->expects($this->once())
            ->method('getContextDefinitions')
            ->willReturn([
            'hit' => $context_definition,
        ]);
        $plugin->expects($this->once())
            ->method('setContext')
            ->with('hit', $context_hit);
        // Make sure that the cacheability metadata is passed to the plugin context.
        $plugin_context = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
        $plugin_context->expects($this->once())
            ->method('addCacheableDependency')
            ->with($context_hit);
        $plugin->expects($this->once())
            ->method('getContext')
            ->with('hit')
            ->willReturn($plugin_context);
        $this->contextHandler
            ->applyContextMapping($plugin, $contexts);
    }
    
    /**
     * @covers ::applyContextMapping
     */
    public function testApplyContextMappingMissingRequired() : void {
        $context = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
        $context->expects($this->never())
            ->method('getContextValue');
        $contexts = [
            'name' => $context,
        ];
        $context_definition = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextDefinitionInterface');
        $context_definition->expects($this->atLeastOnce())
            ->method('isRequired')
            ->willReturn(TRUE);
        $plugin = $this->createMock('Drupal\\Tests\\Core\\Plugin\\TestConfigurableContextAwarePluginInterface');
        $plugin->expects($this->once())
            ->method('getContextMapping')
            ->willReturn([]);
        $plugin->expects($this->once())
            ->method('getContextDefinitions')
            ->willReturn([
            'hit' => $context_definition,
        ]);
        $plugin->expects($this->never())
            ->method('setContext');
        // No context, so no cacheability metadata can be passed along.
        $plugin->expects($this->any())
            ->method('getContext')
            ->willThrowException(new ContextException());
        $this->expectException(MissingValueContextException::class);
        $this->expectExceptionMessage('Required contexts without a value: hit');
        $this->contextHandler
            ->applyContextMapping($plugin, $contexts);
    }
    
    /**
     * @covers ::applyContextMapping
     */
    public function testApplyContextMappingMissingNotRequired() : void {
        $context = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
        $context->expects($this->never())
            ->method('getContextValue');
        $contexts = [
            'name' => $context,
        ];
        $context_definition = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextDefinitionInterface');
        $context_definition->expects($this->atLeastOnce())
            ->method('isRequired')
            ->willReturn(FALSE);
        $plugin = $this->createMock('Drupal\\Tests\\Core\\Plugin\\TestConfigurableContextAwarePluginInterface');
        $plugin->expects($this->once())
            ->method('getContextMapping')
            ->willReturn([
            'optional' => 'missing',
        ]);
        $plugin->expects($this->once())
            ->method('getContextDefinitions')
            ->willReturn([
            'optional' => $context_definition,
        ]);
        $plugin->expects($this->never())
            ->method('setContext');
        // No context, so no cacheability metadata can be passed along.
        $plugin->expects($this->any())
            ->method('getContext')
            ->willThrowException(new ContextException());
        $this->contextHandler
            ->applyContextMapping($plugin, $contexts);
    }
    
    /**
     * @covers ::applyContextMapping
     */
    public function testApplyContextMappingNoValueRequired() : void {
        $context = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
        $context->expects($this->never())
            ->method('getContextValue');
        $context->expects($this->atLeastOnce())
            ->method('hasContextValue')
            ->willReturn(FALSE);
        $contexts = [
            'hit' => $context,
        ];
        $context_definition = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextDefinitionInterface');
        $context_definition->expects($this->atLeastOnce())
            ->method('isRequired')
            ->willReturn(TRUE);
        $plugin = $this->createMock('Drupal\\Tests\\Core\\Plugin\\TestConfigurableContextAwarePluginInterface');
        $plugin->expects($this->once())
            ->method('getContextMapping')
            ->willReturn([]);
        $plugin->expects($this->once())
            ->method('getContextDefinitions')
            ->willReturn([
            'hit' => $context_definition,
        ]);
        $plugin->expects($this->never())
            ->method('setContext');
        $this->expectException(MissingValueContextException::class);
        $this->expectExceptionMessage('Required contexts without a value: hit');
        $this->contextHandler
            ->applyContextMapping($plugin, $contexts);
    }
    
    /**
     * @covers ::applyContextMapping
     */
    public function testApplyContextMappingNoValueNonRequired() : void {
        $context = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
        $context->expects($this->never())
            ->method('getContextValue');
        $context->expects($this->atLeastOnce())
            ->method('hasContextValue')
            ->willReturn(FALSE);
        $contexts = [
            'hit' => $context,
        ];
        $context_definition = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextDefinitionInterface');
        $context_definition->expects($this->atLeastOnce())
            ->method('isRequired')
            ->willReturn(FALSE);
        $plugin = $this->createMock('Drupal\\Tests\\Core\\Plugin\\TestConfigurableContextAwarePluginInterface');
        $plugin->expects($this->once())
            ->method('getContextMapping')
            ->willReturn([]);
        $plugin->expects($this->once())
            ->method('getContextDefinitions')
            ->willReturn([
            'hit' => $context_definition,
        ]);
        $plugin->expects($this->never())
            ->method('setContext');
        $this->contextHandler
            ->applyContextMapping($plugin, $contexts);
    }
    
    /**
     * @covers ::applyContextMapping
     */
    public function testApplyContextMappingConfigurableAssigned() : void {
        $context = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
        $context->expects($this->atLeastOnce())
            ->method('hasContextValue')
            ->willReturn(TRUE);
        $contexts = [
            'name' => $context,
        ];
        $context_definition = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextDefinitionInterface');
        $plugin = $this->createMock('Drupal\\Tests\\Core\\Plugin\\TestConfigurableContextAwarePluginInterface');
        $plugin->expects($this->once())
            ->method('getContextMapping')
            ->willReturn([]);
        $plugin->expects($this->once())
            ->method('getContextDefinitions')
            ->willReturn([
            'hit' => $context_definition,
        ]);
        $plugin->expects($this->once())
            ->method('setContext')
            ->with('hit', $context);
        // Make sure that the cacheability metadata is passed to the plugin context.
        $plugin_context = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
        $plugin_context->expects($this->once())
            ->method('addCacheableDependency')
            ->with($context);
        $plugin->expects($this->once())
            ->method('getContext')
            ->with('hit')
            ->willReturn($plugin_context);
        $this->contextHandler
            ->applyContextMapping($plugin, $contexts, [
            'hit' => 'name',
        ]);
    }
    
    /**
     * @covers ::applyContextMapping
     */
    public function testApplyContextMappingConfigurableAssignedMiss() : void {
        $context = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextInterface');
        $context->expects($this->never())
            ->method('getContextValue');
        $contexts = [
            'name' => $context,
        ];
        $context_definition = $this->createMock('Drupal\\Core\\Plugin\\Context\\ContextDefinitionInterface');
        $plugin = $this->createMock('Drupal\\Tests\\Core\\Plugin\\TestConfigurableContextAwarePluginInterface');
        $plugin->expects($this->once())
            ->method('getContextMapping')
            ->willReturn([]);
        $plugin->expects($this->once())
            ->method('getContextDefinitions')
            ->willReturn([
            'hit' => $context_definition,
        ]);
        $plugin->expects($this->never())
            ->method('setContext');
        $this->expectException(ContextException::class);
        $this->expectExceptionMessage('Assigned contexts were not satisfied: miss');
        $this->contextHandler
            ->applyContextMapping($plugin, $contexts, [
            'miss' => 'name',
        ]);
    }

}

Members

Title Sort descending Modifiers Object type Summary Overriden Title
ContextHandlerTest::$contextHandler protected property The context handler.
ContextHandlerTest::providerTestCheckRequirements public static function Provides data for testCheckRequirements().
ContextHandlerTest::providerTestFilterPluginDefinitionsByContexts public static function Provides data for testFilterPluginDefinitionsByContexts().
ContextHandlerTest::providerTestGetMatchingContexts public static function Provides data for testGetMatchingContexts().
ContextHandlerTest::setUp protected function Overrides UnitTestCase::setUp
ContextHandlerTest::testApplyContextMapping public function @covers ::applyContextMapping
ContextHandlerTest::testApplyContextMappingConfigurableAssigned public function @covers ::applyContextMapping
ContextHandlerTest::testApplyContextMappingConfigurableAssignedMiss public function @covers ::applyContextMapping
ContextHandlerTest::testApplyContextMappingMissingNotRequired public function @covers ::applyContextMapping
ContextHandlerTest::testApplyContextMappingMissingRequired public function @covers ::applyContextMapping
ContextHandlerTest::testApplyContextMappingNoValueNonRequired public function @covers ::applyContextMapping
ContextHandlerTest::testApplyContextMappingNoValueRequired public function @covers ::applyContextMapping
ContextHandlerTest::testCheckRequirements public function @covers ::checkRequirements
ContextHandlerTest::testFilterPluginDefinitionsByContexts public function @covers ::filterPluginDefinitionsByContexts
ContextHandlerTest::testGetMatchingContexts public function @covers ::getMatchingContexts
ExpectDeprecationTrait::expectDeprecation public function Adds an expected deprecation.
ExpectDeprecationTrait::setUpErrorHandler public function Sets up the test error handler.
ExpectDeprecationTrait::tearDownErrorHandler public function Tears down the test error handler.
RandomGeneratorTrait::getRandomGenerator protected function Gets the random generator for the utility methods.
RandomGeneratorTrait::randomMachineName protected function Generates a unique random string containing letters and numbers.
RandomGeneratorTrait::randomObject public function Generates a random PHP object.
RandomGeneratorTrait::randomString public function Generates a pseudo-random string of ASCII characters of codes 32 to 126.
UnitTestCase::$root protected property The app root.
UnitTestCase::getClassResolverStub protected function Returns a stub class resolver.
UnitTestCase::getConfigFactoryStub public function Returns a stub config factory that behaves according to the passed array.
UnitTestCase::getContainerWithCacheTagsInvalidator protected function Sets up a container with a cache tags invalidator.
UnitTestCase::getStringTranslationStub public function Returns a stub translation manager that just returns the passed string.
UnitTestCase::setDebugDumpHandler public static function Registers the dumper CLI handler when the DebugDump extension is enabled.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.