Merge "Separates diff processing from diff building"
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
index 1896c76..feb21e2 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
+++ b/polygerrit-ui/app/elements/diff/gr-diff-builder/gr-diff-builder-image.js
@@ -28,9 +28,7 @@
GrDiffBuilderSideBySide.prototype);
GrDiffBuilderImage.prototype.constructor = GrDiffBuilderImage;
- GrDiffBuilderImage.prototype.emitDiff = function() {
- this.emitGroup(this._groups[0]);
-
+ GrDiffBuilderImage.prototype.renderDiffImages = function() {
var section = this._createElement('tbody', 'image-diff');
this._emitImagePair(section);
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 315692a..3f92e44 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
@@ -14,12 +14,14 @@
limitations under the License.
-->
<link rel="import" href="../../../bower_components/polymer/polymer.html">
+<link rel="import" href="../gr-diff-processor/gr-diff-processor.html">
<dom-module id="gr-diff-builder">
<template>
<div class="contentWrapper">
<content></content>
</div>
+ <gr-diff-processor id="processor"></gr-diff-processor>
</template>
<script src="../gr-diff/gr-diff-line.js"></script>
<script src="../gr-diff/gr-diff-group.js"></script>
@@ -59,7 +61,11 @@
render: function(diff, comments, prefs) {
this._builder = this._getDiffBuilder(diff, comments, prefs);
- this._renderDiff();
+
+ this.$.processor.context = prefs.context;
+ this.$.processor.keyLocations = this._getCommentLocations(comments);
+ this.$.processor.process(diff.content)
+ .then(this._renderDiff.bind(this));
},
getLineElByChild: function(node) {
@@ -176,7 +182,7 @@
},
showContext: function(newGroups, sectionEl) {
- var groups = this._builder._groups;
+ var groups = this._builder.groups;
// TODO(viktard): Polyfill findIndex for IE10.
var contextIndex = groups.findIndex(function(group) {
return group.element == sectionEl;
@@ -207,9 +213,14 @@
throw Error('Unsupported diff view mode: ' + this.viewMode);
},
- _renderDiff: function() {
+ _renderDiff: function(groups) {
+ this._builder.groups = groups;
+
this._clearDiffContent();
this.emitDiff();
+ if (this.isImageDiff) {
+ this._builder.renderDiffImages();
+ }
this.async(function() {
this.fire('render');
}, 1);
@@ -218,6 +229,23 @@
_clearDiffContent: function() {
this.diffElement.innerHTML = null;
},
+
+ _getCommentLocations: function(comments) {
+ var result = {
+ left: {},
+ right: {},
+ };
+ for (var side in comments) {
+ if (side !== GrDiffBuilder.Side.LEFT &&
+ side !== GrDiffBuilder.Side.RIGHT) {
+ continue;
+ }
+ comments[side].forEach(function(c) {
+ result[side][c.line || GrDiffLine.FILE] = true;
+ });
+ }
+ return result;
+ },
});
})();
</script>
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 b96423e..896b60e 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
@@ -22,10 +22,7 @@
this._comments = comments;
this._prefs = prefs;
this._outputEl = outputEl;
- this._groups = [];
-
- this._commentLocations = this._getCommentLocations(comments);
- this._processContent(diff.content, this._groups, prefs.context);
+ this.groups = [];
}
GrDiffBuilder.LESS_THAN_CODE = '<'.charCodeAt(0);
@@ -63,8 +60,8 @@
var PARTIAL_CONTEXT_AMOUNT = 10;
GrDiffBuilder.prototype.emitDiff = function() {
- for (var i = 0; i < this._groups.length; i++) {
- this.emitGroup(this._groups[i]);
+ for (var i = 0; i < this.groups.length; i++) {
+ this.emitGroup(this.groups[i]);
}
};
@@ -79,8 +76,8 @@
};
GrDiffBuilder.prototype.renderSection = function(element) {
- for (var i = 0; i < this._groups.length; i++) {
- var group = this._groups[i];
+ for (var i = 0; i < this.groups.length; i++) {
+ var group = this.groups[i];
if (group.element === element) {
var newElement = this.buildSectionElement(group);
group.element.parentElement.replaceChild(newElement, group.element);
@@ -93,8 +90,8 @@
GrDiffBuilder.prototype.getGroupsByLineRange = function(
startLine, endLine, opt_side) {
var groups = [];
- for (var i = 0; i < this._groups.length; i++) {
- var group = this._groups[i];
+ for (var i = 0; i < this.groups.length; i++) {
+ var group = this.groups[i];
if (group.lines.length === 0) {
continue;
}
@@ -139,196 +136,11 @@
function(group) { return group.element; });
};
- GrDiffBuilder.prototype._processContent = function(content, groups, context) {
- this._appendFileComments(groups);
-
- var WHOLE_FILE = -1;
- context = content.length > 1 ? context : WHOLE_FILE;
-
- var lineNums = {
- left: 0,
- right: 0,
- };
- content = this._splitCommonGroupsWithComments(content, lineNums);
- for (var i = 0; i < content.length; i++) {
- var group = content[i];
- var lines = [];
-
- if (group[GrDiffBuilder.GroupType.BOTH] !== undefined) {
- var rows = group[GrDiffBuilder.GroupType.BOTH];
- this._appendCommonLines(rows, lines, lineNums);
-
- var hiddenRange = [context, rows.length - context];
- if (i === 0) {
- hiddenRange[0] = 0;
- } else if (i === content.length - 1) {
- hiddenRange[1] = rows.length;
- }
-
- if (context !== WHOLE_FILE && hiddenRange[1] - hiddenRange[0] > 0) {
- this._insertContextGroups(groups, lines, hiddenRange);
- } else {
- groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, lines));
- }
- continue;
- }
-
- if (group[GrDiffBuilder.GroupType.REMOVED] !== undefined) {
- var highlights = undefined;
- if (group[GrDiffBuilder.Highlights.REMOVED] !== undefined) {
- highlights = this._normalizeIntralineHighlights(
- group[GrDiffBuilder.GroupType.REMOVED],
- group[GrDiffBuilder.Highlights.REMOVED]);
- }
- this._appendRemovedLines(group[GrDiffBuilder.GroupType.REMOVED], lines,
- lineNums, highlights);
- }
-
- if (group[GrDiffBuilder.GroupType.ADDED] !== undefined) {
- var highlights = undefined;
- if (group[GrDiffBuilder.Highlights.ADDED] !== undefined) {
- highlights = this._normalizeIntralineHighlights(
- group[GrDiffBuilder.GroupType.ADDED],
- group[GrDiffBuilder.Highlights.ADDED]);
- }
- this._appendAddedLines(group[GrDiffBuilder.GroupType.ADDED], lines,
- lineNums, highlights);
- }
- groups.push(new GrDiffGroup(GrDiffGroup.Type.DELTA, lines));
- }
- };
-
- GrDiffBuilder.prototype._appendFileComments = function(groups) {
- var line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.beforeNumber = GrDiffLine.FILE;
- line.afterNumber = GrDiffLine.FILE;
- groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, [line]));
- };
-
- GrDiffBuilder.prototype._getCommentLocations = function(comments) {
- var result = {
- left: {},
- right: {},
- };
- for (var side in comments) {
- if (side !== GrDiffBuilder.Side.LEFT &&
- side !== GrDiffBuilder.Side.RIGHT) {
- continue;
- }
- comments[side].forEach(function(c) {
- result[side][c.line || GrDiffLine.FILE] = true;
- });
- }
- return result;
- };
-
GrDiffBuilder.prototype._commentIsAtLineNum = function(side, lineNum) {
return this._commentLocations[side][lineNum] === true;
};
- // In order to show comments out of the bounds of the selected context,
- // treat them as separate chunks within the model so that the content (and
- // context surrounding it) renders correctly.
- GrDiffBuilder.prototype._splitCommonGroupsWithComments = function(content,
- lineNums) {
- var result = [];
- var leftLineNum = lineNums.left;
- var rightLineNum = lineNums.right;
- for (var i = 0; i < content.length; i++) {
- if (!content[i].ab) {
- result.push(content[i]);
- if (content[i].a) {
- leftLineNum += content[i].a.length;
- }
- if (content[i].b) {
- rightLineNum += content[i].b.length;
- }
- continue;
- }
- var chunk = content[i].ab;
- var currentChunk = {ab: []};
- for (var j = 0; j < chunk.length; j++) {
- leftLineNum++;
- rightLineNum++;
- if (this._commentIsAtLineNum(GrDiffBuilder.Side.LEFT, leftLineNum) ||
- this._commentIsAtLineNum(GrDiffBuilder.Side.RIGHT, rightLineNum)) {
- if (currentChunk.ab && currentChunk.ab.length > 0) {
- result.push(currentChunk);
- currentChunk = {ab: []};
- }
- result.push({ab: [chunk[j]]});
- } else {
- currentChunk.ab.push(chunk[j]);
- }
- }
- // != instead of !== because we want to cover both undefined and null.
- if (currentChunk.ab != null && currentChunk.ab.length > 0) {
- result.push(currentChunk);
- }
- }
- return result;
- };
-
- // The `highlights` array consists of a list of <skip length, mark length>
- // pairs, where the skip length is the number of characters between the
- // end of the previous edit and the start of this edit, and the mark
- // length is the number of edited characters following the skip. The start
- // of the edits is from the beginning of the related diff content lines.
- //
- // Note that the implied newline character at the end of each line is
- // included in the length calculation, and thus it is possible for the
- // edits to span newlines.
- //
- // A line highlight object consists of three fields:
- // - contentIndex: The index of the diffChunk `content` field (the line
- // being referred to).
- // - startIndex: Where the highlight should begin.
- // - endIndex: (optional) Where the highlight should end. If omitted, the
- // highlight is meant to be a continuation onto the next line.
- GrDiffBuilder.prototype._normalizeIntralineHighlights = function(content,
- highlights) {
- var contentIndex = 0;
- var idx = 0;
- var normalized = [];
- for (var i = 0; i < highlights.length; i++) {
- var line = content[contentIndex] + '\n';
- var hl = highlights[i];
- var j = 0;
- while (j < hl[0]) {
- if (idx === line.length) {
- idx = 0;
- line = content[++contentIndex] + '\n';
- continue;
- }
- idx++;
- j++;
- }
- var lineHighlight = {
- contentIndex: contentIndex,
- startIndex: idx,
- };
-
- j = 0;
- while (line && j < hl[1]) {
- if (idx === line.length) {
- idx = 0;
- line = content[++contentIndex] + '\n';
- normalized.push(lineHighlight);
- lineHighlight = {
- contentIndex: contentIndex,
- startIndex: idx,
- };
- continue;
- }
- idx++;
- j++;
- }
- lineHighlight.endIndex = idx;
- normalized.push(lineHighlight);
- }
- return normalized;
- };
-
+ // TODO (wyatta): Move this completely into the processor.
GrDiffBuilder.prototype._insertContextGroups = function(groups, lines,
hiddenRange) {
var linesBeforeCtx = lines.slice(0, hiddenRange[0]);
@@ -350,46 +162,6 @@
}
};
- GrDiffBuilder.prototype._appendCommonLines = function(rows, lines, lineNums) {
- for (var i = 0; i < rows.length; i++) {
- var line = new GrDiffLine(GrDiffLine.Type.BOTH);
- line.text = rows[i];
- line.beforeNumber = ++lineNums.left;
- line.afterNumber = ++lineNums.right;
- lines.push(line);
- }
- };
-
- GrDiffBuilder.prototype._appendRemovedLines = function(rows, lines, lineNums,
- opt_highlights) {
- for (var i = 0; i < rows.length; i++) {
- var line = new GrDiffLine(GrDiffLine.Type.REMOVE);
- line.text = rows[i];
- line.beforeNumber = ++lineNums.left;
- if (opt_highlights) {
- line.highlights = opt_highlights.filter(function(hl) {
- return hl.contentIndex === i;
- });
- }
- lines.push(line);
- }
- };
-
- GrDiffBuilder.prototype._appendAddedLines = function(rows, lines, lineNums,
- opt_highlights) {
- for (var i = 0; i < rows.length; i++) {
- var line = new GrDiffLine(GrDiffLine.Type.ADD);
- line.text = rows[i];
- line.afterNumber = ++lineNums.right;
- if (opt_highlights) {
- line.highlights = opt_highlights.filter(function(hl) {
- return hl.contentIndex === i;
- });
- }
- lines.push(line);
- }
- };
-
GrDiffBuilder.prototype._createContextControl = function(section, line) {
if (!line.contextGroup || !line.contextGroup.lines.length) {
return null;
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 879d8592..cda4dc8 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
@@ -18,11 +18,23 @@
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<title>gr-diff-builder</title>
+<script src="../../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
<script src="../../../bower_components/web-component-tester/browser.js"></script>
<script src="../gr-diff/gr-diff-line.js"></script>
<script src="../gr-diff/gr-diff-group.js"></script>
<script src="gr-diff-builder.js"></script>
+<link rel="import" href="gr-diff-builder.html">
+
+<test-fixture id="basic">
+ <template>
+ <gr-diff-builder>
+ <table id="diffTable"></table>
+ </gr-diff-builder>
+ </template>
+</test-fixture>
+
+
<script>
suite('gr-diff-builder tests', function() {
var builder;
@@ -36,205 +48,6 @@
builder = new GrDiffBuilder({content: []}, {left: [], right: []}, prefs);
});
- test('process loaded content', function() {
- var content = [
- {
- ab: [
- '<!DOCTYPE html>',
- '<meta charset="utf-8">',
- ]
- },
- {
- a: [
- ' Welcome ',
- ' to the wooorld of tomorrow!',
- ],
- b: [
- ' Hello, world!',
- ],
- },
- {
- ab: [
- 'Leela: This is the only place the ship can’t hear us, so ',
- 'everyone pretend to shower.',
- 'Fry: Same as every day. Got it.',
- ]
- },
- ];
- var groups = [];
-
- builder._processContent(content, groups, -1);
-
- assert.equal(groups.length, 4);
-
- var group = groups[0];
- assert.equal(group.type, GrDiffGroup.Type.BOTH);
- assert.equal(group.lines.length, 1);
- assert.equal(group.lines[0].text, '');
- assert.equal(group.lines[0].beforeNumber, GrDiffLine.FILE);
- assert.equal(group.lines[0].afterNumber, GrDiffLine.FILE);
-
- group = groups[1];
- assert.equal(group.type, GrDiffGroup.Type.BOTH);
- assert.equal(group.lines.length, 2);
- assert.equal(group.lines.length, 2);
-
- function beforeNumberFn(l) { return l.beforeNumber; }
- function afterNumberFn(l) { return l.afterNumber; }
- function textFn(l) { return l.text; }
-
- assert.deepEqual(group.lines.map(beforeNumberFn), [1, 2]);
- assert.deepEqual(group.lines.map(afterNumberFn), [1, 2]);
- assert.deepEqual(group.lines.map(textFn), [
- '<!DOCTYPE html>',
- '<meta charset="utf-8">',
- ]);
-
- group = groups[2];
- assert.equal(group.type, GrDiffGroup.Type.DELTA);
- assert.equal(group.lines.length, 3);
- assert.equal(group.adds.length, 1);
- assert.equal(group.removes.length, 2);
- assert.deepEqual(group.removes.map(beforeNumberFn), [3, 4]);
- assert.deepEqual(group.adds.map(afterNumberFn), [3]);
- assert.deepEqual(group.removes.map(textFn), [
- ' Welcome ',
- ' to the wooorld of tomorrow!',
- ]);
- assert.deepEqual(group.adds.map(textFn), [
- ' Hello, world!',
- ]);
-
- group = groups[3];
- assert.equal(group.type, GrDiffGroup.Type.BOTH);
- assert.equal(group.lines.length, 3);
- assert.deepEqual(group.lines.map(beforeNumberFn), [5, 6, 7]);
- assert.deepEqual(group.lines.map(afterNumberFn), [4, 5, 6]);
- assert.deepEqual(group.lines.map(textFn), [
- 'Leela: This is the only place the ship can’t hear us, so ',
- 'everyone pretend to shower.',
- 'Fry: Same as every day. Got it.',
- ]);
- });
-
- test('insert context groups', function() {
- var content = [
- {ab: []},
- {a: ['all work and no play make andybons a dull boy']},
- {ab: []},
- {b: ['elgoog elgoog elgoog']},
- {ab: []},
- ];
- for (var i = 0; i < 100; i++) {
- content[0].ab.push('all work and no play make jack a dull boy');
- content[4].ab.push('all work and no play make jill a dull girl');
- }
- for (var i = 0; i < 5; i++) {
- content[2].ab.push('no tv and no beer make homer go crazy');
- }
- var groups = [];
- var context = 10;
-
- builder._processContent(content, groups, context);
-
- assert.equal(groups[0].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[0].lines.length, 1);
- assert.equal(groups[0].lines[0].text, '');
- assert.equal(groups[0].lines[0].beforeNumber, GrDiffLine.FILE);
- assert.equal(groups[0].lines[0].afterNumber, GrDiffLine.FILE);
-
- assert.equal(groups[1].type, GrDiffGroup.Type.CONTEXT_CONTROL);
- assert.instanceOf(groups[1].lines[0].contextGroup, GrDiffGroup);
- assert.equal(groups[1].lines[0].contextGroup.lines.length, 90);
- groups[1].lines[0].contextGroup.lines.forEach(function(l) {
- assert.equal(l.text, content[0].ab[0]);
- });
-
- assert.equal(groups[2].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[2].lines.length, context);
- groups[2].lines.forEach(function(l) {
- assert.equal(l.text, content[0].ab[0]);
- });
-
- assert.equal(groups[3].type, GrDiffGroup.Type.DELTA);
- assert.equal(groups[3].lines.length, 1);
- assert.equal(groups[3].removes.length, 1);
- assert.equal(groups[3].removes[0].text,
- 'all work and no play make andybons a dull boy');
-
- assert.equal(groups[4].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[4].lines.length, 5);
- groups[4].lines.forEach(function(l) {
- assert.equal(l.text, content[2].ab[0]);
- });
-
- assert.equal(groups[5].type, GrDiffGroup.Type.DELTA);
- assert.equal(groups[5].lines.length, 1);
- assert.equal(groups[5].adds.length, 1);
- assert.equal(groups[5].adds[0].text, 'elgoog elgoog elgoog');
-
- assert.equal(groups[6].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[6].lines.length, context);
- groups[6].lines.forEach(function(l) {
- assert.equal(l.text, content[4].ab[0]);
- });
-
- assert.equal(groups[7].type, GrDiffGroup.Type.CONTEXT_CONTROL);
- assert.instanceOf(groups[7].lines[0].contextGroup, GrDiffGroup);
- assert.equal(groups[7].lines[0].contextGroup.lines.length, 90);
- groups[7].lines[0].contextGroup.lines.forEach(function(l) {
- assert.equal(l.text, content[4].ab[0]);
- });
-
- content = [
- {a: ['all work and no play make andybons a dull boy']},
- {ab: []},
- {b: ['elgoog elgoog elgoog']},
- ];
- for (var i = 0; i < 50; i++) {
- content[1].ab.push('no tv and no beer make homer go crazy');
- }
- groups = [];
-
- builder._processContent(content, groups, 10);
-
- assert.equal(groups[0].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[0].lines.length, 1);
- assert.equal(groups[0].lines[0].text, '');
- assert.equal(groups[0].lines[0].beforeNumber, GrDiffLine.FILE);
- assert.equal(groups[0].lines[0].afterNumber, GrDiffLine.FILE);
-
- assert.equal(groups[1].type, GrDiffGroup.Type.DELTA);
- assert.equal(groups[1].lines.length, 1);
- assert.equal(groups[1].removes.length, 1);
- assert.equal(groups[1].removes[0].text,
- 'all work and no play make andybons a dull boy');
-
- assert.equal(groups[2].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[2].lines.length, context);
- groups[2].lines.forEach(function(l) {
- assert.equal(l.text, content[1].ab[0]);
- });
-
- assert.equal(groups[3].type, GrDiffGroup.Type.CONTEXT_CONTROL);
- assert.instanceOf(groups[3].lines[0].contextGroup, GrDiffGroup);
- assert.equal(groups[3].lines[0].contextGroup.lines.length, 30);
- groups[3].lines[0].contextGroup.lines.forEach(function(l) {
- assert.equal(l.text, content[1].ab[0]);
- });
-
- assert.equal(groups[4].type, GrDiffGroup.Type.BOTH);
- assert.equal(groups[4].lines.length, context);
- groups[4].lines.forEach(function(l) {
- assert.equal(l.text, content[1].ab[0]);
- });
-
- assert.equal(groups[5].type, GrDiffGroup.Type.DELTA);
- assert.equal(groups[5].lines.length, 1);
- assert.equal(groups[5].adds.length, 1);
- assert.equal(groups[5].adds[0].text, 'elgoog elgoog elgoog');
- });
-
test('context control buttons', function() {
var section = {};
var line = {contextGroup: {lines: []}};
@@ -412,153 +225,11 @@
[{id: 'l3', line: 3}, {id: 'r5', line: 5}]);
});
- test('break up common diff chunks', function() {
- builder._commentLocations = {
- left: {1: true},
- right: {10: true},
- };
- var lineNums = {
- left: 0,
- right: 0,
- };
- var content = [
- {
- ab: [
- 'Copyright (C) 2015 The Android Open Source Project',
- '',
- 'Licensed under the Apache License, Version 2.0 (the "License");',
- 'you may not use this file except in compliance with the License.',
- 'You may obtain a copy of the License at',
- '',
- 'http://www.apache.org/licenses/LICENSE-2.0',
- '',
- 'Unless required by applicable law or agreed to in writing, ',
- 'software distributed under the License is distributed on an ',
- '"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, ',
- 'either express or implied. See the License for the specific ',
- 'language governing permissions and limitations under the License.',
- ]
- }
- ];
- var result = builder._splitCommonGroupsWithComments(content, lineNums);
- assert.deepEqual(result, [
- {
- ab: ['Copyright (C) 2015 The Android Open Source Project'],
- },
- {
- ab: [
- '',
- 'Licensed under the Apache License, Version 2.0 (the "License");',
- 'you may not use this file except in compliance with the License.',
- 'You may obtain a copy of the License at',
- '',
- 'http://www.apache.org/licenses/LICENSE-2.0',
- '',
- 'Unless required by applicable law or agreed to in writing, ',
- ]
- },
- {
- ab: ['software distributed under the License is distributed on an '],
- },
- {
- ab: [
- '"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, ',
- 'either express or implied. See the License for the specific ',
- 'language governing permissions and limitations under the License.',
- ]
- }
- ]);
- });
-
- test('intraline normalization', function() {
- // The content and highlights are in the format returned by the Gerrit
- // REST API.
- var content = [
- ' <section class="summary">',
- ' <gr-linked-text content="' +
- '[[_computeCurrentRevisionMessage(change)]]"></gr-linked-text>',
- ' </section>',
- ];
- var highlights = [
- [31, 34], [42, 26]
- ];
- var results = GrDiffBuilder.prototype._normalizeIntralineHighlights(
- content, highlights);
- assert.deepEqual(results, [
- {
- contentIndex: 0,
- startIndex: 31,
- },
- {
- contentIndex: 1,
- startIndex: 0,
- endIndex: 33,
- },
- {
- contentIndex: 1,
- startIndex: 75,
- },
- {
- contentIndex: 2,
- startIndex: 0,
- endIndex: 6,
- }
- ]);
-
- content = [
- ' this._path = value.path;',
- '',
- ' // When navigating away from the page, there is a ' +
- 'possibility that the',
- ' // patch number is no longer a part of the URL ' +
- '(say when navigating to',
- ' // the top-level change info view) and therefore ' +
- 'undefined in `params`.',
- ' if (!this._patchRange.patchNum) {',
- ];
- highlights = [
- [14, 17],
- [11, 70],
- [12, 67],
- [12, 67],
- [14, 29],
- ];
- results = GrDiffBuilder.prototype._normalizeIntralineHighlights(content,
- highlights);
- assert.deepEqual(results, [
- {
- contentIndex: 0,
- startIndex: 14,
- endIndex: 31,
- },
- {
- contentIndex: 2,
- startIndex: 8,
- endIndex: 78,
- },
- {
- contentIndex: 3,
- startIndex: 11,
- endIndex: 78,
- },
- {
- contentIndex: 4,
- startIndex: 11,
- endIndex: 78,
- },
- {
- contentIndex: 5,
- startIndex: 12,
- endIndex: 41,
- }
- ]);
- });
-
suite('rendering', function() {
var content;
var outputEl;
- setup(function() {
+ setup(function(done) {
var prefs = {
line_length: 10,
show_tabs: true,
@@ -577,32 +248,38 @@
]
},
];
- outputEl = document.createElement('out');
- builder =
- new GrDiffBuilder(
- {content: content}, {left: [], right: []}, prefs, outputEl);
- builder.buildSectionElement = function(group) {
- var section = document.createElement('stub');
- section.textContent = group.lines.reduce(function(acc, line) {
- return acc + line.text;
- }, '');
- return section;
- };
- builder.emitDiff();
+ element = fixture('basic');
+ outputEl = element.queryEffectiveChildren('#diffTable');
+ element.addEventListener('render', function() {
+ done();
+ });
+ sinon.stub(element, '_getDiffBuilder', function() {
+ var builder = new GrDiffBuilder(
+ {content: content}, {left: [], right: []}, prefs, outputEl);
+ builder.buildSectionElement = function(group) {
+ var section = document.createElement('stub');
+ section.textContent = group.lines.reduce(function(acc, line) {
+ return acc + line.text;
+ }, '');
+ return section;
+ };
+ return builder;
+ });
+ element.render({ content: content }, {left: [], right: []}, prefs);
});
test('renderSection', function() {
var section = outputEl.querySelector('stub:nth-of-type(2)');
var prevInnerHTML = section.innerHTML;
section.innerHTML = 'wiped';
- builder.renderSection(section);
+ element._builder.renderSection(section);
section = outputEl.querySelector('stub:nth-of-type(2)');
assert.equal(section.innerHTML, prevInnerHTML);
});
test('getSectionsByLineRange one line', function() {
var section = outputEl.querySelector('stub:nth-of-type(2)');
- var sections = builder.getSectionsByLineRange(1, 1, 'left');
+ var sections = element._builder.getSectionsByLineRange(1, 1, 'left');
assert.equal(sections.length, 1);
assert.strictEqual(sections[0], section);
});
@@ -612,7 +289,7 @@
outputEl.querySelector('stub:nth-of-type(2)'),
outputEl.querySelector('stub:nth-of-type(3)'),
];
- var sections = builder.getSectionsByLineRange(1, 2, 'left');
+ var sections = element._builder.getSectionsByLineRange(1, 2, 'left');
assert.equal(sections.length, 2);
assert.strictEqual(sections[0], section[0]);
assert.strictEqual(sections[1], section[1]);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.html b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.html
new file mode 100644
index 0000000..cae8bad
--- /dev/null
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.html
@@ -0,0 +1,23 @@
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<link rel="import" href="../../../bower_components/polymer/polymer.html">
+
+<dom-module id="gr-diff-processor">
+ <script src="../gr-diff/gr-diff-line.js"></script>
+ <script src="../gr-diff/gr-diff-group.js"></script>
+ <script src="gr-diff-processor.js"></script>
+</dom-module>
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
new file mode 100644
index 0000000..0d787c1
--- /dev/null
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor.js
@@ -0,0 +1,303 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+(function() {
+ 'use strict';
+
+ var WHOLE_FILE = -1;
+
+ var DiffSide = {
+ LEFT: 'left',
+ RIGHT: 'right',
+ };
+
+ var DiffGroupType = {
+ ADDED: 'b',
+ BOTH: 'ab',
+ REMOVED: 'a',
+ };
+
+ var DiffHighlights = {
+ ADDED: 'edit_b',
+ REMOVED: 'edit_a',
+ };
+
+ Polymer({
+ is: 'gr-diff-processor',
+
+ properties: {
+
+ /**
+ * The amount of context around collapsed groups.
+ */
+ context: Number,
+
+ /**
+ * The array of groups output by the processor.
+ */
+ groups: {
+ type: Array,
+ notify: true,
+ },
+
+ /**
+ * Locations that should not be collapsed, including the locations of
+ * comments.
+ */
+ keyLocations: {
+ type: Object,
+ value: function() { return {left: {}, right: {}}; },
+ },
+
+ _content: Object,
+ },
+
+ process: function(content) {
+ return new Promise(function(resolve) {
+ var groups = [];
+ this._processContent(content, groups, this.context);
+ this.groups = groups;
+ resolve(groups);
+ }.bind(this));
+ },
+
+ _processContent: function(content, groups, context) {
+ this._appendFileComments(groups);
+
+ context = content.length > 1 ? context : WHOLE_FILE;
+
+ var lineNums = {
+ left: 0,
+ right: 0,
+ };
+ content = this._splitCommonGroupsWithComments(content, lineNums);
+ for (var i = 0; i < content.length; i++) {
+ var group = content[i];
+ var lines = [];
+
+ if (group[DiffGroupType.BOTH] !== undefined) {
+ var rows = group[DiffGroupType.BOTH];
+ this._appendCommonLines(rows, lines, lineNums);
+
+ var hiddenRange = [context, rows.length - context];
+ if (i === 0) {
+ hiddenRange[0] = 0;
+ } else if (i === content.length - 1) {
+ hiddenRange[1] = rows.length;
+ }
+
+ if (context !== WHOLE_FILE && hiddenRange[1] - hiddenRange[0] > 0) {
+ this._insertContextGroups(groups, lines, hiddenRange);
+ } else {
+ groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, lines));
+ }
+ continue;
+ }
+
+ if (group[DiffGroupType.REMOVED] !== undefined) {
+ var highlights = undefined;
+ if (group[DiffHighlights.REMOVED] !== undefined) {
+ highlights = this._normalizeIntralineHighlights(
+ group[DiffGroupType.REMOVED],
+ group[DiffHighlights.REMOVED]);
+ }
+ this._appendRemovedLines(group[DiffGroupType.REMOVED], lines,
+ lineNums, highlights);
+ }
+
+ if (group[DiffGroupType.ADDED] !== undefined) {
+ var highlights = undefined;
+ if (group[DiffHighlights.ADDED] !== undefined) {
+ highlights = this._normalizeIntralineHighlights(
+ group[DiffGroupType.ADDED],
+ group[DiffHighlights.ADDED]);
+ }
+ this._appendAddedLines(group[DiffGroupType.ADDED], lines,
+ lineNums, highlights);
+ }
+ groups.push(new GrDiffGroup(GrDiffGroup.Type.DELTA, lines));
+ }
+ },
+
+ _appendFileComments: function(groups) {
+ var line = new GrDiffLine(GrDiffLine.Type.BOTH);
+ line.beforeNumber = GrDiffLine.FILE;
+ line.afterNumber = GrDiffLine.FILE;
+ groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, [line]));
+ },
+
+ /**
+ * In order to show comments out of the bounds of the selected context,
+ * treat them as separate chunks within the model so that the content (and
+ * context surrounding it) renders correctly.
+ */
+ _splitCommonGroupsWithComments: function(content, lineNums) {
+ var result = [];
+ var leftLineNum = lineNums.left;
+ var rightLineNum = lineNums.right;
+ for (var i = 0; i < content.length; i++) {
+ if (!content[i].ab) {
+ result.push(content[i]);
+ if (content[i].a) {
+ leftLineNum += content[i].a.length;
+ }
+ if (content[i].b) {
+ rightLineNum += content[i].b.length;
+ }
+ continue;
+ }
+ var chunk = content[i].ab;
+ var currentChunk = {ab: []};
+ for (var j = 0; j < chunk.length; j++) {
+ leftLineNum++;
+ rightLineNum++;
+
+ if (this.keyLocations[DiffSide.LEFT][leftLineNum] ||
+ this.keyLocations[DiffSide.RIGHT][rightLineNum]) {
+ if (currentChunk.ab && currentChunk.ab.length > 0) {
+ result.push(currentChunk);
+ currentChunk = {ab: []};
+ }
+ result.push({ab: [chunk[j]]});
+ } else {
+ currentChunk.ab.push(chunk[j]);
+ }
+ }
+ // != instead of !== because we want to cover both undefined and null.
+ if (currentChunk.ab != null && currentChunk.ab.length > 0) {
+ result.push(currentChunk);
+ }
+ }
+ return result;
+ },
+
+ _appendCommonLines: function(rows, lines, lineNums) {
+ for (var i = 0; i < rows.length; i++) {
+ var line = new GrDiffLine(GrDiffLine.Type.BOTH);
+ line.text = rows[i];
+ line.beforeNumber = ++lineNums.left;
+ line.afterNumber = ++lineNums.right;
+ lines.push(line);
+ }
+ },
+
+ _insertContextGroups: function(groups, lines, hiddenRange) {
+ var linesBeforeCtx = lines.slice(0, hiddenRange[0]);
+ var hiddenLines = lines.slice(hiddenRange[0], hiddenRange[1]);
+ var linesAfterCtx = lines.slice(hiddenRange[1]);
+
+ if (linesBeforeCtx.length > 0) {
+ groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, linesBeforeCtx));
+ }
+
+ var ctxLine = new GrDiffLine(GrDiffLine.Type.CONTEXT_CONTROL);
+ ctxLine.contextGroup =
+ new GrDiffGroup(GrDiffGroup.Type.BOTH, hiddenLines);
+ groups.push(new GrDiffGroup(GrDiffGroup.Type.CONTEXT_CONTROL,
+ [ctxLine]));
+
+ if (linesAfterCtx.length > 0) {
+ groups.push(new GrDiffGroup(GrDiffGroup.Type.BOTH, linesAfterCtx));
+ }
+ },
+
+ /**
+ * The `highlights` array consists of a list of <skip length, mark length>
+ * pairs, where the skip length is the number of characters between the
+ * end of the previous edit and the start of this edit, and the mark
+ * length is the number of edited characters following the skip. The start
+ * of the edits is from the beginning of the related diff content lines.
+ *
+ * Note that the implied newline character at the end of each line is
+ * included in the length calculation, and thus it is possible for the
+ * edits to span newlines.
+ *
+ * A line highlight object consists of three fields:
+ * - contentIndex: The index of the diffChunk `content` field (the line
+ * being referred to).
+ * - startIndex: Where the highlight should begin.
+ * - endIndex: (optional) Where the highlight should end. If omitted, the
+ * highlight is meant to be a continuation onto the next line.
+ */
+ _normalizeIntralineHighlights: function(content, highlights) {
+ var contentIndex = 0;
+ var idx = 0;
+ var normalized = [];
+ for (var i = 0; i < highlights.length; i++) {
+ var line = content[contentIndex] + '\n';
+ var hl = highlights[i];
+ var j = 0;
+ while (j < hl[0]) {
+ if (idx === line.length) {
+ idx = 0;
+ line = content[++contentIndex] + '\n';
+ continue;
+ }
+ idx++;
+ j++;
+ }
+ var lineHighlight = {
+ contentIndex: contentIndex,
+ startIndex: idx,
+ };
+
+ j = 0;
+ while (line && j < hl[1]) {
+ if (idx === line.length) {
+ idx = 0;
+ line = content[++contentIndex] + '\n';
+ normalized.push(lineHighlight);
+ lineHighlight = {
+ contentIndex: contentIndex,
+ startIndex: idx,
+ };
+ continue;
+ }
+ idx++;
+ j++;
+ }
+ lineHighlight.endIndex = idx;
+ normalized.push(lineHighlight);
+ }
+ return normalized;
+ },
+
+ _appendRemovedLines: function(rows, lines, lineNums, opt_highlights) {
+ for (var i = 0; i < rows.length; i++) {
+ var line = new GrDiffLine(GrDiffLine.Type.REMOVE);
+ line.text = rows[i];
+ line.beforeNumber = ++lineNums.left;
+ if (opt_highlights) {
+ line.highlights = opt_highlights.filter(function(hl) {
+ return hl.contentIndex === i;
+ });
+ }
+ lines.push(line);
+ }
+ },
+
+ _appendAddedLines: function(rows, lines, lineNums, opt_highlights) {
+ for (var i = 0; i < rows.length; i++) {
+ var line = new GrDiffLine(GrDiffLine.Type.ADD);
+ line.text = rows[i];
+ line.afterNumber = ++lineNums.right;
+ if (opt_highlights) {
+ line.highlights = opt_highlights.filter(function(hl) {
+ return hl.contentIndex === i;
+ });
+ }
+ lines.push(line);
+ }
+ },
+ });
+})();
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
new file mode 100644
index 0000000..6a24d6a
--- /dev/null
+++ b/polygerrit-ui/app/elements/diff/gr-diff-processor/gr-diff-processor_test.html
@@ -0,0 +1,406 @@
+<!DOCTYPE html>
+<!--
+Copyright (C) 2016 The Android Open Source Project
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+<title>gr-diff-processor test</title>
+
+<script src="../../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
+<script src="../../../bower_components/web-component-tester/browser.js"></script>
+
+<link rel="import" href="../../../bower_components/iron-test-helpers/iron-test-helpers.html">
+<link rel="import" href="gr-diff-processor.html">
+
+<test-fixture id="basic">
+ <template>
+ <gr-diff-processor></gr-diff-processor>
+ </template>
+</test-fixture>
+
+<script>
+ suite('gr-diff-processor tests', function() {
+ var element;
+
+ suite('not logged in', function() {
+
+ setup(function() {
+ element = fixture('basic');
+
+ element.context = 4;
+ });
+
+ test('process loaded content', function(done) {
+ var content = [
+ {
+ ab: [
+ '<!DOCTYPE html>',
+ '<meta charset="utf-8">',
+ ]
+ },
+ {
+ a: [
+ ' Welcome ',
+ ' to the wooorld of tomorrow!',
+ ],
+ b: [
+ ' Hello, world!',
+ ],
+ },
+ {
+ ab: [
+ 'Leela: This is the only place the ship can’t hear us, so ',
+ 'everyone pretend to shower.',
+ 'Fry: Same as every day. Got it.',
+ ]
+ },
+ ];
+
+ element.process(content).then(function() {
+ var groups = element.groups;
+
+ assert.equal(groups.length, 4);
+
+ var group = groups[0];
+ assert.equal(group.type, GrDiffGroup.Type.BOTH);
+ assert.equal(group.lines.length, 1);
+ assert.equal(group.lines[0].text, '');
+ assert.equal(group.lines[0].beforeNumber, GrDiffLine.FILE);
+ assert.equal(group.lines[0].afterNumber, GrDiffLine.FILE);
+
+ group = groups[1];
+ assert.equal(group.type, GrDiffGroup.Type.BOTH);
+ assert.equal(group.lines.length, 2);
+ assert.equal(group.lines.length, 2);
+
+ function beforeNumberFn(l) { return l.beforeNumber; }
+ function afterNumberFn(l) { return l.afterNumber; }
+ function textFn(l) { return l.text; }
+
+ assert.deepEqual(group.lines.map(beforeNumberFn), [1, 2]);
+ assert.deepEqual(group.lines.map(afterNumberFn), [1, 2]);
+ assert.deepEqual(group.lines.map(textFn), [
+ '<!DOCTYPE html>',
+ '<meta charset="utf-8">',
+ ]);
+
+ group = groups[2];
+ assert.equal(group.type, GrDiffGroup.Type.DELTA);
+ assert.equal(group.lines.length, 3);
+ assert.equal(group.adds.length, 1);
+ assert.equal(group.removes.length, 2);
+ assert.deepEqual(group.removes.map(beforeNumberFn), [3, 4]);
+ assert.deepEqual(group.adds.map(afterNumberFn), [3]);
+ assert.deepEqual(group.removes.map(textFn), [
+ ' Welcome ',
+ ' to the wooorld of tomorrow!',
+ ]);
+ assert.deepEqual(group.adds.map(textFn), [
+ ' Hello, world!',
+ ]);
+
+ group = groups[3];
+ assert.equal(group.type, GrDiffGroup.Type.BOTH);
+ assert.equal(group.lines.length, 3);
+ assert.deepEqual(group.lines.map(beforeNumberFn), [5, 6, 7]);
+ assert.deepEqual(group.lines.map(afterNumberFn), [4, 5, 6]);
+ assert.deepEqual(group.lines.map(textFn), [
+ 'Leela: This is the only place the ship can’t hear us, so ',
+ 'everyone pretend to shower.',
+ 'Fry: Same as every day. Got it.',
+ ]);
+
+ done();
+ });
+ });
+
+ test('insert context groups', function(done) {
+ var content = [
+ {ab: []},
+ {a: ['all work and no play make andybons a dull boy']},
+ {ab: []},
+ {b: ['elgoog elgoog elgoog']},
+ {ab: []},
+ ];
+ for (var i = 0; i < 100; i++) {
+ content[0].ab.push('all work and no play make jack a dull boy');
+ content[4].ab.push('all work and no play make jill a dull girl');
+ }
+ for (var i = 0; i < 5; i++) {
+ content[2].ab.push('no tv and no beer make homer go crazy');
+ }
+
+ var context = 10;
+ element.context = context;
+
+ element.process(content).then(function() {
+ var groups = element.groups;
+
+ assert.equal(groups[0].type, GrDiffGroup.Type.BOTH);
+ assert.equal(groups[0].lines.length, 1);
+ assert.equal(groups[0].lines[0].text, '');
+ assert.equal(groups[0].lines[0].beforeNumber, GrDiffLine.FILE);
+ assert.equal(groups[0].lines[0].afterNumber, GrDiffLine.FILE);
+
+ assert.equal(groups[1].type, GrDiffGroup.Type.CONTEXT_CONTROL);
+ assert.instanceOf(groups[1].lines[0].contextGroup, GrDiffGroup);
+ assert.equal(groups[1].lines[0].contextGroup.lines.length, 90);
+ groups[1].lines[0].contextGroup.lines.forEach(function(l) {
+ assert.equal(l.text, content[0].ab[0]);
+ });
+
+ assert.equal(groups[2].type, GrDiffGroup.Type.BOTH);
+ assert.equal(groups[2].lines.length, context);
+ groups[2].lines.forEach(function(l) {
+ assert.equal(l.text, content[0].ab[0]);
+ });
+
+ assert.equal(groups[3].type, GrDiffGroup.Type.DELTA);
+ assert.equal(groups[3].lines.length, 1);
+ assert.equal(groups[3].removes.length, 1);
+ assert.equal(groups[3].removes[0].text,
+ 'all work and no play make andybons a dull boy');
+
+ assert.equal(groups[4].type, GrDiffGroup.Type.BOTH);
+ assert.equal(groups[4].lines.length, 5);
+ groups[4].lines.forEach(function(l) {
+ assert.equal(l.text, content[2].ab[0]);
+ });
+
+ assert.equal(groups[5].type, GrDiffGroup.Type.DELTA);
+ assert.equal(groups[5].lines.length, 1);
+ assert.equal(groups[5].adds.length, 1);
+ assert.equal(groups[5].adds[0].text, 'elgoog elgoog elgoog');
+
+ assert.equal(groups[6].type, GrDiffGroup.Type.BOTH);
+ assert.equal(groups[6].lines.length, context);
+ groups[6].lines.forEach(function(l) {
+ assert.equal(l.text, content[4].ab[0]);
+ });
+
+ assert.equal(groups[7].type, GrDiffGroup.Type.CONTEXT_CONTROL);
+ assert.instanceOf(groups[7].lines[0].contextGroup, GrDiffGroup);
+ assert.equal(groups[7].lines[0].contextGroup.lines.length, 90);
+ groups[7].lines[0].contextGroup.lines.forEach(function(l) {
+ assert.equal(l.text, content[4].ab[0]);
+ });
+
+ done();
+ });
+ });
+
+ test('insert context groups', function(done) {
+ content = [
+ {a: ['all work and no play make andybons a dull boy']},
+ {ab: []},
+ {b: ['elgoog elgoog elgoog']},
+ ];
+ for (var i = 0; i < 50; i++) {
+ content[1].ab.push('no tv and no beer make homer go crazy');
+ }
+
+ var context = 10;
+ element.context = context;
+
+ element.process(content).then(function() {
+ var groups = element.groups;
+
+ assert.equal(groups[0].type, GrDiffGroup.Type.BOTH);
+ assert.equal(groups[0].lines.length, 1);
+ assert.equal(groups[0].lines[0].text, '');
+ assert.equal(groups[0].lines[0].beforeNumber, GrDiffLine.FILE);
+ assert.equal(groups[0].lines[0].afterNumber, GrDiffLine.FILE);
+
+ assert.equal(groups[1].type, GrDiffGroup.Type.DELTA);
+ assert.equal(groups[1].lines.length, 1);
+ assert.equal(groups[1].removes.length, 1);
+ assert.equal(groups[1].removes[0].text,
+ 'all work and no play make andybons a dull boy');
+
+ assert.equal(groups[2].type, GrDiffGroup.Type.BOTH);
+ assert.equal(groups[2].lines.length, context);
+ groups[2].lines.forEach(function(l) {
+ assert.equal(l.text, content[1].ab[0]);
+ });
+
+ assert.equal(groups[3].type, GrDiffGroup.Type.CONTEXT_CONTROL);
+ assert.instanceOf(groups[3].lines[0].contextGroup, GrDiffGroup);
+ assert.equal(groups[3].lines[0].contextGroup.lines.length, 30);
+ groups[3].lines[0].contextGroup.lines.forEach(function(l) {
+ assert.equal(l.text, content[1].ab[0]);
+ });
+
+ assert.equal(groups[4].type, GrDiffGroup.Type.BOTH);
+ assert.equal(groups[4].lines.length, context);
+ groups[4].lines.forEach(function(l) {
+ assert.equal(l.text, content[1].ab[0]);
+ });
+
+ assert.equal(groups[5].type, GrDiffGroup.Type.DELTA);
+ assert.equal(groups[5].lines.length, 1);
+ assert.equal(groups[5].adds.length, 1);
+ assert.equal(groups[5].adds[0].text, 'elgoog elgoog elgoog');
+
+ done();
+ });
+ });
+
+ test('break up common diff chunks', function() {
+ element.keyLocations = {
+ left: {1: true},
+ right: {10: true},
+ };
+ var lineNums = {left: 0, right: 0};
+
+ var content = [
+ {
+ ab: [
+ 'Copyright (C) 2015 The Android Open Source Project',
+ '',
+ 'Licensed under the Apache License, Version 2.0 (the "License");',
+ 'you may not use this file except in compliance with the ' +
+ 'License.',
+ 'You may obtain a copy of the License at',
+ '',
+ 'http://www.apache.org/licenses/LICENSE-2.0',
+ '',
+ 'Unless required by applicable law or agreed to in writing, ',
+ 'software distributed under the License is distributed on an ',
+ '"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, ',
+ 'either express or implied. See the License for the specific ',
+ 'language governing permissions and limitations under the ' +
+ 'License.',
+ ]
+ }
+ ];
+ var result = element._splitCommonGroupsWithComments(content, lineNums);
+ assert.deepEqual(result, [
+ {
+ ab: ['Copyright (C) 2015 The Android Open Source Project'],
+ },
+ {
+ ab: [
+ '',
+ 'Licensed under the Apache License, Version 2.0 (the "License");',
+ 'you may not use this file except in compliance with the ' +
+ 'License.',
+ 'You may obtain a copy of the License at',
+ '',
+ 'http://www.apache.org/licenses/LICENSE-2.0',
+ '',
+ 'Unless required by applicable law or agreed to in writing, ',
+ ]
+ },
+ {
+ ab: [
+ 'software distributed under the License is distributed on an '],
+ },
+ {
+ ab: [
+ '"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, ',
+ 'either express or implied. See the License for the specific ',
+ 'language governing permissions and limitations under the ' +
+ 'License.',
+ ]
+ }
+ ]);
+ });
+
+ test('intraline normalization', function() {
+ // The content and highlights are in the format returned by the Gerrit
+ // REST API.
+ var content = [
+ ' <section class="summary">',
+ ' <gr-linked-text content="' +
+ '[[_computeCurrentRevisionMessage(change)]]"></gr-linked-text>',
+ ' </section>',
+ ];
+ var highlights = [
+ [31, 34], [42, 26]
+ ];
+
+ var results = element._normalizeIntralineHighlights(content,
+ highlights);
+ assert.deepEqual(results, [
+ {
+ contentIndex: 0,
+ startIndex: 31,
+ },
+ {
+ contentIndex: 1,
+ startIndex: 0,
+ endIndex: 33,
+ },
+ {
+ contentIndex: 1,
+ startIndex: 75,
+ },
+ {
+ contentIndex: 2,
+ startIndex: 0,
+ endIndex: 6,
+ }
+ ]);
+
+ content = [
+ ' this._path = value.path;',
+ '',
+ ' // When navigating away from the page, there is a ' +
+ 'possibility that the',
+ ' // patch number is no longer a part of the URL ' +
+ '(say when navigating to',
+ ' // the top-level change info view) and therefore ' +
+ 'undefined in `params`.',
+ ' if (!this._patchRange.patchNum) {',
+ ];
+ highlights = [
+ [14, 17],
+ [11, 70],
+ [12, 67],
+ [12, 67],
+ [14, 29],
+ ];
+ results = element._normalizeIntralineHighlights(content, highlights);
+ assert.deepEqual(results, [
+ {
+ contentIndex: 0,
+ startIndex: 14,
+ endIndex: 31,
+ },
+ {
+ contentIndex: 2,
+ startIndex: 8,
+ endIndex: 78,
+ },
+ {
+ contentIndex: 3,
+ startIndex: 11,
+ endIndex: 78,
+ },
+ {
+ contentIndex: 4,
+ startIndex: 11,
+ endIndex: 78,
+ },
+ {
+ contentIndex: 5,
+ startIndex: 12,
+ endIndex: 41,
+ }
+ ]);
+ });
+ });
+ });
+</script>
diff --git a/polygerrit-ui/app/test/index.html b/polygerrit-ui/app/test/index.html
index 96b97cc..98f7eef 100644
--- a/polygerrit-ui/app/test/index.html
+++ b/polygerrit-ui/app/test/index.html
@@ -49,6 +49,7 @@
'diff/gr-diff-cursor/gr-diff-cursor_test.html',
'diff/gr-diff-highlight/gr-diff-highlight_test.html',
'diff/gr-diff-preferences/gr-diff-preferences_test.html',
+ 'diff/gr-diff-processor/gr-diff-processor_test.html',
'diff/gr-diff-selection/gr-diff-selection_test.html',
'diff/gr-diff-view/gr-diff-view_test.html',
'diff/gr-diff/gr-diff-group_test.html',