3 namespace Drupal\Tests\comment\Unit;
5 use Drupal\comment\CommentLinkBuilder;
6 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
8 use Drupal\node\NodeInterface;
9 use Drupal\Tests\Traits\Core\GeneratePermutationsTrait;
10 use Drupal\Tests\UnitTestCase;
13 * @coversDefaultClass \Drupal\comment\CommentLinkBuilder
16 class CommentLinkBuilderTest extends UnitTestCase {
18 use GeneratePermutationsTrait;
21 * Comment manager mock.
23 * @var \Drupal\comment\CommentManagerInterface|\PHPUnit_Framework_MockObject_MockObject
25 protected $commentManager;
28 * String translation mock.
30 * @var \Drupal\Core\StringTranslation\TranslationInterface|\PHPUnit_Framework_MockObject_MockObject
32 protected $stringTranslation;
35 * The entity manager service.
37 * @var \Drupal\Core\Entity\EntityManagerInterface
39 protected $entityManager;
42 * Module handler mock.
44 * @var \Drupal\Core\Extension\ModuleHandlerInterface|\PHPUnit_Framework_MockObject_MockObject
46 protected $moduleHandler;
49 * Current user proxy mock.
51 * @var \Drupal\Core\Session\AccountProxyInterface|\PHPUnit_Framework_MockObject_MockObject
53 protected $currentUser;
56 * Timestamp used in test.
63 * @var \Drupal\comment\CommentLinkBuilderInterface;
65 protected $commentLinkBuilder;
68 * Prepares mocks for the test.
70 protected function setUp() {
71 $this->commentManager = $this->getMock('\Drupal\comment\CommentManagerInterface');
72 $this->stringTranslation = $this->getStringTranslationStub();
73 $this->entityManager = $this->getMock('\Drupal\Core\Entity\EntityManagerInterface');
74 $this->moduleHandler = $this->getMock('\Drupal\Core\Extension\ModuleHandlerInterface');
75 $this->currentUser = $this->getMock('\Drupal\Core\Session\AccountProxyInterface');
76 $this->commentLinkBuilder = new CommentLinkBuilder($this->currentUser, $this->commentManager, $this->moduleHandler, $this->stringTranslation, $this->entityManager);
77 $this->commentManager->expects($this->any())
83 $this->commentManager->expects($this->any())
84 ->method('forbiddenMessage')
85 ->willReturn("Can't let you do that Dave.");
86 $this->stringTranslation->expects($this->any())
87 ->method('formatPlural')
88 ->willReturnArgument(1);
92 * Test the buildCommentedEntityLinks method.
94 * @param \Drupal\node\NodeInterface|\PHPUnit_Framework_MockObject_MockObject $node
96 * @param array $context
97 * Context for the links.
98 * @param bool $has_access_comments
99 * TRUE if the user has 'access comments' permission.
100 * @param bool $history_exists
101 * TRUE if the history module exists.
102 * @param bool $has_post_comments
103 * TRUE if the use has 'post comments' permission.
104 * @param bool $is_anonymous
105 * TRUE if the user is anonymous.
106 * @param array $expected
107 * Array of expected links keyed by link ID. Can be either string (link
108 * title) or array of link properties.
110 * @dataProvider getLinkCombinations
112 * @covers ::buildCommentedEntityLinks
114 public function testCommentLinkBuilder(NodeInterface $node, $context, $has_access_comments, $history_exists, $has_post_comments, $is_anonymous, $expected) {
115 $this->moduleHandler->expects($this->any())
116 ->method('moduleExists')
118 ->willReturn($history_exists);
119 $this->currentUser->expects($this->any())
120 ->method('hasPermission')
122 ['access comments', $has_access_comments],
123 ['post comments', $has_post_comments],
125 $this->currentUser->expects($this->any())
126 ->method('isAuthenticated')
127 ->willReturn(!$is_anonymous);
128 $this->currentUser->expects($this->any())
129 ->method('isAnonymous')
130 ->willReturn($is_anonymous);
131 $links = $this->commentLinkBuilder->buildCommentedEntityLinks($node, $context);
132 if (!empty($expected)) {
133 if (!empty($links)) {
134 foreach ($expected as $link => $detail) {
135 if (is_array($detail)) {
136 // Array of link attributes.
137 foreach ($detail as $key => $value) {
138 $this->assertEquals($value, $links['comment__comment']['#links'][$link][$key]);
143 $this->assertEquals($detail, $links['comment__comment']['#links'][$link]['title']);
148 $this->fail('Expected links but found none.');
152 $this->assertSame($links, $expected);
157 * Data provider for ::testCommentLinkBuilder.
159 public function getLinkCombinations() {
161 // No links should be created if the entity doesn't have the field.
163 $this->getMockNode(FALSE, CommentItemInterface::OPEN, CommentItemInterface::FORM_BELOW, 1),
164 ['view_mode' => 'teaser'],
171 foreach (['search_result', 'search_index', 'print'] as $view_mode) {
172 // Nothing should be output in these view modes.
174 $this->getMockNode(TRUE, CommentItemInterface::OPEN, CommentItemInterface::FORM_BELOW, 1),
175 ['view_mode' => $view_mode],
183 // All other combinations.
185 'is_anonymous' => [FALSE, TRUE],
186 'comment_count' => [0, 1],
187 'has_access_comments' => [0, 1],
188 'history_exists' => [FALSE, TRUE],
189 'has_post_comments' => [0, 1],
190 'form_location' => [CommentItemInterface::FORM_BELOW, CommentItemInterface::FORM_SEPARATE_PAGE],
192 CommentItemInterface::OPEN,
193 CommentItemInterface::CLOSED,
194 CommentItemInterface::HIDDEN,
197 'teaser', 'rss', 'full',
200 $permutations = $this->generatePermutations($combinations);
201 foreach ($permutations as $combination) {
203 $this->getMockNode(TRUE, $combination['comments'], $combination['form_location'], $combination['comment_count']),
204 ['view_mode' => $combination['view_mode']],
205 $combination['has_access_comments'],
206 $combination['history_exists'],
207 $combination['has_post_comments'],
208 $combination['is_anonymous'],
211 // When comments are enabled in teaser mode, and comments exist, and the
212 // user has access - we can output the comment count.
213 if ($combination['comments'] && $combination['view_mode'] == 'teaser' && $combination['comment_count'] && $combination['has_access_comments']) {
214 $expected['comment-comments'] = '1 comment';
215 // And if history module exists, we can show a 'new comments' link.
216 if ($combination['history_exists']) {
217 $expected['comment-new-comments'] = '';
220 // All view modes other than RSS.
221 if ($combination['view_mode'] != 'rss') {
222 // Where commenting is open.
223 if ($combination['comments'] == CommentItemInterface::OPEN) {
224 // And the user has post-comments permission.
225 if ($combination['has_post_comments']) {
226 // If the view mode is teaser, or the user can access comments and
227 // comments exist or the form is on a separate page.
228 if ($combination['view_mode'] == 'teaser' || ($combination['has_access_comments'] && $combination['comment_count']) || $combination['form_location'] == CommentItemInterface::FORM_SEPARATE_PAGE) {
229 // There should be a add comment link.
230 $expected['comment-add'] = ['title' => 'Add new comment'];
231 if ($combination['form_location'] == CommentItemInterface::FORM_BELOW) {
233 $expected['comment-add']['url'] = Url::fromRoute('node.view');
236 // On a separate page.
237 $expected['comment-add']['url'] = Url::fromRoute('comment.reply', ['entity_type' => 'node', 'entity' => 1, 'field_name' => 'comment']);
241 elseif ($combination['is_anonymous']) {
242 // Anonymous users get the forbidden message if the can't post
244 $expected['comment-forbidden'] = "Can't let you do that Dave.";
256 * Builds a mock node based on given scenario.
258 * @param bool $has_field
259 * TRUE if the node has the 'comment' field.
260 * @param int $comment_status
261 * One of CommentItemInterface::OPEN|HIDDEN|CLOSED
262 * @param int $form_location
263 * One of CommentItemInterface::FORM_BELOW|FORM_SEPARATE_PAGE
264 * @param int $comment_count
265 * Number of comments against the field.
267 * @return \Drupal\node\NodeInterface|\PHPUnit_Framework_MockObject_MockObject
268 * Mock node for testing.
270 protected function getMockNode($has_field, $comment_status, $form_location, $comment_count) {
271 $node = $this->getMock('\Drupal\node\NodeInterface');
272 $node->expects($this->any())
274 ->willReturn($has_field);
276 if (empty($this->timestamp)) {
277 $this->timestamp = time();
279 $field_item = (object) [
280 'status' => $comment_status,
281 'comment_count' => $comment_count,
282 'last_comment_timestamp' => $this->timestamp,
284 $node->expects($this->any())
287 ->willReturn($field_item);
289 $field_definition = $this->getMock('\Drupal\Core\Field\FieldDefinitionInterface');
290 $field_definition->expects($this->any())
291 ->method('getSetting')
292 ->with('form_location')
293 ->willReturn($form_location);
294 $node->expects($this->any())
295 ->method('getFieldDefinition')
297 ->willReturn($field_definition);
299 $node->expects($this->any())
303 $node->expects($this->any())
304 ->method('getEntityTypeId')
305 ->willReturn('node');
307 $node->expects($this->any())
311 $url = Url::fromRoute('node.view');
312 $node->expects($this->any())
315 $node->expects($this->any())
317 ->willReturn(['route_name' => 'node.view']);
324 namespace Drupal\comment;
326 if (!function_exists('history_read')) {
327 function history_read() {