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