@fluidframework/merge-tree 2.22.0 → 2.23.0-323641
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/test/client.obliterateFarm.spec.d.ts.map +1 -1
- package/dist/test/client.obliterateFarm.spec.js +12 -0
- package/dist/test/client.obliterateFarm.spec.js.map +1 -1
- package/dist/test/obliterateOperations.d.ts +1 -0
- package/dist/test/obliterateOperations.d.ts.map +1 -1
- package/dist/test/obliterateOperations.js +35 -13
- package/dist/test/obliterateOperations.js.map +1 -1
- package/lib/test/client.obliterateFarm.spec.d.ts.map +1 -1
- package/lib/test/client.obliterateFarm.spec.js +13 -1
- package/lib/test/client.obliterateFarm.spec.js.map +1 -1
- package/lib/test/obliterateOperations.d.ts +1 -0
- package/lib/test/obliterateOperations.d.ts.map +1 -1
- package/lib/test/obliterateOperations.js +33 -12
- package/lib/test/obliterateOperations.js.map +1 -1
- package/package.json +18 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.obliterateFarm.spec.d.ts","sourceRoot":"","sources":["../../src/test/client.obliterateFarm.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EACN,YAAY,EACZ,+BAA+B,EAK/B,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"client.obliterateFarm.spec.d.ts","sourceRoot":"","sources":["../../src/test/client.obliterateFarm.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EACN,YAAY,EACZ,+BAA+B,EAK/B,MAAM,+BAA+B,CAAC;AAYvC,UAAU,qBAAsB,SAAQ,+BAA+B;IACtE,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,YAAY,CAAC;CACtB;AAgBD,eAAO,MAAM,cAAc,EAAE,qBAQ5B,CAAC"}
|
|
@@ -44,6 +44,18 @@ function runObliterateFarmTests(opts, extraSeed) {
|
|
|
44
44
|
// applyOpDuringGeneration: true,
|
|
45
45
|
},
|
|
46
46
|
},
|
|
47
|
+
{
|
|
48
|
+
name: "obliterate exact range allowing zero length",
|
|
49
|
+
config: {
|
|
50
|
+
...opts,
|
|
51
|
+
operations: [
|
|
52
|
+
obliterateOperations_js_1.annotateWithField,
|
|
53
|
+
obliterateOperations_js_1.insertAvoidField,
|
|
54
|
+
obliterateOperations_js_1.insertField,
|
|
55
|
+
obliterateOperations_js_1.obliterateFieldZeroLength,
|
|
56
|
+
],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
47
59
|
])
|
|
48
60
|
it(`${name}: ObliterateFarm_${minLength}`, async () => {
|
|
49
61
|
const random = (0, stochastic_test_utils_1.makeRandom)(0xdeadbeef, 0xfeedbed, minLength, extraSeed ?? 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.obliterateFarm.spec.js","sourceRoot":"","sources":["../../src/test/client.obliterateFarm.spec.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,gFAAsF;AAEtF,+EAOuC;AACvC,
|
|
1
|
+
{"version":3,"file":"client.obliterateFarm.spec.js","sourceRoot":"","sources":["../../src/test/client.obliterateFarm.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { createFuzzDescribe, makeRandom } from \"@fluid-private/stochastic-test-utils\";\n\nimport {\n\tIConfigRange,\n\tIMergeTreeOperationRunnerConfig,\n\tTestOperation,\n\tdoOverRange,\n\tgenerateClientNames,\n\trunMergeTreeOperationRunner,\n} from \"./mergeTreeOperationRunner.js\";\nimport {\n\tannotateWithField,\n\tgenerateInsertWithField,\n\tinsertAvoidField,\n\tinsertField,\n\tobliterateField,\n\tobliterateFieldZeroLength,\n\t// removeWithField,\n} from \"./obliterateOperations.js\";\nimport { TestClient } from \"./testClient.js\";\n\ninterface IObliterateFarmConfig extends IMergeTreeOperationRunnerConfig {\n\tminLength: IConfigRange;\n\tclients: IConfigRange;\n}\n\nconst allOperations: TestOperation[] = [\n\t// The test model is not currently stable enough to support removeWithField: logic to look for fields\n\t// relies on text inside fields being numeric and text outside of fields alphabetic, but if a removal\n\t// operation takes away a whole field, a concurrent field replace (obliterate + insert new field content)\n\t// can result in numeric characters outside of fields.\n\t// removeWithField,\n\tannotateWithField,\n\tinsertAvoidField,\n\tinsertField,\n\tobliterateField,\n];\n\n// Note: this test isn't totally stable for all options matrices. E.g. there appear to be some issues with\n// adding clients mid-run, which is likely related to known issues with obliterate and summarization.\nexport const defaultOptions: IObliterateFarmConfig = {\n\tminLength: { min: 1, max: 512 },\n\tclients: { min: 3, max: 3 },\n\topsPerRoundRange: { min: 1, max: 128 },\n\trounds: 8,\n\toperations: allOperations,\n\tgrowthFunc: (input: number) => input * 2,\n\tinsertText: generateInsertWithField,\n};\n\n// Generate a list of single character client names, support up to 69 clients\nconst clientNames = generateClientNames();\n\nfunction runObliterateFarmTests(opts: IObliterateFarmConfig, extraSeed?: number): void {\n\tdoOverRange(opts.minLength, opts.growthFunc, (minLength) => {\n\t\tfor (const { name, config } of [\n\t\t\t{\n\t\t\t\tname: \"obliterate with exact range replacement\",\n\t\t\t\tconfig: {\n\t\t\t\t\t...opts,\n\t\t\t\t\t// TODO: ensure that obliterate and inserts are not separated before enabling this\n\t\t\t\t\t// applyOpDuringGeneration: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"obliterate exact range allowing zero length\",\n\t\t\t\tconfig: {\n\t\t\t\t\t...opts,\n\t\t\t\t\toperations: [\n\t\t\t\t\t\tannotateWithField,\n\t\t\t\t\t\tinsertAvoidField,\n\t\t\t\t\t\tinsertField,\n\t\t\t\t\t\tobliterateFieldZeroLength,\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t},\n\t\t])\n\t\t\tit(`${name}: ObliterateFarm_${minLength}`, async () => {\n\t\t\t\tconst random = makeRandom(0xdeadbeef, 0xfeedbed, minLength, extraSeed ?? 0);\n\n\t\t\t\tconst clients: TestClient[] = [\n\t\t\t\t\tnew TestClient({\n\t\t\t\t\t\tmergeTreeEnableObliterate: true,\n\t\t\t\t\t\tmergeTreeEnableSidedObliterate: true,\n\t\t\t\t\t\tmergeTreeEnableAnnotateAdjust: true,\n\t\t\t\t\t}),\n\t\t\t\t];\n\t\t\t\tfor (const [i, c] of clients.entries()) c.startOrUpdateCollaboration(clientNames[i]);\n\n\t\t\t\tlet seq = 0;\n\t\t\t\twhile (clients.length < config.clients.max) {\n\t\t\t\t\tfor (const c of clients) c.updateMinSeq(seq);\n\n\t\t\t\t\t// Add double the number of clients each iteration\n\t\t\t\t\tconst targetClients = Math.max(\n\t\t\t\t\t\tconfig.clients.min,\n\t\t\t\t\t\tconfig.growthFunc(clients.length),\n\t\t\t\t\t);\n\t\t\t\t\tfor (let cc = clients.length; cc < targetClients; cc++) {\n\t\t\t\t\t\tconst newClient = await TestClient.createFromClientSnapshot(\n\t\t\t\t\t\t\tclients[0],\n\t\t\t\t\t\t\tclientNames[cc],\n\t\t\t\t\t\t);\n\t\t\t\t\t\tclients.push(newClient);\n\t\t\t\t\t}\n\n\t\t\t\t\tseq = runMergeTreeOperationRunner(random, seq, clients, minLength, config);\n\t\t\t\t}\n\t\t\t}).timeout(30 * 10000);\n\t});\n}\n\n// More tests pass, but due to how this farm selects ops, the tests take a while to run, and merge-tree\n// already a test suite on the longer side.\nconst describeFuzz = createFuzzDescribe({ defaultTestCount: 1 });\ndescribeFuzz(\"MergeTree.Client Obliterate\", ({ testCount }) => {\n\tif (testCount > 1) {\n\t\tdoOverRange(\n\t\t\t{ min: 0, max: testCount - 1 },\n\t\t\t(x) => x + 1,\n\t\t\t(seed) => {\n\t\t\t\tdescribe(`with seed ${seed}`, () => {\n\t\t\t\t\trunObliterateFarmTests(defaultOptions, seed);\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t} else {\n\t\trunObliterateFarmTests(defaultOptions);\n\t}\n});\n"]}
|
|
@@ -8,6 +8,7 @@ import { type TestOperation } from "./mergeTreeOperationRunner.js";
|
|
|
8
8
|
import type { TestClient } from "./testClient.js";
|
|
9
9
|
export declare const insertField: TestOperation;
|
|
10
10
|
export declare const obliterateField: TestOperation;
|
|
11
|
+
export declare const obliterateFieldZeroLength: TestOperation;
|
|
11
12
|
export declare const insertAvoidField: TestOperation;
|
|
12
13
|
export declare const removeWithField: TestOperation;
|
|
13
14
|
export declare const annotateWithField: TestOperation;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obliterateOperations.d.ts","sourceRoot":"","sources":["../../src/test/obliterateOperations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAGpE,OAAO,KAAK,EAAuB,YAAY,EAAE,MAAM,WAAW,CAAC;AAGnE,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAuElD,eAAO,MAAM,WAAW,EAAE,aAUzB,CAAC;
|
|
1
|
+
{"version":3,"file":"obliterateOperations.d.ts","sourceRoot":"","sources":["../../src/test/obliterateOperations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAGpE,OAAO,KAAK,EAAuB,YAAY,EAAE,MAAM,WAAW,CAAC;AAGnE,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAuElD,eAAO,MAAM,WAAW,EAAE,aAUzB,CAAC;AAoBF,eAAO,MAAM,eAAe,EAAE,aAkC7B,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,aAgCvC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,aAY9B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,aAc7B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,aAc/B,CAAC;AAEF,eAAO,MAAM,uBAAuB,WAC3B,UAAU,UACV,OAAO,KACb,YAAY,GAAG,SAQjB,CAAC"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Licensed under the MIT License.
|
|
5
5
|
*/
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.generateInsertWithField = exports.annotateWithField = exports.removeWithField = exports.insertAvoidField = exports.obliterateField = exports.insertField = void 0;
|
|
7
|
+
exports.generateInsertWithField = exports.annotateWithField = exports.removeWithField = exports.insertAvoidField = exports.obliterateFieldZeroLength = exports.obliterateField = exports.insertField = void 0;
|
|
8
8
|
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
9
9
|
const node_assert_1 = require("node:assert");
|
|
10
10
|
const sequencePlace_js_1 = require("../sequencePlace.js");
|
|
@@ -55,6 +55,15 @@ const insertField = (client, opStart, opEnd, random) => {
|
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
57
|
exports.insertField = insertField;
|
|
58
|
+
const obliterateHelper = (client, startPos, endPos, random) => {
|
|
59
|
+
const obliterateOp = client.obliterateRangeLocal({ pos: startPos, side: sequencePlace_js_1.Side.After }, { pos: endPos, side: sequencePlace_js_1.Side.Before });
|
|
60
|
+
const insertOp = insertFieldText(client, startPos + 1, random);
|
|
61
|
+
(0, node_assert_1.strict)(insertOp !== undefined, "Insert op should not be undefined");
|
|
62
|
+
// TODO: AB#31001: We should be able to sometimes use group ops here rather than submit two separate ops,
|
|
63
|
+
// but this causes failures which likely indicate there are bugs with the intersection of obliterate and grouped batching.
|
|
64
|
+
// const op = createGroupOp(obliterateOp, insertOp);
|
|
65
|
+
return [obliterateOp, insertOp];
|
|
66
|
+
};
|
|
58
67
|
const obliterateField = (client, opStart, opEnd, random) => {
|
|
59
68
|
const fieldEndpoints = getFieldEndpoints(client, opStart,
|
|
60
69
|
// the operation runner generates endpoints with client length, but this model only supports up to client length - 1.
|
|
@@ -63,18 +72,9 @@ const obliterateField = (client, opStart, opEnd, random) => {
|
|
|
63
72
|
if (fieldEndpoints !== undefined) {
|
|
64
73
|
const { startPos, endPos } = fieldEndpoints;
|
|
65
74
|
// Obliterate text between the separators, but avoid the case where the obliterate range is zero length.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
(0, node_assert_1.strict)(insertOp !== undefined, "Insert op should not be undefined");
|
|
70
|
-
// TODO: AB#31001: We should be able to sometimes use group ops here rather than submit two separate ops,
|
|
71
|
-
// but this causes failures which likely indicate there are bugs with the intersection of obliterate and grouped batching.
|
|
72
|
-
// const op = createGroupOp(obliterateOp, insertOp);
|
|
73
|
-
return [obliterateOp, insertOp];
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
75
|
+
return endPos - startPos > 1
|
|
76
|
+
? obliterateHelper(client, startPos, endPos, random)
|
|
77
|
+
: undefined;
|
|
78
78
|
}
|
|
79
79
|
if (opEnd >= client.getLength()) {
|
|
80
80
|
endISP = { pos: client.getLength() - 1, side: sequencePlace_js_1.Side.After };
|
|
@@ -88,6 +88,28 @@ const obliterateField = (client, opStart, opEnd, random) => {
|
|
|
88
88
|
}
|
|
89
89
|
};
|
|
90
90
|
exports.obliterateField = obliterateField;
|
|
91
|
+
const obliterateFieldZeroLength = (client, opStart, opEnd, random) => {
|
|
92
|
+
const fieldEndpoints = getFieldEndpoints(client, opStart,
|
|
93
|
+
// the operation runner generates endpoints with client length, but this model only supports up to client length - 1.
|
|
94
|
+
Math.min(opEnd, client.getLength() - 1));
|
|
95
|
+
let endISP;
|
|
96
|
+
if (fieldEndpoints !== undefined) {
|
|
97
|
+
const { startPos, endPos } = fieldEndpoints;
|
|
98
|
+
// Obliterate text between the separators, including the case where the obliterate range is zero length.
|
|
99
|
+
return obliterateHelper(client, startPos, endPos, random);
|
|
100
|
+
}
|
|
101
|
+
if (opEnd >= client.getLength()) {
|
|
102
|
+
endISP = { pos: client.getLength() - 1, side: sequencePlace_js_1.Side.After };
|
|
103
|
+
}
|
|
104
|
+
if (!client.getText(opStart, opEnd).includes("{")) {
|
|
105
|
+
// Avoid issuing obliterates that might contain multiple fields.
|
|
106
|
+
// Otherwise we may end up with field characters that look like they're outside of the field,
|
|
107
|
+
// since one of these obliterates can wipe out the field including the `{}` delimiters, but
|
|
108
|
+
// a "field replace" obliterate + insert can win and insert the numerical characters.
|
|
109
|
+
return client.obliterateRangeLocal({ pos: opStart, side: sequencePlace_js_1.Side.Before }, endISP ?? { pos: opEnd, side: sequencePlace_js_1.Side.After });
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
exports.obliterateFieldZeroLength = obliterateFieldZeroLength;
|
|
91
113
|
const insertAvoidField = (client, opStart, opEnd, random) => {
|
|
92
114
|
let start = opStart;
|
|
93
115
|
const endpoints = posInField(client, opStart);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obliterateOperations.js","sourceRoot":"","sources":["../../src/test/obliterateOperations.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { strict as assert } from \"node:assert\";\n\nimport type { IRandom } from \"@fluid-private/stochastic-test-utils\";\n\n// import { createGroupOp } from \"../opBuilder.js\";\nimport type { IMergeTreeInsertMsg, IMergeTreeOp } from \"../ops.js\";\nimport { InteriorSequencePlace, Side } from \"../sequencePlace.js\";\n\nimport { annotateRange, removeRange, type TestOperation } from \"./mergeTreeOperationRunner.js\";\nimport type { TestClient } from \"./testClient.js\";\n\nconst posInField = (\n\tclient: TestClient,\n\tpos: number,\n): { startPos: number; endPos: number } | undefined => {\n\tconst isFieldCharacter = (char: string): boolean =>\n\t\tNumber.isInteger(Number(char)) || char === \"{\" || char === \"}\";\n\tif (pos >= client.getLength() || !isFieldCharacter(client.getText(pos, pos + 1))) {\n\t\t// pos is not within a field.\n\t\treturn undefined;\n\t}\n\n\tlet startPos = pos;\n\tlet endPos = pos;\n\t// To find the start and end separators, walk backwards and forwards until the desired character is found.\n\twhile (startPos > 0 && client.getText(startPos, startPos + 1) !== \"{\") {\n\t\tconst text = client.getText(endPos, endPos + 1);\n\t\tassert(\n\t\t\tNumber.isInteger(Number(text)) || text === \"}\",\n\t\t\t\"Non-integer character found within a field\",\n\t\t);\n\t\tstartPos--;\n\t}\n\n\twhile (endPos < client.getLength() && client.getText(endPos, endPos + 1) !== \"}\") {\n\t\tconst text = client.getText(endPos, endPos + 1);\n\t\tassert(\n\t\t\tNumber.isInteger(Number(text)) || text === \"{\",\n\t\t\t\"Non-integer character found within a field\",\n\t\t);\n\t\tendPos++;\n\t}\n\n\tassert(client.getText(startPos, startPos + 1) === \"{\", \"Start separator not found\");\n\tassert(\n\t\tendPos < client.getLength() && client.getText(endPos, endPos + 1) === \"}\",\n\t\t\"End separator not found\",\n\t);\n\n\treturn { startPos, endPos };\n};\n\nconst getFieldEndpoints = (\n\tclient: TestClient,\n\tstart: number,\n\tend: number,\n): { startPos: number; endPos: number } | undefined => {\n\tconst startField = posInField(client, start);\n\tconst endField = posInField(client, end);\n\n\tif (startField === undefined && endField === undefined) {\n\t\treturn undefined;\n\t}\n\treturn startField ?? endField;\n};\n\nconst generateFieldText = (client: TestClient, random: IRandom): string => {\n\tconst chunkLength = random.integer(1, 10);\n\treturn (client.longClientId!.codePointAt(0)! % 10).toString().repeat(chunkLength);\n};\n\nconst insertFieldText = (\n\tclient: TestClient,\n\topStart: number,\n\trandom: IRandom,\n): IMergeTreeInsertMsg | undefined => {\n\tconst text = generateFieldText(client, random);\n\treturn client.insertTextLocal(opStart, text);\n};\n\nexport const insertField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tconst numberText = generateFieldText(client, random);\n\tif (posInField(client, opStart) === undefined) {\n\t\treturn client.insertTextLocal(opStart, `{${numberText}}`);\n\t}\n};\n\nexport const obliterateField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tconst fieldEndpoints = getFieldEndpoints(\n\t\tclient,\n\t\topStart,\n\t\t// the operation runner generates endpoints with client length, but this model only supports up to client length - 1.\n\t\tMath.min(opEnd, client.getLength() - 1),\n\t);\n\n\tlet endISP: InteriorSequencePlace | undefined;\n\tif (fieldEndpoints !== undefined) {\n\t\tconst { startPos, endPos } = fieldEndpoints;\n\t\t// Obliterate text between the separators, but avoid the case where the obliterate range is zero length.\n\t\tif (endPos - startPos > 1) {\n\t\t\tconst obliterateOp = client.obliterateRangeLocal(\n\t\t\t\t{ pos: startPos, side: Side.After },\n\t\t\t\t{ pos: endPos, side: Side.Before },\n\t\t\t);\n\t\t\tconst insertOp = insertFieldText(client, startPos + 1, random);\n\t\t\tassert(insertOp !== undefined, \"Insert op should not be undefined\");\n\t\t\t// TODO: AB#31001: We should be able to sometimes use group ops here rather than submit two separate ops,\n\t\t\t// but this causes failures which likely indicate there are bugs with the intersection of obliterate and grouped batching.\n\t\t\t// const op = createGroupOp(obliterateOp, insertOp);\n\t\t\treturn [obliterateOp, insertOp];\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\t}\n\tif (opEnd >= client.getLength()) {\n\t\tendISP = { pos: client.getLength() - 1, side: Side.After };\n\t}\n\tif (!client.getText(opStart, opEnd).includes(\"{\")) {\n\t\t// Avoid issuing obliterates that might contain multiple fields.\n\t\t// Otherwise we may end up with field characters that look like they're outside of the field,\n\t\t// since one of these obliterates can wipe out the field including the `{}` delimiters, but\n\t\t// a \"field replace\" obliterate + insert can win and insert the numerical characters.\n\t\treturn client.obliterateRangeLocal(\n\t\t\t{ pos: opStart, side: Side.Before },\n\t\t\tendISP ?? { pos: opEnd, side: Side.After },\n\t\t);\n\t}\n};\n\nexport const insertAvoidField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tconst endpoints = posInField(client, opStart);\n\tif (endpoints !== undefined) {\n\t\tstart = endpoints.startPos;\n\t}\n\treturn client.insertTextLocal(start, client.longClientId!.repeat(random.integer(1, 3)));\n};\n\nexport const removeWithField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tlet end = opEnd;\n\tconst fieldEndpoints = getFieldEndpoints(client, opStart, opEnd);\n\tif (fieldEndpoints !== undefined) {\n\t\tstart = fieldEndpoints.startPos;\n\t\tend = fieldEndpoints.endPos + 1;\n\t}\n\treturn removeRange(client, start, end, random);\n};\n\nexport const annotateWithField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tlet end = opEnd;\n\tconst fieldEndpoints = getFieldEndpoints(client, opStart, opEnd);\n\tif (fieldEndpoints !== undefined) {\n\t\tstart = fieldEndpoints.startPos;\n\t\tend = fieldEndpoints.endPos + 1;\n\t}\n\treturn annotateRange(client, start, end, random);\n};\n\nexport const generateInsertWithField = (\n\tclient: TestClient,\n\trandom: IRandom,\n): IMergeTreeOp | undefined => {\n\tconst text = client.longClientId!.repeat(random.integer(1, 3));\n\tlet pos = random.integer(0, client.getLength());\n\tconst endpoints = posInField(client, pos);\n\tif (endpoints !== undefined) {\n\t\tpos = 0;\n\t}\n\treturn client.insertTextLocal(pos, text);\n};\n"]}
|
|
1
|
+
{"version":3,"file":"obliterateOperations.js","sourceRoot":"","sources":["../../src/test/obliterateOperations.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,6DAA6D;AAE7D,6CAA+C;AAM/C,0DAAkE;AAElE,+EAA+F;AAG/F,MAAM,UAAU,GAAG,CAClB,MAAkB,EAClB,GAAW,EACwC,EAAE;IACrD,MAAM,gBAAgB,GAAG,CAAC,IAAY,EAAW,EAAE,CAClD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,CAAC;IAChE,IAAI,GAAG,IAAI,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;QAClF,6BAA6B;QAC7B,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,IAAI,QAAQ,GAAG,GAAG,CAAC;IACnB,IAAI,MAAM,GAAG,GAAG,CAAC;IACjB,0GAA0G;IAC1G,OAAO,QAAQ,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;QACvE,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;QAChD,IAAA,oBAAM,EACL,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,GAAG,EAC9C,4CAA4C,CAC5C,CAAC;QACF,QAAQ,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;QAClF,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;QAChD,IAAA,oBAAM,EACL,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,GAAG,EAC9C,4CAA4C,CAC5C,CAAC;QACF,MAAM,EAAE,CAAC;IACV,CAAC;IAED,IAAA,oBAAM,EAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,2BAA2B,CAAC,CAAC;IACpF,IAAA,oBAAM,EACL,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,EACzE,yBAAyB,CACzB,CAAC;IAEF,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC7B,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CACzB,MAAkB,EAClB,KAAa,EACb,GAAW,EACwC,EAAE;IACrD,MAAM,UAAU,GAAG,UAAU,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAEzC,IAAI,UAAU,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QACxD,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,UAAU,IAAI,QAAQ,CAAC;AAC/B,CAAC,CAAC;AAEF,MAAM,iBAAiB,GAAG,CAAC,MAAkB,EAAE,MAAe,EAAU,EAAE;IACzE,MAAM,WAAW,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,CAAC,MAAM,CAAC,YAAa,CAAC,WAAW,CAAC,CAAC,CAAE,GAAG,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;AACnF,CAAC,CAAC;AAEF,MAAM,eAAe,GAAG,CACvB,MAAkB,EAClB,OAAe,EACf,MAAe,EACmB,EAAE;IACpC,MAAM,IAAI,GAAG,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;AAC9C,CAAC,CAAC;AAEK,MAAM,WAAW,GAAkB,CACzC,MAAkB,EAClB,OAAe,EACf,KAAa,EACb,MAAe,EACd,EAAE;IACH,MAAM,UAAU,GAAG,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrD,IAAI,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,SAAS,EAAE,CAAC;QAC/C,OAAO,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,IAAI,UAAU,GAAG,CAAC,CAAC;IAC3D,CAAC;AACF,CAAC,CAAC;AAVW,QAAA,WAAW,eAUtB;AAEF,MAAM,gBAAgB,GAAG,CACxB,MAAkB,EAClB,QAAgB,EAChB,MAAc,EACd,MAAe,EACE,EAAE;IACnB,MAAM,YAAY,GAAG,MAAM,CAAC,oBAAoB,CAC/C,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,uBAAI,CAAC,KAAK,EAAE,EACnC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,uBAAI,CAAC,MAAM,EAAE,CAClC,CAAC;IACF,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,EAAE,QAAQ,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/D,IAAA,oBAAM,EAAC,QAAQ,KAAK,SAAS,EAAE,mCAAmC,CAAC,CAAC;IACpE,yGAAyG;IACzG,0HAA0H;IAC1H,oDAAoD;IACpD,OAAO,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;AACjC,CAAC,CAAC;AAEK,MAAM,eAAe,GAAkB,CAC7C,MAAkB,EAClB,OAAe,EACf,KAAa,EACb,MAAe,EACd,EAAE;IACH,MAAM,cAAc,GAAG,iBAAiB,CACvC,MAAM,EACN,OAAO;IACP,qHAAqH;IACrH,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CACvC,CAAC;IAEF,IAAI,MAAyC,CAAC;IAC9C,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC;QAC5C,wGAAwG;QACxG,OAAO,MAAM,GAAG,QAAQ,GAAG,CAAC;YAC3B,CAAC,CAAC,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACpD,CAAC,CAAC,SAAS,CAAC;IACd,CAAC;IACD,IAAI,KAAK,IAAI,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;QACjC,MAAM,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,uBAAI,CAAC,KAAK,EAAE,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,gEAAgE;QAChE,6FAA6F;QAC7F,2FAA2F;QAC3F,qFAAqF;QACrF,OAAO,MAAM,CAAC,oBAAoB,CACjC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,uBAAI,CAAC,MAAM,EAAE,EACnC,MAAM,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,uBAAI,CAAC,KAAK,EAAE,CAC1C,CAAC;IACH,CAAC;AACF,CAAC,CAAC;AAlCW,QAAA,eAAe,mBAkC1B;AAEK,MAAM,yBAAyB,GAAkB,CACvD,MAAkB,EAClB,OAAe,EACf,KAAa,EACb,MAAe,EACd,EAAE;IACH,MAAM,cAAc,GAAG,iBAAiB,CACvC,MAAM,EACN,OAAO;IACP,qHAAqH;IACrH,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,CACvC,CAAC;IAEF,IAAI,MAAyC,CAAC;IAC9C,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,cAAc,CAAC;QAC5C,wGAAwG;QACxG,OAAO,gBAAgB,CAAC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,KAAK,IAAI,MAAM,CAAC,SAAS,EAAE,EAAE,CAAC;QACjC,MAAM,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,uBAAI,CAAC,KAAK,EAAE,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,gEAAgE;QAChE,6FAA6F;QAC7F,2FAA2F;QAC3F,qFAAqF;QACrF,OAAO,MAAM,CAAC,oBAAoB,CACjC,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,uBAAI,CAAC,MAAM,EAAE,EACnC,MAAM,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,uBAAI,CAAC,KAAK,EAAE,CAC1C,CAAC;IACH,CAAC;AACF,CAAC,CAAC;AAhCW,QAAA,yBAAyB,6BAgCpC;AAEK,MAAM,gBAAgB,GAAkB,CAC9C,MAAkB,EAClB,OAAe,EACf,KAAa,EACb,MAAe,EACd,EAAE;IACH,IAAI,KAAK,GAAG,OAAO,CAAC;IACpB,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC7B,KAAK,GAAG,SAAS,CAAC,QAAQ,CAAC;IAC5B,CAAC;IACD,OAAO,MAAM,CAAC,eAAe,CAAC,KAAK,EAAE,MAAM,CAAC,YAAa,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACzF,CAAC,CAAC;AAZW,QAAA,gBAAgB,oBAY3B;AAEK,MAAM,eAAe,GAAkB,CAC7C,MAAkB,EAClB,OAAe,EACf,KAAa,EACb,MAAe,EACd,EAAE;IACH,IAAI,KAAK,GAAG,OAAO,CAAC;IACpB,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,MAAM,cAAc,GAAG,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACjE,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QAClC,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC;QAChC,GAAG,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,IAAA,yCAAW,EAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AAChD,CAAC,CAAC;AAdW,QAAA,eAAe,mBAc1B;AAEK,MAAM,iBAAiB,GAAkB,CAC/C,MAAkB,EAClB,OAAe,EACf,KAAa,EACb,MAAe,EACd,EAAE;IACH,IAAI,KAAK,GAAG,OAAO,CAAC;IACpB,IAAI,GAAG,GAAG,KAAK,CAAC;IAChB,MAAM,cAAc,GAAG,iBAAiB,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACjE,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;QAClC,KAAK,GAAG,cAAc,CAAC,QAAQ,CAAC;QAChC,GAAG,GAAG,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,IAAA,2CAAa,EAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC,CAAC;AAdW,QAAA,iBAAiB,qBAc5B;AAEK,MAAM,uBAAuB,GAAG,CACtC,MAAkB,EAClB,MAAe,EACY,EAAE;IAC7B,MAAM,IAAI,GAAG,MAAM,CAAC,YAAa,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/D,IAAI,GAAG,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC1C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QAC7B,GAAG,GAAG,CAAC,CAAC;IACT,CAAC;IACD,OAAO,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;AAC1C,CAAC,CAAC;AAXW,QAAA,uBAAuB,2BAWlC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { strict as assert } from \"node:assert\";\n\nimport type { IRandom } from \"@fluid-private/stochastic-test-utils\";\n\n// import { createGroupOp } from \"../opBuilder.js\";\nimport type { IMergeTreeInsertMsg, IMergeTreeOp } from \"../ops.js\";\nimport { InteriorSequencePlace, Side } from \"../sequencePlace.js\";\n\nimport { annotateRange, removeRange, type TestOperation } from \"./mergeTreeOperationRunner.js\";\nimport type { TestClient } from \"./testClient.js\";\n\nconst posInField = (\n\tclient: TestClient,\n\tpos: number,\n): { startPos: number; endPos: number } | undefined => {\n\tconst isFieldCharacter = (char: string): boolean =>\n\t\tNumber.isInteger(Number(char)) || char === \"{\" || char === \"}\";\n\tif (pos >= client.getLength() || !isFieldCharacter(client.getText(pos, pos + 1))) {\n\t\t// pos is not within a field.\n\t\treturn undefined;\n\t}\n\n\tlet startPos = pos;\n\tlet endPos = pos;\n\t// To find the start and end separators, walk backwards and forwards until the desired character is found.\n\twhile (startPos > 0 && client.getText(startPos, startPos + 1) !== \"{\") {\n\t\tconst text = client.getText(endPos, endPos + 1);\n\t\tassert(\n\t\t\tNumber.isInteger(Number(text)) || text === \"}\",\n\t\t\t\"Non-integer character found within a field\",\n\t\t);\n\t\tstartPos--;\n\t}\n\n\twhile (endPos < client.getLength() && client.getText(endPos, endPos + 1) !== \"}\") {\n\t\tconst text = client.getText(endPos, endPos + 1);\n\t\tassert(\n\t\t\tNumber.isInteger(Number(text)) || text === \"{\",\n\t\t\t\"Non-integer character found within a field\",\n\t\t);\n\t\tendPos++;\n\t}\n\n\tassert(client.getText(startPos, startPos + 1) === \"{\", \"Start separator not found\");\n\tassert(\n\t\tendPos < client.getLength() && client.getText(endPos, endPos + 1) === \"}\",\n\t\t\"End separator not found\",\n\t);\n\n\treturn { startPos, endPos };\n};\n\nconst getFieldEndpoints = (\n\tclient: TestClient,\n\tstart: number,\n\tend: number,\n): { startPos: number; endPos: number } | undefined => {\n\tconst startField = posInField(client, start);\n\tconst endField = posInField(client, end);\n\n\tif (startField === undefined && endField === undefined) {\n\t\treturn undefined;\n\t}\n\treturn startField ?? endField;\n};\n\nconst generateFieldText = (client: TestClient, random: IRandom): string => {\n\tconst chunkLength = random.integer(1, 10);\n\treturn (client.longClientId!.codePointAt(0)! % 10).toString().repeat(chunkLength);\n};\n\nconst insertFieldText = (\n\tclient: TestClient,\n\topStart: number,\n\trandom: IRandom,\n): IMergeTreeInsertMsg | undefined => {\n\tconst text = generateFieldText(client, random);\n\treturn client.insertTextLocal(opStart, text);\n};\n\nexport const insertField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tconst numberText = generateFieldText(client, random);\n\tif (posInField(client, opStart) === undefined) {\n\t\treturn client.insertTextLocal(opStart, `{${numberText}}`);\n\t}\n};\n\nconst obliterateHelper = (\n\tclient: TestClient,\n\tstartPos: number,\n\tendPos: number,\n\trandom: IRandom,\n): IMergeTreeOp[] => {\n\tconst obliterateOp = client.obliterateRangeLocal(\n\t\t{ pos: startPos, side: Side.After },\n\t\t{ pos: endPos, side: Side.Before },\n\t);\n\tconst insertOp = insertFieldText(client, startPos + 1, random);\n\tassert(insertOp !== undefined, \"Insert op should not be undefined\");\n\t// TODO: AB#31001: We should be able to sometimes use group ops here rather than submit two separate ops,\n\t// but this causes failures which likely indicate there are bugs with the intersection of obliterate and grouped batching.\n\t// const op = createGroupOp(obliterateOp, insertOp);\n\treturn [obliterateOp, insertOp];\n};\n\nexport const obliterateField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tconst fieldEndpoints = getFieldEndpoints(\n\t\tclient,\n\t\topStart,\n\t\t// the operation runner generates endpoints with client length, but this model only supports up to client length - 1.\n\t\tMath.min(opEnd, client.getLength() - 1),\n\t);\n\n\tlet endISP: InteriorSequencePlace | undefined;\n\tif (fieldEndpoints !== undefined) {\n\t\tconst { startPos, endPos } = fieldEndpoints;\n\t\t// Obliterate text between the separators, but avoid the case where the obliterate range is zero length.\n\t\treturn endPos - startPos > 1\n\t\t\t? obliterateHelper(client, startPos, endPos, random)\n\t\t\t: undefined;\n\t}\n\tif (opEnd >= client.getLength()) {\n\t\tendISP = { pos: client.getLength() - 1, side: Side.After };\n\t}\n\tif (!client.getText(opStart, opEnd).includes(\"{\")) {\n\t\t// Avoid issuing obliterates that might contain multiple fields.\n\t\t// Otherwise we may end up with field characters that look like they're outside of the field,\n\t\t// since one of these obliterates can wipe out the field including the `{}` delimiters, but\n\t\t// a \"field replace\" obliterate + insert can win and insert the numerical characters.\n\t\treturn client.obliterateRangeLocal(\n\t\t\t{ pos: opStart, side: Side.Before },\n\t\t\tendISP ?? { pos: opEnd, side: Side.After },\n\t\t);\n\t}\n};\n\nexport const obliterateFieldZeroLength: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tconst fieldEndpoints = getFieldEndpoints(\n\t\tclient,\n\t\topStart,\n\t\t// the operation runner generates endpoints with client length, but this model only supports up to client length - 1.\n\t\tMath.min(opEnd, client.getLength() - 1),\n\t);\n\n\tlet endISP: InteriorSequencePlace | undefined;\n\tif (fieldEndpoints !== undefined) {\n\t\tconst { startPos, endPos } = fieldEndpoints;\n\t\t// Obliterate text between the separators, including the case where the obliterate range is zero length.\n\t\treturn obliterateHelper(client, startPos, endPos, random);\n\t}\n\tif (opEnd >= client.getLength()) {\n\t\tendISP = { pos: client.getLength() - 1, side: Side.After };\n\t}\n\tif (!client.getText(opStart, opEnd).includes(\"{\")) {\n\t\t// Avoid issuing obliterates that might contain multiple fields.\n\t\t// Otherwise we may end up with field characters that look like they're outside of the field,\n\t\t// since one of these obliterates can wipe out the field including the `{}` delimiters, but\n\t\t// a \"field replace\" obliterate + insert can win and insert the numerical characters.\n\t\treturn client.obliterateRangeLocal(\n\t\t\t{ pos: opStart, side: Side.Before },\n\t\t\tendISP ?? { pos: opEnd, side: Side.After },\n\t\t);\n\t}\n};\n\nexport const insertAvoidField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tconst endpoints = posInField(client, opStart);\n\tif (endpoints !== undefined) {\n\t\tstart = endpoints.startPos;\n\t}\n\treturn client.insertTextLocal(start, client.longClientId!.repeat(random.integer(1, 3)));\n};\n\nexport const removeWithField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tlet end = opEnd;\n\tconst fieldEndpoints = getFieldEndpoints(client, opStart, opEnd);\n\tif (fieldEndpoints !== undefined) {\n\t\tstart = fieldEndpoints.startPos;\n\t\tend = fieldEndpoints.endPos + 1;\n\t}\n\treturn removeRange(client, start, end, random);\n};\n\nexport const annotateWithField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tlet end = opEnd;\n\tconst fieldEndpoints = getFieldEndpoints(client, opStart, opEnd);\n\tif (fieldEndpoints !== undefined) {\n\t\tstart = fieldEndpoints.startPos;\n\t\tend = fieldEndpoints.endPos + 1;\n\t}\n\treturn annotateRange(client, start, end, random);\n};\n\nexport const generateInsertWithField = (\n\tclient: TestClient,\n\trandom: IRandom,\n): IMergeTreeOp | undefined => {\n\tconst text = client.longClientId!.repeat(random.integer(1, 3));\n\tlet pos = random.integer(0, client.getLength());\n\tconst endpoints = posInField(client, pos);\n\tif (endpoints !== undefined) {\n\t\tpos = 0;\n\t}\n\treturn client.insertTextLocal(pos, text);\n};\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.obliterateFarm.spec.d.ts","sourceRoot":"","sources":["../../src/test/client.obliterateFarm.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EACN,YAAY,EACZ,+BAA+B,EAK/B,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"client.obliterateFarm.spec.d.ts","sourceRoot":"","sources":["../../src/test/client.obliterateFarm.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,EACN,YAAY,EACZ,+BAA+B,EAK/B,MAAM,+BAA+B,CAAC;AAYvC,UAAU,qBAAsB,SAAQ,+BAA+B;IACtE,SAAS,EAAE,YAAY,CAAC;IACxB,OAAO,EAAE,YAAY,CAAC;CACtB;AAgBD,eAAO,MAAM,cAAc,EAAE,qBAQ5B,CAAC"}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import { createFuzzDescribe, makeRandom } from "@fluid-private/stochastic-test-utils";
|
|
6
6
|
import { doOverRange, generateClientNames, runMergeTreeOperationRunner, } from "./mergeTreeOperationRunner.js";
|
|
7
|
-
import { annotateWithField, generateInsertWithField, insertAvoidField, insertField, obliterateField,
|
|
7
|
+
import { annotateWithField, generateInsertWithField, insertAvoidField, insertField, obliterateField, obliterateFieldZeroLength,
|
|
8
8
|
// removeWithField,
|
|
9
9
|
} from "./obliterateOperations.js";
|
|
10
10
|
import { TestClient } from "./testClient.js";
|
|
@@ -43,6 +43,18 @@ function runObliterateFarmTests(opts, extraSeed) {
|
|
|
43
43
|
// applyOpDuringGeneration: true,
|
|
44
44
|
},
|
|
45
45
|
},
|
|
46
|
+
{
|
|
47
|
+
name: "obliterate exact range allowing zero length",
|
|
48
|
+
config: {
|
|
49
|
+
...opts,
|
|
50
|
+
operations: [
|
|
51
|
+
annotateWithField,
|
|
52
|
+
insertAvoidField,
|
|
53
|
+
insertField,
|
|
54
|
+
obliterateFieldZeroLength,
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
},
|
|
46
58
|
])
|
|
47
59
|
it(`${name}: ObliterateFarm_${minLength}`, async () => {
|
|
48
60
|
const random = makeRandom(0xdeadbeef, 0xfeedbed, minLength, extraSeed ?? 0);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.obliterateFarm.spec.js","sourceRoot":"","sources":["../../src/test/client.obliterateFarm.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,sCAAsC,CAAC;AAEtF,OAAO,EAIN,WAAW,EACX,mBAAmB,EACnB,2BAA2B,GAC3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EACN,iBAAiB,EACjB,uBAAuB,EACvB,gBAAgB,EAChB,WAAW,EACX,eAAe;
|
|
1
|
+
{"version":3,"file":"client.obliterateFarm.spec.js","sourceRoot":"","sources":["../../src/test/client.obliterateFarm.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { createFuzzDescribe, makeRandom } from \"@fluid-private/stochastic-test-utils\";\n\nimport {\n\tIConfigRange,\n\tIMergeTreeOperationRunnerConfig,\n\tTestOperation,\n\tdoOverRange,\n\tgenerateClientNames,\n\trunMergeTreeOperationRunner,\n} from \"./mergeTreeOperationRunner.js\";\nimport {\n\tannotateWithField,\n\tgenerateInsertWithField,\n\tinsertAvoidField,\n\tinsertField,\n\tobliterateField,\n\tobliterateFieldZeroLength,\n\t// removeWithField,\n} from \"./obliterateOperations.js\";\nimport { TestClient } from \"./testClient.js\";\n\ninterface IObliterateFarmConfig extends IMergeTreeOperationRunnerConfig {\n\tminLength: IConfigRange;\n\tclients: IConfigRange;\n}\n\nconst allOperations: TestOperation[] = [\n\t// The test model is not currently stable enough to support removeWithField: logic to look for fields\n\t// relies on text inside fields being numeric and text outside of fields alphabetic, but if a removal\n\t// operation takes away a whole field, a concurrent field replace (obliterate + insert new field content)\n\t// can result in numeric characters outside of fields.\n\t// removeWithField,\n\tannotateWithField,\n\tinsertAvoidField,\n\tinsertField,\n\tobliterateField,\n];\n\n// Note: this test isn't totally stable for all options matrices. E.g. there appear to be some issues with\n// adding clients mid-run, which is likely related to known issues with obliterate and summarization.\nexport const defaultOptions: IObliterateFarmConfig = {\n\tminLength: { min: 1, max: 512 },\n\tclients: { min: 3, max: 3 },\n\topsPerRoundRange: { min: 1, max: 128 },\n\trounds: 8,\n\toperations: allOperations,\n\tgrowthFunc: (input: number) => input * 2,\n\tinsertText: generateInsertWithField,\n};\n\n// Generate a list of single character client names, support up to 69 clients\nconst clientNames = generateClientNames();\n\nfunction runObliterateFarmTests(opts: IObliterateFarmConfig, extraSeed?: number): void {\n\tdoOverRange(opts.minLength, opts.growthFunc, (minLength) => {\n\t\tfor (const { name, config } of [\n\t\t\t{\n\t\t\t\tname: \"obliterate with exact range replacement\",\n\t\t\t\tconfig: {\n\t\t\t\t\t...opts,\n\t\t\t\t\t// TODO: ensure that obliterate and inserts are not separated before enabling this\n\t\t\t\t\t// applyOpDuringGeneration: true,\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tname: \"obliterate exact range allowing zero length\",\n\t\t\t\tconfig: {\n\t\t\t\t\t...opts,\n\t\t\t\t\toperations: [\n\t\t\t\t\t\tannotateWithField,\n\t\t\t\t\t\tinsertAvoidField,\n\t\t\t\t\t\tinsertField,\n\t\t\t\t\t\tobliterateFieldZeroLength,\n\t\t\t\t\t],\n\t\t\t\t},\n\t\t\t},\n\t\t])\n\t\t\tit(`${name}: ObliterateFarm_${minLength}`, async () => {\n\t\t\t\tconst random = makeRandom(0xdeadbeef, 0xfeedbed, minLength, extraSeed ?? 0);\n\n\t\t\t\tconst clients: TestClient[] = [\n\t\t\t\t\tnew TestClient({\n\t\t\t\t\t\tmergeTreeEnableObliterate: true,\n\t\t\t\t\t\tmergeTreeEnableSidedObliterate: true,\n\t\t\t\t\t\tmergeTreeEnableAnnotateAdjust: true,\n\t\t\t\t\t}),\n\t\t\t\t];\n\t\t\t\tfor (const [i, c] of clients.entries()) c.startOrUpdateCollaboration(clientNames[i]);\n\n\t\t\t\tlet seq = 0;\n\t\t\t\twhile (clients.length < config.clients.max) {\n\t\t\t\t\tfor (const c of clients) c.updateMinSeq(seq);\n\n\t\t\t\t\t// Add double the number of clients each iteration\n\t\t\t\t\tconst targetClients = Math.max(\n\t\t\t\t\t\tconfig.clients.min,\n\t\t\t\t\t\tconfig.growthFunc(clients.length),\n\t\t\t\t\t);\n\t\t\t\t\tfor (let cc = clients.length; cc < targetClients; cc++) {\n\t\t\t\t\t\tconst newClient = await TestClient.createFromClientSnapshot(\n\t\t\t\t\t\t\tclients[0],\n\t\t\t\t\t\t\tclientNames[cc],\n\t\t\t\t\t\t);\n\t\t\t\t\t\tclients.push(newClient);\n\t\t\t\t\t}\n\n\t\t\t\t\tseq = runMergeTreeOperationRunner(random, seq, clients, minLength, config);\n\t\t\t\t}\n\t\t\t}).timeout(30 * 10000);\n\t});\n}\n\n// More tests pass, but due to how this farm selects ops, the tests take a while to run, and merge-tree\n// already a test suite on the longer side.\nconst describeFuzz = createFuzzDescribe({ defaultTestCount: 1 });\ndescribeFuzz(\"MergeTree.Client Obliterate\", ({ testCount }) => {\n\tif (testCount > 1) {\n\t\tdoOverRange(\n\t\t\t{ min: 0, max: testCount - 1 },\n\t\t\t(x) => x + 1,\n\t\t\t(seed) => {\n\t\t\t\tdescribe(`with seed ${seed}`, () => {\n\t\t\t\t\trunObliterateFarmTests(defaultOptions, seed);\n\t\t\t\t});\n\t\t\t},\n\t\t);\n\t} else {\n\t\trunObliterateFarmTests(defaultOptions);\n\t}\n});\n"]}
|
|
@@ -8,6 +8,7 @@ import { type TestOperation } from "./mergeTreeOperationRunner.js";
|
|
|
8
8
|
import type { TestClient } from "./testClient.js";
|
|
9
9
|
export declare const insertField: TestOperation;
|
|
10
10
|
export declare const obliterateField: TestOperation;
|
|
11
|
+
export declare const obliterateFieldZeroLength: TestOperation;
|
|
11
12
|
export declare const insertAvoidField: TestOperation;
|
|
12
13
|
export declare const removeWithField: TestOperation;
|
|
13
14
|
export declare const annotateWithField: TestOperation;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obliterateOperations.d.ts","sourceRoot":"","sources":["../../src/test/obliterateOperations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAGpE,OAAO,KAAK,EAAuB,YAAY,EAAE,MAAM,WAAW,CAAC;AAGnE,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAuElD,eAAO,MAAM,WAAW,EAAE,aAUzB,CAAC;
|
|
1
|
+
{"version":3,"file":"obliterateOperations.d.ts","sourceRoot":"","sources":["../../src/test/obliterateOperations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAGpE,OAAO,KAAK,EAAuB,YAAY,EAAE,MAAM,WAAW,CAAC;AAGnE,OAAO,EAA8B,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAC/F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAuElD,eAAO,MAAM,WAAW,EAAE,aAUzB,CAAC;AAoBF,eAAO,MAAM,eAAe,EAAE,aAkC7B,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,aAgCvC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,aAY9B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,aAc7B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,aAc/B,CAAC;AAEF,eAAO,MAAM,uBAAuB,WAC3B,UAAU,UACV,OAAO,KACb,YAAY,GAAG,SAQjB,CAAC"}
|
|
@@ -51,6 +51,15 @@ export const insertField = (client, opStart, opEnd, random) => {
|
|
|
51
51
|
return client.insertTextLocal(opStart, `{${numberText}}`);
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
|
+
const obliterateHelper = (client, startPos, endPos, random) => {
|
|
55
|
+
const obliterateOp = client.obliterateRangeLocal({ pos: startPos, side: Side.After }, { pos: endPos, side: Side.Before });
|
|
56
|
+
const insertOp = insertFieldText(client, startPos + 1, random);
|
|
57
|
+
assert(insertOp !== undefined, "Insert op should not be undefined");
|
|
58
|
+
// TODO: AB#31001: We should be able to sometimes use group ops here rather than submit two separate ops,
|
|
59
|
+
// but this causes failures which likely indicate there are bugs with the intersection of obliterate and grouped batching.
|
|
60
|
+
// const op = createGroupOp(obliterateOp, insertOp);
|
|
61
|
+
return [obliterateOp, insertOp];
|
|
62
|
+
};
|
|
54
63
|
export const obliterateField = (client, opStart, opEnd, random) => {
|
|
55
64
|
const fieldEndpoints = getFieldEndpoints(client, opStart,
|
|
56
65
|
// the operation runner generates endpoints with client length, but this model only supports up to client length - 1.
|
|
@@ -59,18 +68,30 @@ export const obliterateField = (client, opStart, opEnd, random) => {
|
|
|
59
68
|
if (fieldEndpoints !== undefined) {
|
|
60
69
|
const { startPos, endPos } = fieldEndpoints;
|
|
61
70
|
// Obliterate text between the separators, but avoid the case where the obliterate range is zero length.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
return endPos - startPos > 1
|
|
72
|
+
? obliterateHelper(client, startPos, endPos, random)
|
|
73
|
+
: undefined;
|
|
74
|
+
}
|
|
75
|
+
if (opEnd >= client.getLength()) {
|
|
76
|
+
endISP = { pos: client.getLength() - 1, side: Side.After };
|
|
77
|
+
}
|
|
78
|
+
if (!client.getText(opStart, opEnd).includes("{")) {
|
|
79
|
+
// Avoid issuing obliterates that might contain multiple fields.
|
|
80
|
+
// Otherwise we may end up with field characters that look like they're outside of the field,
|
|
81
|
+
// since one of these obliterates can wipe out the field including the `{}` delimiters, but
|
|
82
|
+
// a "field replace" obliterate + insert can win and insert the numerical characters.
|
|
83
|
+
return client.obliterateRangeLocal({ pos: opStart, side: Side.Before }, endISP ?? { pos: opEnd, side: Side.After });
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
export const obliterateFieldZeroLength = (client, opStart, opEnd, random) => {
|
|
87
|
+
const fieldEndpoints = getFieldEndpoints(client, opStart,
|
|
88
|
+
// the operation runner generates endpoints with client length, but this model only supports up to client length - 1.
|
|
89
|
+
Math.min(opEnd, client.getLength() - 1));
|
|
90
|
+
let endISP;
|
|
91
|
+
if (fieldEndpoints !== undefined) {
|
|
92
|
+
const { startPos, endPos } = fieldEndpoints;
|
|
93
|
+
// Obliterate text between the separators, including the case where the obliterate range is zero length.
|
|
94
|
+
return obliterateHelper(client, startPos, endPos, random);
|
|
74
95
|
}
|
|
75
96
|
if (opEnd >= client.getLength()) {
|
|
76
97
|
endISP = { pos: client.getLength() - 1, side: Side.After };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obliterateOperations.js","sourceRoot":"","sources":["../../src/test/obliterateOperations.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { strict as assert } from \"node:assert\";\n\nimport type { IRandom } from \"@fluid-private/stochastic-test-utils\";\n\n// import { createGroupOp } from \"../opBuilder.js\";\nimport type { IMergeTreeInsertMsg, IMergeTreeOp } from \"../ops.js\";\nimport { InteriorSequencePlace, Side } from \"../sequencePlace.js\";\n\nimport { annotateRange, removeRange, type TestOperation } from \"./mergeTreeOperationRunner.js\";\nimport type { TestClient } from \"./testClient.js\";\n\nconst posInField = (\n\tclient: TestClient,\n\tpos: number,\n): { startPos: number; endPos: number } | undefined => {\n\tconst isFieldCharacter = (char: string): boolean =>\n\t\tNumber.isInteger(Number(char)) || char === \"{\" || char === \"}\";\n\tif (pos >= client.getLength() || !isFieldCharacter(client.getText(pos, pos + 1))) {\n\t\t// pos is not within a field.\n\t\treturn undefined;\n\t}\n\n\tlet startPos = pos;\n\tlet endPos = pos;\n\t// To find the start and end separators, walk backwards and forwards until the desired character is found.\n\twhile (startPos > 0 && client.getText(startPos, startPos + 1) !== \"{\") {\n\t\tconst text = client.getText(endPos, endPos + 1);\n\t\tassert(\n\t\t\tNumber.isInteger(Number(text)) || text === \"}\",\n\t\t\t\"Non-integer character found within a field\",\n\t\t);\n\t\tstartPos--;\n\t}\n\n\twhile (endPos < client.getLength() && client.getText(endPos, endPos + 1) !== \"}\") {\n\t\tconst text = client.getText(endPos, endPos + 1);\n\t\tassert(\n\t\t\tNumber.isInteger(Number(text)) || text === \"{\",\n\t\t\t\"Non-integer character found within a field\",\n\t\t);\n\t\tendPos++;\n\t}\n\n\tassert(client.getText(startPos, startPos + 1) === \"{\", \"Start separator not found\");\n\tassert(\n\t\tendPos < client.getLength() && client.getText(endPos, endPos + 1) === \"}\",\n\t\t\"End separator not found\",\n\t);\n\n\treturn { startPos, endPos };\n};\n\nconst getFieldEndpoints = (\n\tclient: TestClient,\n\tstart: number,\n\tend: number,\n): { startPos: number; endPos: number } | undefined => {\n\tconst startField = posInField(client, start);\n\tconst endField = posInField(client, end);\n\n\tif (startField === undefined && endField === undefined) {\n\t\treturn undefined;\n\t}\n\treturn startField ?? endField;\n};\n\nconst generateFieldText = (client: TestClient, random: IRandom): string => {\n\tconst chunkLength = random.integer(1, 10);\n\treturn (client.longClientId!.codePointAt(0)! % 10).toString().repeat(chunkLength);\n};\n\nconst insertFieldText = (\n\tclient: TestClient,\n\topStart: number,\n\trandom: IRandom,\n): IMergeTreeInsertMsg | undefined => {\n\tconst text = generateFieldText(client, random);\n\treturn client.insertTextLocal(opStart, text);\n};\n\nexport const insertField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tconst numberText = generateFieldText(client, random);\n\tif (posInField(client, opStart) === undefined) {\n\t\treturn client.insertTextLocal(opStart, `{${numberText}}`);\n\t}\n};\n\nexport const obliterateField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tconst fieldEndpoints = getFieldEndpoints(\n\t\tclient,\n\t\topStart,\n\t\t// the operation runner generates endpoints with client length, but this model only supports up to client length - 1.\n\t\tMath.min(opEnd, client.getLength() - 1),\n\t);\n\n\tlet endISP: InteriorSequencePlace | undefined;\n\tif (fieldEndpoints !== undefined) {\n\t\tconst { startPos, endPos } = fieldEndpoints;\n\t\t// Obliterate text between the separators, but avoid the case where the obliterate range is zero length.\n\t\tif (endPos - startPos > 1) {\n\t\t\tconst obliterateOp = client.obliterateRangeLocal(\n\t\t\t\t{ pos: startPos, side: Side.After },\n\t\t\t\t{ pos: endPos, side: Side.Before },\n\t\t\t);\n\t\t\tconst insertOp = insertFieldText(client, startPos + 1, random);\n\t\t\tassert(insertOp !== undefined, \"Insert op should not be undefined\");\n\t\t\t// TODO: AB#31001: We should be able to sometimes use group ops here rather than submit two separate ops,\n\t\t\t// but this causes failures which likely indicate there are bugs with the intersection of obliterate and grouped batching.\n\t\t\t// const op = createGroupOp(obliterateOp, insertOp);\n\t\t\treturn [obliterateOp, insertOp];\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\t}\n\tif (opEnd >= client.getLength()) {\n\t\tendISP = { pos: client.getLength() - 1, side: Side.After };\n\t}\n\tif (!client.getText(opStart, opEnd).includes(\"{\")) {\n\t\t// Avoid issuing obliterates that might contain multiple fields.\n\t\t// Otherwise we may end up with field characters that look like they're outside of the field,\n\t\t// since one of these obliterates can wipe out the field including the `{}` delimiters, but\n\t\t// a \"field replace\" obliterate + insert can win and insert the numerical characters.\n\t\treturn client.obliterateRangeLocal(\n\t\t\t{ pos: opStart, side: Side.Before },\n\t\t\tendISP ?? { pos: opEnd, side: Side.After },\n\t\t);\n\t}\n};\n\nexport const insertAvoidField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tconst endpoints = posInField(client, opStart);\n\tif (endpoints !== undefined) {\n\t\tstart = endpoints.startPos;\n\t}\n\treturn client.insertTextLocal(start, client.longClientId!.repeat(random.integer(1, 3)));\n};\n\nexport const removeWithField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tlet end = opEnd;\n\tconst fieldEndpoints = getFieldEndpoints(client, opStart, opEnd);\n\tif (fieldEndpoints !== undefined) {\n\t\tstart = fieldEndpoints.startPos;\n\t\tend = fieldEndpoints.endPos + 1;\n\t}\n\treturn removeRange(client, start, end, random);\n};\n\nexport const annotateWithField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tlet end = opEnd;\n\tconst fieldEndpoints = getFieldEndpoints(client, opStart, opEnd);\n\tif (fieldEndpoints !== undefined) {\n\t\tstart = fieldEndpoints.startPos;\n\t\tend = fieldEndpoints.endPos + 1;\n\t}\n\treturn annotateRange(client, start, end, random);\n};\n\nexport const generateInsertWithField = (\n\tclient: TestClient,\n\trandom: IRandom,\n): IMergeTreeOp | undefined => {\n\tconst text = client.longClientId!.repeat(random.integer(1, 3));\n\tlet pos = random.integer(0, client.getLength());\n\tconst endpoints = posInField(client, pos);\n\tif (endpoints !== undefined) {\n\t\tpos = 0;\n\t}\n\treturn client.insertTextLocal(pos, text);\n};\n"]}
|
|
1
|
+
{"version":3,"file":"obliterateOperations.js","sourceRoot":"","sources":["../../src/test/obliterateOperations.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable @typescript-eslint/no-non-null-assertion */\n\nimport { strict as assert } from \"node:assert\";\n\nimport type { IRandom } from \"@fluid-private/stochastic-test-utils\";\n\n// import { createGroupOp } from \"../opBuilder.js\";\nimport type { IMergeTreeInsertMsg, IMergeTreeOp } from \"../ops.js\";\nimport { InteriorSequencePlace, Side } from \"../sequencePlace.js\";\n\nimport { annotateRange, removeRange, type TestOperation } from \"./mergeTreeOperationRunner.js\";\nimport type { TestClient } from \"./testClient.js\";\n\nconst posInField = (\n\tclient: TestClient,\n\tpos: number,\n): { startPos: number; endPos: number } | undefined => {\n\tconst isFieldCharacter = (char: string): boolean =>\n\t\tNumber.isInteger(Number(char)) || char === \"{\" || char === \"}\";\n\tif (pos >= client.getLength() || !isFieldCharacter(client.getText(pos, pos + 1))) {\n\t\t// pos is not within a field.\n\t\treturn undefined;\n\t}\n\n\tlet startPos = pos;\n\tlet endPos = pos;\n\t// To find the start and end separators, walk backwards and forwards until the desired character is found.\n\twhile (startPos > 0 && client.getText(startPos, startPos + 1) !== \"{\") {\n\t\tconst text = client.getText(endPos, endPos + 1);\n\t\tassert(\n\t\t\tNumber.isInteger(Number(text)) || text === \"}\",\n\t\t\t\"Non-integer character found within a field\",\n\t\t);\n\t\tstartPos--;\n\t}\n\n\twhile (endPos < client.getLength() && client.getText(endPos, endPos + 1) !== \"}\") {\n\t\tconst text = client.getText(endPos, endPos + 1);\n\t\tassert(\n\t\t\tNumber.isInteger(Number(text)) || text === \"{\",\n\t\t\t\"Non-integer character found within a field\",\n\t\t);\n\t\tendPos++;\n\t}\n\n\tassert(client.getText(startPos, startPos + 1) === \"{\", \"Start separator not found\");\n\tassert(\n\t\tendPos < client.getLength() && client.getText(endPos, endPos + 1) === \"}\",\n\t\t\"End separator not found\",\n\t);\n\n\treturn { startPos, endPos };\n};\n\nconst getFieldEndpoints = (\n\tclient: TestClient,\n\tstart: number,\n\tend: number,\n): { startPos: number; endPos: number } | undefined => {\n\tconst startField = posInField(client, start);\n\tconst endField = posInField(client, end);\n\n\tif (startField === undefined && endField === undefined) {\n\t\treturn undefined;\n\t}\n\treturn startField ?? endField;\n};\n\nconst generateFieldText = (client: TestClient, random: IRandom): string => {\n\tconst chunkLength = random.integer(1, 10);\n\treturn (client.longClientId!.codePointAt(0)! % 10).toString().repeat(chunkLength);\n};\n\nconst insertFieldText = (\n\tclient: TestClient,\n\topStart: number,\n\trandom: IRandom,\n): IMergeTreeInsertMsg | undefined => {\n\tconst text = generateFieldText(client, random);\n\treturn client.insertTextLocal(opStart, text);\n};\n\nexport const insertField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tconst numberText = generateFieldText(client, random);\n\tif (posInField(client, opStart) === undefined) {\n\t\treturn client.insertTextLocal(opStart, `{${numberText}}`);\n\t}\n};\n\nconst obliterateHelper = (\n\tclient: TestClient,\n\tstartPos: number,\n\tendPos: number,\n\trandom: IRandom,\n): IMergeTreeOp[] => {\n\tconst obliterateOp = client.obliterateRangeLocal(\n\t\t{ pos: startPos, side: Side.After },\n\t\t{ pos: endPos, side: Side.Before },\n\t);\n\tconst insertOp = insertFieldText(client, startPos + 1, random);\n\tassert(insertOp !== undefined, \"Insert op should not be undefined\");\n\t// TODO: AB#31001: We should be able to sometimes use group ops here rather than submit two separate ops,\n\t// but this causes failures which likely indicate there are bugs with the intersection of obliterate and grouped batching.\n\t// const op = createGroupOp(obliterateOp, insertOp);\n\treturn [obliterateOp, insertOp];\n};\n\nexport const obliterateField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tconst fieldEndpoints = getFieldEndpoints(\n\t\tclient,\n\t\topStart,\n\t\t// the operation runner generates endpoints with client length, but this model only supports up to client length - 1.\n\t\tMath.min(opEnd, client.getLength() - 1),\n\t);\n\n\tlet endISP: InteriorSequencePlace | undefined;\n\tif (fieldEndpoints !== undefined) {\n\t\tconst { startPos, endPos } = fieldEndpoints;\n\t\t// Obliterate text between the separators, but avoid the case where the obliterate range is zero length.\n\t\treturn endPos - startPos > 1\n\t\t\t? obliterateHelper(client, startPos, endPos, random)\n\t\t\t: undefined;\n\t}\n\tif (opEnd >= client.getLength()) {\n\t\tendISP = { pos: client.getLength() - 1, side: Side.After };\n\t}\n\tif (!client.getText(opStart, opEnd).includes(\"{\")) {\n\t\t// Avoid issuing obliterates that might contain multiple fields.\n\t\t// Otherwise we may end up with field characters that look like they're outside of the field,\n\t\t// since one of these obliterates can wipe out the field including the `{}` delimiters, but\n\t\t// a \"field replace\" obliterate + insert can win and insert the numerical characters.\n\t\treturn client.obliterateRangeLocal(\n\t\t\t{ pos: opStart, side: Side.Before },\n\t\t\tendISP ?? { pos: opEnd, side: Side.After },\n\t\t);\n\t}\n};\n\nexport const obliterateFieldZeroLength: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tconst fieldEndpoints = getFieldEndpoints(\n\t\tclient,\n\t\topStart,\n\t\t// the operation runner generates endpoints with client length, but this model only supports up to client length - 1.\n\t\tMath.min(opEnd, client.getLength() - 1),\n\t);\n\n\tlet endISP: InteriorSequencePlace | undefined;\n\tif (fieldEndpoints !== undefined) {\n\t\tconst { startPos, endPos } = fieldEndpoints;\n\t\t// Obliterate text between the separators, including the case where the obliterate range is zero length.\n\t\treturn obliterateHelper(client, startPos, endPos, random);\n\t}\n\tif (opEnd >= client.getLength()) {\n\t\tendISP = { pos: client.getLength() - 1, side: Side.After };\n\t}\n\tif (!client.getText(opStart, opEnd).includes(\"{\")) {\n\t\t// Avoid issuing obliterates that might contain multiple fields.\n\t\t// Otherwise we may end up with field characters that look like they're outside of the field,\n\t\t// since one of these obliterates can wipe out the field including the `{}` delimiters, but\n\t\t// a \"field replace\" obliterate + insert can win and insert the numerical characters.\n\t\treturn client.obliterateRangeLocal(\n\t\t\t{ pos: opStart, side: Side.Before },\n\t\t\tendISP ?? { pos: opEnd, side: Side.After },\n\t\t);\n\t}\n};\n\nexport const insertAvoidField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tconst endpoints = posInField(client, opStart);\n\tif (endpoints !== undefined) {\n\t\tstart = endpoints.startPos;\n\t}\n\treturn client.insertTextLocal(start, client.longClientId!.repeat(random.integer(1, 3)));\n};\n\nexport const removeWithField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tlet end = opEnd;\n\tconst fieldEndpoints = getFieldEndpoints(client, opStart, opEnd);\n\tif (fieldEndpoints !== undefined) {\n\t\tstart = fieldEndpoints.startPos;\n\t\tend = fieldEndpoints.endPos + 1;\n\t}\n\treturn removeRange(client, start, end, random);\n};\n\nexport const annotateWithField: TestOperation = (\n\tclient: TestClient,\n\topStart: number,\n\topEnd: number,\n\trandom: IRandom,\n) => {\n\tlet start = opStart;\n\tlet end = opEnd;\n\tconst fieldEndpoints = getFieldEndpoints(client, opStart, opEnd);\n\tif (fieldEndpoints !== undefined) {\n\t\tstart = fieldEndpoints.startPos;\n\t\tend = fieldEndpoints.endPos + 1;\n\t}\n\treturn annotateRange(client, start, end, random);\n};\n\nexport const generateInsertWithField = (\n\tclient: TestClient,\n\trandom: IRandom,\n): IMergeTreeOp | undefined => {\n\tconst text = client.longClientId!.repeat(random.integer(1, 3));\n\tlet pos = random.integer(0, client.getLength());\n\tconst endpoints = posInField(client, pos);\n\tif (endpoints !== undefined) {\n\t\tpos = 0;\n\t}\n\treturn client.insertTextLocal(pos, text);\n};\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/merge-tree",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.23.0-323641",
|
|
4
4
|
"description": "Merge tree",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -81,30 +81,30 @@
|
|
|
81
81
|
"temp-directory": "nyc/.nyc_output"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@fluid-internal/client-utils": "
|
|
85
|
-
"@fluidframework/container-definitions": "
|
|
86
|
-
"@fluidframework/core-interfaces": "
|
|
87
|
-
"@fluidframework/core-utils": "
|
|
88
|
-
"@fluidframework/datastore-definitions": "
|
|
89
|
-
"@fluidframework/driver-definitions": "
|
|
90
|
-
"@fluidframework/runtime-definitions": "
|
|
91
|
-
"@fluidframework/runtime-utils": "
|
|
92
|
-
"@fluidframework/shared-object-base": "
|
|
93
|
-
"@fluidframework/telemetry-utils": "
|
|
84
|
+
"@fluid-internal/client-utils": "2.23.0-323641",
|
|
85
|
+
"@fluidframework/container-definitions": "2.23.0-323641",
|
|
86
|
+
"@fluidframework/core-interfaces": "2.23.0-323641",
|
|
87
|
+
"@fluidframework/core-utils": "2.23.0-323641",
|
|
88
|
+
"@fluidframework/datastore-definitions": "2.23.0-323641",
|
|
89
|
+
"@fluidframework/driver-definitions": "2.23.0-323641",
|
|
90
|
+
"@fluidframework/runtime-definitions": "2.23.0-323641",
|
|
91
|
+
"@fluidframework/runtime-utils": "2.23.0-323641",
|
|
92
|
+
"@fluidframework/shared-object-base": "2.23.0-323641",
|
|
93
|
+
"@fluidframework/telemetry-utils": "2.23.0-323641"
|
|
94
94
|
},
|
|
95
95
|
"devDependencies": {
|
|
96
96
|
"@arethetypeswrong/cli": "^0.17.1",
|
|
97
97
|
"@biomejs/biome": "~1.9.3",
|
|
98
|
-
"@fluid-internal/mocha-test-setup": "
|
|
99
|
-
"@fluid-private/stochastic-test-utils": "
|
|
100
|
-
"@fluid-private/test-pairwise-generator": "
|
|
98
|
+
"@fluid-internal/mocha-test-setup": "2.23.0-323641",
|
|
99
|
+
"@fluid-private/stochastic-test-utils": "2.23.0-323641",
|
|
100
|
+
"@fluid-private/test-pairwise-generator": "2.23.0-323641",
|
|
101
101
|
"@fluid-tools/benchmark": "^0.50.0",
|
|
102
|
-
"@fluid-tools/build-cli": "^0.
|
|
102
|
+
"@fluid-tools/build-cli": "^0.53.0",
|
|
103
103
|
"@fluidframework/build-common": "^2.0.3",
|
|
104
|
-
"@fluidframework/build-tools": "^0.
|
|
104
|
+
"@fluidframework/build-tools": "^0.53.0",
|
|
105
105
|
"@fluidframework/eslint-config-fluid": "^5.7.3",
|
|
106
|
-
"@fluidframework/merge-tree-previous": "npm:@fluidframework/merge-tree@2.
|
|
107
|
-
"@fluidframework/test-runtime-utils": "
|
|
106
|
+
"@fluidframework/merge-tree-previous": "npm:@fluidframework/merge-tree@2.22.0",
|
|
107
|
+
"@fluidframework/test-runtime-utils": "2.23.0-323641",
|
|
108
108
|
"@microsoft/api-extractor": "7.47.8",
|
|
109
109
|
"@types/diff": "^3.5.1",
|
|
110
110
|
"@types/mocha": "^10.0.10",
|