@fluidframework/merge-tree 2.31.0 → 2.32.0
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 +4 -0
- package/dist/client.d.ts +7 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +153 -44
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/mergeTree.d.ts +17 -5
- package/dist/mergeTree.d.ts.map +1 -1
- package/dist/mergeTree.js +188 -79
- package/dist/mergeTree.js.map +1 -1
- package/dist/mergeTreeNodes.d.ts +16 -18
- package/dist/mergeTreeNodes.d.ts.map +1 -1
- package/dist/mergeTreeNodes.js +6 -0
- package/dist/mergeTreeNodes.js.map +1 -1
- package/dist/perspective.d.ts +9 -0
- package/dist/perspective.d.ts.map +1 -1
- package/dist/perspective.js +14 -1
- package/dist/perspective.js.map +1 -1
- package/dist/segmentInfos.d.ts +32 -4
- package/dist/segmentInfos.d.ts.map +1 -1
- package/dist/segmentInfos.js +3 -1
- package/dist/segmentInfos.js.map +1 -1
- package/dist/sortedSegmentSet.d.ts +1 -0
- package/dist/sortedSegmentSet.d.ts.map +1 -1
- package/dist/sortedSegmentSet.js +3 -0
- package/dist/sortedSegmentSet.js.map +1 -1
- package/dist/test/beastTest.spec.js +5 -5
- package/dist/test/beastTest.spec.js.map +1 -1
- package/dist/test/client.localReference.spec.js +3 -3
- package/dist/test/client.localReference.spec.js.map +1 -1
- package/dist/test/client.rollback.spec.js +17 -0
- package/dist/test/client.rollback.spec.js.map +1 -1
- package/dist/test/clientTestHelper.d.ts +100 -0
- package/dist/test/clientTestHelper.d.ts.map +1 -0
- package/dist/test/clientTestHelper.js +196 -0
- package/dist/test/clientTestHelper.js.map +1 -0
- package/dist/test/mergeTree.annotate.spec.js +12 -12
- package/dist/test/mergeTree.annotate.spec.js.map +1 -1
- package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +1 -1
- package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -1
- package/dist/test/obliterate.concurrent.spec.js +93 -90
- package/dist/test/obliterate.concurrent.spec.js.map +1 -1
- package/dist/test/obliterate.deltaCallback.spec.js +121 -116
- package/dist/test/obliterate.deltaCallback.spec.js.map +1 -1
- package/dist/test/obliterate.rangeExpansion.spec.js +29 -79
- package/dist/test/obliterate.rangeExpansion.spec.js.map +1 -1
- package/dist/test/obliterate.reconnect.spec.js +235 -58
- package/dist/test/obliterate.reconnect.spec.js.map +1 -1
- package/dist/test/testClient.js +1 -1
- package/dist/test/testClient.js.map +1 -1
- package/dist/test/testUtils.d.ts +13 -0
- package/dist/test/testUtils.d.ts.map +1 -1
- package/dist/test/testUtils.js +22 -1
- package/dist/test/testUtils.js.map +1 -1
- package/lib/client.d.ts +7 -1
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +155 -46
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/mergeTree.d.ts +17 -5
- package/lib/mergeTree.d.ts.map +1 -1
- package/lib/mergeTree.js +192 -83
- package/lib/mergeTree.js.map +1 -1
- package/lib/mergeTreeNodes.d.ts +16 -18
- package/lib/mergeTreeNodes.d.ts.map +1 -1
- package/lib/mergeTreeNodes.js +7 -1
- package/lib/mergeTreeNodes.js.map +1 -1
- package/lib/perspective.d.ts +9 -0
- package/lib/perspective.d.ts.map +1 -1
- package/lib/perspective.js +12 -0
- package/lib/perspective.js.map +1 -1
- package/lib/segmentInfos.d.ts +32 -4
- package/lib/segmentInfos.d.ts.map +1 -1
- package/lib/segmentInfos.js +2 -1
- package/lib/segmentInfos.js.map +1 -1
- package/lib/sortedSegmentSet.d.ts +1 -0
- package/lib/sortedSegmentSet.d.ts.map +1 -1
- package/lib/sortedSegmentSet.js +3 -0
- package/lib/sortedSegmentSet.js.map +1 -1
- package/lib/test/beastTest.spec.js +5 -5
- package/lib/test/beastTest.spec.js.map +1 -1
- package/lib/test/client.localReference.spec.js +3 -3
- package/lib/test/client.localReference.spec.js.map +1 -1
- package/lib/test/client.rollback.spec.js +18 -1
- package/lib/test/client.rollback.spec.js.map +1 -1
- package/lib/test/clientTestHelper.d.ts +100 -0
- package/lib/test/clientTestHelper.d.ts.map +1 -0
- package/lib/test/clientTestHelper.js +192 -0
- package/lib/test/clientTestHelper.js.map +1 -0
- package/lib/test/mergeTree.annotate.spec.js +12 -12
- package/lib/test/mergeTree.annotate.spec.js.map +1 -1
- package/lib/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +1 -1
- package/lib/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -1
- package/lib/test/obliterate.concurrent.spec.js +93 -90
- package/lib/test/obliterate.concurrent.spec.js.map +1 -1
- package/lib/test/obliterate.deltaCallback.spec.js +121 -116
- package/lib/test/obliterate.deltaCallback.spec.js.map +1 -1
- package/lib/test/obliterate.rangeExpansion.spec.js +1 -51
- package/lib/test/obliterate.rangeExpansion.spec.js.map +1 -1
- package/lib/test/obliterate.reconnect.spec.js +236 -59
- package/lib/test/obliterate.reconnect.spec.js.map +1 -1
- package/lib/test/testClient.js +1 -1
- package/lib/test/testClient.js.map +1 -1
- package/lib/test/testUtils.d.ts +13 -0
- package/lib/test/testUtils.d.ts.map +1 -1
- package/lib/test/testUtils.js +20 -0
- package/lib/test/testUtils.js.map +1 -1
- package/package.json +19 -18
- package/src/client.ts +286 -55
- package/src/index.ts +1 -1
- package/src/mergeTree.ts +265 -98
- package/src/mergeTreeNodes.ts +24 -18
- package/src/perspective.ts +21 -0
- package/src/segmentInfos.ts +48 -6
- package/src/sortedSegmentSet.ts +4 -0
- package/dist/test/partialSyncHelper.d.ts +0 -42
- package/dist/test/partialSyncHelper.d.ts.map +0 -1
- package/dist/test/partialSyncHelper.js +0 -96
- package/dist/test/partialSyncHelper.js.map +0 -1
- package/dist/test/reconnectHelper.d.ts +0 -50
- package/dist/test/reconnectHelper.d.ts.map +0 -1
- package/dist/test/reconnectHelper.js +0 -106
- package/dist/test/reconnectHelper.js.map +0 -1
- package/lib/test/partialSyncHelper.d.ts +0 -42
- package/lib/test/partialSyncHelper.d.ts.map +0 -1
- package/lib/test/partialSyncHelper.js +0 -92
- package/lib/test/partialSyncHelper.js.map +0 -1
- package/lib/test/reconnectHelper.d.ts +0 -50
- package/lib/test/reconnectHelper.d.ts.map +0 -1
- package/lib/test/reconnectHelper.js +0 -102
- package/lib/test/reconnectHelper.js.map +0 -1
|
@@ -3,11 +3,20 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
import { strict as assert } from "node:assert";
|
|
6
|
+
import { generatePairwiseOptions } from "@fluid-private/test-pairwise-generator";
|
|
6
7
|
import { MergeTree } from "../mergeTree.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import { Side } from "../sequencePlace.js";
|
|
9
|
+
import { ClientTestHelper } from "./clientTestHelper.js";
|
|
10
|
+
import { itCorrectlyObliterates, useStrictPartialLengthChecks } from "./testUtils.js";
|
|
11
|
+
for (const { incremental, mergeTreeEnableSidedObliterate } of generatePairwiseOptions({
|
|
12
|
+
incremental: [true, false],
|
|
13
|
+
mergeTreeEnableSidedObliterate: [
|
|
14
|
+
false,
|
|
15
|
+
// TODO:AB#31001: Enable this once sided obliterate supports reconnect.
|
|
16
|
+
// true,
|
|
17
|
+
],
|
|
18
|
+
})) {
|
|
19
|
+
describe(`obliterate partial lengths incremental = ${incremental} enableSidedObliterate = ${mergeTreeEnableSidedObliterate}`, () => {
|
|
11
20
|
useStrictPartialLengthChecks();
|
|
12
21
|
beforeEach(() => {
|
|
13
22
|
MergeTree.options.incrementalUpdate = incremental;
|
|
@@ -16,68 +25,60 @@ for (const incremental of [true, false]) {
|
|
|
16
25
|
MergeTree.options.incrementalUpdate = true;
|
|
17
26
|
});
|
|
18
27
|
it("obliterate does not expand during rebase", () => {
|
|
19
|
-
const helper = new
|
|
28
|
+
const helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });
|
|
20
29
|
helper.insertText("B", 0, "ABCD");
|
|
21
30
|
helper.processAllOps();
|
|
22
31
|
helper.removeRange("B", 0, 3);
|
|
23
|
-
helper.disconnect(
|
|
24
|
-
|
|
25
|
-
helper.reconnect(
|
|
26
|
-
helper.submitDisconnectedOp("C", cOp);
|
|
32
|
+
helper.disconnect("C");
|
|
33
|
+
helper.obliterateRange("C", 0, 1);
|
|
34
|
+
helper.reconnect("C");
|
|
27
35
|
helper.processAllOps();
|
|
28
36
|
assert.equal(helper.clients.A.getText(), "D");
|
|
29
37
|
helper.logger.validate();
|
|
30
38
|
});
|
|
31
39
|
it("does delete reconnected insert into obliterate range if insert is rebased", () => {
|
|
32
|
-
const helper = new
|
|
40
|
+
const helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });
|
|
33
41
|
helper.insertText("B", 0, "ABCD");
|
|
34
42
|
helper.processAllOps();
|
|
35
43
|
helper.obliterateRange("B", 0, 3);
|
|
36
|
-
helper.disconnect(
|
|
37
|
-
|
|
38
|
-
helper.reconnect(
|
|
39
|
-
helper.submitDisconnectedOp("C", cOp);
|
|
44
|
+
helper.disconnect("C");
|
|
45
|
+
helper.insertText("C", 2, "aaa");
|
|
46
|
+
helper.reconnect("C");
|
|
40
47
|
helper.processAllOps();
|
|
41
48
|
assert.equal(helper.clients.A.getText(), "D");
|
|
42
49
|
assert.equal(helper.clients.C.getText(), "D");
|
|
43
50
|
helper.logger.validate();
|
|
44
51
|
});
|
|
45
52
|
it("deletes reconnected insert into obliterate range when entire string deleted if rebased", () => {
|
|
46
|
-
const helper = new
|
|
53
|
+
const helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });
|
|
47
54
|
helper.insertText("B", 0, "ABCD");
|
|
48
55
|
helper.processAllOps();
|
|
49
56
|
helper.obliterateRange("B", 0, 4);
|
|
50
|
-
helper.disconnect(
|
|
51
|
-
|
|
52
|
-
helper.reconnect(
|
|
53
|
-
helper.submitDisconnectedOp("C", cOp);
|
|
57
|
+
helper.disconnect("C");
|
|
58
|
+
helper.insertText("C", 2, "aaa");
|
|
59
|
+
helper.reconnect("C");
|
|
54
60
|
helper.processAllOps();
|
|
55
61
|
assert.equal(helper.clients.A.getText(), "");
|
|
56
62
|
assert.equal(helper.clients.C.getText(), "");
|
|
57
63
|
helper.logger.validate();
|
|
58
64
|
});
|
|
59
65
|
it("obliterates local segment while disconnected", () => {
|
|
60
|
-
const helper = new
|
|
66
|
+
const helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });
|
|
61
67
|
// [C]-D-(E)-F-H-G-B-A
|
|
62
68
|
helper.insertText("B", 0, "A");
|
|
63
|
-
helper.disconnect(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
helper.reconnect(
|
|
70
|
-
helper.submitDisconnectedOp("C", op0);
|
|
71
|
-
helper.submitDisconnectedOp("C", op1);
|
|
72
|
-
helper.submitDisconnectedOp("C", op2);
|
|
73
|
-
helper.submitDisconnectedOp("C", op3);
|
|
74
|
-
helper.submitDisconnectedOp("C", op4);
|
|
69
|
+
helper.disconnect("C");
|
|
70
|
+
helper.insertText("C", 0, "B");
|
|
71
|
+
helper.insertText("C", 0, "CDEFG");
|
|
72
|
+
helper.removeRange("C", 0, 1);
|
|
73
|
+
helper.obliterateRange("C", 1, 2);
|
|
74
|
+
helper.insertText("C", 2, "H");
|
|
75
|
+
helper.reconnect("C");
|
|
75
76
|
helper.processAllOps();
|
|
76
77
|
assert.equal(helper.clients.A.getText(), "DFHGBA");
|
|
77
78
|
helper.logger.validate();
|
|
78
79
|
});
|
|
79
80
|
it("deletes concurrently inserted segment between separated group ops", () => {
|
|
80
|
-
const helper = new
|
|
81
|
+
const helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });
|
|
81
82
|
// B-A
|
|
82
83
|
// (B-C-A)
|
|
83
84
|
helper.insertText("A", 0, "A");
|
|
@@ -85,39 +86,37 @@ for (const incremental of [true, false]) {
|
|
|
85
86
|
helper.processAllOps();
|
|
86
87
|
helper.logger.validate();
|
|
87
88
|
helper.insertText("A", 1, "C");
|
|
88
|
-
helper.disconnect(
|
|
89
|
-
|
|
90
|
-
helper.reconnect(
|
|
91
|
-
helper.submitDisconnectedOp("B", op);
|
|
89
|
+
helper.disconnect("B");
|
|
90
|
+
helper.obliterateRange("B", 0, 2);
|
|
91
|
+
helper.reconnect("B");
|
|
92
92
|
helper.processAllOps();
|
|
93
93
|
assert.equal(helper.clients.A.getText(), "");
|
|
94
94
|
helper.logger.validate();
|
|
95
95
|
});
|
|
96
96
|
it("removes correct number of pending segments", () => {
|
|
97
|
-
const helper = new
|
|
97
|
+
const helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });
|
|
98
98
|
// (BC)-[A]
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
helper.
|
|
103
|
-
helper.
|
|
104
|
-
helper.submitDisconnectedOp("A", op2);
|
|
99
|
+
helper.disconnect("A");
|
|
100
|
+
helper.insertText("A", 0, "A");
|
|
101
|
+
helper.insertText("A", 1, "BC");
|
|
102
|
+
helper.obliterateRange("A", 0, 2);
|
|
103
|
+
helper.reconnect("A");
|
|
105
104
|
helper.removeRange("A", 0, 1);
|
|
106
105
|
helper.processAllOps();
|
|
107
106
|
assert.equal(helper.clients.A.getText(), "");
|
|
108
107
|
helper.logger.validate();
|
|
109
108
|
});
|
|
110
109
|
it("doesn't do obliterate ack traversal when starting segment has been acked", () => {
|
|
111
|
-
const helper = new
|
|
110
|
+
const helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });
|
|
112
111
|
// AB
|
|
113
112
|
// (E)-[F]-(G-D-(C-A)-B)
|
|
114
113
|
helper.insertText("B", 0, "AB");
|
|
115
114
|
helper.processAllOps();
|
|
116
115
|
helper.logger.validate();
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
helper.
|
|
120
|
-
helper.
|
|
116
|
+
helper.disconnect("A");
|
|
117
|
+
helper.insertText("A", 0, "C");
|
|
118
|
+
helper.obliterateRange("A", 0, 2);
|
|
119
|
+
helper.reconnect("A");
|
|
121
120
|
helper.insertText("B", 0, "D");
|
|
122
121
|
helper.insertText("A", 0, "EFG");
|
|
123
122
|
helper.obliterateRange("A", 0, 1);
|
|
@@ -128,32 +127,210 @@ for (const incremental of [true, false]) {
|
|
|
128
127
|
helper.logger.validate();
|
|
129
128
|
});
|
|
130
129
|
it("does not delete reconnected insert at start of obliterate range if rebased", () => {
|
|
131
|
-
const helper = new
|
|
130
|
+
const helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });
|
|
132
131
|
helper.insertText("B", 0, "ABCD");
|
|
133
132
|
helper.processAllOps();
|
|
134
133
|
helper.obliterateRange("B", 0, 3);
|
|
135
|
-
helper.disconnect(
|
|
136
|
-
|
|
137
|
-
helper.reconnect(
|
|
138
|
-
helper.submitDisconnectedOp("C", cOp);
|
|
134
|
+
helper.disconnect("C");
|
|
135
|
+
helper.insertText("C", 0, "aaa");
|
|
136
|
+
helper.reconnect("C");
|
|
139
137
|
helper.processAllOps();
|
|
140
138
|
assert.equal(helper.clients.A.getText(), "aaaD");
|
|
141
139
|
assert.equal(helper.clients.C.getText(), "aaaD");
|
|
142
140
|
helper.logger.validate();
|
|
143
141
|
});
|
|
144
142
|
it("does not delete reconnected insert at end of obliterate range", () => {
|
|
145
|
-
const helper = new
|
|
143
|
+
const helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });
|
|
146
144
|
helper.insertText("B", 0, "ABCD");
|
|
147
145
|
helper.processAllOps();
|
|
148
146
|
helper.obliterateRange("B", 0, 3);
|
|
149
|
-
helper.disconnect(
|
|
150
|
-
|
|
151
|
-
helper.reconnect(
|
|
152
|
-
helper.submitDisconnectedOp("C", cOp);
|
|
147
|
+
helper.disconnect("C");
|
|
148
|
+
helper.insertText("C", 3, "aaa");
|
|
149
|
+
helper.reconnect("C");
|
|
153
150
|
helper.processAllOps();
|
|
154
151
|
assert.equal(helper.clients.A.getText(), "aaaD");
|
|
155
152
|
helper.logger.validate();
|
|
156
153
|
});
|
|
157
154
|
});
|
|
158
155
|
}
|
|
156
|
+
describe("sided obliterate reconnect", () => {
|
|
157
|
+
itCorrectlyObliterates({
|
|
158
|
+
title: "add text, disconnect, obliterate, reconnect, insert adjacent to obliterated range",
|
|
159
|
+
action: (helper) => {
|
|
160
|
+
helper.insertText("A", 0, "hello world");
|
|
161
|
+
helper.processAllOps();
|
|
162
|
+
helper.disconnect("C");
|
|
163
|
+
helper.obliterateRange("C", { pos: 1, side: Side.After }, { pos: 4, side: Side.After });
|
|
164
|
+
// inserting adjacent to the obliterated range start
|
|
165
|
+
helper.reconnect("C");
|
|
166
|
+
helper.insertText("A", 2, "123");
|
|
167
|
+
},
|
|
168
|
+
expectedText: "he world",
|
|
169
|
+
});
|
|
170
|
+
itCorrectlyObliterates({
|
|
171
|
+
title: "add text, disconnect, obliterate, insert adjacent to obliterated range, reconnect",
|
|
172
|
+
action: (helper) => {
|
|
173
|
+
helper.insertText("A", 0, "hello world");
|
|
174
|
+
helper.processAllOps();
|
|
175
|
+
helper.disconnect("C");
|
|
176
|
+
helper.obliterateRange("C", { pos: 1, side: Side.After }, { pos: 4, side: Side.After });
|
|
177
|
+
// inserting adjacent to the obliterated range start
|
|
178
|
+
helper.insertText("A", 2, "123");
|
|
179
|
+
helper.reconnect("C");
|
|
180
|
+
},
|
|
181
|
+
expectedText: "he world",
|
|
182
|
+
});
|
|
183
|
+
describe("obliterate rebasing over", () => {
|
|
184
|
+
for (const { removalType, getRemoveMethod } of [
|
|
185
|
+
{
|
|
186
|
+
removalType: "remove",
|
|
187
|
+
getRemoveMethod: (helper) => helper.removeRange.bind(helper),
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
removalType: "obliterate",
|
|
191
|
+
getRemoveMethod: (helper) => helper.obliterateRange.bind(helper),
|
|
192
|
+
},
|
|
193
|
+
]) {
|
|
194
|
+
itCorrectlyObliterates({
|
|
195
|
+
title: `${removalType} overlapping obliterate start`,
|
|
196
|
+
action: (helper) => {
|
|
197
|
+
helper.insertText("A", 0, "0123456789");
|
|
198
|
+
helper.processAllOps();
|
|
199
|
+
helper.disconnect("B");
|
|
200
|
+
helper.obliterateRange("B", { pos: 1, side: Side.Before }, { pos: 8, side: Side.After });
|
|
201
|
+
helper.insertText("A", 5, "should be obliterated");
|
|
202
|
+
getRemoveMethod(helper)("A", 0, 2);
|
|
203
|
+
helper.reconnect("B");
|
|
204
|
+
},
|
|
205
|
+
expectedText: "9",
|
|
206
|
+
});
|
|
207
|
+
itCorrectlyObliterates({
|
|
208
|
+
title: `${removalType} overlapping obliterate middle`,
|
|
209
|
+
action: (helper) => {
|
|
210
|
+
helper.insertText("A", 0, "0123456789");
|
|
211
|
+
helper.processAllOps();
|
|
212
|
+
helper.disconnect("B");
|
|
213
|
+
helper.obliterateRange("B", { pos: 1, side: Side.Before }, { pos: 8, side: Side.After });
|
|
214
|
+
getRemoveMethod(helper)("A", 3, 4);
|
|
215
|
+
helper.insertText("A", 5, "should be obliterated");
|
|
216
|
+
helper.reconnect("B");
|
|
217
|
+
},
|
|
218
|
+
expectedText: "09",
|
|
219
|
+
});
|
|
220
|
+
itCorrectlyObliterates({
|
|
221
|
+
title: `${removalType} overlapping obliterate end`,
|
|
222
|
+
action: (helper) => {
|
|
223
|
+
helper.insertText("A", 0, "0123456789");
|
|
224
|
+
helper.processAllOps();
|
|
225
|
+
helper.disconnect("B");
|
|
226
|
+
helper.obliterateRange("B", { pos: 1, side: Side.Before }, { pos: 8, side: Side.After });
|
|
227
|
+
getRemoveMethod(helper)("A", 8, 10);
|
|
228
|
+
helper.insertText("A", 5, "should be obliterated");
|
|
229
|
+
helper.reconnect("B");
|
|
230
|
+
},
|
|
231
|
+
expectedText: "0",
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
// This test and the analogous endpoint test below provide some rationale for the policy of tending to shrink obliterates
|
|
236
|
+
// inward upon reconnect in the case that regions near their endpoints were removed between the original submission and resubmission.
|
|
237
|
+
itCorrectlyObliterates({
|
|
238
|
+
title: "obliterate shrinks start point to best possible option",
|
|
239
|
+
action: (helper) => {
|
|
240
|
+
helper.insertText("A", 0, "0123456789");
|
|
241
|
+
helper.processAllOps();
|
|
242
|
+
helper.disconnect("B");
|
|
243
|
+
helper.obliterateRange("B", { pos: 3, side: Side.After }, { pos: 8, side: Side.Before }); // 4 through 7
|
|
244
|
+
helper.insertText("A", 7, "inside the original obliterate");
|
|
245
|
+
helper.removeRange("C", 1, 5); // 1234
|
|
246
|
+
helper.advanceClients("B");
|
|
247
|
+
// B recognizes an observer client at this seq will have '056inside the original obliterate789' and B's obliterate should additionally
|
|
248
|
+
// remove '5inside the original obliterate67'.
|
|
249
|
+
// It reconnects at this point and has a choice: it can either specify the startpoint of the obliterate as 'after the 0 character'
|
|
250
|
+
// (preserving the original side) or 'before the 5 character' (which will make its start endpoint no longer "sticky" like
|
|
251
|
+
// the original one). Seeing as the original startpoint has actually already been removed, we should choose the latter.
|
|
252
|
+
helper.reconnect("B");
|
|
253
|
+
// The possibility of another client doing something like this is additional justification for this policy:
|
|
254
|
+
// (point being that B will see this segment as clearly after the "0" character since it was inserted before the 3 in the original string)
|
|
255
|
+
helper.insertText("A", 3, "outside the original obliterate but in danger of being in the new one");
|
|
256
|
+
},
|
|
257
|
+
expectedText: "0outside the original obliterate but in danger of being in the new one89",
|
|
258
|
+
});
|
|
259
|
+
itCorrectlyObliterates({
|
|
260
|
+
title: "obliterate shrinks end point to best possible option",
|
|
261
|
+
action: (helper) => {
|
|
262
|
+
helper.insertText("A", 0, "0123456789");
|
|
263
|
+
helper.processAllOps();
|
|
264
|
+
helper.disconnect("B");
|
|
265
|
+
helper.obliterateRange("B", { pos: 3, side: Side.After }, { pos: 8, side: Side.Before }); // 4 through 7
|
|
266
|
+
helper.insertText("A", 7, "inside the original obliterate");
|
|
267
|
+
helper.removeRange("C", 6, 9); // 678
|
|
268
|
+
helper.advanceClients("B");
|
|
269
|
+
// B recognizes an observer client at this seq will have '056inside the original obliterate789' and B's obliterate should additionally
|
|
270
|
+
// remove '5inside the original obliterate67'.
|
|
271
|
+
// It reconnects at this point and has a choice: it can either specify the startpoint of the obliterate as 'after the 0 character'
|
|
272
|
+
// (preserving the original side) or 'before the 5 character' (which will make its start endpoint no longer "sticky" like
|
|
273
|
+
// the original one). Seeing as the original startpoint has actually already been removed, we should choose the latter.
|
|
274
|
+
helper.reconnect("B");
|
|
275
|
+
// The possibility of another client doing something like this is additional justification for this policy:
|
|
276
|
+
// (point being that B will see this segment as clearly after the "0" character since it was inserted before the 3 in the original string)
|
|
277
|
+
helper.insertText("A", 9 + "inside the original obliterate".length, "outside the original obliterate but in danger of being in the new one");
|
|
278
|
+
},
|
|
279
|
+
expectedText: "0123outside the original obliterate but in danger of being in the new one9",
|
|
280
|
+
});
|
|
281
|
+
itCorrectlyObliterates({
|
|
282
|
+
title: "recomputes obliterate tiebreak winner",
|
|
283
|
+
action: (helper) => {
|
|
284
|
+
helper.insertText("A", 0, "ABCDEFGHIJKLMNOPQ");
|
|
285
|
+
helper.processAllOps();
|
|
286
|
+
helper.disconnect("B");
|
|
287
|
+
helper.obliterateRange("D", { pos: 0, side: Side.Before }, { pos: 6, side: Side.After }); // ABCDEFG
|
|
288
|
+
helper.obliterateRange("C", { pos: 2, side: Side.Before }, { pos: 8, side: Side.After }); // CDEFGHI
|
|
289
|
+
helper.obliterateRange("B", { pos: 3, side: Side.After }, { pos: 4, side: Side.After }); // D
|
|
290
|
+
// This insertion position by B is critically inside the range that B originally obliterated, but that will no longer be the case
|
|
291
|
+
// later on when B reconnects, since the region B wanted to obliterate will be gone (so there is no way to specify the same obliterate).
|
|
292
|
+
helper.insertText("B", 4, "should go away");
|
|
293
|
+
helper.processAllOps();
|
|
294
|
+
helper.removeRange("C", 0, 1); // J
|
|
295
|
+
helper.insertText("C", 0, "01234567"); // C now sees '01234567KLMNOPQ'
|
|
296
|
+
helper.processAllOps();
|
|
297
|
+
// B now needs to recognize that it no longer necessarily has 'last-write-win' privilege over its insertion
|
|
298
|
+
// in the event that the new insertion position was obliterated concurrently to the op it's about to (re)submit.
|
|
299
|
+
helper.reconnect("B");
|
|
300
|
+
// ... and indeed, in this case A has obliterated a region containing the "should go away" B inserted.
|
|
301
|
+
helper.obliterateRange("A", { pos: 7, side: Side.After }, { pos: 9, side: Side.Before }); // K in '01234567KLMNOPQ', expanding on both ends
|
|
302
|
+
},
|
|
303
|
+
expectedText: "01234567LMNOPQ",
|
|
304
|
+
});
|
|
305
|
+
// This test case demonstrates the need to 'pre-compute' the result of rebasing obliterate endpoints upon reconnection
|
|
306
|
+
// before segment order is normalized.
|
|
307
|
+
// TODO: AB#34898: This seems to demonstrate an issue with segment normalization which should be investigated.
|
|
308
|
+
// Resolving that work item may involve including this as a test case targeted at segment ordering instead, and finding an analogous case
|
|
309
|
+
// where legitimate segment reording could affect obliterate rebasing.
|
|
310
|
+
itCorrectlyObliterates({
|
|
311
|
+
title: "computes obliterate rebases before segment normalization",
|
|
312
|
+
action: (helper) => {
|
|
313
|
+
helper.insertText("A", 0, "0ABCDEFGHIJKLMNOPQRSTUVWXYZ");
|
|
314
|
+
helper.processAllOps();
|
|
315
|
+
helper.disconnect("B");
|
|
316
|
+
helper.obliterateRange("B", { pos: 9, side: Side.Before }, { pos: 26, side: Side.After }); // I through Z inclusive
|
|
317
|
+
helper.insertText("B", 3, "e"); // between "B" and "C"
|
|
318
|
+
helper.obliterateRange("B", { pos: 2, side: Side.After }, { pos: 6, side: Side.After }); // the inserted 'e' through F inclusive
|
|
319
|
+
helper.obliterateRange("A", { pos: 4, side: Side.After }, { pos: 15, side: Side.Before }); // E through N inclusive
|
|
320
|
+
helper.processAllOps();
|
|
321
|
+
// Before reconnecting, B's segment order is:
|
|
322
|
+
// 0ABeCDEFGHIJKLMNOPQRSTUVWXYZ
|
|
323
|
+
// B has issued obliterates for:
|
|
324
|
+
// 0ABeCDEFGHIJKLMNOPQRSTUVWXYZ
|
|
325
|
+
// ( ] [ ]
|
|
326
|
+
// and it sees that A has already obliterated:
|
|
327
|
+
// 0ABeCDEFGHIJKLMNOPQRSTUVWXYZ
|
|
328
|
+
// ( )
|
|
329
|
+
// Segment normalization on B will reorder "eCDEFGHIJKLMNOPQRSTUVWXYZ" to "eCDOPQRSTUVWXYZEFGHIJKLMN"
|
|
330
|
+
// (note that this seems unnecessary and is why AB#34898 is filed)
|
|
331
|
+
helper.reconnect("B");
|
|
332
|
+
},
|
|
333
|
+
expectedText: "0AB",
|
|
334
|
+
});
|
|
335
|
+
});
|
|
159
336
|
//# sourceMappingURL=obliterate.reconnect.spec.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"obliterate.reconnect.spec.js","sourceRoot":"","sources":["../../src/test/obliterate.reconnect.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\n\nimport { MergeTree } from \"../mergeTree.js\";\n\nimport { ReconnectTestHelper } from \"./reconnectHelper.js\";\nimport { useStrictPartialLengthChecks } from \"./testUtils.js\";\n\nfor (const incremental of [true, false]) {\n\tdescribe(`obliterate partial lengths incremental = ${incremental}`, () => {\n\t\tuseStrictPartialLengthChecks();\n\n\t\tbeforeEach(() => {\n\t\t\tMergeTree.options.incrementalUpdate = incremental;\n\t\t});\n\n\t\tafterEach(() => {\n\t\t\tMergeTree.options.incrementalUpdate = true;\n\t\t});\n\n\t\tit(\"obliterate does not expand during rebase\", () => {\n\t\t\tconst helper = new ReconnectTestHelper();\n\n\t\t\thelper.insertText(\"B\", 0, \"ABCD\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.removeRange(\"B\", 0, 3);\n\t\t\thelper.disconnect([\"C\"]);\n\t\t\tconst cOp = helper.obliterateRangeLocal(\"C\", 0, 1);\n\t\t\thelper.reconnect([\"C\"]);\n\t\t\thelper.submitDisconnectedOp(\"C\", cOp);\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"D\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"does delete reconnected insert into obliterate range if insert is rebased\", () => {\n\t\t\tconst helper = new ReconnectTestHelper();\n\n\t\t\thelper.insertText(\"B\", 0, \"ABCD\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.obliterateRange(\"B\", 0, 3);\n\t\t\thelper.disconnect([\"C\"]);\n\t\t\tconst cOp = helper.insertTextLocal(\"C\", 2, \"aaa\");\n\t\t\thelper.reconnect([\"C\"]);\n\t\t\thelper.submitDisconnectedOp(\"C\", cOp);\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"D\");\n\t\t\tassert.equal(helper.clients.C.getText(), \"D\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"deletes reconnected insert into obliterate range when entire string deleted if rebased\", () => {\n\t\t\tconst helper = new ReconnectTestHelper();\n\n\t\t\thelper.insertText(\"B\", 0, \"ABCD\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.obliterateRange(\"B\", 0, 4);\n\t\t\thelper.disconnect([\"C\"]);\n\t\t\tconst cOp = helper.insertTextLocal(\"C\", 2, \"aaa\");\n\t\t\thelper.reconnect([\"C\"]);\n\t\t\thelper.submitDisconnectedOp(\"C\", cOp);\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"\");\n\t\t\tassert.equal(helper.clients.C.getText(), \"\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"obliterates local segment while disconnected\", () => {\n\t\t\tconst helper = new ReconnectTestHelper();\n\n\t\t\t// [C]-D-(E)-F-H-G-B-A\n\n\t\t\thelper.insertText(\"B\", 0, \"A\");\n\n\t\t\thelper.disconnect([\"C\"]);\n\t\t\tconst op0 = helper.insertTextLocal(\"C\", 0, \"B\");\n\t\t\tconst op1 = helper.insertTextLocal(\"C\", 0, \"CDEFG\");\n\t\t\tconst op2 = helper.removeRangeLocal(\"C\", 0, 1);\n\t\t\tconst op3 = helper.obliterateRangeLocal(\"C\", 1, 2);\n\t\t\tconst op4 = helper.insertTextLocal(\"C\", 2, \"H\");\n\n\t\t\thelper.reconnect([\"C\"]);\n\t\t\thelper.submitDisconnectedOp(\"C\", op0);\n\t\t\thelper.submitDisconnectedOp(\"C\", op1);\n\t\t\thelper.submitDisconnectedOp(\"C\", op2);\n\t\t\thelper.submitDisconnectedOp(\"C\", op3);\n\t\t\thelper.submitDisconnectedOp(\"C\", op4);\n\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"DFHGBA\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"deletes concurrently inserted segment between separated group ops\", () => {\n\t\t\tconst helper = new ReconnectTestHelper();\n\n\t\t\t// B-A\n\t\t\t// (B-C-A)\n\n\t\t\thelper.insertText(\"A\", 0, \"A\");\n\t\t\thelper.insertText(\"A\", 0, \"B\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.logger.validate();\n\t\t\thelper.insertText(\"A\", 1, \"C\");\n\n\t\t\thelper.disconnect([\"B\"]);\n\t\t\tconst op = helper.obliterateRangeLocal(\"B\", 0, 2);\n\t\t\thelper.reconnect([\"B\"]);\n\t\t\thelper.submitDisconnectedOp(\"B\", op);\n\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"removes correct number of pending segments\", () => {\n\t\t\tconst helper = new ReconnectTestHelper();\n\n\t\t\t// (BC)-[A]\n\n\t\t\tconst op0 = helper.insertTextLocal(\"A\", 0, \"A\");\n\t\t\tconst op1 = helper.insertTextLocal(\"A\", 1, \"BC\");\n\t\t\tconst op2 = helper.obliterateRangeLocal(\"A\", 0, 2);\n\n\t\t\thelper.submitDisconnectedOp(\"A\", op0);\n\t\t\thelper.submitDisconnectedOp(\"A\", op1);\n\t\t\thelper.submitDisconnectedOp(\"A\", op2);\n\n\t\t\thelper.removeRange(\"A\", 0, 1);\n\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"doesn't do obliterate ack traversal when starting segment has been acked\", () => {\n\t\t\tconst helper = new ReconnectTestHelper();\n\n\t\t\t// AB\n\t\t\t// (E)-[F]-(G-D-(C-A)-B)\n\n\t\t\thelper.insertText(\"B\", 0, \"AB\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.logger.validate();\n\n\t\t\tconst op0 = helper.insertTextLocal(\"A\", 0, \"C\");\n\t\t\tconst op1 = helper.obliterateRangeLocal(\"A\", 0, 2);\n\t\t\thelper.submitDisconnectedOp(\"A\", op0);\n\t\t\thelper.submitDisconnectedOp(\"A\", op1);\n\n\t\t\thelper.insertText(\"B\", 0, \"D\");\n\t\t\thelper.insertText(\"A\", 0, \"EFG\");\n\t\t\thelper.obliterateRange(\"A\", 0, 1);\n\t\t\thelper.removeRange(\"A\", 0, 1);\n\t\t\thelper.obliterateRange(\"A\", 0, 2);\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"does not delete reconnected insert at start of obliterate range if rebased\", () => {\n\t\t\tconst helper = new ReconnectTestHelper();\n\n\t\t\thelper.insertText(\"B\", 0, \"ABCD\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.obliterateRange(\"B\", 0, 3);\n\t\t\thelper.disconnect([\"C\"]);\n\t\t\tconst cOp = helper.insertTextLocal(\"C\", 0, \"aaa\");\n\t\t\thelper.reconnect([\"C\"]);\n\t\t\thelper.submitDisconnectedOp(\"C\", cOp);\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"aaaD\");\n\t\t\tassert.equal(helper.clients.C.getText(), \"aaaD\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"does not delete reconnected insert at end of obliterate range\", () => {\n\t\t\tconst helper = new ReconnectTestHelper();\n\n\t\t\thelper.insertText(\"B\", 0, \"ABCD\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.obliterateRange(\"B\", 0, 3);\n\t\t\thelper.disconnect([\"C\"]);\n\t\t\tconst cOp = helper.insertTextLocal(\"C\", 3, \"aaa\");\n\t\t\thelper.reconnect([\"C\"]);\n\t\t\thelper.submitDisconnectedOp(\"C\", cOp);\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"aaaD\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\t});\n}\n"]}
|
|
1
|
+
{"version":3,"file":"obliterate.reconnect.spec.js","sourceRoot":"","sources":["../../src/test/obliterate.reconnect.spec.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { strict as assert } from \"node:assert\";\n\nimport { generatePairwiseOptions } from \"@fluid-private/test-pairwise-generator\";\n\nimport { MergeTree } from \"../mergeTree.js\";\nimport { Side } from \"../sequencePlace.js\";\n\nimport { ClientTestHelper } from \"./clientTestHelper.js\";\nimport { itCorrectlyObliterates, useStrictPartialLengthChecks } from \"./testUtils.js\";\n\nfor (const { incremental, mergeTreeEnableSidedObliterate } of generatePairwiseOptions({\n\tincremental: [true, false],\n\tmergeTreeEnableSidedObliterate: [\n\t\tfalse,\n\t\t// TODO:AB#31001: Enable this once sided obliterate supports reconnect.\n\t\t// true,\n\t],\n})) {\n\tdescribe(`obliterate partial lengths incremental = ${incremental} enableSidedObliterate = ${mergeTreeEnableSidedObliterate}`, () => {\n\t\tuseStrictPartialLengthChecks();\n\n\t\tbeforeEach(() => {\n\t\t\tMergeTree.options.incrementalUpdate = incremental;\n\t\t});\n\n\t\tafterEach(() => {\n\t\t\tMergeTree.options.incrementalUpdate = true;\n\t\t});\n\n\t\tit(\"obliterate does not expand during rebase\", () => {\n\t\t\tconst helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });\n\n\t\t\thelper.insertText(\"B\", 0, \"ABCD\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.removeRange(\"B\", 0, 3);\n\t\t\thelper.disconnect(\"C\");\n\t\t\thelper.obliterateRange(\"C\", 0, 1);\n\t\t\thelper.reconnect(\"C\");\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"D\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"does delete reconnected insert into obliterate range if insert is rebased\", () => {\n\t\t\tconst helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });\n\n\t\t\thelper.insertText(\"B\", 0, \"ABCD\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.obliterateRange(\"B\", 0, 3);\n\t\t\thelper.disconnect(\"C\");\n\t\t\thelper.insertText(\"C\", 2, \"aaa\");\n\t\t\thelper.reconnect(\"C\");\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"D\");\n\t\t\tassert.equal(helper.clients.C.getText(), \"D\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"deletes reconnected insert into obliterate range when entire string deleted if rebased\", () => {\n\t\t\tconst helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });\n\n\t\t\thelper.insertText(\"B\", 0, \"ABCD\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.obliterateRange(\"B\", 0, 4);\n\t\t\thelper.disconnect(\"C\");\n\t\t\thelper.insertText(\"C\", 2, \"aaa\");\n\t\t\thelper.reconnect(\"C\");\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"\");\n\t\t\tassert.equal(helper.clients.C.getText(), \"\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"obliterates local segment while disconnected\", () => {\n\t\t\tconst helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });\n\n\t\t\t// [C]-D-(E)-F-H-G-B-A\n\n\t\t\thelper.insertText(\"B\", 0, \"A\");\n\n\t\t\thelper.disconnect(\"C\");\n\t\t\thelper.insertText(\"C\", 0, \"B\");\n\t\t\thelper.insertText(\"C\", 0, \"CDEFG\");\n\t\t\thelper.removeRange(\"C\", 0, 1);\n\t\t\thelper.obliterateRange(\"C\", 1, 2);\n\t\t\thelper.insertText(\"C\", 2, \"H\");\n\n\t\t\thelper.reconnect(\"C\");\n\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"DFHGBA\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"deletes concurrently inserted segment between separated group ops\", () => {\n\t\t\tconst helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });\n\n\t\t\t// B-A\n\t\t\t// (B-C-A)\n\n\t\t\thelper.insertText(\"A\", 0, \"A\");\n\t\t\thelper.insertText(\"A\", 0, \"B\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.logger.validate();\n\t\t\thelper.insertText(\"A\", 1, \"C\");\n\n\t\t\thelper.disconnect(\"B\");\n\t\t\thelper.obliterateRange(\"B\", 0, 2);\n\t\t\thelper.reconnect(\"B\");\n\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"removes correct number of pending segments\", () => {\n\t\t\tconst helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });\n\n\t\t\t// (BC)-[A]\n\n\t\t\thelper.disconnect(\"A\");\n\t\t\thelper.insertText(\"A\", 0, \"A\");\n\t\t\thelper.insertText(\"A\", 1, \"BC\");\n\t\t\thelper.obliterateRange(\"A\", 0, 2);\n\t\t\thelper.reconnect(\"A\");\n\n\t\t\thelper.removeRange(\"A\", 0, 1);\n\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"doesn't do obliterate ack traversal when starting segment has been acked\", () => {\n\t\t\tconst helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });\n\n\t\t\t// AB\n\t\t\t// (E)-[F]-(G-D-(C-A)-B)\n\n\t\t\thelper.insertText(\"B\", 0, \"AB\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.logger.validate();\n\n\t\t\thelper.disconnect(\"A\");\n\t\t\thelper.insertText(\"A\", 0, \"C\");\n\t\t\thelper.obliterateRange(\"A\", 0, 2);\n\t\t\thelper.reconnect(\"A\");\n\n\t\t\thelper.insertText(\"B\", 0, \"D\");\n\t\t\thelper.insertText(\"A\", 0, \"EFG\");\n\t\t\thelper.obliterateRange(\"A\", 0, 1);\n\t\t\thelper.removeRange(\"A\", 0, 1);\n\t\t\thelper.obliterateRange(\"A\", 0, 2);\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"does not delete reconnected insert at start of obliterate range if rebased\", () => {\n\t\t\tconst helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });\n\n\t\t\thelper.insertText(\"B\", 0, \"ABCD\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.obliterateRange(\"B\", 0, 3);\n\t\t\thelper.disconnect(\"C\");\n\t\t\thelper.insertText(\"C\", 0, \"aaa\");\n\t\t\thelper.reconnect(\"C\");\n\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"aaaD\");\n\t\t\tassert.equal(helper.clients.C.getText(), \"aaaD\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\n\t\tit(\"does not delete reconnected insert at end of obliterate range\", () => {\n\t\t\tconst helper = new ClientTestHelper({ mergeTreeEnableSidedObliterate });\n\n\t\t\thelper.insertText(\"B\", 0, \"ABCD\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.obliterateRange(\"B\", 0, 3);\n\t\t\thelper.disconnect(\"C\");\n\t\t\thelper.insertText(\"C\", 3, \"aaa\");\n\t\t\thelper.reconnect(\"C\");\n\t\t\thelper.processAllOps();\n\n\t\t\tassert.equal(helper.clients.A.getText(), \"aaaD\");\n\n\t\t\thelper.logger.validate();\n\t\t});\n\t});\n}\n\ndescribe(\"sided obliterate reconnect\", () => {\n\titCorrectlyObliterates({\n\t\ttitle: \"add text, disconnect, obliterate, reconnect, insert adjacent to obliterated range\",\n\t\taction: (helper) => {\n\t\t\thelper.insertText(\"A\", 0, \"hello world\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.disconnect(\"C\");\n\t\t\thelper.obliterateRange(\"C\", { pos: 1, side: Side.After }, { pos: 4, side: Side.After });\n\t\t\t// inserting adjacent to the obliterated range start\n\t\t\thelper.reconnect(\"C\");\n\t\t\thelper.insertText(\"A\", 2, \"123\");\n\t\t},\n\t\texpectedText: \"he world\",\n\t});\n\titCorrectlyObliterates({\n\t\ttitle: \"add text, disconnect, obliterate, insert adjacent to obliterated range, reconnect\",\n\t\taction: (helper) => {\n\t\t\thelper.insertText(\"A\", 0, \"hello world\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.disconnect(\"C\");\n\t\t\thelper.obliterateRange(\"C\", { pos: 1, side: Side.After }, { pos: 4, side: Side.After });\n\t\t\t// inserting adjacent to the obliterated range start\n\t\t\thelper.insertText(\"A\", 2, \"123\");\n\t\t\thelper.reconnect(\"C\");\n\t\t},\n\t\texpectedText: \"he world\",\n\t});\n\n\tdescribe(\"obliterate rebasing over\", () => {\n\t\tfor (const { removalType, getRemoveMethod } of [\n\t\t\t{\n\t\t\t\tremovalType: \"remove\",\n\t\t\t\tgetRemoveMethod: (helper: ClientTestHelper): ClientTestHelper[\"removeRange\"] =>\n\t\t\t\t\thelper.removeRange.bind(helper),\n\t\t\t},\n\t\t\t{\n\t\t\t\tremovalType: \"obliterate\",\n\t\t\t\tgetRemoveMethod: (helper: ClientTestHelper): ClientTestHelper[\"removeRange\"] =>\n\t\t\t\t\thelper.obliterateRange.bind(helper),\n\t\t\t},\n\t\t]) {\n\t\t\titCorrectlyObliterates({\n\t\t\t\ttitle: `${removalType} overlapping obliterate start`,\n\t\t\t\taction: (helper) => {\n\t\t\t\t\thelper.insertText(\"A\", 0, \"0123456789\");\n\t\t\t\t\thelper.processAllOps();\n\t\t\t\t\thelper.disconnect(\"B\");\n\t\t\t\t\thelper.obliterateRange(\n\t\t\t\t\t\t\"B\",\n\t\t\t\t\t\t{ pos: 1, side: Side.Before },\n\t\t\t\t\t\t{ pos: 8, side: Side.After },\n\t\t\t\t\t);\n\t\t\t\t\thelper.insertText(\"A\", 5, \"should be obliterated\");\n\t\t\t\t\tgetRemoveMethod(helper)(\"A\", 0, 2);\n\t\t\t\t\thelper.reconnect(\"B\");\n\t\t\t\t},\n\t\t\t\texpectedText: \"9\",\n\t\t\t});\n\n\t\t\titCorrectlyObliterates({\n\t\t\t\ttitle: `${removalType} overlapping obliterate middle`,\n\t\t\t\taction: (helper) => {\n\t\t\t\t\thelper.insertText(\"A\", 0, \"0123456789\");\n\t\t\t\t\thelper.processAllOps();\n\t\t\t\t\thelper.disconnect(\"B\");\n\t\t\t\t\thelper.obliterateRange(\n\t\t\t\t\t\t\"B\",\n\t\t\t\t\t\t{ pos: 1, side: Side.Before },\n\t\t\t\t\t\t{ pos: 8, side: Side.After },\n\t\t\t\t\t);\n\t\t\t\t\tgetRemoveMethod(helper)(\"A\", 3, 4);\n\t\t\t\t\thelper.insertText(\"A\", 5, \"should be obliterated\");\n\t\t\t\t\thelper.reconnect(\"B\");\n\t\t\t\t},\n\t\t\t\texpectedText: \"09\",\n\t\t\t});\n\n\t\t\titCorrectlyObliterates({\n\t\t\t\ttitle: `${removalType} overlapping obliterate end`,\n\t\t\t\taction: (helper) => {\n\t\t\t\t\thelper.insertText(\"A\", 0, \"0123456789\");\n\t\t\t\t\thelper.processAllOps();\n\t\t\t\t\thelper.disconnect(\"B\");\n\t\t\t\t\thelper.obliterateRange(\n\t\t\t\t\t\t\"B\",\n\t\t\t\t\t\t{ pos: 1, side: Side.Before },\n\t\t\t\t\t\t{ pos: 8, side: Side.After },\n\t\t\t\t\t);\n\t\t\t\t\tgetRemoveMethod(helper)(\"A\", 8, 10);\n\t\t\t\t\thelper.insertText(\"A\", 5, \"should be obliterated\");\n\t\t\t\t\thelper.reconnect(\"B\");\n\t\t\t\t},\n\t\t\t\texpectedText: \"0\",\n\t\t\t});\n\t\t}\n\t});\n\n\t// This test and the analogous endpoint test below provide some rationale for the policy of tending to shrink obliterates\n\t// inward upon reconnect in the case that regions near their endpoints were removed between the original submission and resubmission.\n\titCorrectlyObliterates({\n\t\ttitle: \"obliterate shrinks start point to best possible option\",\n\t\taction: (helper) => {\n\t\t\thelper.insertText(\"A\", 0, \"0123456789\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.disconnect(\"B\");\n\t\t\thelper.obliterateRange(\"B\", { pos: 3, side: Side.After }, { pos: 8, side: Side.Before }); // 4 through 7\n\t\t\thelper.insertText(\"A\", 7, \"inside the original obliterate\");\n\t\t\thelper.removeRange(\"C\", 1, 5); // 1234\n\t\t\thelper.advanceClients(\"B\");\n\t\t\t// B recognizes an observer client at this seq will have '056inside the original obliterate789' and B's obliterate should additionally\n\t\t\t// remove '5inside the original obliterate67'.\n\t\t\t// It reconnects at this point and has a choice: it can either specify the startpoint of the obliterate as 'after the 0 character'\n\t\t\t// (preserving the original side) or 'before the 5 character' (which will make its start endpoint no longer \"sticky\" like\n\t\t\t// the original one). Seeing as the original startpoint has actually already been removed, we should choose the latter.\n\t\t\thelper.reconnect(\"B\");\n\t\t\t// The possibility of another client doing something like this is additional justification for this policy:\n\t\t\t// (point being that B will see this segment as clearly after the \"0\" character since it was inserted before the 3 in the original string)\n\t\t\thelper.insertText(\n\t\t\t\t\"A\",\n\t\t\t\t3,\n\t\t\t\t\"outside the original obliterate but in danger of being in the new one\",\n\t\t\t);\n\t\t},\n\t\texpectedText: \"0outside the original obliterate but in danger of being in the new one89\",\n\t});\n\n\titCorrectlyObliterates({\n\t\ttitle: \"obliterate shrinks end point to best possible option\",\n\t\taction: (helper) => {\n\t\t\thelper.insertText(\"A\", 0, \"0123456789\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.disconnect(\"B\");\n\t\t\thelper.obliterateRange(\"B\", { pos: 3, side: Side.After }, { pos: 8, side: Side.Before }); // 4 through 7\n\t\t\thelper.insertText(\"A\", 7, \"inside the original obliterate\");\n\t\t\thelper.removeRange(\"C\", 6, 9); // 678\n\t\t\thelper.advanceClients(\"B\");\n\t\t\t// B recognizes an observer client at this seq will have '056inside the original obliterate789' and B's obliterate should additionally\n\t\t\t// remove '5inside the original obliterate67'.\n\t\t\t// It reconnects at this point and has a choice: it can either specify the startpoint of the obliterate as 'after the 0 character'\n\t\t\t// (preserving the original side) or 'before the 5 character' (which will make its start endpoint no longer \"sticky\" like\n\t\t\t// the original one). Seeing as the original startpoint has actually already been removed, we should choose the latter.\n\t\t\thelper.reconnect(\"B\");\n\t\t\t// The possibility of another client doing something like this is additional justification for this policy:\n\t\t\t// (point being that B will see this segment as clearly after the \"0\" character since it was inserted before the 3 in the original string)\n\t\t\thelper.insertText(\n\t\t\t\t\"A\",\n\t\t\t\t9 + \"inside the original obliterate\".length,\n\t\t\t\t\"outside the original obliterate but in danger of being in the new one\",\n\t\t\t);\n\t\t},\n\t\texpectedText: \"0123outside the original obliterate but in danger of being in the new one9\",\n\t});\n\n\titCorrectlyObliterates({\n\t\ttitle: \"recomputes obliterate tiebreak winner\",\n\t\taction: (helper) => {\n\t\t\thelper.insertText(\"A\", 0, \"ABCDEFGHIJKLMNOPQ\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.disconnect(\"B\");\n\t\t\thelper.obliterateRange(\"D\", { pos: 0, side: Side.Before }, { pos: 6, side: Side.After }); // ABCDEFG\n\t\t\thelper.obliterateRange(\"C\", { pos: 2, side: Side.Before }, { pos: 8, side: Side.After }); // CDEFGHI\n\t\t\thelper.obliterateRange(\"B\", { pos: 3, side: Side.After }, { pos: 4, side: Side.After }); // D\n\t\t\t// This insertion position by B is critically inside the range that B originally obliterated, but that will no longer be the case\n\t\t\t// later on when B reconnects, since the region B wanted to obliterate will be gone (so there is no way to specify the same obliterate).\n\t\t\thelper.insertText(\"B\", 4, \"should go away\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.removeRange(\"C\", 0, 1); // J\n\t\t\thelper.insertText(\"C\", 0, \"01234567\"); // C now sees '01234567KLMNOPQ'\n\t\t\thelper.processAllOps();\n\t\t\t// B now needs to recognize that it no longer necessarily has 'last-write-win' privilege over its insertion\n\t\t\t// in the event that the new insertion position was obliterated concurrently to the op it's about to (re)submit.\n\t\t\thelper.reconnect(\"B\");\n\t\t\t// ... and indeed, in this case A has obliterated a region containing the \"should go away\" B inserted.\n\t\t\thelper.obliterateRange(\"A\", { pos: 7, side: Side.After }, { pos: 9, side: Side.Before }); // K in '01234567KLMNOPQ', expanding on both ends\n\t\t},\n\t\texpectedText: \"01234567LMNOPQ\",\n\t});\n\n\t// This test case demonstrates the need to 'pre-compute' the result of rebasing obliterate endpoints upon reconnection\n\t// before segment order is normalized.\n\t// TODO: AB#34898: This seems to demonstrate an issue with segment normalization which should be investigated.\n\t// Resolving that work item may involve including this as a test case targeted at segment ordering instead, and finding an analogous case\n\t// where legitimate segment reording could affect obliterate rebasing.\n\titCorrectlyObliterates({\n\t\ttitle: \"computes obliterate rebases before segment normalization\",\n\t\taction: (helper) => {\n\t\t\thelper.insertText(\"A\", 0, \"0ABCDEFGHIJKLMNOPQRSTUVWXYZ\");\n\t\t\thelper.processAllOps();\n\t\t\thelper.disconnect(\"B\");\n\t\t\thelper.obliterateRange(\n\t\t\t\t\"B\",\n\t\t\t\t{ pos: 9, side: Side.Before },\n\t\t\t\t{ pos: 26, side: Side.After },\n\t\t\t); // I through Z inclusive\n\t\t\thelper.insertText(\"B\", 3, \"e\"); // between \"B\" and \"C\"\n\t\t\thelper.obliterateRange(\"B\", { pos: 2, side: Side.After }, { pos: 6, side: Side.After }); // the inserted 'e' through F inclusive\n\t\t\thelper.obliterateRange(\n\t\t\t\t\"A\",\n\t\t\t\t{ pos: 4, side: Side.After },\n\t\t\t\t{ pos: 15, side: Side.Before },\n\t\t\t); // E through N inclusive\n\t\t\thelper.processAllOps();\n\t\t\t// Before reconnecting, B's segment order is:\n\t\t\t// 0ABeCDEFGHIJKLMNOPQRSTUVWXYZ\n\t\t\t// B has issued obliterates for:\n\t\t\t// 0ABeCDEFGHIJKLMNOPQRSTUVWXYZ\n\t\t\t// ( ] [ ]\n\t\t\t// and it sees that A has already obliterated:\n\t\t\t// 0ABeCDEFGHIJKLMNOPQRSTUVWXYZ\n\t\t\t// ( )\n\n\t\t\t// Segment normalization on B will reorder \"eCDEFGHIJKLMNOPQRSTUVWXYZ\" to \"eCDOPQRSTUVWXYZEFGHIJKLMN\"\n\t\t\t// (note that this seems unnecessary and is why AB#34898 is filed)\n\t\t\thelper.reconnect(\"B\");\n\t\t},\n\t\texpectedText: \"0AB\",\n\t});\n});\n"]}
|
package/lib/test/testClient.js
CHANGED
|
@@ -218,7 +218,7 @@ export class TestClient extends Client {
|
|
|
218
218
|
return posAccumulated <= pos;
|
|
219
219
|
});
|
|
220
220
|
assert(segment !== undefined, "No segment found");
|
|
221
|
-
const segoff = getSlideToSegoff({ segment, offset }) ?? segment;
|
|
221
|
+
const segoff = getSlideToSegoff({ segment, offset }, undefined, perspective) ?? segment;
|
|
222
222
|
if (segoff.segment === undefined || segoff.offset === undefined) {
|
|
223
223
|
return DetachedReferencePosition;
|
|
224
224
|
}
|