Don't merge threads on same line left/right

Goes along with c/95273/. Adds commentSide attribute to comments to see
which side of the diff view they belong on. This is also used as part
of the locationRange for the gr-diff-comment-thread-group, so that two
thread groups can be on the same line or range for the unified group (
one for the right, one for the left).

Note: there is already a 'side' attribute on the gr-diff-comment, which
is confusing. This side actually references 'PARENT' or 'REVISION', to
identify whether the comment belongs to the parent or any revision. On
diffs where two revisions are compared to each other, this cannot be
used to determine left/right. However, because 'side' is part of
the CommentInfo entity[1], it is difficult to change the name and make
more sense out of that.

[1] https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#comment-info

Bug: Issue 5114
Change-Id: I5cc4c17d4bb134e31e5cc07ff9b08ed349488c97
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
index 9c03d23..7143427 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.html
@@ -208,9 +208,9 @@
         },
 
         createCommentThreadGroup: function(changeNum, patchNum, path, side,
-            projectConfig) {
+            commentSide, projectConfig) {
           return this._builder.createCommentThreadGroup(changeNum, patchNum,
-              path, side, projectConfig);
+              path, side, commentSide, projectConfig);
         },
 
         emitGroup: function(group, sectionEl) {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
index 761fd32..c27c57e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder.js
@@ -315,6 +315,9 @@
     var rightComments =
         comments[GrDiffBuilder.Side.RIGHT].filter(byLineNum(line.afterNumber));
 
+    leftComments.forEach(function(c) { c.__commentSide = 'left'; });
+    rightComments.forEach(function(c) { c.__commentSide = 'right'; });
+
     var result;
 
     switch (opt_side) {
@@ -332,8 +335,8 @@
     return result;
   };
 
-  GrDiffBuilder.prototype.createCommentThreadGroup =
-      function(changeNum, patchNum, path, side, projectConfig, range) {
+  GrDiffBuilder.prototype.createCommentThreadGroup = function(changeNum,
+      patchNum, path, side, projectConfig, range) {
     var threadGroupEl =
         document.createElement('gr-diff-comment-thread-group');
     threadGroupEl.changeNum = changeNum;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
index ad316bb..4665bdf 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder_test.html
@@ -207,17 +207,23 @@
         ],
       };
       assert.deepEqual(builder._getCommentsForLine(comments, line),
-          [{id: 'l3', line: 3}, {id: 'r5', line: 5}]);
+          [{id: 'l3', line: 3, __commentSide: 'left'},
+          {id: 'r5', line: 5, __commentSide: 'right'}]);
       assert.deepEqual(builder._getCommentsForLine(comments, line,
-          GrDiffBuilder.Side.LEFT), [{id: 'l3', line: 3}]);
+          GrDiffBuilder.Side.LEFT), [{id: 'l3', line: 3,
+          __commentSide: 'left'}]);
       assert.deepEqual(builder._getCommentsForLine(comments, line,
-          GrDiffBuilder.Side.RIGHT), [{id: 'r5', line: 5}]);
+          GrDiffBuilder.Side.RIGHT), [{id: 'r5', line: 5,
+          __commentSide: 'right'}]);
     });
 
     test('comment thread group creation', function() {
-      var l3 = {id: 'l3', line: 3, updated: '2016-08-09 00:42:32.000000000'};
-      var l5 = {id: 'l5', line: 5, updated: '2016-08-09 00:42:32.000000000'};
-      var r5 = {id: 'r5', line: 5, updated: '2016-08-09 00:42:32.000000000'};
+      var l3 = {id: 'l3', line: 3, updated: '2016-08-09 00:42:32.000000000',
+          __commentSide: 'left'};
+      var l5 = {id: 'l5', line: 5, updated: '2016-08-09 00:42:32.000000000',
+          __commentSide: 'left'};
+      var r5 = {id: 'r5', line: 5, updated: '2016-08-09 00:42:32.000000000',
+          __commentSide: 'right'};
 
       builder._comments = {
         meta: {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
index 05f7a1d..2c44813 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.html
@@ -29,6 +29,7 @@
         as="thread">
       <gr-diff-comment-thread
           comments="[[thread.comments]]"
+          comment-side="[[thread.commentSide]]"
           change-num="[[changeNum]]"
           location-range="[[thread.locationRange]]"
           patch-num="[[patchNum]]"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
index 9c5626d..da1fe05 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group.js
@@ -40,7 +40,7 @@
       '_commentsChanged(comments.*)',
     ],
 
-    addNewThread: function(locationRange) {
+    addNewThread: function(locationRange, commentSide) {
       this.push('_threadGroups', {
         comments: [],
         locationRange: locationRange,
@@ -78,11 +78,12 @@
       });
     },
 
-    _calculateLocationRange: function(range) {
+    _calculateLocationRange: function(range, comment) {
       return 'range-' + range.start_line + '-' +
           range.start_character + '-' +
           range.end_line + '-' +
-          range.end_character;
+          range.end_character + '-' +
+          comment.__commentSide;
     },
 
     _getThreadGroups: function(comments) {
@@ -91,9 +92,9 @@
       comments.forEach(function(comment) {
         var locationRange;
         if (!comment.range) {
-          locationRange = 'line';
+          locationRange = 'line-' + comment.__commentSide;
         } else {
-          locationRange = this._calculateLocationRange(comment.range);
+          locationRange = this._calculateLocationRange(comment.range, comment);
         }
 
         if (threadGroups[locationRange]) {
@@ -103,6 +104,7 @@
             start_datetime: comment.updated,
             comments: [comment],
             locationRange: locationRange,
+            commentSide: comment.__commentSide,
           };
         }
       }.bind(this));
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
index 6c7fd60..0a50199 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread-group/gr-diff-comment-thread-group_test.html
@@ -54,26 +54,31 @@
           id: 'sallys_confession',
           message: 'i like you, jack',
           updated: '2015-12-23 15:00:20.396000000',
+          __commentSide: 'left',
         }, {
           id: 'jacks_reply',
           message: 'i like you, too',
           updated: '2015-12-24 15:00:20.396000000',
+          __commentSide: 'left',
         },
       ];
 
       var expectedThreadGroups = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
+          commentSide: 'left',
           comments: [{
               id: 'sallys_confession',
               message: 'i like you, jack',
               updated: '2015-12-23 15:00:20.396000000',
+              __commentSide: 'left',
             }, {
               id: 'jacks_reply',
               message: 'i like you, too',
               updated: '2015-12-24 15:00:20.396000000',
+              __commentSide: 'left',
             }],
-          locationRange: 'line',
+          locationRange: 'line-left',
         },
       ];
 
@@ -89,25 +94,30 @@
             start_character: 1,
             end_line: 1,
             end_character: 2,
-          }
+          },
+          __commentSide: 'left',
         });
 
       expectedThreadGroups = [
         {
           start_datetime: '2015-12-23 15:00:20.396000000',
+          commentSide: 'left',
           comments: [{
               id: 'sallys_confession',
               message: 'i like you, jack',
               updated: '2015-12-23 15:00:20.396000000',
+              __commentSide: 'left',
             }, {
               id: 'jacks_reply',
               message: 'i like you, too',
               updated: '2015-12-24 15:00:20.396000000',
+              __commentSide: 'left',
             }],
-          locationRange: 'line',
+          locationRange: 'line-left',
         },
         {
           start_datetime: '2015-12-24 15:00:10.396000000',
+          commentSide: 'left',
           comments: [{
             id: 'betsys_confession',
             message: 'i like you, jack',
@@ -118,8 +128,9 @@
               end_line: 1,
               end_character: 2,
             },
+            __commentSide: 'left',
           }],
-          locationRange: 'range-1-1-1-2',
+          locationRange: 'range-1-1-1-2-left',
         },
       ];
 
@@ -157,13 +168,15 @@
     });
 
     test('_calculateLocationRange', function() {
+      var comment = {__commentSide: 'left'};
       var range = {
         start_line: 1,
         start_character: 2,
         end_line: 3,
         end_character: 4,
       };
-      assert.equal(element._calculateLocationRange(range), 'range-1-2-3-4');
+      assert.equal(
+        element._calculateLocationRange(range, comment), 'range-1-2-3-4-left');
     });
 
     test('thread groups are updated when comments change', function() {
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
index 3a0c3ad..fcd7574 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.html
@@ -43,6 +43,7 @@
             patch-num="[[patchNum]]"
             draft="[[comment.__draft]]"
             show-actions="[[_showActions]]"
+            comment-side="[[comment.__commentSide]]"
             project-config="[[projectConfig]]"
             on-comment-discard="_handleCommentDiscard"
             on-create-ack-comment="_handleCommentAck"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
index ffc11f3..9f450ea 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread.js
@@ -37,6 +37,7 @@
         type: Object,
         value: function() { return document.body; },
       },
+      commentSide: String,
       patchNum: String,
       path: String,
       projectConfig: Object,
@@ -245,6 +246,7 @@
         __date: new Date(),
         path: this.path,
         side: this.side,
+        __commentSide: this.commentSide,
       };
       if (opt_lineNum) {
         d.line = opt_lineNum;
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
index 53f22d4..41c160f 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment-thread/gr-diff-comment-thread_test.html
@@ -544,5 +544,11 @@
       assert.equal(element._computeHostClass(true), 'unresolved');
       assert.equal(element._computeHostClass(false), '');
     });
+
+    test('_newDraft', function() {
+      element.commentSide = 'left';
+      var draft = element._newDraft();
+      assert.equal(draft.__commentSide, 'left');
+    });
   });
 </script>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
index 69854a1..6d6227e 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment.js
@@ -114,6 +114,7 @@
         value: '',
         observer: '_messageTextChanged',
       },
+      commentSide: String,
 
       resolved: {
         type: Boolean,
@@ -171,6 +172,7 @@
           if (this.comment.__draftID) {
             comment.__draftID = this.comment.__draftID;
           }
+          comment.__commentSide = this.commentSide;
           this.comment = comment;
           this.editing = false;
           this._fireSave();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
index 3575ccc..6ea5b96 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff-comment/gr-diff-comment_test.html
@@ -258,11 +258,13 @@
       element.patchNum = 1;
       element.editing = false;
       element.comment = {
+        __commentSide: 'right',
         __draft: true,
         __draftID: 'temp_draft_id',
         path: '/path/to/file',
         line: 5,
       };
+      element.commentSide = 'right';
       sandbox = sinon.sandbox.create();
     });
 
@@ -470,6 +472,7 @@
       assert.deepEqual(fireStub.lastCall.args, [
         'comment-update', {
           comment: {
+            __commentSide: 'right',
             __draft: true,
             __draftID: 'temp_draft_id',
             __editing: true,
@@ -491,6 +494,7 @@
                'comment-save should be sent');
         assert.deepEqual(fireStub.lastCall.args[1], {
           comment: {
+            __commentSide: 'right',
             __draft: true,
             __draftID: 'temp_draft_id',
             __editing: false,
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
index 69eb000..1d5d1b6 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff.js
@@ -232,8 +232,8 @@
       var contentEl = contentText.parentElement;
       var patchNum = this._getPatchNumByLineAndContent(lineEl, contentEl);
       var side = this._getSideByLineAndContent(lineEl, contentEl);
-      var threadEl =
-          this._getOrCreateThreadAtLineRange(contentEl, patchNum, side, range);
+      var threadEl = this._getOrCreateThreadAtLineRange(contentEl, patchNum,
+          diffSide, side, range);
 
       threadEl.addDraft(line, range);
     },
@@ -242,9 +242,10 @@
       var contentText = this.$.diffBuilder.getContentByLineEl(lineEl);
       var contentEl = contentText.parentElement;
       var patchNum = this._getPatchNumByLineAndContent(lineEl, contentEl);
+      var commentSide = this._getCommentSideByLineAndContent(lineEl, contentEl);
       var side = this._getSideByLineAndContent(lineEl, contentEl);
-      var threadEl =
-          this._getOrCreateThreadAtLineRange(contentEl, patchNum, side);
+      var threadEl = this._getOrCreateThreadAtLineRange(contentEl, patchNum,
+          commentSide, side);
 
       threadEl.addOrEditDraft(opt_lineNum);
     },
@@ -257,28 +258,32 @@
       return contentEl.querySelector('gr-diff-comment-thread-group');
     },
 
-    _getOrCreateThreadAtLineRange: function(contentEl, patchNum, side, range) {
+    _getOrCreateThreadAtLineRange:
+        function(contentEl, patchNum, commentSide, side, range) {
       var rangeToCheck = range ?
           'range-' +
           range.startLine + '-' +
           range.startChar + '-' +
           range.endLine + '-' +
-          range.endChar : 'line';
+          range.endChar + '-' +
+          commentSide : 'line-' + commentSide;
 
       // Check if thread group exists.
       var threadGroupEl = this._getThreadGroupForLine(contentEl);
       if (!threadGroupEl) {
         threadGroupEl = this.$.diffBuilder.createCommentThreadGroup(
-          this.changeNum, patchNum, this.path, side, this.projectConfig);
+          this.changeNum, patchNum, this.path, side,
+          this.projectConfig);
         contentEl.appendChild(threadGroupEl);
       }
 
       var threadEl = this._getThreadForRange(threadGroupEl, rangeToCheck);
 
       if (!threadEl) {
-        threadGroupEl.addNewThread(rangeToCheck);
+        threadGroupEl.addNewThread(rangeToCheck, commentSide);
         Polymer.dom.flush();
         threadEl = this._getThreadForRange(threadGroupEl, rangeToCheck);
+        threadEl.commentSide = commentSide;
       }
       return threadEl;
     },
@@ -303,6 +308,15 @@
       return side;
     },
 
+    _getCommentSideByLineAndContent: function(lineEl, contentEl) {
+      var side = 'right';
+      if (lineEl.classList.contains(DiffSide.LEFT) ||
+          contentEl.classList.contains('remove')) {
+        side = 'left';
+      }
+      return side;
+    },
+
     _handleThreadDiscard: function(e) {
       var el = Polymer.dom(e).rootTarget;
       el.parentNode.removeThread(el.locationRange);
@@ -314,29 +328,20 @@
     },
 
     _removeComment: function(comment, opt_patchNum) {
-      var side = this._findCommentSide(comment, opt_patchNum);
+      var side = comment.__commentSide;
       this._removeCommentFromSide(comment, side);
     },
 
-    _findCommentSide: function(comment, opt_patchNum) {
-      if (comment.side === 'PARENT') {
-        return DiffSide.LEFT;
-      } else {
-        return this._comments.meta.patchRange.basePatchNum === opt_patchNum ?
-            DiffSide.LEFT : DiffSide.RIGHT;
-      }
-    },
-
     _handleCommentSave: function(e) {
       var comment = e.detail.comment;
-      var side = this._findCommentSide(comment, e.detail.patchNum);
+      var side = e.detail.comment.__commentSide;
       var idx = this._findDraftIndex(comment, side);
       this.set(['_comments', side, idx], comment);
     },
 
     _handleCommentUpdate: function(e) {
       var comment = e.detail.comment;
-      var side = this._findCommentSide(comment, e.detail.patchNum);
+      var side = e.detail.comment.__commentSide;
       var idx = this._findCommentIndex(comment, side);
       if (idx === -1) {
         idx = this._findDraftIndex(comment, side);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
index 158a9a2..d676ebe 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
+++ b/polygerrit-ui/app/elements/diff/gr-diff/gr-diff_test.html
@@ -128,16 +128,16 @@
             projectConfig: {foo: 'bar'},
           },
           left: [
-            {id: 'bc1', side: 'PARENT'},
-            {id: 'bc2', side: 'PARENT'},
-            {id: 'bd1', __draft: true, side: 'PARENT'},
-            {id: 'bd2', __draft: true, side: 'PARENT'},
+            {id: 'bc1', side: 'PARENT', __commentSide: 'left'},
+            {id: 'bc2', side: 'PARENT', __commentSide: 'left'},
+            {id: 'bd1', __draft: true, side: 'PARENT', __commentSide: 'left'},
+            {id: 'bd2', __draft: true, side: 'PARENT', __commentSide: 'left'},
           ],
           right: [
-            {id: 'c1'},
-            {id: 'c2'},
-            {id: 'd1', __draft: true},
-            {id: 'd2', __draft: true},
+            {id: 'c1', __commentSide: 'right'},
+            {id: 'c2', __commentSide: 'right'},
+            {id: 'd1', __draft: true, __commentSide: 'right'},
+            {id: 'd2', __draft: true, __commentSide: 'right'},
           ],
         };
 
@@ -155,21 +155,22 @@
             projectConfig: {foo: 'bar'},
           },
           left: [
-            {id: 'bc1', side: 'PARENT'},
-            {id: 'bc2', side: 'PARENT'},
-            {id: 'bd1', __draft: true, side: 'PARENT'},
-            {id: 'bd2', __draft: true, side: 'PARENT'},
+            {id: 'bc1', side: 'PARENT', __commentSide: 'left'},
+            {id: 'bc2', side: 'PARENT', __commentSide: 'left'},
+            {id: 'bd1', __draft: true, side: 'PARENT', __commentSide: 'left'},
+            {id: 'bd2', __draft: true, side: 'PARENT', __commentSide: 'left'},
           ],
           right: [
-            {id: 'c1'},
-            {id: 'c2'},
-            {id: 'd1', __draft: true},
-            {id: 'd2', __draft: true},
+            {id: 'c1', __commentSide: 'right'},
+            {id: 'c2', __commentSide: 'right'},
+            {id: 'd1', __draft: true, __commentSide: 'right'},
+            {id: 'd2', __draft: true, __commentSide: 'right'},
           ],
         }));
 
-        element._removeComment({id: 'bc2', side: 'PARENT'});
-        assert.equal(JSON.stringify(element._comments), JSON.stringify({
+        element._removeComment({id: 'bc2', side: 'PARENT',
+            __commentSide: 'left'});
+        assert.deepEqual(element._comments, {
           meta: {
             changeNum: '42',
             patchRange: {
@@ -180,20 +181,20 @@
             projectConfig: {foo: 'bar'},
           },
           left: [
-            {id: 'bc1', side: 'PARENT'},
-            {id: 'bd1', __draft: true, side: 'PARENT'},
-            {id: 'bd2', __draft: true, side: 'PARENT'},
+            {id: 'bc1', side: 'PARENT', __commentSide: 'left'},
+            {id: 'bd1', __draft: true, side: 'PARENT', __commentSide: 'left'},
+            {id: 'bd2', __draft: true, side: 'PARENT', __commentSide: 'left'},
           ],
           right: [
-            {id: 'c1'},
-            {id: 'c2'},
-            {id: 'd1', __draft: true},
-            {id: 'd2', __draft: true},
+            {id: 'c1', __commentSide: 'right'},
+            {id: 'c2', __commentSide: 'right'},
+            {id: 'd1', __draft: true, __commentSide: 'right'},
+            {id: 'd2', __draft: true, __commentSide: 'right'},
           ],
-        }));
+        });
 
-        element._removeComment({id: 'd2'});
-        assert.deepEqual(JSON.stringify(element._comments), JSON.stringify({
+        element._removeComment({id: 'd2', __commentSide: 'right'});
+        assert.deepEqual(element._comments, {
           meta: {
             changeNum: '42',
             patchRange: {
@@ -204,21 +205,22 @@
             projectConfig: {foo: 'bar'},
           },
           left: [
-            {id: 'bc1', side: 'PARENT'},
-            {id: 'bd1', __draft: true, side: 'PARENT'},
-            {id: 'bd2', __draft: true, side: 'PARENT'},
+            {id: 'bc1', side: 'PARENT', __commentSide: 'left'},
+            {id: 'bd1', __draft: true, side: 'PARENT', __commentSide: 'left'},
+            {id: 'bd2', __draft: true, side: 'PARENT', __commentSide: 'left'},
           ],
           right: [
-            {id: 'c1'},
-            {id: 'c2'},
-            {id: 'd1', __draft: true},
+            {id: 'c1', __commentSide: 'right'},
+            {id: 'c2', __commentSide: 'right'},
+            {id: 'd1', __draft: true, __commentSide: 'right'},
           ],
-        }));
+        });
       });
 
       test('thread groups', function() {
         var contentEl = document.createElement('div');
-        var rangeToCheck = 'line';
+        var rangeToCheck = 'line-left';
+        var commentSide = 'left';
         var patchNum = 1;
         var side = 'PARENT';
         var range = {
@@ -228,6 +230,10 @@
           endChar: 2,
         };
 
+        element.changeNum = 123;
+        element.patchRange = {basePatchNum: 1, patchNum: 2};
+        element.path = 'file.txt';
+
         sandbox.stub(element.$.diffBuilder, 'createCommentThreadGroup',
             function() {
           return document.createElement('gr-diff-comment-thread-group');
@@ -237,8 +243,8 @@
         assert.isNotOk(element._getThreadGroupForLine(contentEl));
 
         // A thread group gets created.
-        assert.isOk(
-            element._getOrCreateThreadAtLineRange(contentEl, patchNum, side));
+        assert.isOk(element._getOrCreateThreadAtLineRange(contentEl, patchNum,
+            commentSide, side));
 
         // Try to fetch a thread with a different range.
         range = {
@@ -249,7 +255,7 @@
         };
 
         assert.isOk(element._getOrCreateThreadAtLineRange(
-            contentEl, patchNum, side, range));
+            contentEl, patchNum, commentSide, side, range));
         // The new thread group can be fetched.
         assert.isOk(element._getThreadGroupForLine(contentEl));
 
@@ -443,12 +449,12 @@
       test('get comments and drafts', function(done) {
         var comments = {
           baseComments: [
-            {id: 'bc1'},
-            {id: 'bc2'},
+            {id: 'bc1', __commentSide: 'left'},
+            {id: 'bc2', __commentSide: 'left'},
           ],
           comments: [
-            {id: 'c1'},
-            {id: 'c2'},
+            {id: 'c1', __commentSide: 'right'},
+            {id: 'c2', __commentSide: 'right'},
           ],
         };
         var diffCommentsStub = sandbox.stub(element, '_getDiffComments',
@@ -456,12 +462,12 @@
 
         var drafts = {
           baseComments: [
-            {id: 'bd1'},
-            {id: 'bd2'},
+            {id: 'bd1', __commentSide: 'left'},
+            {id: 'bd2', __commentSide: 'left'},
           ],
           comments: [
-            {id: 'd1'},
-            {id: 'd2'},
+            {id: 'd1', __commentSide: 'right'},
+            {id: 'd2', __commentSide: 'right'},
           ],
         };
 
@@ -470,12 +476,12 @@
 
         var robotComments = {
           baseComments: [
-            {id: 'br1'},
-            {id: 'br2'},
+            {id: 'br1', __commentSide: 'left'},
+            {id: 'br2', __commentSide: 'left'},
           ],
           comments: [
-            {id: 'r1'},
-            {id: 'r2'},
+            {id: 'r1', __commentSide: 'right'},
+            {id: 'r2', __commentSide: 'right'},
           ],
         };
 
@@ -503,20 +509,20 @@
               projectConfig: {foo: 'bar'},
             },
             left: [
-              {id: 'bc1'},
-              {id: 'bc2'},
-              {id: 'bd1', __draft: true},
-              {id: 'bd2', __draft: true},
-              {id: 'br1'},
-              {id: 'br2'},
+              {id: 'bc1', __commentSide: 'left'},
+              {id: 'bc2', __commentSide: 'left'},
+              {id: 'bd1', __draft: true, __commentSide: 'left'},
+              {id: 'bd2', __draft: true, __commentSide: 'left'},
+              {id: 'br1', __commentSide: 'left'},
+              {id: 'br2', __commentSide: 'left'},
             ],
             right: [
-              {id: 'c1'},
-              {id: 'c2'},
-              {id: 'd1', __draft: true},
-              {id: 'd2', __draft: true},
-              {id: 'r1'},
-              {id: 'r2'},
+              {id: 'c1', __commentSide: 'right'},
+              {id: 'c2', __commentSide: 'right'},
+              {id: 'd1', __draft: true, __commentSide: 'right'},
+              {id: 'd2', __draft: true, __commentSide: 'right'},
+              {id: 'r1', __commentSide: 'right'},
+              {id: 'r2', __commentSide: 'right'},
             ],
           });
 
@@ -538,22 +544,23 @@
               projectConfig: {foo: 'bar'},
             },
             left: [
-              {id: 'bc1', side: 'PARENT'},
-              {id: 'bc2', side: 'PARENT'},
-              {id: 'bd1', __draft: true, side: 'PARENT'},
-              {id: 'bd2', __draft: true, side: 'PARENT'},
+              {id: 'bc1', side: 'PARENT', __commentSide: 'left'},
+              {id: 'bc2', side: 'PARENT', __commentSide: 'left'},
+              {id: 'bd1', __draft: true, side: 'PARENT', __commentSide: 'left'},
+              {id: 'bd2', __draft: true, side: 'PARENT', __commentSide: 'left'},
             ],
             right: [
-              {id: 'c1'},
-              {id: 'c2'},
-              {id: 'd1', __draft: true},
-              {id: 'd2', __draft: true},
+              {id: 'c1', __commentSide: 'right'},
+              {id: 'c2', __commentSide: 'right'},
+              {id: 'd1', __draft: true, __commentSide: 'right'},
+              {id: 'd2', __draft: true, __commentSide: 'right'},
             ],
           };
         });
 
         test('creating a draft', function() {
-          var comment = {__draft: true, __draftID: 'tempID', side: 'PARENT'};
+          var comment = {__draft: true, __draftID: 'tempID', side: 'PARENT',
+              __commentSide: 'left'};
           element.fire('comment-update', {comment: comment});
           assert.include(element._comments.left, comment);
         });
@@ -562,9 +569,11 @@
           var draftID = 'tempID';
           var id = 'savedID';
           element._comments.left.push(
-              {__draft: true, __draftID: draftID, side: 'PARENT'});
+              {__draft: true, __draftID: draftID, side: 'PARENT',
+              __commentSide: 'left'});
           element.fire('comment-update', {comment:
-              {id: id, __draft: true, __draftID: draftID, side: 'PARENT'},
+              {id: id, __draft: true, __draftID: draftID, side: 'PARENT',
+              __commentSide: 'left'},
           });
           var drafts = element._comments.left.filter(function(item) {
             return item.__draftID === draftID;