Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/editor/test/common/model/intervalTree.test.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import assert from 'assert';
7
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
8
import { TrackedRangeStickiness } from '../../../common/model.js';
9
import { IntervalNode, IntervalTree, NodeColor, SENTINEL, getNodeColor, intervalCompare, nodeAcceptEdit, setNodeStickiness } from '../../../common/model/intervalTree.js';
10
11
const GENERATE_TESTS = false;
12
const TEST_COUNT = GENERATE_TESTS ? 10000 : 0;
13
const PRINT_TREE = false;
14
const MIN_INTERVAL_START = 1;
15
const MAX_INTERVAL_END = 100;
16
const MIN_INSERTS = 1;
17
const MAX_INSERTS = 30;
18
const MIN_CHANGE_CNT = 10;
19
const MAX_CHANGE_CNT = 20;
20
21
suite('IntervalTree 1', () => {
22
23
ensureNoDisposablesAreLeakedInTestSuite();
24
25
class Interval {
26
_intervalBrand: void = undefined;
27
28
public start: number;
29
public end: number;
30
31
constructor(start: number, end: number) {
32
this.start = start;
33
this.end = end;
34
}
35
}
36
37
class Oracle {
38
public intervals: Interval[];
39
40
constructor() {
41
this.intervals = [];
42
}
43
44
public insert(interval: Interval): Interval {
45
this.intervals.push(interval);
46
this.intervals.sort((a, b) => {
47
if (a.start === b.start) {
48
return a.end - b.end;
49
}
50
return a.start - b.start;
51
});
52
return interval;
53
}
54
55
public delete(interval: Interval): void {
56
for (let i = 0, len = this.intervals.length; i < len; i++) {
57
if (this.intervals[i] === interval) {
58
this.intervals.splice(i, 1);
59
return;
60
}
61
}
62
}
63
64
public search(interval: Interval): Interval[] {
65
const result: Interval[] = [];
66
for (let i = 0, len = this.intervals.length; i < len; i++) {
67
const int = this.intervals[i];
68
if (int.start <= interval.end && int.end >= interval.start) {
69
result.push(int);
70
}
71
}
72
return result;
73
}
74
}
75
76
class TestState {
77
private _oracle: Oracle = new Oracle();
78
private _tree: IntervalTree = new IntervalTree();
79
private _lastNodeId = -1;
80
private _treeNodes: Array<IntervalNode | null> = [];
81
private _oracleNodes: Array<Interval | null> = [];
82
83
public acceptOp(op: IOperation): void {
84
85
if (op.type === 'insert') {
86
if (PRINT_TREE) {
87
console.log(`insert: {${JSON.stringify(new Interval(op.begin, op.end))}}`);
88
}
89
const nodeId = (++this._lastNodeId);
90
this._treeNodes[nodeId] = new IntervalNode(null!, op.begin, op.end);
91
this._tree.insert(this._treeNodes[nodeId]!);
92
this._oracleNodes[nodeId] = this._oracle.insert(new Interval(op.begin, op.end));
93
} else if (op.type === 'delete') {
94
if (PRINT_TREE) {
95
console.log(`delete: {${JSON.stringify(this._oracleNodes[op.id])}}`);
96
}
97
this._tree.delete(this._treeNodes[op.id]!);
98
this._oracle.delete(this._oracleNodes[op.id]!);
99
100
this._treeNodes[op.id] = null;
101
this._oracleNodes[op.id] = null;
102
} else if (op.type === 'change') {
103
104
this._tree.delete(this._treeNodes[op.id]!);
105
this._treeNodes[op.id]!.reset(0, op.begin, op.end, null!);
106
this._tree.insert(this._treeNodes[op.id]!);
107
108
this._oracle.delete(this._oracleNodes[op.id]!);
109
this._oracleNodes[op.id]!.start = op.begin;
110
this._oracleNodes[op.id]!.end = op.end;
111
this._oracle.insert(this._oracleNodes[op.id]!);
112
113
} else {
114
const actualNodes = this._tree.intervalSearch(op.begin, op.end, 0, false, false, 0, false);
115
const actual = actualNodes.map(n => new Interval(n.cachedAbsoluteStart, n.cachedAbsoluteEnd));
116
const expected = this._oracle.search(new Interval(op.begin, op.end));
117
assert.deepStrictEqual(actual, expected);
118
return;
119
}
120
121
if (PRINT_TREE) {
122
printTree(this._tree);
123
}
124
125
assertTreeInvariants(this._tree);
126
127
const actual = this._tree.getAllInOrder().map(n => new Interval(n.cachedAbsoluteStart, n.cachedAbsoluteEnd));
128
const expected = this._oracle.intervals;
129
assert.deepStrictEqual(actual, expected);
130
}
131
132
public getExistingNodeId(index: number): number {
133
let currIndex = -1;
134
for (let i = 0; i < this._treeNodes.length; i++) {
135
if (this._treeNodes[i] === null) {
136
continue;
137
}
138
currIndex++;
139
if (currIndex === index) {
140
return i;
141
}
142
}
143
throw new Error('unexpected');
144
}
145
}
146
147
interface IInsertOperation {
148
type: 'insert';
149
begin: number;
150
end: number;
151
}
152
153
interface IDeleteOperation {
154
type: 'delete';
155
id: number;
156
}
157
158
interface IChangeOperation {
159
type: 'change';
160
id: number;
161
begin: number;
162
end: number;
163
}
164
165
interface ISearchOperation {
166
type: 'search';
167
begin: number;
168
end: number;
169
}
170
171
type IOperation = IInsertOperation | IDeleteOperation | IChangeOperation | ISearchOperation;
172
173
function testIntervalTree(ops: IOperation[]): void {
174
const state = new TestState();
175
for (let i = 0; i < ops.length; i++) {
176
state.acceptOp(ops[i]);
177
}
178
}
179
180
function getRandomInt(min: number, max: number): number {
181
return Math.floor(Math.random() * (max - min + 1)) + min;
182
}
183
184
function getRandomRange(min: number, max: number): [number, number] {
185
const begin = getRandomInt(min, max);
186
let length: number;
187
if (getRandomInt(1, 10) <= 2) {
188
// large range
189
length = getRandomInt(0, max - begin);
190
} else {
191
// small range
192
length = getRandomInt(0, Math.min(max - begin, 10));
193
}
194
return [begin, begin + length];
195
}
196
197
class AutoTest {
198
private _ops: IOperation[] = [];
199
private _state: TestState = new TestState();
200
private _insertCnt: number;
201
private _deleteCnt: number;
202
private _changeCnt: number;
203
204
constructor() {
205
this._insertCnt = getRandomInt(MIN_INSERTS, MAX_INSERTS);
206
this._changeCnt = getRandomInt(MIN_CHANGE_CNT, MAX_CHANGE_CNT);
207
this._deleteCnt = 0;
208
}
209
210
private _doRandomInsert(): void {
211
const range = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END);
212
this._run({
213
type: 'insert',
214
begin: range[0],
215
end: range[1]
216
});
217
}
218
219
private _doRandomDelete(): void {
220
const idx = getRandomInt(Math.floor(this._deleteCnt / 2), this._deleteCnt - 1);
221
this._run({
222
type: 'delete',
223
id: this._state.getExistingNodeId(idx)
224
});
225
}
226
227
private _doRandomChange(): void {
228
const idx = getRandomInt(0, this._deleteCnt - 1);
229
const range = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END);
230
this._run({
231
type: 'change',
232
id: this._state.getExistingNodeId(idx),
233
begin: range[0],
234
end: range[1]
235
});
236
}
237
238
public run() {
239
while (this._insertCnt > 0 || this._deleteCnt > 0 || this._changeCnt > 0) {
240
if (this._insertCnt > 0) {
241
this._doRandomInsert();
242
this._insertCnt--;
243
this._deleteCnt++;
244
} else if (this._changeCnt > 0) {
245
this._doRandomChange();
246
this._changeCnt--;
247
} else {
248
this._doRandomDelete();
249
this._deleteCnt--;
250
}
251
252
// Let's also search for something...
253
const searchRange = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END);
254
this._run({
255
type: 'search',
256
begin: searchRange[0],
257
end: searchRange[1]
258
});
259
}
260
}
261
262
private _run(op: IOperation): void {
263
this._ops.push(op);
264
this._state.acceptOp(op);
265
}
266
267
public print(): void {
268
console.log(`testIntervalTree(${JSON.stringify(this._ops)})`);
269
}
270
271
}
272
273
suite('generated', () => {
274
test('gen01', () => {
275
testIntervalTree([
276
{ type: 'insert', begin: 28, end: 35 },
277
{ type: 'insert', begin: 52, end: 54 },
278
{ type: 'insert', begin: 63, end: 69 }
279
]);
280
});
281
282
test('gen02', () => {
283
testIntervalTree([
284
{ type: 'insert', begin: 80, end: 89 },
285
{ type: 'insert', begin: 92, end: 100 },
286
{ type: 'insert', begin: 99, end: 99 }
287
]);
288
});
289
290
test('gen03', () => {
291
testIntervalTree([
292
{ type: 'insert', begin: 89, end: 96 },
293
{ type: 'insert', begin: 71, end: 74 },
294
{ type: 'delete', id: 1 }
295
]);
296
});
297
298
test('gen04', () => {
299
testIntervalTree([
300
{ type: 'insert', begin: 44, end: 46 },
301
{ type: 'insert', begin: 85, end: 88 },
302
{ type: 'delete', id: 0 }
303
]);
304
});
305
306
test('gen05', () => {
307
testIntervalTree([
308
{ type: 'insert', begin: 82, end: 90 },
309
{ type: 'insert', begin: 69, end: 73 },
310
{ type: 'delete', id: 0 },
311
{ type: 'delete', id: 1 }
312
]);
313
});
314
315
test('gen06', () => {
316
testIntervalTree([
317
{ type: 'insert', begin: 41, end: 63 },
318
{ type: 'insert', begin: 98, end: 98 },
319
{ type: 'insert', begin: 47, end: 51 },
320
{ type: 'delete', id: 2 }
321
]);
322
});
323
324
test('gen07', () => {
325
testIntervalTree([
326
{ type: 'insert', begin: 24, end: 26 },
327
{ type: 'insert', begin: 11, end: 28 },
328
{ type: 'insert', begin: 27, end: 30 },
329
{ type: 'insert', begin: 80, end: 85 },
330
{ type: 'delete', id: 1 }
331
]);
332
});
333
334
test('gen08', () => {
335
testIntervalTree([
336
{ type: 'insert', begin: 100, end: 100 },
337
{ type: 'insert', begin: 100, end: 100 }
338
]);
339
});
340
341
test('gen09', () => {
342
testIntervalTree([
343
{ type: 'insert', begin: 58, end: 65 },
344
{ type: 'insert', begin: 82, end: 96 },
345
{ type: 'insert', begin: 58, end: 65 }
346
]);
347
});
348
349
test('gen10', () => {
350
testIntervalTree([
351
{ type: 'insert', begin: 32, end: 40 },
352
{ type: 'insert', begin: 25, end: 29 },
353
{ type: 'insert', begin: 24, end: 32 }
354
]);
355
});
356
357
test('gen11', () => {
358
testIntervalTree([
359
{ type: 'insert', begin: 25, end: 70 },
360
{ type: 'insert', begin: 99, end: 100 },
361
{ type: 'insert', begin: 46, end: 51 },
362
{ type: 'insert', begin: 57, end: 57 },
363
{ type: 'delete', id: 2 }
364
]);
365
});
366
367
test('gen12', () => {
368
testIntervalTree([
369
{ type: 'insert', begin: 20, end: 26 },
370
{ type: 'insert', begin: 10, end: 18 },
371
{ type: 'insert', begin: 99, end: 99 },
372
{ type: 'insert', begin: 37, end: 59 },
373
{ type: 'delete', id: 2 }
374
]);
375
});
376
377
test('gen13', () => {
378
testIntervalTree([
379
{ type: 'insert', begin: 3, end: 91 },
380
{ type: 'insert', begin: 57, end: 57 },
381
{ type: 'insert', begin: 35, end: 44 },
382
{ type: 'insert', begin: 72, end: 81 },
383
{ type: 'delete', id: 2 }
384
]);
385
});
386
387
test('gen14', () => {
388
testIntervalTree([
389
{ type: 'insert', begin: 58, end: 61 },
390
{ type: 'insert', begin: 34, end: 35 },
391
{ type: 'insert', begin: 56, end: 62 },
392
{ type: 'insert', begin: 69, end: 78 },
393
{ type: 'delete', id: 0 }
394
]);
395
});
396
397
test('gen15', () => {
398
testIntervalTree([
399
{ type: 'insert', begin: 63, end: 69 },
400
{ type: 'insert', begin: 17, end: 24 },
401
{ type: 'insert', begin: 3, end: 13 },
402
{ type: 'insert', begin: 84, end: 94 },
403
{ type: 'insert', begin: 18, end: 23 },
404
{ type: 'insert', begin: 96, end: 98 },
405
{ type: 'delete', id: 1 }
406
]);
407
});
408
409
test('gen16', () => {
410
testIntervalTree([
411
{ type: 'insert', begin: 27, end: 27 },
412
{ type: 'insert', begin: 42, end: 87 },
413
{ type: 'insert', begin: 42, end: 49 },
414
{ type: 'insert', begin: 69, end: 71 },
415
{ type: 'insert', begin: 20, end: 27 },
416
{ type: 'insert', begin: 8, end: 9 },
417
{ type: 'insert', begin: 42, end: 49 },
418
{ type: 'delete', id: 1 }
419
]);
420
});
421
422
test('gen17', () => {
423
testIntervalTree([
424
{ type: 'insert', begin: 21, end: 23 },
425
{ type: 'insert', begin: 83, end: 87 },
426
{ type: 'insert', begin: 56, end: 58 },
427
{ type: 'insert', begin: 1, end: 55 },
428
{ type: 'insert', begin: 56, end: 59 },
429
{ type: 'insert', begin: 58, end: 60 },
430
{ type: 'insert', begin: 56, end: 65 },
431
{ type: 'delete', id: 1 },
432
{ type: 'delete', id: 0 },
433
{ type: 'delete', id: 6 }
434
]);
435
});
436
437
test('gen18', () => {
438
testIntervalTree([
439
{ type: 'insert', begin: 25, end: 25 },
440
{ type: 'insert', begin: 67, end: 79 },
441
{ type: 'delete', id: 0 },
442
{ type: 'search', begin: 65, end: 75 }
443
]);
444
});
445
446
test('force delta overflow', () => {
447
// Search the IntervalNode ctor for FORCE_OVERFLOWING_TEST
448
// to force that this test leads to a delta normalization
449
testIntervalTree([
450
{ type: 'insert', begin: 686081138593427, end: 733009856502260 },
451
{ type: 'insert', begin: 591031326181669, end: 591031326181672 },
452
{ type: 'insert', begin: 940037682731896, end: 940037682731903 },
453
{ type: 'insert', begin: 598413641151120, end: 598413641151128 },
454
{ type: 'insert', begin: 800564156553344, end: 800564156553351 },
455
{ type: 'insert', begin: 894198957565481, end: 894198957565491 }
456
]);
457
});
458
});
459
460
// TEST_COUNT = 0;
461
// PRINT_TREE = true;
462
463
for (let i = 0; i < TEST_COUNT; i++) {
464
if (i % 100 === 0) {
465
console.log(`TEST ${i + 1}/${TEST_COUNT}`);
466
}
467
const test = new AutoTest();
468
469
try {
470
test.run();
471
} catch (err) {
472
console.log(err);
473
test.print();
474
return;
475
}
476
}
477
478
suite('searching', () => {
479
480
function createCormenTree(): IntervalTree {
481
const r = new IntervalTree();
482
const data: [number, number][] = [
483
[16, 21],
484
[8, 9],
485
[25, 30],
486
[5, 8],
487
[15, 23],
488
[17, 19],
489
[26, 26],
490
[0, 3],
491
[6, 10],
492
[19, 20]
493
];
494
data.forEach((int) => {
495
const node = new IntervalNode(null!, int[0], int[1]);
496
r.insert(node);
497
});
498
return r;
499
}
500
501
const T = createCormenTree();
502
503
function assertIntervalSearch(start: number, end: number, expected: [number, number][]): void {
504
const actualNodes = T.intervalSearch(start, end, 0, false, false, 0, false);
505
const actual = actualNodes.map((n) => <[number, number]>[n.cachedAbsoluteStart, n.cachedAbsoluteEnd]);
506
assert.deepStrictEqual(actual, expected);
507
}
508
509
test('cormen 1->2', () => {
510
assertIntervalSearch(
511
1, 2,
512
[
513
[0, 3],
514
]
515
);
516
});
517
518
test('cormen 4->8', () => {
519
assertIntervalSearch(
520
4, 8,
521
[
522
[5, 8],
523
[6, 10],
524
[8, 9],
525
]
526
);
527
});
528
529
test('cormen 10->15', () => {
530
assertIntervalSearch(
531
10, 15,
532
[
533
[6, 10],
534
[15, 23],
535
]
536
);
537
});
538
539
test('cormen 21->25', () => {
540
assertIntervalSearch(
541
21, 25,
542
[
543
[15, 23],
544
[16, 21],
545
[25, 30],
546
]
547
);
548
});
549
550
test('cormen 24->24', () => {
551
assertIntervalSearch(
552
24, 24,
553
[
554
]
555
);
556
});
557
});
558
});
559
560
suite('IntervalTree 2', () => {
561
562
ensureNoDisposablesAreLeakedInTestSuite();
563
564
function assertNodeAcceptEdit(msg: string, nodeStart: number, nodeEnd: number, nodeStickiness: TrackedRangeStickiness, start: number, end: number, textLength: number, forceMoveMarkers: boolean, expectedNodeStart: number, expectedNodeEnd: number): void {
565
const node = new IntervalNode('', nodeStart, nodeEnd);
566
setNodeStickiness(node, nodeStickiness);
567
nodeAcceptEdit(node, start, end, textLength, forceMoveMarkers);
568
assert.deepStrictEqual([node.start, node.end], [expectedNodeStart, expectedNodeEnd], msg);
569
}
570
571
test('nodeAcceptEdit', () => {
572
// A. collapsed decoration
573
{
574
// no-op
575
assertNodeAcceptEdit('A.000', 0, 0, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 0, false, 0, 0);
576
assertNodeAcceptEdit('A.001', 0, 0, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 0, false, 0, 0);
577
assertNodeAcceptEdit('A.002', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 0, false, 0, 0);
578
assertNodeAcceptEdit('A.003', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 0, false, 0, 0);
579
assertNodeAcceptEdit('A.004', 0, 0, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 0, true, 0, 0);
580
assertNodeAcceptEdit('A.005', 0, 0, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 0, true, 0, 0);
581
assertNodeAcceptEdit('A.006', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 0, true, 0, 0);
582
assertNodeAcceptEdit('A.007', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 0, true, 0, 0);
583
// insertion
584
assertNodeAcceptEdit('A.008', 0, 0, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 1, false, 0, 1);
585
assertNodeAcceptEdit('A.009', 0, 0, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 1, false, 1, 1);
586
assertNodeAcceptEdit('A.010', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 1, false, 0, 0);
587
assertNodeAcceptEdit('A.011', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 1, false, 1, 1);
588
assertNodeAcceptEdit('A.012', 0, 0, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 1, true, 1, 1);
589
assertNodeAcceptEdit('A.013', 0, 0, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 1, true, 1, 1);
590
assertNodeAcceptEdit('A.014', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 1, true, 1, 1);
591
assertNodeAcceptEdit('A.015', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 1, true, 1, 1);
592
}
593
594
// B. non collapsed decoration
595
{
596
// no-op
597
assertNodeAcceptEdit('B.000', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 0, false, 0, 5);
598
assertNodeAcceptEdit('B.001', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 0, false, 0, 5);
599
assertNodeAcceptEdit('B.002', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 0, false, 0, 5);
600
assertNodeAcceptEdit('B.003', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 0, false, 0, 5);
601
assertNodeAcceptEdit('B.004', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 0, true, 0, 5);
602
assertNodeAcceptEdit('B.005', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 0, true, 0, 5);
603
assertNodeAcceptEdit('B.006', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 0, true, 0, 5);
604
assertNodeAcceptEdit('B.007', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 0, true, 0, 5);
605
// insertion at start
606
assertNodeAcceptEdit('B.008', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 1, false, 0, 6);
607
assertNodeAcceptEdit('B.009', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 1, false, 1, 6);
608
assertNodeAcceptEdit('B.010', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 1, false, 0, 6);
609
assertNodeAcceptEdit('B.011', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 1, false, 1, 6);
610
assertNodeAcceptEdit('B.012', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 1, true, 1, 6);
611
assertNodeAcceptEdit('B.013', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 1, true, 1, 6);
612
assertNodeAcceptEdit('B.014', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 1, true, 1, 6);
613
assertNodeAcceptEdit('B.015', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 1, true, 1, 6);
614
// insertion in middle
615
assertNodeAcceptEdit('B.016', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 2, 2, 1, false, 0, 6);
616
assertNodeAcceptEdit('B.017', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 2, 2, 1, false, 0, 6);
617
assertNodeAcceptEdit('B.018', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 2, 2, 1, false, 0, 6);
618
assertNodeAcceptEdit('B.019', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 2, 2, 1, false, 0, 6);
619
assertNodeAcceptEdit('B.020', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 2, 2, 1, true, 0, 6);
620
assertNodeAcceptEdit('B.021', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 2, 2, 1, true, 0, 6);
621
assertNodeAcceptEdit('B.022', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 2, 2, 1, true, 0, 6);
622
assertNodeAcceptEdit('B.023', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 2, 2, 1, true, 0, 6);
623
// insertion at end
624
assertNodeAcceptEdit('B.024', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 5, 1, false, 0, 6);
625
assertNodeAcceptEdit('B.025', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 5, 1, false, 0, 5);
626
assertNodeAcceptEdit('B.026', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 5, 1, false, 0, 5);
627
assertNodeAcceptEdit('B.027', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 5, 1, false, 0, 6);
628
assertNodeAcceptEdit('B.028', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 5, 1, true, 0, 6);
629
assertNodeAcceptEdit('B.029', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 5, 1, true, 0, 6);
630
assertNodeAcceptEdit('B.030', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 5, 1, true, 0, 6);
631
assertNodeAcceptEdit('B.031', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 5, 1, true, 0, 6);
632
633
// replace with larger text until start
634
assertNodeAcceptEdit('B.032', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 5, 2, false, 5, 11);
635
assertNodeAcceptEdit('B.033', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 5, 2, false, 6, 11);
636
assertNodeAcceptEdit('B.034', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 5, 2, false, 5, 11);
637
assertNodeAcceptEdit('B.035', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 5, 2, false, 6, 11);
638
assertNodeAcceptEdit('B.036', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 5, 2, true, 6, 11);
639
assertNodeAcceptEdit('B.037', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 5, 2, true, 6, 11);
640
assertNodeAcceptEdit('B.038', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 5, 2, true, 6, 11);
641
assertNodeAcceptEdit('B.039', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 5, 2, true, 6, 11);
642
// replace with smaller text until start
643
assertNodeAcceptEdit('B.040', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 3, 5, 1, false, 4, 9);
644
assertNodeAcceptEdit('B.041', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 3, 5, 1, false, 4, 9);
645
assertNodeAcceptEdit('B.042', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 3, 5, 1, false, 4, 9);
646
assertNodeAcceptEdit('B.043', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 3, 5, 1, false, 4, 9);
647
assertNodeAcceptEdit('B.044', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 3, 5, 1, true, 4, 9);
648
assertNodeAcceptEdit('B.045', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 3, 5, 1, true, 4, 9);
649
assertNodeAcceptEdit('B.046', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 3, 5, 1, true, 4, 9);
650
assertNodeAcceptEdit('B.047', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 3, 5, 1, true, 4, 9);
651
652
// replace with larger text select start
653
assertNodeAcceptEdit('B.048', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 3, false, 5, 11);
654
assertNodeAcceptEdit('B.049', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 3, false, 5, 11);
655
assertNodeAcceptEdit('B.050', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 3, false, 5, 11);
656
assertNodeAcceptEdit('B.051', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 3, false, 5, 11);
657
assertNodeAcceptEdit('B.052', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 3, true, 7, 11);
658
assertNodeAcceptEdit('B.053', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 3, true, 7, 11);
659
assertNodeAcceptEdit('B.054', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 3, true, 7, 11);
660
assertNodeAcceptEdit('B.055', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 3, true, 7, 11);
661
// replace with smaller text select start
662
assertNodeAcceptEdit('B.056', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 1, false, 5, 9);
663
assertNodeAcceptEdit('B.057', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 1, false, 5, 9);
664
assertNodeAcceptEdit('B.058', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 1, false, 5, 9);
665
assertNodeAcceptEdit('B.059', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 1, false, 5, 9);
666
assertNodeAcceptEdit('B.060', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 1, true, 5, 9);
667
assertNodeAcceptEdit('B.061', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 1, true, 5, 9);
668
assertNodeAcceptEdit('B.062', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 1, true, 5, 9);
669
assertNodeAcceptEdit('B.063', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 1, true, 5, 9);
670
671
// replace with larger text from start
672
assertNodeAcceptEdit('B.064', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 6, 2, false, 5, 11);
673
assertNodeAcceptEdit('B.065', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 6, 2, false, 5, 11);
674
assertNodeAcceptEdit('B.066', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 6, 2, false, 5, 11);
675
assertNodeAcceptEdit('B.067', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 6, 2, false, 5, 11);
676
assertNodeAcceptEdit('B.068', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 6, 2, true, 7, 11);
677
assertNodeAcceptEdit('B.069', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 6, 2, true, 7, 11);
678
assertNodeAcceptEdit('B.070', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 6, 2, true, 7, 11);
679
assertNodeAcceptEdit('B.071', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 6, 2, true, 7, 11);
680
// replace with smaller text from start
681
assertNodeAcceptEdit('B.072', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 7, 1, false, 5, 9);
682
assertNodeAcceptEdit('B.073', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 7, 1, false, 5, 9);
683
assertNodeAcceptEdit('B.074', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 7, 1, false, 5, 9);
684
assertNodeAcceptEdit('B.075', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 7, 1, false, 5, 9);
685
assertNodeAcceptEdit('B.076', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 7, 1, true, 6, 9);
686
assertNodeAcceptEdit('B.077', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 7, 1, true, 6, 9);
687
assertNodeAcceptEdit('B.078', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 7, 1, true, 6, 9);
688
assertNodeAcceptEdit('B.079', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 7, 1, true, 6, 9);
689
690
// replace with larger text to end
691
assertNodeAcceptEdit('B.080', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 10, 2, false, 5, 11);
692
assertNodeAcceptEdit('B.081', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 10, 2, false, 5, 10);
693
assertNodeAcceptEdit('B.082', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 10, 2, false, 5, 10);
694
assertNodeAcceptEdit('B.083', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 10, 2, false, 5, 11);
695
assertNodeAcceptEdit('B.084', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 10, 2, true, 5, 11);
696
assertNodeAcceptEdit('B.085', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 10, 2, true, 5, 11);
697
assertNodeAcceptEdit('B.086', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 10, 2, true, 5, 11);
698
assertNodeAcceptEdit('B.087', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 10, 2, true, 5, 11);
699
// replace with smaller text to end
700
assertNodeAcceptEdit('B.088', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 8, 10, 1, false, 5, 9);
701
assertNodeAcceptEdit('B.089', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 8, 10, 1, false, 5, 9);
702
assertNodeAcceptEdit('B.090', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 8, 10, 1, false, 5, 9);
703
assertNodeAcceptEdit('B.091', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 8, 10, 1, false, 5, 9);
704
assertNodeAcceptEdit('B.092', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 8, 10, 1, true, 5, 9);
705
assertNodeAcceptEdit('B.093', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 8, 10, 1, true, 5, 9);
706
assertNodeAcceptEdit('B.094', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 8, 10, 1, true, 5, 9);
707
assertNodeAcceptEdit('B.095', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 8, 10, 1, true, 5, 9);
708
709
// replace with larger text select end
710
assertNodeAcceptEdit('B.096', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 3, false, 5, 10);
711
assertNodeAcceptEdit('B.097', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 3, false, 5, 10);
712
assertNodeAcceptEdit('B.098', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 3, false, 5, 10);
713
assertNodeAcceptEdit('B.099', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 3, false, 5, 10);
714
assertNodeAcceptEdit('B.100', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 3, true, 5, 12);
715
assertNodeAcceptEdit('B.101', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 3, true, 5, 12);
716
assertNodeAcceptEdit('B.102', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 3, true, 5, 12);
717
assertNodeAcceptEdit('B.103', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 3, true, 5, 12);
718
// replace with smaller text select end
719
assertNodeAcceptEdit('B.104', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 1, false, 5, 10);
720
assertNodeAcceptEdit('B.105', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 1, false, 5, 10);
721
assertNodeAcceptEdit('B.106', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 1, false, 5, 10);
722
assertNodeAcceptEdit('B.107', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 1, false, 5, 10);
723
assertNodeAcceptEdit('B.108', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 1, true, 5, 10);
724
assertNodeAcceptEdit('B.109', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 1, true, 5, 10);
725
assertNodeAcceptEdit('B.110', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 1, true, 5, 10);
726
assertNodeAcceptEdit('B.111', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 1, true, 5, 10);
727
728
// replace with larger text from end
729
assertNodeAcceptEdit('B.112', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 11, 3, false, 5, 10);
730
assertNodeAcceptEdit('B.113', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 11, 3, false, 5, 10);
731
assertNodeAcceptEdit('B.114', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 11, 3, false, 5, 10);
732
assertNodeAcceptEdit('B.115', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 11, 3, false, 5, 10);
733
assertNodeAcceptEdit('B.116', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 11, 3, true, 5, 13);
734
assertNodeAcceptEdit('B.117', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 11, 3, true, 5, 13);
735
assertNodeAcceptEdit('B.118', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 11, 3, true, 5, 13);
736
assertNodeAcceptEdit('B.119', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 11, 3, true, 5, 13);
737
// replace with smaller text from end
738
assertNodeAcceptEdit('B.120', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 12, 1, false, 5, 10);
739
assertNodeAcceptEdit('B.121', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 12, 1, false, 5, 10);
740
assertNodeAcceptEdit('B.122', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 12, 1, false, 5, 10);
741
assertNodeAcceptEdit('B.123', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 12, 1, false, 5, 10);
742
assertNodeAcceptEdit('B.124', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 12, 1, true, 5, 11);
743
assertNodeAcceptEdit('B.125', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 12, 1, true, 5, 11);
744
assertNodeAcceptEdit('B.126', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 12, 1, true, 5, 11);
745
assertNodeAcceptEdit('B.127', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 12, 1, true, 5, 11);
746
747
// delete until start
748
assertNodeAcceptEdit('B.128', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 5, 0, false, 4, 9);
749
assertNodeAcceptEdit('B.129', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 5, 0, false, 4, 9);
750
assertNodeAcceptEdit('B.130', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 5, 0, false, 4, 9);
751
assertNodeAcceptEdit('B.131', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 5, 0, false, 4, 9);
752
assertNodeAcceptEdit('B.132', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 5, 0, true, 4, 9);
753
assertNodeAcceptEdit('B.133', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 5, 0, true, 4, 9);
754
assertNodeAcceptEdit('B.134', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 5, 0, true, 4, 9);
755
assertNodeAcceptEdit('B.135', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 5, 0, true, 4, 9);
756
757
// delete select start
758
assertNodeAcceptEdit('B.136', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 0, false, 4, 8);
759
assertNodeAcceptEdit('B.137', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 0, false, 4, 8);
760
assertNodeAcceptEdit('B.138', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 0, false, 4, 8);
761
assertNodeAcceptEdit('B.139', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 0, false, 4, 8);
762
assertNodeAcceptEdit('B.140', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 0, true, 4, 8);
763
assertNodeAcceptEdit('B.141', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 0, true, 4, 8);
764
assertNodeAcceptEdit('B.142', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 0, true, 4, 8);
765
assertNodeAcceptEdit('B.143', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 0, true, 4, 8);
766
767
// delete from start
768
assertNodeAcceptEdit('B.144', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 6, 0, false, 5, 9);
769
assertNodeAcceptEdit('B.145', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 6, 0, false, 5, 9);
770
assertNodeAcceptEdit('B.146', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 6, 0, false, 5, 9);
771
assertNodeAcceptEdit('B.147', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 6, 0, false, 5, 9);
772
assertNodeAcceptEdit('B.148', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 6, 0, true, 5, 9);
773
assertNodeAcceptEdit('B.149', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 6, 0, true, 5, 9);
774
assertNodeAcceptEdit('B.150', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 6, 0, true, 5, 9);
775
assertNodeAcceptEdit('B.151', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 6, 0, true, 5, 9);
776
777
// delete to end
778
assertNodeAcceptEdit('B.152', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 10, 0, false, 5, 9);
779
assertNodeAcceptEdit('B.153', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 10, 0, false, 5, 9);
780
assertNodeAcceptEdit('B.154', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 10, 0, false, 5, 9);
781
assertNodeAcceptEdit('B.155', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 10, 0, false, 5, 9);
782
assertNodeAcceptEdit('B.156', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 10, 0, true, 5, 9);
783
assertNodeAcceptEdit('B.157', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 10, 0, true, 5, 9);
784
assertNodeAcceptEdit('B.158', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 10, 0, true, 5, 9);
785
assertNodeAcceptEdit('B.159', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 10, 0, true, 5, 9);
786
787
// delete select end
788
assertNodeAcceptEdit('B.160', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 0, false, 5, 9);
789
assertNodeAcceptEdit('B.161', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 0, false, 5, 9);
790
assertNodeAcceptEdit('B.162', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 0, false, 5, 9);
791
assertNodeAcceptEdit('B.163', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 0, false, 5, 9);
792
assertNodeAcceptEdit('B.164', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 0, true, 5, 9);
793
assertNodeAcceptEdit('B.165', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 0, true, 5, 9);
794
assertNodeAcceptEdit('B.166', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 0, true, 5, 9);
795
assertNodeAcceptEdit('B.167', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 0, true, 5, 9);
796
797
// delete from end
798
assertNodeAcceptEdit('B.168', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 11, 0, false, 5, 10);
799
assertNodeAcceptEdit('B.169', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 11, 0, false, 5, 10);
800
assertNodeAcceptEdit('B.170', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 11, 0, false, 5, 10);
801
assertNodeAcceptEdit('B.171', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 11, 0, false, 5, 10);
802
assertNodeAcceptEdit('B.172', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 11, 0, true, 5, 10);
803
assertNodeAcceptEdit('B.173', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 11, 0, true, 5, 10);
804
assertNodeAcceptEdit('B.174', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 11, 0, true, 5, 10);
805
assertNodeAcceptEdit('B.175', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 11, 0, true, 5, 10);
806
807
// replace with larger text entire
808
assertNodeAcceptEdit('B.176', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 10, 3, false, 5, 8);
809
assertNodeAcceptEdit('B.177', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 10, 3, false, 5, 8);
810
assertNodeAcceptEdit('B.178', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 10, 3, false, 5, 8);
811
assertNodeAcceptEdit('B.179', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 10, 3, false, 5, 8);
812
assertNodeAcceptEdit('B.180', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 10, 3, true, 8, 8);
813
assertNodeAcceptEdit('B.181', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 10, 3, true, 8, 8);
814
assertNodeAcceptEdit('B.182', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 10, 3, true, 8, 8);
815
assertNodeAcceptEdit('B.183', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 10, 3, true, 8, 8);
816
// replace with smaller text entire
817
assertNodeAcceptEdit('B.184', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 10, 7, false, 5, 12);
818
assertNodeAcceptEdit('B.185', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 10, 7, false, 5, 10);
819
assertNodeAcceptEdit('B.186', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 10, 7, false, 5, 10);
820
assertNodeAcceptEdit('B.187', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 10, 7, false, 5, 12);
821
assertNodeAcceptEdit('B.188', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 10, 7, true, 12, 12);
822
assertNodeAcceptEdit('B.189', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 10, 7, true, 12, 12);
823
assertNodeAcceptEdit('B.190', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 10, 7, true, 12, 12);
824
assertNodeAcceptEdit('B.191', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 10, 7, true, 12, 12);
825
826
}
827
});
828
});
829
830
function printTree(T: IntervalTree): void {
831
if (T.root === SENTINEL) {
832
console.log(`~~ empty`);
833
return;
834
}
835
const out: string[] = [];
836
_printTree(T, T.root, '', 0, out);
837
console.log(out.join(''));
838
}
839
840
function _printTree(T: IntervalTree, n: IntervalNode, indent: string, delta: number, out: string[]): void {
841
out.push(`${indent}[${getNodeColor(n) === NodeColor.Red ? 'R' : 'B'},${n.delta}, ${n.start}->${n.end}, ${n.maxEnd}] : {${delta + n.start}->${delta + n.end}}, maxEnd: ${n.maxEnd + delta}\n`);
842
if (n.left !== SENTINEL) {
843
_printTree(T, n.left, indent + ' ', delta, out);
844
} else {
845
out.push(`${indent} NIL\n`);
846
}
847
if (n.right !== SENTINEL) {
848
_printTree(T, n.right, indent + ' ', delta + n.delta, out);
849
} else {
850
out.push(`${indent} NIL\n`);
851
}
852
}
853
854
//#region Assertion
855
856
function assertTreeInvariants(T: IntervalTree): void {
857
assert(getNodeColor(SENTINEL) === NodeColor.Black);
858
assert(SENTINEL.parent === SENTINEL);
859
assert(SENTINEL.left === SENTINEL);
860
assert(SENTINEL.right === SENTINEL);
861
assert(SENTINEL.start === 0);
862
assert(SENTINEL.end === 0);
863
assert(SENTINEL.delta === 0);
864
assert(T.root.parent === SENTINEL);
865
assertValidTree(T);
866
}
867
868
function depth(n: IntervalNode): number {
869
if (n === SENTINEL) {
870
// The leafs are black
871
return 1;
872
}
873
assert(depth(n.left) === depth(n.right));
874
return (getNodeColor(n) === NodeColor.Black ? 1 : 0) + depth(n.left);
875
}
876
877
function assertValidNode(n: IntervalNode, delta: number): void {
878
if (n === SENTINEL) {
879
return;
880
}
881
882
const l = n.left;
883
const r = n.right;
884
885
if (getNodeColor(n) === NodeColor.Red) {
886
assert(getNodeColor(l) === NodeColor.Black);
887
assert(getNodeColor(r) === NodeColor.Black);
888
}
889
890
let expectedMaxEnd = n.end;
891
if (l !== SENTINEL) {
892
assert(intervalCompare(l.start + delta, l.end + delta, n.start + delta, n.end + delta) <= 0);
893
expectedMaxEnd = Math.max(expectedMaxEnd, l.maxEnd);
894
}
895
if (r !== SENTINEL) {
896
assert(intervalCompare(n.start + delta, n.end + delta, r.start + delta + n.delta, r.end + delta + n.delta) <= 0);
897
expectedMaxEnd = Math.max(expectedMaxEnd, r.maxEnd + n.delta);
898
}
899
assert(n.maxEnd === expectedMaxEnd);
900
901
assertValidNode(l, delta);
902
assertValidNode(r, delta + n.delta);
903
}
904
905
function assertValidTree(T: IntervalTree): void {
906
if (T.root === SENTINEL) {
907
return;
908
}
909
assert(getNodeColor(T.root) === NodeColor.Black);
910
assert(depth(T.root.left) === depth(T.root.right));
911
assertValidNode(T.root, 0);
912
}
913
914
//#endregion
915
916