Index: modules/comment/comment.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.module,v
retrieving revision 1.709
diff -u -p -r1.709 comment.module
--- modules/comment/comment.module	12 May 2009 08:37:44 -0000	1.709
+++ modules/comment/comment.module	19 May 2009 20:30:52 -0000
@@ -500,8 +500,15 @@ function comment_node_view($node, $tease
 
     // Append the list of comments to $node->content for node detail pages.
     if ($node->comment && (bool)menu_get_object() && $node->build_mode != NODE_BUILD_PREVIEW) {
+      // Set the comment id if one was passed (for collapsed comments).
+      if (is_numeric(arg(2))) {
+        $cid = arg(2);
+      }
+      else {
+        $cid = 0;
+      }
       $node->content['comments'] = array(
-        '#markup' => comment_render($node),
+        '#markup' => comment_render($node, $cid),
         '#sorted' => TRUE,
       );
     }
@@ -2175,7 +2182,7 @@ function comment_unpublish_action($comme
     $subject = db_query('SELECT subject FROM {comment} WHERE cid = :cid', array(':cid', $cid))->fetchField();
   }
   db_update('comment')
-    ->fields(array('status' => COMMENT_NOT_PUBLISHED,))
+    ->fields(array('status' => COMMENT_NOT_PUBLISHED))
     ->condition('cid', $cid)
     ->execute();
   watchdog('action', 'Unpublished comment %subject.', array('%subject' => $subject));
Index: modules/comment/comment.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/comment/comment.test,v
retrieving revision 1.28
diff -u -p -r1.28 comment.test
--- modules/comment/comment.test	31 Mar 2009 01:49:50 -0000	1.28
+++ modules/comment/comment.test	19 May 2009 20:30:53 -0000
@@ -9,8 +9,17 @@ class CommentHelperCase extends DrupalWe
   function setUp() {
     parent::setUp('comment');
     // Create users.
-    $this->admin_user = $this->drupalCreateUser(array('administer content types', 'administer comments', 'administer permissions', 'administer blocks'));
-    $this->web_user = $this->drupalCreateUser(array('access comments', 'post comments', 'create article content'));
+    $this->admin_user = $this->drupalCreateUser(array(
+      'administer content types', 
+      'administer comments', 
+      'administer permissions', 
+      'administer blocks'
+    ));
+    $this->web_user = $this->drupalCreateUser(array(
+      'access comments', 
+      'post comments', 
+      'create article content'
+    ));
 
     $this->drupalLogin($this->web_user);
     $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
@@ -24,7 +33,9 @@ class CommentHelperCase extends DrupalWe
    * @param string $subject Comment subject.
    * @param string $comment Comment body.
    * @param boolean $preview Should preview be required.
-   * @param mixed $contact Set to NULL for no contact info, TRUE to ignore success checking, and array of values to set contact info.
+   * @param mixed $contact Set to NULL for no contact info, 
+   *   TRUE to ignore success checking, 
+   *   or array of values to set contact info.
    */
   function postComment($node, $subject, $comment, $preview = TRUE, $contact = NULL) {
     $edit = array();
@@ -40,7 +51,8 @@ class CommentHelperCase extends DrupalWe
     }
 
     if ($preview) {
-      $this->assertNoFieldByName('op', t('Save'), t('Save button not found.')); // Preview required so no save button should be found.
+      // Preview required so no save button should be found.
+      $this->assertNoFieldByName('op', t('Save'), t('Save button not found.')); 
       $this->drupalPost(NULL, $edit, t('Preview'));
     }
     $this->drupalPost(NULL, $edit, t('Save'));
@@ -71,11 +83,21 @@ class CommentHelperCase extends DrupalWe
    */
   function commentExists($comment, $reply = FALSE) {
     if ($comment && is_object($comment)) {
-      $regex = '/' . ($reply ? '<div class="indented">(.*?)' : '');
+      // Default thread setting for comments is threaded, expanded.
+      $thread_setting = $this->getCommentSettings('comment_default_mode',
+        COMMENT_MODE_THREADED_EXPANDED);
+      $threaded = $thread_setting == COMMENT_MODE_THREADED_EXPANDED
+        || $thread_setting == COMMENT_MODE_THREADED_COLLAPSED;
+      // Replies are only indented if we're in threaded mode.
+      $regex = '/' . ($reply && $threaded ? '<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.
+      // Comment body only shows up if we're in expanded mode.
+      if ($thread_setting == COMMENT_MODE_THREADED_EXPANDED
+      || $thread_setting == COMMENT_MODE_FLAT_EXPANDED) {
+          $regex .= $comment->comment . '(.*?)'; // Match comment.
+      }
       $regex .= '<\/div>/s'; // Dot matches newlines and ensure that match doesn't bleed outside comment div.
 
       return (boolean)preg_match($regex, $this->drupalGetContent());
@@ -103,7 +125,8 @@ class CommentHelperCase extends DrupalWe
    *   Subject value.
    */
   function setCommentSubject($enabled) {
-    $this->setCommentSettings('comment_subject_field', ($enabled ? '1' : '0'), 'Comment subject ' . ($enabled ? 'enabled' : 'disabled') . '.');
+    $this->setCommentSettings('comment_subject_field', ($enabled ? '1' : '0'), 
+      'Comment subject ' . ($enabled ? 'enabled' : 'disabled') . '.');
   }
 
   /**
@@ -113,7 +136,18 @@ class CommentHelperCase extends DrupalWe
    *   Preview value.
    */
   function setCommentPreview($required) {
-    $this->setCommentSettings('comment_preview', ($required ? '1' : '0'), 'Comment preview ' . ($required ? 'required' : 'optional') . '.');
+    $this->setCommentSettings('comment_preview', ($required ? '1' : '0'), 
+      'Comment preview ' . ($required ? 'required' : 'optional') . '.');
+  }
+
+  /**
+   * Set comment mode setting.
+   *
+   * @param boolean $level
+   *   Comment level.
+   */
+  function setCommentMode($level) {
+    $this->setCommentSettings('comment_default_mode', $level, 'Comment display mode set to level ' . $level . '.');
   }
 
   /**
@@ -123,7 +157,9 @@ class CommentHelperCase extends DrupalWe
    *   Form value.
    */
   function setCommentForm($enabled) {
-    $this->setCommentSettings('comment_form_location', ($enabled ? '1' : '3'), 'Comment controls ' . ($enabled ? 'enabled' : 'disabled') . '.');
+    $this->setCommentSettings('comment_form_location',
+      ($enabled ? COMMENT_FORM_BELOW : COMMENT_FORM_SEPARATE_PAGE),
+      'Comment controls ' . ($enabled ? 'enabled' : 'disabled') . '.');
   }
 
   /**
@@ -143,7 +179,8 @@ class CommentHelperCase extends DrupalWe
    *   Comments per page value.
    */
   function setCommentsPerPage($number) {
-    $this->setCommentSettings('comment_default_per_page_article', $number, 'Number of comments per page set to ' . $number .'.');
+    $this->setCommentSettings('comment_default_per_page', $number, 
+      'Number of comments per page set to ' . $number . '.');
   }
 
   /**
@@ -162,6 +199,20 @@ class CommentHelperCase extends DrupalWe
   }
 
   /**
+   * Get comment setting for article content type
+   *
+   * @param string $name
+   *   Name of variable
+   * @param string $default
+   *   Default value to return if $name variable is not set
+   * @return mixed
+   *   Value of $name variable or $default if $name variable is not set
+   */
+  function getCommentSettings($name, $default) {
+    return variable_get($name . '_article', $default);
+  }
+
+  /**
    * Set anonymous comment setting.
    *
    * @param boolean $enabled
@@ -175,7 +226,8 @@ class CommentHelperCase extends DrupalWe
     $edit['1[post comments]'] = $enabled;
     $edit['1[post comments without approval]'] = $without_approval;
     $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
-    $this->assertText(t('The changes have been saved.'), t('Anonymous user comments ' . ($enabled ? 'enabled' : 'disabled') . '.'));
+    $this->assertText(t('The changes have been saved.'), 
+      t('Anonymous user comments ' . ($enabled ? 'enabled' : 'disabled') . '.'));
   }
 
   /**
@@ -184,7 +236,8 @@ class CommentHelperCase extends DrupalWe
    * @return boolean Contact info is available.
    */
   function commentContactInfoAvailable() {
-    return preg_match('/(input).*?(name="name").*?(input).*?(name="mail").*?(input).*?(name="homepage")/s', $this->drupalGetContent());
+    return preg_match('/(input).*?(name="name").*?(input).*?(name="mail").*?(input).*?(name="homepage")/s',
+     $this->drupalGetContent());
   }
 
   /**
@@ -205,10 +258,12 @@ class CommentHelperCase extends DrupalWe
 
     if ($operation == 'delete') {
       $this->drupalPost(NULL, array(), t('Delete comments'));
-      $this->assertText(t('The comments have been deleted.'), t('Operation "' . $operation . '" was performed on comment.'));
+      $this->assertText(t('The comments have been deleted.'), 
+        t('Operation "' . $operation . '" was performed on comment.'));
     }
     else {
-      $this->assertText(t('The update has been performed.'), t('Operation "' . $operation . '" was performed on comment.'));
+      $this->assertText(t('The update has been performed.'), 
+        t('Operation "' . $operation . '" was performed on comment.'));
     }
   }
 
@@ -244,7 +299,9 @@ class CommentInterfaceTest extends Comme
     // Set comments to not have subject.
     $this->drupalLogin($this->admin_user);
     $this->setCommentPreview(TRUE);
+    $this->setCommentForm(TRUE);
     $this->setCommentSubject(FALSE);
+    $this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED_EXPANDED, t('Comment paging changed.'));
     $this->drupalLogout();
 
     // Post comment without subject.
@@ -272,6 +329,13 @@ class CommentInterfaceTest extends Comme
     $this->assertText($subject_text, t('Individual comment subject found.'));
     $this->assertText($comment_text, t('Individual comment body found.'));
 
+    // Check threaded comment display.
+    $this->setCommentMode(COMMENT_MODE_FLAT_COLLAPSED);
+    $this->drupalGet('node/' . $this->node->nid);
+    $this->assertText($subject_text, t('Individual comment subject found.'));
+    $this->assertNoText($comment_text, t('Individual comment body not found because not threaded.'));
+    $this->setCommentMode(COMMENT_MODE_THREADED_EXPANDED); // Revert to default.
+
     // Reply to comment without a subject.
     $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
     $this->assertText($subject_text, t('Individual comment-reply subject found.'));
@@ -280,51 +344,67 @@ class CommentInterfaceTest extends Comme
     $reply_loaded = comment_load($reply->id);
     $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.'));
+    $this->assertEqual(rtrim($comment_loaded->thread, '/') . '.00/', 
+      $reply_loaded->thread, t('Thread of reply grows correctly.'));
 
-    // Second reply to comment
+    // Second reply to comment.
     $this->drupalGet('comment/reply/' . $this->node->nid . '/' . $comment->id);
     $this->assertText($subject_text, t('Individual comment-reply subject found.'));
     $this->assertText($comment_text, t('Individual comment-reply body found.'));
     $reply = $this->postComment(NULL, $this->randomName(), $this->randomName());
     $reply_loaded = comment_load($reply->id);
     $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.'));
+    $this->assertEqual(rtrim($comment_loaded->thread, '/') . '.01/', 
+      $reply_loaded->thread, t('Thread of second reply grows correctly.'));
 
     // Edit reply.
     $this->drupalGet('comment/edit/' . $reply->id);
     $reply = $this->postComment(NULL, $this->randomName(), $this->randomName());
     $this->assertTrue($this->commentExists($reply, TRUE), t('Modified reply found.'));
 
-    // Correct link count
+    // Verify correct link count.
     $this->drupalGet('node');
     $this->assertRaw('3 comments', t('Link to the 3 comments exist.'));
 
-    // Pager
-    $this->setCommentsPerPage(2);
+    // Test paging.
+    $this->drupalGet('node/' . $this->node->nid);
     $comment_new_page = $this->postComment($this->node, $this->randomName(), $this->randomName());
+    $this->setCommentsPerPage(2);
     $this->drupalGet('node/' . $this->node->nid);
-    $this->assertTrue($this->commentExists($comment) && $this->commentExists($comment_new_page), t('Page one exists. %s'));
+    $this->assertTrue($this->commentExists($comment), t('Comment on page one exists. %s'));
+    $this->assertFalse($this->commentExists($comment_new_page), t('New comment on page one doesn\'t exist. %s'));
     $this->drupalGet('node/' . $this->node->nid, array('query' => 'page=1'));
-    $this->assertTrue($this->commentExists($reply, TRUE), t('Page two exists. %s'));
+    $this->assertTrue($this->commentExists($reply, TRUE), t('New comment exists on page two. %s'));
     $this->setCommentsPerPage(50);
 
     // Attempt to post to node with comments disabled.
-    $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_HIDDEN));
+    $this->node = $this->drupalCreateNode(array(
+      'type' => 'article', 
+      'promote' => 1, 
+      'comment' => COMMENT_NODE_HIDDEN
+    ));
     $this->assertTrue($this->node, t('Article node created.'));
     $this->drupalGet('comment/reply/' . $this->node->nid);
     $this->assertText('This discussion is closed', t('Posting to node with comments disabled'));
     $this->assertNoField('edit-comment', t('Comment body field found.'));
 
     // Attempt to post to node with read-only comments.
-    $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_CLOSED));
+    $this->node = $this->drupalCreateNode(array(
+      'type' => 'article', 
+      'promote' => 1, 
+      'comment' => COMMENT_NODE_CLOSED
+    ));
     $this->assertTrue($this->node, t('Article node created.'));
     $this->drupalGet('comment/reply/' . $this->node->nid);
     $this->assertText('This discussion is closed', t('Posting to node with comments read-only'));
     $this->assertNoField('edit-comment', t('Comment body field found.'));
 
     // Attempt to post to node with comments enabled (check field names etc).
-    $this->node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1, 'comment' => COMMENT_NODE_OPEN));
+    $this->node = $this->drupalCreateNode(array(
+      'type' => 'article', 
+      'promote' => 1, 
+      'comment' => COMMENT_NODE_OPEN
+    ));
     $this->assertTrue($this->node, t('Article node created.'));
     $this->drupalGet('comment/reply/' . $this->node->nid);
     $this->assertNoText('This discussion is closed', t('Posting to node with comments enabled'));
@@ -395,8 +475,9 @@ class CommentAnonymous extends CommentHe
     $this->drupalGet('comment/reply/' . $this->node->nid);
     $this->assertTrue($this->commentContactInfoAvailable(), t('Contact information available.'));
 
-    $anonymous_comment2 = $this->postComment($this->node, $this->randomName(), $this->randomName());
-    $this->assertTrue($this->commentExists($anonymous_comment2), t('Anonymous comment with contact info (optional) found.'));
+    $anonymous_comment_two = $this->postComment($this->node, $this->randomName(), $this->randomName());
+    $this->assertTrue($this->commentExists($anonymous_comment_two), 
+      t('Anonymous comment with contact info (optional) found.'));
 
     // Require contact info.
     $this->drupalLogin($this->admin_user);
@@ -407,32 +488,37 @@ class CommentAnonymous extends CommentHe
     $this->drupalGet('comment/reply/' . $this->node->nid);
     $this->assertTrue($this->commentContactInfoAvailable(), t('Contact information available.'));
 
-    $anonymous_comment3 = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE, TRUE);
-    $this->assertText(t('E-mail field is required.'), t('E-mail required.')); // Name should have 'Anonymous' for value by default.
-    $this->assertFalse($this->commentExists($anonymous_comment3), t('Anonymous comment with contact info (required) not found.'));
+    $anonymous_comment_three = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE, TRUE);
+    // Name should have 'Anonymous' for value by default.
+    $this->assertText(t('E-mail field is required.'), t('E-mail required.'));
+    $this->assertFalse($this->commentExists($anonymous_comment_three), 
+      t('Anonymous comment with contact info (required) not found.'));
 
     // Post comment with contact info (required).
-    $anonymous_comment3 = $this->postComment($this->node, $this->randomName(), $this->randomName(), TRUE, array('mail' => 'tester@simpletest.org'));
-    $this->assertTrue($this->commentExists($anonymous_comment3), t('Anonymous comment with contact info (required) found.'));
+    $anonymous_comment_three = 
+      $this->postComment($this->node, $this->randomName(), $this->randomName(), 
+        TRUE, array('mail' => 'tester@example.com'));
+    $this->assertTrue($this->commentExists($anonymous_comment_three), 
+      t('Anonymous comment with contact info (required) found.'));
 
     // Unpublish comment.
     $this->drupalLogin($this->admin_user);
-    $this->performCommentOperation($anonymous_comment3, 'unpublish');
+    $this->performCommentOperation($anonymous_comment_three, 'unpublish');
 
     $this->drupalGet('admin/content/comment/approval');
-    $this->assertRaw('comments[' . $anonymous_comment3->id . ']', t('Comment was unpublished.'));
+    $this->assertRaw('comments[' . $anonymous_comment_three->id . ']', t('Comment was unpublished.'));
 
     // Publish comment.
-    $this->performCommentOperation($anonymous_comment3, 'publish', TRUE);
+    $this->performCommentOperation($anonymous_comment_three, 'publish', TRUE);
 
     $this->drupalGet('admin/content/comment');
-    $this->assertRaw('comments[' . $anonymous_comment3->id . ']', t('Comment was published.'));
+    $this->assertRaw('comments[' . $anonymous_comment_three->id . ']', t('Comment was published.'));
 
     // Delete comment.
-    $this->performCommentOperation($anonymous_comment3, 'delete');
+    $this->performCommentOperation($anonymous_comment_three, 'delete');
 
     $this->drupalGet('admin/content/comment');
-    $this->assertNoRaw('comments[' . $anonymous_comment3->id . ']', t('Comment was deleted.'));
+    $this->assertNoRaw('comments[' . $anonymous_comment_three->id . ']', t('Comment was deleted.'));
 
     // Reset.
     $this->drupalLogin($this->admin_user);
@@ -477,24 +563,31 @@ class CommentApprovalTest extends Commen
     // Post anonymous comment without contact info.
     $subject = $this->randomName();
     $body = $this->randomName();
-    $this->postComment($this->node, $subject, $body, TRUE, TRUE); // Set $contact to true so that it won't check for id and message.
-    $this->assertText(t('Your comment has been queued for review by site administrators and will be published after approval.'), t('Comment requires approval.'));
+    // Set $contact to true so that it won't check for id and message.
+    $this->postComment($this->node, $subject, $body, TRUE, TRUE); 
+    $this->assertText(t('Your comment has been queued for review by site 
+      administrators and will be published after approval.'), 
+      t('Comment requires approval.'));
 
     // Get unapproved comment id.
     $this->drupalLogin($this->admin_user);
-    $anonymous_comment4 = $this->getUnapprovedComment($subject);
-    $anonymous_comment4 = (object) array('id' => $anonymous_comment4, 'subject' => $subject, 'comment' => $body);
+    $anonymous_comment_four = $this->getUnapprovedComment($subject);
+    $anonymous_comment_four = (object) array(
+      'id' => $anonymous_comment_four, 
+      'subject' => $subject, 
+      'comment' => $body
+    );
     $this->drupalLogout();
 
-    $this->assertFalse($this->commentExists($anonymous_comment4), t('Anonymous comment was not published.'));
+    $this->assertFalse($this->commentExists($anonymous_comment_four), t('Anonymous comment was not published.'));
 
     // Approve comment.
     $this->drupalLogin($this->admin_user);
-    $this->performCommentOperation($anonymous_comment4, 'publish', TRUE);
+    $this->performCommentOperation($anonymous_comment_four, 'publish', TRUE);
     $this->drupalLogout();
 
     $this->drupalGet('node/' . $this->node->nid);
-    $this->assertTrue($this->commentExists($anonymous_comment4), t('Anonymous comment visible.'));
+    $this->assertTrue($this->commentExists($anonymous_comment_four), t('Anonymous comment visible.'));
   }
 
   /**
@@ -511,25 +604,161 @@ class CommentApprovalTest extends Commen
     // Post anonymous comment without contact info.
     $subject = $this->randomName();
     $body = $this->randomName();
-    $this->postComment($this->node, $subject, $body, TRUE, TRUE); // Set $contact to true so that it won't check for id and message.
-    $this->assertText(t('Your comment has been queued for review by site administrators and will be published after approval.'), t('Comment requires approval.'));
+    // Set $contact to true so that it won't check for id and message.
+    $this->postComment($this->node, $subject, $body, TRUE, TRUE); 
+    $this->assertText(t('Your comment has been queued for review by site 
+      administrators and will be published after approval.'), 
+      t('Comment requires approval.'));
 
     // Get unapproved comment id.
     $this->drupalLogin($this->admin_user);
-    $anonymous_comment4 = $this->getUnapprovedComment($subject);
-    $anonymous_comment4 = (object) array('id' => $anonymous_comment4, 'subject' => $subject, 'comment' => $body);
+    $anonymous_comment_four = $this->getUnapprovedComment($subject);
+    $anonymous_comment_four = (object) array(
+      'id' => $anonymous_comment_four, 
+      'subject' => $subject, 
+      'comment' => $body
+    );
     $this->drupalLogout();
 
-    $this->assertFalse($this->commentExists($anonymous_comment4), t('Anonymous comment was not published.'));
+    $this->assertFalse($this->commentExists($anonymous_comment_four), t('Anonymous comment was not published.'));
 
     // Approve comment.
     $this->drupalLogin($this->admin_user);
-    $this->drupalGet('node/'. $this->node->nid);
+    $this->drupalGet('node/' . $this->node->nid);
     $this->clickLink(t('approve'));
     $this->drupalLogout();
 
-    $this->drupalGet('node/'. $this->node->nid);
-    $this->assertTrue($this->commentExists($anonymous_comment4), t('Anonymous comment visible.'));
+    $this->drupalGet('node/' . $this->node->nid);
+    $this->assertTrue($this->commentExists($anonymous_comment_four), t('Anonymous comment visible.'));
+  }
+}
+
+/**
+ * Threading tests for comments.
+ */
+class CommentThreadingTest extends CommentHelperCase {
+  function getInfo() {
+    return array(
+      'name' => t('Comment thread settings'),
+      'description' => t('Test threading of comments and their settings.'),
+      'group' => t('Comment'),
+    );
+  }
+
+  /**
+   * Test the four collapsed / expanded modes:
+   * COMMENT_MODE_FLAT_COLLAPSED
+   * COMMENT_MODE_THREADED_COLLAPSED
+   * COMMENT_MODE_FLAT_EXPANDED
+   * COMMENT_MODE_THREADED_EXPANDED
+   *
+   * We don't need special tests in this function for collapsed vs. expanded
+   * with respect to showing or hiding comment body. Those tests are built
+   * into CommentHelperCase::commentExists .
+   */
+  function testExpandedCollapsed() {
+    $this->drupalLogin($this->admin_user);
+    $this->setCommentForm(TRUE);
+    $this->setCommentSubject(TRUE);
+    $this->setCommentPreview(FALSE);
+
+    $node = $this->drupalCreateNode(array('type' => 'article', 'promote' => 1));
+    $comment_one = $this->postComment($node, $this->randomName(), $this->randomName(), FALSE, TRUE);
+    $comment_two = $this->postComment($node, $this->randomName(), $this->randomName(), FALSE, TRUE);
+
+    // Post a reply to test threading.
+    $this->drupalGet('comment/reply/' . $node->nid . '/' . $comment_one->id);
+    $reply_one = $this->postComment(null, $this->randomName(), $this->randomName(), FALSE, TRUE);
+
+    // Post a reply to the reply to further test threading.
+    $this->drupalGet('comment/reply/' . $node->nid . '/' . $reply_one->id);
+    $reply_two = $this->postComment(null, $this->randomName(), $this->randomName(), FALSE, TRUE);
+
+    $pattern = '/<div class="indented">(<a id="new">)?<a id="comment-' . $reply_one->id . '">/';
+    $xpath = '//div[@class="indented"]/div[@class="indented"]/a[@id="comment-' . $reply_two->id . '"]';
+
+    $this->setCommentsPerPage(2);
+
+    // In flat view, the replies should not be on the first page, even though
+    // they're replies to the oldest comment. This is not a paging test, but
+    // it's easier than checking the DOM.
+    // ==================================
+    // = TESTS FOR FLAT, COLLAPSED MODE =
+    // ==================================
+    $this->setCommentSettings('comment_default_mode', COMMENT_MODE_FLAT_COLLAPSED,
+      t('Switched to flat, collapsed mode.'));
+    $this->drupalGet('node/' . $node->nid, array('query' => 'page=0'));
+    $this->assertFalse($this->commentExists($reply_one, TRUE),
+      t('Flat, collapsed mode is flattened on page 1 (1).'), 'Comment');
+    $this->assertFalse($this->commentExists($reply_two, TRUE),
+      t('Flat, expanded mode is flattened on page 1 (2).'), 'Comment');
+
+    // And where they exist, they should not be indented
+    $this->drupalGet('node/' . $node->nid, array('query' => 'page=1'));
+    $this->assertTrue($this->commentExists($reply_one, TRUE),
+      t('Flat, collapsed mode is flattened on page 2.'), 'Comment');
+    $this->assertNoPattern($pattern, t('Flat, collapsed reply is not indented'), 'Comment');
+    $this->assertFalse($this->xpath($xpath));
+
+    // =================================
+    // = TESTS FOR FLAT, EXPANDED MODE =
+    // =================================
+    $this->setCommentSettings('comment_default_mode', COMMENT_MODE_FLAT_EXPANDED,
+      t('Switched to flat, expanded mode.'));
+    $this->drupalGet('node/' . $node->nid, array('query' => 'page=0'));
+    $this->assertFalse($this->commentExists($reply_one, TRUE),
+      t('Flat, expanded mode reply 1 is flattened on page 1.'), 'Comment');
+    $this->assertFalse($this->commentExists($reply_two, TRUE),
+      t('Flat, expanded mode reply 2 is flattened on page 1.'), 'Comment');
+
+    // Replies should not be indented in flat mode.
+    $this->drupalGet('node/' . $node->nid, array('query' => 'page=1'));
+    $this->assertTrue($this->commentExists($reply_one, TRUE),
+      t('Flat, expanded mode reply 1 is flattened on page 2.'), 'Comment');
+    $this->assertTrue($this->commentExists($reply_two, TRUE),
+      t('Flat, expanded mode reply 2 is flattened on page 2.'), 'Comment');
+    $this->assertNoPattern($pattern, t('Flat, expanded reply is not indented.'), 'Comment');
+    $this->assertFalse($this->xpath($xpath), t('Flat, expanded reply 2 is not indented.'), 'Comment');
+
+    // In threaded mode, the replies on the oldest comment should appear
+    // on the first page, while comment 2 should be bumped to the second.
+    // This is not a paging test, but it's easier than checking the DOM.
+    // ======================================
+    // = TESTS FOR THREADED, COLLAPSED MODE =
+    // ======================================
+    $this->setCommentsPerPage(3);
+    $this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED_COLLAPSED,
+      t('Switched to threaded, collapsed mode.'));
+    $this->drupalGet('node/' . $node->nid, array('query' => 'page=0'));
+    $this->assertTrue($this->commentExists($reply_one, TRUE),
+      t('Threaded, collapsed mode is threaded on page 1 (1).'), 'Comment');
+    $this->assertTrue($this->commentExists($reply_two, TRUE),
+      t('Threaded, collapsed mode is threaded on page 1 (2).'), 'Comment');
+    $this->assertFalse($this->commentExists($comment_two, TRUE),
+      t('Threaded, collapsed mode is threaded on page 1 (3).'), 'Comment');
+
+    // Replies should be indented in threaded, expanded mode.
+    $this->assertPattern($pattern, t('Threaded, collapsed reply is indented'), 'Comment');
+    $this->assertTrue($this->xpath($xpath),
+      t('Threaded, collapsed reply to a reply is double-indented'), 'Comment');
+
+    // =====================================
+    // = TESTS FOR THREADED, EXPANDED MODE =
+    // =====================================
+    $this->setCommentSettings('comment_default_mode', COMMENT_MODE_THREADED_EXPANDED,
+      t('Switched to threaded, expanded mode.'));
+    $this->drupalGet('node/' . $node->nid, array('query' => 'page=0'));
+    $this->assertTrue($this->commentExists($reply_one, TRUE),
+      t('Threaded, expanded mode is threaded on page 1 (1).'), 'Comment');
+    $this->assertTrue($this->commentExists($reply_two, TRUE),
+      t('Threaded, expanded mode is threaded on page 1 (2).'), 'Comment');
+    $this->assertFalse($this->commentExists($comment_two, TRUE),
+      t('Threaded, expanded mode is threaded on page 1 (3).'), 'Comment');
+
+    // Replies should be indented in threaded, expanded mode.
+    $this->assertPattern($pattern, t('Threaded, expanded reply is indented'), 'Comment');
+    $this->assertTrue($this->xpath($xpath),
+      t('Threaded, expanded reply to a reply is double-indented'), 'Comment');
   }
 }
 
@@ -567,9 +796,9 @@ class CommentBlockFunctionalTest extends
     $this->assertText(t('The block configuration has been saved.'), t('Block saved.'));
 
     // Add some test comments, one without a subject.
-    $comment1 = $this->postComment($this->node, $this->randomName(), $this->randomName());
-    $comment2 = $this->postComment($this->node, $this->randomName(), $this->randomName());
-    $comment3 = $this->postComment($this->node, '', $this->randomName());
+    $comment_one = $this->postComment($this->node, $this->randomName(), $this->randomName());
+    $comment_two = $this->postComment($this->node, $this->randomName(), $this->randomName());
+    $comment_three = $this->postComment($this->node, '', $this->randomName());
 
     // Test that a user without the 'access comments' permission can not see the block.
     $this->drupalLogout();
@@ -581,24 +810,25 @@ class CommentBlockFunctionalTest extends
     $this->assertText($block['title'], t('Block was found.'));
 
     // Test the only the 2 latest comments are shown and in the proper order.
-    $this->assertNoText($comment1->subject, t('Comment not found in block.'));
-    $this->assertText($comment2->subject, t('Comment found in block.'));
-    $this->assertText($comment3->comment, t('Comment found in block.'));
-    $this->assertTrue(strpos($this->drupalGetContent(), $comment3->comment) < strpos($this->drupalGetContent(), $comment2->subject), t('Comments were ordered correctly in block.'));
+    $this->assertNoText($comment_one->subject, t('Comment not found in block.'));
+    $this->assertText($comment_two->subject, t('Comment found in block.'));
+    $this->assertText($comment_three->comment, t('Comment found in block.'));
+    $this->assertTrue(
+      strpos($this->drupalGetContent(), $comment_three->comment) 
+      < strpos($this->drupalGetContent(), $comment_two->subject), 
+      t('Comments were ordered correctly in block.'));
 
     // Set the number of recent comments to show to 10.
     $this->drupalLogout();
     $this->drupalLogin($this->admin_user);
-    $block = array(
-      'comment_block_count' => 10,
-    );
+    $block = array('comment_block_count' => 10);
     $this->drupalPost('admin/build/block/configure/comment/recent', $block, t('Save block'));
     $this->assertText(t('The block configuration has been saved.'), t('Block saved.'));
 
     // Test that all three comments are shown.
-    $this->assertText($comment1->subject, t('Comment found in block.'));
-    $this->assertText($comment2->subject, t('Comment found in block.'));
-    $this->assertText($comment3->comment, t('Comment found in block.'));
+    $this->assertText($comment_one->subject, t('Comment found in block.'));
+    $this->assertText($comment_two->subject, t('Comment found in block.'));
+    $this->assertText($comment_three->comment, t('Comment found in block.'));
   }
 }
 
@@ -621,7 +851,7 @@ class CommentRSSUnitTest extends Comment
     $this->drupalLogin($this->web_user);
     $comment = $this->postComment($this->node, $this->randomName(), $this->randomName());
     $this->drupalGet('rss.xml');
-    $raw = '<comments>' . url('node/' . $this->node->nid, array('fragment' => 'comments', 'absolute' => TRUE)) . '</comments>';
-    $this->assertRaw($raw, t('Comments as part of RSS feed.'));
+    $url = url('node/' . $this->node->nid, array('fragment' => 'comments', 'absolute' => TRUE));
+    $this->assertRaw('<comments>' . $url . '</comments>', t('Comments as part of RSS feed.'));
   }
 }
