Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Menu / LocalActionManagerTest.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\Tests\Core\Menu\LocalActionManagerTest.
6  */
7
8 namespace Drupal\Tests\Core\Menu;
9
10 use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
11 use Drupal\Component\Plugin\Factory\FactoryInterface;
12 use Drupal\Core\Access\AccessManagerInterface;
13 use Drupal\Core\Access\AccessResult;
14 use Drupal\Core\Access\AccessResultForbidden;
15 use Drupal\Core\Cache\CacheBackendInterface;
16 use Drupal\Core\Cache\Context\CacheContextsManager;
17 use Drupal\Core\Controller\ControllerResolver;
18 use Drupal\Core\DependencyInjection\Container;
19 use Drupal\Core\Extension\ModuleHandlerInterface;
20 use Drupal\Core\Language\Language;
21 use Drupal\Core\Menu\LocalActionManager;
22 use Drupal\Core\Menu\LocalTaskManager;
23 use Drupal\Core\Routing\RouteMatchInterface;
24 use Drupal\Core\Routing\RouteProviderInterface;
25 use Drupal\Core\Session\AccountInterface;
26 use Drupal\Core\Url;
27 use Drupal\Tests\UnitTestCase;
28 use Prophecy\Argument;
29 use Symfony\Component\HttpFoundation\Request;
30 use Symfony\Component\HttpFoundation\RequestStack;
31 use Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface;
32
33 /**
34  * @coversDefaultClass \Drupal\Core\Menu\LocalActionManager
35  * @group Menu
36  */
37 class LocalActionManagerTest extends UnitTestCase {
38
39   /**
40    * The mocked argument resolver.
41    *
42    * @var \Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface|\PHPUnit_Framework_MockObject_MockObject
43    */
44   protected $argumentResolver;
45
46   /**
47    * The mocked request.
48    *
49    * @var \Symfony\Component\HttpFoundation\Request|\PHPUnit_Framework_MockObject_MockObject
50    */
51   protected $request;
52
53   /**
54    * The mocked module handler.
55    *
56    * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
57    */
58   protected $moduleHandler;
59
60   /**
61    * The mocked router provider.
62    *
63    * @var \Drupal\Core\Routing\RouteProviderInterface|\PHPUnit_Framework_MockObject_MockObject
64    */
65   protected $routeProvider;
66
67   /**
68    * The mocked cache backend.
69    *
70    * @var \Drupal\Core\Cache\CacheBackendInterface|\PHPUnit_Framework_MockObject_MockObject
71    */
72   protected $cacheBackend;
73
74   /**
75    * The mocked access manager.
76    *
77    * @var \Drupal\Core\Access\AccessManagerInterface|\PHPUnit_Framework_MockObject_MockObject
78    */
79   protected $accessManager;
80
81   /**
82    * The mocked account.
83    *
84    * @var \Drupal\Core\Session\AccountInterface|\PHPUnit_Framework_MockObject_MockObject
85    */
86   protected $account;
87
88   /**
89    * The mocked factory.
90    *
91    * @var \Drupal\Component\Plugin\Factory\FactoryInterface|\PHPUnit_Framework_MockObject_MockObject
92    */
93   protected $factory;
94
95   /**
96    * The mocked plugin discovery.
97    *
98    * @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface|\PHPUnit_Framework_MockObject_MockObject
99    */
100   protected $discovery;
101
102   /**
103    * The tested local action manager
104    *
105    * @var \Drupal\Tests\Core\Menu\TestLocalActionManager
106    */
107   protected $localActionManager;
108
109   /**
110    * {@inheritdoc}
111    */
112   protected function setUp() {
113     $this->argumentResolver = $this->getMock('\Symfony\Component\HttpKernel\Controller\ArgumentResolverInterface');
114     $this->request = $this->getMock('Symfony\Component\HttpFoundation\Request');
115     $this->routeProvider = $this->getMock('Drupal\Core\Routing\RouteProviderInterface');
116     $this->moduleHandler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
117     $this->cacheBackend = $this->getMock('Drupal\Core\Cache\CacheBackendInterface');
118
119     $cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
120     $cache_contexts_manager->assertValidTokens(Argument::any())
121       ->willReturn(TRUE);
122
123     $container = new Container();
124     $container->set('cache_contexts_manager', $cache_contexts_manager->reveal());
125     \Drupal::setContainer($container);
126
127     $access_result = (new AccessResultForbidden())->cachePerPermissions();
128     $this->accessManager = $this->getMock('Drupal\Core\Access\AccessManagerInterface');
129     $this->accessManager->expects($this->any())
130       ->method('checkNamedRoute')
131       ->willReturn($access_result);
132     $this->account = $this->getMock('Drupal\Core\Session\AccountInterface');
133     $this->discovery = $this->getMock('Drupal\Component\Plugin\Discovery\DiscoveryInterface');
134     $this->factory = $this->getMock('Drupal\Component\Plugin\Factory\FactoryInterface');
135     $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
136
137     $this->localActionManager = new TestLocalActionManager($this->argumentResolver, $this->request, $route_match, $this->routeProvider, $this->moduleHandler, $this->cacheBackend, $this->accessManager, $this->account, $this->discovery, $this->factory);
138   }
139
140   /**
141    * @covers ::getTitle
142    */
143   public function testGetTitle() {
144     $local_action = $this->getMock('Drupal\Core\Menu\LocalActionInterface');
145     $local_action->expects($this->once())
146       ->method('getTitle')
147       ->with('test');
148
149     $this->argumentResolver->expects($this->once())
150       ->method('getArguments')
151       ->with($this->request, [$local_action, 'getTitle'])
152       ->will($this->returnValue(['test']));
153
154     $this->localActionManager->getTitle($local_action);
155   }
156
157   /**
158    * @covers ::getActionsForRoute
159    *
160    * @dataProvider getActionsForRouteProvider
161    */
162   public function testGetActionsForRoute($route_appears, array $plugin_definitions, array $expected_actions) {
163     $this->discovery->expects($this->any())
164       ->method('getDefinitions')
165       ->will($this->returnValue($plugin_definitions));
166     $map = [];
167     foreach ($plugin_definitions as $plugin_id => $plugin_definition) {
168       $plugin = $this->getMock('Drupal\Core\Menu\LocalActionInterface');
169       $plugin->expects($this->any())
170         ->method('getRouteName')
171         ->will($this->returnValue($plugin_definition['route_name']));
172       $plugin->expects($this->any())
173         ->method('getRouteParameters')
174         ->will($this->returnValue(isset($plugin_definition['route_parameters']) ? $plugin_definition['route_parameters'] : []));
175       $plugin->expects($this->any())
176         ->method('getTitle')
177         ->will($this->returnValue($plugin_definition['title']));
178       $this->argumentResolver->expects($this->any())
179         ->method('getArguments')
180         ->with($this->request, [$plugin, 'getTitle'])
181         ->will($this->returnValue([]));
182
183       $plugin->expects($this->any())
184         ->method('getWeight')
185         ->will($this->returnValue($plugin_definition['weight']));
186       $this->argumentResolver->expects($this->any())
187         ->method('getArguments')
188         ->with($this->request, [$plugin, 'getTitle'])
189         ->will($this->returnValue([]));
190       $map[] = [$plugin_id, [], $plugin];
191     }
192     $this->factory->expects($this->any())
193       ->method('createInstance')
194       ->will($this->returnValueMap($map));
195
196     $this->assertEquals($expected_actions, $this->localActionManager->getActionsForRoute($route_appears));
197   }
198
199   public function getActionsForRouteProvider() {
200     $cache_contexts_manager = $this->prophesize(CacheContextsManager::class);
201     $cache_contexts_manager->assertValidTokens(Argument::any())
202       ->willReturn(TRUE);
203
204     $container = new Container();
205     $container->set('cache_contexts_manager', $cache_contexts_manager->reveal());
206     \Drupal::setContainer($container);
207
208     // Single available and single expected plugins.
209     $data[] = [
210       'test_route',
211       [
212         'plugin_id_1' => [
213           'appears_on' => [
214             'test_route',
215           ],
216           'route_name' => 'test_route_2',
217           'title' => 'Plugin ID 1',
218           'weight' => 0,
219         ],
220       ],
221       [
222         '#cache' => [
223           'tags' => [],
224           'contexts' => ['route', 'user.permissions'],
225           'max-age' => 0,
226         ],
227         'plugin_id_1' => [
228           '#theme' => 'menu_local_action',
229           '#link' => [
230             'title' => 'Plugin ID 1',
231             'url' => Url::fromRoute('test_route_2'),
232             'localized_options' => '',
233           ],
234           '#access' => AccessResult::forbidden()->cachePerPermissions(),
235           '#weight' => 0,
236         ],
237       ],
238     ];
239     // Multiple available and single expected plugins.
240     $data[] = [
241       'test_route',
242       [
243         'plugin_id_1' => [
244           'appears_on' => [
245             'test_route',
246           ],
247           'route_name' => 'test_route_2',
248           'title' => 'Plugin ID 1',
249           'weight' => 0,
250         ],
251         'plugin_id_2' => [
252           'appears_on' => [
253             'test_route2',
254           ],
255           'route_name' => 'test_route_3',
256           'title' => 'Plugin ID 2',
257           'weight' => 0,
258         ],
259       ],
260       [
261         '#cache' => [
262           'tags' => [],
263           'contexts' => ['route', 'user.permissions'],
264           'max-age' => 0,
265         ],
266         'plugin_id_1' => [
267           '#theme' => 'menu_local_action',
268           '#link' => [
269             'title' => 'Plugin ID 1',
270             'url' => Url::fromRoute('test_route_2'),
271             'localized_options' => '',
272           ],
273           '#access' => AccessResult::forbidden()->cachePerPermissions(),
274           '#weight' => 0,
275         ],
276       ],
277     ];
278
279     // Multiple available and multiple expected plugins and specified weight.
280     $data[] = [
281       'test_route',
282       [
283         'plugin_id_1' => [
284           'appears_on' => [
285             'test_route',
286           ],
287           'route_name' => 'test_route_2',
288           'title' => 'Plugin ID 1',
289           'weight' => 1,
290         ],
291         'plugin_id_2' => [
292           'appears_on' => [
293             'test_route',
294           ],
295           'route_name' => 'test_route_3',
296           'title' => 'Plugin ID 2',
297           'weight' => 0,
298         ],
299       ],
300       [
301         '#cache' => [
302           'contexts' => ['route', 'user.permissions'],
303           'tags' => [],
304           'max-age' => 0,
305         ],
306         'plugin_id_1' => [
307           '#theme' => 'menu_local_action',
308           '#link' => [
309             'title' => 'Plugin ID 1',
310             'url' => Url::fromRoute('test_route_2'),
311             'localized_options' => '',
312           ],
313           '#access' => AccessResult::forbidden()->cachePerPermissions(),
314           '#weight' => 1,
315         ],
316         'plugin_id_2' => [
317           '#theme' => 'menu_local_action',
318           '#link' => [
319             'title' => 'Plugin ID 2',
320             'url' => Url::fromRoute('test_route_3'),
321             'localized_options' => '',
322           ],
323           '#access' => AccessResult::forbidden()->cachePerPermissions(),
324           '#weight' => 0,
325         ],
326       ],
327     ];
328
329     // Two plugins with the same route name but different route parameters.
330     $data[] = [
331       'test_route',
332       [
333         'plugin_id_1' => [
334           'appears_on' => [
335             'test_route',
336           ],
337           'route_name' => 'test_route_2',
338           'route_parameters' => ['test1'],
339           'title' => 'Plugin ID 1',
340           'weight' => 1,
341         ],
342         'plugin_id_2' => [
343           'appears_on' => [
344             'test_route',
345           ],
346           'route_name' => 'test_route_2',
347           'route_parameters' => ['test2'],
348           'title' => 'Plugin ID 2',
349           'weight' => 0,
350         ],
351       ],
352       [
353         '#cache' => [
354           'contexts' => ['route', 'user.permissions'],
355           'tags' => [],
356           'max-age' => 0,
357         ],
358         'plugin_id_1' => [
359           '#theme' => 'menu_local_action',
360           '#link' => [
361             'title' => 'Plugin ID 1',
362             'url' => Url::fromRoute('test_route_2', ['test1']),
363             'localized_options' => '',
364           ],
365           '#access' => AccessResult::forbidden()->cachePerPermissions(),
366           '#weight' => 1,
367         ],
368         'plugin_id_2' => [
369           '#theme' => 'menu_local_action',
370           '#link' => [
371             'title' => 'Plugin ID 2',
372             'url' => Url::fromRoute('test_route_2', ['test2']),
373             'localized_options' => '',
374           ],
375           '#access' => AccessResult::forbidden()->cachePerPermissions(),
376           '#weight' => 0,
377         ],
378       ],
379     ];
380
381     return $data;
382   }
383
384   /**
385    * @expectedDeprecation Using the 'controller_resolver' service as the first argument is deprecated, use the 'http_kernel.controller.argument_resolver' instead. If your subclass requires the 'controller_resolver' service add it as an additional argument. See https://www.drupal.org/node/2959408.
386    * @group legacy
387    */
388   public function testControllerResolverDeprecation() {
389     $controller_resolver = $this->getMockBuilder(ControllerResolver::class)->disableOriginalConstructor()->getMock();
390     $route_match = $this->getMock('Drupal\Core\Routing\RouteMatchInterface');
391     $request_stack = new RequestStack();
392     $request_stack->push($this->request);
393     $module_handler = $this->getMock('Drupal\Core\Extension\ModuleHandlerInterface');
394     $module_handler->expects($this->any())
395       ->method('getModuleDirectories')
396       ->willReturn([]);
397     $language_manager = $this->getMock('Drupal\Core\Language\LanguageManagerInterface');
398     $language_manager->expects($this->any())
399       ->method('getCurrentLanguage')
400       ->will($this->returnValue(new Language(['id' => 'en'])));
401     new LocalTaskManager($controller_resolver, $request_stack, $route_match, $this->routeProvider, $this->moduleHandler, $this->cacheBackend, $language_manager, $this->accessManager, $this->account);
402   }
403
404 }
405
406 class TestLocalActionManager extends LocalActionManager {
407
408   public function __construct(ArgumentResolverInterface $argument_resolver, Request $request, RouteMatchInterface $route_match, RouteProviderInterface $route_provider, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache_backend, AccessManagerInterface $access_manager, AccountInterface $account, DiscoveryInterface $discovery, FactoryInterface $factory) {
409     $this->discovery = $discovery;
410     $this->factory = $factory;
411     $this->routeProvider = $route_provider;
412     $this->accessManager = $access_manager;
413     $this->account = $account;
414     $this->argumentResolver = $argument_resolver;
415     $this->requestStack = new RequestStack();
416     $this->requestStack->push($request);
417     $this->routeMatch = $route_match;
418     $this->moduleHandler = $module_handler;
419     $this->alterInfo('menu_local_actions');
420     $this->setCacheBackend($cache_backend, 'local_action_plugins', ['local_action']);
421   }
422
423 }