comment.test 93.4 KB
Newer Older
1
2
<?php

3
/**
4
 * @file
5
 * Tests for the Comment module.
6
7
 */

8
class CommentHelperCase extends DrupalWebTestCase {
9
10
11
12
13
  protected $admin_user;
  protected $web_user;
  protected $node;

  function setUp() {
14
    parent::setUp('comment', 'search');
15
16
    // Create users and test node.
    $this->admin_user = $this->drupalCreateUser(array('administer content types', 'administer comments', 'administer blocks'));
17
    $this->web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'create article content', 'edit own comments'));
18
    $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'uid' => $this->web_user->uid));
19
20
  }

21
  /**
22
   * Posts a comment.
23
   *
24
25
26
27
28
29
30
31
32
   * @param $node
   *   Node to post comment on.
   * @param $comment
   *   Comment body.
   * @param $subject
   *   Comment subject.
   * @param $contact
   *   Set to NULL for no contact info, TRUE to ignore success checking, and
   *   array of values to set contact info.
33
   */
34
  function postComment($node, $comment, $subject = '', $contact = NULL) {
35
    $langcode = LANGUAGE_NONE;
36
    $edit = array();
37
    $edit['comment_body[' . $langcode . '][0][value]'] = $comment;
38

39
40
    $preview_mode = variable_get('comment_preview_article', DRUPAL_OPTIONAL);
    $subject_mode = variable_get('comment_subject_field_article', 1);
41

42
    // Must get the page before we test for fields.
43
44
45
46
    if ($node !== NULL) {
      $this->drupalGet('comment/reply/' . $node->nid);
    }

47
48
49
50
    if ($subject_mode == TRUE) {
      $edit['subject'] = $subject;
    }
    else {
51
      $this->assertNoFieldByName('subject', '', t('Subject field not found.'));
52
53
54
55
56
57
58
59
    }

    if ($contact !== NULL && is_array($contact)) {
      $edit += $contact;
    }
    switch ($preview_mode) {
      case DRUPAL_REQUIRED:
        // Preview required so no save button should be found.
60
        $this->assertNoFieldByName('op', t('Save'), t('Save button not found.'));
61
62
63
64
        $this->drupalPost(NULL, $edit, t('Preview'));
        // Don't break here so that we can test post-preview field presence and
        // function below.
      case DRUPAL_OPTIONAL:
65
66
        $this->assertFieldByName('op', t('Preview'), t('Preview button found.'));
        $this->assertFieldByName('op', t('Save'), t('Save button found.'));
67
68
69
70
        $this->drupalPost(NULL, $edit, t('Save'));
        break;

      case DRUPAL_DISABLED:
71
72
        $this->assertNoFieldByName('op', t('Preview'), t('Preview button not found.'));
        $this->assertFieldByName('op', t('Save'), t('Save button found.'));
73
74
        $this->drupalPost(NULL, $edit, t('Save'));
        break;
75
76
77
    }
    $match = array();
    // Get comment ID
78
    preg_match('/#comment-([0-9]+)/', $this->getURL(), $match);
79
80
81

    // Get comment.
    if ($contact !== TRUE) { // If true then attempting to find error message.
82
83
84
      if ($subject) {
        $this->assertText($subject, 'Comment subject posted.');
      }
85
      $this->assertText($comment, 'Comment body posted.');
86
      $this->assertTrue((!empty($match) && !empty($match[1])), t('Comment id found.'));
87
88
89
    }

    if (isset($match[1])) {
90
      return entity_create('comment', array('id' => $match[1], 'subject' => $subject, 'comment' => $comment));
91
92
93
94
95
96
    }
  }

  /**
   * Checks current page for specified comment.
   *
97
98
99
100
101
102
103
   * @param object $comment
   *   The comment object.
   * @param boolean $reply
   *   Boolean indicating whether the comment is a reply to another comment.
   *
   * @return boolean
   *   Boolean indicating whether the comment was found.
104
105
106
107
108
109
110
111
   */
  function commentExists($comment, $reply = FALSE) {
    if ($comment && is_object($comment)) {
      $regex = '/' . ($reply ? '<div class="indented">(.*?)' : '');
      $regex .= '<a id="comment-' . $comment->id . '"(.*?)'; // Comment anchor.
      $regex .= '<div(.*?)'; // Begin in comment div.
      $regex .= $comment->subject . '(.*?)'; // Match subject.
      $regex .= $comment->comment . '(.*?)'; // Match comment.
112
      $regex .= '/s';
113

114
      return (boolean)preg_match($regex, $this->drupalGetContent());
115
116
117
118
119
120
121
    }
    else {
      return FALSE;
    }
  }

  /**
122
   * Deletes a comment.
123
124
125
126
127
   *
   * @param object $comment
   *   Comment to delete.
   */
  function deleteComment($comment) {
128
    $this->drupalPost('comment/' . $comment->id . '/delete', array(), t('Delete'));
129
    $this->assertText(t('The comment and all its replies have been deleted.'), t('Comment deleted.'));
130
131
132
  }

  /**
133
   * Sets the value governing whether the subject field should be enabled.
134
135
   *
   * @param boolean $enabled
136
   *   Boolean specifying whether the subject field should be enabled.
137
138
139
140
141
142
   */
  function setCommentSubject($enabled) {
    $this->setCommentSettings('comment_subject_field', ($enabled ? '1' : '0'), 'Comment subject ' . ($enabled ? 'enabled' : 'disabled') . '.');
  }

  /**
143
   * Sets the value governing the previewing mode for the comment form.
144
   *
145
   * @param int $mode
146
   *   The preview mode: DRUPAL_DISABLED, DRUPAL_OPTIONAL or DRUPAL_REQUIRED.
147
   */
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
  function setCommentPreview($mode) {
    switch ($mode) {
      case DRUPAL_DISABLED:
        $mode_text = 'disabled';
        break;

      case DRUPAL_OPTIONAL:
        $mode_text = 'optional';
        break;

      case DRUPAL_REQUIRED:
        $mode_text = 'required';
        break;
    }
    $this->setCommentSettings('comment_preview', $mode, 'Comment preview ' . $mode_text . '.');
163
164
165
  }

  /**
166
   * Sets the value governing whether the comment form is on its own page.
167
168
   *
   * @param boolean $enabled
169
170
   *   TRUE if the comment form should be displayed on the same page as the
   *   comments; FALSE if it should be displayed on its own page.
171
172
   */
  function setCommentForm($enabled) {
173
    $this->setCommentSettings('comment_form_location', ($enabled ? COMMENT_FORM_BELOW : COMMENT_FORM_SEPARATE_PAGE), 'Comment controls ' . ($enabled ? 'enabled' : 'disabled') . '.');
174
175
176
  }

  /**
177
   * Sets the value governing restrictions on anonymous comments.
178
179
   *
   * @param integer $level
180
181
182
183
   *   The level of the contact information allowed for anonymous comments:
   *   - 0: No contact information allowed.
   *   - 1: Contact information allowed but not required.
   *   - 2: Contact information required.
184
185
186
187
188
189
   */
  function setCommentAnonymous($level) {
    $this->setCommentSettings('comment_anonymous', $level, 'Anonymous commenting set to level ' . $level . '.');
  }

  /**
190
   * Sets the value specifying the default number of comments per page.
191
192
193
194
195
   *
   * @param integer $comments
   *   Comments per page value.
   */
  function setCommentsPerPage($number) {
196
    $this->setCommentSettings('comment_default_per_page', $number, 'Number of comments per page set to ' . $number . '.');
197
198
199
  }

  /**
200
   * Sets a comment settings variable for the article content type.
201
202
203
204
205
206
207
208
209
210
   *
   * @param string $name
   *   Name of variable.
   * @param string $value
   *   Value of variable.
   * @param string $message
   *   Status message to display.
   */
  function setCommentSettings($name, $value, $message) {
    variable_set($name . '_article', $value);
211
    $this->assertTrue(TRUE, t($message)); // Display status message.
212
213
214
  }

  /**
215
   * Checks whether the commenter's contact information is displayed.
216
   *
217
218
   * @return boolean
   *   Contact info is available.
219
220
221
222
223
224
   */
  function commentContactInfoAvailable() {
    return preg_match('/(input).*?(name="name").*?(input).*?(name="mail").*?(input).*?(name="homepage")/s', $this->drupalGetContent());
  }

  /**
225
   * Performs the specified operation on the specified comment.
226
227
228
229
230
231
232
233
234
235
236
237
   *
   * @param object $comment
   *   Comment to perform operation on.
   * @param string $operation
   *   Operation to perform.
   * @param boolean $aproval
   *   Operation is found on approval page.
   */
  function performCommentOperation($comment, $operation, $approval = FALSE) {
    $edit = array();
    $edit['operation'] = $operation;
    $edit['comments[' . $comment->id . ']'] = TRUE;
238
    $this->drupalPost('admin/content/comment' . ($approval ? '/approval' : ''), $edit, t('Update'));
239
240
241

    if ($operation == 'delete') {
      $this->drupalPost(NULL, array(), t('Delete comments'));
242
      $this->assertRaw(format_plural(1, 'Deleted 1 comment.', 'Deleted @count comments.'), t('Operation "' . $operation . '" was performed on comment.'));
243
244
    }
    else {
245
      $this->assertText(t('The update has been performed.'), t('Operation "' . $operation . '" was performed on comment.'));
246
247
248
249
    }
  }

  /**
250
   * Gets the comment ID for an unapproved comment.
251
252
253
   *
   * @param string $subject
   *   Comment subject to find.
254
   *
255
256
257
258
   * @return integer
   *   Comment id.
   */
  function getUnapprovedComment($subject) {
259
    $this->drupalGet('admin/content/comment/approval');
260
261
262
263
264
265
266
    preg_match('/href="(.*?)#comment-([^"]+)"(.*?)>(' . $subject . ')/', $this->drupalGetContent(), $match);

    return $match[2];
  }
}

class CommentInterfaceTest extends CommentHelperCase {
267
  public static function getInfo() {
268
    return array(
269
270
271
      'name' => 'Comment interface',
      'description' => 'Test comment user interfaces.',
      'group' => 'Comment',
272
273
274
    );
  }

275
  /**
276
   * Tests the comment interface.
277
278
   */
  function testCommentInterface() {
279
    $langcode = LANGUAGE_NONE;
280
    // Set comments to have subject and preview disabled.
281
    $this->drupalLogin($this->admin_user);
282
    $this->setCommentPreview(DRUPAL_DISABLED);
283
    $this->setCommentForm(TRUE);
284
    $this->setCommentSubject(FALSE);
285
    $this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED, t('Comment paging changed.'));
286
287
    $this->drupalLogout();

288
    // Post comment #1 without subject or preview.
289
    $this->drupalLogin($this->web_user);
290
291
292
    $comment_text = $this->randomName();
    $comment = $this->postComment($this->node, $comment_text);
    $comment_loaded = comment_load($comment->id);
293
    $this->assertTrue($this->commentExists($comment), t('Comment found.'));
294
295
296
297
298

    // Set comments to have subject and preview to required.
    $this->drupalLogout();
    $this->drupalLogin($this->admin_user);
    $this->setCommentSubject(TRUE);
299
    $this->setCommentPreview(DRUPAL_REQUIRED);
300
301
    $this->drupalLogout();

302
    // Create comment #2 that allows subject and requires preview.
303
    $this->drupalLogin($this->web_user);
304
305
    $subject_text = $this->randomName();
    $comment_text = $this->randomName();
306
    $comment = $this->postComment($this->node, $comment_text, $subject_text, TRUE);
307
    $comment_loaded = comment_load($comment->id);
308
    $this->assertTrue($this->commentExists($comment), t('Comment found.'));
309

310
311
    // Check comment display.
    $this->drupalGet('node/' . $this->node->nid . '/' . $comment->id);
312
313
    $this->assertText($subject_text, t('Individual comment subject found.'));
    $this->assertText($comment_text, t('Individual comment body found.'));
314

315
316
317
318
319
    // Set comments to have subject and preview to optional.
    $this->drupalLogout();
    $this->drupalLogin($this->admin_user);
    $this->setCommentSubject(TRUE);
    $this->setCommentPreview(DRUPAL_OPTIONAL);
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339

    // Test changing the comment author to "Anonymous".
    $this->drupalGet('comment/' . $comment->id . '/edit');
    $comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => ''));
    $comment_loaded = comment_load($comment->id);
    $this->assertTrue(empty($comment_loaded->name) && $comment_loaded->uid == 0, t('Comment author successfully changed to anonymous.'));

    // Test changing the comment author to an unverified user.
    $random_name = $this->randomName();
    $this->drupalGet('comment/' . $comment->id . '/edit');
    $comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => $random_name));
    $this->drupalGet('node/' . $this->node->nid);
    $this->assertText($random_name . ' (' . t('not verified') . ')', t('Comment author successfully changed to an unverified user.'));

    // Test changing the comment author to a verified user.
    $this->drupalGet('comment/' . $comment->id . '/edit');
    $comment = $this->postComment(NULL, $comment->comment, $comment->subject, array('name' => $this->web_user->name));
    $comment_loaded = comment_load($comment->id);
    $this->assertTrue($comment_loaded->name == $this->web_user->name && $comment_loaded->uid == $this->web_user->uid, t('Comment author successfully changed to a registered user.'));

340
341
342
343
344
    $this->drupalLogout();

    // Reply to comment #2 creating comment #3 with optional preview and no
    // subject though field enabled.
    $this->drupalLogin($this->web_user);
345
    $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
346
347
    $this->assertText($subject_text, t('Individual comment-reply subject found.'));
    $this->assertText($comment_text, t('Individual comment-reply body found.'));
348
    $reply = $this->postComment(NULL, $this->randomName(), '', TRUE);
349
    $reply_loaded = comment_load($reply->id);
350
351
352
    $this->assertTrue($this->commentExists($reply, TRUE), t('Reply found.'));
    $this->assertEqual($comment->id, $reply_loaded->pid, t('Pid of a reply to a comment is set correctly.'));
    $this->assertEqual(rtrim($comment_loaded->thread, '/') . '.00/', $reply_loaded->thread, t('Thread of reply grows correctly.'));
353

354
    // Second reply to comment #3 creating comment #4.
355
    $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
356
357
    $this->assertText($subject_text, t('Individual comment-reply subject found.'));
    $this->assertText($comment_text, t('Individual comment-reply body found.'));
358
    $reply = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
359
    $reply_loaded = comment_load($reply->id);
360
361
    $this->assertTrue($this->commentExists($reply, TRUE), t('Second reply found.'));
    $this->assertEqual(rtrim($comment_loaded->thread, '/') . '.01/', $reply_loaded->thread, t('Thread of second reply grows correctly.'));
362
363

    // Edit reply.
364
    $this->drupalGet('comment/' . $reply->id . '/edit');
365
    $reply = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
366
    $this->assertTrue($this->commentExists($reply, TRUE), t('Modified reply found.'));
367

368
369
    // Correct link count
    $this->drupalGet('node');
370
    $this->assertRaw('4 comments', t('Link to the 4 comments exist.'));
371

372
    // Confirm a new comment is posted to the correct page.
373
    $this->setCommentsPerPage(2);
374
    $comment_new_page = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE);
375
    $this->assertTrue($this->commentExists($comment_new_page), t('Page one exists. %s'));
376
    $this->drupalGet('node/' . $this->node->nid, array('query' => array('page' => 1)));
377
    $this->assertTrue($this->commentExists($reply, TRUE), t('Page two exists. %s'));
378
379
    $this->setCommentsPerPage(50);

380
    // Attempt to post to node with comments disabled.
381
    $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_HIDDEN));
382
    $this->assertTrue($this->node, t('Article node created.'));
383
    $this->drupalGet('comment/reply/' . $this->node->nid);
384
385
    $this->assertText('This discussion is closed', t('Posting to node with comments disabled'));
    $this->assertNoField('edit-comment', t('Comment body field found.'));
386

387
    // Attempt to post to node with read-only comments.
388
    $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_CLOSED));
389
    $this->assertTrue($this->node, t('Article node created.'));
390
    $this->drupalGet('comment/reply/' . $this->node->nid);
391
392
    $this->assertText('This discussion is closed', t('Posting to node with comments read-only'));
    $this->assertNoField('edit-comment', t('Comment body field found.'));
393
394

    // Attempt to post to node with comments enabled (check field names etc).
395
    $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_OPEN));
396
    $this->assertTrue($this->node, t('Article node created.'));
397
    $this->drupalGet('comment/reply/' . $this->node->nid);
398
399
    $this->assertNoText('This discussion is closed', t('Posting to node with comments enabled'));
    $this->assertField('edit-comment-body-' . $langcode . '-0-value', t('Comment body field found.'));
400

401
402
403
404
    // Delete comment and make sure that reply is also removed.
    $this->drupalLogout();
    $this->drupalLogin($this->admin_user);
    $this->deleteComment($comment);
405
    $this->deleteComment($comment_new_page);
406

407
    $this->drupalGet('node/' . $this->node->nid);
408
409
    $this->assertFalse($this->commentExists($comment), t('Comment not found.'));
    $this->assertFalse($this->commentExists($reply, TRUE), t('Reply not found.'));
410

411
412
413
414
415
416
417
    // Enabled comment form on node page.
    $this->drupalLogin($this->admin_user);
    $this->setCommentForm(TRUE);
    $this->drupalLogout();

    // Submit comment through node form.
    $this->drupalLogin($this->web_user);
418
    $this->drupalGet('node/' . $this->node->nid);
419
    $form_comment = $this->postComment(NULL, $this->randomName(), $this->randomName(), TRUE);
420
    $this->assertTrue($this->commentExists($form_comment), t('Form comment found.'));
421
422
423
424
425
426

    // Disable comment form on node page.
    $this->drupalLogout();
    $this->drupalLogin($this->admin_user);
    $this->setCommentForm(FALSE);
  }
427

428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
  /**
   * Tests new comment marker.
   */
  public function testCommentNewCommentsIndicator() {
    // Test if the right links are displayed when no comment is present for the
    // node.
    $this->drupalLogin($this->admin_user);
    $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_OPEN));
    $this->drupalGet('node');
    $this->assertNoLink(t('@count comments', array('@count' => 0)));
    $this->assertNoLink(t('@count new comments', array('@count' => 0)));
    $this->assertLink(t('Read more'));
    $count = $this->xpath('//div[@id=:id]/div[@class=:class]/ul/li', array(':id' => 'node-' . $this->node->nid, ':class' => 'link-wrapper'));
    $this->assertTrue(count($count) == 1, t('One child found'));

    // Create a new comment. This helper function may be run with different
    // comment settings so use comment_save() to avoid complex setup.
    $comment = entity_create('comment', array(
      'cid' => NULL,
      'nid' => $this->node->nid,
      'node_type' => $this->node->type,
      'pid' => 0,
      'uid' => $this->loggedInUser->uid,
      'status' => COMMENT_PUBLISHED,
      'subject' => $this->randomName(),
      'hostname' => ip_address(),
454
      'langcode' => LANGUAGE_NONE,
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
      'comment_body' => array(LANGUAGE_NONE => array($this->randomName())),
    ));
    comment_save($comment);
    $this->drupalLogout();

    // Log in with 'web user' and check comment links.
    $this->drupalLogin($this->web_user);
    $this->drupalGet('node');
    $this->assertLink(t('1 new comment'));
    $this->clickLink(t('1 new comment'));
    $this->assertRaw('<a id="new"></a>', t('Found "new" marker.'));
    $this->assertTrue($this->xpath('//a[@id=:new]/following-sibling::a[1][@id=:comment_id]', array(':new' => 'new', ':comment_id' => 'comment-1')), t('The "new" anchor is positioned at the right comment.'));

    // Test if "new comment" link is correctly removed.
    $this->drupalGet('node');
    $this->assertLink(t('1 comment'));
    $this->assertLink(t('Read more'));
    $this->assertNoLink(t('1 new comment'));
    $this->assertNoLink(t('@count new comments', array('@count' => 0)));
    $count = $this->xpath('//div[@id=:id]/div[@class=:class]/ul/li', array(':id' => 'node-' . $this->node->nid, ':class' => 'link-wrapper'));
    $this->assertTrue(count($count) == 2, print_r($count, TRUE));
  }

478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
  /**
   * Tests CSS classes on comments.
   */
  function testCommentClasses() {
    // Create all permutations for comments, users, and nodes.
    $parameters = array(
      'node_uid' => array(0, $this->web_user->uid),
      'comment_uid' => array(0, $this->web_user->uid, $this->admin_user->uid),
      'comment_status' => array(COMMENT_PUBLISHED, COMMENT_NOT_PUBLISHED),
      'user' => array('anonymous', 'authenticated', 'admin'),
    );
    $permutations = $this->generatePermutations($parameters);

    foreach ($permutations as $case) {
      // Create a new node.
      $node = $this->drupalCreateNode(array('type' => 'article', 'uid' => $case['node_uid']));

      // Add a comment.
      $comment = entity_create('comment', array(
        'nid' => $node->nid,
        'uid' => $case['comment_uid'],
        'status' => $case['comment_status'],
        'subject' => $this->randomName(),
        'language' => LANGUAGE_NONE,
        'comment_body' => array(LANGUAGE_NONE => array($this->randomName())),
      ));
      comment_save($comment);

      // Adjust the current/viewing user.
      switch ($case['user']) {
        case 'anonymous':
          $this->drupalLogout();
          $case['user_uid'] = 0;
          break;

        case 'authenticated':
          $this->drupalLogin($this->web_user);
          $case['user_uid'] = $this->web_user->uid;
          break;

        case 'admin':
          $this->drupalLogin($this->admin_user);
          $case['user_uid'] = $this->admin_user->uid;
          break;
      }
      // Request the node with the comment.
      $this->drupalGet('node/' . $node->nid);

      // Verify classes if the comment is visible for the current user.
      if ($case['comment_status'] == COMMENT_PUBLISHED || $case['user'] == 'admin') {
        // Verify the comment-by-anonymous class.
        $comments = $this->xpath('//*[contains(@class, "comment-by-anonymous")]');
        if ($case['comment_uid'] == 0) {
          $this->assertTrue(count($comments) == 1, 'comment-by-anonymous class found.');
        }
        else {
          $this->assertFalse(count($comments), 'comment-by-anonymous class not found.');
        }

        // Verify the comment-by-node-author class.
        $comments = $this->xpath('//*[contains(@class, "comment-by-node-author")]');
        if ($case['comment_uid'] > 0 && $case['comment_uid'] == $case['node_uid']) {
          $this->assertTrue(count($comments) == 1, 'comment-by-node-author class found.');
        }
        else {
          $this->assertFalse(count($comments), 'comment-by-node-author class not found.');
        }

        // Verify the comment-by-viewer class.
        $comments = $this->xpath('//*[contains(@class, "comment-by-viewer")]');
        if ($case['comment_uid'] > 0 && $case['comment_uid'] == $case['user_uid']) {
          $this->assertTrue(count($comments) == 1, 'comment-by-viewer class found.');
        }
        else {
          $this->assertFalse(count($comments), 'comment-by-viewer class not found.');
        }
      }

      // Verify the comment-unpublished class.
      $comments = $this->xpath('//*[contains(@class, "comment-unpublished")]');
      if ($case['comment_status'] == COMMENT_NOT_PUBLISHED && $case['user'] == 'admin') {
        $this->assertTrue(count($comments) == 1, 'comment-unpublished class found.');
      }
      else {
        $this->assertFalse(count($comments), 'comment-unpublished class not found.');
      }

      // Verify the comment-new class.
      if ($case['comment_status'] == COMMENT_PUBLISHED || $case['user'] == 'admin') {
        $comments = $this->xpath('//*[contains(@class, "comment-new")]');
        if ($case['user'] != 'anonymous') {
          $this->assertTrue(count($comments) == 1, 'comment-new class found.');

          // Request the node again. The comment-new class should disappear.
          $this->drupalGet('node/' . $node->nid);
          $comments = $this->xpath('//*[contains(@class, "comment-new")]');
          $this->assertFalse(count($comments), 'comment-new class not found.');
        }
        else {
          $this->assertFalse(count($comments), 'comment-new class not found.');
        }
      }
    }
  }

583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
  /**
   * Tests the node comment statistics.
   */
  function testCommentNodeCommentStatistics() {
    $langcode = LANGUAGE_NONE;
    // Set comments to have subject and preview disabled.
    $this->drupalLogin($this->admin_user);
    $this->setCommentPreview(DRUPAL_DISABLED);
    $this->setCommentForm(TRUE);
    $this->setCommentSubject(FALSE);
    $this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED, t('Comment paging changed.'));
    $this->drupalLogout();

    // Creates a second user to post comments.
    $this->web_user2 = $this->drupalCreateUser(array('access comments', 'post comments', 'create article content', 'edit own comments'));

    // Checks the initial values of node comment statistics with no comment.
    $node = node_load($this->node->nid);
    $this->assertEqual($node->last_comment_timestamp, $this->node->created, t('The initial value of node last_comment_timestamp is the node created date.'));
    $this->assertEqual($node->last_comment_name, NULL, t('The initial value of node last_comment_name is NULL.'));
    $this->assertEqual($node->last_comment_uid, $this->web_user->uid, t('The initial value of node last_comment_uid is the node uid.'));
    $this->assertEqual($node->comment_count, 0, t('The initial value of node comment_count is zero.'));

    // Post comment #1 as web_user2.
    $this->drupalLogin($this->web_user2);
    $comment_text = $this->randomName();
    $comment = $this->postComment($this->node, $comment_text);
    $comment_loaded = comment_load($comment->id);

    // Checks the new values of node comment statistics with comment #1.
    // The node needs to be reloaded with a node_load_multiple cache reset.
    $node = node_load($this->node->nid, NULL, TRUE);
    $this->assertEqual($node->last_comment_name, NULL, t('The value of node last_comment_name is NULL.'));
    $this->assertEqual($node->last_comment_uid, $this->web_user2->uid, t('The value of node last_comment_uid is the comment #1 uid.'));
    $this->assertEqual($node->comment_count, 1, t('The value of node comment_count is 1.'));

    // Prepare for anonymous comment submission (comment approval enabled).
    variable_set('user_register', USER_REGISTER_VISITORS);
    $this->drupalLogin($this->admin_user);
    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
      'access comments' => TRUE,
      'post comments' => TRUE,
      'skip comment approval' => FALSE,
    ));
    // Ensure that the poster can leave some contact info.
    $this->setCommentAnonymous('1');
    $this->drupalLogout();

    // Post comment #2 as anonymous (comment approval enabled).
    $this->drupalGet('comment/reply/' . $this->node->nid);
    $anonymous_comment = $this->postComment($this->node, $this->randomName(), '', TRUE);
    $comment_unpublished_loaded = comment_load($anonymous_comment->id);

    // Checks the new values of node comment statistics with comment #2 and
    // ensure they haven't changed since the comment has not been moderated.
    // The node needs to be reloaded with a node_load_multiple cache reset.
    $node = node_load($this->node->nid, NULL, TRUE);
    $this->assertEqual($node->last_comment_name, NULL, t('The value of node last_comment_name is still NULL.'));
    $this->assertEqual($node->last_comment_uid, $this->web_user2->uid, t('The value of node last_comment_uid is still the comment #1 uid.'));
    $this->assertEqual($node->comment_count, 1, t('The value of node comment_count is still 1.'));

    // Prepare for anonymous comment submission (no approval required).
    $this->drupalLogin($this->admin_user);
    user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array(
      'access comments' => TRUE,
      'post comments' => TRUE,
      'skip comment approval' => TRUE,
    ));
    $this->drupalLogout();

    // Post comment #3 as anonymous.
    $this->drupalGet('comment/reply/' . $this->node->nid);
    $anonymous_comment = $this->postComment($this->node, $this->randomName(), '', array('name' => $this->randomName()));
    $comment_loaded = comment_load($anonymous_comment->id);

    // Checks the new values of node comment statistics with comment #3.
    // The node needs to be reloaded with a node_load_multiple cache reset.
    $node = node_load($this->node->nid, NULL, TRUE);
    $this->assertEqual($node->last_comment_name, $comment_loaded->name, t('The value of node last_comment_name is the name of the anonymous user.'));
    $this->assertEqual($node->last_comment_uid, 0, t('The value of node last_comment_uid is zero.'));
    $this->assertEqual($node->comment_count, 2, t('The value of node comment_count is 2.'));
  }
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679

  /**
   * Tests comment links.
   *
   * The output of comment links depends on various environment conditions:
   * - Various Comment module configuration settings, user registration
   *   settings, and user access permissions.
   * - Whether the user is authenticated or not, and whether any comments exist.
   *
   * To account for all possible cases, this test creates permutations of all
   * possible conditions and tests the expected appearance of comment links in
   * each environment.
   */
  function testCommentLinks() {
    // Bartik theme alters comment links, so use a different theme.
680
681
    theme_enable(array('stark'));
    variable_set('theme_default', 'stark');
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771

    // Remove additional user permissions from $this->web_user added by setUp(),
    // since this test is limited to anonymous and authenticated roles only.
    user_role_delete(key($this->web_user->roles));

    // Matrix of possible environmental conditions and configuration settings.
    // See setEnvironment() for details.
    $conditions = array(
      'authenticated'   => array(FALSE, TRUE),
      'comment count'   => array(FALSE, TRUE),
      'access comments' => array(0, 1),
      'post comments'   => array(0, 1),
      'form'            => array(COMMENT_FORM_BELOW, COMMENT_FORM_SEPARATE_PAGE),
      // USER_REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL is irrelevant for this
      // test; there is only a difference between open and closed registration.
      'user_register'   => array(USER_REGISTER_VISITORS, USER_REGISTER_ADMINISTRATORS_ONLY),
      // @todo Complete test coverage for:
      //'comments'        => array(COMMENT_NODE_OPEN, COMMENT_NODE_CLOSED, COMMENT_NODE_HIDDEN),
      //// COMMENT_ANONYMOUS_MUST_CONTACT is irrelevant for this test.
      //'contact '        => array(COMMENT_ANONYMOUS_MAY_CONTACT, COMMENT_ANONYMOUS_MAYNOT_CONTACT),
    );

    $environments = $this->generatePermutations($conditions);
    foreach ($environments as $info) {
      $this->assertCommentLinks($info);
    }
  }

  /**
   * Re-configures the environment, module settings, and user permissions.
   *
   * @param $info
   *   An associative array describing the environment to setup:
   *   - Environment conditions:
   *     - authenticated: Boolean whether to test with $this->web_user or
   *       anonymous.
   *     - comment count: Boolean whether to test with a new/unread comment on
   *       $this->node or no comments.
   *   - Configuration settings:
   *     - form: COMMENT_FORM_BELOW or COMMENT_FORM_SEPARATE_PAGE.
   *     - user_register: USER_REGISTER_ADMINISTRATORS_ONLY or
   *       USER_REGISTER_VISITORS.
   *     - contact: COMMENT_ANONYMOUS_MAY_CONTACT or
   *       COMMENT_ANONYMOUS_MAYNOT_CONTACT.
   *     - comments: COMMENT_NODE_OPEN, COMMENT_NODE_CLOSED, or
   *       COMMENT_NODE_HIDDEN.
   *   - User permissions:
   *     These are granted or revoked for the user, according to the
   *     'authenticated' flag above. Pass 0 or 1 as parameter values. See
   *     user_role_change_permissions().
   *     - access comments
   *     - post comments
   *     - skip comment approval
   *     - edit own comments
   */
  function setEnvironment(array $info) {
    static $current;

    // Apply defaults to initial environment.
    if (!isset($current)) {
      $current = array(
        'authenticated' => FALSE,
        'comment count' => FALSE,
        'form' => COMMENT_FORM_BELOW,
        'user_register' => USER_REGISTER_VISITORS,
        'contact' => COMMENT_ANONYMOUS_MAY_CONTACT,
        'comments' => COMMENT_NODE_OPEN,
        'access comments' => 0,
        'post comments' => 0,
        // Enabled by default, because it's irrelevant for this test.
        'skip comment approval' => 1,
        'edit own comments' => 0,
      );
    }
    // Complete new environment with current environment.
    $info = array_merge($current, $info);

    // Change environment conditions.
    if ($current['authenticated'] != $info['authenticated']) {
      if ($this->loggedInUser) {
        $this->drupalLogout();
      }
      else {
        $this->drupalLogin($this->web_user);
      }
    }
    if ($current['comment count'] != $info['comment count']) {
      if ($info['comment count']) {
        // Create a comment via CRUD API functionality, since
        // $this->postComment() relies on actual user permissions.
772
        $comment = entity_create('comment', array(
773
774
775
776
777
778
779
780
          'cid' => NULL,
          'nid' => $this->node->nid,
          'node_type' => $this->node->type,
          'pid' => 0,
          'uid' => 0,
          'status' => COMMENT_PUBLISHED,
          'subject' => $this->randomName(),
          'hostname' => ip_address(),
781
          'langcode' => LANGUAGE_NONE,
782
          'comment_body' => array(LANGUAGE_NONE => array($this->randomName())),
783
        ));
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
        comment_save($comment);
        $this->comment = $comment;

        // comment_num_new() relies on node_last_viewed(), so ensure that no one
        // has seen the node of this comment.
        db_delete('history')->condition('nid', $this->node->nid)->execute();
      }
      else {
        $cids = db_query("SELECT cid FROM {comment}")->fetchCol();
        comment_delete_multiple($cids);
        unset($this->comment);
      }
    }

    // Change comment settings.
    variable_set('comment_form_location_' . $this->node->type, $info['form']);
    variable_set('comment_anonymous_' . $this->node->type, $info['contact']);
    if ($this->node->comment != $info['comments']) {
      $this->node->comment = $info['comments'];
      node_save($this->node);
    }

    // Change user settings.
    variable_set('user_register', $info['user_register']);

    // Change user permissions.
    $rid = ($this->loggedInUser ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID);
    $perms = array_intersect_key($info, array('access comments' => 1, 'post comments' => 1, 'skip comment approval' => 1, 'edit own comments' => 1));
    user_role_change_permissions($rid, $perms);

    // Output verbose debugging information.
    // @see DrupalTestCase::error()
    $t_form = array(
      COMMENT_FORM_BELOW => 'below',
      COMMENT_FORM_SEPARATE_PAGE => 'separate page',
    );
    $t_contact = array(
      COMMENT_ANONYMOUS_MAY_CONTACT => 'optional',
      COMMENT_ANONYMOUS_MAYNOT_CONTACT => 'disabled',
      COMMENT_ANONYMOUS_MUST_CONTACT => 'required',
    );
    $t_comments = array(
      COMMENT_NODE_OPEN => 'open',
      COMMENT_NODE_CLOSED => 'closed',
      COMMENT_NODE_HIDDEN => 'hidden',
    );
    $verbose = $info;
    $verbose['form'] = $t_form[$info['form']];
    $verbose['contact'] = $t_contact[$info['contact']];
    $verbose['comments'] = $t_comments[$info['comments']];
    $message = t('Changed environment:<pre>@verbose</pre>', array(
      '@verbose' => var_export($verbose, TRUE),
    ));
    $this->assert('debug', $message, 'Debug');

    // Update current environment.
    $current = $info;

    return $info;
  }

  /**
846
   * Asserts that comment links appear according to the passed environment.
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
   *
   * @param $info
   *   An associative array describing the environment to pass to
   *   setEnvironment().
   */
  function assertCommentLinks(array $info) {
    $info = $this->setEnvironment($info);

    $nid = $this->node->nid;

    foreach (array('', "node/$nid") as $path) {
      $this->drupalGet($path);

      // User is allowed to view comments.
      if ($info['access comments']) {
        if ($path == '') {
          // In teaser view, a link containing the comment count is always
          // expected.
          if ($info['comment count']) {
            $this->assertLink(t('1 comment'));

            // For logged in users, a link containing the amount of new/unread
            // comments is expected.
            // See important note about comment_num_new() below.
            if ($this->loggedInUser && isset($this->comment) && !isset($this->comment->seen)) {
              $this->assertLink(t('1 new comment'));
              $this->comment->seen = TRUE;
            }
          }
        }
      }
      else {
        $this->assertNoLink(t('1 comment'));
        $this->assertNoLink(t('1 new comment'));
      }
      // comment_num_new() is based on node views, so comments are marked as
      // read when a node is viewed, regardless of whether we have access to
      // comments.
      if ($path == "node/$nid" && $this->loggedInUser && isset($this->comment)) {
        $this->comment->seen = TRUE;
      }

      // User is not allowed to post comments.
      if (!$info['post comments']) {
        $this->assertNoLink('Add new comment');

        // Anonymous users should see a note to log in or register in case
        // authenticated users are allowed to post comments.
        // @see theme_comment_post_forbidden()
        if (!$this->loggedInUser) {
          if (user_access('post comments', $this->web_user)) {
            // The note depends on whether users are actually able to register.
            if ($info['user_register']) {
              $this->assertText('Log in or register to post comments');
            }
            else {
              $this->assertText('Log in to post comments');
            }
          }
          else {
            $this->assertNoText('Log in or register to post comments');
            $this->assertNoText('Log in to post comments');
          }
        }
      }
      // User is allowed to post comments.
      else {
        $this->assertNoText('Log in or register to post comments');

        // "Add new comment" is always expected, except when there are no
        // comments or if the user cannot see them.
        if ($path == "node/$nid" && $info['form'] == COMMENT_FORM_BELOW && (!$info['comment count'] || !$info['access comments'])) {
          $this->assertNoLink('Add new comment');
        }
        else {
          $this->assertLink('Add new comment');
923
924
925
926
927
928
929
930
931
932
933

          // Verify that the "Add new comment" link points to the correct URL
          // based on the comment form location configuration.
          if ($info['form'] == COMMENT_FORM_SEPARATE_PAGE) {
            $this->assertLinkByHref("comment/reply/$nid#comment-form", 0, 'Comment form link destination is on a separate page.');
            $this->assertNoLinkByHref("node/$nid#comment-form");
          }
          else {
            $this->assertLinkByHref("node/$nid#comment-form", 0, 'Comment form link destination is on node.');
            $this->assertNoLinkByHref("comment/reply/$nid#comment-form");
          }
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
        }

        // Also verify that the comment form appears according to the configured
        // location.
        if ($path == "node/$nid") {
          $elements = $this->xpath('//form[@id=:id]', array(':id' => 'comment-form'));
          if ($info['form'] == COMMENT_FORM_BELOW) {
            $this->assertTrue(count($elements), t('Comment form found below.'));
          }
          else {
            $this->assertFalse(count($elements), t('Comment form not found below.'));
          }
        }
      }
    }
  }
950
951
}

952
/**
953
 * Tests previewing comments.
954
955
956
957
958
959
960
961
962
963
964
 */
class CommentPreviewTest extends CommentHelperCase {
  public static function getInfo() {
    return array(
      'name' => 'Comment preview',
      'description' => 'Test comment preview.',
      'group' => 'Comment',
    );
  }

  /**
965
   * Tests comment preview.
966
967
   */
  function testCommentPreview() {
968
969
    $langcode = LANGUAGE_NONE;

970
971
    // As admin user, configure comment settings.
    $this->drupalLogin($this->admin_user);
972
    $this->setCommentPreview(DRUPAL_OPTIONAL);
973
974
975
976
977
    $this->setCommentForm(TRUE);
    $this->setCommentSubject(TRUE);
    $this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED, t('Comment paging changed.'));
    $this->drupalLogout();

978
    // Login as web user and add a signature and a user picture.
979
    $this->drupalLogin($this->web_user);
980
    variable_set('user_signatures', 1);
981
    variable_set('user_pictures', 1);
982
983
984
    $test_signature = $this->randomName();
    $edit['signature[value]'] = '<a href="http://example.com/">' . $test_signature. '</a>';
    $edit['signature[format]'] = 'filtered_html';
985
986
    $image = current($this->drupalGetTestFiles('image'));
    $edit['files[picture_upload]'] = drupal_realpath($image->uri);
987
988
    $this->drupalPost('user/' . $this->web_user->uid . '/edit', $edit, t('Save'));

989
    // As the web user, fill in the comment form and preview the comment.
990
991
    $edit = array();
    $edit['subject'] = $this->randomName(8);
992
    $edit['comment_body[' . $langcode . '][0][value]'] = $this->randomName(16);
993
994
995
    $this->drupalPost('node/' . $this->node->nid, $edit, t('Preview'));

    // Check that the preview is displaying the title and body.
996
997
998
    $this->assertTitle(t('Preview comment | Drupal'), t('Page title is "Preview comment".'));
    $this->assertText($edit['subject'], t('Subject displayed.'));
    $this->assertText($edit['comment_body[' . $langcode . '][0][value]'], t('Comment displayed.'));
999
1000

    // Check that the title and body fields are displayed with the correct values.
For faster browsing, not all history is shown. View entire blame