Wyatt Allen 7f2bd97901 Separates diff processing from diff building
Moves the diff-processing functionality of the gr-diff-builder component
into a new gr-diff-processor component which exposes a promise-based
interface. This is step one of creating an asynchronous (non-blocking)
diff rendering system.

As much as possible, this change is a transfer of code (with tests) from
one component to another, making it easier to verify that functionality
has not changed. Cleanup of the code, and refactoring it into a
more-testable form will come with later changes.

Feature: Issue 3916
Change-Id: I875b03b20bf953b128cbe3c5001ba1f8eba12c61
2016-06-27 16:44:19 -07:00

407 lines
14 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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 cant 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 cant 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>