Path: blob/main/src/vs/editor/test/common/model/textModel.test.ts
5243 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 { DisposableStore } from '../../../../base/common/lifecycle.js';7import { UTF8_BOM_CHARACTER } from '../../../../base/common/strings.js';8import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';9import { Position } from '../../../common/core/position.js';10import { Range } from '../../../common/core/range.js';11import { PLAINTEXT_LANGUAGE_ID } from '../../../common/languages/modesRegistry.js';12import { EndOfLinePreference } from '../../../common/model.js';13import { TextModel, createTextBuffer } from '../../../common/model/textModel.js';14import { createModelServices, createTextModel } from '../testTextModel.js';15import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js';1617function testGuessIndentation(defaultInsertSpaces: boolean, defaultTabSize: number, expectedInsertSpaces: boolean, expectedTabSize: number, text: string[], msg?: string): void {18const m = createTextModel(19text.join('\n'),20undefined,21{22tabSize: defaultTabSize,23insertSpaces: defaultInsertSpaces,24detectIndentation: true25}26);27const r = m.getOptions();28m.dispose();2930assert.strictEqual(r.insertSpaces, expectedInsertSpaces, msg);31assert.strictEqual(r.tabSize, expectedTabSize, msg);32}3334function assertGuess(expectedInsertSpaces: boolean | undefined, expectedTabSize: number | undefined | [number], text: string[], msg?: string): void {35if (typeof expectedInsertSpaces === 'undefined') {36// cannot guess insertSpaces37if (typeof expectedTabSize === 'undefined') {38// cannot guess tabSize39testGuessIndentation(true, 13370, true, 13370, text, msg);40testGuessIndentation(false, 13371, false, 13371, text, msg);41} else if (typeof expectedTabSize === 'number') {42// can guess tabSize43testGuessIndentation(true, 13370, true, expectedTabSize, text, msg);44testGuessIndentation(false, 13371, false, expectedTabSize, text, msg);45} else {46// can only guess tabSize when insertSpaces is true47testGuessIndentation(true, 13370, true, expectedTabSize[0], text, msg);48testGuessIndentation(false, 13371, false, 13371, text, msg);49}50} else {51// can guess insertSpaces52if (typeof expectedTabSize === 'undefined') {53// cannot guess tabSize54testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg);55testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg);56} else if (typeof expectedTabSize === 'number') {57// can guess tabSize58testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize, text, msg);59testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize, text, msg);60} else {61// can only guess tabSize when insertSpaces is true62if (expectedInsertSpaces === true) {63testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize[0], text, msg);64testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize[0], text, msg);65} else {66testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg);67testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg);68}69}70}71}7273suite('TextModelData.fromString', () => {7475ensureNoDisposablesAreLeakedInTestSuite();7677interface ITextBufferData {78EOL: string;79lines: string[];80containsRTL: boolean;81isBasicASCII: boolean;82}8384function testTextModelDataFromString(text: string, expected: ITextBufferData): void {85const { textBuffer, disposable } = createTextBuffer(text, TextModel.DEFAULT_CREATION_OPTIONS.defaultEOL);86const actual: ITextBufferData = {87EOL: textBuffer.getEOL(),88lines: textBuffer.getLinesContent(),89containsRTL: textBuffer.mightContainRTL(),90isBasicASCII: !textBuffer.mightContainNonBasicASCII()91};92assert.deepStrictEqual(actual, expected);93disposable.dispose();94}9596test('one line text', () => {97testTextModelDataFromString('Hello world!',98{99EOL: '\n',100lines: [101'Hello world!'102],103containsRTL: false,104isBasicASCII: true105}106);107});108109test('multiline text', () => {110testTextModelDataFromString('Hello,\r\ndear friend\nHow\rare\r\nyou?',111{112EOL: '\r\n',113lines: [114'Hello,',115'dear friend',116'How',117'are',118'you?'119],120containsRTL: false,121isBasicASCII: true122}123);124});125126test('Non Basic ASCII 1', () => {127testTextModelDataFromString('Hello,\nZürich',128{129EOL: '\n',130lines: [131'Hello,',132'Zürich'133],134containsRTL: false,135isBasicASCII: false136}137);138});139140test('containsRTL 1', () => {141testTextModelDataFromString('Hello,\nזוהי עובדה מבוססת שדעתו',142{143EOL: '\n',144lines: [145'Hello,',146'זוהי עובדה מבוססת שדעתו'147],148containsRTL: true,149isBasicASCII: false150}151);152});153154test('containsRTL 2', () => {155testTextModelDataFromString('Hello,\nهناك حقيقة مثبتة منذ زمن طويل',156{157EOL: '\n',158lines: [159'Hello,',160'هناك حقيقة مثبتة منذ زمن طويل'161],162containsRTL: true,163isBasicASCII: false164}165);166});167168});169170suite('Editor Model - TextModel', () => {171172ensureNoDisposablesAreLeakedInTestSuite();173174test('TextModel does not use events internally', () => {175// Make sure that all model parts receive text model events explicitly176// to avoid that by any chance an outside listener receives events before177// the parts and thus are able to access the text model in an inconsistent state.178//179// We simply check that there are no listeners attached to text model180// after instantiation181const disposables = new DisposableStore();182const instantiationService: IInstantiationService = createModelServices(disposables);183const textModel = disposables.add(instantiationService.createInstance(TextModel, '', PLAINTEXT_LANGUAGE_ID, TextModel.DEFAULT_CREATION_OPTIONS, null));184assert.strictEqual(textModel._hasListeners(), false);185disposables.dispose();186});187188test('getValueLengthInRange', () => {189190let m = createTextModel('My First Line\r\nMy Second Line\r\nMy Third Line');191assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 1)), ''.length);192assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 2)), 'M'.length);193assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 1, 3)), 'y'.length);194assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 14)), 'My First Line'.length);195assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1)), 'My First Line\r\n'.length);196assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1)), 'y First Line\r\n'.length);197assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 2)), 'y First Line\r\nM'.length);198assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1000)), 'y First Line\r\nMy Second Line'.length);199assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1)), 'y First Line\r\nMy Second Line\r\n'.length);200assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1000)), 'y First Line\r\nMy Second Line\r\nMy Third Line'.length);201assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000)), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);202m.dispose();203204m = createTextModel('My First Line\nMy Second Line\nMy Third Line');205assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 1)), ''.length);206assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 2)), 'M'.length);207assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 1, 3)), 'y'.length);208assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1, 14)), 'My First Line'.length);209assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1)), 'My First Line\n'.length);210assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1)), 'y First Line\n'.length);211assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 2)), 'y First Line\nM'.length);212assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 2, 1000)), 'y First Line\nMy Second Line'.length);213assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1)), 'y First Line\nMy Second Line\n'.length);214assert.strictEqual(m.getValueLengthInRange(new Range(1, 2, 3, 1000)), 'y First Line\nMy Second Line\nMy Third Line'.length);215assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000)), 'My First Line\nMy Second Line\nMy Third Line'.length);216m.dispose();217});218219test('getValueLengthInRange different EOL', () => {220221let m = createTextModel('My First Line\r\nMy Second Line\r\nMy Third Line');222assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.TextDefined), 'My First Line\r\n'.length);223assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.CRLF), 'My First Line\r\n'.length);224assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.LF), 'My First Line\n'.length);225assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.TextDefined), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);226assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.CRLF), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);227assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.LF), 'My First Line\nMy Second Line\nMy Third Line'.length);228m.dispose();229230m = createTextModel('My First Line\nMy Second Line\nMy Third Line');231assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.TextDefined), 'My First Line\n'.length);232assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.LF), 'My First Line\n'.length);233assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 2, 1), EndOfLinePreference.CRLF), 'My First Line\r\n'.length);234assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.TextDefined), 'My First Line\nMy Second Line\nMy Third Line'.length);235assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.LF), 'My First Line\nMy Second Line\nMy Third Line'.length);236assert.strictEqual(m.getValueLengthInRange(new Range(1, 1, 1000, 1000), EndOfLinePreference.CRLF), 'My First Line\r\nMy Second Line\r\nMy Third Line'.length);237m.dispose();238});239240test('guess indentation 1', () => {241242assertGuess(undefined, undefined, [243'x',244'x',245'x',246'x',247'x',248'x',249'x'250], 'no clues');251252assertGuess(false, undefined, [253'\tx',254'x',255'x',256'x',257'x',258'x',259'x'260], 'no spaces, 1xTAB');261262assertGuess(true, 2, [263' x',264'x',265'x',266'x',267'x',268'x',269'x'270], '1x2');271272assertGuess(false, undefined, [273'\tx',274'\tx',275'\tx',276'\tx',277'\tx',278'\tx',279'\tx'280], '7xTAB');281282assertGuess(undefined, [2], [283'\tx',284' x',285'\tx',286' x',287'\tx',288' x',289'\tx',290' x',291], '4x2, 4xTAB');292assertGuess(false, undefined, [293'\tx',294' x',295'\tx',296' x',297'\tx',298' x',299'\tx',300' x'301], '4x1, 4xTAB');302assertGuess(false, undefined, [303'\tx',304'\tx',305' x',306'\tx',307' x',308'\tx',309' x',310'\tx',311' x',312], '4x2, 5xTAB');313assertGuess(false, undefined, [314'\tx',315'\tx',316'x',317'\tx',318'x',319'\tx',320'x',321'\tx',322' x',323], '1x2, 5xTAB');324assertGuess(false, undefined, [325'\tx',326'\tx',327'x',328'\tx',329'x',330'\tx',331'x',332'\tx',333' x',334], '1x4, 5xTAB');335assertGuess(false, undefined, [336'\tx',337'\tx',338'x',339'\tx',340'x',341'\tx',342' x',343'\tx',344' x',345], '1x2, 1x4, 5xTAB');346347assertGuess(undefined, undefined, [348'x',349' x',350' x',351' x',352' x',353' x',354' x',355' x'356], '7x1 - 1 space is never guessed as an indentation');357assertGuess(true, undefined, [358'x',359' x',360' x',361' x',362' x',363' x',364' x',365' x'366], '1x10, 6x1');367assertGuess(undefined, undefined, [368'',369' ',370' ',371' ',372' ',373' ',374' ',375' ',376], 'whitespace lines don\'t count');377assertGuess(true, 3, [378'x',379' x',380' x',381' x',382'x',383' x',384' x',385' x',386'x',387' x',388' x',389' x',390], '6x3, 3x4');391assertGuess(true, 5, [392'x',393' x',394' x',395' x',396'x',397' x',398' x',399' x',400'x',401' x',402' x',403' x',404], '6x5, 3x4');405assertGuess(true, 7, [406'x',407' x',408' x',409' x',410'x',411' x',412' x',413' x',414'x',415' x',416' x',417' x',418], '6x7, 1x5, 2x4');419assertGuess(true, 2, [420'x',421' x',422' x',423' x',424' x',425'x',426' x',427' x',428' x',429' x',430], '8x2');431432assertGuess(true, 2, [433'x',434' x',435' x',436'x',437' x',438' x',439'x',440' x',441' x',442'x',443' x',444' x',445], '8x2');446assertGuess(true, 2, [447'x',448' x',449' x',450'x',451' x',452' x',453'x',454' x',455' x',456'x',457' x',458' x',459], '4x2, 4x4');460assertGuess(true, 2, [461'x',462' x',463' x',464' x',465'x',466' x',467' x',468' x',469'x',470' x',471' x',472' x',473], '6x2, 3x4');474assertGuess(true, 2, [475'x',476' x',477' x',478' x',479' x',480'x',481' x',482' x',483' x',484' x',485], '4x2, 4x4');486assertGuess(true, 2, [487'x',488' x',489' x',490' x',491'x',492' x',493' x',494' x',495], '2x2, 4x4');496assertGuess(true, 4, [497'x',498' x',499' x',500'x',501' x',502' x',503'x',504' x',505' x',506'x',507' x',508' x',509], '8x4');510assertGuess(true, 2, [511'x',512' x',513' x',514' x',515' x',516'x',517' x',518' x',519' x',520' x',521], '2x2, 4x4, 2x6');522assertGuess(true, 2, [523'x',524' x',525' x',526' x',527' x',528' x',529' x',530], '1x2, 2x4, 2x6, 1x8');531assertGuess(true, 4, [532'x',533' x',534' x',535' x',536' x',537' x',538'x',539' x',540' x',541' x',542' x',543' x',544], '6x4, 2x5, 2x8');545assertGuess(true, 4, [546'x',547' x',548' x',549' x',550' x',551' x',552' x',553], '3x4, 1x5, 2x8');554assertGuess(true, 4, [555'x',556'x',557' x',558' x',559' x',560' x',561' x',562'x',563'x',564' x',565' x',566' x',567' x',568' x',569], '6x4, 2x5, 4x8');570assertGuess(true, 3, [571'x',572' x',573' x',574' x',575' x',576' x',577'x',578' x',579' x',580' x',581], '5x1, 2x0, 1x3, 2x4');582assertGuess(false, undefined, [583'\t x',584' \t x',585'\tx'586], 'mixed whitespace 1');587assertGuess(false, undefined, [588'\tx',589'\t x'590], 'mixed whitespace 2');591});592593test('issue #44991: Wrong indentation size auto-detection', () => {594assertGuess(true, 4, [595'a = 10 # 0 space indent',596'b = 5 # 0 space indent',597'if a > 10: # 0 space indent',598' a += 1 # 4 space indent delta 4 spaces',599' if b > 5: # 4 space indent',600' b += 1 # 8 space indent delta 4 spaces',601' b += 1 # 8 space indent',602' b += 1 # 8 space indent',603'# comment line 1 # 0 space indent delta 8 spaces',604'# comment line 2 # 0 space indent',605'# comment line 3 # 0 space indent',606' b += 1 # 8 space indent delta 8 spaces',607' b += 1 # 8 space indent',608' b += 1 # 8 space indent',609]);610});611612test('issue #55818: Broken indentation detection', () => {613assertGuess(true, 2, [614'',615'/* REQUIRE */',616'',617'const foo = require ( \'foo\' ),',618' bar = require ( \'bar\' );',619'',620'/* MY FN */',621'',622'function myFn () {',623'',624' const asd = 1,',625' dsa = 2;',626'',627' return bar ( foo ( asd ) );',628'',629'}',630'',631'/* EXPORT */',632'',633'module.exports = myFn;',634'',635]);636});637638test('issue #70832: Broken indentation detection', () => {639assertGuess(false, undefined, [640'x',641'x',642'x',643'x',644' x',645' x',646' x',647' x',648' x',649' x',650' x',651' x',652' x',653' x',654'x',655]);656});657658test('issue #62143: Broken indentation detection', () => {659// works before the fix660assertGuess(true, 2, [661'x',662'x',663' x',664' x'665]);666667// works before the fix668assertGuess(true, 2, [669'x',670' - item2',671' - item3'672]);673674// works before the fix675testGuessIndentation(true, 2, true, 2, [676'x x',677' x',678' x',679]);680681// fails before the fix682// empty space inline breaks the indentation guess683testGuessIndentation(true, 2, true, 2, [684'x x',685' x',686' x',687' x'688]);689690testGuessIndentation(true, 2, true, 2, [691'<!--test1.md -->',692'- item1',693' - item2',694' - item3'695]);696});697698test('issue #84217: Broken indentation detection', () => {699assertGuess(true, 4, [700'def main():',701' print(\'hello\')',702]);703assertGuess(true, 4, [704'def main():',705' with open(\'foo\') as fp:',706' print(fp.read())',707]);708});709710test('issue #65668: YAML file indented with 2 spaces', () => {711// Full YAML file from the issue - should detect as 2 spaces712assertGuess(true, 2, [713'version: 2',714'',715'jobs:',716' build:',717' docker:',718' - circleci/golang:1.11',719'',720' environment:',721' TEST_RESULTS: /tmp/test-results',722'',723' steps:',724' - checkout',725' - run: mkdir -p $TEST_RESULTS',726'',727' - restore_cache:',728' keys:',729' - v1-pkg-cache',730'',731' - run:',732' name: dep ensure',733' command: dep ensure -v',734'',735' - run:',736' name: Run unit tests',737' command: |',738' trap "go-junit-report <${TEST_RESULTS}/go-test.out > ${TEST_RESULTS}/go-test-report.xml" EXIT',739' go test -v ./... | tee ${TEST_RESULTS}/go-test.out',740'',741' - run:',742' name: Build',743' command: go build -v',744'',745' - save_cache:',746' key: v1-pkg-cache',747' paths:',748' - "/go/pkg"',749'',750' - store_artifacts:',751' path: /tmp/test-results',752' destination: raw-test-output',753'',754' - store_test_results:',755' path: /tmp/test-results',756]);757});758759test('issue #249040: 4-space indent should win over 2-space when predominant', () => {760// File with mostly 4-space indents but some 2-space indents should detect as 4 spaces761assertGuess(true, 4, [762'function foo() {',763' let a = 1;',764' let b = 2;',765' if (true) {',766' console.log(a);',767' console.log(b);',768' }',769' const obj = {',770' x: 1,', // 2-space indent here771' y: 2', // 2-space indent here772' };',773' return obj;',774'}',775]);776});777778test('validatePosition', () => {779780const m = createTextModel('line one\nline two');781782assert.deepStrictEqual(m.validatePosition(new Position(0, 0)), new Position(1, 1));783assert.deepStrictEqual(m.validatePosition(new Position(0, 1)), new Position(1, 1));784785assert.deepStrictEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));786assert.deepStrictEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));787assert.deepStrictEqual(m.validatePosition(new Position(1, 30)), new Position(1, 9));788789assert.deepStrictEqual(m.validatePosition(new Position(2, 0)), new Position(2, 1));790assert.deepStrictEqual(m.validatePosition(new Position(2, 1)), new Position(2, 1));791assert.deepStrictEqual(m.validatePosition(new Position(2, 2)), new Position(2, 2));792assert.deepStrictEqual(m.validatePosition(new Position(2, 30)), new Position(2, 9));793794assert.deepStrictEqual(m.validatePosition(new Position(3, 0)), new Position(2, 9));795assert.deepStrictEqual(m.validatePosition(new Position(3, 1)), new Position(2, 9));796assert.deepStrictEqual(m.validatePosition(new Position(3, 30)), new Position(2, 9));797798assert.deepStrictEqual(m.validatePosition(new Position(30, 30)), new Position(2, 9));799800assert.deepStrictEqual(m.validatePosition(new Position(-123.123, -0.5)), new Position(1, 1));801assert.deepStrictEqual(m.validatePosition(new Position(Number.MIN_VALUE, Number.MIN_VALUE)), new Position(1, 1));802803assert.deepStrictEqual(m.validatePosition(new Position(Number.MAX_VALUE, Number.MAX_VALUE)), new Position(2, 9));804assert.deepStrictEqual(m.validatePosition(new Position(123.23, 47.5)), new Position(2, 9));805806m.dispose();807});808809test('validatePosition around high-low surrogate pairs 1', () => {810811const m = createTextModel('a📚b');812813assert.deepStrictEqual(m.validatePosition(new Position(0, 0)), new Position(1, 1));814assert.deepStrictEqual(m.validatePosition(new Position(0, 1)), new Position(1, 1));815assert.deepStrictEqual(m.validatePosition(new Position(0, 7)), new Position(1, 1));816817assert.deepStrictEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));818assert.deepStrictEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));819assert.deepStrictEqual(m.validatePosition(new Position(1, 3)), new Position(1, 2));820assert.deepStrictEqual(m.validatePosition(new Position(1, 4)), new Position(1, 4));821assert.deepStrictEqual(m.validatePosition(new Position(1, 5)), new Position(1, 5));822assert.deepStrictEqual(m.validatePosition(new Position(1, 30)), new Position(1, 5));823824assert.deepStrictEqual(m.validatePosition(new Position(2, 0)), new Position(1, 5));825assert.deepStrictEqual(m.validatePosition(new Position(2, 1)), new Position(1, 5));826assert.deepStrictEqual(m.validatePosition(new Position(2, 2)), new Position(1, 5));827assert.deepStrictEqual(m.validatePosition(new Position(2, 30)), new Position(1, 5));828829assert.deepStrictEqual(m.validatePosition(new Position(-123.123, -0.5)), new Position(1, 1));830assert.deepStrictEqual(m.validatePosition(new Position(Number.MIN_VALUE, Number.MIN_VALUE)), new Position(1, 1));831832assert.deepStrictEqual(m.validatePosition(new Position(Number.MAX_VALUE, Number.MAX_VALUE)), new Position(1, 5));833assert.deepStrictEqual(m.validatePosition(new Position(123.23, 47.5)), new Position(1, 5));834835m.dispose();836});837838test('validatePosition around high-low surrogate pairs 2', () => {839840const m = createTextModel('a📚📚b');841842assert.deepStrictEqual(m.validatePosition(new Position(1, 1)), new Position(1, 1));843assert.deepStrictEqual(m.validatePosition(new Position(1, 2)), new Position(1, 2));844assert.deepStrictEqual(m.validatePosition(new Position(1, 3)), new Position(1, 2));845assert.deepStrictEqual(m.validatePosition(new Position(1, 4)), new Position(1, 4));846assert.deepStrictEqual(m.validatePosition(new Position(1, 5)), new Position(1, 4));847assert.deepStrictEqual(m.validatePosition(new Position(1, 6)), new Position(1, 6));848assert.deepStrictEqual(m.validatePosition(new Position(1, 7)), new Position(1, 7));849850m.dispose();851852});853854test('validatePosition handle NaN.', () => {855856const m = createTextModel('line one\nline two');857858assert.deepStrictEqual(m.validatePosition(new Position(NaN, 1)), new Position(1, 1));859assert.deepStrictEqual(m.validatePosition(new Position(1, NaN)), new Position(1, 1));860861assert.deepStrictEqual(m.validatePosition(new Position(NaN, NaN)), new Position(1, 1));862assert.deepStrictEqual(m.validatePosition(new Position(2, NaN)), new Position(2, 1));863assert.deepStrictEqual(m.validatePosition(new Position(NaN, 3)), new Position(1, 3));864865m.dispose();866});867868test('issue #71480: validatePosition handle floats', () => {869const m = createTextModel('line one\nline two');870871assert.deepStrictEqual(m.validatePosition(new Position(0.2, 1)), new Position(1, 1), 'a');872assert.deepStrictEqual(m.validatePosition(new Position(1.2, 1)), new Position(1, 1), 'b');873assert.deepStrictEqual(m.validatePosition(new Position(1.5, 2)), new Position(1, 2), 'c');874assert.deepStrictEqual(m.validatePosition(new Position(1.8, 3)), new Position(1, 3), 'd');875assert.deepStrictEqual(m.validatePosition(new Position(1, 0.3)), new Position(1, 1), 'e');876assert.deepStrictEqual(m.validatePosition(new Position(2, 0.8)), new Position(2, 1), 'f');877assert.deepStrictEqual(m.validatePosition(new Position(1, 1.2)), new Position(1, 1), 'g');878assert.deepStrictEqual(m.validatePosition(new Position(2, 1.5)), new Position(2, 1), 'h');879880m.dispose();881});882883test('issue #71480: validateRange handle floats', () => {884const m = createTextModel('line one\nline two');885886assert.deepStrictEqual(m.validateRange(new Range(0.2, 1.5, 0.8, 2.5)), new Range(1, 1, 1, 1));887assert.deepStrictEqual(m.validateRange(new Range(1.2, 1.7, 1.8, 2.2)), new Range(1, 1, 1, 2));888889m.dispose();890});891892test('validateRange around high-low surrogate pairs 1', () => {893894const m = createTextModel('a📚b');895896assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 1)), new Range(1, 1, 1, 1));897assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 7)), new Range(1, 1, 1, 1));898899assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 1)), new Range(1, 1, 1, 1));900assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 2)), new Range(1, 1, 1, 2));901assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 3)), new Range(1, 1, 1, 4));902assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 4)), new Range(1, 1, 1, 4));903assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 5)), new Range(1, 1, 1, 5));904905assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 2)), new Range(1, 2, 1, 2));906assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 3)), new Range(1, 2, 1, 4));907assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 4)), new Range(1, 2, 1, 4));908assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 5)), new Range(1, 2, 1, 5));909910assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 3)), new Range(1, 2, 1, 2));911assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 4)), new Range(1, 2, 1, 4));912assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 5)), new Range(1, 2, 1, 5));913914assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 4)), new Range(1, 4, 1, 4));915assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 5)), new Range(1, 4, 1, 5));916917assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 5)), new Range(1, 5, 1, 5));918919m.dispose();920});921922test('validateRange around high-low surrogate pairs 2', () => {923924const m = createTextModel('a📚📚b');925926assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 1)), new Range(1, 1, 1, 1));927assert.deepStrictEqual(m.validateRange(new Range(0, 0, 0, 7)), new Range(1, 1, 1, 1));928929assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 1)), new Range(1, 1, 1, 1));930assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 2)), new Range(1, 1, 1, 2));931assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 3)), new Range(1, 1, 1, 4));932assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 4)), new Range(1, 1, 1, 4));933assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 5)), new Range(1, 1, 1, 6));934assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 6)), new Range(1, 1, 1, 6));935assert.deepStrictEqual(m.validateRange(new Range(1, 1, 1, 7)), new Range(1, 1, 1, 7));936937assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 2)), new Range(1, 2, 1, 2));938assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 3)), new Range(1, 2, 1, 4));939assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 4)), new Range(1, 2, 1, 4));940assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 5)), new Range(1, 2, 1, 6));941assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 6)), new Range(1, 2, 1, 6));942assert.deepStrictEqual(m.validateRange(new Range(1, 2, 1, 7)), new Range(1, 2, 1, 7));943944assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 3)), new Range(1, 2, 1, 2));945assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 4)), new Range(1, 2, 1, 4));946assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 5)), new Range(1, 2, 1, 6));947assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 6)), new Range(1, 2, 1, 6));948assert.deepStrictEqual(m.validateRange(new Range(1, 3, 1, 7)), new Range(1, 2, 1, 7));949950assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 4)), new Range(1, 4, 1, 4));951assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 5)), new Range(1, 4, 1, 6));952assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 6)), new Range(1, 4, 1, 6));953assert.deepStrictEqual(m.validateRange(new Range(1, 4, 1, 7)), new Range(1, 4, 1, 7));954955assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 5)), new Range(1, 4, 1, 4));956assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 6)), new Range(1, 4, 1, 6));957assert.deepStrictEqual(m.validateRange(new Range(1, 5, 1, 7)), new Range(1, 4, 1, 7));958959assert.deepStrictEqual(m.validateRange(new Range(1, 6, 1, 6)), new Range(1, 6, 1, 6));960assert.deepStrictEqual(m.validateRange(new Range(1, 6, 1, 7)), new Range(1, 6, 1, 7));961962assert.deepStrictEqual(m.validateRange(new Range(1, 7, 1, 7)), new Range(1, 7, 1, 7));963964m.dispose();965});966967test('modifyPosition', () => {968969const m = createTextModel('line one\nline two');970assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 0), new Position(1, 1));971assert.deepStrictEqual(m.modifyPosition(new Position(0, 0), 0), new Position(1, 1));972assert.deepStrictEqual(m.modifyPosition(new Position(30, 1), 0), new Position(2, 9));973974assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 17), new Position(2, 9));975assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 1), new Position(1, 2));976assert.deepStrictEqual(m.modifyPosition(new Position(1, 1), 3), new Position(1, 4));977assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 10), new Position(2, 3));978assert.deepStrictEqual(m.modifyPosition(new Position(1, 5), 13), new Position(2, 9));979assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 16), new Position(2, 9));980981assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -17), new Position(1, 1));982assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), -1), new Position(1, 1));983assert.deepStrictEqual(m.modifyPosition(new Position(1, 4), -3), new Position(1, 1));984assert.deepStrictEqual(m.modifyPosition(new Position(2, 3), -10), new Position(1, 2));985assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -13), new Position(1, 5));986assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -16), new Position(1, 2));987988assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 17), new Position(2, 9));989assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), 100), new Position(2, 9));990991assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), -2), new Position(1, 1));992assert.deepStrictEqual(m.modifyPosition(new Position(1, 2), -100), new Position(1, 1));993assert.deepStrictEqual(m.modifyPosition(new Position(2, 2), -100), new Position(1, 1));994assert.deepStrictEqual(m.modifyPosition(new Position(2, 9), -18), new Position(1, 1));995996m.dispose();997});998999test('normalizeIndentation 1', () => {1000const model = createTextModel('',1001undefined,1002{1003insertSpaces: false1004}1005);10061007assert.strictEqual(model.normalizeIndentation('\t'), '\t');1008assert.strictEqual(model.normalizeIndentation(' '), '\t');1009assert.strictEqual(model.normalizeIndentation(' '), ' ');1010assert.strictEqual(model.normalizeIndentation(' '), ' ');1011assert.strictEqual(model.normalizeIndentation(' '), ' ');1012assert.strictEqual(model.normalizeIndentation(''), '');1013assert.strictEqual(model.normalizeIndentation(' \t '), '\t\t');1014assert.strictEqual(model.normalizeIndentation(' \t '), '\t ');1015assert.strictEqual(model.normalizeIndentation(' \t '), '\t ');1016assert.strictEqual(model.normalizeIndentation(' \t '), '\t ');1017assert.strictEqual(model.normalizeIndentation(' \t'), '\t');10181019assert.strictEqual(model.normalizeIndentation('\ta'), '\ta');1020assert.strictEqual(model.normalizeIndentation(' a'), '\ta');1021assert.strictEqual(model.normalizeIndentation(' a'), ' a');1022assert.strictEqual(model.normalizeIndentation(' a'), ' a');1023assert.strictEqual(model.normalizeIndentation(' a'), ' a');1024assert.strictEqual(model.normalizeIndentation('a'), 'a');1025assert.strictEqual(model.normalizeIndentation(' \t a'), '\t\ta');1026assert.strictEqual(model.normalizeIndentation(' \t a'), '\t a');1027assert.strictEqual(model.normalizeIndentation(' \t a'), '\t a');1028assert.strictEqual(model.normalizeIndentation(' \t a'), '\t a');1029assert.strictEqual(model.normalizeIndentation(' \ta'), '\ta');10301031model.dispose();1032});10331034test('normalizeIndentation 2', () => {1035const model = createTextModel('');10361037assert.strictEqual(model.normalizeIndentation('\ta'), ' a');1038assert.strictEqual(model.normalizeIndentation(' a'), ' a');1039assert.strictEqual(model.normalizeIndentation(' a'), ' a');1040assert.strictEqual(model.normalizeIndentation(' a'), ' a');1041assert.strictEqual(model.normalizeIndentation(' a'), ' a');1042assert.strictEqual(model.normalizeIndentation('a'), 'a');1043assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');1044assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');1045assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');1046assert.strictEqual(model.normalizeIndentation(' \t a'), ' a');1047assert.strictEqual(model.normalizeIndentation(' \ta'), ' a');10481049model.dispose();1050});10511052test('getLineFirstNonWhitespaceColumn', () => {1053const model = createTextModel([1054'asd',1055' asd',1056'\tasd',1057' asd',1058'\t\tasd',1059' ',1060' ',1061'\t',1062'\t\t',1063' \tasd',1064'',1065''1066].join('\n'));10671068assert.strictEqual(model.getLineFirstNonWhitespaceColumn(1), 1, '1');1069assert.strictEqual(model.getLineFirstNonWhitespaceColumn(2), 2, '2');1070assert.strictEqual(model.getLineFirstNonWhitespaceColumn(3), 2, '3');1071assert.strictEqual(model.getLineFirstNonWhitespaceColumn(4), 3, '4');1072assert.strictEqual(model.getLineFirstNonWhitespaceColumn(5), 3, '5');1073assert.strictEqual(model.getLineFirstNonWhitespaceColumn(6), 0, '6');1074assert.strictEqual(model.getLineFirstNonWhitespaceColumn(7), 0, '7');1075assert.strictEqual(model.getLineFirstNonWhitespaceColumn(8), 0, '8');1076assert.strictEqual(model.getLineFirstNonWhitespaceColumn(9), 0, '9');1077assert.strictEqual(model.getLineFirstNonWhitespaceColumn(10), 4, '10');1078assert.strictEqual(model.getLineFirstNonWhitespaceColumn(11), 0, '11');1079assert.strictEqual(model.getLineFirstNonWhitespaceColumn(12), 0, '12');10801081model.dispose();1082});10831084test('getLineLastNonWhitespaceColumn', () => {1085const model = createTextModel([1086'asd',1087'asd ',1088'asd\t',1089'asd ',1090'asd\t\t',1091' ',1092' ',1093'\t',1094'\t\t',1095'asd \t',1096'',1097''1098].join('\n'));10991100assert.strictEqual(model.getLineLastNonWhitespaceColumn(1), 4, '1');1101assert.strictEqual(model.getLineLastNonWhitespaceColumn(2), 4, '2');1102assert.strictEqual(model.getLineLastNonWhitespaceColumn(3), 4, '3');1103assert.strictEqual(model.getLineLastNonWhitespaceColumn(4), 4, '4');1104assert.strictEqual(model.getLineLastNonWhitespaceColumn(5), 4, '5');1105assert.strictEqual(model.getLineLastNonWhitespaceColumn(6), 0, '6');1106assert.strictEqual(model.getLineLastNonWhitespaceColumn(7), 0, '7');1107assert.strictEqual(model.getLineLastNonWhitespaceColumn(8), 0, '8');1108assert.strictEqual(model.getLineLastNonWhitespaceColumn(9), 0, '9');1109assert.strictEqual(model.getLineLastNonWhitespaceColumn(10), 4, '10');1110assert.strictEqual(model.getLineLastNonWhitespaceColumn(11), 0, '11');1111assert.strictEqual(model.getLineLastNonWhitespaceColumn(12), 0, '12');11121113model.dispose();1114});11151116test('#50471. getValueInRange with invalid range', () => {1117const m = createTextModel('My First Line\r\nMy Second Line\r\nMy Third Line');1118assert.strictEqual(m.getValueInRange(new Range(1, NaN, 1, 3)), 'My');1119assert.strictEqual(m.getValueInRange(new Range(NaN, NaN, NaN, NaN)), '');1120m.dispose();1121});11221123test('issue #168836: updating tabSize should also update indentSize when indentSize is set to "tabSize"', () => {1124const m = createTextModel('some text', null, {1125tabSize: 2,1126indentSize: 'tabSize'1127});1128assert.strictEqual(m.getOptions().tabSize, 2);1129assert.strictEqual(m.getOptions().indentSize, 2);1130assert.strictEqual(m.getOptions().originalIndentSize, 'tabSize');1131m.updateOptions({1132tabSize: 41133});1134assert.strictEqual(m.getOptions().tabSize, 4);1135assert.strictEqual(m.getOptions().indentSize, 4);1136assert.strictEqual(m.getOptions().originalIndentSize, 'tabSize');1137m.dispose();1138});1139});11401141suite('TextModel.mightContainRTL', () => {11421143ensureNoDisposablesAreLeakedInTestSuite();11441145test('nope', () => {1146const model = createTextModel('hello world!');1147assert.strictEqual(model.mightContainRTL(), false);1148model.dispose();1149});11501151test('yes', () => {1152const model = createTextModel('Hello,\nזוהי עובדה מבוססת שדעתו');1153assert.strictEqual(model.mightContainRTL(), true);1154model.dispose();1155});11561157test('setValue resets 1', () => {1158const model = createTextModel('hello world!');1159assert.strictEqual(model.mightContainRTL(), false);1160model.setValue('Hello,\nזוהי עובדה מבוססת שדעתו');1161assert.strictEqual(model.mightContainRTL(), true);1162model.dispose();1163});11641165test('setValue resets 2', () => {1166const model = createTextModel('Hello,\nهناك حقيقة مثبتة منذ زمن طويل');1167assert.strictEqual(model.mightContainRTL(), true);1168model.setValue('hello world!');1169assert.strictEqual(model.mightContainRTL(), false);1170model.dispose();1171});11721173});11741175suite('TextModel.createSnapshot', () => {11761177ensureNoDisposablesAreLeakedInTestSuite();11781179test('empty file', () => {1180const model = createTextModel('');1181const snapshot = model.createSnapshot();1182assert.strictEqual(snapshot.read(), null);1183model.dispose();1184});11851186test('file with BOM', () => {1187const model = createTextModel(UTF8_BOM_CHARACTER + 'Hello');1188assert.strictEqual(model.getLineContent(1), 'Hello');1189const snapshot = model.createSnapshot(true);1190assert.strictEqual(snapshot.read(), UTF8_BOM_CHARACTER + 'Hello');1191assert.strictEqual(snapshot.read(), null);1192model.dispose();1193});11941195test('regular file', () => {1196const model = createTextModel('My First Line\n\t\tMy Second Line\n Third Line\n\n1');1197const snapshot = model.createSnapshot();1198assert.strictEqual(snapshot.read(), 'My First Line\n\t\tMy Second Line\n Third Line\n\n1');1199assert.strictEqual(snapshot.read(), null);1200model.dispose();1201});12021203test('large file', () => {1204const lines: string[] = [];1205for (let i = 0; i < 1000; i++) {1206lines[i] = 'Just some text that is a bit long such that it can consume some memory';1207}1208const text = lines.join('\n');12091210const model = createTextModel(text);1211const snapshot = model.createSnapshot();1212let actual = '';12131214// 70999 length => at most 2 read calls are necessary1215const tmp1 = snapshot.read();1216assert.ok(tmp1);1217actual += tmp1;12181219const tmp2 = snapshot.read();1220if (tmp2 === null) {1221// all good1222} else {1223actual += tmp2;1224assert.strictEqual(snapshot.read(), null);1225}12261227assert.strictEqual(actual, text);12281229model.dispose();1230});12311232test('issue #119632: invalid range', () => {1233const model = createTextModel('hello world!');1234// eslint-disable-next-line local/code-no-any-casts1235const actual = model._validateRangeRelaxedNoAllocations(new Range(<any>undefined, 0, <any>undefined, 1));1236assert.deepStrictEqual(actual, new Range(1, 1, 1, 1));1237model.dispose();1238});12391240});124112421243