commentManager = $this->getMock('\Drupal\comment\CommentManagerInterface'); $this->stringTranslation = $this->getStringTranslationStub(); $this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface'); $this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface'); $this->currentUser = $this->getMock('\Drupal\Core\Session\AccountProxyInterface'); $this->commentLinkBuilder = new CommentLinkBuilder($this->currentUser, $this->commentManager, $this->moduleHandler, $this->stringTranslation, $this->entityManager); $this->commentManager->expects($this->any()) ->method('getFields') ->with('node') ->willReturn([ 'comment' => [], ]); $this->commentManager->expects($this->any()) ->method('forbiddenMessage') ->willReturn("Can't let you do that Dave."); $this->stringTranslation->expects($this->any()) ->method('formatPlural') ->willReturnArgument(1); } /** * Test the buildCommentedEntityLinks method. * * @param \Drupal\node\NodeInterface|\PHPUnit_Framework_MockObject_MockObject $node * Mock node. * @param array $context * Context for the links. * @param bool $has_access_comments * TRUE if the user has 'access comments' permission. * @param bool $history_exists * TRUE if the history module exists. * @param bool $has_post_comments * TRUE if the use has 'post comments' permission. * @param bool $is_anonymous * TRUE if the user is anonymous. * @param array $expected * Array of expected links keyed by link ID. Can be either string (link * title) or array of link properties. * * @dataProvider getLinkCombinations * * @covers ::buildCommentedEntityLinks */ public function testCommentLinkBuilder(NodeInterface $node, $context, $has_access_comments, $history_exists, $has_post_comments, $is_anonymous, $expected) { $this->moduleHandler->expects($this->any()) ->method('moduleExists') ->with('history') ->willReturn($history_exists); $this->currentUser->expects($this->any()) ->method('hasPermission') ->willReturnMap([ ['access comments', $has_access_comments], ['post comments', $has_post_comments], ]); $this->currentUser->expects($this->any()) ->method('isAuthenticated') ->willReturn(!$is_anonymous); $this->currentUser->expects($this->any()) ->method('isAnonymous') ->willReturn($is_anonymous); $links = $this->commentLinkBuilder->buildCommentedEntityLinks($node, $context); if (!empty($expected)) { if (!empty($links)) { foreach ($expected as $link => $detail) { if (is_array($detail)) { // Array of link attributes. foreach ($detail as $key => $value) { $this->assertEquals($value, $links['comment__comment']['#links'][$link][$key]); } } else { // Just the title. $this->assertEquals($detail, $links['comment__comment']['#links'][$link]['title']); } } } else { $this->fail('Expected links but found none.'); } } else { $this->assertSame($links, $expected); } } /** * Data provider for ::testCommentLinkBuilder. */ public function getLinkCombinations() { $cases = []; // No links should be created if the entity doesn't have the field. $cases[] = [ $this->getMockNode(FALSE, CommentItemInterface::OPEN, CommentItemInterface::FORM_BELOW, 1), ['view_mode' => 'teaser'], TRUE, TRUE, TRUE, TRUE, [], ]; foreach (['search_result', 'search_index', 'print'] as $view_mode) { // Nothing should be output in these view modes. $cases[] = [ $this->getMockNode(TRUE, CommentItemInterface::OPEN, CommentItemInterface::FORM_BELOW, 1), ['view_mode' => $view_mode], TRUE, TRUE, TRUE, TRUE, [], ]; } // All other combinations. $combinations = [ 'is_anonymous' => [FALSE, TRUE], 'comment_count' => [0, 1], 'has_access_comments' => [0, 1], 'history_exists' => [FALSE, TRUE], 'has_post_comments' => [0, 1], 'form_location' => [CommentItemInterface::FORM_BELOW, CommentItemInterface::FORM_SEPARATE_PAGE], 'comments' => [ CommentItemInterface::OPEN, CommentItemInterface::CLOSED, CommentItemInterface::HIDDEN, ], 'view_mode' => [ 'teaser', 'rss', 'full', ], ]; $permutations = $this->generatePermutations($combinations); foreach ($permutations as $combination) { $case = [ $this->getMockNode(TRUE, $combination['comments'], $combination['form_location'], $combination['comment_count']), ['view_mode' => $combination['view_mode']], $combination['has_access_comments'], $combination['history_exists'], $combination['has_post_comments'], $combination['is_anonymous'], ]; $expected = []; // When comments are enabled in teaser mode, and comments exist, and the // user has access - we can output the comment count. if ($combination['comments'] && $combination['view_mode'] == 'teaser' && $combination['comment_count'] && $combination['has_access_comments']) { $expected['comment-comments'] = '1 comment'; // And if history module exists, we can show a 'new comments' link. if ($combination['history_exists']) { $expected['comment-new-comments'] = ''; } } // All view modes other than RSS. if ($combination['view_mode'] != 'rss') { // Where commenting is open. if ($combination['comments'] == CommentItemInterface::OPEN) { // And the user has post-comments permission. if ($combination['has_post_comments']) { // If the view mode is teaser, or the user can access comments and // comments exist or the form is on a separate page. if ($combination['view_mode'] == 'teaser' || ($combination['has_access_comments'] && $combination['comment_count']) || $combination['form_location'] == CommentItemInterface::FORM_SEPARATE_PAGE) { // There should be a add comment link. $expected['comment-add'] = ['title' => 'Add new comment']; if ($combination['form_location'] == CommentItemInterface::FORM_BELOW) { // On the same page. $expected['comment-add']['url'] = Url::fromRoute('node.view'); } else { // On a separate page. $expected['comment-add']['url'] = Url::fromRoute('comment.reply', ['entity_type' => 'node', 'entity' => 1, 'field_name' => 'comment']); } } } elseif ($combination['is_anonymous']) { // Anonymous users get the forbidden message if the can't post // comments. $expected['comment-forbidden'] = "Can't let you do that Dave."; } } } $case[] = $expected; $cases[] = $case; } return $cases; } /** * Builds a mock node based on given scenario. * * @param bool $has_field * TRUE if the node has the 'comment' field. * @param int $comment_status * One of CommentItemInterface::OPEN|HIDDEN|CLOSED * @param int $form_location * One of CommentItemInterface::FORM_BELOW|FORM_SEPARATE_PAGE * @param int $comment_count * Number of comments against the field. * * @return \Drupal\node\NodeInterface|\PHPUnit_Framework_MockObject_MockObject * Mock node for testing. */ protected function getMockNode($has_field, $comment_status, $form_location, $comment_count) { $node = $this->getMock('\Drupal\node\NodeInterface'); $node->expects($this->once()) ->method('hasField') ->willReturn($has_field); if (empty($this->timestamp)) { $this->timestamp = time(); } $field_item = (object) [ 'status' => $comment_status, 'comment_count' => $comment_count, 'last_comment_timestamp' => $this->timestamp, ]; $node->expects($this->any()) ->method('get') ->with('comment') ->willReturn($field_item); $field_definition = $this->getMock('\Drupal\Core\Field\FieldDefinitionInterface'); $field_definition->expects($this->any()) ->method('getSetting') ->with('form_location') ->willReturn($form_location); $node->expects($this->any()) ->method('getFieldDefinition') ->with('comment') ->willReturn($field_definition); $node->expects($this->any()) ->method('language') ->willReturn('und'); $node->expects($this->any()) ->method('getEntityTypeId') ->willReturn('node'); $node->expects($this->any()) ->method('id') ->willReturn(1); $url = Url::fromRoute('node.view'); $node->expects($this->any()) ->method('urlInfo') ->willReturn($url); $node->expects($this->any()) ->method('url') ->willReturn(['route_name' => 'node.view']); return $node; } } namespace Drupal\comment; if (!function_exists('history_read')) { function history_read() { return 0; } }