3 namespace Drupal\Tests\content_moderation\Unit;
5 use Drupal\block_content\Entity\BlockContent;
6 use Drupal\Core\Access\AccessResultAllowed;
7 use Drupal\Core\Access\AccessResultForbidden;
8 use Drupal\Core\Access\AccessResultNeutral;
9 use Drupal\Core\Cache\Context\CacheContextsManager;
10 use Drupal\Core\Routing\RouteMatch;
11 use Drupal\Core\Session\AccountInterface;
12 use Drupal\node\Entity\Node;
13 use Drupal\content_moderation\Access\LatestRevisionCheck;
14 use Drupal\content_moderation\ModerationInformation;
15 use Drupal\user\EntityOwnerInterface;
16 use Prophecy\Argument;
17 use Symfony\Component\DependencyInjection\ContainerBuilder;
18 use Symfony\Component\Routing\Route;
21 * @coversDefaultClass \Drupal\content_moderation\Access\LatestRevisionCheck
22 * @group content_moderation
24 class LatestRevisionCheckTest extends \PHPUnit_Framework_TestCase {
29 protected function setUp() {
32 // Initialize Drupal container since the cache context manager is needed.
33 $contexts_manager = $this->prophesize(CacheContextsManager::class);
34 $contexts_manager->assertValidTokens(Argument::any())->willReturn(TRUE);
35 $builder = new ContainerBuilder();
36 $builder->set('cache_contexts_manager', $contexts_manager->reveal());
37 \Drupal::setContainer($builder);
41 * Test the access check of the LatestRevisionCheck service.
43 * @param string $entity_class
44 * The class of the entity to mock.
45 * @param string $entity_type
46 * The machine name of the entity to mock.
47 * @param bool $has_forward
48 * Whether this entity should have a forward revision in the system.
49 * @param array $account_permissions
50 * An array of permissions the account has.
51 * @param bool $is_owner
52 * Indicates if the user should be the owner of the entity.
53 * @param string $result_class
54 * The AccessResult class that should result. One of AccessResultAllowed,
55 * AccessResultForbidden, AccessResultNeutral.
57 * @dataProvider accessSituationProvider
59 public function testLatestAccessPermissions($entity_class, $entity_type, $has_forward, array $account_permissions, $is_owner, $result_class) {
61 /** @var \Drupal\Core\Session\AccountInterface $account */
62 $account = $this->prophesize(AccountInterface::class);
63 $possible_permissions = [
64 'view latest version',
65 'view any unpublished content',
66 'view own unpublished content',
68 foreach ($possible_permissions as $permission) {
69 $account->hasPermission($permission)->willReturn(in_array($permission, $account_permissions));
71 $account->id()->willReturn(42);
73 /** @var \Drupal\Core\Entity\EntityInterface $entity */
74 $entity = $this->prophesize($entity_class);
75 $entity->getCacheContexts()->willReturn([]);
76 $entity->getCacheTags()->willReturn([]);
77 $entity->getCacheMaxAge()->willReturn(0);
78 if (is_subclass_of($entity_class, EntityOwnerInterface::class)) {
79 $entity->getOwnerId()->willReturn($is_owner ? 42 : 3);
82 /** @var \Drupal\content_moderation\ModerationInformation $mod_info */
83 $mod_info = $this->prophesize(ModerationInformation::class);
84 $mod_info->hasForwardRevision($entity->reveal())->willReturn($has_forward);
86 $route = $this->prophesize(Route::class);
88 $route->getOption('_content_moderation_entity_type')->willReturn($entity_type);
90 $route_match = $this->prophesize(RouteMatch::class);
91 $route_match->getParameter($entity_type)->willReturn($entity->reveal());
93 $lrc = new LatestRevisionCheck($mod_info->reveal());
95 /** @var \Drupal\Core\Access\AccessResult $result */
96 $result = $lrc->access($route->reveal(), $route_match->reveal(), $account->reveal());
98 $this->assertInstanceOf($result_class, $result);
103 * Data provider for testLastAccessPermissions().
105 public function accessSituationProvider() {
107 // Node with global permissions and latest version.
108 [Node::class, 'node', TRUE, ['view latest version', 'view any unpublished content'], FALSE, AccessResultAllowed::class],
109 // Node with global permissions and no latest version.
110 [Node::class, 'node', FALSE, ['view latest version', 'view any unpublished content'], FALSE, AccessResultForbidden::class],
111 // Node with own content permissions and latest version.
112 [Node::class, 'node', TRUE, ['view latest version', 'view own unpublished content'], TRUE, AccessResultAllowed::class],
113 // Node with own content permissions and no latest version.
114 [Node::class, 'node', FALSE, ['view latest version', 'view own unpublished content'], FALSE, AccessResultForbidden::class],
115 // Node with own content permissions and latest version, but no perms to
116 // view latest version.
117 [Node::class, 'node', TRUE, ['view own unpublished content'], TRUE, AccessResultNeutral::class],
118 // Node with own content permissions and no latest version, but no perms
119 // to view latest version.
120 [Node::class, 'node', TRUE, ['view own unpublished content'], FALSE, AccessResultNeutral::class],
121 // Block with forward revision, and permissions to view any.
122 [BlockContent::class, 'block_content', TRUE, ['view latest version', 'view any unpublished content'], FALSE, AccessResultAllowed::class],
123 // Block with no forward revision.
124 [BlockContent::class, 'block_content', FALSE, ['view latest version', 'view any unpublished content'], FALSE, AccessResultForbidden::class],
125 // Block with forward revision, but no permission to view any.
126 [BlockContent::class, 'block_content', TRUE, ['view latest version', 'view own unpublished content'], FALSE, AccessResultNeutral::class],
127 // Block with no forward revision.
128 [BlockContent::class, 'block_content', FALSE, ['view latest version', 'view own unpublished content'], FALSE, AccessResultForbidden::class],