Path: blob/main/src/vs/editor/test/common/model/textModelSearch.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 { Position } from '../../../common/core/position.js';8import { Range } from '../../../common/core/range.js';9import { getMapForWordSeparators } from '../../../common/core/wordCharacterClassifier.js';10import { USUAL_WORD_SEPARATORS } from '../../../common/core/wordHelper.js';11import { EndOfLineSequence, FindMatch, SearchData } from '../../../common/model.js';12import { TextModel } from '../../../common/model/textModel.js';13import { SearchParams, TextModelSearch, isMultilineRegexSource } from '../../../common/model/textModelSearch.js';14import { createTextModel } from '../testTextModel.js';1516// --------- Find17suite('TextModelSearch', () => {1819ensureNoDisposablesAreLeakedInTestSuite();2021const usualWordSeparators = getMapForWordSeparators(USUAL_WORD_SEPARATORS, []);2223function assertFindMatch(actual: FindMatch | null, expectedRange: Range, expectedMatches: string[] | null = null): void {24assert.deepStrictEqual(actual, new FindMatch(expectedRange, expectedMatches));25}2627function _assertFindMatches(model: TextModel, searchParams: SearchParams, expectedMatches: FindMatch[]): void {28const actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), false, 1000);29assert.deepStrictEqual(actual, expectedMatches, 'findMatches OK');3031// test `findNextMatch`32let startPos = new Position(1, 1);33let match = TextModelSearch.findNextMatch(model, searchParams, startPos, false);34assert.deepStrictEqual(match, expectedMatches[0], `findNextMatch ${startPos}`);35for (const expectedMatch of expectedMatches) {36startPos = expectedMatch.range.getStartPosition();37match = TextModelSearch.findNextMatch(model, searchParams, startPos, false);38assert.deepStrictEqual(match, expectedMatch, `findNextMatch ${startPos}`);39}4041// test `findPrevMatch`42startPos = new Position(model.getLineCount(), model.getLineMaxColumn(model.getLineCount()));43match = TextModelSearch.findPreviousMatch(model, searchParams, startPos, false);44assert.deepStrictEqual(match, expectedMatches[expectedMatches.length - 1], `findPrevMatch ${startPos}`);45for (const expectedMatch of expectedMatches) {46startPos = expectedMatch.range.getEndPosition();47match = TextModelSearch.findPreviousMatch(model, searchParams, startPos, false);48assert.deepStrictEqual(match, expectedMatch, `findPrevMatch ${startPos}`);49}50}5152function assertFindMatches(text: string, searchString: string, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, _expected: [number, number, number, number][]): void {53const expectedRanges = _expected.map(entry => new Range(entry[0], entry[1], entry[2], entry[3]));54const expectedMatches = expectedRanges.map(entry => new FindMatch(entry, null));55const searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);5657const model = createTextModel(text);58_assertFindMatches(model, searchParams, expectedMatches);59model.dispose();606162const model2 = createTextModel(text);63model2.setEOL(EndOfLineSequence.CRLF);64_assertFindMatches(model2, searchParams, expectedMatches);65model2.dispose();66}6768const regularText = [69'This is some foo - bar text which contains foo and bar - as in Barcelona.',70'Now it begins a word fooBar and now it is caps Foo-isn\'t this great?',71'And here\'s a dull line with nothing interesting in it',72'It is also interesting if it\'s part of a word like amazingFooBar',73'Again nothing interesting here'74];7576test('Simple find', () => {77assertFindMatches(78regularText.join('\n'),79'foo', false, false, null,80[81[1, 14, 1, 17],82[1, 44, 1, 47],83[2, 22, 2, 25],84[2, 48, 2, 51],85[4, 59, 4, 62]86]87);88});8990test('Case sensitive find', () => {91assertFindMatches(92regularText.join('\n'),93'foo', false, true, null,94[95[1, 14, 1, 17],96[1, 44, 1, 47],97[2, 22, 2, 25]98]99);100});101102test('Whole words find', () => {103assertFindMatches(104regularText.join('\n'),105'foo', false, false, USUAL_WORD_SEPARATORS,106[107[1, 14, 1, 17],108[1, 44, 1, 47],109[2, 48, 2, 51]110]111);112});113114test('/^/ find', () => {115assertFindMatches(116regularText.join('\n'),117'^', true, false, null,118[119[1, 1, 1, 1],120[2, 1, 2, 1],121[3, 1, 3, 1],122[4, 1, 4, 1],123[5, 1, 5, 1]124]125);126});127128test('/$/ find', () => {129assertFindMatches(130regularText.join('\n'),131'$', true, false, null,132[133[1, 74, 1, 74],134[2, 69, 2, 69],135[3, 54, 3, 54],136[4, 65, 4, 65],137[5, 31, 5, 31]138]139);140});141142test('/.*/ find', () => {143assertFindMatches(144regularText.join('\n'),145'.*', true, false, null,146[147[1, 1, 1, 74],148[2, 1, 2, 69],149[3, 1, 3, 54],150[4, 1, 4, 65],151[5, 1, 5, 31]152]153);154});155156test('/^$/ find', () => {157assertFindMatches(158[159'This is some foo - bar text which contains foo and bar - as in Barcelona.',160'',161'And here\'s a dull line with nothing interesting in it',162'',163'Again nothing interesting here'164].join('\n'),165'^$', true, false, null,166[167[2, 1, 2, 1],168[4, 1, 4, 1]169]170);171});172173test('multiline find 1', () => {174assertFindMatches(175[176'Just some text text',177'Just some text text',178'some text again',179'again some text'180].join('\n'),181'text\\n', true, false, null,182[183[1, 16, 2, 1],184[2, 16, 3, 1],185]186);187});188189test('multiline find 2', () => {190assertFindMatches(191[192'Just some text text',193'Just some text text',194'some text again',195'again some text'196].join('\n'),197'text\\nJust', true, false, null,198[199[1, 16, 2, 5]200]201);202});203204test('multiline find 3', () => {205assertFindMatches(206[207'Just some text text',208'Just some text text',209'some text again',210'again some text'211].join('\n'),212'\\nagain', true, false, null,213[214[3, 16, 4, 6]215]216);217});218219test('multiline find 4', () => {220assertFindMatches(221[222'Just some text text',223'Just some text text',224'some text again',225'again some text'226].join('\n'),227'.*\\nJust.*\\n', true, false, null,228[229[1, 1, 3, 1]230]231);232});233234test('multiline find with line beginning regex', () => {235assertFindMatches(236[237'if',238'else',239'',240'if',241'else'242].join('\n'),243'^if\\nelse', true, false, null,244[245[1, 1, 2, 5],246[4, 1, 5, 5]247]248);249});250251test('matching empty lines using boundary expression', () => {252assertFindMatches(253[254'if',255'',256'else',257' ',258'if',259' ',260'else'261].join('\n'),262'^\\s*$\\n', true, false, null,263[264[2, 1, 3, 1],265[4, 1, 5, 1],266[6, 1, 7, 1]267]268);269});270271test('matching lines starting with A and ending with B', () => {272assertFindMatches(273[274'a if b',275'a',276'ab',277'eb'278].join('\n'),279'^a.*b$', true, false, null,280[281[1, 1, 1, 7],282[3, 1, 3, 3]283]284);285});286287test('multiline find with line ending regex', () => {288assertFindMatches(289[290'if',291'else',292'',293'if',294'elseif',295'else'296].join('\n'),297'if\\nelse$', true, false, null,298[299[1, 1, 2, 5],300[5, 5, 6, 5]301]302);303});304305test('issue #4836 - ^.*$', () => {306assertFindMatches(307[308'Just some text text',309'',310'some text again',311'',312'again some text'313].join('\n'),314'^.*$', true, false, null,315[316[1, 1, 1, 20],317[2, 1, 2, 1],318[3, 1, 3, 16],319[4, 1, 4, 1],320[5, 1, 5, 16],321]322);323});324325test('multiline find for non-regex string', () => {326assertFindMatches(327[328'Just some text text',329'some text text',330'some text again',331'again some text',332'but not some'333].join('\n'),334'text\nsome', false, false, null,335[336[1, 16, 2, 5],337[2, 11, 3, 5],338]339);340});341342test('issue #3623: Match whole word does not work for not latin characters', () => {343assertFindMatches(344[345'я',346'компилятор',347'обфускация',348':я-я'349].join('\n'),350'я', false, false, USUAL_WORD_SEPARATORS,351[352[1, 1, 1, 2],353[4, 2, 4, 3],354[4, 4, 4, 5],355]356);357});358359test('issue #27459: Match whole words regression', () => {360assertFindMatches(361[362'this._register(this._textAreaInput.onKeyDown((e: IKeyboardEvent) => {',363' this._viewController.emitKeyDown(e);',364'}));',365].join('\n'),366'((e: ', false, false, USUAL_WORD_SEPARATORS,367[368[1, 45, 1, 50]369]370);371});372373test('issue #27594: Search results disappear', () => {374assertFindMatches(375[376'this.server.listen(0);',377].join('\n'),378'listen(', false, false, USUAL_WORD_SEPARATORS,379[380[1, 13, 1, 20]381]382);383});384385test('findNextMatch without regex', () => {386const model = createTextModel('line line one\nline two\nthree');387388const searchParams = new SearchParams('line', false, false, null);389390let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), false);391assertFindMatch(actual, new Range(1, 1, 1, 5));392393actual = TextModelSearch.findNextMatch(model, searchParams, actual!.range.getEndPosition(), false);394assertFindMatch(actual, new Range(1, 6, 1, 10));395396actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 3), false);397assertFindMatch(actual, new Range(1, 6, 1, 10));398399actual = TextModelSearch.findNextMatch(model, searchParams, actual!.range.getEndPosition(), false);400assertFindMatch(actual, new Range(2, 1, 2, 5));401402actual = TextModelSearch.findNextMatch(model, searchParams, actual!.range.getEndPosition(), false);403assertFindMatch(actual, new Range(1, 1, 1, 5));404405model.dispose();406});407408test('findNextMatch with beginning boundary regex', () => {409const model = createTextModel('line one\nline two\nthree');410411const searchParams = new SearchParams('^line', true, false, null);412413let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), false);414assertFindMatch(actual, new Range(1, 1, 1, 5));415416actual = TextModelSearch.findNextMatch(model, searchParams, actual!.range.getEndPosition(), false);417assertFindMatch(actual, new Range(2, 1, 2, 5));418419actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 3), false);420assertFindMatch(actual, new Range(2, 1, 2, 5));421422actual = TextModelSearch.findNextMatch(model, searchParams, actual!.range.getEndPosition(), false);423assertFindMatch(actual, new Range(1, 1, 1, 5));424425model.dispose();426});427428test('findNextMatch with beginning boundary regex and line has repetitive beginnings', () => {429const model = createTextModel('line line one\nline two\nthree');430431const searchParams = new SearchParams('^line', true, false, null);432433let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), false);434assertFindMatch(actual, new Range(1, 1, 1, 5));435436actual = TextModelSearch.findNextMatch(model, searchParams, actual!.range.getEndPosition(), false);437assertFindMatch(actual, new Range(2, 1, 2, 5));438439actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 3), false);440assertFindMatch(actual, new Range(2, 1, 2, 5));441442actual = TextModelSearch.findNextMatch(model, searchParams, actual!.range.getEndPosition(), false);443assertFindMatch(actual, new Range(1, 1, 1, 5));444445model.dispose();446});447448test('findNextMatch with beginning boundary multiline regex and line has repetitive beginnings', () => {449const model = createTextModel('line line one\nline two\nline three\nline four');450451const searchParams = new SearchParams('^line.*\\nline', true, false, null);452453let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), false);454assertFindMatch(actual, new Range(1, 1, 2, 5));455456actual = TextModelSearch.findNextMatch(model, searchParams, actual!.range.getEndPosition(), false);457assertFindMatch(actual, new Range(3, 1, 4, 5));458459actual = TextModelSearch.findNextMatch(model, searchParams, new Position(2, 1), false);460assertFindMatch(actual, new Range(2, 1, 3, 5));461462model.dispose();463});464465test('findNextMatch with ending boundary regex', () => {466const model = createTextModel('one line line\ntwo line\nthree');467468const searchParams = new SearchParams('line$', true, false, null);469470let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), false);471assertFindMatch(actual, new Range(1, 10, 1, 14));472473actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 4), false);474assertFindMatch(actual, new Range(1, 10, 1, 14));475476actual = TextModelSearch.findNextMatch(model, searchParams, actual!.range.getEndPosition(), false);477assertFindMatch(actual, new Range(2, 5, 2, 9));478479actual = TextModelSearch.findNextMatch(model, searchParams, actual!.range.getEndPosition(), false);480assertFindMatch(actual, new Range(1, 10, 1, 14));481482model.dispose();483});484485test('findMatches with capturing matches', () => {486const model = createTextModel('one line line\ntwo line\nthree');487488const searchParams = new SearchParams('(l(in)e)', true, false, null);489490const actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 100);491assert.deepStrictEqual(actual, [492new FindMatch(new Range(1, 5, 1, 9), ['line', 'line', 'in']),493new FindMatch(new Range(1, 10, 1, 14), ['line', 'line', 'in']),494new FindMatch(new Range(2, 5, 2, 9), ['line', 'line', 'in']),495]);496497model.dispose();498});499500test('findMatches multiline with capturing matches', () => {501const model = createTextModel('one line line\ntwo line\nthree');502503const searchParams = new SearchParams('(l(in)e)\\n', true, false, null);504505const actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 100);506assert.deepStrictEqual(actual, [507new FindMatch(new Range(1, 10, 2, 1), ['line\n', 'line', 'in']),508new FindMatch(new Range(2, 5, 3, 1), ['line\n', 'line', 'in']),509]);510511model.dispose();512});513514test('findNextMatch with capturing matches', () => {515const model = createTextModel('one line line\ntwo line\nthree');516517const searchParams = new SearchParams('(l(in)e)', true, false, null);518519const actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);520assertFindMatch(actual, new Range(1, 5, 1, 9), ['line', 'line', 'in']);521522model.dispose();523});524525test('findNextMatch multiline with capturing matches', () => {526const model = createTextModel('one line line\ntwo line\nthree');527528const searchParams = new SearchParams('(l(in)e)\\n', true, false, null);529530const actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);531assertFindMatch(actual, new Range(1, 10, 2, 1), ['line\n', 'line', 'in']);532533model.dispose();534});535536test('findPreviousMatch with capturing matches', () => {537const model = createTextModel('one line line\ntwo line\nthree');538539const searchParams = new SearchParams('(l(in)e)', true, false, null);540541const actual = TextModelSearch.findPreviousMatch(model, searchParams, new Position(1, 1), true);542assertFindMatch(actual, new Range(2, 5, 2, 9), ['line', 'line', 'in']);543544model.dispose();545});546547test('findPreviousMatch multiline with capturing matches', () => {548const model = createTextModel('one line line\ntwo line\nthree');549550const searchParams = new SearchParams('(l(in)e)\\n', true, false, null);551552const actual = TextModelSearch.findPreviousMatch(model, searchParams, new Position(1, 1), true);553assertFindMatch(actual, new Range(2, 5, 3, 1), ['line\n', 'line', 'in']);554555model.dispose();556});557558test('\\n matches \\r\\n', () => {559const model = createTextModel('a\r\nb\r\nc\r\nd\r\ne\r\nf\r\ng\r\nh\r\ni');560561assert.strictEqual(model.getEOL(), '\r\n');562563let searchParams = new SearchParams('h\\n', true, false, null);564let actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);565actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 1000)[0];566assertFindMatch(actual, new Range(8, 1, 9, 1), ['h\n']);567568searchParams = new SearchParams('g\\nh\\n', true, false, null);569actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);570actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 1000)[0];571assertFindMatch(actual, new Range(7, 1, 9, 1), ['g\nh\n']);572573searchParams = new SearchParams('\\ni', true, false, null);574actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);575actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 1000)[0];576assertFindMatch(actual, new Range(8, 2, 9, 2), ['\ni']);577578model.dispose();579});580581test('\\r can never be found', () => {582const model = createTextModel('a\r\nb\r\nc\r\nd\r\ne\r\nf\r\ng\r\nh\r\ni');583584assert.strictEqual(model.getEOL(), '\r\n');585586const searchParams = new SearchParams('\\r\\n', true, false, null);587const actual = TextModelSearch.findNextMatch(model, searchParams, new Position(1, 1), true);588assert.strictEqual(actual, null);589assert.deepStrictEqual(TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 1000), []);590591model.dispose();592});593594function assertParseSearchResult(searchString: string, isRegex: boolean, matchCase: boolean, wordSeparators: string | null, expected: SearchData | null): void {595const searchParams = new SearchParams(searchString, isRegex, matchCase, wordSeparators);596const actual = searchParams.parseSearchRequest();597598if (expected === null) {599assert.ok(actual === null);600} else {601assert.deepStrictEqual(actual!.regex, expected.regex);602assert.deepStrictEqual(actual!.simpleSearch, expected.simpleSearch);603if (wordSeparators) {604assert.ok(actual!.wordSeparators !== null);605} else {606assert.ok(actual!.wordSeparators === null);607}608}609}610611test('parseSearchRequest invalid', () => {612assertParseSearchResult('', true, true, USUAL_WORD_SEPARATORS, null);613assertParseSearchResult('(', true, false, null, null);614});615616test('parseSearchRequest non regex', () => {617assertParseSearchResult('foo', false, false, null, new SearchData(/foo/giu, null, null));618assertParseSearchResult('foo', false, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/giu, usualWordSeparators, null));619assertParseSearchResult('foo', false, true, null, new SearchData(/foo/gu, null, 'foo'));620assertParseSearchResult('foo', false, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/gu, usualWordSeparators, 'foo'));621assertParseSearchResult('foo\\n', false, false, null, new SearchData(/foo\\n/giu, null, null));622assertParseSearchResult('foo\\\\n', false, false, null, new SearchData(/foo\\\\n/giu, null, null));623assertParseSearchResult('foo\\r', false, false, null, new SearchData(/foo\\r/giu, null, null));624assertParseSearchResult('foo\\\\r', false, false, null, new SearchData(/foo\\\\r/giu, null, null));625});626627test('parseSearchRequest regex', () => {628assertParseSearchResult('foo', true, false, null, new SearchData(/foo/giu, null, null));629assertParseSearchResult('foo', true, false, USUAL_WORD_SEPARATORS, new SearchData(/foo/giu, usualWordSeparators, null));630assertParseSearchResult('foo', true, true, null, new SearchData(/foo/gu, null, null));631assertParseSearchResult('foo', true, true, USUAL_WORD_SEPARATORS, new SearchData(/foo/gu, usualWordSeparators, null));632assertParseSearchResult('foo\\n', true, false, null, new SearchData(/foo\n/gimu, null, null));633assertParseSearchResult('foo\\\\n', true, false, null, new SearchData(/foo\\n/giu, null, null));634assertParseSearchResult('foo\\r', true, false, null, new SearchData(/foo\r/gimu, null, null));635assertParseSearchResult('foo\\\\r', true, false, null, new SearchData(/foo\\r/giu, null, null));636});637638test('issue #53415. \W should match line break.', () => {639assertFindMatches(640[641'text',642'180702-',643'180703-180704'644].join('\n'),645'\\d{6}-\\W', true, false, null,646[647[2, 1, 3, 1]648]649);650651assertFindMatches(652[653'Just some text',654'',655'Just'656].join('\n'),657'\\W', true, false, null,658[659[1, 5, 1, 6],660[1, 10, 1, 11],661[1, 15, 2, 1],662[2, 1, 3, 1]663]664);665666// Line break doesn't affect the result as we always use \n as line break when doing search667assertFindMatches(668[669'Just some text',670'',671'Just'672].join('\r\n'),673'\\W', true, false, null,674[675[1, 5, 1, 6],676[1, 10, 1, 11],677[1, 15, 2, 1],678[2, 1, 3, 1]679]680);681682assertFindMatches(683[684'Just some text',685'\tJust',686'Just'687].join('\n'),688'\\W', true, false, null,689[690[1, 5, 1, 6],691[1, 10, 1, 11],692[1, 15, 2, 1],693[2, 1, 2, 2],694[2, 6, 3, 1],695]696);697698// line break is seen as one non-word character699assertFindMatches(700[701'Just some text',702'',703'Just'704].join('\n'),705'\\W{2}', true, false, null,706[707[1, 5, 1, 7],708[1, 16, 3, 1]709]710);711712// even if it's \r\n713assertFindMatches(714[715'Just some text',716'',717'Just'718].join('\r\n'),719'\\W{2}', true, false, null,720[721[1, 5, 1, 7],722[1, 16, 3, 1]723]724);725});726727test('Simple find using unicode escape sequences', () => {728assertFindMatches(729regularText.join('\n'),730'\\u{0066}\\u006f\\u006F', true, false, null,731[732[1, 14, 1, 17],733[1, 44, 1, 47],734[2, 22, 2, 25],735[2, 48, 2, 51],736[4, 59, 4, 62]737]738);739});740741test('isMultilineRegexSource', () => {742assert(!isMultilineRegexSource('foo'));743assert(!isMultilineRegexSource(''));744assert(!isMultilineRegexSource('foo\\sbar'));745assert(!isMultilineRegexSource('\\\\notnewline'));746747assert(isMultilineRegexSource('foo\\nbar'));748assert(isMultilineRegexSource('foo\\nbar\\s'));749assert(isMultilineRegexSource('foo\\r\\n'));750assert(isMultilineRegexSource('\\n'));751assert(isMultilineRegexSource('foo\\W'));752assert(isMultilineRegexSource('foo\n'));753assert(isMultilineRegexSource('foo\r\n'));754});755756test('isMultilineRegexSource correctly identifies multiline patterns', () => {757const singleLinePatterns = [758'MARK:\\s*(?<label>.*)$',759'^// Header$',760'\\s*[-=]+\\s*',761];762763const multiLinePatterns = [764'^\/\/ =+\\n^\/\/ (?<label>[^\\n]+?)\\n^\/\/ =+$',765'header\\r\\nfooter',766'start\\r|\\nend',767'top\nmiddle\r\nbottom'768];769770for (const pattern of singleLinePatterns) {771assert.strictEqual(isMultilineRegexSource(pattern), false, `Pattern should not be multiline: ${pattern}`);772}773774for (const pattern of multiLinePatterns) {775assert.strictEqual(isMultilineRegexSource(pattern), true, `Pattern should be multiline: ${pattern}`);776}777});778779test('issue #74715. \\d* finds empty string and stops searching.', () => {780const model = createTextModel('10.243.30.10');781782const searchParams = new SearchParams('\\d*', true, false, null);783784const actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 100);785assert.deepStrictEqual(actual, [786new FindMatch(new Range(1, 1, 1, 3), ['10']),787new FindMatch(new Range(1, 3, 1, 3), ['']),788new FindMatch(new Range(1, 4, 1, 7), ['243']),789new FindMatch(new Range(1, 7, 1, 7), ['']),790new FindMatch(new Range(1, 8, 1, 10), ['30']),791new FindMatch(new Range(1, 10, 1, 10), ['']),792new FindMatch(new Range(1, 11, 1, 13), ['10'])793]);794795model.dispose();796});797798test('issue #100134. Zero-length matches should properly step over surrogate pairs', () => {799// 1[Laptop]1 - there shoud be no matches inside of [Laptop] emoji800assertFindMatches('1\uD83D\uDCBB1', '()', true, false, null,801[802[1, 1, 1, 1],803[1, 2, 1, 2],804[1, 4, 1, 4],805[1, 5, 1, 5],806807]808);809// 1[Hacker Cat]1 = 1[Cat Face][ZWJ][Laptop]1 - there shoud be matches between emoji and ZWJ810// there shoud be no matches inside of [Cat Face] and [Laptop] emoji811assertFindMatches('1\uD83D\uDC31\u200D\uD83D\uDCBB1', '()', true, false, null,812[813[1, 1, 1, 1],814[1, 2, 1, 2],815[1, 4, 1, 4],816[1, 5, 1, 5],817[1, 7, 1, 7],818[1, 8, 1, 8]819]820);821});822});823824825