Path: blob/main/src/vs/workbench/api/test/browser/extHostWorkspace.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 { CancellationToken } from '../../../../base/common/cancellation.js';7import { basename } from '../../../../base/common/path.js';8import { URI, UriComponents } from '../../../../base/common/uri.js';9import { ExtensionIdentifier } from '../../../../platform/extensions/common/extensions.js';10import { ILogService, NullLogService } from '../../../../platform/log/common/log.js';11import { IWorkspaceFolderData } from '../../../../platform/workspace/common/workspace.js';12import { MainThreadWorkspace } from '../../browser/mainThreadWorkspace.js';13import { IMainContext, IWorkspaceData, MainContext, ITextSearchComplete } from '../../common/extHost.protocol.js';14import { RelativePattern } from '../../common/extHostTypes.js';15import { ExtHostWorkspace } from '../../common/extHostWorkspace.js';16import { mock } from '../../../../base/test/common/mock.js';17import { TestRPCProtocol } from '../common/testRPCProtocol.js';18import { ExtHostRpcService } from '../../common/extHostRpcService.js';19import { IExtHostInitDataService } from '../../common/extHostInitDataService.js';20import { IFileQueryBuilderOptions, ITextQueryBuilderOptions } from '../../../services/search/common/queryBuilder.js';21import { IPatternInfo } from '../../../services/search/common/search.js';22import { isLinux, isWindows } from '../../../../base/common/platform.js';23import { IExtHostFileSystemInfo } from '../../common/extHostFileSystemInfo.js';24import { FileSystemProviderCapabilities } from '../../../../platform/files/common/files.js';25import { nullExtensionDescription as extensionDescriptor } from '../../../services/extensions/common/extensions.js';26import { IURITransformerService } from '../../common/extHostUriTransformerService.js';27import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';28import { ExcludeSettingOptions } from '../../../services/search/common/searchExtTypes.js';2930function createExtHostWorkspace(mainContext: IMainContext, data: IWorkspaceData, logService: ILogService): ExtHostWorkspace {31const result = new ExtHostWorkspace(32new ExtHostRpcService(mainContext),33new class extends mock<IExtHostInitDataService>() { override workspace = data; },34new class extends mock<IExtHostFileSystemInfo>() { override getCapabilities() { return isLinux ? FileSystemProviderCapabilities.PathCaseSensitive : undefined; } },35logService,36new class extends mock<IURITransformerService>() { }37);38result.$initializeWorkspace(data, true);39return result;40}4142suite('ExtHostWorkspace', function () {4344ensureNoDisposablesAreLeakedInTestSuite();4546function assertAsRelativePath(workspace: ExtHostWorkspace, input: string, expected: string, includeWorkspace?: boolean) {47const actual = workspace.getRelativePath(input, includeWorkspace);48assert.strictEqual(actual, expected);49}5051test('asRelativePath', () => {5253const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService());5455assertAsRelativePath(ws, '/Coding/Applications/NewsWoWBot/bernd/das/brot', 'bernd/das/brot');56assertAsRelativePath(ws, '/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart',57'/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart');5859assertAsRelativePath(ws, '', '');60assertAsRelativePath(ws, '/foo/bar', '/foo/bar');61assertAsRelativePath(ws, 'in/out', 'in/out');62});6364test('asRelativePath, same paths, #11402', function () {65const root = '/home/aeschli/workspaces/samples/docker';66const input = '/home/aeschli/workspaces/samples/docker';67const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());6869assertAsRelativePath(ws, input, input);7071const input2 = '/home/aeschli/workspaces/samples/docker/a.file';72assertAsRelativePath(ws, input2, 'a.file');73});7475test('asRelativePath, no workspace', function () {76const ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService());77assertAsRelativePath(ws, '', '');78assertAsRelativePath(ws, '/foo/bar', '/foo/bar');79});8081test('asRelativePath, multiple folders', function () {82const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());83assertAsRelativePath(ws, '/Coding/One/file.txt', 'One/file.txt');84assertAsRelativePath(ws, '/Coding/Two/files/out.txt', 'Two/files/out.txt');85assertAsRelativePath(ws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');86});8788test('slightly inconsistent behaviour of asRelativePath and getWorkspaceFolder, #31553', function () {89const mrws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());9091assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt');92assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt', true);93assertAsRelativePath(mrws, '/Coding/One/file.txt', 'file.txt', false);94assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'Two/files/out.txt');95assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'Two/files/out.txt', true);96assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'files/out.txt', false);97assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');98assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true);99assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false);100101const srws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService());102assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt');103assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt', false);104assertAsRelativePath(srws, '/Coding/One/file.txt', 'One/file.txt', true);105assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');106assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true);107assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false);108});109110test('getPath, legacy', function () {111let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());112assert.strictEqual(ws.getPath(), undefined);113114ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService());115assert.strictEqual(ws.getPath(), undefined);116117ws = createExtHostWorkspace(new TestRPCProtocol(), undefined!, new NullLogService());118assert.strictEqual(ws.getPath(), undefined);119120ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService());121assert.strictEqual(ws.getPath()!.replace(/\\/g, '/'), '/Folder');122123ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService());124assert.strictEqual(ws.getPath()!.replace(/\\/g, '/'), '/Folder');125});126127test('WorkspaceFolder has name and index', function () {128const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());129130const [one, two] = ws.getWorkspaceFolders()!;131132assert.strictEqual(one.name, 'One');133assert.strictEqual(one.index, 0);134assert.strictEqual(two.name, 'Two');135assert.strictEqual(two.index, 1);136});137138test('getContainingWorkspaceFolder', () => {139const ws = createExtHostWorkspace(new TestRPCProtocol(), {140id: 'foo',141name: 'Test',142folders: [143aWorkspaceFolderData(URI.file('/Coding/One'), 0),144aWorkspaceFolderData(URI.file('/Coding/Two'), 1),145aWorkspaceFolderData(URI.file('/Coding/Two/Nested'), 2)146]147}, new NullLogService());148149let folder = ws.getWorkspaceFolder(URI.file('/foo/bar'));150assert.strictEqual(folder, undefined);151152folder = ws.getWorkspaceFolder(URI.file('/Coding/One/file/path.txt'))!;153assert.strictEqual(folder.name, 'One');154155folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/file/path.txt'))!;156assert.strictEqual(folder.name, 'Two');157158folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nest'))!;159assert.strictEqual(folder.name, 'Two');160161folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/file'))!;162assert.strictEqual(folder.name, 'Nested');163164folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/f'))!;165assert.strictEqual(folder.name, 'Nested');166167folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'), true)!;168assert.strictEqual(folder.name, 'Two');169170folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'), true)!;171assert.strictEqual(folder.name, 'Two');172173folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'))!;174assert.strictEqual(folder.name, 'Nested');175176folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'))!;177assert.strictEqual(folder.name, 'Nested');178179folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), true)!;180assert.strictEqual(folder, undefined);181182folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), false)!;183assert.strictEqual(folder.name, 'Two');184});185186test('Multiroot change event should have a delta, #29641', function (done) {187const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());188189let finished = false;190const finish = (error?: any) => {191if (!finished) {192finished = true;193done(error);194}195};196197let sub = ws.onDidChangeWorkspace(e => {198try {199assert.deepStrictEqual(e.added, []);200assert.deepStrictEqual(e.removed, []);201} catch (error) {202finish(error);203}204});205ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] });206sub.dispose();207208sub = ws.onDidChangeWorkspace(e => {209try {210assert.deepStrictEqual(e.removed, []);211assert.strictEqual(e.added.length, 1);212assert.strictEqual(e.added[0].uri.toString(), 'foo:bar');213} catch (error) {214finish(error);215}216});217ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] });218sub.dispose();219220sub = ws.onDidChangeWorkspace(e => {221try {222assert.deepStrictEqual(e.removed, []);223assert.strictEqual(e.added.length, 1);224assert.strictEqual(e.added[0].uri.toString(), 'foo:bar2');225} catch (error) {226finish(error);227}228});229ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1)] });230sub.dispose();231232sub = ws.onDidChangeWorkspace(e => {233try {234assert.strictEqual(e.removed.length, 2);235assert.strictEqual(e.removed[0].uri.toString(), 'foo:bar');236assert.strictEqual(e.removed[1].uri.toString(), 'foo:bar2');237238assert.strictEqual(e.added.length, 1);239assert.strictEqual(e.added[0].uri.toString(), 'foo:bar3');240} catch (error) {241finish(error);242}243});244ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] });245sub.dispose();246finish();247});248249test('Multiroot change keeps existing workspaces live', function () {250const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService());251252const firstFolder = ws.getWorkspaceFolders()![0];253ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar2'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1, 'renamed')] });254255assert.strictEqual(ws.getWorkspaceFolders()![1], firstFolder);256assert.strictEqual(firstFolder.index, 1);257assert.strictEqual(firstFolder.name, 'renamed');258259ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1), aWorkspaceFolderData(URI.parse('foo:bar'), 2)] });260assert.strictEqual(ws.getWorkspaceFolders()![2], firstFolder);261assert.strictEqual(firstFolder.index, 2);262263ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] });264ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1)] });265266assert.notStrictEqual(firstFolder, ws.workspace!.folders[0]);267});268269test('updateWorkspaceFolders - invalid arguments', function () {270let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());271272assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, null!, null!));273assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0));274assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1));275assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0));276assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, 0));277assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, -1));278279ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService());280281assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 1));282assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2));283assert.strictEqual(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1, asUpdateWorkspaceFolderData(URI.parse('foo:bar'))));284});285286test('updateWorkspaceFolders - valid arguments', function (done) {287let finished = false;288const finish = (error?: any) => {289if (!finished) {290finished = true;291done(error);292}293};294295const protocol: IMainContext = {296getProxy: () => { return undefined!; },297set: () => { return undefined!; },298dispose: () => { },299assertRegistered: () => { },300drain: () => { return undefined!; },301};302303const ws = createExtHostWorkspace(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService());304305//306// Add one folder307//308309assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar'))));310assert.strictEqual(1, ws.workspace!.folders.length);311assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());312313const firstAddedFolder = ws.getWorkspaceFolders()![0];314315let gotEvent = false;316let sub = ws.onDidChangeWorkspace(e => {317try {318assert.deepStrictEqual(e.removed, []);319assert.strictEqual(e.added.length, 1);320assert.strictEqual(e.added[0].uri.toString(), 'foo:bar');321assert.strictEqual(e.added[0], firstAddedFolder); // verify object is still live322gotEvent = true;323} catch (error) {324finish(error);325}326});327ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }); // simulate acknowledgement from main side328assert.strictEqual(gotEvent, true);329sub.dispose();330assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live331332//333// Add two more folders334//335336assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar1')), asUpdateWorkspaceFolderData(URI.parse('foo:bar2'))));337assert.strictEqual(3, ws.workspace!.folders.length);338assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());339assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString());340assert.strictEqual(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar2').toString());341342const secondAddedFolder = ws.getWorkspaceFolders()![1];343const thirdAddedFolder = ws.getWorkspaceFolders()![2];344345gotEvent = false;346sub = ws.onDidChangeWorkspace(e => {347try {348assert.deepStrictEqual(e.removed, []);349assert.strictEqual(e.added.length, 2);350assert.strictEqual(e.added[0].uri.toString(), 'foo:bar1');351assert.strictEqual(e.added[1].uri.toString(), 'foo:bar2');352assert.strictEqual(e.added[0], secondAddedFolder);353assert.strictEqual(e.added[1], thirdAddedFolder);354gotEvent = true;355} catch (error) {356finish(error);357}358});359ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1), aWorkspaceFolderData(URI.parse('foo:bar2'), 2)] }); // simulate acknowledgement from main side360assert.strictEqual(gotEvent, true);361sub.dispose();362assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live363assert.strictEqual(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live364assert.strictEqual(ws.getWorkspaceFolders()![2], thirdAddedFolder); // verify object is still live365366//367// Remove one folder368//369370assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 1));371assert.strictEqual(2, ws.workspace!.folders.length);372assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());373assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString());374375gotEvent = false;376sub = ws.onDidChangeWorkspace(e => {377try {378assert.deepStrictEqual(e.added, []);379assert.strictEqual(e.removed.length, 1);380assert.strictEqual(e.removed[0], thirdAddedFolder);381gotEvent = true;382} catch (error) {383finish(error);384}385});386ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1)] }); // simulate acknowledgement from main side387assert.strictEqual(gotEvent, true);388sub.dispose();389assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live390assert.strictEqual(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live391392//393// Rename folder394//395396assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar'), 'renamed 1'), asUpdateWorkspaceFolderData(URI.parse('foo:bar1'), 'renamed 2')));397assert.strictEqual(2, ws.workspace!.folders.length);398assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());399assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString());400assert.strictEqual(ws.workspace!.folders[0].name, 'renamed 1');401assert.strictEqual(ws.workspace!.folders[1].name, 'renamed 2');402assert.strictEqual(ws.getWorkspaceFolders()![0].name, 'renamed 1');403assert.strictEqual(ws.getWorkspaceFolders()![1].name, 'renamed 2');404405gotEvent = false;406sub = ws.onDidChangeWorkspace(e => {407try {408assert.deepStrictEqual(e.added, []);409assert.strictEqual(e.removed.length, 0);410gotEvent = true;411} catch (error) {412finish(error);413}414});415ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0, 'renamed 1'), aWorkspaceFolderData(URI.parse('foo:bar1'), 1, 'renamed 2')] }); // simulate acknowledgement from main side416assert.strictEqual(gotEvent, true);417sub.dispose();418assert.strictEqual(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live419assert.strictEqual(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live420assert.strictEqual(ws.workspace!.folders[0].name, 'renamed 1');421assert.strictEqual(ws.workspace!.folders[1].name, 'renamed 2');422assert.strictEqual(ws.getWorkspaceFolders()![0].name, 'renamed 1');423assert.strictEqual(ws.getWorkspaceFolders()![1].name, 'renamed 2');424425//426// Add and remove folders427//428429assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar3')), asUpdateWorkspaceFolderData(URI.parse('foo:bar4'))));430assert.strictEqual(2, ws.workspace!.folders.length);431assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar3').toString());432assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar4').toString());433434const fourthAddedFolder = ws.getWorkspaceFolders()![0];435const fifthAddedFolder = ws.getWorkspaceFolders()![1];436437gotEvent = false;438sub = ws.onDidChangeWorkspace(e => {439try {440assert.strictEqual(e.added.length, 2);441assert.strictEqual(e.added[0], fourthAddedFolder);442assert.strictEqual(e.added[1], fifthAddedFolder);443assert.strictEqual(e.removed.length, 2);444assert.strictEqual(e.removed[0], firstAddedFolder);445assert.strictEqual(e.removed[1], secondAddedFolder);446gotEvent = true;447} catch (error) {448finish(error);449}450});451ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar4'), 1)] }); // simulate acknowledgement from main side452assert.strictEqual(gotEvent, true);453sub.dispose();454assert.strictEqual(ws.getWorkspaceFolders()![0], fourthAddedFolder); // verify object is still live455assert.strictEqual(ws.getWorkspaceFolders()![1], fifthAddedFolder); // verify object is still live456457//458// Swap folders459//460461assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar4')), asUpdateWorkspaceFolderData(URI.parse('foo:bar3'))));462assert.strictEqual(2, ws.workspace!.folders.length);463assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString());464assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString());465466assert.strictEqual(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live467assert.strictEqual(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live468469gotEvent = false;470sub = ws.onDidChangeWorkspace(e => {471try {472assert.strictEqual(e.added.length, 0);473assert.strictEqual(e.removed.length, 0);474gotEvent = true;475} catch (error) {476finish(error);477}478});479ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar4'), 0), aWorkspaceFolderData(URI.parse('foo:bar3'), 1)] }); // simulate acknowledgement from main side480assert.strictEqual(gotEvent, true);481sub.dispose();482assert.strictEqual(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live483assert.strictEqual(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live484assert.strictEqual(fifthAddedFolder.index, 0);485assert.strictEqual(fourthAddedFolder.index, 1);486487//488// Add one folder after the other without waiting for confirmation (not supported currently)489//490491assert.strictEqual(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar5'))));492493assert.strictEqual(3, ws.workspace!.folders.length);494assert.strictEqual(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString());495assert.strictEqual(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString());496assert.strictEqual(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar5').toString());497498const sixthAddedFolder = ws.getWorkspaceFolders()![2];499500gotEvent = false;501sub = ws.onDidChangeWorkspace(e => {502try {503assert.strictEqual(e.added.length, 1);504assert.strictEqual(e.added[0], sixthAddedFolder);505gotEvent = true;506} catch (error) {507finish(error);508}509});510ws.$acceptWorkspaceData({511id: 'foo', name: 'Test', folders: [512aWorkspaceFolderData(URI.parse('foo:bar4'), 0),513aWorkspaceFolderData(URI.parse('foo:bar3'), 1),514aWorkspaceFolderData(URI.parse('foo:bar5'), 2)515]516}); // simulate acknowledgement from main side517assert.strictEqual(gotEvent, true);518sub.dispose();519520assert.strictEqual(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live521assert.strictEqual(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live522assert.strictEqual(ws.getWorkspaceFolders()![2], sixthAddedFolder); // verify object is still live523524finish();525});526527test('Multiroot change event is immutable', function (done) {528let finished = false;529const finish = (error?: any) => {530if (!finished) {531finished = true;532done(error);533}534};535536const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());537const sub = ws.onDidChangeWorkspace(e => {538try {539assert.throws(() => {540(<any>e).added = [];541});542// assert.throws(() => {543// (<any>e.added)[0] = null;544// });545} catch (error) {546finish(error);547}548});549ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] });550sub.dispose();551finish();552});553554test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () {555if (isWindows) {556557const ws = createExtHostWorkspace(new TestRPCProtocol(), {558id: 'foo', name: 'Test', folders: [559aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0)560]561}, new NullLogService());562563assert.ok(ws.getWorkspaceFolder(URI.file('c:/Users/marek/Desktop/vsc_test/a.txt')));564assert.ok(ws.getWorkspaceFolder(URI.file('C:/Users/marek/Desktop/vsc_test/b.txt')));565}566});567568function aWorkspaceFolderData(uri: URI, index: number, name: string = ''): IWorkspaceFolderData {569return {570uri,571index,572name: name || basename(uri.path)573};574}575576function asUpdateWorkspaceFolderData(uri: URI, name?: string): { uri: URI; name?: string } {577return { uri, name };578}579580suite('findFiles -', function () {581test('string include', () => {582const root = '/project/foo';583const rpcProtocol = new TestRPCProtocol();584585let mainThreadCalled = false;586rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {587override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {588mainThreadCalled = true;589assert.strictEqual(options.includePattern, 'foo');590assert.strictEqual(_includeFolder, null);591assert.strictEqual(options.excludePattern, undefined);592assert.strictEqual(options.disregardExcludeSettings, false);593assert.strictEqual(options.maxResults, 10);594return Promise.resolve(null);595}596});597598const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());599return ws.findFiles('foo', undefined, 10, new ExtensionIdentifier('test')).then(() => {600assert(mainThreadCalled, 'mainThreadCalled');601});602});603604function testFindFilesInclude(pattern: RelativePattern) {605const root = '/project/foo';606const rpcProtocol = new TestRPCProtocol();607608let mainThreadCalled = false;609rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {610override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {611mainThreadCalled = true;612assert.strictEqual(options.includePattern, 'glob/**');613assert.deepStrictEqual(_includeFolder ? URI.from(_includeFolder).toJSON() : null, URI.file('/other/folder').toJSON());614assert.strictEqual(options.excludePattern, undefined);615assert.strictEqual(options.disregardExcludeSettings, false);616return Promise.resolve(null);617}618});619620const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());621return ws.findFiles(pattern, undefined, 10, new ExtensionIdentifier('test')).then(() => {622assert(mainThreadCalled, 'mainThreadCalled');623});624}625626test('RelativePattern include (string)', () => {627return testFindFilesInclude(new RelativePattern('/other/folder', 'glob/**'));628});629630test('RelativePattern include (URI)', () => {631return testFindFilesInclude(new RelativePattern(URI.file('/other/folder'), 'glob/**'));632});633634test('no excludes', () => {635const root = '/project/foo';636const rpcProtocol = new TestRPCProtocol();637638let mainThreadCalled = false;639rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {640override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {641mainThreadCalled = true;642assert.strictEqual(options.includePattern, 'glob/**');643assert.deepStrictEqual(URI.revive(_includeFolder!).toString(), URI.file('/other/folder').toString());644assert.strictEqual(options.excludePattern, undefined);645assert.strictEqual(options.disregardExcludeSettings, true);646return Promise.resolve(null);647}648});649650const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());651return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), null, 10, new ExtensionIdentifier('test')).then(() => {652assert(mainThreadCalled, 'mainThreadCalled');653});654});655656test('with cancelled token', () => {657const root = '/project/foo';658const rpcProtocol = new TestRPCProtocol();659660let mainThreadCalled = false;661rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {662override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {663mainThreadCalled = true;664return Promise.resolve(null);665}666});667668const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());669670const token = CancellationToken.Cancelled;671return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), null, 10, new ExtensionIdentifier('test'), token).then(() => {672assert(!mainThreadCalled, '!mainThreadCalled');673});674});675676test('RelativePattern exclude', () => {677const root = '/project/foo';678const rpcProtocol = new TestRPCProtocol();679680let mainThreadCalled = false;681rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {682override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {683mainThreadCalled = true;684assert.strictEqual(options.disregardExcludeSettings, false);685assert.strictEqual(options.excludePattern?.length, 1);686assert.strictEqual(options.excludePattern[0].pattern, 'glob/**'); // Note that the base portion is ignored, see #52651687return Promise.resolve(null);688}689});690691const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());692return ws.findFiles('', new RelativePattern(root, 'glob/**'), 10, new ExtensionIdentifier('test')).then(() => {693assert(mainThreadCalled, 'mainThreadCalled');694});695});696});697698suite('findFiles2 -', function () {699test('string include', () => {700const root = '/project/foo';701const rpcProtocol = new TestRPCProtocol();702703let mainThreadCalled = false;704rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {705override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {706mainThreadCalled = true;707assert.strictEqual(options.filePattern, 'foo');708assert.strictEqual(options.includePattern, undefined);709assert.strictEqual(_includeFolder, null);710assert.strictEqual(options.excludePattern, undefined);711assert.strictEqual(options.disregardExcludeSettings, false);712assert.strictEqual(options.maxResults, 10);713return Promise.resolve(null);714}715});716717const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());718return ws.findFiles2(['foo'], { maxResults: 10, useExcludeSettings: ExcludeSettingOptions.FilesExclude }, new ExtensionIdentifier('test')).then(() => {719assert(mainThreadCalled, 'mainThreadCalled');720});721});722723function testFindFiles2Include(pattern: RelativePattern[]) {724const root = '/project/foo';725const rpcProtocol = new TestRPCProtocol();726727let mainThreadCalled = false;728rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {729override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {730mainThreadCalled = true;731assert.strictEqual(options.filePattern, 'glob/**');732assert.strictEqual(options.includePattern, undefined);733assert.deepStrictEqual(_includeFolder ? URI.from(_includeFolder).toJSON() : null, URI.file('/other/folder').toJSON());734assert.strictEqual(options.excludePattern, undefined);735assert.strictEqual(options.disregardExcludeSettings, false);736return Promise.resolve(null);737}738});739740const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());741return ws.findFiles2(pattern, { maxResults: 10 }, new ExtensionIdentifier('test')).then(() => {742assert(mainThreadCalled, 'mainThreadCalled');743});744}745746test('RelativePattern include (string)', () => {747return testFindFiles2Include([new RelativePattern('/other/folder', 'glob/**')]);748});749750test('RelativePattern include (URI)', () => {751return testFindFiles2Include([new RelativePattern(URI.file('/other/folder'), 'glob/**')]);752});753754test('no excludes', () => {755const root = '/project/foo';756const rpcProtocol = new TestRPCProtocol();757758let mainThreadCalled = false;759rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {760override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {761mainThreadCalled = true;762assert.strictEqual(options.filePattern, 'glob/**');763assert.strictEqual(options.includePattern, undefined);764assert.deepStrictEqual(URI.revive(_includeFolder!).toString(), URI.file('/other/folder').toString());765assert.strictEqual(options.excludePattern, undefined);766assert.strictEqual(options.disregardExcludeSettings, false);767return Promise.resolve(null);768}769});770771const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());772return ws.findFiles2([new RelativePattern('/other/folder', 'glob/**')], {}, new ExtensionIdentifier('test')).then(() => {773assert(mainThreadCalled, 'mainThreadCalled');774});775});776777test('with cancelled token', () => {778const root = '/project/foo';779const rpcProtocol = new TestRPCProtocol();780781let mainThreadCalled = false;782rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {783override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {784mainThreadCalled = true;785return Promise.resolve(null);786}787});788789const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());790791const token = CancellationToken.Cancelled;792return ws.findFiles2([new RelativePattern('/other/folder', 'glob/**')], {}, new ExtensionIdentifier('test'), token).then(() => {793assert(!mainThreadCalled, '!mainThreadCalled');794});795});796797test('RelativePattern exclude', () => {798const root = '/project/foo';799const rpcProtocol = new TestRPCProtocol();800801let mainThreadCalled = false;802rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {803override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {804mainThreadCalled = true;805assert.strictEqual(options.disregardExcludeSettings, false);806assert.strictEqual(options.excludePattern?.length, 1);807assert.strictEqual(options.excludePattern[0].pattern, 'glob/**'); // Note that the base portion is ignored, see #52651808return Promise.resolve(null);809}810});811812const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());813return ws.findFiles2([''], { exclude: [new RelativePattern(root, 'glob/**')] }, new ExtensionIdentifier('test')).then(() => {814assert(mainThreadCalled, 'mainThreadCalled');815});816});817test('useIgnoreFiles', () => {818const root = '/project/foo';819const rpcProtocol = new TestRPCProtocol();820821let mainThreadCalled = false;822rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {823override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {824mainThreadCalled = true;825assert.strictEqual(options.disregardExcludeSettings, false);826assert.strictEqual(options.disregardIgnoreFiles, false);827assert.strictEqual(options.disregardGlobalIgnoreFiles, false);828assert.strictEqual(options.disregardParentIgnoreFiles, false);829return Promise.resolve(null);830}831});832833const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());834return ws.findFiles2([''], { useIgnoreFiles: { local: true, parent: true, global: true } }, new ExtensionIdentifier('test')).then(() => {835assert(mainThreadCalled, 'mainThreadCalled');836});837});838839test('use symlinks', () => {840const root = '/project/foo';841const rpcProtocol = new TestRPCProtocol();842843let mainThreadCalled = false;844rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {845override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {846mainThreadCalled = true;847assert.strictEqual(options.ignoreSymlinks, false);848return Promise.resolve(null);849}850});851852const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());853return ws.findFiles2([''], { followSymlinks: true }, new ExtensionIdentifier('test')).then(() => {854assert(mainThreadCalled, 'mainThreadCalled');855});856});857858// todo: add tests with multiple filePatterns and excludes859860});861862suite('findTextInFiles -', function () {863test('no include', async () => {864const root = '/project/foo';865const rpcProtocol = new TestRPCProtocol();866867let mainThreadCalled = false;868rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {869override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {870mainThreadCalled = true;871assert.strictEqual(query.pattern, 'foo');872assert.strictEqual(folder, null);873assert.strictEqual(options.includePattern, undefined);874assert.strictEqual(options.excludePattern, undefined);875return null;876}877});878879const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());880await ws.findTextInFiles({ pattern: 'foo' }, {}, () => { }, new ExtensionIdentifier('test'));881assert(mainThreadCalled, 'mainThreadCalled');882});883884test('string include', async () => {885const root = '/project/foo';886const rpcProtocol = new TestRPCProtocol();887888let mainThreadCalled = false;889rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {890override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {891mainThreadCalled = true;892assert.strictEqual(query.pattern, 'foo');893assert.strictEqual(folder, null);894assert.strictEqual(options.includePattern, '**/files');895assert.strictEqual(options.excludePattern, undefined);896return null;897}898});899900const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());901await ws.findTextInFiles({ pattern: 'foo' }, { include: '**/files' }, () => { }, new ExtensionIdentifier('test'));902assert(mainThreadCalled, 'mainThreadCalled');903});904905test('RelativePattern include', async () => {906const root = '/project/foo';907const rpcProtocol = new TestRPCProtocol();908909let mainThreadCalled = false;910rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {911override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {912mainThreadCalled = true;913assert.strictEqual(query.pattern, 'foo');914assert.deepStrictEqual(URI.revive(folder!).toString(), URI.file('/other/folder').toString());915assert.strictEqual(options.includePattern, 'glob/**');916assert.strictEqual(options.excludePattern, undefined);917return null;918}919});920921const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());922await ws.findTextInFiles({ pattern: 'foo' }, { include: new RelativePattern('/other/folder', 'glob/**') }, () => { }, new ExtensionIdentifier('test'));923assert(mainThreadCalled, 'mainThreadCalled');924});925926test('with cancelled token', async () => {927const root = '/project/foo';928const rpcProtocol = new TestRPCProtocol();929930let mainThreadCalled = false;931rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {932override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {933mainThreadCalled = true;934return null;935}936});937938const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());939const token = CancellationToken.Cancelled;940await ws.findTextInFiles({ pattern: 'foo' }, {}, () => { }, new ExtensionIdentifier('test'), token);941assert(!mainThreadCalled, '!mainThreadCalled');942});943944test('RelativePattern exclude', async () => {945const root = '/project/foo';946const rpcProtocol = new TestRPCProtocol();947948let mainThreadCalled = false;949rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {950override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {951mainThreadCalled = true;952assert.strictEqual(query.pattern, 'foo');953assert.deepStrictEqual(folder, null);954assert.strictEqual(options.includePattern, undefined);955assert.strictEqual(options.excludePattern?.length, 1);956assert.strictEqual(options.excludePattern[0].pattern, 'glob/**'); // exclude folder is ignored...957return null;958}959});960961const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());962await ws.findTextInFiles({ pattern: 'foo' }, { exclude: new RelativePattern('/other/folder', 'glob/**') }, () => { }, new ExtensionIdentifier('test'));963assert(mainThreadCalled, 'mainThreadCalled');964});965});966967suite('findTextInFiles2 -', function () {968test('no include', async () => {969const root = '/project/foo';970const rpcProtocol = new TestRPCProtocol();971972let mainThreadCalled = false;973rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {974override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {975mainThreadCalled = true;976assert.strictEqual(query.pattern, 'foo');977assert.strictEqual(folder, null);978assert.strictEqual(options.includePattern, undefined);979assert.strictEqual(options.excludePattern, undefined);980return null;981}982});983984const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());985await (ws.findTextInFiles2({ pattern: 'foo' }, {}, new ExtensionIdentifier('test'))).complete;986assert(mainThreadCalled, 'mainThreadCalled');987});988989test('string include', async () => {990const root = '/project/foo';991const rpcProtocol = new TestRPCProtocol();992993let mainThreadCalled = false;994rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {995override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {996mainThreadCalled = true;997assert.strictEqual(query.pattern, 'foo');998assert.strictEqual(folder, null);999assert.strictEqual(options.includePattern, '**/files');1000assert.strictEqual(options.excludePattern, undefined);1001return null;1002}1003});10041005const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());1006await (ws.findTextInFiles2({ pattern: 'foo' }, { include: ['**/files'] }, new ExtensionIdentifier('test'))).complete;1007assert(mainThreadCalled, 'mainThreadCalled');1008});10091010test('RelativePattern include', async () => {1011const root = '/project/foo';1012const rpcProtocol = new TestRPCProtocol();10131014let mainThreadCalled = false;1015rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {1016override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {1017mainThreadCalled = true;1018assert.strictEqual(query.pattern, 'foo');1019assert.deepStrictEqual(URI.revive(folder!).toString(), URI.file('/other/folder').toString());1020assert.strictEqual(options.includePattern, 'glob/**');1021assert.strictEqual(options.excludePattern, undefined);1022return null;1023}1024});10251026const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());1027await (ws.findTextInFiles2({ pattern: 'foo' }, { include: [new RelativePattern('/other/folder', 'glob/**')] }, new ExtensionIdentifier('test'))).complete;1028assert(mainThreadCalled, 'mainThreadCalled');1029});10301031test('with cancelled token', async () => {1032const root = '/project/foo';1033const rpcProtocol = new TestRPCProtocol();10341035let mainThreadCalled = false;1036rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {1037override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {1038mainThreadCalled = true;1039return null;1040}1041});10421043const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());1044const token = CancellationToken.Cancelled;1045await (ws.findTextInFiles2({ pattern: 'foo' }, undefined, new ExtensionIdentifier('test'), token)).complete;1046assert(!mainThreadCalled, '!mainThreadCalled');1047});10481049test('RelativePattern exclude', async () => {1050const root = '/project/foo';1051const rpcProtocol = new TestRPCProtocol();10521053let mainThreadCalled = false;1054rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {1055override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {1056mainThreadCalled = true;1057assert.strictEqual(query.pattern, 'foo');1058assert.deepStrictEqual(folder, null);1059assert.strictEqual(options.includePattern, undefined);1060assert.strictEqual(options.excludePattern?.length, 1);1061assert.strictEqual(options.excludePattern[0].pattern, 'glob/**'); // exclude folder is ignored...1062return null;1063}1064});10651066const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());1067await (ws.findTextInFiles2({ pattern: 'foo' }, { exclude: [new RelativePattern('/other/folder', 'glob/**')] }, new ExtensionIdentifier('test'))).complete;1068assert(mainThreadCalled, 'mainThreadCalled');1069});10701071// TODO: test multiple includes/excludess1072});1073});107410751076