move mutation tests

This commit is contained in:
webzwo0i 2020-07-30 16:28:27 +02:00
parent 18f6fd7cf4
commit a2a1fd0490
3 changed files with 243 additions and 232 deletions

View file

@ -28,14 +28,13 @@ var helper = require("./helper.js")
var assert = helper.assert;
var literal = helper.literal;
//var throughIterator = helper.throughIterator;
var assertEqualStrings = helper.assertEqualStrings;
var assertEqualArrays = helper.assertEqualArrays;
function random() {
this.nextInt = function (maxValue) {
return Math.floor(Math.random() * maxValue);
}
// maxValue is not used
this.nextDouble = function (maxValue) {
return Math.random();
}
@ -52,238 +51,8 @@ function random() {
// assert("throughSmartAssembler(" + literal(x) + ") == " + literal(x));
// })();
function applyMutations(mu, arrayOfArrays) {
arrayOfArrays.forEach(function (a) {
var result = mu[a[0]].apply(mu, a.slice(1));
if (a[0] == 'remove' && a[3]) {
assertEqualStrings(a[3], result);
}
});
}
function mutationsToChangeset(oldLen, arrayOfArrays) {
var assem = Changeset.smartOpAssembler();
var op = Changeset.newOp();
var bank = Changeset.stringAssembler();
var oldPos = 0;
var newLen = 0;
arrayOfArrays.forEach(function (a) {
if (a[0] == 'skip') {
op.opcode = '=';
op.chars = a[1];
op.lines = (a[2] || 0);
assem.append(op);
oldPos += op.chars;
newLen += op.chars;
} else if (a[0] == 'remove') {
op.opcode = '-';
op.chars = a[1];
op.lines = (a[2] || 0);
assem.append(op);
oldPos += op.chars;
} else if (a[0] == 'insert') {
op.opcode = '+';
bank.append(a[1]);
op.chars = a[1].length;
op.lines = (a[2] || 0);
assem.append(op);
newLen += op.chars;
}
});
newLen += oldLen - oldPos;
assem.endDocument();
return Changeset.pack(oldLen, newLen, assem.toString(), bank.toString());
}
function runMutationTest(origLines, muts) {
var lines1 = origLines.slice();
var mu = Changeset.textLinesMutator(lines1);
applyMutations(mu, muts);
mu.close();
var inText = origLines.join('');
var cs = mutationsToChangeset(inText.length, muts);
lines2 = origLines.slice();
Changeset.mutateTextLines(cs, lines2);
var outText = Changeset.applyToText(cs, inText);
return [lines1,lines2,outText];
}
describe("text line mutations",function(){
it("applies mutations to an array of lines #1",function(done){
var expected = ["tuple\n", "banana\n", "cream\n", "pie\n", "cabot\n", "bubba\n", "eggplant\n"];
var result = runMutationTest(["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"], [
['remove', 1, 0, "a"],
['insert', "tu"],
['remove', 1, 0, "p"],
['skip', 4, 1],
['skip', 7, 1],
['insert', "cream\npie\n", 2],
['skip', 2],
['insert', "bot"],
['insert', "\n", 1],
['insert', "bu"],
['skip', 3],
['remove', 3, 1, "ge\n"],
['remove', 6, 0, "duffle"]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #2",function(done){
var expected = ["tuple\n", "banana\n", "cream\n", "pie\n", "cabot\n", "bubba\n", "eggplant\n"];
var result = runMutationTest(["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"], [
['remove', 1, 0, "a"],
['remove', 1, 0, "p"],
['insert', "tu"],
['skip', 11, 2],
['insert', "cream\npie\n", 2],
['skip', 2],
['insert', "bot"],
['insert', "\n", 1],
['insert', "bu"],
['skip', 3],
['remove', 3, 1, "ge\n"],
['remove', 6, 0, "duffle"]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #3",function(done){
var expected = ["banana\n", "cabbage\n", "duffle\n"];
var result = runMutationTest(["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"], [
['remove', 6, 1, "apple\n"],
['skip', 15, 2],
['skip', 6],
['remove', 1, 1, "\n"],
['remove', 8, 0, "eggplant"],
['skip', 1, 1]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #4",function(done){
var expected = ["1\n", "2\n", "3\n", "4\n", "5\n"];
var result = runMutationTest(["15\n"], [
['skip', 1],
['insert', "\n2\n3\n4\n", 4],
['skip', 2, 1]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #5",function(done){
var expected = ["15\n"];
var result = runMutationTest(["1\n", "2\n", "3\n", "4\n", "5\n"], [
['skip', 1],
['remove', 7, 4, "\n2\n3\n4\n"],
['skip', 2, 1]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #6",function(done){
var expected = ["0123\n", "abc\n", "xyz\n"];
var result = runMutationTest(["123\n", "abc\n", "def\n", "ghi\n", "xyz\n"], [
['insert', "0"],
['skip', 4, 1],
['skip', 4, 1],
['remove', 8, 2, "def\nghi\n"],
['skip', 4, 1]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #7",function(done){
var expected = ["banana\n", "cabbage\n", "duffle\n"];
var result = runMutationTest(["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"], [
['remove', 6, 1, "apple\n"],
['skip', 15, 2, true],
['skip', 6, 0, true],
['remove', 1, 1, "\n"],
['remove', 8, 0, "eggplant"],
['skip', 1, 1, true]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
// #2836 regressions
xit("applies mutations to an array of lines #8",function(done){
var expected = ["foo\n","c"];
var result = runMutationTest(["\n","foo\n","\n"], [
['remove', 1, 1, "\n"],
['skip', 4, 1, false],
['remove', 1, 1, "\n"],
['insert',"c"]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
xit("applies mutations to an array of lines #9",function(done){
var expected = ["fooc"];
var result = runMutationTest(["\n","foo\n","\n"], [
['remove', 1, 1, "\n"],
['skip', 3, 0, false],
['remove', 2, 2, "\n\n"],
['insert',"c"]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
xit("applies mutations to an array of lines #10",function(done){
var expected = ["c"]; //TODO find out if c must have a newline because of unknown constraints
var result = runMutationTest(["\n"], [
['remove', 1, 1, "\n"],
['insert',"c", 0]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
xit("applies mutations to an array of lines #11",function(done){
var expected = ["ac\n"];
var result = runMutationTest(["\n"], [
['remove', 1, 1, "\n"],
['insert', "a"],
['insert',"c\n", 1]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
xit("applies mutations to an array of lines #12",function(done){
var expected = ["a\n","c"]; //TODO find out if c must have a newline because of unknown constraints
var result = runMutationTest(["\n"], [
['remove', 1, 1, "\n"],
['insert', "a\n", 1],
['insert',"c"]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
})
function poolOrArray(attribs) {
@ -369,6 +138,7 @@ describe("textLinesMutator",function(){
function runMutateAttributionTest(testId, attribs, cs, alines, outCorrect) {
var p = poolOrArray(attribs);
var alines2 = Array.prototype.slice.call(alines);
// result is never used
var result = Changeset.mutateAttributionLines(
Changeset.checkRep(cs), alines2, p);
assertEqualArrays(outCorrect, alines2);
@ -558,6 +328,7 @@ describe("textLinesMutator",function(){
// assumes attrib pool like ['apple,','apple,true','banana,','banana,true']
if (opcode == '-' || rand.nextInt(3)) {
return '';
// branch never taken
} else if (rand.nextInt(3)) {
if (opcode == '+' || rand.nextInt(2)) {
return '*' + Changeset.numToString(rand.nextInt(2) * 2 + 1);

View file

@ -17,6 +17,7 @@ exports.assertEqualStrings = function (a, b) {
return a === b
}
// not used
exports.throughIterator = function (opsStr) {
var iter = Changeset.opIterator(opsStr);
var assem = Changeset.opAssembler();
@ -26,6 +27,7 @@ exports.throughIterator = function (opsStr) {
return assem.toString();
}
// not used
exports.throughSmartAssembler = function (opsStr) {
var iter = Changeset.opIterator(opsStr);
var assem = Changeset.smartOpAssembler();

View file

@ -0,0 +1,238 @@
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
var helper = require("./helper.js")
var assertEqualStrings = helper.assertEqualStrings;
var assertEqualArrays = helper.assertEqualArrays;
describe("text line mutations",function(){
it("applies mutations to an array of lines #1",function(done){
var expected = ["tuple\n", "banana\n", "cream\n", "pie\n", "cabot\n", "bubba\n", "eggplant\n"];
var result = runMutationTest(["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"], [
['remove', 1, 0, "a"],
['insert', "tu"],
['remove', 1, 0, "p"],
['skip', 4, 1],
['skip', 7, 1],
['insert', "cream\npie\n", 2],
['skip', 2],
['insert', "bot"],
['insert', "\n", 1],
['insert', "bu"],
['skip', 3],
['remove', 3, 1, "ge\n"],
['remove', 6, 0, "duffle"]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #2",function(done){
var expected = ["tuple\n", "banana\n", "cream\n", "pie\n", "cabot\n", "bubba\n", "eggplant\n"];
var result = runMutationTest(["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"], [
['remove', 1, 0, "a"],
['remove', 1, 0, "p"],
['insert', "tu"],
['skip', 11, 2],
['insert', "cream\npie\n", 2],
['skip', 2],
['insert', "bot"],
['insert', "\n", 1],
['insert', "bu"],
['skip', 3],
['remove', 3, 1, "ge\n"],
['remove', 6, 0, "duffle"]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #3",function(done){
var expected = ["banana\n", "cabbage\n", "duffle\n"];
var result = runMutationTest(["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"], [
['remove', 6, 1, "apple\n"],
['skip', 15, 2],
['skip', 6],
['remove', 1, 1, "\n"],
['remove', 8, 0, "eggplant"],
['skip', 1, 1]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #4",function(done){
var expected = ["1\n", "2\n", "3\n", "4\n", "5\n"];
var result = runMutationTest(["15\n"], [
['skip', 1],
['insert', "\n2\n3\n4\n", 4],
['skip', 2, 1]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #5",function(done){
var expected = ["15\n"];
var result = runMutationTest(["1\n", "2\n", "3\n", "4\n", "5\n"], [
['skip', 1],
['remove', 7, 4, "\n2\n3\n4\n"],
['skip', 2, 1]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #6",function(done){
var expected = ["0123\n", "abc\n", "xyz\n"];
var result = runMutationTest(["123\n", "abc\n", "def\n", "ghi\n", "xyz\n"], [
['insert', "0"],
['skip', 4, 1],
['skip', 4, 1],
['remove', 8, 2, "def\nghi\n"],
['skip', 4, 1]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
it("applies mutations to an array of lines #7",function(done){
var expected = ["banana\n", "cabbage\n", "duffle\n"];
var result = runMutationTest(["apple\n", "banana\n", "cabbage\n", "duffle\n", "eggplant\n"], [
['remove', 6, 1, "apple\n"],
['skip', 15, 2, true],
['skip', 6, 0, true],
['remove', 1, 1, "\n"],
['remove', 8, 0, "eggplant"],
['skip', 1, 1, true]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
// #2836 regressions
xit("applies mutations to an array of lines #8",function(done){
var expected = ["foo\n","c"];
var result = runMutationTest(["\n","foo\n","\n"], [
['remove', 1, 1, "\n"],
['skip', 4, 1, false],
['remove', 1, 1, "\n"],
['insert',"c"]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
xit("applies mutations to an array of lines #9",function(done){
var expected = ["fooc"];
var result = runMutationTest(["\n","foo\n","\n"], [
['remove', 1, 1, "\n"],
['skip', 3, 0, false],
['remove', 2, 2, "\n\n"],
['insert',"c"]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
xit("applies mutations to an array of lines #10",function(done){
var expected = ["c"]; //TODO find out if c must have a newline because of unknown constraints
var result = runMutationTest(["\n"], [
['remove', 1, 1, "\n"],
['insert',"c", 0]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
xit("applies mutations to an array of lines #11",function(done){
var expected = ["ac\n"];
var result = runMutationTest(["\n"], [
['remove', 1, 1, "\n"],
['insert', "a"],
['insert',"c\n", 1]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
xit("applies mutations to an array of lines #12",function(done){
var expected = ["a\n","c"]; //TODO find out if c must have a newline because of unknown constraints
var result = runMutationTest(["\n"], [
['remove', 1, 1, "\n"],
['insert', "a\n", 1],
['insert',"c"]
]);
if (!assertEqualArrays(result[0], expected)) throw new Error("textLinesMutator result is wrong: expected "+expected+" got "+result[0]);
if (!assertEqualArrays(result[1], expected)) throw new Error("mutateTextLines result is wrong: expected "+expected+" got "+result[1]);
if (!assertEqualStrings(result[2], expected.join(''))) throw new Error('applyToText result is wrong: expected '+expected.join('')+" got "+result[2]);
done()
})
})
function runMutationTest(origLines, muts) {
var lines1 = origLines.slice();
var mu = Changeset.textLinesMutator(lines1);
applyMutations(mu, muts);
mu.close();
var inText = origLines.join('');
var cs = mutationsToChangeset(inText.length, muts);
lines2 = origLines.slice();
Changeset.mutateTextLines(cs, lines2);
var outText = Changeset.applyToText(cs, inText);
return [lines1,lines2,outText];
}
function applyMutations(mu, arrayOfArrays) {
arrayOfArrays.forEach(function (a) {
var result = mu[a[0]].apply(mu, a.slice(1));
if (a[0] == 'remove' && a[3]) {
assertEqualStrings(a[3], result);
}
});
}
function mutationsToChangeset(oldLen, arrayOfArrays) {
var assem = Changeset.smartOpAssembler();
var op = Changeset.newOp();
var bank = Changeset.stringAssembler();
var oldPos = 0;
var newLen = 0;
arrayOfArrays.forEach(function (a) {
if (a[0] == 'skip') {
op.opcode = '=';
op.chars = a[1];
op.lines = (a[2] || 0);
assem.append(op);
oldPos += op.chars;
newLen += op.chars;
} else if (a[0] == 'remove') {
op.opcode = '-';
op.chars = a[1];
op.lines = (a[2] || 0);
assem.append(op);
oldPos += op.chars;
} else if (a[0] == 'insert') {
op.opcode = '+';
bank.append(a[1]);
op.chars = a[1].length;
op.lines = (a[2] || 0);
assem.append(op);
newLen += op.chars;
}
});
newLen += oldLen - oldPos;
assem.endDocument();
return Changeset.pack(oldLen, newLen, assem.toString(), bank.toString());
}