pad.libre-service.eu-etherpad/tests/backend/specs/easysync/inverserandom.js

280 lines
7.6 KiB
JavaScript
Raw Normal View History

2020-08-04 12:47:44 +02:00
var Changeset = require("ep_etherpad-lite/static/js/Changeset");
var AttributePool = require("ep_etherpad-lite/static/js/AttributePool");
var helper = require("./helper.js")
var assertEqualStrings = helper.assertEqualStrings;
var assertEqualArrays = helper.assertEqualArrays;
var assert = helper.assert;
describe("inverseRandom",function(){
it("inverseRandom",function(done){
for (var i = 0; i < 30; i++) testInverseRandom(i);
done();
})
})
function testInverseRandom(randomSeed) {
var rand = new random();
var p = poolOrArray(['apple,', 'apple,true', 'banana,', 'banana,true']);
var startText = randomMultiline(10, 20, rand) + '\n';
var alines = Changeset.splitAttributionLines(Changeset.makeAttribution(startText), startText);
var lines = startText.slice(0, -1).split('\n').map(function (s) {
return s + '\n';
});
var stylifier = randomTestChangeset(startText, rand, true)[0];
//print(alines.join('\n'));
Changeset.mutateAttributionLines(stylifier, alines, p);
//print(stylifier);
//print(alines.join('\n'));
Changeset.mutateTextLines(stylifier, lines);
var changeset = randomTestChangeset(lines.join(''), rand, true)[0];
var inverseChangeset = Changeset.inverse(changeset, lines, alines, p);
var origLines = lines.slice();
var origALines = alines.slice();
Changeset.mutateTextLines(changeset, lines);
Changeset.mutateAttributionLines(changeset, alines, p);
//print(origALines.join('\n'));
//print(changeset);
//print(inverseChangeset);
//print(origLines.map(function(s) { return '1: '+s.slice(0,-1); }).join('\n'));
//print(lines.map(function(s) { return '2: '+s.slice(0,-1); }).join('\n'));
//print(alines.join('\n'));
Changeset.mutateTextLines(inverseChangeset, lines);
Changeset.mutateAttributionLines(inverseChangeset, alines, p);
//print(lines.map(function(s) { return '3: '+s.slice(0,-1); }).join('\n'));
assertEqualArrays(origLines, lines);
assertEqualArrays(origALines, alines);
}
function random() {
this.nextInt = function (maxValue) {
return Math.floor(Math.random() * maxValue);
}
// maxValue is not used
this.nextDouble = function (maxValue) {
return Math.random();
}
}
function poolOrArray(attribs) {
if (attribs.getAttrib) {
return attribs; // it's already an attrib pool
} else {
// assume it's an array of attrib strings to be split and added
var p = new AttributePool();
attribs.forEach(function (kv) {
p.putAttrib(kv.split(','));
});
return p;
}
}
function randomMultiline(approxMaxLines, approxMaxCols, rand) {
var numParts = rand.nextInt(approxMaxLines * 2) + 1;
var txt = Changeset.stringAssembler();
txt.append(rand.nextInt(2) ? '\n' : '');
for (var i = 0; i < numParts; i++) {
if ((i % 2) == 0) {
if (rand.nextInt(10)) {
txt.append(randomInlineString(rand.nextInt(approxMaxCols) + 1, rand));
} else {
txt.append('\n');
}
} else {
txt.append('\n');
}
}
return txt.toString();
}
function randomInlineString(len, rand) {
var assem = Changeset.stringAssembler();
for (var i = 0; i < len; i++) {
assem.append(String.fromCharCode(rand.nextInt(26) + 97));
}
return assem.toString();
}
function randomTestChangeset(origText, rand, withAttribs) {
var charBank = Changeset.stringAssembler();
var textLeft = origText; // always keep final newline
var outTextAssem = Changeset.stringAssembler();
var opAssem = Changeset.smartOpAssembler();
var oldLen = origText.length;
var nextOp = Changeset.newOp();
function appendMultilineOp(opcode, txt) {
nextOp.opcode = opcode;
if (withAttribs) {
nextOp.attribs = randomTwoPropAttribs(opcode, rand);
}
txt.replace(/\n|[^\n]+/g, function (t) {
if (t == '\n') {
nextOp.chars = 1;
nextOp.lines = 1;
opAssem.append(nextOp);
} else {
nextOp.chars = t.length;
nextOp.lines = 0;
opAssem.append(nextOp);
}
return '';
});
}
function doOp() {
var o = randomStringOperation(textLeft.length, rand);
if (o.insert) {
var txt = o.insert;
charBank.append(txt);
outTextAssem.append(txt);
appendMultilineOp('+', txt);
} else if (o.skip) {
var txt = textLeft.substring(0, o.skip);
textLeft = textLeft.substring(o.skip);
outTextAssem.append(txt);
appendMultilineOp('=', txt);
} else if (o.remove) {
var txt = textLeft.substring(0, o.remove);
textLeft = textLeft.substring(o.remove);
appendMultilineOp('-', txt);
}
}
while (textLeft.length > 1) doOp();
for (var i = 0; i < 5; i++) doOp(); // do some more (only insertions will happen)
var outText = outTextAssem.toString() + '\n';
opAssem.endDocument();
var cs = Changeset.pack(oldLen, outText.length, opAssem.toString(), charBank.toString());
Changeset.checkRep(cs);
return [cs, outText];
}
function randomStringOperation(numCharsLeft, rand) {
var result;
switch (rand.nextInt(9)) {
case 0:
{
// insert char
result = {
insert: randomInlineString(1, rand)
};
break;
}
case 1:
{
// delete char
result = {
remove: 1
};
break;
}
case 2:
{
// skip char
result = {
skip: 1
};
break;
}
case 3:
{
// insert small
result = {
insert: randomInlineString(rand.nextInt(4) + 1, rand)
};
break;
}
case 4:
{
// delete small
result = {
remove: rand.nextInt(4) + 1
};
break;
}
case 5:
{
// skip small
result = {
skip: rand.nextInt(4) + 1
};
break;
}
case 6:
{
// insert multiline;
result = {
insert: randomMultiline(5, 20, rand)
};
break;
}
case 7:
{
// delete multiline
result = {
remove: Math.round(numCharsLeft * rand.nextDouble() * rand.nextDouble())
};
break;
}
case 8:
{
// skip multiline
result = {
skip: Math.round(numCharsLeft * rand.nextDouble() * rand.nextDouble())
};
break;
}
case 9:
{
// delete to end
result = {
remove: numCharsLeft
};
break;
}
case 10:
{
// skip to end
result = {
skip: numCharsLeft
};
break;
}
}
var maxOrig = numCharsLeft - 1;
if ('remove' in result) {
result.remove = Math.min(result.remove, maxOrig);
} else if ('skip' in result) {
result.skip = Math.min(result.skip, maxOrig);
}
return result;
}
function randomTwoPropAttribs(opcode, rand) {
// assumes attrib pool like ['apple,','apple,true','banana,','banana,true']
if (opcode == '-' || rand.nextInt(3)) {
return '';
// always true
} else if (rand.nextInt(3)) {
if (opcode == '+' || rand.nextInt(2)) {
return '*' + Changeset.numToString(rand.nextInt(2) * 2 + 1);
} else {
return '*' + Changeset.numToString(rand.nextInt(2) * 2);
}
} else {
if (opcode == '+' || rand.nextInt(4) == 0) {
return '*1*3';
} else {
return ['*0*2', '*0*3', '*1*2'][rand.nextInt(3)];
}
}
}
function assertEqualArrays(a, b) {
assert("JSON.stringify(" + literal(a) + ") == JSON.stringify(" + literal(b) + ")");
}