Merge "Cut dep from highlight onto comment model"

This commit is contained in:
Ole Rehmsen
2018-11-13 22:22:51 +00:00
committed by Gerrit Code Review
8 changed files with 235 additions and 219 deletions

View File

@@ -29,7 +29,7 @@ limitations under the License.
</div> </div>
<gr-ranged-comment-layer <gr-ranged-comment-layer
id="rangeLayer" id="rangeLayer"
comments="[[comments]]"></gr-ranged-comment-layer> comment-ranges="[[commentRanges]]"></gr-ranged-comment-layer>
<gr-syntax-layer <gr-syntax-layer
id="syntaxLayer" id="syntaxLayer"
diff="[[diff]]"></gr-syntax-layer> diff="[[diff]]"></gr-syntax-layer>
@@ -109,7 +109,6 @@ limitations under the License.
changeNum: String, changeNum: String,
patchNum: String, patchNum: String,
viewMode: String, viewMode: String,
comments: Object,
isImageDiff: Boolean, isImageDiff: Boolean,
baseImage: Object, baseImage: Object,
revisionImage: Object, revisionImage: Object,
@@ -125,6 +124,10 @@ limitations under the License.
_groups: Array, _groups: Array,
_layers: Array, _layers: Array,
_showTabs: Boolean, _showTabs: Boolean,
/** @type {!Array<!Gerrit.HoveredRange>} */
commentRanges: {
type: Array,
},
}, },
get diffElement() { get diffElement() {

View File

@@ -389,7 +389,7 @@ limitations under the License.
test('_handlePreferenceError called with invalid preference', () => { test('_handlePreferenceError called with invalid preference', () => {
sandbox.stub(element, '_handlePreferenceError'); sandbox.stub(element, '_handlePreferenceError');
const prefs = {tab_size: 0}; const prefs = {tab_size: 0};
element._getDiffBuilder(element.diff, element.comments, prefs); element._getDiffBuilder(element.diff, undefined, prefs);
assert.isTrue(element._handlePreferenceError.lastCall assert.isTrue(element._handlePreferenceError.lastCall
.calledWithExactly('tab size')); .calledWithExactly('tab size'));
}); });

View File

@@ -21,7 +21,11 @@
is: 'gr-diff-highlight', is: 'gr-diff-highlight',
properties: { properties: {
comments: Object, /** @type {!Array<!Gerrit.HoveredRange>} */
commentRanges: {
type: Array,
notify: true,
},
loggedIn: Boolean, loggedIn: Boolean,
/** /**
* querySelector can return null, so needs to be nullable. * querySelector can return null, so needs to be nullable.
@@ -71,35 +75,44 @@
}, },
_handleCommentMouseOver(e) { _handleCommentMouseOver(e) {
const comment = e.detail.comment; const threadEl = Polymer.dom(e).localTarget;
if (!comment.range) { return; } const index = this._indexForThreadEl(threadEl);
const lineEl = this.diffBuilder.getLineElByChild(e.target);
const side = this.diffBuilder.getSideByLineEl(lineEl);
const index = this._indexOfComment(side, comment);
if (index !== undefined) { if (index !== undefined) {
this.set(['comments', side, index, '__hovering'], true); this.set(['commentRanges', index, 'hovering'], true);
} }
}, },
_handleCommentMouseOut(e) { _handleCommentMouseOut(e) {
const comment = e.detail.comment; const threadEl = Polymer.dom(e).localTarget;
if (!comment.range) { return; } const index = this._indexForThreadEl(threadEl);
const lineEl = this.diffBuilder.getLineElByChild(e.target);
const side = this.diffBuilder.getSideByLineEl(lineEl);
const index = this._indexOfComment(side, comment);
if (index !== undefined) { if (index !== undefined) {
this.set(['comments', side, index, '__hovering'], false); this.set(['commentRanges', index, 'hovering'], false);
} }
}, },
_indexOfComment(side, comment) { _indexForThreadEl(threadEl) {
const idProp = comment.id ? 'id' : '__draftID'; const side = threadEl.getAttribute('comment-side');
for (let i = 0; i < this.comments[side].length; i++) { const range = JSON.parse(threadEl.getAttribute('range'));
if (comment[idProp] &&
this.comments[side][i][idProp] === comment[idProp]) { if (!range) return undefined;
return i;
} return this._indexOfCommentRange(side, range);
},
_indexOfCommentRange(side, range) {
function rangesEqual(a, b) {
if (!a && !b) { return true; }
if (!a || !b) { return false; }
return a.start_line === b.start_line &&
a.start_character === b.start_character &&
a.end_line === b.end_line &&
a.end_character === b.end_character;
} }
return this.commentRanges.findIndex(commentRange =>
commentRange.side === side && rangesEqual(commentRange.range, range));
}, },
/** /**

View File

@@ -205,7 +205,7 @@ limitations under the License.
test('comment-mouse-over from ranged comment causes set', () => { test('comment-mouse-over from ranged comment causes set', () => {
sandbox.stub(element, 'set'); sandbox.stub(element, 'set');
sandbox.stub(element, '_indexOfComment').returns(0); sandbox.stub(element, '_indexForThreadEl').returns(0);
element.fire('comment-mouse-over', {comment: {range: {}}}); element.fire('comment-mouse-over', {comment: {range: {}}});
assert.isTrue(element.set.called); assert.isTrue(element.set.called);
}); });

View File

@@ -280,10 +280,10 @@ limitations under the License.
<gr-diff-highlight <gr-diff-highlight
id="highlights" id="highlights"
logged-in="[[loggedIn]]" logged-in="[[loggedIn]]"
comments="{{comments}}"> comment-ranges="{{_commentRanges}}">
<gr-diff-builder <gr-diff-builder
id="diffBuilder" id="diffBuilder"
comments="[[comments]]" comment-ranges="[[_commentRanges]]"
project-name="[[projectName]]" project-name="[[projectName]]"
diff="[[diff]]" diff="[[diff]]"
diff-path="[[path]]" diff-path="[[path]]"

View File

@@ -43,6 +43,11 @@
* end_line: number, end_character: number}} */ * end_line: number, end_character: number}} */
Gerrit.Range; Gerrit.Range;
function isThreadEl(node) {
return node.nodeType === Node.ELEMENT_NODE &&
node.classList.contains('comment-thread');
}
Polymer({ Polymer({
is: 'gr-diff', is: 'gr-diff',
@@ -100,6 +105,11 @@
type: Object, type: Object,
value: {left: [], right: []}, value: {left: [], right: []},
}, },
/** @type {!Array<!Gerrit.HoveredRange>} */
_commentRanges: {
type: Array,
value: [],
},
lineWrapping: { lineWrapping: {
type: Boolean, type: Boolean,
value: false, value: false,
@@ -185,7 +195,19 @@
_diffLength: Number, _diffLength: Number,
/** @type {?PolymerDomApi.ObserveHandle} */ /**
* Observes comment nodes added or removed after the initial render.
* Can be used to unregister when the entire diff is (re-)rendered or upon
* detachment.
* @type {?PolymerDomApi.ObserveHandle}
*/
_incrementalNodeObserver: Object,
/**
* Observes comment nodes added or removed at any point.
* Can be used to unregister upon detachment.
* @type {?PolymerDomApi.ObserveHandle}
*/
_nodeObserver: Object, _nodeObserver: Object,
}, },
@@ -201,10 +223,36 @@
'render-content': '_handleRenderContent', 'render-content': '_handleRenderContent',
}, },
attached() {
this._updateRangesWhenNodesChange();
},
detached() { detached() {
this._unobserveIncrementalNodes();
this._unobserveNodes(); this._unobserveNodes();
}, },
_updateRangesWhenNodesChange() {
function commentRangeFromThreadEl(threadEl) {
const side = threadEl.getAttribute('comment-side');
const range = JSON.parse(threadEl.getAttribute('range'));
return {side, range, hovering: false};
}
this._nodeObserver = Polymer.dom(this).observeNodes(info => {
const addedThreadEls = info.addedNodes.filter(isThreadEl);
const addedCommentRanges = addedThreadEls
.map(commentRangeFromThreadEl)
.filter(({range}) => range);
this.push('_commentRanges', ...addedCommentRanges);
// In principal we should also handle removed nodes, but I have not
// figured out how to do that yet without also catching all the removals
// caused by further redistribution. Right now, comments are never
// removed by no longer slotting them in, so I decided to not handle
// this situation until it occurs.
});
},
/** Cancel any remaining diff builder rendering work. */ /** Cancel any remaining diff builder rendering work. */
cancel() { cancel() {
this.$.diffBuilder.cancel(); this.$.diffBuilder.cancel();
@@ -577,7 +625,7 @@
}, },
_renderDiffTable() { _renderDiffTable() {
this._unobserveNodes(); this._unobserveIncrementalNodes();
if (!this.prefs) { if (!this.prefs) {
this.dispatchEvent(new CustomEvent('render', {bubbles: true})); this.dispatchEvent(new CustomEvent('render', {bubbles: true}));
return; return;
@@ -595,9 +643,8 @@
}, },
_handleRenderContent() { _handleRenderContent() {
this._nodeObserver = Polymer.dom(this).observeNodes(info => { this._incrementalNodeObserver = Polymer.dom(this).observeNodes(info => {
const addedThreadEls = info.addedNodes.filter( const addedThreadEls = info.addedNodes.filter(isThreadEl);
node => node.nodeType === Node.ELEMENT_NODE);
// In principal we should also handle removed nodes, but I have not // In principal we should also handle removed nodes, but I have not
// figured out how to do that yet without also catching all the removals // figured out how to do that yet without also catching all the removals
// caused by further redistribution. Right now, comments are never // caused by further redistribution. Right now, comments are never
@@ -616,6 +663,12 @@
}); });
}, },
_unobserveIncrementalNodes() {
if (this._incrementalNodeObserver) {
Polymer.dom(this).unobserveNodes(this._incrementalNodeObserver);
}
},
_unobserveNodes() { _unobserveNodes() {
if (this._nodeObserver) { if (this._nodeObserver) {
Polymer.dom(this).unobserveNodes(this._nodeObserver); Polymer.dom(this).unobserveNodes(this._nodeObserver);
@@ -633,7 +686,7 @@
}, },
clearDiffContent() { clearDiffContent() {
this._unobserveNodes(); this._unobserveIncrementalNodes();
this.$.diffTable.innerHTML = null; this.$.diffTable.innerHTML = null;
}, },

View File

@@ -17,31 +17,34 @@
(function() { (function() {
'use strict'; 'use strict';
const HOVER_PATH_PATTERN = /^comments\.(left|right)\.\#(\d+)\.__hovering$/; const HOVER_PATH_PATTERN = /^commentRanges\.\#(\d+)\.hovering$/;
const SPLICE_PATH_PATTERN = /^comments\.(left|right)\.splices$/;
const RANGE_HIGHLIGHT = 'range'; const RANGE_HIGHLIGHT = 'range';
const HOVER_HIGHLIGHT = 'rangeHighlight'; const HOVER_HIGHLIGHT = 'rangeHighlight';
const NORMALIZE_RANGE_EVENT = 'normalize-range'; const NORMALIZE_RANGE_EVENT = 'normalize-range';
/** @typedef {{side: string, range: Gerrit.Range, hovering: boolean}} */
Gerrit.HoveredRange;
Polymer({ Polymer({
is: 'gr-ranged-comment-layer', is: 'gr-ranged-comment-layer',
properties: { properties: {
comments: Object, /** @type {!Array<!Gerrit.HoveredRange>} */
commentRanges: Array,
_listeners: { _listeners: {
type: Array, type: Array,
value() { return []; }, value() { return []; },
}, },
_commentMap: { _rangesMap: {
type: Object, type: Object,
value() { return {left: [], right: []}; }, value() { return {left: {}, right: {}}; },
}, },
}, },
observers: [ observers: [
'_handleCommentChange(comments.*)', '_handleCommentRangesChange(commentRanges.*)',
], ],
/** /**
@@ -93,97 +96,78 @@
}, },
/** /**
* Handle change in the comments by updating the comment maps and by * Handle change in the ranges by updating the ranges maps and by
* emitting appropriate update notifications. * emitting appropriate update notifications.
* @param {Object} record The change record. * @param {Object} record The change record.
*/ */
_handleCommentChange(record) { _handleCommentRangesChange(record) {
if (!record.path) { return; } if (!record) return;
// If the entire set of comments was changed. // If the entire set of comments was changed.
if (record.path === 'comments') { if (record.path === 'commentRanges') {
this._commentMap.left = this._computeCommentMap(this.comments.left); this._rangesMap = {left: {}, right: {}};
this._commentMap.right = this._computeCommentMap(this.comments.right); for (const {side, range, hovering} of record.value) {
return; this._updateRangesMap(
} side, range, hovering, (forLine, start, end, hovering) => {
forLine.push({start, end, hovering});
// If the change only changed the `hovering` property of a comment.
let match = record.path.match(HOVER_PATH_PATTERN);
let side;
if (match) {
side = match[1];
const index = match[2];
const comment = this.comments[side][index];
if (comment && comment.range) {
this._commentMap[side] = this._computeCommentMap(this.comments[side]);
this._notifyUpdateRange(
comment.range.start_line, comment.range.end_line, side);
}
return;
}
// If comments were spliced in or out.
match = record.path.match(SPLICE_PATH_PATTERN);
if (match) {
side = match[1];
this._commentMap[side] = this._computeCommentMap(this.comments[side]);
this._handleCommentSplice(record.value, side);
}
},
/**
* Take a list of comments and return a sparse list mapping line numbers to
* partial ranges. Uses an end-character-index of -1 to indicate the end of
* the line.
* @param {?} commentList The list of comments.
* Getting this param to match closure requirements caused problems.
* @return {!Object} The sparse list.
*/
_computeCommentMap(commentList) {
const result = {};
for (const comment of commentList) {
if (!comment.range) { continue; }
const range = comment.range;
for (let line = range.start_line; line <= range.end_line; line++) {
if (!result[line]) { result[line] = []; }
result[line].push({
comment,
start: line === range.start_line ? range.start_character : 0,
end: line === range.end_line ? range.end_character : -1,
}); });
} }
} }
return result;
// If the change only changed the `hovering` property of a comment.
const match = record.path.match(HOVER_PATH_PATTERN);
if (match) {
const commentRangesIndex = match[1];
const {side, range, hovering} = this.commentRanges[commentRangesIndex];
this._updateRangesMap(
side, range, hovering, (forLine, start, end, hovering) => {
const index = forLine.findIndex(lineRange =>
lineRange.start === start && lineRange.end === end);
forLine[index].hovering = hovering;
});
}
// If comments were spliced in or out.
if (record.path === 'commentRanges.splices') {
for (const indexSplice of record.value.indexSplices) {
const removed = indexSplice.removed;
for (const {side, range, hovering} of removed) {
this._updateRangesMap(
side, range, hovering, (forLine, start, end) => {
const index = forLine.findIndex(lineRange =>
lineRange.start === start && lineRange.end === end);
forLine.splice(index, 1);
});
}
const added = indexSplice.object.slice(
indexSplice.index, indexSplice.index + indexSplice.addedCount);
for (const {side, range, hovering} of added) {
this._updateRangesMap(
side, range, hovering, (forLine, start, end, hovering) => {
forLine.push({start, end, hovering});
});
}
}
}
}, },
/** _updateRangesMap(side, range, hovering, operation) {
* Translate a splice record into range update notifications. const forSide = this._rangesMap[side] || (this._rangesMap[side] = {});
*/ for (let line = range.start_line; line <= range.end_line; line++) {
_handleCommentSplice(record, side) { const forLine = forSide[line] || (forSide[line] = []);
if (!record || !record.indexSplices) { return; } const start = line === range.start_line ? range.start_character : 0;
const end = line === range.end_line ? range.end_character : -1;
for (const splice of record.indexSplices) { operation(forLine, start, end, hovering);
const ranges = splice.removed.length ? }
splice.removed.map(c => { return c.range; }) :
[splice.object[splice.index].range];
for (const range of ranges) {
if (!range) { continue; }
this._notifyUpdateRange(range.start_line, range.end_line, side); this._notifyUpdateRange(range.start_line, range.end_line, side);
}
}
}, },
_getRangesForLine(line, side) { _getRangesForLine(line, side) {
const lineNum = side === 'left' ? line.beforeNumber : line.afterNumber; const lineNum = side === 'left' ? line.beforeNumber : line.afterNumber;
const ranges = this.get(['_commentMap', side, lineNum]) || []; const ranges = this.get(['_rangesMap', side, lineNum]) || [];
return ranges return ranges
.map(range => { .map(range => {
range = { range.end = range.end === -1 ? line.text.length : range.end;
start: range.start,
end: range.end === -1 ? line.text.length : range.end,
hovering: !!range.comment.__hovering,
};
// Normalize invalid ranges where the start is after the end but the // Normalize invalid ranges where the start is after the end but the
// start still makes sense. Set the end to the end of the line. // start still makes sense. Set the end to the end of the line.

View File

@@ -40,49 +40,36 @@ limitations under the License.
let sandbox; let sandbox;
setup(() => { setup(() => {
const initialComments = { const initialCommentRanges = [
left: [
{ {
id: '12345', side: 'left',
line: 39,
message: 'range comment',
range: { range: {
end_character: 9, end_character: 9,
end_line: 39, end_line: 39,
start_character: 6, start_character: 6,
start_line: 36, start_line: 36,
}, },
}, {
id: '23456',
line: 100,
message: 'non range comment',
}, },
],
right: [
{ {
id: '34567', side: 'right',
line: 10,
message: 'range comment',
range: { range: {
end_character: 22, end_character: 22,
end_line: 12, end_line: 12,
start_character: 10, start_character: 10,
start_line: 10, start_line: 10,
}, },
}, { },
id: '45678', {
line: 100, side: 'right',
message: 'single line range comment',
range: { range: {
end_character: 15, end_character: 15,
end_line: 100, end_line: 100,
start_character: 5, start_character: 5,
start_line: 100, start_line: 100,
}, },
}, { },
id: '8675309', {
line: 55, side: 'right',
message: 'nonsense range',
range: { range: {
end_character: 2, end_character: 2,
end_line: 55, end_line: 55,
@@ -90,12 +77,11 @@ limitations under the License.
start_line: 55, start_line: 55,
}, },
}, },
], ];
};
sandbox = sinon.sandbox.create(); sandbox = sinon.sandbox.create();
element = fixture('basic'); element = fixture('basic');
element.comments = initialComments; element.commentRanges = initialCommentRanges;
}); });
teardown(() => { teardown(() => {
@@ -149,7 +135,7 @@ limitations under the License.
test('type=Remove has-comment hovering', () => { test('type=Remove has-comment hovering', () => {
line.type = GrDiffLine.Type.REMOVE; line.type = GrDiffLine.Type.REMOVE;
line.beforeNumber = 36; line.beforeNumber = 36;
element.set(['comments', 'left', 0, '__hovering'], true); element.set(['commentRanges', 0, 'hovering'], true);
const expectedStart = 6; const expectedStart = 6;
const expectedLength = line.text.length - expectedStart; const expectedLength = line.text.length - expectedStart;
@@ -210,29 +196,18 @@ limitations under the License.
}); });
}); });
test('_handleCommentChange overwrite', () => { test('_handleCommentRangesChange overwrite', () => {
const handlerSpy = sandbox.spy(element, '_handleCommentChange'); element.set('commentRanges', []);
const mapSpy = sandbox.spy(element, '_computeCommentMap');
element.set('comments', {left: [], right: []}); assert.equal(Object.keys(element._rangesMap.left).length, 0);
assert.equal(Object.keys(element._rangesMap.right).length, 0);
assert.isTrue(handlerSpy.called);
assert.equal(mapSpy.callCount, 2);
assert.equal(Object.keys(element._commentMap.left).length, 0);
assert.equal(Object.keys(element._commentMap.right).length, 0);
}); });
test('_handleCommentChange hovering', () => { test('_handleCommentRangesChange hovering', () => {
const handlerSpy = sandbox.spy(element, '_handleCommentChange');
const mapSpy = sandbox.spy(element, '_computeCommentMap');
const notifyStub = sinon.stub(); const notifyStub = sinon.stub();
element.addListener(notifyStub); element.addListener(notifyStub);
element.set(['comments', 'right', 0, '__hovering'], true); element.set(['commentRanges', 1, 'hovering'], true);
assert.isTrue(handlerSpy.called);
assert.isTrue(mapSpy.called);
assert.isTrue(notifyStub.called); assert.isTrue(notifyStub.called);
const lastCall = notifyStub.lastCall; const lastCall = notifyStub.lastCall;
@@ -241,16 +216,11 @@ limitations under the License.
assert.equal(lastCall.args[2], 'right'); assert.equal(lastCall.args[2], 'right');
}); });
test('_handleCommentChange splice out', () => { test('_handleCommentRangesChange splice out', () => {
const handlerSpy = sandbox.spy(element, '_handleCommentChange');
const mapSpy = sandbox.spy(element, '_computeCommentMap');
const notifyStub = sinon.stub(); const notifyStub = sinon.stub();
element.addListener(notifyStub); element.addListener(notifyStub);
element.splice('comments.right', 0, 1); element.splice('commentRanges', 1, 1);
assert.isTrue(handlerSpy.called);
assert.isTrue(mapSpy.called);
assert.isTrue(notifyStub.called); assert.isTrue(notifyStub.called);
const lastCall = notifyStub.lastCall; const lastCall = notifyStub.lastCall;
@@ -259,16 +229,12 @@ limitations under the License.
assert.equal(lastCall.args[2], 'right'); assert.equal(lastCall.args[2], 'right');
}); });
test('_handleCommentChange splice in', () => { test('_handleCommentRangesChange splice in', () => {
const handlerSpy = sandbox.spy(element, '_handleCommentChange');
const mapSpy = sandbox.spy(element, '_computeCommentMap');
const notifyStub = sinon.stub(); const notifyStub = sinon.stub();
element.addListener(notifyStub); element.addListener(notifyStub);
element.splice('comments.left', element.comments.left.length, 0, { element.splice('commentRanges', 1, 0, {
id: '56123', side: 'left',
line: 250,
message: 'new range comment',
range: { range: {
end_character: 15, end_character: 15,
end_line: 275, end_line: 275,
@@ -277,9 +243,6 @@ limitations under the License.
}, },
}); });
assert.isTrue(handlerSpy.called);
assert.isTrue(mapSpy.called);
assert.isTrue(notifyStub.called); assert.isTrue(notifyStub.called);
const lastCall = notifyStub.lastCall; const lastCall = notifyStub.lastCall;
assert.equal(lastCall.args[0], 250); assert.equal(lastCall.args[0], 250);
@@ -291,48 +254,48 @@ limitations under the License.
// There is only one ranged comment on the left, but it spans ll.36-39. // There is only one ranged comment on the left, but it spans ll.36-39.
const leftKeys = []; const leftKeys = [];
for (let i = 36; i <= 39; i++) { leftKeys.push('' + i); } for (let i = 36; i <= 39; i++) { leftKeys.push('' + i); }
assert.deepEqual(Object.keys(element._commentMap.left).sort(), assert.deepEqual(Object.keys(element._rangesMap.left).sort(),
leftKeys.sort()); leftKeys.sort());
assert.equal(element._commentMap.left[36].length, 1); assert.equal(element._rangesMap.left[36].length, 1);
assert.equal(element._commentMap.left[36][0].start, 6); assert.equal(element._rangesMap.left[36][0].start, 6);
assert.equal(element._commentMap.left[36][0].end, -1); assert.equal(element._rangesMap.left[36][0].end, -1);
assert.equal(element._commentMap.left[37].length, 1); assert.equal(element._rangesMap.left[37].length, 1);
assert.equal(element._commentMap.left[37][0].start, 0); assert.equal(element._rangesMap.left[37][0].start, 0);
assert.equal(element._commentMap.left[37][0].end, -1); assert.equal(element._rangesMap.left[37][0].end, -1);
assert.equal(element._commentMap.left[38].length, 1); assert.equal(element._rangesMap.left[38].length, 1);
assert.equal(element._commentMap.left[38][0].start, 0); assert.equal(element._rangesMap.left[38][0].start, 0);
assert.equal(element._commentMap.left[38][0].end, -1); assert.equal(element._rangesMap.left[38][0].end, -1);
assert.equal(element._commentMap.left[39].length, 1); assert.equal(element._rangesMap.left[39].length, 1);
assert.equal(element._commentMap.left[39][0].start, 0); assert.equal(element._rangesMap.left[39][0].start, 0);
assert.equal(element._commentMap.left[39][0].end, 9); assert.equal(element._rangesMap.left[39][0].end, 9);
// The right has two ranged comments, one spanning ll.10-12 and the other // The right has two ranged comments, one spanning ll.10-12 and the other
// on line 100. // on line 100.
const rightKeys = []; const rightKeys = [];
for (let i = 10; i <= 12; i++) { rightKeys.push('' + i); } for (let i = 10; i <= 12; i++) { rightKeys.push('' + i); }
rightKeys.push('55', '100'); rightKeys.push('55', '100');
assert.deepEqual(Object.keys(element._commentMap.right).sort(), assert.deepEqual(Object.keys(element._rangesMap.right).sort(),
rightKeys.sort()); rightKeys.sort());
assert.equal(element._commentMap.right[10].length, 1); assert.equal(element._rangesMap.right[10].length, 1);
assert.equal(element._commentMap.right[10][0].start, 10); assert.equal(element._rangesMap.right[10][0].start, 10);
assert.equal(element._commentMap.right[10][0].end, -1); assert.equal(element._rangesMap.right[10][0].end, -1);
assert.equal(element._commentMap.right[11].length, 1); assert.equal(element._rangesMap.right[11].length, 1);
assert.equal(element._commentMap.right[11][0].start, 0); assert.equal(element._rangesMap.right[11][0].start, 0);
assert.equal(element._commentMap.right[11][0].end, -1); assert.equal(element._rangesMap.right[11][0].end, -1);
assert.equal(element._commentMap.right[12].length, 1); assert.equal(element._rangesMap.right[12].length, 1);
assert.equal(element._commentMap.right[12][0].start, 0); assert.equal(element._rangesMap.right[12][0].start, 0);
assert.equal(element._commentMap.right[12][0].end, 22); assert.equal(element._rangesMap.right[12][0].end, 22);
assert.equal(element._commentMap.right[100].length, 1); assert.equal(element._rangesMap.right[100].length, 1);
assert.equal(element._commentMap.right[100][0].start, 5); assert.equal(element._rangesMap.right[100][0].start, 5);
assert.equal(element._commentMap.right[100][0].end, 15); assert.equal(element._rangesMap.right[100][0].end, 15);
}); });
test('_getRangesForLine normalizes invalid ranges', () => { test('_getRangesForLine normalizes invalid ranges', () => {