Path: blob/main/src/vs/editor/test/common/model/intervalTree.test.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import assert from 'assert';6import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';7import { TrackedRangeStickiness } from '../../../common/model.js';8import { IntervalNode, IntervalTree, NodeColor, SENTINEL, getNodeColor, intervalCompare, nodeAcceptEdit, setNodeStickiness } from '../../../common/model/intervalTree.js';910const GENERATE_TESTS = false;11const TEST_COUNT = GENERATE_TESTS ? 10000 : 0;12const PRINT_TREE = false;13const MIN_INTERVAL_START = 1;14const MAX_INTERVAL_END = 100;15const MIN_INSERTS = 1;16const MAX_INSERTS = 30;17const MIN_CHANGE_CNT = 10;18const MAX_CHANGE_CNT = 20;1920suite('IntervalTree 1', () => {2122ensureNoDisposablesAreLeakedInTestSuite();2324class Interval {25_intervalBrand: void = undefined;2627public start: number;28public end: number;2930constructor(start: number, end: number) {31this.start = start;32this.end = end;33}34}3536class Oracle {37public intervals: Interval[];3839constructor() {40this.intervals = [];41}4243public insert(interval: Interval): Interval {44this.intervals.push(interval);45this.intervals.sort((a, b) => {46if (a.start === b.start) {47return a.end - b.end;48}49return a.start - b.start;50});51return interval;52}5354public delete(interval: Interval): void {55for (let i = 0, len = this.intervals.length; i < len; i++) {56if (this.intervals[i] === interval) {57this.intervals.splice(i, 1);58return;59}60}61}6263public search(interval: Interval): Interval[] {64const result: Interval[] = [];65for (let i = 0, len = this.intervals.length; i < len; i++) {66const int = this.intervals[i];67if (int.start <= interval.end && int.end >= interval.start) {68result.push(int);69}70}71return result;72}73}7475class TestState {76private _oracle: Oracle = new Oracle();77private _tree: IntervalTree = new IntervalTree();78private _lastNodeId = -1;79private _treeNodes: Array<IntervalNode | null> = [];80private _oracleNodes: Array<Interval | null> = [];8182public acceptOp(op: IOperation): void {8384if (op.type === 'insert') {85if (PRINT_TREE) {86console.log(`insert: {${JSON.stringify(new Interval(op.begin, op.end))}}`);87}88const nodeId = (++this._lastNodeId);89this._treeNodes[nodeId] = new IntervalNode(null!, op.begin, op.end);90this._tree.insert(this._treeNodes[nodeId]!);91this._oracleNodes[nodeId] = this._oracle.insert(new Interval(op.begin, op.end));92} else if (op.type === 'delete') {93if (PRINT_TREE) {94console.log(`delete: {${JSON.stringify(this._oracleNodes[op.id])}}`);95}96this._tree.delete(this._treeNodes[op.id]!);97this._oracle.delete(this._oracleNodes[op.id]!);9899this._treeNodes[op.id] = null;100this._oracleNodes[op.id] = null;101} else if (op.type === 'change') {102103this._tree.delete(this._treeNodes[op.id]!);104this._treeNodes[op.id]!.reset(0, op.begin, op.end, null!);105this._tree.insert(this._treeNodes[op.id]!);106107this._oracle.delete(this._oracleNodes[op.id]!);108this._oracleNodes[op.id]!.start = op.begin;109this._oracleNodes[op.id]!.end = op.end;110this._oracle.insert(this._oracleNodes[op.id]!);111112} else {113const actualNodes = this._tree.intervalSearch(op.begin, op.end, 0, false, false, 0, false);114const actual = actualNodes.map(n => new Interval(n.cachedAbsoluteStart, n.cachedAbsoluteEnd));115const expected = this._oracle.search(new Interval(op.begin, op.end));116assert.deepStrictEqual(actual, expected);117return;118}119120if (PRINT_TREE) {121printTree(this._tree);122}123124assertTreeInvariants(this._tree);125126const actual = this._tree.getAllInOrder().map(n => new Interval(n.cachedAbsoluteStart, n.cachedAbsoluteEnd));127const expected = this._oracle.intervals;128assert.deepStrictEqual(actual, expected);129}130131public getExistingNodeId(index: number): number {132let currIndex = -1;133for (let i = 0; i < this._treeNodes.length; i++) {134if (this._treeNodes[i] === null) {135continue;136}137currIndex++;138if (currIndex === index) {139return i;140}141}142throw new Error('unexpected');143}144}145146interface IInsertOperation {147type: 'insert';148begin: number;149end: number;150}151152interface IDeleteOperation {153type: 'delete';154id: number;155}156157interface IChangeOperation {158type: 'change';159id: number;160begin: number;161end: number;162}163164interface ISearchOperation {165type: 'search';166begin: number;167end: number;168}169170type IOperation = IInsertOperation | IDeleteOperation | IChangeOperation | ISearchOperation;171172function testIntervalTree(ops: IOperation[]): void {173const state = new TestState();174for (let i = 0; i < ops.length; i++) {175state.acceptOp(ops[i]);176}177}178179function getRandomInt(min: number, max: number): number {180return Math.floor(Math.random() * (max - min + 1)) + min;181}182183function getRandomRange(min: number, max: number): [number, number] {184const begin = getRandomInt(min, max);185let length: number;186if (getRandomInt(1, 10) <= 2) {187// large range188length = getRandomInt(0, max - begin);189} else {190// small range191length = getRandomInt(0, Math.min(max - begin, 10));192}193return [begin, begin + length];194}195196class AutoTest {197private _ops: IOperation[] = [];198private _state: TestState = new TestState();199private _insertCnt: number;200private _deleteCnt: number;201private _changeCnt: number;202203constructor() {204this._insertCnt = getRandomInt(MIN_INSERTS, MAX_INSERTS);205this._changeCnt = getRandomInt(MIN_CHANGE_CNT, MAX_CHANGE_CNT);206this._deleteCnt = 0;207}208209private _doRandomInsert(): void {210const range = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END);211this._run({212type: 'insert',213begin: range[0],214end: range[1]215});216}217218private _doRandomDelete(): void {219const idx = getRandomInt(Math.floor(this._deleteCnt / 2), this._deleteCnt - 1);220this._run({221type: 'delete',222id: this._state.getExistingNodeId(idx)223});224}225226private _doRandomChange(): void {227const idx = getRandomInt(0, this._deleteCnt - 1);228const range = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END);229this._run({230type: 'change',231id: this._state.getExistingNodeId(idx),232begin: range[0],233end: range[1]234});235}236237public run() {238while (this._insertCnt > 0 || this._deleteCnt > 0 || this._changeCnt > 0) {239if (this._insertCnt > 0) {240this._doRandomInsert();241this._insertCnt--;242this._deleteCnt++;243} else if (this._changeCnt > 0) {244this._doRandomChange();245this._changeCnt--;246} else {247this._doRandomDelete();248this._deleteCnt--;249}250251// Let's also search for something...252const searchRange = getRandomRange(MIN_INTERVAL_START, MAX_INTERVAL_END);253this._run({254type: 'search',255begin: searchRange[0],256end: searchRange[1]257});258}259}260261private _run(op: IOperation): void {262this._ops.push(op);263this._state.acceptOp(op);264}265266public print(): void {267console.log(`testIntervalTree(${JSON.stringify(this._ops)})`);268}269270}271272suite('generated', () => {273test('gen01', () => {274testIntervalTree([275{ type: 'insert', begin: 28, end: 35 },276{ type: 'insert', begin: 52, end: 54 },277{ type: 'insert', begin: 63, end: 69 }278]);279});280281test('gen02', () => {282testIntervalTree([283{ type: 'insert', begin: 80, end: 89 },284{ type: 'insert', begin: 92, end: 100 },285{ type: 'insert', begin: 99, end: 99 }286]);287});288289test('gen03', () => {290testIntervalTree([291{ type: 'insert', begin: 89, end: 96 },292{ type: 'insert', begin: 71, end: 74 },293{ type: 'delete', id: 1 }294]);295});296297test('gen04', () => {298testIntervalTree([299{ type: 'insert', begin: 44, end: 46 },300{ type: 'insert', begin: 85, end: 88 },301{ type: 'delete', id: 0 }302]);303});304305test('gen05', () => {306testIntervalTree([307{ type: 'insert', begin: 82, end: 90 },308{ type: 'insert', begin: 69, end: 73 },309{ type: 'delete', id: 0 },310{ type: 'delete', id: 1 }311]);312});313314test('gen06', () => {315testIntervalTree([316{ type: 'insert', begin: 41, end: 63 },317{ type: 'insert', begin: 98, end: 98 },318{ type: 'insert', begin: 47, end: 51 },319{ type: 'delete', id: 2 }320]);321});322323test('gen07', () => {324testIntervalTree([325{ type: 'insert', begin: 24, end: 26 },326{ type: 'insert', begin: 11, end: 28 },327{ type: 'insert', begin: 27, end: 30 },328{ type: 'insert', begin: 80, end: 85 },329{ type: 'delete', id: 1 }330]);331});332333test('gen08', () => {334testIntervalTree([335{ type: 'insert', begin: 100, end: 100 },336{ type: 'insert', begin: 100, end: 100 }337]);338});339340test('gen09', () => {341testIntervalTree([342{ type: 'insert', begin: 58, end: 65 },343{ type: 'insert', begin: 82, end: 96 },344{ type: 'insert', begin: 58, end: 65 }345]);346});347348test('gen10', () => {349testIntervalTree([350{ type: 'insert', begin: 32, end: 40 },351{ type: 'insert', begin: 25, end: 29 },352{ type: 'insert', begin: 24, end: 32 }353]);354});355356test('gen11', () => {357testIntervalTree([358{ type: 'insert', begin: 25, end: 70 },359{ type: 'insert', begin: 99, end: 100 },360{ type: 'insert', begin: 46, end: 51 },361{ type: 'insert', begin: 57, end: 57 },362{ type: 'delete', id: 2 }363]);364});365366test('gen12', () => {367testIntervalTree([368{ type: 'insert', begin: 20, end: 26 },369{ type: 'insert', begin: 10, end: 18 },370{ type: 'insert', begin: 99, end: 99 },371{ type: 'insert', begin: 37, end: 59 },372{ type: 'delete', id: 2 }373]);374});375376test('gen13', () => {377testIntervalTree([378{ type: 'insert', begin: 3, end: 91 },379{ type: 'insert', begin: 57, end: 57 },380{ type: 'insert', begin: 35, end: 44 },381{ type: 'insert', begin: 72, end: 81 },382{ type: 'delete', id: 2 }383]);384});385386test('gen14', () => {387testIntervalTree([388{ type: 'insert', begin: 58, end: 61 },389{ type: 'insert', begin: 34, end: 35 },390{ type: 'insert', begin: 56, end: 62 },391{ type: 'insert', begin: 69, end: 78 },392{ type: 'delete', id: 0 }393]);394});395396test('gen15', () => {397testIntervalTree([398{ type: 'insert', begin: 63, end: 69 },399{ type: 'insert', begin: 17, end: 24 },400{ type: 'insert', begin: 3, end: 13 },401{ type: 'insert', begin: 84, end: 94 },402{ type: 'insert', begin: 18, end: 23 },403{ type: 'insert', begin: 96, end: 98 },404{ type: 'delete', id: 1 }405]);406});407408test('gen16', () => {409testIntervalTree([410{ type: 'insert', begin: 27, end: 27 },411{ type: 'insert', begin: 42, end: 87 },412{ type: 'insert', begin: 42, end: 49 },413{ type: 'insert', begin: 69, end: 71 },414{ type: 'insert', begin: 20, end: 27 },415{ type: 'insert', begin: 8, end: 9 },416{ type: 'insert', begin: 42, end: 49 },417{ type: 'delete', id: 1 }418]);419});420421test('gen17', () => {422testIntervalTree([423{ type: 'insert', begin: 21, end: 23 },424{ type: 'insert', begin: 83, end: 87 },425{ type: 'insert', begin: 56, end: 58 },426{ type: 'insert', begin: 1, end: 55 },427{ type: 'insert', begin: 56, end: 59 },428{ type: 'insert', begin: 58, end: 60 },429{ type: 'insert', begin: 56, end: 65 },430{ type: 'delete', id: 1 },431{ type: 'delete', id: 0 },432{ type: 'delete', id: 6 }433]);434});435436test('gen18', () => {437testIntervalTree([438{ type: 'insert', begin: 25, end: 25 },439{ type: 'insert', begin: 67, end: 79 },440{ type: 'delete', id: 0 },441{ type: 'search', begin: 65, end: 75 }442]);443});444445test('force delta overflow', () => {446// Search the IntervalNode ctor for FORCE_OVERFLOWING_TEST447// to force that this test leads to a delta normalization448testIntervalTree([449{ type: 'insert', begin: 686081138593427, end: 733009856502260 },450{ type: 'insert', begin: 591031326181669, end: 591031326181672 },451{ type: 'insert', begin: 940037682731896, end: 940037682731903 },452{ type: 'insert', begin: 598413641151120, end: 598413641151128 },453{ type: 'insert', begin: 800564156553344, end: 800564156553351 },454{ type: 'insert', begin: 894198957565481, end: 894198957565491 }455]);456});457});458459// TEST_COUNT = 0;460// PRINT_TREE = true;461462for (let i = 0; i < TEST_COUNT; i++) {463if (i % 100 === 0) {464console.log(`TEST ${i + 1}/${TEST_COUNT}`);465}466const test = new AutoTest();467468try {469test.run();470} catch (err) {471console.log(err);472test.print();473return;474}475}476477suite('searching', () => {478479function createCormenTree(): IntervalTree {480const r = new IntervalTree();481const data: [number, number][] = [482[16, 21],483[8, 9],484[25, 30],485[5, 8],486[15, 23],487[17, 19],488[26, 26],489[0, 3],490[6, 10],491[19, 20]492];493data.forEach((int) => {494const node = new IntervalNode(null!, int[0], int[1]);495r.insert(node);496});497return r;498}499500const T = createCormenTree();501502function assertIntervalSearch(start: number, end: number, expected: [number, number][]): void {503const actualNodes = T.intervalSearch(start, end, 0, false, false, 0, false);504const actual = actualNodes.map((n) => <[number, number]>[n.cachedAbsoluteStart, n.cachedAbsoluteEnd]);505assert.deepStrictEqual(actual, expected);506}507508test('cormen 1->2', () => {509assertIntervalSearch(5101, 2,511[512[0, 3],513]514);515});516517test('cormen 4->8', () => {518assertIntervalSearch(5194, 8,520[521[5, 8],522[6, 10],523[8, 9],524]525);526});527528test('cormen 10->15', () => {529assertIntervalSearch(53010, 15,531[532[6, 10],533[15, 23],534]535);536});537538test('cormen 21->25', () => {539assertIntervalSearch(54021, 25,541[542[15, 23],543[16, 21],544[25, 30],545]546);547});548549test('cormen 24->24', () => {550assertIntervalSearch(55124, 24,552[553]554);555});556});557});558559suite('IntervalTree 2', () => {560561ensureNoDisposablesAreLeakedInTestSuite();562563function assertNodeAcceptEdit(msg: string, nodeStart: number, nodeEnd: number, nodeStickiness: TrackedRangeStickiness, start: number, end: number, textLength: number, forceMoveMarkers: boolean, expectedNodeStart: number, expectedNodeEnd: number): void {564const node = new IntervalNode('', nodeStart, nodeEnd);565setNodeStickiness(node, nodeStickiness);566nodeAcceptEdit(node, start, end, textLength, forceMoveMarkers);567assert.deepStrictEqual([node.start, node.end], [expectedNodeStart, expectedNodeEnd], msg);568}569570test('nodeAcceptEdit', () => {571// A. collapsed decoration572{573// no-op574assertNodeAcceptEdit('A.000', 0, 0, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 0, false, 0, 0);575assertNodeAcceptEdit('A.001', 0, 0, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 0, false, 0, 0);576assertNodeAcceptEdit('A.002', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 0, false, 0, 0);577assertNodeAcceptEdit('A.003', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 0, false, 0, 0);578assertNodeAcceptEdit('A.004', 0, 0, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 0, true, 0, 0);579assertNodeAcceptEdit('A.005', 0, 0, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 0, true, 0, 0);580assertNodeAcceptEdit('A.006', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 0, true, 0, 0);581assertNodeAcceptEdit('A.007', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 0, true, 0, 0);582// insertion583assertNodeAcceptEdit('A.008', 0, 0, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 1, false, 0, 1);584assertNodeAcceptEdit('A.009', 0, 0, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 1, false, 1, 1);585assertNodeAcceptEdit('A.010', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 1, false, 0, 0);586assertNodeAcceptEdit('A.011', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 1, false, 1, 1);587assertNodeAcceptEdit('A.012', 0, 0, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 1, true, 1, 1);588assertNodeAcceptEdit('A.013', 0, 0, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 1, true, 1, 1);589assertNodeAcceptEdit('A.014', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 1, true, 1, 1);590assertNodeAcceptEdit('A.015', 0, 0, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 1, true, 1, 1);591}592593// B. non collapsed decoration594{595// no-op596assertNodeAcceptEdit('B.000', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 0, false, 0, 5);597assertNodeAcceptEdit('B.001', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 0, false, 0, 5);598assertNodeAcceptEdit('B.002', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 0, false, 0, 5);599assertNodeAcceptEdit('B.003', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 0, false, 0, 5);600assertNodeAcceptEdit('B.004', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 0, true, 0, 5);601assertNodeAcceptEdit('B.005', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 0, true, 0, 5);602assertNodeAcceptEdit('B.006', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 0, true, 0, 5);603assertNodeAcceptEdit('B.007', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 0, true, 0, 5);604// insertion at start605assertNodeAcceptEdit('B.008', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 1, false, 0, 6);606assertNodeAcceptEdit('B.009', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 1, false, 1, 6);607assertNodeAcceptEdit('B.010', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 1, false, 0, 6);608assertNodeAcceptEdit('B.011', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 1, false, 1, 6);609assertNodeAcceptEdit('B.012', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 0, 0, 1, true, 1, 6);610assertNodeAcceptEdit('B.013', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 0, 0, 1, true, 1, 6);611assertNodeAcceptEdit('B.014', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 0, 0, 1, true, 1, 6);612assertNodeAcceptEdit('B.015', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 0, 0, 1, true, 1, 6);613// insertion in middle614assertNodeAcceptEdit('B.016', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 2, 2, 1, false, 0, 6);615assertNodeAcceptEdit('B.017', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 2, 2, 1, false, 0, 6);616assertNodeAcceptEdit('B.018', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 2, 2, 1, false, 0, 6);617assertNodeAcceptEdit('B.019', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 2, 2, 1, false, 0, 6);618assertNodeAcceptEdit('B.020', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 2, 2, 1, true, 0, 6);619assertNodeAcceptEdit('B.021', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 2, 2, 1, true, 0, 6);620assertNodeAcceptEdit('B.022', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 2, 2, 1, true, 0, 6);621assertNodeAcceptEdit('B.023', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 2, 2, 1, true, 0, 6);622// insertion at end623assertNodeAcceptEdit('B.024', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 5, 1, false, 0, 6);624assertNodeAcceptEdit('B.025', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 5, 1, false, 0, 5);625assertNodeAcceptEdit('B.026', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 5, 1, false, 0, 5);626assertNodeAcceptEdit('B.027', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 5, 1, false, 0, 6);627assertNodeAcceptEdit('B.028', 0, 5, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 5, 1, true, 0, 6);628assertNodeAcceptEdit('B.029', 0, 5, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 5, 1, true, 0, 6);629assertNodeAcceptEdit('B.030', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 5, 1, true, 0, 6);630assertNodeAcceptEdit('B.031', 0, 5, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 5, 1, true, 0, 6);631632// replace with larger text until start633assertNodeAcceptEdit('B.032', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 5, 2, false, 5, 11);634assertNodeAcceptEdit('B.033', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 5, 2, false, 6, 11);635assertNodeAcceptEdit('B.034', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 5, 2, false, 5, 11);636assertNodeAcceptEdit('B.035', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 5, 2, false, 6, 11);637assertNodeAcceptEdit('B.036', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 5, 2, true, 6, 11);638assertNodeAcceptEdit('B.037', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 5, 2, true, 6, 11);639assertNodeAcceptEdit('B.038', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 5, 2, true, 6, 11);640assertNodeAcceptEdit('B.039', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 5, 2, true, 6, 11);641// replace with smaller text until start642assertNodeAcceptEdit('B.040', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 3, 5, 1, false, 4, 9);643assertNodeAcceptEdit('B.041', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 3, 5, 1, false, 4, 9);644assertNodeAcceptEdit('B.042', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 3, 5, 1, false, 4, 9);645assertNodeAcceptEdit('B.043', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 3, 5, 1, false, 4, 9);646assertNodeAcceptEdit('B.044', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 3, 5, 1, true, 4, 9);647assertNodeAcceptEdit('B.045', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 3, 5, 1, true, 4, 9);648assertNodeAcceptEdit('B.046', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 3, 5, 1, true, 4, 9);649assertNodeAcceptEdit('B.047', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 3, 5, 1, true, 4, 9);650651// replace with larger text select start652assertNodeAcceptEdit('B.048', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 3, false, 5, 11);653assertNodeAcceptEdit('B.049', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 3, false, 5, 11);654assertNodeAcceptEdit('B.050', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 3, false, 5, 11);655assertNodeAcceptEdit('B.051', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 3, false, 5, 11);656assertNodeAcceptEdit('B.052', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 3, true, 7, 11);657assertNodeAcceptEdit('B.053', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 3, true, 7, 11);658assertNodeAcceptEdit('B.054', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 3, true, 7, 11);659assertNodeAcceptEdit('B.055', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 3, true, 7, 11);660// replace with smaller text select start661assertNodeAcceptEdit('B.056', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 1, false, 5, 9);662assertNodeAcceptEdit('B.057', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 1, false, 5, 9);663assertNodeAcceptEdit('B.058', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 1, false, 5, 9);664assertNodeAcceptEdit('B.059', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 1, false, 5, 9);665assertNodeAcceptEdit('B.060', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 1, true, 5, 9);666assertNodeAcceptEdit('B.061', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 1, true, 5, 9);667assertNodeAcceptEdit('B.062', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 1, true, 5, 9);668assertNodeAcceptEdit('B.063', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 1, true, 5, 9);669670// replace with larger text from start671assertNodeAcceptEdit('B.064', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 6, 2, false, 5, 11);672assertNodeAcceptEdit('B.065', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 6, 2, false, 5, 11);673assertNodeAcceptEdit('B.066', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 6, 2, false, 5, 11);674assertNodeAcceptEdit('B.067', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 6, 2, false, 5, 11);675assertNodeAcceptEdit('B.068', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 6, 2, true, 7, 11);676assertNodeAcceptEdit('B.069', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 6, 2, true, 7, 11);677assertNodeAcceptEdit('B.070', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 6, 2, true, 7, 11);678assertNodeAcceptEdit('B.071', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 6, 2, true, 7, 11);679// replace with smaller text from start680assertNodeAcceptEdit('B.072', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 7, 1, false, 5, 9);681assertNodeAcceptEdit('B.073', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 7, 1, false, 5, 9);682assertNodeAcceptEdit('B.074', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 7, 1, false, 5, 9);683assertNodeAcceptEdit('B.075', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 7, 1, false, 5, 9);684assertNodeAcceptEdit('B.076', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 7, 1, true, 6, 9);685assertNodeAcceptEdit('B.077', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 7, 1, true, 6, 9);686assertNodeAcceptEdit('B.078', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 7, 1, true, 6, 9);687assertNodeAcceptEdit('B.079', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 7, 1, true, 6, 9);688689// replace with larger text to end690assertNodeAcceptEdit('B.080', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 10, 2, false, 5, 11);691assertNodeAcceptEdit('B.081', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 10, 2, false, 5, 10);692assertNodeAcceptEdit('B.082', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 10, 2, false, 5, 10);693assertNodeAcceptEdit('B.083', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 10, 2, false, 5, 11);694assertNodeAcceptEdit('B.084', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 10, 2, true, 5, 11);695assertNodeAcceptEdit('B.085', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 10, 2, true, 5, 11);696assertNodeAcceptEdit('B.086', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 10, 2, true, 5, 11);697assertNodeAcceptEdit('B.087', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 10, 2, true, 5, 11);698// replace with smaller text to end699assertNodeAcceptEdit('B.088', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 8, 10, 1, false, 5, 9);700assertNodeAcceptEdit('B.089', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 8, 10, 1, false, 5, 9);701assertNodeAcceptEdit('B.090', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 8, 10, 1, false, 5, 9);702assertNodeAcceptEdit('B.091', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 8, 10, 1, false, 5, 9);703assertNodeAcceptEdit('B.092', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 8, 10, 1, true, 5, 9);704assertNodeAcceptEdit('B.093', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 8, 10, 1, true, 5, 9);705assertNodeAcceptEdit('B.094', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 8, 10, 1, true, 5, 9);706assertNodeAcceptEdit('B.095', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 8, 10, 1, true, 5, 9);707708// replace with larger text select end709assertNodeAcceptEdit('B.096', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 3, false, 5, 10);710assertNodeAcceptEdit('B.097', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 3, false, 5, 10);711assertNodeAcceptEdit('B.098', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 3, false, 5, 10);712assertNodeAcceptEdit('B.099', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 3, false, 5, 10);713assertNodeAcceptEdit('B.100', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 3, true, 5, 12);714assertNodeAcceptEdit('B.101', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 3, true, 5, 12);715assertNodeAcceptEdit('B.102', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 3, true, 5, 12);716assertNodeAcceptEdit('B.103', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 3, true, 5, 12);717// replace with smaller text select end718assertNodeAcceptEdit('B.104', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 1, false, 5, 10);719assertNodeAcceptEdit('B.105', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 1, false, 5, 10);720assertNodeAcceptEdit('B.106', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 1, false, 5, 10);721assertNodeAcceptEdit('B.107', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 1, false, 5, 10);722assertNodeAcceptEdit('B.108', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 1, true, 5, 10);723assertNodeAcceptEdit('B.109', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 1, true, 5, 10);724assertNodeAcceptEdit('B.110', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 1, true, 5, 10);725assertNodeAcceptEdit('B.111', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 1, true, 5, 10);726727// replace with larger text from end728assertNodeAcceptEdit('B.112', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 11, 3, false, 5, 10);729assertNodeAcceptEdit('B.113', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 11, 3, false, 5, 10);730assertNodeAcceptEdit('B.114', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 11, 3, false, 5, 10);731assertNodeAcceptEdit('B.115', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 11, 3, false, 5, 10);732assertNodeAcceptEdit('B.116', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 11, 3, true, 5, 13);733assertNodeAcceptEdit('B.117', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 11, 3, true, 5, 13);734assertNodeAcceptEdit('B.118', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 11, 3, true, 5, 13);735assertNodeAcceptEdit('B.119', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 11, 3, true, 5, 13);736// replace with smaller text from end737assertNodeAcceptEdit('B.120', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 12, 1, false, 5, 10);738assertNodeAcceptEdit('B.121', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 12, 1, false, 5, 10);739assertNodeAcceptEdit('B.122', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 12, 1, false, 5, 10);740assertNodeAcceptEdit('B.123', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 12, 1, false, 5, 10);741assertNodeAcceptEdit('B.124', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 12, 1, true, 5, 11);742assertNodeAcceptEdit('B.125', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 12, 1, true, 5, 11);743assertNodeAcceptEdit('B.126', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 12, 1, true, 5, 11);744assertNodeAcceptEdit('B.127', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 12, 1, true, 5, 11);745746// delete until start747assertNodeAcceptEdit('B.128', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 5, 0, false, 4, 9);748assertNodeAcceptEdit('B.129', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 5, 0, false, 4, 9);749assertNodeAcceptEdit('B.130', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 5, 0, false, 4, 9);750assertNodeAcceptEdit('B.131', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 5, 0, false, 4, 9);751assertNodeAcceptEdit('B.132', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 5, 0, true, 4, 9);752assertNodeAcceptEdit('B.133', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 5, 0, true, 4, 9);753assertNodeAcceptEdit('B.134', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 5, 0, true, 4, 9);754assertNodeAcceptEdit('B.135', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 5, 0, true, 4, 9);755756// delete select start757assertNodeAcceptEdit('B.136', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 0, false, 4, 8);758assertNodeAcceptEdit('B.137', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 0, false, 4, 8);759assertNodeAcceptEdit('B.138', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 0, false, 4, 8);760assertNodeAcceptEdit('B.139', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 0, false, 4, 8);761assertNodeAcceptEdit('B.140', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 4, 6, 0, true, 4, 8);762assertNodeAcceptEdit('B.141', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 4, 6, 0, true, 4, 8);763assertNodeAcceptEdit('B.142', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 4, 6, 0, true, 4, 8);764assertNodeAcceptEdit('B.143', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 4, 6, 0, true, 4, 8);765766// delete from start767assertNodeAcceptEdit('B.144', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 6, 0, false, 5, 9);768assertNodeAcceptEdit('B.145', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 6, 0, false, 5, 9);769assertNodeAcceptEdit('B.146', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 6, 0, false, 5, 9);770assertNodeAcceptEdit('B.147', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 6, 0, false, 5, 9);771assertNodeAcceptEdit('B.148', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 6, 0, true, 5, 9);772assertNodeAcceptEdit('B.149', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 6, 0, true, 5, 9);773assertNodeAcceptEdit('B.150', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 6, 0, true, 5, 9);774assertNodeAcceptEdit('B.151', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 6, 0, true, 5, 9);775776// delete to end777assertNodeAcceptEdit('B.152', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 10, 0, false, 5, 9);778assertNodeAcceptEdit('B.153', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 10, 0, false, 5, 9);779assertNodeAcceptEdit('B.154', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 10, 0, false, 5, 9);780assertNodeAcceptEdit('B.155', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 10, 0, false, 5, 9);781assertNodeAcceptEdit('B.156', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 10, 0, true, 5, 9);782assertNodeAcceptEdit('B.157', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 10, 0, true, 5, 9);783assertNodeAcceptEdit('B.158', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 10, 0, true, 5, 9);784assertNodeAcceptEdit('B.159', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 10, 0, true, 5, 9);785786// delete select end787assertNodeAcceptEdit('B.160', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 0, false, 5, 9);788assertNodeAcceptEdit('B.161', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 0, false, 5, 9);789assertNodeAcceptEdit('B.162', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 0, false, 5, 9);790assertNodeAcceptEdit('B.163', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 0, false, 5, 9);791assertNodeAcceptEdit('B.164', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 9, 11, 0, true, 5, 9);792assertNodeAcceptEdit('B.165', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 9, 11, 0, true, 5, 9);793assertNodeAcceptEdit('B.166', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 9, 11, 0, true, 5, 9);794assertNodeAcceptEdit('B.167', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 9, 11, 0, true, 5, 9);795796// delete from end797assertNodeAcceptEdit('B.168', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 11, 0, false, 5, 10);798assertNodeAcceptEdit('B.169', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 11, 0, false, 5, 10);799assertNodeAcceptEdit('B.170', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 11, 0, false, 5, 10);800assertNodeAcceptEdit('B.171', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 11, 0, false, 5, 10);801assertNodeAcceptEdit('B.172', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 10, 11, 0, true, 5, 10);802assertNodeAcceptEdit('B.173', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 10, 11, 0, true, 5, 10);803assertNodeAcceptEdit('B.174', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 10, 11, 0, true, 5, 10);804assertNodeAcceptEdit('B.175', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 10, 11, 0, true, 5, 10);805806// replace with larger text entire807assertNodeAcceptEdit('B.176', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 10, 3, false, 5, 8);808assertNodeAcceptEdit('B.177', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 10, 3, false, 5, 8);809assertNodeAcceptEdit('B.178', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 10, 3, false, 5, 8);810assertNodeAcceptEdit('B.179', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 10, 3, false, 5, 8);811assertNodeAcceptEdit('B.180', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 10, 3, true, 8, 8);812assertNodeAcceptEdit('B.181', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 10, 3, true, 8, 8);813assertNodeAcceptEdit('B.182', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 10, 3, true, 8, 8);814assertNodeAcceptEdit('B.183', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 10, 3, true, 8, 8);815// replace with smaller text entire816assertNodeAcceptEdit('B.184', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 10, 7, false, 5, 12);817assertNodeAcceptEdit('B.185', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 10, 7, false, 5, 10);818assertNodeAcceptEdit('B.186', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 10, 7, false, 5, 10);819assertNodeAcceptEdit('B.187', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 10, 7, false, 5, 12);820assertNodeAcceptEdit('B.188', 5, 10, TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges, 5, 10, 7, true, 12, 12);821assertNodeAcceptEdit('B.189', 5, 10, TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, 5, 10, 7, true, 12, 12);822assertNodeAcceptEdit('B.190', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingBefore, 5, 10, 7, true, 12, 12);823assertNodeAcceptEdit('B.191', 5, 10, TrackedRangeStickiness.GrowsOnlyWhenTypingAfter, 5, 10, 7, true, 12, 12);824825}826});827});828829function printTree(T: IntervalTree): void {830if (T.root === SENTINEL) {831console.log(`~~ empty`);832return;833}834const out: string[] = [];835_printTree(T, T.root, '', 0, out);836console.log(out.join(''));837}838839function _printTree(T: IntervalTree, n: IntervalNode, indent: string, delta: number, out: string[]): void {840out.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`);841if (n.left !== SENTINEL) {842_printTree(T, n.left, indent + ' ', delta, out);843} else {844out.push(`${indent} NIL\n`);845}846if (n.right !== SENTINEL) {847_printTree(T, n.right, indent + ' ', delta + n.delta, out);848} else {849out.push(`${indent} NIL\n`);850}851}852853//#region Assertion854855function assertTreeInvariants(T: IntervalTree): void {856assert(getNodeColor(SENTINEL) === NodeColor.Black);857assert(SENTINEL.parent === SENTINEL);858assert(SENTINEL.left === SENTINEL);859assert(SENTINEL.right === SENTINEL);860assert(SENTINEL.start === 0);861assert(SENTINEL.end === 0);862assert(SENTINEL.delta === 0);863assert(T.root.parent === SENTINEL);864assertValidTree(T);865}866867function depth(n: IntervalNode): number {868if (n === SENTINEL) {869// The leafs are black870return 1;871}872assert(depth(n.left) === depth(n.right));873return (getNodeColor(n) === NodeColor.Black ? 1 : 0) + depth(n.left);874}875876function assertValidNode(n: IntervalNode, delta: number): void {877if (n === SENTINEL) {878return;879}880881const l = n.left;882const r = n.right;883884if (getNodeColor(n) === NodeColor.Red) {885assert(getNodeColor(l) === NodeColor.Black);886assert(getNodeColor(r) === NodeColor.Black);887}888889let expectedMaxEnd = n.end;890if (l !== SENTINEL) {891assert(intervalCompare(l.start + delta, l.end + delta, n.start + delta, n.end + delta) <= 0);892expectedMaxEnd = Math.max(expectedMaxEnd, l.maxEnd);893}894if (r !== SENTINEL) {895assert(intervalCompare(n.start + delta, n.end + delta, r.start + delta + n.delta, r.end + delta + n.delta) <= 0);896expectedMaxEnd = Math.max(expectedMaxEnd, r.maxEnd + n.delta);897}898assert(n.maxEnd === expectedMaxEnd);899900assertValidNode(l, delta);901assertValidNode(r, delta + n.delta);902}903904function assertValidTree(T: IntervalTree): void {905if (T.root === SENTINEL) {906return;907}908assert(getNodeColor(T.root) === NodeColor.Black);909assert(depth(T.root.left) === depth(T.root.right));910assertValidNode(T.root, 0);911}912913//#endregion914915916