/** * @license * 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. */ import '../test/common-test-setup-karma.js'; import { _testOnly_computeWipForPatchSets, computeAllPatchSets, fetchChangeUpdates, findEditParentPatchNum, findEditParentRevision, getParentIndex, getRevisionByPatchNum, isMergeParent, patchNumEquals, sortRevisions, } from './patch-set-util.js'; suite('gr-patch-set-util tests', () => { test('getRevisionByPatchNum', () => { const revisions = [ {_number: 0}, {_number: 1}, {_number: 2}, ]; assert.deepEqual(getRevisionByPatchNum(revisions, '1'), revisions[1]); assert.deepEqual(getRevisionByPatchNum(revisions, 2), revisions[2]); assert.equal(getRevisionByPatchNum(revisions, '3'), undefined); }); test('fetchChangeUpdates on latest', done => { const knownChange = { revisions: { sha1: {description: 'patch 1', _number: 1}, sha2: {description: 'patch 2', _number: 2}, }, status: 'NEW', messages: [], }; const mockRestApi = { getChangeDetail() { return Promise.resolve(knownChange); }, }; fetchChangeUpdates(knownChange, mockRestApi) .then(result => { assert.isTrue(result.isLatest); assert.isNotOk(result.newStatus); assert.isFalse(result.newMessages); done(); }); }); test('fetchChangeUpdates not on latest', done => { const knownChange = { revisions: { sha1: {description: 'patch 1', _number: 1}, sha2: {description: 'patch 2', _number: 2}, }, status: 'NEW', messages: [], }; const actualChange = { revisions: { sha1: {description: 'patch 1', _number: 1}, sha2: {description: 'patch 2', _number: 2}, sha3: {description: 'patch 3', _number: 3}, }, status: 'NEW', messages: [], }; const mockRestApi = { getChangeDetail() { return Promise.resolve(actualChange); }, }; fetchChangeUpdates(knownChange, mockRestApi) .then(result => { assert.isFalse(result.isLatest); assert.isNotOk(result.newStatus); assert.isFalse(result.newMessages); done(); }); }); test('fetchChangeUpdates new status', done => { const knownChange = { revisions: { sha1: {description: 'patch 1', _number: 1}, sha2: {description: 'patch 2', _number: 2}, }, status: 'NEW', messages: [], }; const actualChange = { revisions: { sha1: {description: 'patch 1', _number: 1}, sha2: {description: 'patch 2', _number: 2}, }, status: 'MERGED', messages: [], }; const mockRestApi = { getChangeDetail() { return Promise.resolve(actualChange); }, }; fetchChangeUpdates(knownChange, mockRestApi) .then(result => { assert.isTrue(result.isLatest); assert.equal(result.newStatus, 'MERGED'); assert.isFalse(result.newMessages); done(); }); }); test('fetchChangeUpdates new messages', done => { const knownChange = { revisions: { sha1: {description: 'patch 1', _number: 1}, sha2: {description: 'patch 2', _number: 2}, }, status: 'NEW', messages: [], }; const actualChange = { revisions: { sha1: {description: 'patch 1', _number: 1}, sha2: {description: 'patch 2', _number: 2}, }, status: 'NEW', messages: [{message: 'blah blah'}], }; const mockRestApi = { getChangeDetail() { return Promise.resolve(actualChange); }, }; fetchChangeUpdates(knownChange, mockRestApi) .then(result => { assert.isTrue(result.isLatest); assert.isNotOk(result.newStatus); assert.isTrue(result.newMessages); done(); }); }); test('_computeWipForPatchSets', () => { // Compute patch sets for a given timeline on a change. The initial WIP // property of the change can be true or false. The map of tags by // revision is keyed by patch set number. Each value is a list of change // message tags in the order that they occurred in the timeline. These // indicate actions that modify the WIP property of the change and/or // create new patch sets. // // Returns the actual results with an assertWip method that can be used // to compare against an expected value for a particular patch set. const compute = (initialWip, tagsByRevision) => { const change = { messages: [], work_in_progress: initialWip, }; const revs = Object.keys(tagsByRevision).sort((a, b) => a - b); for (const rev of revs) { for (const tag of tagsByRevision[rev]) { change.messages.push({ tag, _revision_number: rev, }); } } let patchNums = revs.map(rev => { return {num: rev}; }); patchNums = _testOnly_computeWipForPatchSets( change, patchNums); const actualWipsByRevision = {}; for (const patchNum of patchNums) { actualWipsByRevision[patchNum.num] = patchNum.wip; } const verifier = { assertWip(revision, expectedWip) { const patchNum = patchNums.find(patchNum => patchNum.num == revision); if (!patchNum) { assert.fail('revision ' + revision + ' not found'); } assert.equal(patchNum.wip, expectedWip, 'wip state for ' + revision + ' is ' + patchNum.wip + '; expected ' + expectedWip); return verifier; }, }; return verifier; }; compute(false, {1: ['upload']}).assertWip(1, false); compute(true, {1: ['upload']}).assertWip(1, true); const setWip = 'autogenerated:gerrit:setWorkInProgress'; const uploadInWip = 'autogenerated:gerrit:newWipPatchSet'; const clearWip = 'autogenerated:gerrit:setReadyForReview'; compute(false, { 1: ['upload', setWip], 2: ['upload'], 3: ['upload', clearWip], 4: ['upload', setWip], }).assertWip(1, false) // Change was created with PS1 ready for review .assertWip(2, true) // PS2 was uploaded during WIP .assertWip(3, false) // PS3 was marked ready for review after upload .assertWip(4, false); // PS4 was uploaded ready for review compute(false, { 1: [uploadInWip, null, 'addReviewer'], 2: ['upload'], 3: ['upload', clearWip, setWip], 4: ['upload'], 5: ['upload', clearWip], 6: [uploadInWip], }).assertWip(1, true) // Change was created in WIP .assertWip(2, true) // PS2 was uploaded during WIP .assertWip(3, false) // PS3 was marked ready for review .assertWip(4, true) // PS4 was uploaded during WIP .assertWip(5, false) // PS5 was marked ready for review .assertWip(6, true); // PS6 was uploaded with WIP option }); test('patchNumEquals', () => { assert.isFalse(patchNumEquals('edit', 'PARENT')); assert.isFalse(patchNumEquals('edit', NaN)); assert.isFalse(patchNumEquals(1, '2')); assert.isTrue(patchNumEquals(1, '1')); assert.isTrue(patchNumEquals(1, 1)); assert.isTrue(patchNumEquals('edit', 'edit')); assert.isTrue(patchNumEquals('PARENT', 'PARENT')); }); test('isMergeParent', () => { assert.isFalse(isMergeParent(1)); assert.isFalse(isMergeParent(4321)); assert.isFalse(isMergeParent('52')); assert.isFalse(isMergeParent('edit')); assert.isFalse(isMergeParent('PARENT')); assert.isFalse(isMergeParent(0)); assert.isTrue(isMergeParent(-23)); assert.isTrue(isMergeParent(-1)); assert.isTrue(isMergeParent('-42')); }); test('findEditParentRevision', () => { let revisions = [ {_number: 0}, {_number: 1}, {_number: 2}, ]; assert.strictEqual(findEditParentRevision(revisions), null); revisions = [...revisions, {_number: 'edit', basePatchNum: 3}]; assert.strictEqual(findEditParentRevision(revisions), null); revisions = [...revisions, {_number: 3}]; assert.deepEqual(findEditParentRevision(revisions), {_number: 3}); }); test('findEditParentPatchNum', () => { let revisions = [ {_number: 0}, {_number: 1}, {_number: 2}, ]; assert.equal(findEditParentPatchNum(revisions), -1); revisions = [...revisions, {_number: 'edit', basePatchNum: 3}, {_number: 3}]; assert.deepEqual(findEditParentPatchNum(revisions), 3); }); test('sortRevisions', () => { const revisions = [ {_number: 0}, {_number: 2}, {_number: 1}, ]; const sorted = [ {_number: 2}, {_number: 1}, {_number: 0}, ]; assert.deepEqual(sortRevisions(revisions), sorted); // Edit patchset should follow directly after its basePatchNum. revisions.push({_number: 'edit', basePatchNum: 2}); sorted.unshift({_number: 'edit', basePatchNum: 2}); assert.deepEqual(sortRevisions(revisions), sorted); revisions[0].basePatchNum = 0; const edit = sorted.shift(); edit.basePatchNum = 0; // Edit patchset should be at index 2. sorted.splice(2, 0, edit); assert.deepEqual(sortRevisions(revisions), sorted); }); test('getParentIndex', () => { assert.equal(getParentIndex('-13'), 13); assert.equal(getParentIndex(-4), 4); }); test('computeAllPatchSets', () => { const expected = [ {num: 4, desc: 'test', sha: 'rev4'}, {num: 3, desc: 'test', sha: 'rev3'}, {num: 2, desc: 'test', sha: 'rev2'}, {num: 1, desc: 'test', sha: 'rev1'}, ]; const patchNums = computeAllPatchSets({ revisions: { rev3: {_number: 3, description: 'test', date: 3}, rev1: {_number: 1, description: 'test', date: 1}, rev4: {_number: 4, description: 'test', date: 4}, rev2: {_number: 2, description: 'test', date: 2}, }, }); assert.equal(patchNums.length, expected.length); for (let i = 0; i < expected.length; i++) { assert.deepEqual(patchNums[i], expected[i]); } }); });