
When a diff request includes an ignore-whitespace level, the same diff content is returned, but a number of diff chunks are marked as "common" with the understanding that those chunks only contain the kind of whitespace that can be ignored. Thus, actually ignoring these chunks is up to the frontend. In this commit, support is added for editing the preferred whitespace level, and the preferred level is included in diff requests. When a diff is loaded with an ignore-whitespace level, gr-diff-host transforms the marked deltas into shared chunks. In this way, when the transformed diff is passed down into gr-diff, it can be rendered like normal and the unwanted whitespace deltas do not appear. To transform a diff with chunks to be ignored, the strategy is as follows. If a marked delta chunk has revision (a right-side), then it's converted to a shared chunk where both sides are made up of the revision content. (If a marked delta chunk has no revision content, it's merely omitted.) Finally, adjacent shared chunks that result from modifying the marked chunks are merged together so that gr-diff will properly position context-control barriers. Feature: Issue 6198 Change-Id: I1e4cc1075edf34f5ce87ee6bfc2cf415a3b98d94
864 lines
29 KiB
HTML
864 lines
29 KiB
HTML
<!DOCTYPE html>
|
||
<!--
|
||
@license
|
||
Copyright (C) 2018 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</title>
|
||
|
||
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
|
||
<script src="../../../bower_components/web-component-tester/browser.js"></script>
|
||
<link rel="import" href="../../../test/common-test-setup.html"/>
|
||
|
||
<link rel="import" href="gr-diff-host.html">
|
||
|
||
<script>void(0);</script>
|
||
|
||
<test-fixture id="basic">
|
||
<template>
|
||
<gr-diff-host></gr-diff-host>
|
||
</template>
|
||
</test-fixture>
|
||
|
||
<script>
|
||
suite('gr-diff-host tests', () => {
|
||
let element;
|
||
let sandbox;
|
||
|
||
setup(() => {
|
||
sandbox = sinon.sandbox.create();
|
||
element = fixture('basic');
|
||
});
|
||
|
||
teardown(() => {
|
||
sandbox.restore();
|
||
});
|
||
|
||
test('reload() cancels before network resolves', () => {
|
||
const cancelStub = sandbox.stub(element.$.diff, 'cancel');
|
||
|
||
// Stub the network calls into requests that never resolve.
|
||
sandbox.stub(element, '_getDiff', () => new Promise(() => {}));
|
||
|
||
element.reload();
|
||
assert.isTrue(cancelStub.called);
|
||
});
|
||
|
||
suite('not logged in', () => {
|
||
setup(() => {
|
||
const getLoggedInPromise = Promise.resolve(false);
|
||
stub('gr-rest-api-interface', {
|
||
getLoggedIn() { return getLoggedInPromise; },
|
||
});
|
||
element = fixture('basic');
|
||
return getLoggedInPromise;
|
||
});
|
||
|
||
test('reload() loads files weblinks', () => {
|
||
const weblinksStub = sandbox.stub(Gerrit.Nav, '_generateWeblinks')
|
||
.returns({name: 'stubb', url: '#s'});
|
||
sandbox.stub(element.$.restAPI, 'getDiff').returns(Promise.resolve({
|
||
content: [],
|
||
}));
|
||
element.projectName = 'test-project';
|
||
element.path = 'test-path';
|
||
element.commitRange = {baseCommit: 'test-base', commit: 'test-commit'};
|
||
element.patchRange = {};
|
||
return element.reload().then(() => {
|
||
assert.isTrue(weblinksStub.calledTwice);
|
||
assert.isTrue(weblinksStub.firstCall.calledWith({
|
||
commit: 'test-base',
|
||
file: 'test-path',
|
||
options: {
|
||
weblinks: undefined,
|
||
},
|
||
repo: 'test-project',
|
||
type: Gerrit.Nav.WeblinkType.FILE}));
|
||
assert.isTrue(weblinksStub.secondCall.calledWith({
|
||
commit: 'test-commit',
|
||
file: 'test-path',
|
||
options: {
|
||
weblinks: undefined,
|
||
},
|
||
repo: 'test-project',
|
||
type: Gerrit.Nav.WeblinkType.FILE}));
|
||
assert.deepEqual(element.filesWeblinks, {
|
||
meta_a: [{name: 'stubb', url: '#s'}],
|
||
meta_b: [{name: 'stubb', url: '#s'}],
|
||
});
|
||
});
|
||
});
|
||
|
||
test('_getDiff handles null diff responses', done => {
|
||
stub('gr-rest-api-interface', {
|
||
getDiff() { return Promise.resolve(null); },
|
||
});
|
||
element.changeNum = 123;
|
||
element.patchRange = {basePatchNum: 1, patchNum: 2};
|
||
element.path = 'file.txt';
|
||
element._getDiff().then(done);
|
||
});
|
||
|
||
test('reload resolves on error', () => {
|
||
const onErrStub = sandbox.stub(element, '_handleGetDiffError');
|
||
const error = {ok: false, status: 500};
|
||
sandbox.stub(element.$.restAPI, 'getDiff',
|
||
(changeNum, basePatchNum, patchNum, path, onErr) => {
|
||
onErr(error);
|
||
});
|
||
return element.reload().then(() => {
|
||
assert.isTrue(onErrStub.calledOnce);
|
||
});
|
||
});
|
||
|
||
suite('_handleGetDiffError', () => {
|
||
let serverErrorStub;
|
||
let pageErrorStub;
|
||
|
||
setup(() => {
|
||
serverErrorStub = sinon.stub();
|
||
element.addEventListener('server-error', serverErrorStub);
|
||
pageErrorStub = sinon.stub();
|
||
element.addEventListener('page-error', pageErrorStub);
|
||
});
|
||
|
||
test('page error on HTTP-409', () => {
|
||
element._handleGetDiffError({status: 409});
|
||
assert.isTrue(serverErrorStub.calledOnce);
|
||
assert.isFalse(pageErrorStub.called);
|
||
assert.isNotOk(element._errorMessage);
|
||
});
|
||
|
||
test('server error on non-HTTP-409', () => {
|
||
element._handleGetDiffError({status: 500});
|
||
assert.isFalse(serverErrorStub.called);
|
||
assert.isTrue(pageErrorStub.calledOnce);
|
||
assert.isNotOk(element._errorMessage);
|
||
});
|
||
|
||
test('error message if showLoadFailure', () => {
|
||
element.showLoadFailure = true;
|
||
element._handleGetDiffError({status: 500, statusText: 'Failure!'});
|
||
assert.isFalse(serverErrorStub.called);
|
||
assert.isFalse(pageErrorStub.called);
|
||
assert.equal(element._errorMessage,
|
||
'Encountered error when loading the diff: 500 Failure!');
|
||
});
|
||
});
|
||
|
||
suite('image diffs', () => {
|
||
let mockFile1;
|
||
let mockFile2;
|
||
setup(() => {
|
||
mockFile1 = {
|
||
body: 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
|
||
'wsAAAAAAAAAAAAAAAAA/w==',
|
||
type: 'image/bmp',
|
||
};
|
||
mockFile2 = {
|
||
body: 'Qk06AAAAAAAAADYAAAAoAAAAAQAAAP////8BACAAAAAAAAAAAAATCwAAE' +
|
||
'wsAAAAAAAAAAAAA/////w==',
|
||
type: 'image/bmp',
|
||
};
|
||
sandbox.stub(element.$.restAPI,
|
||
'getB64FileContents',
|
||
(changeId, patchNum, path, opt_parentIndex) => {
|
||
return Promise.resolve(opt_parentIndex === 1 ? mockFile1 :
|
||
mockFile2);
|
||
});
|
||
|
||
element.patchRange = {basePatchNum: 'PARENT', patchNum: 1};
|
||
element.comments = {left: [], right: []};
|
||
});
|
||
|
||
test('renders image diffs with same file name', done => {
|
||
const mockDiff = {
|
||
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
|
||
meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg',
|
||
lines: 560},
|
||
intraline_status: 'OK',
|
||
change_type: 'MODIFIED',
|
||
diff_header: [
|
||
'diff --git a/carrot.jpg b/carrot.jpg',
|
||
'index 2adc47d..f9c2f2c 100644',
|
||
'--- a/carrot.jpg',
|
||
'+++ b/carrot.jpg',
|
||
'Binary files differ',
|
||
],
|
||
content: [{skip: 66}],
|
||
binary: true,
|
||
};
|
||
sandbox.stub(element.$.restAPI, 'getDiff')
|
||
.returns(Promise.resolve(mockDiff));
|
||
|
||
const rendered = () => {
|
||
// Recognizes that it should be an image diff.
|
||
assert.isTrue(element.isImageDiff);
|
||
assert.instanceOf(
|
||
element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
|
||
|
||
// Left image rendered with the parent commit's version of the file.
|
||
const leftImage =
|
||
element.$.diff.$.diffTable.querySelector('td.left img');
|
||
const leftLabel =
|
||
element.$.diff.$.diffTable.querySelector('td.left label');
|
||
const leftLabelContent = leftLabel.querySelector('.label');
|
||
const leftLabelName = leftLabel.querySelector('.name');
|
||
|
||
const rightImage =
|
||
element.$.diff.$.diffTable.querySelector('td.right img');
|
||
const rightLabel = element.$.diff.$.diffTable.querySelector(
|
||
'td.right label');
|
||
const rightLabelContent = rightLabel.querySelector('.label');
|
||
const rightLabelName = rightLabel.querySelector('.name');
|
||
|
||
assert.isNotOk(rightLabelName);
|
||
assert.isNotOk(leftLabelName);
|
||
|
||
let leftLoaded = false;
|
||
let rightLoaded = false;
|
||
|
||
leftImage.addEventListener('load', () => {
|
||
assert.isOk(leftImage);
|
||
assert.equal(leftImage.getAttribute('src'),
|
||
'data:image/bmp;base64, ' + mockFile1.body);
|
||
assert.equal(leftLabelContent.textContent, '1×1 image/bmp');
|
||
leftLoaded = true;
|
||
if (rightLoaded) {
|
||
element.removeEventListener('render', rendered);
|
||
done();
|
||
}
|
||
});
|
||
|
||
rightImage.addEventListener('load', () => {
|
||
assert.isOk(rightImage);
|
||
assert.equal(rightImage.getAttribute('src'),
|
||
'data:image/bmp;base64, ' + mockFile2.body);
|
||
assert.equal(rightLabelContent.textContent, '1×1 image/bmp');
|
||
|
||
rightLoaded = true;
|
||
if (leftLoaded) {
|
||
element.removeEventListener('render', rendered);
|
||
done();
|
||
}
|
||
});
|
||
};
|
||
|
||
element.addEventListener('render', rendered);
|
||
|
||
element.$.restAPI.getDiffPreferences().then(prefs => {
|
||
element.prefs = prefs;
|
||
element.reload();
|
||
});
|
||
});
|
||
|
||
test('renders image diffs with a different file name', done => {
|
||
const mockDiff = {
|
||
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg', lines: 66},
|
||
meta_b: {name: 'carrot2.jpg', content_type: 'image/jpeg',
|
||
lines: 560},
|
||
intraline_status: 'OK',
|
||
change_type: 'MODIFIED',
|
||
diff_header: [
|
||
'diff --git a/carrot.jpg b/carrot2.jpg',
|
||
'index 2adc47d..f9c2f2c 100644',
|
||
'--- a/carrot.jpg',
|
||
'+++ b/carrot2.jpg',
|
||
'Binary files differ',
|
||
],
|
||
content: [{skip: 66}],
|
||
binary: true,
|
||
};
|
||
sandbox.stub(element.$.restAPI, 'getDiff')
|
||
.returns(Promise.resolve(mockDiff));
|
||
|
||
const rendered = () => {
|
||
// Recognizes that it should be an image diff.
|
||
assert.isTrue(element.isImageDiff);
|
||
assert.instanceOf(
|
||
element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
|
||
|
||
// Left image rendered with the parent commit's version of the file.
|
||
const leftImage =
|
||
element.$.diff.$.diffTable.querySelector('td.left img');
|
||
const leftLabel =
|
||
element.$.diff.$.diffTable.querySelector('td.left label');
|
||
const leftLabelContent = leftLabel.querySelector('.label');
|
||
const leftLabelName = leftLabel.querySelector('.name');
|
||
|
||
const rightImage =
|
||
element.$.diff.$.diffTable.querySelector('td.right img');
|
||
const rightLabel = element.$.diff.$.diffTable.querySelector(
|
||
'td.right label');
|
||
const rightLabelContent = rightLabel.querySelector('.label');
|
||
const rightLabelName = rightLabel.querySelector('.name');
|
||
|
||
assert.isOk(rightLabelName);
|
||
assert.isOk(leftLabelName);
|
||
assert.equal(leftLabelName.textContent, mockDiff.meta_a.name);
|
||
assert.equal(rightLabelName.textContent, mockDiff.meta_b.name);
|
||
|
||
let leftLoaded = false;
|
||
let rightLoaded = false;
|
||
|
||
leftImage.addEventListener('load', () => {
|
||
assert.isOk(leftImage);
|
||
assert.equal(leftImage.getAttribute('src'),
|
||
'data:image/bmp;base64, ' + mockFile1.body);
|
||
assert.equal(leftLabelContent.textContent, '1×1 image/bmp');
|
||
leftLoaded = true;
|
||
if (rightLoaded) {
|
||
element.removeEventListener('render', rendered);
|
||
done();
|
||
}
|
||
});
|
||
|
||
rightImage.addEventListener('load', () => {
|
||
assert.isOk(rightImage);
|
||
assert.equal(rightImage.getAttribute('src'),
|
||
'data:image/bmp;base64, ' + mockFile2.body);
|
||
assert.equal(rightLabelContent.textContent, '1×1 image/bmp');
|
||
|
||
rightLoaded = true;
|
||
if (leftLoaded) {
|
||
element.removeEventListener('render', rendered);
|
||
done();
|
||
}
|
||
});
|
||
};
|
||
|
||
element.addEventListener('render', rendered);
|
||
|
||
element.$.restAPI.getDiffPreferences().then(prefs => {
|
||
element.prefs = prefs;
|
||
element.reload();
|
||
});
|
||
});
|
||
|
||
test('renders added image', done => {
|
||
const mockDiff = {
|
||
meta_b: {name: 'carrot.jpg', content_type: 'image/jpeg',
|
||
lines: 560},
|
||
intraline_status: 'OK',
|
||
change_type: 'ADDED',
|
||
diff_header: [
|
||
'diff --git a/carrot.jpg b/carrot.jpg',
|
||
'index 0000000..f9c2f2c 100644',
|
||
'--- /dev/null',
|
||
'+++ b/carrot.jpg',
|
||
'Binary files differ',
|
||
],
|
||
content: [{skip: 66}],
|
||
binary: true,
|
||
};
|
||
sandbox.stub(element.$.restAPI, 'getDiff')
|
||
.returns(Promise.resolve(mockDiff));
|
||
|
||
element.addEventListener('render', () => {
|
||
// Recognizes that it should be an image diff.
|
||
assert.isTrue(element.isImageDiff);
|
||
assert.instanceOf(
|
||
element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
|
||
|
||
const leftImage =
|
||
element.$.diff.$.diffTable.querySelector('td.left img');
|
||
const rightImage =
|
||
element.$.diff.$.diffTable.querySelector('td.right img');
|
||
|
||
assert.isNotOk(leftImage);
|
||
assert.isOk(rightImage);
|
||
done();
|
||
});
|
||
|
||
element.$.restAPI.getDiffPreferences().then(prefs => {
|
||
element.prefs = prefs;
|
||
element.reload();
|
||
});
|
||
});
|
||
|
||
test('renders removed image', done => {
|
||
const mockDiff = {
|
||
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg',
|
||
lines: 560},
|
||
intraline_status: 'OK',
|
||
change_type: 'DELETED',
|
||
diff_header: [
|
||
'diff --git a/carrot.jpg b/carrot.jpg',
|
||
'index f9c2f2c..0000000 100644',
|
||
'--- a/carrot.jpg',
|
||
'+++ /dev/null',
|
||
'Binary files differ',
|
||
],
|
||
content: [{skip: 66}],
|
||
binary: true,
|
||
};
|
||
sandbox.stub(element.$.restAPI, 'getDiff')
|
||
.returns(Promise.resolve(mockDiff));
|
||
|
||
element.addEventListener('render', () => {
|
||
// Recognizes that it should be an image diff.
|
||
assert.isTrue(element.isImageDiff);
|
||
assert.instanceOf(
|
||
element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
|
||
|
||
const leftImage =
|
||
element.$.diff.$.diffTable.querySelector('td.left img');
|
||
const rightImage =
|
||
element.$.diff.$.diffTable.querySelector('td.right img');
|
||
|
||
assert.isOk(leftImage);
|
||
assert.isNotOk(rightImage);
|
||
done();
|
||
});
|
||
|
||
element.$.restAPI.getDiffPreferences().then(prefs => {
|
||
element.prefs = prefs;
|
||
element.reload();
|
||
});
|
||
});
|
||
|
||
test('does not render disallowed image type', done => {
|
||
const mockDiff = {
|
||
meta_a: {name: 'carrot.jpg', content_type: 'image/jpeg-evil',
|
||
lines: 560},
|
||
intraline_status: 'OK',
|
||
change_type: 'DELETED',
|
||
diff_header: [
|
||
'diff --git a/carrot.jpg b/carrot.jpg',
|
||
'index f9c2f2c..0000000 100644',
|
||
'--- a/carrot.jpg',
|
||
'+++ /dev/null',
|
||
'Binary files differ',
|
||
],
|
||
content: [{skip: 66}],
|
||
binary: true,
|
||
};
|
||
mockFile1.type = 'image/jpeg-evil';
|
||
|
||
sandbox.stub(element.$.restAPI, 'getDiff')
|
||
.returns(Promise.resolve(mockDiff));
|
||
|
||
element.addEventListener('render', () => {
|
||
// Recognizes that it should be an image diff.
|
||
assert.isTrue(element.isImageDiff);
|
||
assert.instanceOf(
|
||
element.$.diff.$.diffBuilder._builder, GrDiffBuilderImage);
|
||
const leftImage =
|
||
element.$.diff.$.diffTable.querySelector('td.left img');
|
||
assert.isNotOk(leftImage);
|
||
done();
|
||
});
|
||
|
||
element.$.restAPI.getDiffPreferences().then(prefs => {
|
||
element.prefs = prefs;
|
||
element.reload();
|
||
});
|
||
});
|
||
});
|
||
});
|
||
|
||
test('delegates cancel()', () => {
|
||
const stub = sandbox.stub(element.$.diff, 'cancel');
|
||
element.reload();
|
||
assert.isTrue(stub.calledOnce);
|
||
assert.equal(stub.lastCall.args.length, 0);
|
||
});
|
||
|
||
test('delegates getCursorStops()', () => {
|
||
const returnValue = [document.createElement('b')];
|
||
const stub = sandbox.stub(element.$.diff, 'getCursorStops')
|
||
.returns(returnValue);
|
||
assert.equal(element.getCursorStops(), returnValue);
|
||
assert.isTrue(stub.calledOnce);
|
||
assert.equal(stub.lastCall.args.length, 0);
|
||
});
|
||
|
||
test('delegates isRangeSelected()', () => {
|
||
const returnValue = true;
|
||
const stub = sandbox.stub(element.$.diff, 'isRangeSelected')
|
||
.returns(returnValue);
|
||
assert.equal(element.isRangeSelected(), returnValue);
|
||
assert.isTrue(stub.calledOnce);
|
||
assert.equal(stub.lastCall.args.length, 0);
|
||
});
|
||
|
||
test('delegates toggleLeftDiff()', () => {
|
||
const stub = sandbox.stub(element.$.diff, 'toggleLeftDiff');
|
||
element.toggleLeftDiff();
|
||
assert.isTrue(stub.calledOnce);
|
||
assert.equal(stub.lastCall.args.length, 0);
|
||
});
|
||
|
||
suite('blame', () => {
|
||
setup(() => {
|
||
element = fixture('basic');
|
||
});
|
||
|
||
test('clearBlame', () => {
|
||
element._blame = [];
|
||
const setBlameSpy = sandbox.spy(element.$.diff.$.diffBuilder, 'setBlame');
|
||
element.clearBlame();
|
||
assert.isNull(element._blame);
|
||
assert.isTrue(setBlameSpy.calledWithExactly(null));
|
||
assert.equal(element.isBlameLoaded, false);
|
||
});
|
||
|
||
test('loadBlame', () => {
|
||
const mockBlame = [{id: 'commit id', ranges: [{start: 1, end: 2}]}];
|
||
const showAlertStub = sinon.stub();
|
||
element.addEventListener('show-alert', showAlertStub);
|
||
const getBlameStub = sandbox.stub(element.$.restAPI, 'getBlame')
|
||
.returns(Promise.resolve(mockBlame));
|
||
element.changeNum = 42;
|
||
element.patchRange = {patchNum: 5, basePatchNum: 4};
|
||
element.path = 'foo/bar.baz';
|
||
return element.loadBlame().then(() => {
|
||
assert.isTrue(getBlameStub.calledWithExactly(
|
||
42, 5, 'foo/bar.baz', true));
|
||
assert.isFalse(showAlertStub.called);
|
||
assert.equal(element._blame, mockBlame);
|
||
assert.equal(element.isBlameLoaded, true);
|
||
});
|
||
});
|
||
|
||
test('loadBlame empty', () => {
|
||
const mockBlame = [];
|
||
const showAlertStub = sinon.stub();
|
||
element.addEventListener('show-alert', showAlertStub);
|
||
sandbox.stub(element.$.restAPI, 'getBlame')
|
||
.returns(Promise.resolve(mockBlame));
|
||
element.changeNum = 42;
|
||
element.patchRange = {patchNum: 5, basePatchNum: 4};
|
||
element.path = 'foo/bar.baz';
|
||
return element.loadBlame()
|
||
.then(() => {
|
||
assert.isTrue(false, 'Promise should not resolve');
|
||
})
|
||
.catch(() => {
|
||
assert.isTrue(showAlertStub.calledOnce);
|
||
assert.isNull(element._blame);
|
||
assert.equal(element.isBlameLoaded, false);
|
||
});
|
||
});
|
||
});
|
||
|
||
test('delegates getThreadEls()', () => {
|
||
const returnValue = [document.createElement('b')];
|
||
const stub = sandbox.stub(element.$.diff, 'getThreadEls')
|
||
.returns(returnValue);
|
||
assert.equal(element.getThreadEls(), returnValue);
|
||
assert.isTrue(stub.calledOnce);
|
||
assert.equal(stub.lastCall.args.length, 0);
|
||
});
|
||
|
||
test('delegates addDraftAtLine(el)', () => {
|
||
const param0 = document.createElement('b');
|
||
const stub = sandbox.stub(element.$.diff, 'addDraftAtLine');
|
||
element.addDraftAtLine(param0);
|
||
assert.isTrue(stub.calledOnce);
|
||
assert.equal(stub.lastCall.args.length, 1);
|
||
assert.equal(stub.lastCall.args[0], param0);
|
||
});
|
||
|
||
test('delegates clearDiffContent()', () => {
|
||
const stub = sandbox.stub(element.$.diff, 'clearDiffContent');
|
||
element.clearDiffContent();
|
||
assert.isTrue(stub.calledOnce);
|
||
assert.equal(stub.lastCall.args.length, 0);
|
||
});
|
||
|
||
test('delegates expandAllContext()', () => {
|
||
const stub = sandbox.stub(element.$.diff, 'expandAllContext');
|
||
element.expandAllContext();
|
||
assert.isTrue(stub.calledOnce);
|
||
assert.equal(stub.lastCall.args.length, 0);
|
||
});
|
||
|
||
test('passes in changeNum', () => {
|
||
const value = '12345';
|
||
element.changeNum = value;
|
||
assert.equal(element.$.diff.changeNum, value);
|
||
});
|
||
|
||
test('passes in noAutoRender', () => {
|
||
const value = true;
|
||
element.noAutoRender = value;
|
||
assert.equal(element.$.diff.noAutoRender, value);
|
||
});
|
||
|
||
test('passes in patchRange', () => {
|
||
const value = {patchNum: 'foo', basePatchNum: 'bar'};
|
||
element.patchRange = value;
|
||
assert.equal(element.$.diff.patchRange, value);
|
||
});
|
||
|
||
test('passes in path', () => {
|
||
const value = 'some/file/path';
|
||
element.path = value;
|
||
assert.equal(element.$.diff.path, value);
|
||
});
|
||
|
||
test('passes in prefs', () => {
|
||
const value = {};
|
||
element.prefs = value;
|
||
assert.equal(element.$.diff.prefs, value);
|
||
});
|
||
|
||
test('passes in projectConfig', () => {
|
||
const value = {};
|
||
element.projectConfig = value;
|
||
assert.equal(element.$.diff.projectConfig, value);
|
||
});
|
||
|
||
test('passes in changeNum', () => {
|
||
const value = '12345';
|
||
element.changeNum = value;
|
||
assert.equal(element.$.diff.changeNum, value);
|
||
});
|
||
|
||
test('passes in projectName', () => {
|
||
const value = 'Gerrit';
|
||
element.projectName = value;
|
||
assert.equal(element.$.diff.projectName, value);
|
||
});
|
||
|
||
test('passes in displayLine', () => {
|
||
const value = true;
|
||
element.displayLine = value;
|
||
assert.equal(element.$.diff.displayLine, value);
|
||
});
|
||
|
||
test('passes in commitRange', () => {
|
||
const value = {};
|
||
element.commitRange = value;
|
||
assert.equal(element.$.diff.commitRange, value);
|
||
});
|
||
|
||
test('passes in hidden', () => {
|
||
const value = true;
|
||
element.hidden = value;
|
||
assert.equal(element.$.diff.hidden, value);
|
||
assert.isNotNull(element.getAttribute('hidden'));
|
||
});
|
||
|
||
test('passes in noRenderOnPrefsChange', () => {
|
||
const value = true;
|
||
element.noRenderOnPrefsChange = value;
|
||
assert.equal(element.$.diff.noRenderOnPrefsChange, value);
|
||
});
|
||
|
||
test('passes in comments', () => {
|
||
const value = {left: [], right: []};
|
||
element.comments = value;
|
||
assert.equal(element.$.diff.comments, value);
|
||
});
|
||
|
||
test('passes in lineWrapping', () => {
|
||
const value = true;
|
||
element.lineWrapping = value;
|
||
assert.equal(element.$.diff.lineWrapping, value);
|
||
});
|
||
|
||
test('passes in viewMode', () => {
|
||
const value = 'SIDE_BY_SIDE';
|
||
element.viewMode = value;
|
||
assert.equal(element.$.diff.viewMode, value);
|
||
});
|
||
|
||
test('passes in lineOfInterest', () => {
|
||
const value = {number: 123, leftSide: true};
|
||
element.lineOfInterest = value;
|
||
assert.equal(element.$.diff.lineOfInterest, value);
|
||
});
|
||
|
||
suite('_reportDiff', () => {
|
||
let reportStub;
|
||
|
||
setup(() => {
|
||
element = fixture('basic');
|
||
element.patchRange = {basePatchNum: 1};
|
||
reportStub = sandbox.stub(element.$.reporting, 'reportInteraction');
|
||
});
|
||
|
||
test('null and content-less', () => {
|
||
element._reportDiff(null);
|
||
assert.isFalse(reportStub.called);
|
||
|
||
element._reportDiff({});
|
||
assert.isFalse(reportStub.called);
|
||
});
|
||
|
||
test('diff w/ no delta', () => {
|
||
const diff = {
|
||
content: [
|
||
{ab: ['foo', 'bar']},
|
||
{ab: ['baz', 'foo']},
|
||
],
|
||
};
|
||
element._reportDiff(diff);
|
||
assert.isTrue(reportStub.calledOnce);
|
||
assert.equal(reportStub.lastCall.args[0], 'rebase-percent-zero');
|
||
assert.isUndefined(reportStub.lastCall.args[1]);
|
||
});
|
||
|
||
test('diff w/ no rebase delta', () => {
|
||
const diff = {
|
||
content: [
|
||
{ab: ['foo', 'bar']},
|
||
{a: ['baz', 'foo']},
|
||
{ab: ['foo', 'bar']},
|
||
{a: ['baz', 'foo'], b: ['bar', 'baz']},
|
||
{ab: ['foo', 'bar']},
|
||
{b: ['baz', 'foo']},
|
||
{ab: ['foo', 'bar']},
|
||
],
|
||
};
|
||
element._reportDiff(diff);
|
||
assert.isTrue(reportStub.calledOnce);
|
||
assert.equal(reportStub.lastCall.args[0], 'rebase-percent-zero');
|
||
assert.isUndefined(reportStub.lastCall.args[1]);
|
||
});
|
||
|
||
test('diff w/ some rebase delta', () => {
|
||
const diff = {
|
||
content: [
|
||
{ab: ['foo', 'bar']},
|
||
{a: ['baz', 'foo'], due_to_rebase: true},
|
||
{ab: ['foo', 'bar']},
|
||
{a: ['baz', 'foo'], b: ['bar', 'baz']},
|
||
{ab: ['foo', 'bar']},
|
||
{b: ['baz', 'foo'], due_to_rebase: true},
|
||
{ab: ['foo', 'bar']},
|
||
{a: ['baz', 'foo']},
|
||
],
|
||
};
|
||
element._reportDiff(diff);
|
||
assert.isTrue(reportStub.calledOnce);
|
||
assert.equal(reportStub.lastCall.args[0], 'rebase-percent-nonzero');
|
||
assert.strictEqual(reportStub.lastCall.args[1], 50);
|
||
});
|
||
|
||
test('diff w/ all rebase delta', () => {
|
||
const diff = {content: [{
|
||
a: ['foo', 'bar'],
|
||
b: ['baz', 'foo'],
|
||
due_to_rebase: true,
|
||
}]};
|
||
element._reportDiff(diff);
|
||
assert.isTrue(reportStub.calledOnce);
|
||
assert.equal(reportStub.lastCall.args[0], 'rebase-percent-nonzero');
|
||
assert.strictEqual(reportStub.lastCall.args[1], 100);
|
||
});
|
||
|
||
test('diff against parent event', () => {
|
||
element.patchRange.basePatchNum = 'PARENT';
|
||
const diff = {content: [{
|
||
a: ['foo', 'bar'],
|
||
b: ['baz', 'foo'],
|
||
}]};
|
||
element._reportDiff(diff);
|
||
assert.isTrue(reportStub.calledOnce);
|
||
assert.equal(reportStub.lastCall.args[0], 'diff-against-parent');
|
||
assert.isUndefined(reportStub.lastCall.args[1]);
|
||
});
|
||
});
|
||
|
||
suite('_translateChunksToIgnore', () => {
|
||
let content;
|
||
|
||
setup(() => {
|
||
content = [
|
||
{ab: ['one', 'two']},
|
||
{a: ['three'], b: ['different three']},
|
||
{b: ['four']},
|
||
{ab: ['five', 'six']},
|
||
{a: ['seven']},
|
||
{ab: ['eight', 'nine']},
|
||
];
|
||
});
|
||
|
||
test('does nothing to unmarked diff', () => {
|
||
assert.deepEqual(element._translateChunksToIgnore({content}),
|
||
{content});
|
||
});
|
||
|
||
test('merges marked delta chunk', () => {
|
||
content[1].common = true;
|
||
assert.deepEqual(element._translateChunksToIgnore({content}), {
|
||
content: [
|
||
{ab: ['one', 'two', 'different three']},
|
||
{b: ['four']},
|
||
{ab: ['five', 'six']},
|
||
{a: ['seven']},
|
||
{ab: ['eight', 'nine']},
|
||
],
|
||
});
|
||
});
|
||
|
||
test('merges marked addition chunk', () => {
|
||
content[2].common = true;
|
||
assert.deepEqual(element._translateChunksToIgnore({content}), {
|
||
content: [
|
||
{ab: ['one', 'two']},
|
||
{a: ['three'], b: ['different three']},
|
||
{ab: ['four', 'five', 'six']},
|
||
{a: ['seven']},
|
||
{ab: ['eight', 'nine']},
|
||
],
|
||
});
|
||
});
|
||
|
||
test('merges multiple marked delta', () => {
|
||
content[1].common = true;
|
||
content[2].common = true;
|
||
assert.deepEqual(element._translateChunksToIgnore({content}), {
|
||
content: [
|
||
{ab: ['one', 'two', 'different three', 'four', 'five', 'six']},
|
||
{a: ['seven']},
|
||
{ab: ['eight', 'nine']},
|
||
],
|
||
});
|
||
});
|
||
|
||
test('marked deletion chunks are omitted', () => {
|
||
content[4].common = true;
|
||
assert.deepEqual(element._translateChunksToIgnore({content}), {
|
||
content: [
|
||
{ab: ['one', 'two']},
|
||
{a: ['three'], b: ['different three']},
|
||
{b: ['four']},
|
||
{ab: ['five', 'six', 'eight', 'nine']},
|
||
],
|
||
});
|
||
});
|
||
|
||
test('marked deltas can start shared chunks', () => {
|
||
content[0] = {a: ['one'], b: ['two'], common: true};
|
||
assert.deepEqual(element._translateChunksToIgnore({content}), {
|
||
content: [
|
||
{ab: ['two']},
|
||
{a: ['three'], b: ['different three']},
|
||
{b: ['four']},
|
||
{ab: ['five', 'six']},
|
||
{a: ['seven']},
|
||
{ab: ['eight', 'nine']},
|
||
],
|
||
});
|
||
});
|
||
});
|
||
});
|
||
</script>
|