View source
<?php
namespace Drupal\Tests\Core\Menu;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Cache\Context\CacheContextsManager;
use Drupal\Core\DependencyInjection\Container;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Menu\DefaultMenuLinkTreeManipulators;
use Drupal\Core\Menu\MenuLinkTreeElement;
use Drupal\Tests\UnitTestCase;
use Drupal\node\NodeInterface;
class DefaultMenuLinkTreeManipulatorsTest extends UnitTestCase {
protected $accessManager;
protected $currentUser;
protected $entityTypeManager;
protected $defaultMenuTreeManipulators;
protected $originalTree = [];
protected $links = [];
protected function setUp() {
parent::setUp();
$this->accessManager = $this
->createMock('\\Drupal\\Core\\Access\\AccessManagerInterface');
$this->currentUser = $this
->createMock('Drupal\\Core\\Session\\AccountInterface');
$this->currentUser
->method('isAuthenticated')
->willReturn(TRUE);
$this->entityTypeManager = $this
->createMock(EntityTypeManagerInterface::class);
$this->defaultMenuTreeManipulators = new DefaultMenuLinkTreeManipulators($this->accessManager, $this->currentUser, $this->entityTypeManager);
$cache_contexts_manager = $this
->prophesize(CacheContextsManager::class);
$cache_contexts_manager
->assertValidTokens()
->willReturn(TRUE);
$cache_contexts_manager
->reveal();
$container = new Container();
$container
->set('cache_contexts_manager', $cache_contexts_manager);
\Drupal::setContainer($container);
}
protected function mockTree() {
$this->links = [
1 => MenuLinkMock::create([
'id' => 'test.example1',
'route_name' => 'example1',
'title' => 'foo',
'parent' => '',
]),
2 => MenuLinkMock::create([
'id' => 'test.example2',
'route_name' => 'example2',
'title' => 'bar',
'parent' => 'test.example1',
'route_parameters' => [
'foo' => 'bar',
],
]),
3 => MenuLinkMock::create([
'id' => 'test.example3',
'route_name' => 'example3',
'title' => 'baz',
'parent' => 'test.example2',
'route_parameters' => [
'baz' => 'qux',
],
]),
4 => MenuLinkMock::create([
'id' => 'test.example4',
'route_name' => 'example4',
'title' => 'qux',
'parent' => 'test.example3',
]),
5 => MenuLinkMock::create([
'id' => 'test.example5',
'route_name' => 'example5',
'title' => 'foofoo',
'parent' => '',
]),
6 => MenuLinkMock::create([
'id' => 'test.example6',
'route_name' => '',
'url' => 'https://www.drupal.org/',
'title' => 'barbar',
'parent' => '',
]),
7 => MenuLinkMock::create([
'id' => 'test.example7',
'route_name' => 'example7',
'title' => 'bazbaz',
'parent' => '',
]),
8 => MenuLinkMock::create([
'id' => 'test.example8',
'route_name' => 'example8',
'title' => 'quxqux',
'parent' => '',
]),
9 => DynamicMenuLinkMock::create([
'id' => 'test.example9',
'parent' => '',
])
->setCurrentUser($this->currentUser),
];
$this->originalTree = [];
$this->originalTree[1] = new MenuLinkTreeElement($this->links[1], FALSE, 1, FALSE, []);
$this->originalTree[2] = new MenuLinkTreeElement($this->links[2], TRUE, 1, FALSE, [
3 => new MenuLinkTreeElement($this->links[3], TRUE, 2, FALSE, [
4 => new MenuLinkTreeElement($this->links[4], FALSE, 3, FALSE, []),
]),
]);
$this->originalTree[5] = new MenuLinkTreeElement($this->links[5], TRUE, 1, FALSE, [
7 => new MenuLinkTreeElement($this->links[7], FALSE, 2, FALSE, []),
]);
$this->originalTree[6] = new MenuLinkTreeElement($this->links[6], FALSE, 1, FALSE, []);
$this->originalTree[8] = new MenuLinkTreeElement($this->links[8], FALSE, 1, FALSE, []);
$this->originalTree[9] = new MenuLinkTreeElement($this->links[9], FALSE, 1, FALSE, []);
}
public function testGenerateIndexAndSort() {
$this
->mockTree();
$tree = $this->originalTree;
$tree = $this->defaultMenuTreeManipulators
->generateIndexAndSort($tree);
$this
->assertEquals($this->links[1]
->getPluginId(), $tree['50000 foo test.example1']->link
->getPluginId());
$this
->assertEquals($this->links[2]
->getPluginId(), $tree['50000 bar test.example2']->link
->getPluginId());
$this
->assertEquals($this->links[5]
->getPluginId(), $tree['50000 foofoo test.example5']->link
->getPluginId());
$this
->assertEquals($this->links[6]
->getPluginId(), $tree['50000 barbar test.example6']->link
->getPluginId());
$this
->assertEquals($this->links[8]
->getPluginId(), $tree['50000 quxqux test.example8']->link
->getPluginId());
$this
->assertEquals($this->links[4]
->getPluginId(), $tree['50000 bar test.example2']->subtree['50000 baz test.example3']->subtree['50000 qux test.example4']->link
->getPluginId());
$this
->assertEquals($this->links[7]
->getPluginId(), $tree['50000 foofoo test.example5']->subtree['50000 bazbaz test.example7']->link
->getPluginId());
}
public function testCheckAccess() {
$this->accessManager
->expects($this
->exactly(5))
->method('checkNamedRoute')
->will($this
->returnValueMap([
[
'example1',
[],
$this->currentUser,
TRUE,
AccessResult::forbidden(),
],
[
'example2',
[
'foo' => 'bar',
],
$this->currentUser,
TRUE,
AccessResult::allowed()
->cachePerPermissions(),
],
[
'example3',
[
'baz' => 'qux',
],
$this->currentUser,
TRUE,
AccessResult::neutral(),
],
[
'example5',
[],
$this->currentUser,
TRUE,
AccessResult::allowed(),
],
[
'user.logout',
[],
$this->currentUser,
TRUE,
AccessResult::allowed(),
],
]));
$this
->mockTree();
$this->originalTree[5]->subtree[7]->access = AccessResult::neutral();
$this->originalTree[8]->access = AccessResult::allowed()
->cachePerUser();
$tree = $this->defaultMenuTreeManipulators
->checkAccess($this->originalTree);
$element = $tree[1];
$this
->assertEquals(AccessResult::forbidden()
->cachePerPermissions(), $element->access);
$this
->assertInstanceOf('\\Drupal\\Core\\Menu\\InaccessibleMenuLink', $element->link);
$element = $tree[2];
$this
->assertEquals(AccessResult::allowed()
->cachePerPermissions(), $element->access);
$this
->assertNotInstanceOf('\\Drupal\\Core\\Menu\\InaccessibleMenuLink', $element->link);
$element = $tree[2]->subtree[3];
$this
->assertEquals(AccessResult::neutral()
->cachePerPermissions(), $element->access);
$this
->assertInstanceOf('\\Drupal\\Core\\Menu\\InaccessibleMenuLink', $element->link);
$this
->assertArrayNotHasKey(4, $tree[2]->subtree[3]->subtree);
$element = $tree[5];
$this
->assertEquals(AccessResult::allowed()
->cachePerPermissions(), $element->access);
$this
->assertNotInstanceOf('\\Drupal\\Core\\Menu\\InaccessibleMenuLink', $element->link);
$element = $tree[6];
$this
->assertEquals(AccessResult::allowed()
->cachePerPermissions(), $element->access);
$this
->assertNotInstanceOf('\\Drupal\\Core\\Menu\\InaccessibleMenuLink', $element->link);
$element = $tree[5]->subtree[7];
$this
->assertEquals(AccessResult::neutral(), $element->access);
$this
->assertInstanceOf('\\Drupal\\Core\\Menu\\InaccessibleMenuLink', $element->link);
$element = $tree[8];
$this
->assertEquals(AccessResult::allowed()
->cachePerUser(), $element->access);
$this
->assertNotInstanceOf('\\Drupal\\Core\\Menu\\InaccessibleMenuLink', $element->link);
}
public function testCheckAccessWithLinkToAnyPagePermission() {
$this
->mockTree();
$this->currentUser
->expects($this
->exactly(9))
->method('hasPermission')
->with('link to any page')
->willReturn(TRUE);
$this
->mockTree();
$this->defaultMenuTreeManipulators
->checkAccess($this->originalTree);
$expected_access_result = AccessResult::allowed()
->cachePerPermissions();
$this
->assertEquals($expected_access_result, $this->originalTree[1]->access);
$this
->assertEquals($expected_access_result, $this->originalTree[2]->access);
$this
->assertEquals($expected_access_result, $this->originalTree[2]->subtree[3]->access);
$this
->assertEquals($expected_access_result, $this->originalTree[2]->subtree[3]->subtree[4]->access);
$this
->assertEquals($expected_access_result, $this->originalTree[5]->subtree[7]->access);
$this
->assertEquals($expected_access_result, $this->originalTree[6]->access);
$this
->assertEquals($expected_access_result, $this->originalTree[8]->access);
$this
->assertEquals($expected_access_result, $this->originalTree[9]->access);
}
public function testFlatten() {
$this
->mockTree();
$tree = $this->defaultMenuTreeManipulators
->flatten($this->originalTree);
$this
->assertEquals([
1,
2,
5,
6,
8,
9,
], array_keys($this->originalTree));
$this
->assertEquals([
1,
2,
5,
6,
8,
9,
3,
4,
7,
], array_keys($tree));
}
public function testCheckNodeAccess() {
$links = [
1 => MenuLinkMock::create([
'id' => 'node.1',
'route_name' => 'entity.node.canonical',
'title' => 'foo',
'parent' => '',
'route_parameters' => [
'node' => 1,
],
]),
2 => MenuLinkMock::create([
'id' => 'node.2',
'route_name' => 'entity.node.canonical',
'title' => 'bar',
'parent' => '',
'route_parameters' => [
'node' => 2,
],
]),
3 => MenuLinkMock::create([
'id' => 'node.3',
'route_name' => 'entity.node.canonical',
'title' => 'baz',
'parent' => 'node.2',
'route_parameters' => [
'node' => 3,
],
]),
4 => MenuLinkMock::create([
'id' => 'node.4',
'route_name' => 'entity.node.canonical',
'title' => 'qux',
'parent' => 'node.3',
'route_parameters' => [
'node' => 4,
],
]),
5 => MenuLinkMock::create([
'id' => 'test.1',
'route_name' => 'test_route',
'title' => 'qux',
'parent' => '',
]),
6 => MenuLinkMock::create([
'id' => 'test.2',
'route_name' => 'test_route',
'title' => 'qux',
'parent' => 'test.1',
]),
];
$tree = [];
$tree[1] = new MenuLinkTreeElement($links[1], FALSE, 1, FALSE, []);
$tree[2] = new MenuLinkTreeElement($links[2], TRUE, 1, FALSE, [
3 => new MenuLinkTreeElement($links[3], TRUE, 2, FALSE, [
4 => new MenuLinkTreeElement($links[4], FALSE, 3, FALSE, []),
]),
]);
$tree[5] = new MenuLinkTreeElement($links[5], TRUE, 1, FALSE, [
6 => new MenuLinkTreeElement($links[6], FALSE, 2, FALSE, []),
]);
$query = $this
->createMock('Drupal\\Core\\Entity\\Query\\QueryInterface');
$query
->expects($this
->at(0))
->method('condition')
->with('nid', [
1,
2,
3,
4,
]);
$query
->expects($this
->at(1))
->method('condition')
->with('status', NodeInterface::PUBLISHED);
$query
->expects($this
->once())
->method('execute')
->willReturn([
1,
2,
4,
]);
$storage = $this
->createMock(EntityStorageInterface::class);
$storage
->expects($this
->once())
->method('getQuery')
->willReturn($query);
$this->entityTypeManager
->expects($this
->once())
->method('getStorage')
->with('node')
->willReturn($storage);
$node_access_result = AccessResult::allowed()
->cachePerPermissions()
->addCacheContexts([
'user.node_grants:view',
]);
$tree = $this->defaultMenuTreeManipulators
->checkNodeAccess($tree);
$this
->assertEquals($node_access_result, $tree[1]->access);
$this
->assertEquals($node_access_result, $tree[2]->access);
$this
->assertEquals(AccessResult::neutral(), $tree[2]->subtree[3]->access);
$this
->assertEquals($node_access_result, $tree[2]->subtree[3]->subtree[4]->access);
$this
->assertNull($tree[5]->access);
$this
->assertNull($tree[5]->subtree[6]->access);
$this->accessManager
->expects($this
->at(0))
->method('checkNamedRoute')
->with('test_route', [], $this->currentUser, TRUE)
->willReturn(AccessResult::allowed());
$this->accessManager
->expects($this
->at(1))
->method('checkNamedRoute')
->with('test_route', [], $this->currentUser, TRUE)
->willReturn(AccessResult::neutral());
$tree = $this->defaultMenuTreeManipulators
->checkAccess($tree);
$this
->assertEquals($node_access_result, $tree[1]->access);
$this
->assertEquals($node_access_result, $tree[2]->access);
$this
->assertEquals(AccessResult::neutral(), $tree[2]->subtree[3]->access);
$this
->assertEquals(AccessResult::allowed()
->cachePerPermissions(), $tree[5]->access);
$this
->assertEquals(AccessResult::neutral()
->cachePerPermissions(), $tree[5]->subtree[6]->access);
}
}