3 namespace Drupal\Tests\Core\Menu;
5 use Drupal\Component\Plugin\Exception\PluginException;
6 use Drupal\Core\Access\AccessResult;
7 use Drupal\Core\Language\Language;
8 use Drupal\Core\Menu\ContextualLinkDefault;
9 use Drupal\Tests\UnitTestCase;
10 use Symfony\Component\HttpFoundation\RequestStack;
13 * @coversDefaultClass \Drupal\Core\Menu\ContextualLinkManager
16 class ContextualLinkManagerTest extends UnitTestCase {
19 * The tested contextual link manager.
21 * @var \Drupal\Core\Menu\ContextualLinkManager
23 protected $contextualLinkManager;
26 * The mocked controller resolver.
28 * @var \Symfony\Component\HttpKernel\Controller\ControllerResolverInterface|\Drupal\Core\\PHPUnit_Framework_MockObject_MockObject
30 protected $controllerResolver;
33 * The mocked plugin discovery.
35 * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface|\PHPUnit_Framework_MockObject_MockObject
37 protected $pluginDiscovery;
40 * The plugin factory used in the test.
42 * @var \Drupal\Component\Plugin\Factory\FactoryInterface|\PHPUnit_Framework_MockObject_MockObject
47 * The cache backend used in the test.
49 * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
51 protected $cacheBackend;
54 * The mocked module handler.
56 * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
58 protected $moduleHandler;
61 * The mocked access manager.
63 * @var \Drupal\Core\Access\AccessManagerInterface|\PHPUnit_Framework_MockObject_MockObject
65 protected $accessManager;
70 * @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
74 protected function setUp() {
75 $this->contextualLinkManager = $this
76 ->getMockBuilder('Drupal\Core\Menu\ContextualLinkManager')
77 ->disableOriginalConstructor()
81 $this->controllerResolver = $this->getMock('Symfony\Component\HttpKernel\Controller\ControllerResolverInterface');
82 $this->pluginDiscovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
83 $this->factory = $this->getMock('Drupal\Component\Plugin\Factory\FactoryInterface');
84 $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
85 $this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface');
86 $this->accessManager = $this->getMock('Drupal\Core\Access\AccessManagerInterface');
87 $this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
89 $property = new \ReflectionProperty('Drupal\Core\Menu\ContextualLinkManager', 'controllerResolver');
90 $property->setAccessible(TRUE);
91 $property->setValue($this->contextualLinkManager, $this->controllerResolver);
93 $property = new \ReflectionProperty('Drupal\Core\Menu\ContextualLinkManager', 'discovery');
94 $property->setAccessible(TRUE);
95 $property->setValue($this->contextualLinkManager, $this->pluginDiscovery);
97 $property = new \ReflectionProperty('Drupal\Core\Menu\ContextualLinkManager', 'factory');
98 $property->setAccessible(TRUE);
99 $property->setValue($this->contextualLinkManager, $this->factory);
101 $property = new \ReflectionProperty('Drupal\Core\Menu\ContextualLinkManager', 'account');
102 $property->setAccessible(TRUE);
103 $property->setValue($this->contextualLinkManager, $this->account);
105 $property = new \ReflectionProperty('Drupal\Core\Menu\ContextualLinkManager', 'accessManager');
106 $property->setAccessible(TRUE);
107 $property->setValue($this->contextualLinkManager, $this->accessManager);
109 $property = new \ReflectionProperty('Drupal\Core\Menu\ContextualLinkManager', 'moduleHandler');
110 $property->setAccessible(TRUE);
111 $property->setValue($this->contextualLinkManager, $this->moduleHandler);
113 $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
114 $language_manager->expects($this->any())
115 ->method('getCurrentLanguage')
116 ->will($this->returnValue(new Language(['id' => 'en'])));
118 $request_stack = new RequestStack();
119 $property = new \ReflectionProperty('Drupal\Core\Menu\ContextualLinkManager', 'requestStack');
120 $property->setAccessible(TRUE);
121 $property->setValue($this->contextualLinkManager, $request_stack);
123 $method = new \ReflectionMethod('Drupal\Core\Menu\ContextualLinkManager', 'alterInfo');
124 $method->setAccessible(TRUE);
125 $method->invoke($this->contextualLinkManager, 'contextual_links_plugins');
127 $this->contextualLinkManager->setCacheBackend($this->cacheBackend, 'contextual_links_plugins:en');
131 * Tests the getContextualLinkPluginsByGroup method.
133 * @see \Drupal\Core\Menu\ContextualLinkManager::getContextualLinkPluginsByGroup()
135 public function testGetContextualLinkPluginsByGroup() {
138 'id' => 'test_plugin1',
139 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
141 'route_name' => 'test_route',
144 'id' => 'test_plugin2',
145 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
147 'route_name' => 'test_route2',
150 'id' => 'test_plugin3',
151 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
153 'route_name' => 'test_router3',
156 $this->pluginDiscovery->expects($this->once())
157 ->method('getDefinitions')
158 ->will($this->returnValue($definitions));
160 // Test with a non existing group.
161 $result = $this->contextualLinkManager->getContextualLinkPluginsByGroup('group_non_existing');
162 $this->assertEmpty($result);
164 $result = $this->contextualLinkManager->getContextualLinkPluginsByGroup('group1');
165 $this->assertEquals(['test_plugin1', 'test_plugin2'], array_keys($result));
167 $result = $this->contextualLinkManager->getContextualLinkPluginsByGroup('group2');
168 $this->assertEquals(['test_plugin3'], array_keys($result));
172 * Tests the getContextualLinkPluginsByGroup method with a prefilled cache.
174 public function testGetContextualLinkPluginsByGroupWithCache() {
177 'id' => 'test_plugin1',
178 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
180 'route_name' => 'test_route',
183 'id' => 'test_plugin2',
184 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
186 'route_name' => 'test_route2',
190 $this->cacheBackend->expects($this->once())
192 ->with('contextual_links_plugins:en:group1')
193 ->will($this->returnValue((object) ['data' => $definitions]));
195 $result = $this->contextualLinkManager->getContextualLinkPluginsByGroup('group1');
196 $this->assertEquals($definitions, $result);
198 // Ensure that the static cache works, so no second cache get is executed.
200 $result = $this->contextualLinkManager->getContextualLinkPluginsByGroup('group1');
201 $this->assertEquals($definitions, $result);
205 * Tests processDefinition() by passing a plugin definition without a route.
207 * @see \Drupal\Core\Menu\ContextualLinkManager::processDefinition()
209 public function testProcessDefinitionWithoutRoute() {
211 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
212 'group' => 'example',
213 'id' => 'test_plugin',
215 $this->setExpectedException(PluginException::class);
216 $this->contextualLinkManager->processDefinition($definition, 'test_plugin');
220 * Tests processDefinition() by passing a plugin definition without a group.
222 * @see \Drupal\Core\Menu\ContextualLinkManager::processDefinition()
224 public function testProcessDefinitionWithoutGroup() {
226 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
227 'route_name' => 'example',
228 'id' => 'test_plugin',
230 $this->setExpectedException(PluginException::class);
231 $this->contextualLinkManager->processDefinition($definition, 'test_plugin');
235 * Tests the getContextualLinksArrayByGroup method.
237 * @see \Drupal\Core\Menu\ContextualLinkManager::getContextualLinksArrayByGroup()
239 public function testGetContextualLinksArrayByGroup() {
242 'id' => 'test_plugin1',
243 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
244 'title' => 'Plugin 1',
247 'route_name' => 'test_route',
251 'id' => 'test_plugin2',
252 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
253 'title' => 'Plugin 2',
256 'route_name' => 'test_route2',
257 'options' => ['key' => 'value'],
260 'id' => 'test_plugin3',
261 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
262 'title' => 'Plugin 3',
265 'route_name' => 'test_router3',
270 $this->pluginDiscovery->expects($this->once())
271 ->method('getDefinitions')
272 ->will($this->returnValue($definitions));
274 $this->accessManager->expects($this->any())
275 ->method('checkNamedRoute')
276 ->will($this->returnValue(AccessResult::allowed()));
278 // Set up mocking of the plugin factory.
280 foreach ($definitions as $plugin_id => $definition) {
281 $plugin = $this->getMock('Drupal\Core\Menu\ContextualLinkInterface');
282 $plugin->expects($this->any())
283 ->method('getRouteName')
284 ->will($this->returnValue($definition['route_name']));
285 $plugin->expects($this->any())
287 ->will($this->returnValue($definition['title']));
288 $plugin->expects($this->any())
289 ->method('getWeight')
290 ->will($this->returnValue($definition['weight']));
291 $plugin->expects($this->any())
292 ->method('getOptions')
293 ->will($this->returnValue($definition['options']));
294 $map[] = [$plugin_id, [], $plugin];
296 $this->factory->expects($this->any())
297 ->method('createInstance')
298 ->will($this->returnValueMap($map));
300 $this->moduleHandler->expects($this->at(1))
302 ->with($this->equalTo('contextual_links'), new \PHPUnit_Framework_Constraint_Count(2), $this->equalTo('group1'), $this->equalTo(['key' => 'value']));
304 $result = $this->contextualLinkManager->getContextualLinksArrayByGroup('group1', ['key' => 'value']);
305 $this->assertCount(2, $result);
306 foreach (['test_plugin1', 'test_plugin2'] as $plugin_id) {
307 $definition = $definitions[$plugin_id];
308 $this->assertEquals($definition['weight'], $result[$plugin_id]['weight']);
309 $this->assertEquals($definition['title'], $result[$plugin_id]['title']);
310 $this->assertEquals($definition['route_name'], $result[$plugin_id]['route_name']);
315 * Tests the access checking of the getContextualLinksArrayByGroup method.
317 * @see \Drupal\Core\Menu\ContextualLinkManager::getContextualLinksArrayByGroup()
319 public function testGetContextualLinksArrayByGroupAccessCheck() {
322 'id' => 'test_plugin1',
323 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
324 'title' => 'Plugin 1',
327 'route_name' => 'test_route',
331 'id' => 'test_plugin2',
332 'class' => '\Drupal\Core\Menu\ContextualLinkDefault',
333 'title' => 'Plugin 2',
336 'route_name' => 'test_route2',
337 'options' => ['key' => 'value'],
341 $this->pluginDiscovery->expects($this->once())
342 ->method('getDefinitions')
343 ->will($this->returnValue($definitions));
345 $this->accessManager->expects($this->any())
346 ->method('checkNamedRoute')
347 ->will($this->returnValueMap([
348 ['test_route', ['key' => 'value'], $this->account, FALSE, TRUE],
349 ['test_route2', ['key' => 'value'], $this->account, FALSE, FALSE],
352 // Set up mocking of the plugin factory.
354 foreach ($definitions as $plugin_id => $definition) {
355 $plugin = $this->getMock('Drupal\Core\Menu\ContextualLinkInterface');
356 $plugin->expects($this->any())
357 ->method('getRouteName')
358 ->will($this->returnValue($definition['route_name']));
359 $plugin->expects($this->any())
361 ->will($this->returnValue($definition['title']));
362 $plugin->expects($this->any())
363 ->method('getWeight')
364 ->will($this->returnValue($definition['weight']));
365 $plugin->expects($this->any())
366 ->method('getOptions')
367 ->will($this->returnValue($definition['options']));
368 $map[] = [$plugin_id, [], $plugin];
370 $this->factory->expects($this->any())
371 ->method('createInstance')
372 ->will($this->returnValueMap($map));
374 $result = $this->contextualLinkManager->getContextualLinksArrayByGroup('group1', ['key' => 'value']);
376 // Ensure that access checking was respected.
377 $this->assertTrue(isset($result['test_plugin1']));
378 $this->assertFalse(isset($result['test_plugin2']));
382 * Tests the plugins alter hook.
384 public function testPluginDefinitionAlter() {
385 $definitions['test_plugin'] = [
386 'id' => 'test_plugin',
387 'class' => ContextualLinkDefault::class,
391 'route_name' => 'test_route',
392 'options' => ['key' => 'value'],
395 $this->pluginDiscovery->expects($this->once())
396 ->method('getDefinitions')
397 ->will($this->returnValue($definitions));
399 $this->moduleHandler->expects($this->once())
401 ->with('contextual_links_plugins', $definitions);
403 $this->contextualLinkManager->getDefinition('test_plugin');