@fluidframework/sequence 2.0.0-rc.2.0.2 → 2.0.0-rc.3.0.1
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/CHANGELOG.md +23 -0
- package/README.md +1 -1
- package/api-report/sequence.api.md +32 -32
- package/beta.d.ts +11 -0
- package/dist/{localValues.d.ts → IntervalCollectionValues.d.ts} +13 -12
- package/dist/IntervalCollectionValues.d.ts.map +1 -0
- package/dist/{localValues.js → IntervalCollectionValues.js} +6 -6
- package/dist/IntervalCollectionValues.js.map +1 -0
- package/dist/beta.d.ts +12 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -10
- package/dist/index.js.map +1 -1
- package/dist/intervalCollection.d.ts +10 -10
- package/dist/intervalCollection.d.ts.map +1 -1
- package/dist/intervalCollection.js +103 -99
- package/dist/intervalCollection.js.map +1 -1
- package/dist/{defaultMap.d.ts → intervalCollectionMap.d.ts} +11 -44
- package/dist/intervalCollectionMap.d.ts.map +1 -0
- package/dist/{defaultMap.js → intervalCollectionMap.js} +15 -70
- package/dist/intervalCollectionMap.js.map +1 -0
- package/dist/{defaultMapInterfaces.d.ts → intervalCollectionMapInterfaces.d.ts} +17 -16
- package/dist/intervalCollectionMapInterfaces.d.ts.map +1 -0
- package/dist/{defaultMapInterfaces.js → intervalCollectionMapInterfaces.js} +1 -1
- package/dist/intervalCollectionMapInterfaces.js.map +1 -0
- package/dist/intervalIndex/endpointInRangeIndex.d.ts +1 -1
- package/dist/intervalIndex/endpointInRangeIndex.d.ts.map +1 -1
- package/dist/intervalIndex/endpointInRangeIndex.js +3 -3
- package/dist/intervalIndex/endpointInRangeIndex.js.map +1 -1
- package/dist/intervalIndex/endpointIndex.d.ts +1 -1
- package/dist/intervalIndex/endpointIndex.d.ts.map +1 -1
- package/dist/intervalIndex/endpointIndex.js +3 -3
- package/dist/intervalIndex/endpointIndex.js.map +1 -1
- package/dist/intervalIndex/idIntervalIndex.d.ts.map +1 -1
- package/dist/intervalIndex/idIntervalIndex.js +3 -3
- package/dist/intervalIndex/idIntervalIndex.js.map +1 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts +3 -3
- package/dist/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
- package/dist/intervalIndex/overlappingIntervalsIndex.js +2 -3
- package/dist/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.d.ts.map +1 -1
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js +6 -6
- package/dist/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
- package/dist/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
- package/dist/intervalIndex/startpointInRangeIndex.d.ts +1 -1
- package/dist/intervalIndex/startpointInRangeIndex.d.ts.map +1 -1
- package/dist/intervalIndex/startpointInRangeIndex.js +3 -3
- package/dist/intervalIndex/startpointInRangeIndex.js.map +1 -1
- package/dist/intervalTree.d.ts +1 -1
- package/dist/intervalTree.d.ts.map +1 -1
- package/dist/intervalTree.js +2 -2
- package/dist/intervalTree.js.map +1 -1
- package/dist/intervals/interval.d.ts +1 -1
- package/dist/intervals/interval.d.ts.map +1 -1
- package/dist/intervals/interval.js +10 -10
- package/dist/intervals/interval.js.map +1 -1
- package/dist/intervals/intervalUtils.d.ts +1 -1
- package/dist/intervals/intervalUtils.d.ts.map +1 -1
- package/dist/intervals/intervalUtils.js +5 -5
- package/dist/intervals/intervalUtils.js.map +1 -1
- package/dist/intervals/sequenceInterval.d.ts +1 -1
- package/dist/intervals/sequenceInterval.d.ts.map +1 -1
- package/dist/intervals/sequenceInterval.js +34 -34
- package/dist/intervals/sequenceInterval.js.map +1 -1
- package/dist/legacy.d.ts +61 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/public.d.ts +12 -0
- package/dist/revertibles.d.ts +2 -2
- package/dist/revertibles.d.ts.map +1 -1
- package/dist/revertibles.js +34 -34
- package/dist/revertibles.js.map +1 -1
- package/dist/sequence.d.ts +7 -6
- package/dist/sequence.d.ts.map +1 -1
- package/dist/sequence.js +34 -34
- package/dist/sequence.js.map +1 -1
- package/dist/sequenceDeltaEvent.d.ts +1 -1
- package/dist/sequenceDeltaEvent.d.ts.map +1 -1
- package/dist/sequenceDeltaEvent.js +4 -4
- package/dist/sequenceDeltaEvent.js.map +1 -1
- package/dist/sequenceFactory.d.ts +1 -1
- package/dist/sequenceFactory.d.ts.map +1 -1
- package/dist/sequenceFactory.js +3 -3
- package/dist/sequenceFactory.js.map +1 -1
- package/dist/sharedIntervalCollection.d.ts +4 -3
- package/dist/sharedIntervalCollection.d.ts.map +1 -1
- package/dist/sharedIntervalCollection.js +5 -5
- package/dist/sharedIntervalCollection.js.map +1 -1
- package/dist/sharedSequence.d.ts +3 -2
- package/dist/sharedSequence.d.ts.map +1 -1
- package/dist/sharedSequence.js +4 -4
- package/dist/sharedSequence.js.map +1 -1
- package/dist/sharedString.d.ts +2 -2
- package/dist/sharedString.d.ts.map +1 -1
- package/dist/sharedString.js +9 -9
- package/dist/sharedString.js.map +1 -1
- package/internal.d.ts +11 -0
- package/legacy.d.ts +11 -0
- package/lib/{localValues.d.ts → IntervalCollectionValues.d.ts} +13 -12
- package/lib/IntervalCollectionValues.d.ts.map +1 -0
- package/lib/{localValues.js → IntervalCollectionValues.js} +3 -3
- package/lib/IntervalCollectionValues.js.map +1 -0
- package/lib/beta.d.ts +12 -0
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/intervalCollection.d.ts +10 -10
- package/lib/intervalCollection.d.ts.map +1 -1
- package/lib/intervalCollection.js +8 -4
- package/lib/intervalCollection.js.map +1 -1
- package/lib/{defaultMap.d.ts → intervalCollectionMap.d.ts} +11 -44
- package/lib/intervalCollectionMap.d.ts.map +1 -0
- package/lib/{defaultMap.js → intervalCollectionMap.js} +8 -63
- package/lib/intervalCollectionMap.js.map +1 -0
- package/lib/{defaultMapInterfaces.d.ts → intervalCollectionMapInterfaces.d.ts} +17 -16
- package/lib/intervalCollectionMapInterfaces.d.ts.map +1 -0
- package/lib/{defaultMapInterfaces.js → intervalCollectionMapInterfaces.js} +1 -1
- package/lib/intervalCollectionMapInterfaces.js.map +1 -0
- package/lib/intervalIndex/endpointInRangeIndex.d.ts +1 -1
- package/lib/intervalIndex/endpointInRangeIndex.d.ts.map +1 -1
- package/lib/intervalIndex/endpointInRangeIndex.js +1 -1
- package/lib/intervalIndex/endpointInRangeIndex.js.map +1 -1
- package/lib/intervalIndex/endpointIndex.d.ts +1 -1
- package/lib/intervalIndex/endpointIndex.d.ts.map +1 -1
- package/lib/intervalIndex/endpointIndex.js +1 -1
- package/lib/intervalIndex/endpointIndex.js.map +1 -1
- package/lib/intervalIndex/idIntervalIndex.d.ts.map +1 -1
- package/lib/intervalIndex/idIntervalIndex.js +1 -1
- package/lib/intervalIndex/idIntervalIndex.js.map +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts +3 -3
- package/lib/intervalIndex/overlappingIntervalsIndex.d.ts.map +1 -1
- package/lib/intervalIndex/overlappingIntervalsIndex.js +2 -3
- package/lib/intervalIndex/overlappingIntervalsIndex.js.map +1 -1
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.d.ts.map +1 -1
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js +2 -2
- package/lib/intervalIndex/overlappingSequenceIntervalsIndex.js.map +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.d.ts +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.d.ts.map +1 -1
- package/lib/intervalIndex/sequenceIntervalIndexes.js.map +1 -1
- package/lib/intervalIndex/startpointInRangeIndex.d.ts +1 -1
- package/lib/intervalIndex/startpointInRangeIndex.d.ts.map +1 -1
- package/lib/intervalIndex/startpointInRangeIndex.js +1 -1
- package/lib/intervalIndex/startpointInRangeIndex.js.map +1 -1
- package/lib/intervalTree.d.ts +1 -1
- package/lib/intervalTree.d.ts.map +1 -1
- package/lib/intervalTree.js +1 -1
- package/lib/intervalTree.js.map +1 -1
- package/lib/intervals/interval.d.ts +1 -1
- package/lib/intervals/interval.d.ts.map +1 -1
- package/lib/intervals/interval.js +3 -3
- package/lib/intervals/interval.js.map +1 -1
- package/lib/intervals/intervalUtils.d.ts +1 -1
- package/lib/intervals/intervalUtils.d.ts.map +1 -1
- package/lib/intervals/intervalUtils.js +1 -1
- package/lib/intervals/intervalUtils.js.map +1 -1
- package/lib/intervals/sequenceInterval.d.ts +1 -1
- package/lib/intervals/sequenceInterval.d.ts.map +1 -1
- package/lib/intervals/sequenceInterval.js +3 -3
- package/lib/intervals/sequenceInterval.js.map +1 -1
- package/lib/legacy.d.ts +61 -0
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/public.d.ts +12 -0
- package/lib/revertibles.d.ts +2 -2
- package/lib/revertibles.d.ts.map +1 -1
- package/lib/revertibles.js +3 -4
- package/lib/revertibles.js.map +1 -1
- package/lib/sequence.d.ts +7 -6
- package/lib/sequence.d.ts.map +1 -1
- package/lib/sequence.js +11 -12
- package/lib/sequence.js.map +1 -1
- package/lib/sequenceDeltaEvent.d.ts +1 -1
- package/lib/sequenceDeltaEvent.d.ts.map +1 -1
- package/lib/sequenceDeltaEvent.js +3 -4
- package/lib/sequenceDeltaEvent.js.map +1 -1
- package/lib/sequenceFactory.d.ts +1 -1
- package/lib/sequenceFactory.d.ts.map +1 -1
- package/lib/sequenceFactory.js +1 -1
- package/lib/sequenceFactory.js.map +1 -1
- package/lib/sharedIntervalCollection.d.ts +4 -3
- package/lib/sharedIntervalCollection.d.ts.map +1 -1
- package/lib/sharedIntervalCollection.js +4 -4
- package/lib/sharedIntervalCollection.js.map +1 -1
- package/lib/sharedSequence.d.ts +3 -2
- package/lib/sharedSequence.d.ts.map +1 -1
- package/lib/sharedSequence.js +2 -2
- package/lib/sharedSequence.js.map +1 -1
- package/lib/sharedString.d.ts +2 -2
- package/lib/sharedString.d.ts.map +1 -1
- package/lib/sharedString.js +1 -1
- package/lib/sharedString.js.map +1 -1
- package/package.json +41 -58
- package/src/{localValues.ts → IntervalCollectionValues.ts} +26 -18
- package/src/index.ts +2 -2
- package/src/intervalCollection.ts +46 -47
- package/src/{defaultMap.ts → intervalCollectionMap.ts} +42 -105
- package/src/{defaultMapInterfaces.ts → intervalCollectionMapInterfaces.ts} +26 -16
- package/src/intervalIndex/endpointInRangeIndex.ts +4 -1
- package/src/intervalIndex/endpointIndex.ts +4 -1
- package/src/intervalIndex/idIntervalIndex.ts +4 -2
- package/src/intervalIndex/overlappingIntervalsIndex.ts +8 -5
- package/src/intervalIndex/overlappingSequenceIntervalsIndex.ts +6 -3
- package/src/intervalIndex/sequenceIntervalIndexes.ts +3 -1
- package/src/intervalIndex/startpointInRangeIndex.ts +4 -1
- package/src/intervalTree.ts +4 -3
- package/src/intervals/interval.ts +6 -3
- package/src/intervals/intervalUtils.ts +4 -2
- package/src/intervals/sequenceInterval.ts +5 -3
- package/src/packageVersion.ts +1 -1
- package/src/revertibles.ts +10 -10
- package/src/sequence.ts +24 -31
- package/src/sequenceDeltaEvent.ts +3 -4
- package/src/sequenceFactory.ts +4 -3
- package/src/sharedIntervalCollection.ts +12 -18
- package/src/sharedSequence.ts +9 -6
- package/src/sharedString.ts +4 -3
- package/api-extractor-cjs.json +0 -8
- package/dist/defaultMap.d.ts.map +0 -1
- package/dist/defaultMap.js.map +0 -1
- package/dist/defaultMapInterfaces.d.ts.map +0 -1
- package/dist/defaultMapInterfaces.js.map +0 -1
- package/dist/localValues.d.ts.map +0 -1
- package/dist/localValues.js.map +0 -1
- package/dist/sequence-alpha.d.ts +0 -1432
- package/dist/sequence-beta.d.ts +0 -246
- package/dist/sequence-public.d.ts +0 -246
- package/dist/sequence-untrimmed.d.ts +0 -1820
- package/lib/defaultMap.d.ts.map +0 -1
- package/lib/defaultMap.js.map +0 -1
- package/lib/defaultMapInterfaces.d.ts.map +0 -1
- package/lib/defaultMapInterfaces.js.map +0 -1
- package/lib/localValues.d.ts.map +0 -1
- package/lib/localValues.js.map +0 -1
- package/lib/sequence-alpha.d.ts +0 -1432
- package/lib/sequence-beta.d.ts +0 -246
- package/lib/sequence-public.d.ts +0 -246
- package/lib/sequence-untrimmed.d.ts +0 -1820
- package/lib/test/collections.intervalTree.js +0 -73
- package/lib/test/collections.intervalTree.js.map +0 -1
- package/lib/test/createSnapshotFiles.js +0 -15
- package/lib/test/createSnapshotFiles.js.map +0 -1
- package/lib/test/dirname.cjs +0 -16
- package/lib/test/dirname.cjs.map +0 -1
- package/lib/test/endpointInRangeIndex.spec.js +0 -182
- package/lib/test/endpointInRangeIndex.spec.js.map +0 -1
- package/lib/test/fuzz/fuzzUtils.js +0 -250
- package/lib/test/fuzz/fuzzUtils.js.map +0 -1
- package/lib/test/fuzz/intervalCollection.fuzz.spec.js +0 -200
- package/lib/test/fuzz/intervalCollection.fuzz.spec.js.map +0 -1
- package/lib/test/fuzz/intervalRevertibles.fuzz.spec.js +0 -129
- package/lib/test/fuzz/intervalRevertibles.fuzz.spec.js.map +0 -1
- package/lib/test/fuzz/sharedString.fuzz.spec.js +0 -91
- package/lib/test/fuzz/sharedString.fuzz.spec.js.map +0 -1
- package/lib/test/generateSharedStrings.js +0 -138
- package/lib/test/generateSharedStrings.js.map +0 -1
- package/lib/test/intervalCollection.detached.spec.js +0 -126
- package/lib/test/intervalCollection.detached.spec.js.map +0 -1
- package/lib/test/intervalCollection.events.spec.js +0 -491
- package/lib/test/intervalCollection.events.spec.js.map +0 -1
- package/lib/test/intervalCollection.perf.spec.js +0 -88
- package/lib/test/intervalCollection.perf.spec.js.map +0 -1
- package/lib/test/intervalCollection.snapshot.spec.js +0 -171
- package/lib/test/intervalCollection.snapshot.spec.js.map +0 -1
- package/lib/test/intervalCollection.spec.js +0 -1660
- package/lib/test/intervalCollection.spec.js.map +0 -1
- package/lib/test/intervalIndexTestUtils.js +0 -49
- package/lib/test/intervalIndexTestUtils.js.map +0 -1
- package/lib/test/intervalRebasing.spec.js +0 -589
- package/lib/test/intervalRebasing.spec.js.map +0 -1
- package/lib/test/intervalStashedOps.spec.js +0 -142
- package/lib/test/intervalStashedOps.spec.js.map +0 -1
- package/lib/test/intervalTestUtils.js +0 -81
- package/lib/test/intervalTestUtils.js.map +0 -1
- package/lib/test/marshalling.spec.js +0 -55
- package/lib/test/marshalling.spec.js.map +0 -1
- package/lib/test/memory/sharedSequence.spec.js +0 -82
- package/lib/test/memory/sharedSequence.spec.js.map +0 -1
- package/lib/test/memory/sharedString.spec.js +0 -134
- package/lib/test/memory/sharedString.spec.js.map +0 -1
- package/lib/test/overlappingSequenceIntervalsIndex.spec.js +0 -348
- package/lib/test/overlappingSequenceIntervalsIndex.spec.js.map +0 -1
- package/lib/test/partialLoad.spec.js +0 -211
- package/lib/test/partialLoad.spec.js.map +0 -1
- package/lib/test/rebasing.spec.js +0 -81
- package/lib/test/rebasing.spec.js.map +0 -1
- package/lib/test/reentrancy.spec.js +0 -174
- package/lib/test/reentrancy.spec.js.map +0 -1
- package/lib/test/revertibles.spec.js +0 -971
- package/lib/test/revertibles.spec.js.map +0 -1
- package/lib/test/sequenceDeltaEvent.spec.js +0 -2144
- package/lib/test/sequenceDeltaEvent.spec.js.map +0 -1
- package/lib/test/sharedIntervalCollection.spec.js +0 -159
- package/lib/test/sharedIntervalCollection.spec.js.map +0 -1
- package/lib/test/sharedString.spec.js +0 -532
- package/lib/test/sharedString.spec.js.map +0 -1
- package/lib/test/snapshotEmptyProps.spec.js +0 -45
- package/lib/test/snapshotEmptyProps.spec.js.map +0 -1
- package/lib/test/snapshotVersion.spec.js +0 -149
- package/lib/test/snapshotVersion.spec.js.map +0 -1
- package/lib/test/startpointInRangeIndex.spec.js +0 -182
- package/lib/test/startpointInRangeIndex.spec.js.map +0 -1
- package/lib/test/subSequence.spec.js +0 -92
- package/lib/test/subSequence.spec.js.map +0 -1
- package/lib/test/types/validateSequencePrevious.generated.js +0 -162
- package/lib/test/types/validateSequencePrevious.generated.js.map +0 -1
- package/lib/test/v1IntervalCollectionHelpers.js +0 -93
- package/lib/test/v1IntervalCollectionHelpers.js.map +0 -1
- /package/{dist → lib}/tsdoc-metadata.json +0 -0
|
@@ -1,2144 +0,0 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
-
* Licensed under the MIT License.
|
|
4
|
-
*/
|
|
5
|
-
import { strict as assert } from "assert";
|
|
6
|
-
import { isNullOrUndefined } from "util";
|
|
7
|
-
import { createAnnotateRangeOp, createInsertSegmentOp, createRemoveRangeOp, TextSegment, } from "@fluidframework/merge-tree";
|
|
8
|
-
// eslint-disable-next-line import/no-internal-modules
|
|
9
|
-
import { TestClient } from "@fluidframework/merge-tree/test";
|
|
10
|
-
import { SequenceDeltaEvent } from "../sequenceDeltaEvent.js";
|
|
11
|
-
describe("non-collab", () => {
|
|
12
|
-
const userId = "localUser";
|
|
13
|
-
let client;
|
|
14
|
-
describe("insert", () => {
|
|
15
|
-
before(() => {
|
|
16
|
-
client = new TestClient();
|
|
17
|
-
client.startOrUpdateCollaboration(userId);
|
|
18
|
-
});
|
|
19
|
-
const initialText = "done";
|
|
20
|
-
const beginningText = "What's ";
|
|
21
|
-
const middleText = " is";
|
|
22
|
-
const endText = " done";
|
|
23
|
-
it("initially", () => {
|
|
24
|
-
insertText(0, initialText);
|
|
25
|
-
});
|
|
26
|
-
it("in the beginning", () => {
|
|
27
|
-
insertText(0, beginningText);
|
|
28
|
-
});
|
|
29
|
-
it("in the end", () => {
|
|
30
|
-
insertText(client.getLength(), endText);
|
|
31
|
-
});
|
|
32
|
-
it("in the middle", () => {
|
|
33
|
-
insertText(initialText.length + beginningText.length, middleText);
|
|
34
|
-
});
|
|
35
|
-
function insertText(offset, text) {
|
|
36
|
-
let deltaArgs;
|
|
37
|
-
client.on("delta", (opArgs, delta) => {
|
|
38
|
-
deltaArgs = delta;
|
|
39
|
-
});
|
|
40
|
-
const op = client.insertTextLocal(offset, text);
|
|
41
|
-
assert(deltaArgs);
|
|
42
|
-
assert.equal(deltaArgs.deltaSegments.length, 1);
|
|
43
|
-
assert(op);
|
|
44
|
-
const event = new SequenceDeltaEvent({ op }, deltaArgs, client);
|
|
45
|
-
assert(event.isLocal);
|
|
46
|
-
assert.equal(event.ranges.length, 1);
|
|
47
|
-
assert.equal(event.first.position, offset);
|
|
48
|
-
assert.equal(event.first.segment.cachedLength, text.length);
|
|
49
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, offset + text.length);
|
|
50
|
-
const segment = event.first.segment;
|
|
51
|
-
assert.equal(segment.text, text);
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
describe("remove", () => {
|
|
55
|
-
before(() => {
|
|
56
|
-
client = new TestClient();
|
|
57
|
-
client.insertTextLocal(0, "All is well!");
|
|
58
|
-
client.startOrUpdateCollaboration(userId);
|
|
59
|
-
});
|
|
60
|
-
it("from the middle", () => {
|
|
61
|
-
removeText(3, 7);
|
|
62
|
-
});
|
|
63
|
-
it("from the beginning", () => {
|
|
64
|
-
removeText(0, 3);
|
|
65
|
-
});
|
|
66
|
-
it("from the end", () => {
|
|
67
|
-
removeText(4, 5);
|
|
68
|
-
});
|
|
69
|
-
it("all", () => {
|
|
70
|
-
removeText(0, client.getLength());
|
|
71
|
-
});
|
|
72
|
-
function removeText(start, end) {
|
|
73
|
-
let deltaArgs;
|
|
74
|
-
client.on("delta", (opArgs, delta) => {
|
|
75
|
-
deltaArgs = delta;
|
|
76
|
-
});
|
|
77
|
-
const op = client.removeRangeLocal(start, end);
|
|
78
|
-
assert(deltaArgs);
|
|
79
|
-
assert.equal(deltaArgs.deltaSegments.length, 1);
|
|
80
|
-
assert(op);
|
|
81
|
-
const event = new SequenceDeltaEvent({ op }, deltaArgs, client);
|
|
82
|
-
assert(event.isLocal);
|
|
83
|
-
assert.equal(event.ranges.length, 1);
|
|
84
|
-
assert.equal(event.first.position, start);
|
|
85
|
-
assert.equal(event.first.segment.cachedLength, end - start);
|
|
86
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, end);
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
describe("annotate", () => {
|
|
90
|
-
before(() => {
|
|
91
|
-
client = new TestClient();
|
|
92
|
-
client.insertTextLocal(0, "All is well!");
|
|
93
|
-
client.startOrUpdateCollaboration(userId);
|
|
94
|
-
});
|
|
95
|
-
it("add property over separate range", () => {
|
|
96
|
-
annotateText(0, 3, { foo1: "bar1" }, [
|
|
97
|
-
{ offset: 0, numChar: 3, props: { foo1: "bar1" }, propDeltas: { foo1: null } },
|
|
98
|
-
]);
|
|
99
|
-
annotateText(3, 7, { foo2: "bar2" }, [
|
|
100
|
-
{ offset: 3, numChar: 4, props: { foo2: "bar2" }, propDeltas: { foo2: null } },
|
|
101
|
-
]);
|
|
102
|
-
annotateText(7, client.getLength(), { foo3: "bar3" }, [
|
|
103
|
-
{ offset: 7, numChar: 5, props: { foo3: "bar3" }, propDeltas: { foo3: null } },
|
|
104
|
-
]);
|
|
105
|
-
});
|
|
106
|
-
it("add property over overlapping runs", () => {
|
|
107
|
-
annotateText(2, 10, { foo: "bar" }, [
|
|
108
|
-
{
|
|
109
|
-
offset: 2,
|
|
110
|
-
numChar: 1,
|
|
111
|
-
props: { foo: "bar", foo1: "bar1" },
|
|
112
|
-
propDeltas: { foo: null },
|
|
113
|
-
},
|
|
114
|
-
{
|
|
115
|
-
offset: 3,
|
|
116
|
-
numChar: 4,
|
|
117
|
-
props: { foo: "bar", foo2: "bar2" },
|
|
118
|
-
propDeltas: { foo: null },
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
offset: 7,
|
|
122
|
-
numChar: 3,
|
|
123
|
-
props: { foo: "bar", foo3: "bar3" },
|
|
124
|
-
propDeltas: { foo: null },
|
|
125
|
-
},
|
|
126
|
-
]);
|
|
127
|
-
});
|
|
128
|
-
it("nullify all properties", () => {
|
|
129
|
-
annotateText(2, 10, { foo: undefined }, [
|
|
130
|
-
{
|
|
131
|
-
offset: 2,
|
|
132
|
-
numChar: 1,
|
|
133
|
-
props: { foo: undefined, foo1: "bar1" },
|
|
134
|
-
propDeltas: { foo: "bar" },
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
offset: 3,
|
|
138
|
-
numChar: 4,
|
|
139
|
-
props: { foo: undefined, foo2: "bar2" },
|
|
140
|
-
propDeltas: { foo: "bar" },
|
|
141
|
-
},
|
|
142
|
-
{
|
|
143
|
-
offset: 7,
|
|
144
|
-
numChar: 3,
|
|
145
|
-
props: { foo: undefined, foo3: "bar3" },
|
|
146
|
-
propDeltas: { foo: "bar" },
|
|
147
|
-
},
|
|
148
|
-
]);
|
|
149
|
-
annotateText(2, 3, { foo1: undefined }, [
|
|
150
|
-
{
|
|
151
|
-
offset: 2,
|
|
152
|
-
numChar: 1,
|
|
153
|
-
props: { foo: undefined, foo1: undefined },
|
|
154
|
-
propDeltas: { foo1: "bar1" },
|
|
155
|
-
},
|
|
156
|
-
]);
|
|
157
|
-
annotateText(3, 7, { foo2: undefined }, [
|
|
158
|
-
{
|
|
159
|
-
offset: 3,
|
|
160
|
-
numChar: 4,
|
|
161
|
-
props: { foo: undefined, foo2: undefined },
|
|
162
|
-
propDeltas: { foo2: "bar2" },
|
|
163
|
-
},
|
|
164
|
-
]);
|
|
165
|
-
annotateText(7, 10, { foo3: undefined }, [
|
|
166
|
-
{
|
|
167
|
-
offset: 7,
|
|
168
|
-
numChar: 3,
|
|
169
|
-
props: { foo: undefined, foo3: undefined },
|
|
170
|
-
propDeltas: { foo3: "bar3" },
|
|
171
|
-
},
|
|
172
|
-
]);
|
|
173
|
-
});
|
|
174
|
-
function annotateText(start, end, newProps, expected) {
|
|
175
|
-
let deltaArgs;
|
|
176
|
-
client.on("delta", (opArgs, delta) => {
|
|
177
|
-
deltaArgs = delta;
|
|
178
|
-
});
|
|
179
|
-
const op = client.annotateRangeLocal(start, end, newProps);
|
|
180
|
-
assert(deltaArgs);
|
|
181
|
-
assert.equal(deltaArgs.deltaSegments.length, expected.length);
|
|
182
|
-
assert(op);
|
|
183
|
-
const event = new SequenceDeltaEvent({ op }, deltaArgs, client);
|
|
184
|
-
assert(event.isLocal);
|
|
185
|
-
assert.equal(event.first.position, start);
|
|
186
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, end);
|
|
187
|
-
assert.equal(event.ranges.length, expected.length);
|
|
188
|
-
for (let i = 0; i < expected.length; i = i + 1) {
|
|
189
|
-
assert.equal(event.ranges[i].position, expected[i].offset);
|
|
190
|
-
assert.equal(event.ranges[i].segment.cachedLength, expected[i].numChar);
|
|
191
|
-
assert.equal(Object.keys(event.ranges[i].segment.properties ?? {}).length, Object.keys(expected[i].props).length);
|
|
192
|
-
for (const key of Object.keys(event.ranges[i].segment.properties ?? {})) {
|
|
193
|
-
assert.equal(event.ranges[i].segment.properties?.[key], expected[i].props[key]);
|
|
194
|
-
}
|
|
195
|
-
if (expected[i].propDeltas !== undefined) {
|
|
196
|
-
assert.equal(Object.keys(event.ranges[i].propertyDeltas).length, Object.keys(expected[i].propDeltas ?? {}).length);
|
|
197
|
-
for (const key of Object.keys(event.ranges[i].propertyDeltas)) {
|
|
198
|
-
assert.equal(event.ranges[i].propertyDeltas[key], expected[i].propDeltas?.[key]);
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
assert(event.ranges[i].propertyDeltas === undefined);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
describe("collab", () => {
|
|
209
|
-
const localUserId = "localUser";
|
|
210
|
-
const remoteUserId = "remoteUser";
|
|
211
|
-
let client;
|
|
212
|
-
describe("insert", () => {
|
|
213
|
-
beforeEach(() => {
|
|
214
|
-
client = new TestClient();
|
|
215
|
-
client.insertTextLocal(0, "The fox jumps over the dog");
|
|
216
|
-
client.startOrUpdateCollaboration(localUserId);
|
|
217
|
-
});
|
|
218
|
-
it("separate regions, local before remote", () => {
|
|
219
|
-
const localInsertPos = 4; // before "brown"
|
|
220
|
-
const localInsertText = "quick brown ";
|
|
221
|
-
const remoteInsertPos = client.getLength() - 3; // before "dog"
|
|
222
|
-
const remoteInsertText = "lazy ";
|
|
223
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
224
|
-
let event;
|
|
225
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
226
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
227
|
-
});
|
|
228
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 1, currentSeqNumber);
|
|
229
|
-
client.applyMsg(localInsertMessage);
|
|
230
|
-
assert(event);
|
|
231
|
-
assert(event.isLocal);
|
|
232
|
-
assert.equal(event.first.position, localInsertPos);
|
|
233
|
-
assert.equal(event.last.position, localInsertPos);
|
|
234
|
-
assert.equal(event.first.segment.cachedLength, localInsertText.length);
|
|
235
|
-
assert.equal(event.last.segment.cachedLength, localInsertText.length);
|
|
236
|
-
assert.equal(event.ranges.length, 1);
|
|
237
|
-
const segment1 = event.first.segment;
|
|
238
|
-
assert.equal(segment1.text, localInsertText);
|
|
239
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
|
|
240
|
-
remoteUserId);
|
|
241
|
-
client.applyMsg(remoteInsertMessage);
|
|
242
|
-
assert(!event.isLocal);
|
|
243
|
-
assert.equal(event.first.position, remoteInsertPos + localInsertText.length);
|
|
244
|
-
assert.equal(event.last.position, remoteInsertPos + localInsertText.length);
|
|
245
|
-
assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
|
|
246
|
-
assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
|
|
247
|
-
assert.equal(event.ranges.length, 1);
|
|
248
|
-
const segment2 = event.first.segment;
|
|
249
|
-
assert.equal(segment2.text, remoteInsertText);
|
|
250
|
-
});
|
|
251
|
-
it("separate regions, remote before local", () => {
|
|
252
|
-
const localInsertPos = client.getLength() - 3; // before "dog"
|
|
253
|
-
const localInsertText = "lazy ";
|
|
254
|
-
const remoteInsertPos = 4; // before "fox"
|
|
255
|
-
const remoteInsertText = "quick brown ";
|
|
256
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
257
|
-
let event;
|
|
258
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
259
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
260
|
-
});
|
|
261
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 2, currentSeqNumber);
|
|
262
|
-
assert(event);
|
|
263
|
-
assert(event.isLocal);
|
|
264
|
-
assert.equal(event.first.position, localInsertPos);
|
|
265
|
-
assert.equal(event.last.position, localInsertPos);
|
|
266
|
-
assert.equal(event.first.segment.cachedLength, localInsertText.length);
|
|
267
|
-
assert.equal(event.last.segment.cachedLength, localInsertText.length);
|
|
268
|
-
assert.equal(event.ranges.length, 1);
|
|
269
|
-
const segment1 = event.first.segment;
|
|
270
|
-
assert.equal(segment1.text, localInsertText);
|
|
271
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
|
|
272
|
-
remoteUserId);
|
|
273
|
-
client.applyMsg(remoteInsertMessage);
|
|
274
|
-
client.applyMsg(localInsertMessage);
|
|
275
|
-
assert(!event.isLocal);
|
|
276
|
-
assert.equal(event.first.position, remoteInsertPos);
|
|
277
|
-
assert.equal(event.last.position, remoteInsertPos);
|
|
278
|
-
assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
|
|
279
|
-
assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
|
|
280
|
-
assert.equal(event.ranges.length, 1);
|
|
281
|
-
const segment2 = event.first.segment;
|
|
282
|
-
assert.equal(segment2.text, remoteInsertText);
|
|
283
|
-
});
|
|
284
|
-
it("at same position, local before remote", () => {
|
|
285
|
-
const localInsertPos = 4; // before "fox"
|
|
286
|
-
const localInsertText = "brown ";
|
|
287
|
-
const remoteInsertPos = 4; // before "fox"
|
|
288
|
-
const remoteInsertText = "quick ";
|
|
289
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
290
|
-
let event;
|
|
291
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
292
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
293
|
-
});
|
|
294
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 1, currentSeqNumber);
|
|
295
|
-
client.applyMsg(localInsertMessage);
|
|
296
|
-
assert(event);
|
|
297
|
-
assert(event.isLocal);
|
|
298
|
-
assert.equal(event.first.position, localInsertPos);
|
|
299
|
-
assert.equal(event.last.position, localInsertPos);
|
|
300
|
-
assert.equal(event.first.segment.cachedLength, localInsertText.length);
|
|
301
|
-
assert.equal(event.last.segment.cachedLength, localInsertText.length);
|
|
302
|
-
assert.equal(event.ranges.length, 1);
|
|
303
|
-
const segment1 = event.first.segment;
|
|
304
|
-
assert.equal(segment1.text, localInsertText);
|
|
305
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
306
|
-
remoteUserId);
|
|
307
|
-
client.applyMsg(remoteInsertMessage);
|
|
308
|
-
assert(!event.isLocal);
|
|
309
|
-
assert.equal(event.first.position, remoteInsertPos);
|
|
310
|
-
assert.equal(event.last.position, remoteInsertPos);
|
|
311
|
-
assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
|
|
312
|
-
assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
|
|
313
|
-
assert.equal(event.ranges.length, 1);
|
|
314
|
-
assert.equal(event.first.position, remoteInsertPos);
|
|
315
|
-
const segment2 = event.first.segment;
|
|
316
|
-
assert.equal(segment2.text, remoteInsertText);
|
|
317
|
-
});
|
|
318
|
-
it("at same position, remote before local", () => {
|
|
319
|
-
const localInsertPos = 4; // before "fox"
|
|
320
|
-
const localInsertText = "quick ";
|
|
321
|
-
const remoteInsertPos = 4; // before "fox"
|
|
322
|
-
const remoteInsertText = "brown ";
|
|
323
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
324
|
-
let event;
|
|
325
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
326
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
327
|
-
});
|
|
328
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 2, currentSeqNumber);
|
|
329
|
-
assert(event);
|
|
330
|
-
assert(event.isLocal);
|
|
331
|
-
assert.equal(event.ranges.length, 1);
|
|
332
|
-
assert.equal(event.first.position, localInsertPos);
|
|
333
|
-
assert.equal(event.last.position, localInsertPos);
|
|
334
|
-
assert.equal(event.first.segment.cachedLength, localInsertText.length);
|
|
335
|
-
assert.equal(event.last.segment.cachedLength, localInsertText.length);
|
|
336
|
-
const segment1 = event.first.segment;
|
|
337
|
-
assert.equal(segment1.text, localInsertText);
|
|
338
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
339
|
-
remoteUserId);
|
|
340
|
-
client.applyMsg(remoteInsertMessage);
|
|
341
|
-
client.applyMsg(localInsertMessage);
|
|
342
|
-
assert(!event.isLocal);
|
|
343
|
-
assert.equal(event.ranges.length, 1);
|
|
344
|
-
assert.equal(event.first.position, remoteInsertPos + localInsertText.length);
|
|
345
|
-
assert.equal(event.last.position, remoteInsertPos + localInsertText.length);
|
|
346
|
-
assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
|
|
347
|
-
assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
|
|
348
|
-
const segment2 = event.first.segment;
|
|
349
|
-
assert.equal(segment2.text, remoteInsertText);
|
|
350
|
-
});
|
|
351
|
-
it("overlapping regions, local before remote", () => {
|
|
352
|
-
const localInsertPos = 4; // before "fox"
|
|
353
|
-
const localInsertText = "quick brown ";
|
|
354
|
-
const remoteInsertPos = 3; // before "fox"
|
|
355
|
-
const remoteInsertText = " legendary";
|
|
356
|
-
// output: The legendary quick brown fox jumps over the dog
|
|
357
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
358
|
-
let event;
|
|
359
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
360
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
361
|
-
});
|
|
362
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 1, currentSeqNumber);
|
|
363
|
-
client.applyMsg(localInsertMessage);
|
|
364
|
-
assert(event);
|
|
365
|
-
assert(event.isLocal);
|
|
366
|
-
assert.equal(event.first.position, localInsertPos);
|
|
367
|
-
assert.equal(event.last.position, localInsertPos);
|
|
368
|
-
assert.equal(event.first.segment.cachedLength, localInsertText.length);
|
|
369
|
-
assert.equal(event.last.segment.cachedLength, localInsertText.length);
|
|
370
|
-
assert.equal(event.ranges.length, 1);
|
|
371
|
-
const segment1 = event.first.segment;
|
|
372
|
-
assert.equal(segment1.text, localInsertText);
|
|
373
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
374
|
-
remoteUserId);
|
|
375
|
-
client.applyMsg(remoteInsertMessage);
|
|
376
|
-
assert(!event.isLocal);
|
|
377
|
-
assert.equal(event.first.position, remoteInsertPos);
|
|
378
|
-
assert.equal(event.last.position, remoteInsertPos);
|
|
379
|
-
assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
|
|
380
|
-
assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
|
|
381
|
-
assert.equal(event.ranges.length, 1);
|
|
382
|
-
const segment2 = event.first.segment;
|
|
383
|
-
assert.equal(segment2.text, remoteInsertText);
|
|
384
|
-
});
|
|
385
|
-
it("overlapping regions, remote before local", () => {
|
|
386
|
-
const localInsertPos = 3; // before "fox"
|
|
387
|
-
const localInsertText = " legendary";
|
|
388
|
-
const remoteInsertPos = 4; // before "fox"
|
|
389
|
-
const remoteInsertText = "quick brown ";
|
|
390
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
391
|
-
let event;
|
|
392
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
393
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
394
|
-
});
|
|
395
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 2, currentSeqNumber);
|
|
396
|
-
assert(event);
|
|
397
|
-
assert(event.isLocal);
|
|
398
|
-
assert.equal(event.first.position, localInsertPos);
|
|
399
|
-
assert.equal(event.last.position, localInsertPos);
|
|
400
|
-
assert.equal(event.first.segment.cachedLength, localInsertText.length);
|
|
401
|
-
assert.equal(event.last.segment.cachedLength, localInsertText.length);
|
|
402
|
-
assert.equal(event.ranges.length, 1);
|
|
403
|
-
const segment1 = event.first.segment;
|
|
404
|
-
assert.equal(segment1.text, localInsertText);
|
|
405
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
406
|
-
remoteUserId);
|
|
407
|
-
client.applyMsg(remoteInsertMessage);
|
|
408
|
-
client.applyMsg(localInsertMessage);
|
|
409
|
-
assert(!event.isLocal);
|
|
410
|
-
assert.equal(event.first.position, remoteInsertPos + localInsertText.length);
|
|
411
|
-
assert.equal(event.last.position, remoteInsertPos + localInsertText.length);
|
|
412
|
-
assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
|
|
413
|
-
assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
|
|
414
|
-
assert.equal(event.ranges.length, 1);
|
|
415
|
-
const segment2 = event.first.segment;
|
|
416
|
-
assert.equal(segment2.text, remoteInsertText);
|
|
417
|
-
});
|
|
418
|
-
it("overlapping regions, multiple inserts: local, remote, remoteAfterLocal", () => {
|
|
419
|
-
const localInsertPos = 4; // before "fox"
|
|
420
|
-
const localInsertText = "brown ";
|
|
421
|
-
const remoteInsertPos1 = 4; // before "fox", and before local update
|
|
422
|
-
const remoteInsertText1 = "quick ";
|
|
423
|
-
// before "fox", but after local update
|
|
424
|
-
const remoteInsertPos2 = client.getLength() - 3 + localInsertText.length + remoteInsertText1.length;
|
|
425
|
-
const remoteInsertText2 = "lazy ";
|
|
426
|
-
// output: The quick brown fox jumps over the lazy dog
|
|
427
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
428
|
-
let event;
|
|
429
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
430
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
431
|
-
});
|
|
432
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(localInsertPos, localInsertText), currentSeqNumber + 1, currentSeqNumber);
|
|
433
|
-
client.applyMsg(localInsertMessage);
|
|
434
|
-
assert(event);
|
|
435
|
-
assert(event.isLocal);
|
|
436
|
-
assert.equal(event.first.position, localInsertPos);
|
|
437
|
-
assert.equal(event.last.position, localInsertPos);
|
|
438
|
-
assert.equal(event.first.segment.cachedLength, localInsertText.length);
|
|
439
|
-
assert.equal(event.last.segment.cachedLength, localInsertText.length);
|
|
440
|
-
assert.equal(event.ranges.length, 1);
|
|
441
|
-
const segment1 = event.first.segment;
|
|
442
|
-
assert.equal(segment1.text, localInsertText);
|
|
443
|
-
const remoteInsertMessage1 = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos1, new TextSegment(remoteInsertText1)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
|
|
444
|
-
remoteUserId);
|
|
445
|
-
client.applyMsg(remoteInsertMessage1);
|
|
446
|
-
assert(!event.isLocal);
|
|
447
|
-
assert.equal(event.first.position, remoteInsertPos1);
|
|
448
|
-
assert.equal(event.last.position, remoteInsertPos1);
|
|
449
|
-
assert.equal(event.first.segment.cachedLength, remoteInsertText1.length);
|
|
450
|
-
assert.equal(event.last.segment.cachedLength, remoteInsertText1.length);
|
|
451
|
-
assert.equal(event.ranges.length, 1);
|
|
452
|
-
const segment2 = event.first.segment;
|
|
453
|
-
assert.equal(segment2.text, remoteInsertText1);
|
|
454
|
-
const remoteInsertMessage2 = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos2, new TextSegment(remoteInsertText2)), currentSeqNumber + 3, currentSeqNumber + 1, // refseqnum
|
|
455
|
-
remoteUserId);
|
|
456
|
-
client.applyMsg(remoteInsertMessage2);
|
|
457
|
-
assert(!event.isLocal);
|
|
458
|
-
assert.equal(event.first.position, remoteInsertPos2);
|
|
459
|
-
assert.equal(event.last.position, remoteInsertPos2);
|
|
460
|
-
assert.equal(event.first.segment.cachedLength, remoteInsertText2.length);
|
|
461
|
-
assert.equal(event.last.segment.cachedLength, remoteInsertText2.length);
|
|
462
|
-
assert.equal(event.ranges.length, 1);
|
|
463
|
-
const segment3 = event.first.segment;
|
|
464
|
-
assert.equal(segment3.text, remoteInsertText2);
|
|
465
|
-
});
|
|
466
|
-
it("overlapping regions, multiple inserts: remote, local, localAfterRemote", () => {
|
|
467
|
-
const localInsertPos1 = 4; // before "fox"
|
|
468
|
-
const localInsertText1 = "quick ";
|
|
469
|
-
const remoteInsertPos = 4; // before "fox", and before local update
|
|
470
|
-
const remoteInsertText = "brown ";
|
|
471
|
-
// before "dog", after local update
|
|
472
|
-
const localInsertPos2 = client.getLength() - 3 + remoteInsertText.length + localInsertText1.length;
|
|
473
|
-
const localInsertText2 = "lazy ";
|
|
474
|
-
// output: The quick brown fox jumps over the lazy dog
|
|
475
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
476
|
-
let event;
|
|
477
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
478
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
479
|
-
});
|
|
480
|
-
const localInsertMessage1 = client.makeOpMessage(client.insertTextLocal(localInsertPos1, localInsertText1), currentSeqNumber + 2, currentSeqNumber);
|
|
481
|
-
assert(event);
|
|
482
|
-
assert(event.isLocal);
|
|
483
|
-
assert.equal(event.first.position, localInsertPos1);
|
|
484
|
-
assert.equal(event.last.position, localInsertPos1);
|
|
485
|
-
assert.equal(event.first.segment.cachedLength, localInsertText1.length);
|
|
486
|
-
assert.equal(event.last.segment.cachedLength, localInsertText1.length);
|
|
487
|
-
assert.equal(event.ranges.length, 1);
|
|
488
|
-
const segment1 = event.first.segment;
|
|
489
|
-
assert.equal(segment1.text, localInsertText1);
|
|
490
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(remoteInsertPos, new TextSegment(remoteInsertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
|
|
491
|
-
remoteUserId);
|
|
492
|
-
client.applyMsg(remoteInsertMessage);
|
|
493
|
-
client.applyMsg(localInsertMessage1);
|
|
494
|
-
assert(!event.isLocal);
|
|
495
|
-
assert.equal(event.first.position, remoteInsertPos + localInsertText1.length);
|
|
496
|
-
assert.equal(event.last.position, remoteInsertPos + localInsertText1.length);
|
|
497
|
-
assert.equal(event.first.segment.cachedLength, remoteInsertText.length);
|
|
498
|
-
assert.equal(event.last.segment.cachedLength, remoteInsertText.length);
|
|
499
|
-
assert.equal(event.ranges.length, 1);
|
|
500
|
-
const segment2 = event.first.segment;
|
|
501
|
-
assert.equal(segment2.text, remoteInsertText);
|
|
502
|
-
const localInsertMessage2 = client.makeOpMessage(client.insertTextLocal(localInsertPos2, localInsertText2), currentSeqNumber + 3, currentSeqNumber + 1);
|
|
503
|
-
client.applyMsg(localInsertMessage2);
|
|
504
|
-
assert(event.isLocal);
|
|
505
|
-
assert.equal(event.first.position, localInsertPos2);
|
|
506
|
-
assert.equal(event.last.position, localInsertPos2);
|
|
507
|
-
assert.equal(event.first.segment.cachedLength, localInsertText2.length);
|
|
508
|
-
assert.equal(event.last.segment.cachedLength, localInsertText2.length);
|
|
509
|
-
assert.equal(event.ranges.length, 1);
|
|
510
|
-
const segment3 = event.first.segment;
|
|
511
|
-
assert.equal(segment3.text, localInsertText2);
|
|
512
|
-
});
|
|
513
|
-
});
|
|
514
|
-
describe("delete", () => {
|
|
515
|
-
beforeEach(() => {
|
|
516
|
-
client = new TestClient();
|
|
517
|
-
client.insertTextLocal(0, "The quick brown fox jumps over the lazy dog");
|
|
518
|
-
client.startOrUpdateCollaboration(localUserId);
|
|
519
|
-
});
|
|
520
|
-
it("separate regions, local before remote", () => {
|
|
521
|
-
const localRemovePosStart = 4; // "quick "
|
|
522
|
-
const localRemovePosEnd = localRemovePosStart + 6;
|
|
523
|
-
const remoteRemovePosStart = client.getLength() - 8; // "lazy "
|
|
524
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 5;
|
|
525
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
526
|
-
let event;
|
|
527
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
528
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
529
|
-
});
|
|
530
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
531
|
-
client.applyMsg(localRemoveMessage);
|
|
532
|
-
assert(event);
|
|
533
|
-
assert(event.isLocal);
|
|
534
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
535
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
536
|
-
assert.equal(event.ranges.length, 1);
|
|
537
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
538
|
-
const segment1 = event.first.segment;
|
|
539
|
-
assert.equal(segment1.text, "quick ");
|
|
540
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
541
|
-
remoteUserId);
|
|
542
|
-
client.applyMsg(remoteRemoveMessage);
|
|
543
|
-
assert(!event.isLocal);
|
|
544
|
-
assert.equal(event.first.position, remoteRemovePosStart - localRemovePosEnd + localRemovePosStart);
|
|
545
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, remoteRemovePosEnd - localRemovePosEnd + localRemovePosStart);
|
|
546
|
-
assert.equal(event.ranges.length, 1);
|
|
547
|
-
assert.equal(event.first.segment.cachedLength, remoteRemovePosEnd - remoteRemovePosStart);
|
|
548
|
-
const segment2 = event.first.segment;
|
|
549
|
-
assert.equal(segment2.text, "lazy ");
|
|
550
|
-
});
|
|
551
|
-
it("separate regions, remote before local", () => {
|
|
552
|
-
const localRemovePosStart = 4; // "quick "
|
|
553
|
-
const localRemovePosEnd = localRemovePosStart + 6;
|
|
554
|
-
const remoteRemovePosStart = client.getLength() - 8; // "lazy "
|
|
555
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 5;
|
|
556
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
557
|
-
let event;
|
|
558
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
559
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
560
|
-
});
|
|
561
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
562
|
-
assert(event);
|
|
563
|
-
assert(event.isLocal);
|
|
564
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
565
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
566
|
-
assert.equal(event.ranges.length, 1);
|
|
567
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
568
|
-
const segment1 = event.first.segment;
|
|
569
|
-
assert.equal(segment1.text, "quick ");
|
|
570
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
571
|
-
remoteUserId);
|
|
572
|
-
client.applyMsg(remoteRemoveMessage);
|
|
573
|
-
client.applyMsg(localRemoveMessage);
|
|
574
|
-
assert(!event.isLocal);
|
|
575
|
-
assert.equal(event.first.position, remoteRemovePosStart - localRemovePosEnd + localRemovePosStart);
|
|
576
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, remoteRemovePosEnd - localRemovePosEnd + localRemovePosStart);
|
|
577
|
-
assert.equal(event.ranges.length, 1);
|
|
578
|
-
assert.equal(event.first.segment.cachedLength, remoteRemovePosEnd - remoteRemovePosStart);
|
|
579
|
-
const segment2 = event.first.segment;
|
|
580
|
-
assert.equal(segment2.text, "lazy ");
|
|
581
|
-
});
|
|
582
|
-
it("overlapping regions, same range, local before remote", () => {
|
|
583
|
-
const localRemovePosStart = 4; // "quick brown "
|
|
584
|
-
const localRemovePosEnd = localRemovePosStart + 12;
|
|
585
|
-
const remoteRemovePosStart = 4; // "quick brown "
|
|
586
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 12;
|
|
587
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
588
|
-
const events = [];
|
|
589
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
590
|
-
events.push(new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client));
|
|
591
|
-
});
|
|
592
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
593
|
-
client.applyMsg(localRemoveMessage);
|
|
594
|
-
assert.equal(events.length, 1);
|
|
595
|
-
const [event] = events;
|
|
596
|
-
assert(event.isLocal);
|
|
597
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
598
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
599
|
-
assert.equal(event.ranges.length, 1);
|
|
600
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
601
|
-
const segment = event.first.segment;
|
|
602
|
-
assert.equal(segment.text, "quick brown ");
|
|
603
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
604
|
-
remoteUserId);
|
|
605
|
-
client.applyMsg(remoteRemoveMessage);
|
|
606
|
-
// No new event should be emitted since the delta is empty.
|
|
607
|
-
assert.equal(events.length, 1);
|
|
608
|
-
});
|
|
609
|
-
it("overlapping regions, same range, remote before local", () => {
|
|
610
|
-
const localRemovePosStart = 4; // "quick brown "
|
|
611
|
-
const localRemovePosEnd = localRemovePosStart + 12;
|
|
612
|
-
const remoteRemovePosStart = 4; // "quick brown "
|
|
613
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 12;
|
|
614
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
615
|
-
const events = [];
|
|
616
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
617
|
-
events.push(new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client));
|
|
618
|
-
});
|
|
619
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
620
|
-
assert.equal(events.length, 1);
|
|
621
|
-
const [event] = events;
|
|
622
|
-
assert(event.isLocal);
|
|
623
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
624
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
625
|
-
assert.equal(event.ranges.length, 1);
|
|
626
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
627
|
-
const segment = event.first.segment;
|
|
628
|
-
assert.equal(segment.text, "quick brown ");
|
|
629
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
630
|
-
remoteUserId);
|
|
631
|
-
client.applyMsg(remoteRemoveMessage);
|
|
632
|
-
client.applyMsg(localRemoveMessage);
|
|
633
|
-
// No new event should be emitted since the delta is empty.
|
|
634
|
-
assert.equal(events.length, 1);
|
|
635
|
-
});
|
|
636
|
-
it("overlapping regions, local shadows remote, local before remote", () => {
|
|
637
|
-
const localRemovePosStart = 4; // "quick brown "
|
|
638
|
-
const localRemovePosEnd = localRemovePosStart + 12;
|
|
639
|
-
const remoteRemovePosStart = 10; // "brown"
|
|
640
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 5;
|
|
641
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
642
|
-
const events = [];
|
|
643
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
644
|
-
events.push(new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client));
|
|
645
|
-
});
|
|
646
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
647
|
-
client.applyMsg(localRemoveMessage);
|
|
648
|
-
assert.equal(events.length, 1);
|
|
649
|
-
const [event] = events;
|
|
650
|
-
assert(event.isLocal);
|
|
651
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
652
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
653
|
-
assert.equal(event.ranges.length, 1);
|
|
654
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
655
|
-
const segment = event.first.segment;
|
|
656
|
-
assert.equal(segment.text, "quick brown ");
|
|
657
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
658
|
-
remoteUserId);
|
|
659
|
-
client.applyMsg(remoteRemoveMessage);
|
|
660
|
-
// No new event should be emitted since the delta is empty.
|
|
661
|
-
assert.equal(events.length, 1);
|
|
662
|
-
});
|
|
663
|
-
it("overlapping regions, local shadows remote, remote before local", () => {
|
|
664
|
-
const localRemovePosStart = 4; // "quick brown "
|
|
665
|
-
const localRemovePosEnd = localRemovePosStart + 12;
|
|
666
|
-
const remoteRemovePosStart = 10; // "brown"
|
|
667
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 5;
|
|
668
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
669
|
-
const events = [];
|
|
670
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
671
|
-
events.push(new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client));
|
|
672
|
-
});
|
|
673
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
674
|
-
assert.equal(events.length, 1);
|
|
675
|
-
const [event] = events;
|
|
676
|
-
assert(event.isLocal);
|
|
677
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
678
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
679
|
-
assert.equal(event.ranges.length, 1);
|
|
680
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
681
|
-
const segment = event.first.segment;
|
|
682
|
-
assert.equal(segment.text, "quick brown ");
|
|
683
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
684
|
-
remoteUserId);
|
|
685
|
-
client.applyMsg(remoteRemoveMessage);
|
|
686
|
-
client.applyMsg(localRemoveMessage);
|
|
687
|
-
// No new event should be emitted since the delta is empty.
|
|
688
|
-
assert.equal(events.length, 1);
|
|
689
|
-
});
|
|
690
|
-
it("overlapping regions, local range precedes remote range, local before remote", () => {
|
|
691
|
-
// space after "quick" is the overlap
|
|
692
|
-
const localRemovePosStart = 4; // "quick "
|
|
693
|
-
const localRemovePosEnd = localRemovePosStart + 6;
|
|
694
|
-
const remoteRemovePosStart = 9; // " brown "
|
|
695
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 7;
|
|
696
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
697
|
-
let event;
|
|
698
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
699
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
700
|
-
});
|
|
701
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
702
|
-
client.applyMsg(localRemoveMessage);
|
|
703
|
-
assert(event);
|
|
704
|
-
assert(event.isLocal);
|
|
705
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
706
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
707
|
-
assert.equal(event.ranges.length, 1);
|
|
708
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
709
|
-
const segment1 = event.first.segment;
|
|
710
|
-
assert.equal(segment1.text, "quick ");
|
|
711
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
712
|
-
remoteUserId);
|
|
713
|
-
client.applyMsg(remoteRemoveMessage);
|
|
714
|
-
// start = remoteRemovePosStart - localRemovePosEnd + localRemovePosStart + 1
|
|
715
|
-
// 1 is for overlapping character
|
|
716
|
-
const start = 4;
|
|
717
|
-
// end = 4 + 7 - 1
|
|
718
|
-
const end = 10;
|
|
719
|
-
assert(!event.isLocal);
|
|
720
|
-
assert.equal(event.first.position, start);
|
|
721
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, end);
|
|
722
|
-
assert.equal(event.ranges.length, 1);
|
|
723
|
-
assert.equal(event.first.segment.cachedLength, end - start);
|
|
724
|
-
const segment2 = event.first.segment;
|
|
725
|
-
assert.equal(segment2.text, "brown ");
|
|
726
|
-
});
|
|
727
|
-
it("overlapping regions, local range precedes remote range, remote before local", () => {
|
|
728
|
-
// space after "quick" is the overlap
|
|
729
|
-
const localRemovePosStart = 4; // "quick "
|
|
730
|
-
const localRemovePosEnd = localRemovePosStart + 6;
|
|
731
|
-
const remoteRemovePosStart = 9; // " brown "
|
|
732
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 7;
|
|
733
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
734
|
-
let event;
|
|
735
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
736
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
737
|
-
});
|
|
738
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
739
|
-
assert(event);
|
|
740
|
-
assert(event.isLocal);
|
|
741
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
742
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
743
|
-
assert.equal(event.ranges.length, 1);
|
|
744
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
745
|
-
const segment1 = event.first.segment;
|
|
746
|
-
assert.equal(segment1.text, "quick ");
|
|
747
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
748
|
-
remoteUserId);
|
|
749
|
-
client.applyMsg(remoteRemoveMessage);
|
|
750
|
-
client.applyMsg(localRemoveMessage);
|
|
751
|
-
// start = remoteRemovePosStart - localRemovePosEnd + localRemovePosStart + 1
|
|
752
|
-
// 1 is for overlapping character
|
|
753
|
-
const start = 4;
|
|
754
|
-
// end = 4 + 7 - 1
|
|
755
|
-
const end = 10;
|
|
756
|
-
assert(!event.isLocal);
|
|
757
|
-
assert.equal(event.first.position, start);
|
|
758
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, end);
|
|
759
|
-
assert.equal(event.ranges.length, 1);
|
|
760
|
-
assert.equal(event.first.segment.cachedLength, end - start);
|
|
761
|
-
const segment2 = event.first.segment;
|
|
762
|
-
assert.equal(segment2.text, "brown ");
|
|
763
|
-
});
|
|
764
|
-
it("overlapping regions, remote range precedes local range, local before remote", () => {
|
|
765
|
-
// space after "quick" is the overlap
|
|
766
|
-
const localRemovePosStart = 9; // " brown "
|
|
767
|
-
const localRemovePosEnd = localRemovePosStart + 7;
|
|
768
|
-
const remoteRemovePosStart = 4; // "quick "
|
|
769
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 6;
|
|
770
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
771
|
-
let event;
|
|
772
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
773
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
774
|
-
});
|
|
775
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
776
|
-
client.applyMsg(localRemoveMessage);
|
|
777
|
-
assert(event);
|
|
778
|
-
assert(event.isLocal);
|
|
779
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
780
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
781
|
-
assert.equal(event.ranges.length, 1);
|
|
782
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
783
|
-
const segment1 = event.first.segment;
|
|
784
|
-
assert.equal(segment1.text, " brown ");
|
|
785
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
786
|
-
remoteUserId);
|
|
787
|
-
client.applyMsg(remoteRemoveMessage);
|
|
788
|
-
// start = remoteRemovePosStart - localRemovePosEnd + localRemovePosStart + 1
|
|
789
|
-
// 1 is for overlapping character
|
|
790
|
-
const start = 4;
|
|
791
|
-
// end = 4 + 6 - 1
|
|
792
|
-
const end = 9;
|
|
793
|
-
assert(!event.isLocal);
|
|
794
|
-
assert.equal(event.first.position, start);
|
|
795
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, end);
|
|
796
|
-
assert.equal(event.ranges.length, 1);
|
|
797
|
-
assert.equal(event.first.segment.cachedLength, end - start);
|
|
798
|
-
const segment2 = event.first.segment;
|
|
799
|
-
assert.equal(segment2.text, "quick");
|
|
800
|
-
});
|
|
801
|
-
it("overlapping regions, remote range precedes local range, remote before local", () => {
|
|
802
|
-
// space after "quick" is the overlap
|
|
803
|
-
const localRemovePosStart = 9; // " brown "
|
|
804
|
-
const localRemovePosEnd = localRemovePosStart + 7;
|
|
805
|
-
const remoteRemovePosStart = 4; // "quick "
|
|
806
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 6;
|
|
807
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
808
|
-
let event;
|
|
809
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
810
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
811
|
-
});
|
|
812
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
813
|
-
assert(event);
|
|
814
|
-
assert(event.isLocal);
|
|
815
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
816
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
817
|
-
assert.equal(event.ranges.length, 1);
|
|
818
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
819
|
-
const segment1 = event.first.segment;
|
|
820
|
-
assert.equal(segment1.text, " brown ");
|
|
821
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
822
|
-
remoteUserId);
|
|
823
|
-
client.applyMsg(remoteRemoveMessage);
|
|
824
|
-
client.applyMsg(localRemoveMessage);
|
|
825
|
-
// start = remoteRemovePosStart - localRemovePosEnd + localRemovePosStart + 1
|
|
826
|
-
// 1 is for overlapping character
|
|
827
|
-
const start = 4;
|
|
828
|
-
// end = 4 + 6 - 1
|
|
829
|
-
const end = 9;
|
|
830
|
-
assert(!event.isLocal);
|
|
831
|
-
assert.equal(event.first.position, start);
|
|
832
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, end);
|
|
833
|
-
assert.equal(event.ranges.length, 1);
|
|
834
|
-
assert.equal(event.first.segment.cachedLength, end - start);
|
|
835
|
-
const segment2 = event.first.segment;
|
|
836
|
-
assert.equal(segment2.text, "quick");
|
|
837
|
-
});
|
|
838
|
-
it("overlapping regions, remote shadows local, local before remote", () => {
|
|
839
|
-
const localRemovePosStart = 10; // "brown"
|
|
840
|
-
const localRemovePosEnd = localRemovePosStart + 5;
|
|
841
|
-
const remoteRemovePosStart = 4; // "quick brown "
|
|
842
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 12;
|
|
843
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
844
|
-
let event;
|
|
845
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
846
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
847
|
-
});
|
|
848
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
849
|
-
client.applyMsg(localRemoveMessage);
|
|
850
|
-
assert(event);
|
|
851
|
-
assert(event.isLocal);
|
|
852
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
853
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
854
|
-
assert.equal(event.ranges.length, 1);
|
|
855
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
856
|
-
const segment1 = event.first.segment;
|
|
857
|
-
assert.equal(segment1.text, "brown");
|
|
858
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
859
|
-
remoteUserId);
|
|
860
|
-
client.applyMsg(remoteRemoveMessage);
|
|
861
|
-
assert(!event.isLocal);
|
|
862
|
-
assert.equal(event.ranges.length, 2);
|
|
863
|
-
assert.equal(event.first.position, remoteRemovePosStart);
|
|
864
|
-
// -1 is for split
|
|
865
|
-
assert.equal(event.first.segment.cachedLength, "quick ".length);
|
|
866
|
-
const segment2 = event.first.segment;
|
|
867
|
-
assert.equal(segment2.text, "quick ");
|
|
868
|
-
assert.equal(event.ranges[1].position, remoteRemovePosStart);
|
|
869
|
-
// -1 is for split
|
|
870
|
-
assert.equal(event.ranges[1].segment.cachedLength, " ".length);
|
|
871
|
-
const segment3 = event.ranges[1].segment;
|
|
872
|
-
assert.equal(segment3.text, " ");
|
|
873
|
-
});
|
|
874
|
-
it("overlapping regions, remote shadows local, remote before local", () => {
|
|
875
|
-
const localRemovePosStart = 10; // "brown"
|
|
876
|
-
const localRemovePosEnd = localRemovePosStart + 5;
|
|
877
|
-
const remoteRemovePosStart = 4; // "quick brown "
|
|
878
|
-
const remoteRemovePosEnd = remoteRemovePosStart + 12;
|
|
879
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
880
|
-
let event;
|
|
881
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
882
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
883
|
-
});
|
|
884
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(localRemovePosStart, localRemovePosEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
885
|
-
assert(event);
|
|
886
|
-
assert(event.isLocal);
|
|
887
|
-
assert.equal(event.first.position, localRemovePosStart);
|
|
888
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, localRemovePosEnd);
|
|
889
|
-
assert.equal(event.ranges.length, 1);
|
|
890
|
-
assert.equal(event.first.segment.cachedLength, localRemovePosEnd - localRemovePosStart);
|
|
891
|
-
const segment1 = event.first.segment;
|
|
892
|
-
assert.equal(segment1.text, "brown");
|
|
893
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(remoteRemovePosStart, remoteRemovePosEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
894
|
-
remoteUserId);
|
|
895
|
-
client.applyMsg(remoteRemoveMessage);
|
|
896
|
-
client.applyMsg(localRemoveMessage);
|
|
897
|
-
assert(!event.isLocal);
|
|
898
|
-
assert.equal(event.ranges.length, 2);
|
|
899
|
-
assert.equal(event.first.position, remoteRemovePosStart);
|
|
900
|
-
// -1 is for split
|
|
901
|
-
assert.equal(event.first.segment.cachedLength, "quick ".length);
|
|
902
|
-
const segment2 = event.first.segment;
|
|
903
|
-
assert.equal(segment2.text, "quick ");
|
|
904
|
-
assert.equal(event.ranges[1].position, remoteRemovePosStart);
|
|
905
|
-
// -1 is for split
|
|
906
|
-
assert.equal(event.ranges[1].segment.cachedLength, " ".length);
|
|
907
|
-
const segment3 = event.ranges[1].segment;
|
|
908
|
-
assert.equal(segment3.text, " ");
|
|
909
|
-
});
|
|
910
|
-
});
|
|
911
|
-
describe("annotate", () => {
|
|
912
|
-
beforeEach(() => {
|
|
913
|
-
client = new TestClient();
|
|
914
|
-
client.insertTextLocal(0, "Habits change into character");
|
|
915
|
-
client.startOrUpdateCollaboration(localUserId);
|
|
916
|
-
});
|
|
917
|
-
it("same range, same property, local before remote", () => {
|
|
918
|
-
const localPosStart = 7; // "change"
|
|
919
|
-
const localPosEnd = localPosStart + 6;
|
|
920
|
-
const remotePosStart = 7; // "change"
|
|
921
|
-
const remotePosEnd = remotePosStart + 6;
|
|
922
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
923
|
-
let event;
|
|
924
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
925
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
926
|
-
});
|
|
927
|
-
const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo: "bar" }), currentSeqNumber + 1, currentSeqNumber);
|
|
928
|
-
client.applyMsg(localMessage);
|
|
929
|
-
assert(event);
|
|
930
|
-
verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
|
|
931
|
-
{
|
|
932
|
-
numChar: localPosEnd - localPosStart,
|
|
933
|
-
offset: localPosStart,
|
|
934
|
-
propDeltas: { foo: null },
|
|
935
|
-
props: { foo: "bar" },
|
|
936
|
-
text: "change",
|
|
937
|
-
},
|
|
938
|
-
]);
|
|
939
|
-
const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo: "bar" }), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
940
|
-
remoteUserId);
|
|
941
|
-
client.applyMsg(remoteMessage);
|
|
942
|
-
verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
|
|
943
|
-
{
|
|
944
|
-
numChar: remotePosEnd - remotePosStart,
|
|
945
|
-
offset: remotePosStart,
|
|
946
|
-
propDeltas: { foo: "bar" },
|
|
947
|
-
props: { foo: "bar" },
|
|
948
|
-
text: "change",
|
|
949
|
-
},
|
|
950
|
-
]);
|
|
951
|
-
});
|
|
952
|
-
it("same range, same property, remote before local", () => {
|
|
953
|
-
const localPosStart = 7; // "change"
|
|
954
|
-
const localPosEnd = localPosStart + 6;
|
|
955
|
-
const remotePosStart = 7; // "change"
|
|
956
|
-
const remotePosEnd = remotePosStart + 6;
|
|
957
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
958
|
-
let event;
|
|
959
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
960
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
961
|
-
});
|
|
962
|
-
const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo: "bar" }), currentSeqNumber + 2, currentSeqNumber);
|
|
963
|
-
assert(event);
|
|
964
|
-
verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
|
|
965
|
-
{
|
|
966
|
-
numChar: localPosEnd - localPosStart,
|
|
967
|
-
offset: localPosStart,
|
|
968
|
-
propDeltas: { foo: null },
|
|
969
|
-
props: { foo: "bar" },
|
|
970
|
-
text: "change",
|
|
971
|
-
},
|
|
972
|
-
]);
|
|
973
|
-
const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo: "bar" }), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
974
|
-
remoteUserId);
|
|
975
|
-
client.applyMsg(remoteMessage);
|
|
976
|
-
verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
|
|
977
|
-
{
|
|
978
|
-
numChar: remotePosEnd - remotePosStart,
|
|
979
|
-
offset: remotePosStart,
|
|
980
|
-
props: { foo: "bar" },
|
|
981
|
-
text: "change",
|
|
982
|
-
},
|
|
983
|
-
]);
|
|
984
|
-
client.applyMsg(localMessage);
|
|
985
|
-
});
|
|
986
|
-
it("same range, same property, different value, local before remote", () => {
|
|
987
|
-
const localPosStart = 7; // "change"
|
|
988
|
-
const localPosEnd = localPosStart + 6;
|
|
989
|
-
const remotePosStart = 7; // "change"
|
|
990
|
-
const remotePosEnd = remotePosStart + 6;
|
|
991
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
992
|
-
let event;
|
|
993
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
994
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
995
|
-
});
|
|
996
|
-
const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo: "bar" }), currentSeqNumber + 1, currentSeqNumber);
|
|
997
|
-
client.applyMsg(localMessage);
|
|
998
|
-
assert(event);
|
|
999
|
-
verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
|
|
1000
|
-
{
|
|
1001
|
-
numChar: localPosEnd - localPosStart,
|
|
1002
|
-
offset: localPosStart,
|
|
1003
|
-
propDeltas: { foo: null },
|
|
1004
|
-
props: { foo: "bar" },
|
|
1005
|
-
text: "change",
|
|
1006
|
-
},
|
|
1007
|
-
]);
|
|
1008
|
-
const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo: "bardash" }), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
1009
|
-
remoteUserId);
|
|
1010
|
-
client.applyMsg(remoteMessage);
|
|
1011
|
-
verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
|
|
1012
|
-
{
|
|
1013
|
-
numChar: remotePosEnd - remotePosStart,
|
|
1014
|
-
offset: remotePosStart,
|
|
1015
|
-
propDeltas: { foo: "bar" },
|
|
1016
|
-
props: { foo: "bardash" },
|
|
1017
|
-
text: "change",
|
|
1018
|
-
},
|
|
1019
|
-
]);
|
|
1020
|
-
});
|
|
1021
|
-
it("same range, same property, different value, remote before local", () => {
|
|
1022
|
-
const localPosStart = 7; // "change"
|
|
1023
|
-
const localPosEnd = localPosStart + 6;
|
|
1024
|
-
const remotePosStart = 7; // "change"
|
|
1025
|
-
const remotePosEnd = remotePosStart + 6;
|
|
1026
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1027
|
-
let event;
|
|
1028
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1029
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1030
|
-
});
|
|
1031
|
-
const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo: "bar" }), currentSeqNumber + 2, currentSeqNumber);
|
|
1032
|
-
assert(event);
|
|
1033
|
-
verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
|
|
1034
|
-
{
|
|
1035
|
-
numChar: localPosEnd - localPosStart,
|
|
1036
|
-
offset: localPosStart,
|
|
1037
|
-
propDeltas: { foo: null },
|
|
1038
|
-
props: { foo: "bar" },
|
|
1039
|
-
text: "change",
|
|
1040
|
-
},
|
|
1041
|
-
]);
|
|
1042
|
-
const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo: "bardash" }), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
1043
|
-
remoteUserId);
|
|
1044
|
-
client.applyMsg(remoteMessage);
|
|
1045
|
-
client.applyMsg(localMessage);
|
|
1046
|
-
verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
|
|
1047
|
-
{
|
|
1048
|
-
numChar: remotePosEnd - remotePosStart,
|
|
1049
|
-
offset: remotePosStart,
|
|
1050
|
-
props: { foo: "bar" },
|
|
1051
|
-
text: "change",
|
|
1052
|
-
},
|
|
1053
|
-
]);
|
|
1054
|
-
});
|
|
1055
|
-
it("same range, different properties, local before remote", () => {
|
|
1056
|
-
const localPosStart = 7; // "change"
|
|
1057
|
-
const localPosEnd = localPosStart + 6;
|
|
1058
|
-
const remotePosStart = 7; // "change"
|
|
1059
|
-
const remotePosEnd = remotePosStart + 6;
|
|
1060
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1061
|
-
let event;
|
|
1062
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1063
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1064
|
-
});
|
|
1065
|
-
const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo1: "bar1" }), currentSeqNumber + 1, currentSeqNumber);
|
|
1066
|
-
client.applyMsg(localMessage);
|
|
1067
|
-
assert(event);
|
|
1068
|
-
verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
|
|
1069
|
-
{
|
|
1070
|
-
numChar: localPosEnd - localPosStart,
|
|
1071
|
-
offset: localPosStart,
|
|
1072
|
-
propDeltas: { foo1: null },
|
|
1073
|
-
props: { foo1: "bar1" },
|
|
1074
|
-
text: "change",
|
|
1075
|
-
},
|
|
1076
|
-
]);
|
|
1077
|
-
const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo2: "bar2" }), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
1078
|
-
remoteUserId);
|
|
1079
|
-
client.applyMsg(remoteMessage);
|
|
1080
|
-
verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
|
|
1081
|
-
{
|
|
1082
|
-
numChar: remotePosEnd - remotePosStart,
|
|
1083
|
-
offset: remotePosStart,
|
|
1084
|
-
propDeltas: { foo2: null },
|
|
1085
|
-
props: { foo1: "bar1", foo2: "bar2" },
|
|
1086
|
-
text: "change",
|
|
1087
|
-
},
|
|
1088
|
-
]);
|
|
1089
|
-
});
|
|
1090
|
-
it("same range, different properties, remote before local", () => {
|
|
1091
|
-
const localPosStart = 7; // "change"
|
|
1092
|
-
const localPosEnd = localPosStart + 6;
|
|
1093
|
-
const remotePosStart = 7; // "change"
|
|
1094
|
-
const remotePosEnd = remotePosStart + 6;
|
|
1095
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1096
|
-
let event;
|
|
1097
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1098
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1099
|
-
});
|
|
1100
|
-
const localMessage = client.makeOpMessage(client.annotateRangeLocal(localPosStart, localPosEnd, { foo1: "bar1" }), currentSeqNumber + 2, currentSeqNumber);
|
|
1101
|
-
assert(event);
|
|
1102
|
-
verifyEventForAnnotate(event, true, localPosStart, localPosEnd, [
|
|
1103
|
-
{
|
|
1104
|
-
numChar: localPosEnd - localPosStart,
|
|
1105
|
-
offset: localPosStart,
|
|
1106
|
-
propDeltas: { foo1: null },
|
|
1107
|
-
props: { foo1: "bar1" },
|
|
1108
|
-
text: "change",
|
|
1109
|
-
},
|
|
1110
|
-
]);
|
|
1111
|
-
const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(remotePosStart, remotePosEnd, { foo2: "bar2" }), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
1112
|
-
remoteUserId);
|
|
1113
|
-
client.applyMsg(remoteMessage);
|
|
1114
|
-
verifyEventForAnnotate(event, false, remotePosStart, remotePosEnd, [
|
|
1115
|
-
{
|
|
1116
|
-
numChar: remotePosEnd - remotePosStart,
|
|
1117
|
-
offset: remotePosStart,
|
|
1118
|
-
propDeltas: { foo2: null },
|
|
1119
|
-
props: { foo1: "bar1", foo2: "bar2" },
|
|
1120
|
-
text: "change",
|
|
1121
|
-
},
|
|
1122
|
-
]);
|
|
1123
|
-
client.applyMsg(localMessage);
|
|
1124
|
-
});
|
|
1125
|
-
it("overlapping ranges, same properties, different values", () => {
|
|
1126
|
-
// initialize as following:
|
|
1127
|
-
// - second word has property foo1=bar1
|
|
1128
|
-
// - third word has property foo2=bar2
|
|
1129
|
-
// - fourth word has property foo3=bar3
|
|
1130
|
-
initialize();
|
|
1131
|
-
// apply remote operation that has seen "initialize" seqnum as following:
|
|
1132
|
-
// - apply foo=bar on whole line
|
|
1133
|
-
step1(client.mergeTree.collabWindow.currentSeq + 1, client.mergeTree.collabWindow.currentSeq);
|
|
1134
|
-
// apply local operation that has seen "step1" seqnum as following:
|
|
1135
|
-
// - change foo=bar1 for [firstWordStart, secondWordEnd)
|
|
1136
|
-
step2(client.mergeTree.collabWindow.currentSeq + 1, client.mergeTree.collabWindow.currentSeq);
|
|
1137
|
-
// apply remote operation that has not seen "step2" seqnum as following:
|
|
1138
|
-
// - change foo=bar2 for [thirdWordStart, fourthWordEnd)
|
|
1139
|
-
step3(client.mergeTree.collabWindow.currentSeq + 1, client.mergeTree.collabWindow.currentSeq - 1);
|
|
1140
|
-
// apply local operation that has seen "step3" seqnum as following:
|
|
1141
|
-
// - change foo=bar3 for [secondWordStart, fourthWordEnd)
|
|
1142
|
-
step4(client.mergeTree.collabWindow.currentSeq + 1, client.mergeTree.collabWindow.currentSeq);
|
|
1143
|
-
});
|
|
1144
|
-
const firstWordStart = 0; // "Habits"
|
|
1145
|
-
const secondWordStart = 7; // "change"
|
|
1146
|
-
const secondWordEnd = 13;
|
|
1147
|
-
const thirdWordStart = 14; // "into"
|
|
1148
|
-
const thirdWordEnd = 18;
|
|
1149
|
-
const fourthWordStart = 19; // "character"
|
|
1150
|
-
const fourthWordEnd = 28;
|
|
1151
|
-
function initialize() {
|
|
1152
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1153
|
-
let event;
|
|
1154
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1155
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1156
|
-
});
|
|
1157
|
-
const localMessage1 = client.makeOpMessage(client.annotateRangeLocal(secondWordStart, secondWordEnd, { foo1: "bar1" }), currentSeqNumber + 1, currentSeqNumber);
|
|
1158
|
-
client.applyMsg(localMessage1);
|
|
1159
|
-
assert(event);
|
|
1160
|
-
verifyEventForAnnotate(event, true, secondWordStart, secondWordEnd, [
|
|
1161
|
-
{
|
|
1162
|
-
numChar: secondWordEnd - secondWordStart,
|
|
1163
|
-
offset: secondWordStart,
|
|
1164
|
-
propDeltas: { foo1: null },
|
|
1165
|
-
props: { foo1: "bar1" },
|
|
1166
|
-
text: "change",
|
|
1167
|
-
},
|
|
1168
|
-
]);
|
|
1169
|
-
const localMessage2 = client.makeOpMessage(client.annotateRangeLocal(fourthWordStart, fourthWordEnd, { foo3: "bar3" }), currentSeqNumber + 2, currentSeqNumber + 1);
|
|
1170
|
-
client.applyMsg(localMessage2);
|
|
1171
|
-
verifyEventForAnnotate(event, true, fourthWordStart, fourthWordEnd, [
|
|
1172
|
-
{
|
|
1173
|
-
numChar: fourthWordEnd - fourthWordStart,
|
|
1174
|
-
offset: fourthWordStart,
|
|
1175
|
-
propDeltas: { foo3: null },
|
|
1176
|
-
props: { foo3: "bar3" },
|
|
1177
|
-
text: "character",
|
|
1178
|
-
},
|
|
1179
|
-
]);
|
|
1180
|
-
const remoteMessage1 = client.makeOpMessage(createAnnotateRangeOp(thirdWordStart, thirdWordEnd, { foo2: "bar2" }), currentSeqNumber + 3, currentSeqNumber, // refseq
|
|
1181
|
-
remoteUserId);
|
|
1182
|
-
client.applyMsg(remoteMessage1);
|
|
1183
|
-
verifyEventForAnnotate(event, false, thirdWordStart, thirdWordEnd, [
|
|
1184
|
-
{
|
|
1185
|
-
numChar: thirdWordEnd - thirdWordStart,
|
|
1186
|
-
offset: thirdWordStart,
|
|
1187
|
-
propDeltas: { foo2: null },
|
|
1188
|
-
props: { foo2: "bar2" },
|
|
1189
|
-
text: "into",
|
|
1190
|
-
},
|
|
1191
|
-
]);
|
|
1192
|
-
}
|
|
1193
|
-
function step1(seqnum, refseqnum) {
|
|
1194
|
-
let event;
|
|
1195
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1196
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1197
|
-
});
|
|
1198
|
-
const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(firstWordStart, fourthWordEnd, { foo: "bar" }), seqnum, refseqnum, remoteUserId);
|
|
1199
|
-
client.applyMsg(remoteMessage);
|
|
1200
|
-
assert(event);
|
|
1201
|
-
verifyEventForAnnotate(event, false, firstWordStart, fourthWordEnd, [
|
|
1202
|
-
{
|
|
1203
|
-
numChar: secondWordStart - firstWordStart,
|
|
1204
|
-
offset: firstWordStart,
|
|
1205
|
-
propDeltas: { foo: null },
|
|
1206
|
-
props: { foo: "bar" },
|
|
1207
|
-
text: "Habits ",
|
|
1208
|
-
},
|
|
1209
|
-
{
|
|
1210
|
-
numChar: secondWordEnd - secondWordStart,
|
|
1211
|
-
offset: secondWordStart,
|
|
1212
|
-
propDeltas: { foo: null },
|
|
1213
|
-
props: { foo: "bar", foo1: "bar1" },
|
|
1214
|
-
text: "change",
|
|
1215
|
-
},
|
|
1216
|
-
{
|
|
1217
|
-
numChar: thirdWordStart - secondWordEnd,
|
|
1218
|
-
offset: secondWordEnd,
|
|
1219
|
-
propDeltas: { foo: null },
|
|
1220
|
-
props: { foo: "bar" },
|
|
1221
|
-
text: " ",
|
|
1222
|
-
},
|
|
1223
|
-
{
|
|
1224
|
-
numChar: thirdWordEnd - thirdWordStart,
|
|
1225
|
-
offset: thirdWordStart,
|
|
1226
|
-
propDeltas: { foo: null },
|
|
1227
|
-
props: { foo: "bar", foo2: "bar2" },
|
|
1228
|
-
text: "into",
|
|
1229
|
-
},
|
|
1230
|
-
{
|
|
1231
|
-
numChar: fourthWordStart - thirdWordEnd,
|
|
1232
|
-
offset: thirdWordEnd,
|
|
1233
|
-
propDeltas: { foo: null },
|
|
1234
|
-
props: { foo: "bar" },
|
|
1235
|
-
text: " ",
|
|
1236
|
-
},
|
|
1237
|
-
{
|
|
1238
|
-
numChar: fourthWordEnd - fourthWordStart,
|
|
1239
|
-
offset: fourthWordStart,
|
|
1240
|
-
propDeltas: { foo: null },
|
|
1241
|
-
props: { foo: "bar", foo3: "bar3" },
|
|
1242
|
-
text: "character",
|
|
1243
|
-
},
|
|
1244
|
-
]);
|
|
1245
|
-
}
|
|
1246
|
-
function step2(seqnum, refseqnum) {
|
|
1247
|
-
let event;
|
|
1248
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1249
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1250
|
-
});
|
|
1251
|
-
const localMessage = client.makeOpMessage(client.annotateRangeLocal(firstWordStart, secondWordEnd, { foo: "bar1" }), seqnum, refseqnum);
|
|
1252
|
-
client.applyMsg(localMessage);
|
|
1253
|
-
assert(event);
|
|
1254
|
-
verifyEventForAnnotate(event, true, firstWordStart, secondWordEnd, [
|
|
1255
|
-
{
|
|
1256
|
-
numChar: secondWordStart - firstWordStart,
|
|
1257
|
-
offset: firstWordStart,
|
|
1258
|
-
propDeltas: { foo: "bar" },
|
|
1259
|
-
props: { foo: "bar1" },
|
|
1260
|
-
text: "Habits ",
|
|
1261
|
-
},
|
|
1262
|
-
{
|
|
1263
|
-
numChar: secondWordEnd - secondWordStart,
|
|
1264
|
-
offset: secondWordStart,
|
|
1265
|
-
propDeltas: { foo: "bar" },
|
|
1266
|
-
props: { foo: "bar1", foo1: "bar1" },
|
|
1267
|
-
text: "change",
|
|
1268
|
-
},
|
|
1269
|
-
]);
|
|
1270
|
-
}
|
|
1271
|
-
function step3(seqnum, refseqnum) {
|
|
1272
|
-
let event;
|
|
1273
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1274
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1275
|
-
});
|
|
1276
|
-
const remoteMessage = client.makeOpMessage(createAnnotateRangeOp(thirdWordStart, fourthWordEnd, { foo: "bar2" }), seqnum, refseqnum, remoteUserId);
|
|
1277
|
-
client.applyMsg(remoteMessage);
|
|
1278
|
-
assert(event);
|
|
1279
|
-
verifyEventForAnnotate(event, false, thirdWordStart, fourthWordEnd, [
|
|
1280
|
-
{
|
|
1281
|
-
numChar: thirdWordEnd - thirdWordStart,
|
|
1282
|
-
offset: thirdWordStart,
|
|
1283
|
-
propDeltas: { foo: "bar" },
|
|
1284
|
-
props: { foo: "bar2", foo2: "bar2" },
|
|
1285
|
-
text: "into",
|
|
1286
|
-
},
|
|
1287
|
-
{
|
|
1288
|
-
numChar: fourthWordStart - thirdWordEnd,
|
|
1289
|
-
offset: thirdWordEnd,
|
|
1290
|
-
propDeltas: { foo: "bar" },
|
|
1291
|
-
props: { foo: "bar2" },
|
|
1292
|
-
text: " ",
|
|
1293
|
-
},
|
|
1294
|
-
{
|
|
1295
|
-
numChar: fourthWordEnd - fourthWordStart,
|
|
1296
|
-
offset: fourthWordStart,
|
|
1297
|
-
propDeltas: { foo: "bar" },
|
|
1298
|
-
props: { foo: "bar2", foo3: "bar3" },
|
|
1299
|
-
text: "character",
|
|
1300
|
-
},
|
|
1301
|
-
]);
|
|
1302
|
-
}
|
|
1303
|
-
function step4(seqnum, refseqnum) {
|
|
1304
|
-
let event;
|
|
1305
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1306
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1307
|
-
});
|
|
1308
|
-
const localMessage = client.makeOpMessage(client.annotateRangeLocal(secondWordStart, fourthWordEnd, { foo: "bar3" }), seqnum, refseqnum);
|
|
1309
|
-
client.applyMsg(localMessage);
|
|
1310
|
-
assert(event);
|
|
1311
|
-
verifyEventForAnnotate(event, true, secondWordStart, fourthWordEnd, [
|
|
1312
|
-
{
|
|
1313
|
-
numChar: secondWordEnd - secondWordStart,
|
|
1314
|
-
offset: secondWordStart,
|
|
1315
|
-
propDeltas: { foo: "bar1" },
|
|
1316
|
-
props: { foo: "bar3", foo1: "bar1" },
|
|
1317
|
-
text: "change",
|
|
1318
|
-
},
|
|
1319
|
-
{
|
|
1320
|
-
numChar: thirdWordStart - secondWordEnd,
|
|
1321
|
-
offset: secondWordEnd,
|
|
1322
|
-
propDeltas: { foo: "bar" },
|
|
1323
|
-
props: { foo: "bar3" },
|
|
1324
|
-
text: " ",
|
|
1325
|
-
},
|
|
1326
|
-
{
|
|
1327
|
-
numChar: thirdWordEnd - thirdWordStart,
|
|
1328
|
-
offset: thirdWordStart,
|
|
1329
|
-
propDeltas: { foo: "bar2" },
|
|
1330
|
-
props: { foo: "bar3", foo2: "bar2" },
|
|
1331
|
-
text: "into",
|
|
1332
|
-
},
|
|
1333
|
-
{
|
|
1334
|
-
numChar: fourthWordStart - thirdWordEnd,
|
|
1335
|
-
offset: thirdWordEnd,
|
|
1336
|
-
propDeltas: { foo: "bar2" },
|
|
1337
|
-
props: { foo: "bar3" },
|
|
1338
|
-
text: " ",
|
|
1339
|
-
},
|
|
1340
|
-
{
|
|
1341
|
-
numChar: fourthWordEnd - fourthWordStart,
|
|
1342
|
-
offset: fourthWordStart,
|
|
1343
|
-
propDeltas: { foo: "bar2" },
|
|
1344
|
-
props: { foo: "bar3", foo3: "bar3" },
|
|
1345
|
-
text: "character",
|
|
1346
|
-
},
|
|
1347
|
-
]);
|
|
1348
|
-
}
|
|
1349
|
-
function verifyEventForAnnotate(event, isLocal, start, end, expected) {
|
|
1350
|
-
assert(event.isLocal === isLocal);
|
|
1351
|
-
assert.equal(event.first.position, start);
|
|
1352
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, end);
|
|
1353
|
-
assert.equal(event.ranges.length, expected.length);
|
|
1354
|
-
for (let i = 0; i < expected.length; i = i + 1) {
|
|
1355
|
-
assert.equal(event.ranges[i].position, expected[i].offset);
|
|
1356
|
-
assert.equal(event.ranges[i].segment.cachedLength, expected[i].numChar);
|
|
1357
|
-
assert.equal(Object.keys(event.ranges[i].segment.properties ?? {}).length, Object.keys(expected[i].props).length);
|
|
1358
|
-
for (const key of Object.keys(event.ranges[i].segment.properties ?? {})) {
|
|
1359
|
-
assert.equal(event.ranges[i].segment.properties?.[key], expected[i].props[key]);
|
|
1360
|
-
}
|
|
1361
|
-
if (expected[i].propDeltas !== undefined) {
|
|
1362
|
-
assert.equal(Object.keys(event.ranges[i].propertyDeltas).length, Object.keys(expected[i].propDeltas ?? {}).length);
|
|
1363
|
-
for (const key of Object.keys(event.ranges[i].propertyDeltas)) {
|
|
1364
|
-
assert.equal(event.ranges[i].propertyDeltas[key], expected[i].propDeltas?.[key]);
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
else {
|
|
1368
|
-
assert(isNullOrUndefined(event.ranges[i].propertyDeltas) ||
|
|
1369
|
-
Object.keys(event.ranges[i].propertyDeltas).length === 0);
|
|
1370
|
-
}
|
|
1371
|
-
if (expected[i].text !== undefined) {
|
|
1372
|
-
const segment = event.ranges[i].segment;
|
|
1373
|
-
assert.equal(segment.text, expected[i].text);
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
}
|
|
1377
|
-
});
|
|
1378
|
-
describe("combination", () => {
|
|
1379
|
-
beforeEach(() => {
|
|
1380
|
-
client = new TestClient();
|
|
1381
|
-
client.insertTextLocal(0, "The brown fox jumps over the lazy dog");
|
|
1382
|
-
client.startOrUpdateCollaboration(localUserId);
|
|
1383
|
-
});
|
|
1384
|
-
it("insertPos before deleteRange, insertLocal deleteRemote, local before remote", () => {
|
|
1385
|
-
const insertPos = 4; // before "brown"
|
|
1386
|
-
const insertText = "quick ";
|
|
1387
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1388
|
-
const deleteRangeEnd = 34;
|
|
1389
|
-
const output = "The quick brown fox jumps over the dog";
|
|
1390
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1391
|
-
let event;
|
|
1392
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1393
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1394
|
-
});
|
|
1395
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 1, currentSeqNumber);
|
|
1396
|
-
client.applyMsg(localInsertMessage);
|
|
1397
|
-
assert(event);
|
|
1398
|
-
assert(event.isLocal);
|
|
1399
|
-
assert.equal(event.first.position, insertPos);
|
|
1400
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1401
|
-
assert.equal(event.ranges.length, 1);
|
|
1402
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1403
|
-
const segment1 = event.first.segment;
|
|
1404
|
-
assert.equal(segment1.text, insertText);
|
|
1405
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
1406
|
-
remoteUserId);
|
|
1407
|
-
client.applyMsg(remoteRemoveMessage);
|
|
1408
|
-
assert(!event.isLocal);
|
|
1409
|
-
assert.equal(event.first.position, deleteRangeStart + insertText.length);
|
|
1410
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd + insertText.length);
|
|
1411
|
-
assert.equal(event.ranges.length, 1);
|
|
1412
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1413
|
-
const segment2 = event.first.segment;
|
|
1414
|
-
assert.equal(segment2.text, "lazy ");
|
|
1415
|
-
assert.equal(client.getText(), output);
|
|
1416
|
-
});
|
|
1417
|
-
it("insertPos before deleteRange, insertLocal deleteRemote, remote before local", () => {
|
|
1418
|
-
const insertPos = 4; // before "brown"
|
|
1419
|
-
const insertText = "quick ";
|
|
1420
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1421
|
-
const deleteRangeEnd = 34;
|
|
1422
|
-
const output = "The quick brown fox jumps over the dog";
|
|
1423
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1424
|
-
let event;
|
|
1425
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1426
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1427
|
-
});
|
|
1428
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 2, currentSeqNumber);
|
|
1429
|
-
assert(event);
|
|
1430
|
-
assert(event.isLocal);
|
|
1431
|
-
assert.equal(event.first.position, insertPos);
|
|
1432
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1433
|
-
assert.equal(event.ranges.length, 1);
|
|
1434
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1435
|
-
const segment1 = event.first.segment;
|
|
1436
|
-
assert.equal(segment1.text, insertText);
|
|
1437
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
1438
|
-
remoteUserId);
|
|
1439
|
-
client.applyMsg(remoteRemoveMessage);
|
|
1440
|
-
assert(!event.isLocal);
|
|
1441
|
-
assert.equal(event.first.position, deleteRangeStart + insertText.length);
|
|
1442
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd + insertText.length);
|
|
1443
|
-
assert.equal(event.ranges.length, 1);
|
|
1444
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1445
|
-
const segment2 = event.first.segment;
|
|
1446
|
-
assert.equal(segment2.text, "lazy ");
|
|
1447
|
-
client.applyMsg(localInsertMessage);
|
|
1448
|
-
assert.equal(client.getText(), output);
|
|
1449
|
-
});
|
|
1450
|
-
it("insertPos before deleteRange, deleteLocal insertRemote, local before remote", () => {
|
|
1451
|
-
const insertPos = 4; // before "brown"
|
|
1452
|
-
const insertText = "quick ";
|
|
1453
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1454
|
-
const deleteRangeEnd = 34;
|
|
1455
|
-
const output = "The quick brown fox jumps over the dog";
|
|
1456
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1457
|
-
let event;
|
|
1458
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1459
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1460
|
-
});
|
|
1461
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
1462
|
-
client.applyMsg(localRemoveMessage);
|
|
1463
|
-
assert(event);
|
|
1464
|
-
assert(event.isLocal);
|
|
1465
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1466
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1467
|
-
assert.equal(event.ranges.length, 1);
|
|
1468
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1469
|
-
const segment1 = event.first.segment;
|
|
1470
|
-
assert.equal(segment1.text, "lazy ");
|
|
1471
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
|
|
1472
|
-
remoteUserId);
|
|
1473
|
-
client.applyMsg(remoteInsertMessage);
|
|
1474
|
-
assert(!event.isLocal);
|
|
1475
|
-
assert.equal(event.first.position, insertPos);
|
|
1476
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1477
|
-
assert.equal(event.ranges.length, 1);
|
|
1478
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1479
|
-
const segment2 = event.first.segment;
|
|
1480
|
-
assert.equal(segment2.text, insertText);
|
|
1481
|
-
assert.equal(client.getText(), output);
|
|
1482
|
-
});
|
|
1483
|
-
it("insertPos before deleteRange, deleteLocal insertRemote, remote before local", () => {
|
|
1484
|
-
const insertPos = 4; // before "brown"
|
|
1485
|
-
const insertText = "quick ";
|
|
1486
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1487
|
-
const deleteRangeEnd = 34;
|
|
1488
|
-
const output = "The quick brown fox jumps over the dog";
|
|
1489
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1490
|
-
let event;
|
|
1491
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1492
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1493
|
-
});
|
|
1494
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
1495
|
-
assert(event);
|
|
1496
|
-
assert(event.isLocal);
|
|
1497
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1498
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1499
|
-
assert.equal(event.ranges.length, 1);
|
|
1500
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1501
|
-
const segment1 = event.first.segment;
|
|
1502
|
-
assert.equal(segment1.text, "lazy ");
|
|
1503
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
|
|
1504
|
-
remoteUserId);
|
|
1505
|
-
client.applyMsg(remoteInsertMessage);
|
|
1506
|
-
assert(!event.isLocal);
|
|
1507
|
-
assert.equal(event.first.position, insertPos);
|
|
1508
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1509
|
-
assert.equal(event.ranges.length, 1);
|
|
1510
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1511
|
-
const segment2 = event.first.segment;
|
|
1512
|
-
assert.equal(segment2.text, insertText);
|
|
1513
|
-
client.applyMsg(localRemoveMessage);
|
|
1514
|
-
assert.equal(client.getText(), output);
|
|
1515
|
-
});
|
|
1516
|
-
it("insertPos after deleteRange, insertLocal deleteRemote, local before remote", () => {
|
|
1517
|
-
const insertPos = 29; // before "lazy"
|
|
1518
|
-
const insertText = "black ";
|
|
1519
|
-
const deleteRangeStart = 4; // "brown "
|
|
1520
|
-
const deleteRangeEnd = 10;
|
|
1521
|
-
const output = "The fox jumps over the black lazy dog";
|
|
1522
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1523
|
-
let event;
|
|
1524
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1525
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1526
|
-
});
|
|
1527
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 1, currentSeqNumber);
|
|
1528
|
-
client.applyMsg(localInsertMessage);
|
|
1529
|
-
assert(event);
|
|
1530
|
-
assert(event.isLocal);
|
|
1531
|
-
assert.equal(event.first.position, insertPos);
|
|
1532
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1533
|
-
assert.equal(event.ranges.length, 1);
|
|
1534
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1535
|
-
const segment1 = event.first.segment;
|
|
1536
|
-
assert.equal(segment1.text, insertText);
|
|
1537
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
1538
|
-
remoteUserId);
|
|
1539
|
-
client.applyMsg(remoteRemoveMessage);
|
|
1540
|
-
assert(!event.isLocal);
|
|
1541
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1542
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1543
|
-
assert.equal(event.ranges.length, 1);
|
|
1544
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1545
|
-
const segment2 = event.first.segment;
|
|
1546
|
-
assert.equal(segment2.text, "brown ");
|
|
1547
|
-
assert.equal(client.getText(), output);
|
|
1548
|
-
});
|
|
1549
|
-
it("insertPos after deleteRange, insertLocal deleteRemote, remote before local", () => {
|
|
1550
|
-
const insertPos = 29; // before "lazy"
|
|
1551
|
-
const insertText = "black ";
|
|
1552
|
-
const deleteRangeStart = 4; // "brown "
|
|
1553
|
-
const deleteRangeEnd = 10;
|
|
1554
|
-
const output = "The fox jumps over the black lazy dog";
|
|
1555
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1556
|
-
let event;
|
|
1557
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1558
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1559
|
-
});
|
|
1560
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 2, currentSeqNumber);
|
|
1561
|
-
assert(event);
|
|
1562
|
-
assert(event.isLocal);
|
|
1563
|
-
assert.equal(event.first.position, insertPos);
|
|
1564
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1565
|
-
assert.equal(event.ranges.length, 1);
|
|
1566
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1567
|
-
const segment1 = event.first.segment;
|
|
1568
|
-
assert.equal(segment1.text, insertText);
|
|
1569
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
1570
|
-
remoteUserId);
|
|
1571
|
-
client.applyMsg(remoteRemoveMessage);
|
|
1572
|
-
assert(!event.isLocal);
|
|
1573
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1574
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1575
|
-
assert.equal(event.ranges.length, 1);
|
|
1576
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1577
|
-
const segment2 = event.first.segment;
|
|
1578
|
-
assert.equal(segment2.text, "brown ");
|
|
1579
|
-
client.applyMsg(localInsertMessage);
|
|
1580
|
-
assert.equal(client.getText(), output);
|
|
1581
|
-
});
|
|
1582
|
-
it("insertPos after deleteRange, deleteLocal insertRemote, local before remote", () => {
|
|
1583
|
-
const insertPos = 29; // before "lazy"
|
|
1584
|
-
const insertText = "black ";
|
|
1585
|
-
const deleteRangeStart = 4; // "brown "
|
|
1586
|
-
const deleteRangeEnd = 10;
|
|
1587
|
-
const output = "The fox jumps over the black lazy dog";
|
|
1588
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1589
|
-
let event;
|
|
1590
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1591
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1592
|
-
});
|
|
1593
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
1594
|
-
client.applyMsg(localRemoveMessage);
|
|
1595
|
-
assert(event);
|
|
1596
|
-
assert(event.isLocal);
|
|
1597
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1598
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1599
|
-
assert.equal(event.ranges.length, 1);
|
|
1600
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1601
|
-
const segment1 = event.first.segment;
|
|
1602
|
-
assert.equal(segment1.text, "brown ");
|
|
1603
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
|
|
1604
|
-
remoteUserId);
|
|
1605
|
-
client.applyMsg(remoteInsertMessage);
|
|
1606
|
-
assert(!event.isLocal);
|
|
1607
|
-
assert.equal(event.first.position, insertPos - (deleteRangeEnd - deleteRangeStart));
|
|
1608
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos - (deleteRangeEnd - deleteRangeStart) + insertText.length);
|
|
1609
|
-
assert.equal(event.ranges.length, 1);
|
|
1610
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1611
|
-
const segment2 = event.first.segment;
|
|
1612
|
-
assert.equal(segment2.text, insertText);
|
|
1613
|
-
assert.equal(client.getText(), output);
|
|
1614
|
-
});
|
|
1615
|
-
it("insertPos after deleteRange, deleteLocal insertRemote, remote before local", () => {
|
|
1616
|
-
const insertPos = 29; // before "lazy"
|
|
1617
|
-
const insertText = "black ";
|
|
1618
|
-
const deleteRangeStart = 4; // "brown "
|
|
1619
|
-
const deleteRangeEnd = 10;
|
|
1620
|
-
const output = "The fox jumps over the black lazy dog";
|
|
1621
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1622
|
-
let event;
|
|
1623
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1624
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1625
|
-
});
|
|
1626
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
1627
|
-
assert(event);
|
|
1628
|
-
assert(event.isLocal);
|
|
1629
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1630
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1631
|
-
assert.equal(event.ranges.length, 1);
|
|
1632
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1633
|
-
const segment1 = event.first.segment;
|
|
1634
|
-
assert.equal(segment1.text, "brown ");
|
|
1635
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
|
|
1636
|
-
remoteUserId);
|
|
1637
|
-
client.applyMsg(remoteInsertMessage);
|
|
1638
|
-
assert(!event.isLocal);
|
|
1639
|
-
assert.equal(event.first.position, insertPos - (deleteRangeEnd - deleteRangeStart));
|
|
1640
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos - (deleteRangeEnd - deleteRangeStart) + insertText.length);
|
|
1641
|
-
assert.equal(event.ranges.length, 1);
|
|
1642
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1643
|
-
const segment2 = event.first.segment;
|
|
1644
|
-
assert.equal(segment2.text, insertText);
|
|
1645
|
-
client.applyMsg(localRemoveMessage);
|
|
1646
|
-
assert.equal(client.getText(), output);
|
|
1647
|
-
});
|
|
1648
|
-
it("insertPos is deleteRangeStart, insertLocal deleteRemote, local before remote", () => {
|
|
1649
|
-
const insertPos = 29; // before "lazy"
|
|
1650
|
-
const insertText = "black ";
|
|
1651
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1652
|
-
const deleteRangeEnd = 34;
|
|
1653
|
-
const output = "The brown fox jumps over the black dog";
|
|
1654
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1655
|
-
let event;
|
|
1656
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1657
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1658
|
-
});
|
|
1659
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 1, currentSeqNumber);
|
|
1660
|
-
client.applyMsg(localInsertMessage);
|
|
1661
|
-
assert(event);
|
|
1662
|
-
assert(event.isLocal);
|
|
1663
|
-
assert.equal(event.first.position, insertPos);
|
|
1664
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1665
|
-
assert.equal(event.ranges.length, 1);
|
|
1666
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1667
|
-
const segment1 = event.first.segment;
|
|
1668
|
-
assert.equal(segment1.text, insertText);
|
|
1669
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
1670
|
-
remoteUserId);
|
|
1671
|
-
client.applyMsg(remoteRemoveMessage);
|
|
1672
|
-
assert(!event.isLocal);
|
|
1673
|
-
assert.equal(event.first.position, deleteRangeStart + insertText.length);
|
|
1674
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd + insertText.length);
|
|
1675
|
-
assert.equal(event.ranges.length, 1);
|
|
1676
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1677
|
-
const segment2 = event.first.segment;
|
|
1678
|
-
assert.equal(segment2.text, "lazy ");
|
|
1679
|
-
assert.equal(client.getText(), output);
|
|
1680
|
-
});
|
|
1681
|
-
it("insertPos is deleteRangeStart, insertLocal deleteRemote, remote before local", () => {
|
|
1682
|
-
const insertPos = 29; // before "lazy"
|
|
1683
|
-
const insertText = "black ";
|
|
1684
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1685
|
-
const deleteRangeEnd = 34;
|
|
1686
|
-
const output = "The brown fox jumps over the black dog";
|
|
1687
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1688
|
-
let event;
|
|
1689
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1690
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1691
|
-
});
|
|
1692
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 2, currentSeqNumber);
|
|
1693
|
-
assert(event);
|
|
1694
|
-
assert(event.isLocal);
|
|
1695
|
-
assert.equal(event.first.position, insertPos);
|
|
1696
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1697
|
-
assert.equal(event.ranges.length, 1);
|
|
1698
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1699
|
-
const segment1 = event.first.segment;
|
|
1700
|
-
assert.equal(segment1.text, insertText);
|
|
1701
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
1702
|
-
remoteUserId);
|
|
1703
|
-
client.applyMsg(remoteRemoveMessage);
|
|
1704
|
-
assert(!event.isLocal);
|
|
1705
|
-
assert.equal(event.first.position, deleteRangeStart + insertText.length);
|
|
1706
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd + insertText.length);
|
|
1707
|
-
assert.equal(event.ranges.length, 1);
|
|
1708
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1709
|
-
const segment2 = event.first.segment;
|
|
1710
|
-
assert.equal(segment2.text, "lazy ");
|
|
1711
|
-
client.applyMsg(localInsertMessage);
|
|
1712
|
-
assert.equal(client.getText(), output);
|
|
1713
|
-
});
|
|
1714
|
-
it("insertPos is deleteRangeStart, deleteLocal insertRemote, local before remote", () => {
|
|
1715
|
-
const insertPos = 29; // before "lazy"
|
|
1716
|
-
const insertText = "black ";
|
|
1717
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1718
|
-
const deleteRangeEnd = 34;
|
|
1719
|
-
const output = "The brown fox jumps over the black dog";
|
|
1720
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1721
|
-
let event;
|
|
1722
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1723
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1724
|
-
});
|
|
1725
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
1726
|
-
client.applyMsg(localRemoveMessage);
|
|
1727
|
-
assert(event);
|
|
1728
|
-
assert(event.isLocal);
|
|
1729
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1730
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1731
|
-
assert.equal(event.ranges.length, 1);
|
|
1732
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1733
|
-
const segment1 = event.first.segment;
|
|
1734
|
-
assert.equal(segment1.text, "lazy ");
|
|
1735
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
|
|
1736
|
-
remoteUserId);
|
|
1737
|
-
client.applyMsg(remoteInsertMessage);
|
|
1738
|
-
assert(!event.isLocal);
|
|
1739
|
-
assert.equal(event.first.position, insertPos);
|
|
1740
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1741
|
-
assert.equal(event.ranges.length, 1);
|
|
1742
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1743
|
-
const segment2 = event.first.segment;
|
|
1744
|
-
assert.equal(segment2.text, insertText);
|
|
1745
|
-
assert.equal(client.getText(), output);
|
|
1746
|
-
});
|
|
1747
|
-
it("insertPos is deleteRangeStart, deleteLocal insertRemote, remote before local", () => {
|
|
1748
|
-
const insertPos = 29; // before "lazy"
|
|
1749
|
-
const insertText = "black ";
|
|
1750
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1751
|
-
const deleteRangeEnd = 34;
|
|
1752
|
-
const output = "The brown fox jumps over the black dog";
|
|
1753
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1754
|
-
let event;
|
|
1755
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1756
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1757
|
-
});
|
|
1758
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
1759
|
-
assert(event);
|
|
1760
|
-
assert(event.isLocal);
|
|
1761
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1762
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1763
|
-
assert.equal(event.ranges.length, 1);
|
|
1764
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1765
|
-
const segment1 = event.first.segment;
|
|
1766
|
-
assert.equal(segment1.text, "lazy ");
|
|
1767
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
|
|
1768
|
-
remoteUserId);
|
|
1769
|
-
client.applyMsg(remoteInsertMessage);
|
|
1770
|
-
assert(!event.isLocal);
|
|
1771
|
-
assert.equal(event.first.position, insertPos);
|
|
1772
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1773
|
-
assert.equal(event.ranges.length, 1);
|
|
1774
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1775
|
-
const segment2 = event.first.segment;
|
|
1776
|
-
assert.equal(segment2.text, insertText);
|
|
1777
|
-
client.applyMsg(localRemoveMessage);
|
|
1778
|
-
assert.equal(client.getText(), output);
|
|
1779
|
-
});
|
|
1780
|
-
it("insertPos is deleteRangeEnd, insertLocal deleteRemote, local before remote", () => {
|
|
1781
|
-
const insertPos = 34; // after "lazy"
|
|
1782
|
-
const insertText = "black ";
|
|
1783
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1784
|
-
const deleteRangeEnd = 34;
|
|
1785
|
-
const output = "The brown fox jumps over the black dog";
|
|
1786
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1787
|
-
let event;
|
|
1788
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1789
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1790
|
-
});
|
|
1791
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 1, currentSeqNumber);
|
|
1792
|
-
client.applyMsg(localInsertMessage);
|
|
1793
|
-
assert(event);
|
|
1794
|
-
assert(event.isLocal);
|
|
1795
|
-
assert.equal(event.first.position, insertPos);
|
|
1796
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1797
|
-
assert.equal(event.ranges.length, 1);
|
|
1798
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1799
|
-
const segment1 = event.first.segment;
|
|
1800
|
-
assert.equal(segment1.text, insertText);
|
|
1801
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
1802
|
-
remoteUserId);
|
|
1803
|
-
client.applyMsg(remoteRemoveMessage);
|
|
1804
|
-
assert(!event.isLocal);
|
|
1805
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1806
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1807
|
-
assert.equal(event.ranges.length, 1);
|
|
1808
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1809
|
-
const segment2 = event.first.segment;
|
|
1810
|
-
assert.equal(segment2.text, "lazy ");
|
|
1811
|
-
assert.equal(client.getText(), output);
|
|
1812
|
-
});
|
|
1813
|
-
it("insertPos is deleteRangeEnd, insertLocal deleteRemote, remote before local", () => {
|
|
1814
|
-
const insertPos = 34; // after "lazy"
|
|
1815
|
-
const insertText = "black ";
|
|
1816
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1817
|
-
const deleteRangeEnd = 34;
|
|
1818
|
-
const output = "The brown fox jumps over the black dog";
|
|
1819
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1820
|
-
let event;
|
|
1821
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1822
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1823
|
-
});
|
|
1824
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 2, currentSeqNumber);
|
|
1825
|
-
assert(event);
|
|
1826
|
-
assert(event.isLocal);
|
|
1827
|
-
assert.equal(event.first.position, insertPos);
|
|
1828
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1829
|
-
assert.equal(event.ranges.length, 1);
|
|
1830
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1831
|
-
const segment1 = event.first.segment;
|
|
1832
|
-
assert.equal(segment1.text, insertText);
|
|
1833
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
1834
|
-
remoteUserId);
|
|
1835
|
-
client.applyMsg(remoteRemoveMessage);
|
|
1836
|
-
assert(!event.isLocal);
|
|
1837
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1838
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1839
|
-
assert.equal(event.ranges.length, 1);
|
|
1840
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1841
|
-
const segment2 = event.first.segment;
|
|
1842
|
-
assert.equal(segment2.text, "lazy ");
|
|
1843
|
-
client.applyMsg(localInsertMessage);
|
|
1844
|
-
assert.equal(client.getText(), output);
|
|
1845
|
-
});
|
|
1846
|
-
it("insertPos is deleteRangeEnd, deleteLocal insertRemote, local before remote", () => {
|
|
1847
|
-
const insertPos = 34; // after "lazy"
|
|
1848
|
-
const insertText = "black ";
|
|
1849
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1850
|
-
const deleteRangeEnd = 34;
|
|
1851
|
-
const output = "The brown fox jumps over the black dog";
|
|
1852
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1853
|
-
let event;
|
|
1854
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1855
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1856
|
-
});
|
|
1857
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
1858
|
-
assert(event);
|
|
1859
|
-
assert(event.isLocal);
|
|
1860
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1861
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1862
|
-
assert.equal(event.ranges.length, 1);
|
|
1863
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1864
|
-
const segment1 = event.first.segment;
|
|
1865
|
-
assert.equal(segment1.text, "lazy ");
|
|
1866
|
-
client.applyMsg(localRemoveMessage);
|
|
1867
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
|
|
1868
|
-
remoteUserId);
|
|
1869
|
-
client.applyMsg(remoteInsertMessage);
|
|
1870
|
-
assert(!event.isLocal);
|
|
1871
|
-
assert.equal(event.first.position, insertPos - (deleteRangeEnd - deleteRangeStart));
|
|
1872
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length - (deleteRangeEnd - deleteRangeStart));
|
|
1873
|
-
assert.equal(event.ranges.length, 1);
|
|
1874
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1875
|
-
const segment2 = event.first.segment;
|
|
1876
|
-
assert.equal(segment2.text, insertText);
|
|
1877
|
-
assert.equal(client.getText(), output);
|
|
1878
|
-
});
|
|
1879
|
-
it("insertPos is deleteRangeEnd, deleteLocal insertRemote, remote before local", () => {
|
|
1880
|
-
const insertPos = 34; // after "lazy"
|
|
1881
|
-
const insertText = "black ";
|
|
1882
|
-
const deleteRangeStart = 29; // "lazy "
|
|
1883
|
-
const deleteRangeEnd = 34;
|
|
1884
|
-
const output = "The brown fox jumps over the black dog";
|
|
1885
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1886
|
-
let event;
|
|
1887
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1888
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1889
|
-
});
|
|
1890
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
1891
|
-
assert(event);
|
|
1892
|
-
assert(event.isLocal);
|
|
1893
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
1894
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
1895
|
-
assert.equal(event.ranges.length, 1);
|
|
1896
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
1897
|
-
const segment1 = event.first.segment;
|
|
1898
|
-
assert.equal(segment1.text, "lazy ");
|
|
1899
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
|
|
1900
|
-
remoteUserId);
|
|
1901
|
-
client.applyMsg(remoteInsertMessage);
|
|
1902
|
-
assert(!event.isLocal);
|
|
1903
|
-
assert.equal(event.first.position, insertPos - (deleteRangeEnd - deleteRangeStart));
|
|
1904
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length - (deleteRangeEnd - deleteRangeStart));
|
|
1905
|
-
assert.equal(event.ranges.length, 1);
|
|
1906
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1907
|
-
const segment2 = event.first.segment;
|
|
1908
|
-
assert.equal(segment2.text, insertText);
|
|
1909
|
-
client.applyMsg(localRemoveMessage);
|
|
1910
|
-
assert.equal(client.getText(), output);
|
|
1911
|
-
});
|
|
1912
|
-
it("insertPos is deleteRangeStart, insertLocal deleteRemote, local before remote", () => {
|
|
1913
|
-
const insertPos = 10; // before "fox"
|
|
1914
|
-
const insertText = "black wolf ";
|
|
1915
|
-
const deleteRangeStart = 4; // "brown fox "
|
|
1916
|
-
const deleteRangeEnd = 14;
|
|
1917
|
-
const output = "The black wolf jumps over the lazy dog";
|
|
1918
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1919
|
-
let event;
|
|
1920
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1921
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1922
|
-
});
|
|
1923
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 1, currentSeqNumber);
|
|
1924
|
-
client.applyMsg(localInsertMessage);
|
|
1925
|
-
assert(event);
|
|
1926
|
-
assert(event.isLocal);
|
|
1927
|
-
assert.equal(event.first.position, insertPos);
|
|
1928
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1929
|
-
assert.equal(event.ranges.length, 1);
|
|
1930
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1931
|
-
const segment1 = event.first.segment;
|
|
1932
|
-
assert.equal(segment1.text, insertText);
|
|
1933
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber, // refseq
|
|
1934
|
-
remoteUserId);
|
|
1935
|
-
client.applyMsg(remoteRemoveMessage);
|
|
1936
|
-
const expectedRangeStart1 = deleteRangeStart;
|
|
1937
|
-
const expectedRangeEnd1 = expectedRangeStart1 + "brown ".length;
|
|
1938
|
-
// merge tree internal: "brown " is deleted and then end is calculated
|
|
1939
|
-
const expectedRangeStart2 = deleteRangeStart + insertText.length;
|
|
1940
|
-
const expectedRangeEnd2 = expectedRangeStart2 + "fox ".length;
|
|
1941
|
-
assert(!event.isLocal);
|
|
1942
|
-
assert.equal(event.first.position, expectedRangeStart1);
|
|
1943
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, expectedRangeEnd2);
|
|
1944
|
-
assert.equal(event.ranges.length, 2);
|
|
1945
|
-
assert.equal(event.first.segment.cachedLength, expectedRangeEnd1 - expectedRangeStart1);
|
|
1946
|
-
const segment2 = event.first.segment;
|
|
1947
|
-
assert.equal(segment2.text, "brown ");
|
|
1948
|
-
assert.equal(event.ranges[1].position, expectedRangeStart2);
|
|
1949
|
-
assert.equal(event.ranges[1].segment.cachedLength, expectedRangeEnd2 - expectedRangeStart2);
|
|
1950
|
-
const segment3 = event.ranges[1].segment;
|
|
1951
|
-
assert.equal(segment3.text, "fox ");
|
|
1952
|
-
assert.equal(client.getText(), output);
|
|
1953
|
-
});
|
|
1954
|
-
it("insertPos is deleteRangeStart, insertLocal deleteRemote, remote before local", () => {
|
|
1955
|
-
const insertPos = 10; // before "fox"
|
|
1956
|
-
const insertText = "black wolf ";
|
|
1957
|
-
const deleteRangeStart = 4; // "brown fox "
|
|
1958
|
-
const deleteRangeEnd = 14;
|
|
1959
|
-
const output = "The black wolf jumps over the lazy dog";
|
|
1960
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
1961
|
-
let event;
|
|
1962
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
1963
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
1964
|
-
});
|
|
1965
|
-
const localInsertMessage = client.makeOpMessage(client.insertTextLocal(insertPos, insertText), currentSeqNumber + 2, currentSeqNumber);
|
|
1966
|
-
assert(event);
|
|
1967
|
-
assert(event.isLocal);
|
|
1968
|
-
assert.equal(event.first.position, insertPos);
|
|
1969
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertPos + insertText.length);
|
|
1970
|
-
assert.equal(event.ranges.length, 1);
|
|
1971
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
1972
|
-
const segment1 = event.first.segment;
|
|
1973
|
-
assert.equal(segment1.text, insertText);
|
|
1974
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber, // refseq
|
|
1975
|
-
remoteUserId);
|
|
1976
|
-
client.applyMsg(remoteRemoveMessage);
|
|
1977
|
-
const expectedRangeStart1 = deleteRangeStart;
|
|
1978
|
-
const expectedRangeEnd1 = expectedRangeStart1 + "brown ".length;
|
|
1979
|
-
// merge tree internal: "brown " is deleted and then end is calculated
|
|
1980
|
-
const expectedRangeStart2 = deleteRangeStart + insertText.length;
|
|
1981
|
-
const expectedRangeEnd2 = expectedRangeStart2 + "fox ".length;
|
|
1982
|
-
assert(!event.isLocal);
|
|
1983
|
-
assert.equal(event.first.position, expectedRangeStart1);
|
|
1984
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, expectedRangeEnd2);
|
|
1985
|
-
assert.equal(event.ranges.length, 2);
|
|
1986
|
-
assert.equal(event.first.segment.cachedLength, expectedRangeEnd1 - expectedRangeStart1);
|
|
1987
|
-
const segment2 = event.first.segment;
|
|
1988
|
-
assert.equal(segment2.text, "brown ");
|
|
1989
|
-
assert.equal(event.ranges[1].position, expectedRangeStart2);
|
|
1990
|
-
assert.equal(event.ranges[1].segment.cachedLength, expectedRangeEnd2 - expectedRangeStart2);
|
|
1991
|
-
const segment3 = event.ranges[1].segment;
|
|
1992
|
-
assert.equal(segment3.text, "fox ");
|
|
1993
|
-
client.applyMsg(localInsertMessage);
|
|
1994
|
-
assert.equal(client.getText(), output);
|
|
1995
|
-
});
|
|
1996
|
-
it("insertPos is deleteRangeStart, deleteLocal insertRemote, local before remote", () => {
|
|
1997
|
-
const insertPos = 10; // before "fox"
|
|
1998
|
-
const insertText = "black wolf ";
|
|
1999
|
-
const deleteRangeStart = 4; // "brown fox "
|
|
2000
|
-
const deleteRangeEnd = 14;
|
|
2001
|
-
const output = "The black wolf jumps over the lazy dog";
|
|
2002
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
2003
|
-
let event;
|
|
2004
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
2005
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
2006
|
-
});
|
|
2007
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 1, currentSeqNumber);
|
|
2008
|
-
client.applyMsg(localRemoveMessage);
|
|
2009
|
-
assert(event);
|
|
2010
|
-
assert(event.isLocal);
|
|
2011
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
2012
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
2013
|
-
assert.equal(event.ranges.length, 1);
|
|
2014
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
2015
|
-
const segment1 = event.first.segment;
|
|
2016
|
-
assert.equal(segment1.text, "brown fox ");
|
|
2017
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 2, currentSeqNumber, // refseqnum
|
|
2018
|
-
remoteUserId);
|
|
2019
|
-
client.applyMsg(remoteInsertMessage);
|
|
2020
|
-
assert(!event.isLocal);
|
|
2021
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
2022
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeStart + insertText.length);
|
|
2023
|
-
assert.equal(event.ranges.length, 1);
|
|
2024
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
2025
|
-
const segment2 = event.first.segment;
|
|
2026
|
-
assert.equal(segment2.text, insertText);
|
|
2027
|
-
assert.equal(client.getText(), output);
|
|
2028
|
-
});
|
|
2029
|
-
it("insertPos is deleteRangeStart, deleteLocal insertRemote, remote before local", () => {
|
|
2030
|
-
const insertPos = 10; // before "fox"
|
|
2031
|
-
const insertText = "black wolf ";
|
|
2032
|
-
const deleteRangeStart = 4; // "brown fox "
|
|
2033
|
-
const deleteRangeEnd = 14;
|
|
2034
|
-
const output = "The black wolf jumps over the lazy dog";
|
|
2035
|
-
const currentSeqNumber = client.mergeTree.collabWindow.currentSeq;
|
|
2036
|
-
let event;
|
|
2037
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
2038
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
2039
|
-
});
|
|
2040
|
-
const localRemoveMessage = client.makeOpMessage(client.removeRangeLocal(deleteRangeStart, deleteRangeEnd), currentSeqNumber + 2, currentSeqNumber);
|
|
2041
|
-
assert(event);
|
|
2042
|
-
assert(event.isLocal);
|
|
2043
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
2044
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeEnd);
|
|
2045
|
-
assert.equal(event.ranges.length, 1);
|
|
2046
|
-
assert.equal(event.first.segment.cachedLength, deleteRangeEnd - deleteRangeStart);
|
|
2047
|
-
const segment1 = event.first.segment;
|
|
2048
|
-
assert.equal(segment1.text, "brown fox ");
|
|
2049
|
-
const remoteInsertMessage = client.makeOpMessage(createInsertSegmentOp(insertPos, new TextSegment(insertText)), currentSeqNumber + 1, currentSeqNumber, // refseqnum
|
|
2050
|
-
remoteUserId);
|
|
2051
|
-
client.applyMsg(remoteInsertMessage);
|
|
2052
|
-
assert(!event.isLocal);
|
|
2053
|
-
assert.equal(event.first.position, deleteRangeStart);
|
|
2054
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, deleteRangeStart + insertText.length);
|
|
2055
|
-
assert.equal(event.ranges.length, 1);
|
|
2056
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
2057
|
-
const segment2 = event.first.segment;
|
|
2058
|
-
assert.equal(segment2.text, insertText);
|
|
2059
|
-
client.applyMsg(localRemoveMessage);
|
|
2060
|
-
assert.equal(client.getText(), output);
|
|
2061
|
-
});
|
|
2062
|
-
});
|
|
2063
|
-
});
|
|
2064
|
-
describe("SequenceDeltaEvent", () => {
|
|
2065
|
-
const localUserLongId = "localUser";
|
|
2066
|
-
let client;
|
|
2067
|
-
beforeEach(() => {
|
|
2068
|
-
client = new TestClient();
|
|
2069
|
-
client.startOrUpdateCollaboration(localUserLongId);
|
|
2070
|
-
});
|
|
2071
|
-
describe(".ranges", () => {
|
|
2072
|
-
it("single segment", () => {
|
|
2073
|
-
const insertText = "text";
|
|
2074
|
-
let deltaArgs;
|
|
2075
|
-
client.on("delta", (opArgs, delta) => {
|
|
2076
|
-
deltaArgs = delta;
|
|
2077
|
-
});
|
|
2078
|
-
const op = client.insertTextLocal(0, insertText);
|
|
2079
|
-
assert(deltaArgs);
|
|
2080
|
-
assert.equal(deltaArgs.deltaSegments.length, 1);
|
|
2081
|
-
assert(op);
|
|
2082
|
-
const event = new SequenceDeltaEvent({ op }, deltaArgs, client);
|
|
2083
|
-
assert(event.isLocal);
|
|
2084
|
-
assert.equal(event.ranges.length, 1);
|
|
2085
|
-
assert.equal(event.first.position, 0);
|
|
2086
|
-
assert.equal(event.first.segment.cachedLength, insertText.length);
|
|
2087
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, insertText.length);
|
|
2088
|
-
});
|
|
2089
|
-
it("multiple continuous segments", () => {
|
|
2090
|
-
const insertText = "text";
|
|
2091
|
-
const segmentCount = 5;
|
|
2092
|
-
for (let i = 0; i < segmentCount + 2; i = i + 1) {
|
|
2093
|
-
client.insertTextLocal(0, insertText);
|
|
2094
|
-
}
|
|
2095
|
-
let deltaArgs;
|
|
2096
|
-
client.on("delta", (opArgs, delta) => {
|
|
2097
|
-
deltaArgs = delta;
|
|
2098
|
-
});
|
|
2099
|
-
const op = client.annotateRangeLocal(insertText.length, client.getLength() - insertText.length, {
|
|
2100
|
-
foo: "bar",
|
|
2101
|
-
});
|
|
2102
|
-
assert(deltaArgs);
|
|
2103
|
-
assert.equal(deltaArgs.deltaSegments.length, segmentCount);
|
|
2104
|
-
assert(op);
|
|
2105
|
-
const event = new SequenceDeltaEvent({ op }, deltaArgs, client);
|
|
2106
|
-
assert(event.isLocal);
|
|
2107
|
-
assert.equal(event.ranges.length, segmentCount);
|
|
2108
|
-
assert.equal(event.first.position, insertText.length);
|
|
2109
|
-
for (let i = 0; i < segmentCount; i = i + 1) {
|
|
2110
|
-
assert.equal(event.ranges[i].position, (i + 1) * insertText.length);
|
|
2111
|
-
assert.equal(event.ranges[i].segment.cachedLength, insertText.length);
|
|
2112
|
-
assert.equal(event.ranges[i].propertyDeltas.foo, null);
|
|
2113
|
-
}
|
|
2114
|
-
assert.equal(event.last.position + event.last.segment.cachedLength, client.getLength() - insertText.length);
|
|
2115
|
-
});
|
|
2116
|
-
it("multiple noncontinuous segments", () => {
|
|
2117
|
-
const textCount = 4;
|
|
2118
|
-
const segmentCount = 5;
|
|
2119
|
-
for (let i = 0; i < segmentCount; i = i + 1) {
|
|
2120
|
-
const op = client.insertTextLocal(0, `${i}`.repeat(textCount));
|
|
2121
|
-
client.applyMsg(client.makeOpMessage(op, client.mergeTree.collabWindow.currentSeq + 1));
|
|
2122
|
-
}
|
|
2123
|
-
const remoteRemoveMessage = client.makeOpMessage(createRemoveRangeOp(0, client.getLength()), client.mergeTree.collabWindow.currentSeq + 1);
|
|
2124
|
-
remoteRemoveMessage.clientSequenceNumber = 0;
|
|
2125
|
-
remoteRemoveMessage.clientId = "remote user";
|
|
2126
|
-
for (let i = 0; i < segmentCount; i = i + 1) {
|
|
2127
|
-
client.insertTextLocal(i * 2 * textCount, "b".repeat(textCount));
|
|
2128
|
-
}
|
|
2129
|
-
let event;
|
|
2130
|
-
client.on("delta", (clientArgs, mergeTreeArgs) => {
|
|
2131
|
-
event = new SequenceDeltaEvent(clientArgs, mergeTreeArgs, client);
|
|
2132
|
-
});
|
|
2133
|
-
client.applyMsg(remoteRemoveMessage);
|
|
2134
|
-
assert(event);
|
|
2135
|
-
assert(!event.isLocal);
|
|
2136
|
-
assert.equal(event.ranges.length, segmentCount);
|
|
2137
|
-
for (let i = 0; i < segmentCount; i = i + 1) {
|
|
2138
|
-
assert.equal(event.ranges[i].position, (i + 1) * textCount);
|
|
2139
|
-
assert.equal(event.ranges[i].segment.cachedLength, textCount);
|
|
2140
|
-
}
|
|
2141
|
-
});
|
|
2142
|
-
});
|
|
2143
|
-
});
|
|
2144
|
-
//# sourceMappingURL=sequenceDeltaEvent.spec.js.map
|