140 lines
4.0 KiB
JavaScript
140 lines
4.0 KiB
JavaScript
var _ = require('lodash');
|
|
var fuzzer = require('ot-fuzzer');
|
|
var richType = require('../lib/type');
|
|
var Delta = richType.Delta;
|
|
|
|
var FORMATS = {
|
|
color: ['red', 'orange', 'yellow', 'green', 'blue', 'purple', null],
|
|
font: ['serif', 'sans-serif', 'monospace', null],
|
|
bold: [true, null],
|
|
italic: [true, null]
|
|
};
|
|
|
|
|
|
function generateRandomFormat (includeNull) {
|
|
var format = {};
|
|
for (var key in FORMATS) {
|
|
if (fuzzer.randomReal() < 0.5) {
|
|
var value = FORMATS[key][fuzzer.randomInt(FORMATS[key].length)];
|
|
if (value || includeNull) {
|
|
format[key] = value;
|
|
}
|
|
}
|
|
}
|
|
return Object.keys(format).length > 0 ? format : undefined;
|
|
};
|
|
|
|
function generateRandomOp (snapshot) {
|
|
snapshot = _.cloneDeep(snapshot);
|
|
var length = snapshot.ops.reduce(function(length, op) {
|
|
if (!op.insert) {
|
|
console.error(snapshot);
|
|
throw new Error('Snapshot should only have inserts');
|
|
}
|
|
// Snapshot should only have inserts
|
|
return length + (_.isString(op.insert) ? op.insert.length : 1);
|
|
}, 0);
|
|
|
|
var base = length > 100 ? 10 : 7; // Favor deleting on long documents
|
|
var delta = new Delta();
|
|
var result = new Delta();
|
|
|
|
do {
|
|
// Allows insert/delete to occur at the end (deletes will be noop)
|
|
var modIndex = fuzzer.randomInt(Math.min(length, 5) + 1);
|
|
length -= modIndex;
|
|
var modLength = Math.min(length, fuzzer.randomInt(4) + 1);
|
|
|
|
delta.retain(modIndex);
|
|
var ops = next(snapshot, modIndex);
|
|
for (var i in ops) {
|
|
result.push(ops[i]);
|
|
}
|
|
|
|
switch (fuzzer.randomInt(base)) {
|
|
case 0:
|
|
// Insert plain text
|
|
var word = fuzzer.randomWord();
|
|
delta.insert(word);
|
|
result.insert(word);
|
|
break;
|
|
case 1:
|
|
// Insert formatted text
|
|
var word = fuzzer.randomWord();
|
|
var formats = generateRandomFormat(false);
|
|
delta.insert(word, formats);
|
|
result.insert(word, formats);
|
|
break;
|
|
case 2:
|
|
// Insert embed
|
|
var type = fuzzer.randomInt(2) + 1;
|
|
var formats = generateRandomFormat(false);
|
|
delta.insert(type, formats);
|
|
result.insert(type, formats);
|
|
break;
|
|
case 3: case 4:
|
|
var attributes = generateRandomFormat(true);
|
|
delta.retain(modLength, attributes);
|
|
ops = next(snapshot, modLength);
|
|
for (var i in ops) {
|
|
ops[i].attributes = ops[i].attributes || {};
|
|
for (var key in attributes) {
|
|
ops[i].attributes[key] = (attributes[key] === null) ? undefined : attributes[key];
|
|
}
|
|
ops[i].attributes = _.reduce(ops[i].attributes, function (memo, value, key) {
|
|
if (value !== null && value !== undefined) {
|
|
memo[key] = value;
|
|
}
|
|
return memo;
|
|
}, {});
|
|
var newOp = { insert: ops[i].insert };
|
|
if (_.keys(ops[i].attributes).length > 0) newOp.attributes = ops[i].attributes;
|
|
result.push(newOp);
|
|
}
|
|
length -= modLength;
|
|
break;
|
|
default:
|
|
next(snapshot, modLength);
|
|
delta.delete(modLength);
|
|
length -= modLength;
|
|
break;
|
|
}
|
|
} while (length > 0 && fuzzer.randomInt(2) > 0);
|
|
|
|
for (var i in snapshot.ops) {
|
|
result.push(snapshot.ops[i]);
|
|
}
|
|
|
|
return [delta, result];
|
|
};
|
|
|
|
function next (snapshot, length) {
|
|
var ops = [];
|
|
while (length > 0) {
|
|
var opLength;
|
|
if (_.isString(snapshot.ops[0].insert)) {
|
|
if (length >= snapshot.ops[0].insert.length) {
|
|
opLength = snapshot.ops[0].insert.length;
|
|
ops.push(snapshot.ops.shift());
|
|
} else {
|
|
var insert = snapshot.ops[0].insert.substr(0, length);
|
|
snapshot.ops[0].insert = snapshot.ops[0].insert.substr(insert.length);
|
|
opLength = insert.length;
|
|
var op = { insert: insert };
|
|
if (snapshot.ops[0].attributes) {
|
|
op.attributes = _.clone(snapshot.ops[0].attributes);
|
|
}
|
|
ops.push(op);
|
|
}
|
|
} else {
|
|
ops.push(snapshot.ops.shift());
|
|
opLength = 1;
|
|
}
|
|
length -= opLength;
|
|
}
|
|
return ops;
|
|
};
|
|
|
|
|
|
fuzzer(richType, generateRandomOp, 100);
|