chrome-devtools-frontend
Version:
Chrome DevTools UI
462 lines (413 loc) • 27.4 kB
text/typescript
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as TextUtils from './text_utils.js';
interface ExpectedTextRange {
startLine: number;
startColumn: number;
endLine: number;
endColumn: number;
}
function assertIsTextRangeAndEqualsRange(
range: TextUtils.TextRange.TextRange, expectedRange: ExpectedTextRange, description: string) {
const prefix = description.length ? `${description}, but ` : '';
assert.instanceOf(range, TextUtils.TextRange.TextRange, `${prefix}range is not a TextUtils.TextRange.TextRange`);
assert.strictEqual(range.startLine, expectedRange.startLine, `${prefix}range's startLine differs from expectation`);
assert.strictEqual(
range.startColumn, expectedRange.startColumn, `${prefix}range's startColumn differs from expectation`);
assert.strictEqual(range.endLine, expectedRange.endLine, `${prefix}range's endLine differs from expectation`);
assert.strictEqual(range.endColumn, expectedRange.endColumn, `${prefix}range's endColumn differs from expectation`);
}
function assertIsUnitTextRange(
range: TextUtils.TextRange.TextRange, line: number, column: number, description: string) {
const prefix = description.length ? `${description}, but ` : '';
assert.instanceOf(range, TextUtils.TextRange.TextRange, `${prefix}range is not a TextUtils.TextRange.TextRange`);
assert.strictEqual(range.startLine, range.endLine, `${prefix}the range is not a unit range: start/end lines differ`);
assert.strictEqual(
range.startColumn, range.endColumn, `${prefix}the range is not a unit range: start/end columns differ`);
assert.strictEqual(range.startLine, line, `${prefix}the line was not set correctly`);
assert.strictEqual(range.startColumn, column, `${prefix}the column was not set correctly`);
}
describe('TextRange', () => {
it('can be instantiated successfully', () => {
const startLine = 1;
const startColumn = 2;
const endLine = 3;
const endColumn = 4;
const textRange = new TextUtils.TextRange.TextRange(startLine, startColumn, endLine, endColumn);
assert.strictEqual(textRange.startLine, startLine, 'the start line was not set or retrieved correctly');
assert.strictEqual(textRange.startColumn, startColumn, 'the start column was not set or retrieved correctly');
assert.strictEqual(textRange.endLine, endLine, 'the end line was not set or retrieved correctly');
assert.strictEqual(textRange.endColumn, endColumn, 'the end column was not set or retrieved correctly');
});
it('can be created from a location', () => {
const line = 1;
const column = 2;
const textRange = TextUtils.TextRange.TextRange.createFromLocation(line, column);
assertIsUnitTextRange(textRange, line, column, 'range created from a location should be a unit range');
});
it('can be created from a serialized text range', () => {
const range = {startLine: 1, startColumn: 2, endLine: 3, endColumn: 4};
const textRange = TextUtils.TextRange.TextRange.fromObject(range);
assertIsTextRangeAndEqualsRange(textRange, range, 'deserializing should preserve the range');
const serializedRange = textRange.serializeToObject();
const deserializedTextRange = TextUtils.TextRange.TextRange.fromObject(serializedRange);
assertIsTextRangeAndEqualsRange(deserializedTextRange, range, 'deserializing should preserve the range');
});
it('can be checked for emptiness', () => {
const textRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 1, endColumn: 2});
assert.isTrue(textRange.isEmpty(), 'the range was non-empty');
});
describe('immediatelyPrecedes()', () => {
it('can handle non-range inputs', () => {
const textRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
assert.isFalse(textRange.immediatelyPrecedes(), 'invalid ranges should not be judged as immediatelly preceeding');
});
it('can judge immediate preceedence correctly', () => {
const textRangeA =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
const textRangeB =
TextUtils.TextRange.TextRange.fromObject({startLine: 3, startColumn: 4, endLine: 5, endColumn: 6});
const textRangeC =
TextUtils.TextRange.TextRange.fromObject({startLine: 5, startColumn: 6, endLine: 7, endColumn: 8});
assert.isTrue(textRangeA.immediatelyPrecedes(textRangeB), 'range A should immediatelly preceed range B');
assert.isTrue(textRangeB.immediatelyPrecedes(textRangeC), 'range B should immediatelly preceed range C');
assert.isFalse(textRangeB.immediatelyPrecedes(textRangeA), 'range B should not immediatelly preceed range A');
assert.isFalse(textRangeA.immediatelyPrecedes(textRangeC), 'range A should not immediatelly preceed range C');
});
});
describe('immediatelyFollows()', () => {
it('can handle non-range inputs', () => {
const textRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
assert.isFalse(textRange.immediatelyFollows(), 'invalid ranges should not be judged as \'immediatelly follows\'');
});
it('can judge \'immediatelly follows\' relationship correctly', () => {
const textRangeA =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
const textRangeB =
TextUtils.TextRange.TextRange.fromObject({startLine: 3, startColumn: 4, endLine: 5, endColumn: 6});
const textRangeC =
TextUtils.TextRange.TextRange.fromObject({startLine: 5, startColumn: 6, endLine: 7, endColumn: 8});
assert.isTrue(textRangeB.immediatelyFollows(textRangeA), 'range B should immediatelly follow range A');
assert.isTrue(textRangeC.immediatelyFollows(textRangeB), 'range C should immediatelly follow range B');
assert.isFalse(textRangeA.immediatelyFollows(textRangeB), 'range A should not immediatelly follow range B');
assert.isFalse(textRangeC.immediatelyFollows(textRangeA), 'range C should not immediatelly follow range A');
});
});
describe('follows()', () => {
it('can judge \'follows\' relationship correctly', () => {
const textRangeA =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
const textRangeB =
TextUtils.TextRange.TextRange.fromObject({startLine: 3, startColumn: 4, endLine: 5, endColumn: 6});
const textRangeC =
TextUtils.TextRange.TextRange.fromObject({startLine: 5, startColumn: 6, endLine: 7, endColumn: 8});
assert.isTrue(textRangeB.follows(textRangeA), 'range B should follow range A');
assert.isTrue(textRangeC.follows(textRangeB), 'range C should follow range B');
assert.isFalse(textRangeA.follows(textRangeB), 'range A should not follow range B');
assert.isTrue(textRangeC.follows(textRangeA), 'range C should follow range A');
});
});
it('can report the line count', () => {
const textRangeA =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 1, endColumn: 2});
const textRangeB =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 2, endColumn: 2});
const textRangeC =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 12, endColumn: 2});
assert.strictEqual(textRangeA.linesCount, 0, 'line count was wrong');
assert.strictEqual(textRangeB.linesCount, 1, 'line count was wrong');
assert.strictEqual(textRangeC.linesCount, 11, 'line count was wrong');
});
it('can be collapsed to start', () => {
const rangeA = {startLine: 1, startColumn: 2, endLine: 1, endColumn: 2};
const textRangeA = TextUtils.TextRange.TextRange.fromObject(rangeA);
const rangeB = {startLine: 4, startColumn: 2, endLine: 2, endColumn: 2};
const textRangeB = TextUtils.TextRange.TextRange.fromObject(rangeB);
const textRangeACollapsed = textRangeA.collapseToStart();
assertIsUnitTextRange(
textRangeACollapsed, rangeA.startLine, rangeA.startColumn,
'collapsing to start should produce a unit range at start');
const textRangeBCollapsed = textRangeB.collapseToStart();
assertIsUnitTextRange(
textRangeBCollapsed, rangeB.startLine, rangeB.startColumn,
'collapsing to start should produce a unit range at start');
assertIsTextRangeAndEqualsRange(textRangeA, rangeA, 'original TextUtils.TextRange.TextRange should be unchanged');
assertIsTextRangeAndEqualsRange(textRangeB, rangeB, 'original TextUtils.TextRange.TextRange should be unchanged');
});
it('can be collapsed to end', () => {
const rangeA = {startLine: 1, startColumn: 2, endLine: 1, endColumn: 2};
const textRangeA = TextUtils.TextRange.TextRange.fromObject(rangeA);
const rangeB = {startLine: 4, startColumn: 2, endLine: 2, endColumn: 2};
const textRangeB = TextUtils.TextRange.TextRange.fromObject(rangeB);
const textRangeACollapsed = textRangeA.collapseToEnd();
assertIsUnitTextRange(
textRangeACollapsed, rangeA.endLine, rangeA.endColumn, 'collapsing to end should produce a unit range at end');
const textRangeBCollapsed = textRangeB.collapseToEnd();
assertIsUnitTextRange(
textRangeBCollapsed, rangeB.endLine, rangeB.endColumn, 'collapsing to end should produce a unit range at end');
assertIsTextRangeAndEqualsRange(textRangeA, rangeA, 'original TextUtils.TextRange.TextRange should be unchanged');
assertIsTextRangeAndEqualsRange(textRangeB, rangeB, 'original TextUtils.TextRange.TextRange should be unchanged');
});
it('can be normalized', () => {
const rangeA = {startLine: 1, startColumn: 2, endLine: 3, endColumn: 4};
const textRangeA = TextUtils.TextRange.TextRange.fromObject(rangeA);
const rangeB = {startLine: 3, startColumn: 4, endLine: 1, endColumn: 2};
const textRangeB = TextUtils.TextRange.TextRange.fromObject(rangeB);
const textRangeANormalized = textRangeA.normalize();
const textRangeBNormalized = textRangeB.normalize();
assertIsTextRangeAndEqualsRange(textRangeANormalized, rangeA, 'normalizing should keep range A unchanged');
assert.notStrictEqual(textRangeANormalized, textRangeA, 'range should have been cloned');
assertIsTextRangeAndEqualsRange(textRangeBNormalized, rangeA, 'range B should be normalized');
assertIsTextRangeAndEqualsRange(textRangeA, rangeA, 'range A should be unchanged');
assertIsTextRangeAndEqualsRange(textRangeB, rangeB, 'range B should be unchanged');
});
it('can be cloned', () => {
const rangeA = {startLine: 1, startColumn: 2, endLine: 3, endColumn: 4};
const textRangeA = TextUtils.TextRange.TextRange.fromObject(rangeA);
const textRangeB = textRangeA.clone();
assertIsTextRangeAndEqualsRange(textRangeB, rangeA, 'cloned range should be equal');
assert.notStrictEqual(textRangeB, textRangeA, 'cloned range should be different object');
assertIsTextRangeAndEqualsRange(textRangeA, rangeA, 'original range should be unchanged');
});
it('can be checked for equality', () => {
const rangeA = {startLine: 1, startColumn: 2, endLine: 3, endColumn: 4};
const textRangeA = TextUtils.TextRange.TextRange.fromObject(rangeA);
const textRangeB = TextUtils.TextRange.TextRange.fromObject(rangeA);
assert.isTrue(textRangeA.equal(textRangeA), 'range A is equal to itself');
assert.isTrue(textRangeA.equal(textRangeB), 'range A and B are equal');
});
it('can be compared', () => {
const textRangeA =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
const textRangeB =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 4, endLine: 3, endColumn: 4});
const textRangeC =
TextUtils.TextRange.TextRange.fromObject({startLine: 2, startColumn: 2, endLine: 3, endColumn: 4});
const textRangeD =
TextUtils.TextRange.TextRange.fromObject({startLine: 3, startColumn: 1, endLine: 3, endColumn: 4});
assert.strictEqual(textRangeA.compareTo(textRangeA), 0, 'A should be equal to itself');
assert.strictEqual(textRangeA.compareTo(textRangeB), -1, 'A should be before B');
assert.strictEqual(textRangeB.compareTo(textRangeA), 1, 'B should be after A');
assert.strictEqual(textRangeA.compareTo(textRangeC), -1, 'A should be before C');
assert.strictEqual(textRangeC.compareTo(textRangeA), 1, 'C should be after A');
assert.strictEqual(textRangeC.compareTo(textRangeD), -1, 'C should be before D');
assert.strictEqual(textRangeD.compareTo(textRangeC), 1, 'D should be after C');
});
it('can be compared with TextUtils.TextRange.TextRange.comparator', () => {
const textRangeA =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
const textRangeB =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 4, endLine: 3, endColumn: 4});
const textRangeC =
TextUtils.TextRange.TextRange.fromObject({startLine: 2, startColumn: 2, endLine: 3, endColumn: 4});
const textRangeD =
TextUtils.TextRange.TextRange.fromObject({startLine: 3, startColumn: 1, endLine: 3, endColumn: 4});
assert.strictEqual(
TextUtils.TextRange.TextRange.comparator(textRangeA, textRangeA), 0, 'A should be equal to itself');
assert.strictEqual(TextUtils.TextRange.TextRange.comparator(textRangeA, textRangeB), -1, 'A should be before B');
assert.strictEqual(TextUtils.TextRange.TextRange.comparator(textRangeB, textRangeA), 1, 'B should be after A');
assert.strictEqual(TextUtils.TextRange.TextRange.comparator(textRangeA, textRangeC), -1, 'A should be before C');
assert.strictEqual(TextUtils.TextRange.TextRange.comparator(textRangeC, textRangeA), 1, 'C should be after A');
assert.strictEqual(TextUtils.TextRange.TextRange.comparator(textRangeC, textRangeD), -1, 'C should be before D');
assert.strictEqual(TextUtils.TextRange.TextRange.comparator(textRangeD, textRangeC), 1, 'D should be after C');
});
it('can be compared to a position', () => {
const textRangeA =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
assert.strictEqual(textRangeA.compareToPosition(0, 3), -1, 'position before range should compare less');
assert.strictEqual(textRangeA.compareToPosition(1, 1), -1, 'position before range should compare less');
assert.strictEqual(textRangeA.compareToPosition(1, 2), 0, 'start position should compare equal');
assert.strictEqual(textRangeA.compareToPosition(1, 4), 0, 'position in range should compare equal');
assert.strictEqual(textRangeA.compareToPosition(3, 4), 0, 'end position should compare equal');
assert.strictEqual(textRangeA.compareToPosition(3, 5), 1, 'position after range should compare greater');
assert.strictEqual(textRangeA.compareToPosition(4, 4), 1, 'position after range should compare greater');
});
it('can be adjusted relative to a position', () => {
const textRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 4, startColumn: 3, endLine: 6, endColumn: 7});
const relativeTextRangeA = textRange.relativeTo(2, 2);
const expectedRangeA = {startLine: 2, startColumn: 3, endLine: 4, endColumn: 7};
assertIsTextRangeAndEqualsRange(
relativeTextRangeA, expectedRangeA,
'relativating to position strictly inside line range should not change columns');
const relativeTextRangeB = textRange.relativeTo(4, 2);
const expectedRangeB = {startLine: 0, startColumn: 1, endLine: 2, endColumn: 7};
assertIsTextRangeAndEqualsRange(
relativeTextRangeB, expectedRangeB, 'relativating to position on start line should change start column');
const relativeTextRangeC = textRange.relativeTo(6, 3);
const expectedRangeC = {startLine: -2, startColumn: 3, endLine: 0, endColumn: 4};
assertIsTextRangeAndEqualsRange(
relativeTextRangeC, expectedRangeC, 'relativating to position on end line should change end column');
const relativeTextRangeD = textRange.relativeTo(0, 0);
assert.notStrictEqual(relativeTextRangeD, textRange, 'relativeTo should clone range');
});
it('can be adjusted relative from a position', () => {
const textRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 4, startColumn: 3, endLine: 6, endColumn: 7});
const relativeTextRangeA = textRange.relativeFrom(2, 2);
const expectedRangeA = {startLine: 6, startColumn: 3, endLine: 8, endColumn: 7};
assertIsTextRangeAndEqualsRange(
relativeTextRangeA, expectedRangeA,
'relativating from position strictly inside line range should not change columns');
const relativeTextRangeB = textRange.relativeFrom(4, 2);
const expectedRangeB = {startLine: 8, startColumn: 3, endLine: 10, endColumn: 7};
assertIsTextRangeAndEqualsRange(
relativeTextRangeB, expectedRangeB, 'relativating from position on start line should not change columns');
const relativeTextRangeC = textRange.relativeFrom(6, 3);
const expectedRangeC = {startLine: 10, startColumn: 3, endLine: 12, endColumn: 7};
assertIsTextRangeAndEqualsRange(
relativeTextRangeC, expectedRangeC, 'relativating from position on end line should not change columns');
const relativeTextRangeD = textRange.relativeFrom(0, 0);
assert.notStrictEqual(relativeTextRangeD, textRange, 'relativeFrom should clone range');
const textRange2 =
TextUtils.TextRange.TextRange.fromObject({startLine: 0, startColumn: 3, endLine: 6, endColumn: 7});
const relativeTextRangeE = textRange2.relativeFrom(2, 2);
const expectedRangeE = {startLine: 2, startColumn: 5, endLine: 8, endColumn: 7};
assertIsTextRangeAndEqualsRange(
relativeTextRangeE, expectedRangeE, 'relativating range with startLine 0 should change start column');
const textRange3 =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 3, endLine: 0, endColumn: 7});
const relativeTextRangeF = textRange3.relativeFrom(2, 2);
const expectedRangeF = {startLine: 3, startColumn: 3, endLine: 2, endColumn: 9};
assertIsTextRangeAndEqualsRange(
relativeTextRangeF, expectedRangeF, 'relativating range with endLine 0 should change end column');
});
describe('containsLocation', () => {
it('can check if a position is contained', () => {
const textRangeA =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
assert.isFalse(textRangeA.containsLocation(0, 3), 'position before range should not be contained');
assert.isFalse(textRangeA.containsLocation(1, 1), 'position before range should not be contained');
assert.isTrue(textRangeA.containsLocation(1, 2), 'start position should be contained');
assert.isTrue(textRangeA.containsLocation(1, 4), 'position in range should be contained');
assert.isFalse(textRangeA.containsLocation(3, 4), 'end position should not be contained');
assert.isFalse(textRangeA.containsLocation(3, 5), 'position after range should compare greater');
assert.isFalse(textRangeA.containsLocation(4, 4), 'position after range should compare greater');
const textRangeB =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 1, endColumn: 4});
assert.isFalse(textRangeB.containsLocation(1, 1), 'position before range should not be contained');
assert.isTrue(textRangeB.containsLocation(1, 2), 'start position should be contained');
assert.isFalse(textRangeB.containsLocation(1, 4), 'end position should not be contained');
assert.isFalse(textRangeB.containsLocation(1, 5), 'position after range should not be contained');
});
});
describe('fromEdit()', () => {
it('can construct a range from an edit of a text ending with a newline', () => {
const textRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
const text = 'This is\nan example text\nwith newlines\nin it. It is for\n the test.\n';
const textRangeEdited = TextUtils.TextRange.TextRange.fromEdit(textRange, text);
const expectedRange = {startLine: 1, startColumn: 2, endLine: 6, endColumn: 0};
assertIsTextRangeAndEqualsRange(textRangeEdited, expectedRange, 'range end should have been shifted back');
});
it('can construct a range from an edit of a text ending without a newline', () => {
const textRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
const text = 'This is\nan example text\nwith newlines\nin it. It is for\n the test.';
const textRangeEdited = TextUtils.TextRange.TextRange.fromEdit(textRange, text);
const expectedRange = {startLine: 1, startColumn: 2, endLine: 5, endColumn: 10};
assertIsTextRangeAndEqualsRange(textRangeEdited, expectedRange, 'range end should have been shifted back');
});
it('can construct a range from an edit of a text without newlines', () => {
const textRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
const text = 'This is an example text without newlines in it. It is for the test.';
const textRangeEdited = TextUtils.TextRange.TextRange.fromEdit(textRange, text);
const expectedRange = {startLine: 1, startColumn: 2, endLine: 1, endColumn: 69};
assertIsTextRangeAndEqualsRange(textRangeEdited, expectedRange, 'range end should have been shifted forward');
});
});
describe('rebaseAfterTextEdit()', () => {
let originalRange: TextUtils.TextRange.TextRange;
let editedRange: TextUtils.TextRange.TextRange;
beforeEach(() => {
originalRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
editedRange = TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 7, endColumn: 8});
});
it('can rebase a range that doesn\'t follow the original range', () => {
const range = {startLine: 2, startColumn: 4, endLine: 7, endColumn: 8};
const textRange = TextUtils.TextRange.TextRange.fromObject(range);
const rebasedTextrange = textRange.rebaseAfterTextEdit(originalRange, editedRange);
assertIsTextRangeAndEqualsRange(rebasedTextrange, range, 'range should not have been modified');
});
it('can rebase a range if its rebased range neither starts nor ends at end of the edited range', () => {
const textRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 4, startColumn: 4, endLine: 6, endColumn: 8});
const rebasedTextRange = textRange.rebaseAfterTextEdit(originalRange, editedRange);
const expectedRange = {startLine: 8, startColumn: 4, endLine: 10, endColumn: 8};
assertIsTextRangeAndEqualsRange(rebasedTextRange, expectedRange, 'range’s lines should have been shifted back');
});
it('can rebase a range if its rebased range starts at the end of the edited range', () => {
const textRangeToRebase =
TextUtils.TextRange.TextRange.fromObject({startLine: 3, startColumn: 5, endLine: 6, endColumn: 8});
const rebasedTextRange = textRangeToRebase.rebaseAfterTextEdit(originalRange, editedRange);
const expectedRange = {startLine: 7, startColumn: 9, endLine: 10, endColumn: 8};
assertIsTextRangeAndEqualsRange(
rebasedTextRange, expectedRange, 'range’s lines and start column should have been shifted back');
});
it('can rebase a range if its rebased range starts and ends at the end of the edited range', () => {
const textRangeToRebase =
TextUtils.TextRange.TextRange.fromObject({startLine: 3, startColumn: 5, endLine: 3, endColumn: 8});
const rebasedTextRange = textRangeToRebase.rebaseAfterTextEdit(originalRange, editedRange);
const expectedRange = {startLine: 7, startColumn: 9, endLine: 7, endColumn: 12};
assertIsTextRangeAndEqualsRange(
rebasedTextRange, expectedRange, 'range’s lines and columns should have been shifted back');
});
});
it('can be stringified', () => {
const textRange =
TextUtils.TextRange.TextRange.fromObject({startLine: 1, startColumn: 2, endLine: 3, endColumn: 4});
assert.strictEqual(typeof textRange.toString(), 'string', 'toString should return a string');
});
describe('intersection', () => {
const {TextRange} = TextUtils.TextRange;
it('yields empty range for empty inputs', () => {
const range1 = new TextRange(0, 0, 0, 0);
const range2 = new TextRange(1, 4, 1, 4);
assert.isTrue(range1.intersection(range2).isEmpty(), 'intersection should be empty');
assert.isTrue(range2.intersection(range1).isEmpty(), 'intersection should be empty');
});
it('yields empty range for non-overlapping inputs', () => {
const range1 = new TextRange(1, 0, 2, 0);
const range2 = new TextRange(3, 0, 4, 0);
assert.isTrue(range1.intersection(range2).isEmpty(), 'intersection should be empty');
assert.isTrue(range2.intersection(range1).isEmpty(), 'intersection should be empty');
const range3 = new TextRange(7, 1, 8, 4);
const range4 = new TextRange(8, 4, 8, 9);
assert.isTrue(range3.intersection(range4).isEmpty(), 'intersection should be empty');
assert.isTrue(range4.intersection(range3).isEmpty(), 'intersection should be empty');
});
it('yields same range for identical inputs', () => {
const range = new TextRange(1, 2, 3, 4);
assert.deepEqual(range.intersection(range), range);
});
it('yields a point range for inputs overlapping on a single character', () => {
const range1 = new TextRange(7, 1, 7, 4);
const range2 = new TextRange(7, 3, 9, 9);
const result = new TextRange(range2.startLine, range2.startColumn, range1.endLine, range1.endColumn);
assert.deepEqual(range1.intersection(range2), result);
assert.deepEqual(range2.intersection(range1), result);
});
it('yields a copy and never the input', () => {
const range = new TextRange(8, 0, 8, 9);
const empty = new TextRange(7, 0, 7, 0);
assert.notStrictEqual(range.intersection(range), range);
assert.notStrictEqual(empty.intersection(empty), empty);
assert.notStrictEqual(empty.intersection(range), empty);
assert.notStrictEqual(empty.intersection(range), range);
assert.notStrictEqual(range.intersection(empty), empty);
assert.notStrictEqual(range.intersection(empty), range);
});
it('yields the smaller range if it is fully contained in the other', () => {
const large = new TextRange(0, 1, 10, 0);
const small = new TextRange(0, 2, 9, 25);
assert.deepEqual(large.intersection(small), small);
assert.deepEqual(small.intersection(large), small);
});
});
});