Path: blob/main/src/vs/workbench/api/test/browser/extHostWorkspace.test.ts
5240 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// eslint-disable-next-line local/code-no-any-casts541(<any>e).added = [];542});543// assert.throws(() => {544// (<any>e.added)[0] = null;545// });546} catch (error) {547finish(error);548}549});550ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] });551sub.dispose();552finish();553});554555test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () {556if (isWindows) {557558const ws = createExtHostWorkspace(new TestRPCProtocol(), {559id: 'foo', name: 'Test', folders: [560aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0)561]562}, new NullLogService());563564assert.ok(ws.getWorkspaceFolder(URI.file('c:/Users/marek/Desktop/vsc_test/a.txt')));565assert.ok(ws.getWorkspaceFolder(URI.file('C:/Users/marek/Desktop/vsc_test/b.txt')));566}567});568569function aWorkspaceFolderData(uri: URI, index: number, name: string = ''): IWorkspaceFolderData {570return {571uri,572index,573name: name || basename(uri.path)574};575}576577function asUpdateWorkspaceFolderData(uri: URI, name?: string): { uri: URI; name?: string } {578return { uri, name };579}580581suite('findFiles -', function () {582test('string include', () => {583const root = '/project/foo';584const rpcProtocol = new TestRPCProtocol();585586let mainThreadCalled = false;587rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {588override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {589mainThreadCalled = true;590assert.strictEqual(options.includePattern, 'foo');591assert.strictEqual(_includeFolder, null);592assert.strictEqual(options.excludePattern, undefined);593assert.strictEqual(options.disregardExcludeSettings, false);594assert.strictEqual(options.maxResults, 10);595return Promise.resolve(null);596}597});598599const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());600return ws.findFiles('foo', undefined, 10, new ExtensionIdentifier('test')).then(() => {601assert(mainThreadCalled, 'mainThreadCalled');602});603});604605function testFindFilesInclude(pattern: RelativePattern) {606const root = '/project/foo';607const rpcProtocol = new TestRPCProtocol();608609let mainThreadCalled = false;610rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {611override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {612mainThreadCalled = true;613assert.strictEqual(options.includePattern, 'glob/**');614assert.deepStrictEqual(_includeFolder ? URI.from(_includeFolder).toJSON() : null, URI.file('/other/folder').toJSON());615assert.strictEqual(options.excludePattern, undefined);616assert.strictEqual(options.disregardExcludeSettings, false);617return Promise.resolve(null);618}619});620621const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());622return ws.findFiles(pattern, undefined, 10, new ExtensionIdentifier('test')).then(() => {623assert(mainThreadCalled, 'mainThreadCalled');624});625}626627test('RelativePattern include (string)', () => {628return testFindFilesInclude(new RelativePattern('/other/folder', 'glob/**'));629});630631test('RelativePattern include (URI)', () => {632return testFindFilesInclude(new RelativePattern(URI.file('/other/folder'), 'glob/**'));633});634635test('no excludes', () => {636const root = '/project/foo';637const rpcProtocol = new TestRPCProtocol();638639let mainThreadCalled = false;640rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {641override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {642mainThreadCalled = true;643assert.strictEqual(options.includePattern, 'glob/**');644assert.deepStrictEqual(URI.revive(_includeFolder!).toString(), URI.file('/other/folder').toString());645assert.strictEqual(options.excludePattern, undefined);646assert.strictEqual(options.disregardExcludeSettings, true);647return Promise.resolve(null);648}649});650651const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());652return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), null, 10, new ExtensionIdentifier('test')).then(() => {653assert(mainThreadCalled, 'mainThreadCalled');654});655});656657test('with cancelled token', () => {658const root = '/project/foo';659const rpcProtocol = new TestRPCProtocol();660661let mainThreadCalled = false;662rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {663override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {664mainThreadCalled = true;665return Promise.resolve(null);666}667});668669const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());670671const token = CancellationToken.Cancelled;672return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), null, 10, new ExtensionIdentifier('test'), token).then(() => {673assert(!mainThreadCalled, '!mainThreadCalled');674});675});676677test('RelativePattern exclude', () => {678const root = '/project/foo';679const rpcProtocol = new TestRPCProtocol();680681let mainThreadCalled = false;682rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {683override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {684mainThreadCalled = true;685assert.strictEqual(options.disregardExcludeSettings, false);686assert.strictEqual(options.excludePattern?.length, 1);687assert.strictEqual(options.excludePattern[0].pattern, 'glob/**'); // Note that the base portion is ignored, see #52651688return Promise.resolve(null);689}690});691692const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());693return ws.findFiles('', new RelativePattern(root, 'glob/**'), 10, new ExtensionIdentifier('test')).then(() => {694assert(mainThreadCalled, 'mainThreadCalled');695});696});697});698699suite('findFiles2 -', function () {700test('string include', () => {701const root = '/project/foo';702const rpcProtocol = new TestRPCProtocol();703704let mainThreadCalled = false;705rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {706override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {707mainThreadCalled = true;708assert.strictEqual(options.filePattern, 'foo');709assert.strictEqual(options.includePattern, undefined);710assert.strictEqual(_includeFolder, null);711assert.strictEqual(options.excludePattern, undefined);712assert.strictEqual(options.disregardExcludeSettings, false);713assert.strictEqual(options.maxResults, 10);714return Promise.resolve(null);715}716});717718const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());719return ws.findFiles2(['foo'], { maxResults: 10, useExcludeSettings: ExcludeSettingOptions.FilesExclude }, new ExtensionIdentifier('test')).then(() => {720assert(mainThreadCalled, 'mainThreadCalled');721});722});723724function testFindFiles2Include(pattern: RelativePattern[]) {725const root = '/project/foo';726const rpcProtocol = new TestRPCProtocol();727728let mainThreadCalled = false;729rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {730override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {731mainThreadCalled = true;732assert.strictEqual(options.filePattern, 'glob/**');733assert.strictEqual(options.includePattern, undefined);734assert.deepStrictEqual(_includeFolder ? URI.from(_includeFolder).toJSON() : null, URI.file('/other/folder').toJSON());735assert.strictEqual(options.excludePattern, undefined);736assert.strictEqual(options.disregardExcludeSettings, false);737return Promise.resolve(null);738}739});740741const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());742return ws.findFiles2(pattern, { maxResults: 10 }, new ExtensionIdentifier('test')).then(() => {743assert(mainThreadCalled, 'mainThreadCalled');744});745}746747test('RelativePattern include (string)', () => {748return testFindFiles2Include([new RelativePattern('/other/folder', 'glob/**')]);749});750751test('RelativePattern include (URI)', () => {752return testFindFiles2Include([new RelativePattern(URI.file('/other/folder'), 'glob/**')]);753});754755test('no excludes', () => {756const root = '/project/foo';757const rpcProtocol = new TestRPCProtocol();758759let mainThreadCalled = false;760rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {761override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {762mainThreadCalled = true;763assert.strictEqual(options.filePattern, 'glob/**');764assert.strictEqual(options.includePattern, undefined);765assert.deepStrictEqual(URI.revive(_includeFolder!).toString(), URI.file('/other/folder').toString());766assert.strictEqual(options.excludePattern, undefined);767assert.strictEqual(options.disregardExcludeSettings, false);768return Promise.resolve(null);769}770});771772const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());773return ws.findFiles2([new RelativePattern('/other/folder', 'glob/**')], {}, new ExtensionIdentifier('test')).then(() => {774assert(mainThreadCalled, 'mainThreadCalled');775});776});777778test('no dups', () => {779const root = '/project/foo';780const rpcProtocol = new TestRPCProtocol();781782let mainThreadCalled = false;783rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {784override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {785mainThreadCalled = true;786assert.strictEqual(options.includePattern, undefined);787assert.strictEqual(options.excludePattern, undefined);788assert.strictEqual(options.disregardExcludeSettings, false);789return Promise.resolve([URI.file(root + '/main.py')]);790}791});792793// Only add the root directory as a workspace folder - main.py will be a file within it794const folders = [aWorkspaceFolderData(URI.file(root), 0)];795const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: folders, name: 'Test' }, new NullLogService());796797return ws.findFiles2(['**/main.py', '**/main.py/**'], {}, new ExtensionIdentifier('test')).then((uris) => {798assert(mainThreadCalled, 'mainThreadCalled');799assert.equal(uris.length, 1);800assert.equal(uris[0].toString(), URI.file(root + '/main.py').toString());801});802});803804test('with cancelled token', () => {805const root = '/project/foo';806const rpcProtocol = new TestRPCProtocol();807808let mainThreadCalled = false;809rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {810override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {811mainThreadCalled = true;812return Promise.resolve(null);813}814});815816const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());817818const token = CancellationToken.Cancelled;819return ws.findFiles2([new RelativePattern('/other/folder', 'glob/**')], {}, new ExtensionIdentifier('test'), token).then(() => {820assert(!mainThreadCalled, '!mainThreadCalled');821});822});823824test('RelativePattern exclude', () => {825const root = '/project/foo';826const rpcProtocol = new TestRPCProtocol();827828let mainThreadCalled = false;829rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {830override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {831mainThreadCalled = true;832assert.strictEqual(options.disregardExcludeSettings, false);833assert.strictEqual(options.excludePattern?.length, 1);834assert.strictEqual(options.excludePattern[0].pattern, 'glob/**'); // Note that the base portion is ignored, see #52651835return Promise.resolve(null);836}837});838839const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());840return ws.findFiles2([''], { exclude: [new RelativePattern(root, 'glob/**')] }, new ExtensionIdentifier('test')).then(() => {841assert(mainThreadCalled, 'mainThreadCalled');842});843});844test('useIgnoreFiles', () => {845const root = '/project/foo';846const rpcProtocol = new TestRPCProtocol();847848let mainThreadCalled = false;849rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {850override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {851mainThreadCalled = true;852assert.strictEqual(options.disregardExcludeSettings, false);853assert.strictEqual(options.disregardIgnoreFiles, false);854assert.strictEqual(options.disregardGlobalIgnoreFiles, false);855assert.strictEqual(options.disregardParentIgnoreFiles, false);856return Promise.resolve(null);857}858});859860const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());861return ws.findFiles2([''], { useIgnoreFiles: { local: true, parent: true, global: true } }, new ExtensionIdentifier('test')).then(() => {862assert(mainThreadCalled, 'mainThreadCalled');863});864});865866test('use symlinks', () => {867const root = '/project/foo';868const rpcProtocol = new TestRPCProtocol();869870let mainThreadCalled = false;871rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {872override $startFileSearch(_includeFolder: UriComponents | null, options: IFileQueryBuilderOptions, token: CancellationToken): Promise<URI[] | null> {873mainThreadCalled = true;874assert.strictEqual(options.ignoreSymlinks, false);875return Promise.resolve(null);876}877});878879const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());880return ws.findFiles2([''], { followSymlinks: true }, new ExtensionIdentifier('test')).then(() => {881assert(mainThreadCalled, 'mainThreadCalled');882});883});884885// todo: add tests with multiple filePatterns and excludes886887});888889suite('findTextInFiles -', function () {890test('no include', async () => {891const root = '/project/foo';892const rpcProtocol = new TestRPCProtocol();893894let mainThreadCalled = false;895rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {896override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {897mainThreadCalled = true;898assert.strictEqual(query.pattern, 'foo');899assert.strictEqual(folder, null);900assert.strictEqual(options.includePattern, undefined);901assert.strictEqual(options.excludePattern, undefined);902return null;903}904});905906const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());907await ws.findTextInFiles({ pattern: 'foo' }, {}, () => { }, new ExtensionIdentifier('test'));908assert(mainThreadCalled, 'mainThreadCalled');909});910911test('string include', async () => {912const root = '/project/foo';913const rpcProtocol = new TestRPCProtocol();914915let mainThreadCalled = false;916rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {917override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {918mainThreadCalled = true;919assert.strictEqual(query.pattern, 'foo');920assert.strictEqual(folder, null);921assert.strictEqual(options.includePattern, '**/files');922assert.strictEqual(options.excludePattern, undefined);923return null;924}925});926927const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());928await ws.findTextInFiles({ pattern: 'foo' }, { include: '**/files' }, () => { }, new ExtensionIdentifier('test'));929assert(mainThreadCalled, 'mainThreadCalled');930});931932test('RelativePattern include', async () => {933const root = '/project/foo';934const rpcProtocol = new TestRPCProtocol();935936let mainThreadCalled = false;937rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {938override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {939mainThreadCalled = true;940assert.strictEqual(query.pattern, 'foo');941assert.deepStrictEqual(URI.revive(folder!).toString(), URI.file('/other/folder').toString());942assert.strictEqual(options.includePattern, 'glob/**');943assert.strictEqual(options.excludePattern, undefined);944return null;945}946});947948const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());949await ws.findTextInFiles({ pattern: 'foo' }, { include: new RelativePattern('/other/folder', 'glob/**') }, () => { }, new ExtensionIdentifier('test'));950assert(mainThreadCalled, 'mainThreadCalled');951});952953test('with cancelled token', async () => {954const root = '/project/foo';955const rpcProtocol = new TestRPCProtocol();956957let mainThreadCalled = false;958rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {959override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {960mainThreadCalled = true;961return null;962}963});964965const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());966const token = CancellationToken.Cancelled;967await ws.findTextInFiles({ pattern: 'foo' }, {}, () => { }, new ExtensionIdentifier('test'), token);968assert(!mainThreadCalled, '!mainThreadCalled');969});970971test('RelativePattern exclude', async () => {972const root = '/project/foo';973const rpcProtocol = new TestRPCProtocol();974975let mainThreadCalled = false;976rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {977override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {978mainThreadCalled = true;979assert.strictEqual(query.pattern, 'foo');980assert.deepStrictEqual(folder, null);981assert.strictEqual(options.includePattern, undefined);982assert.strictEqual(options.excludePattern?.length, 1);983assert.strictEqual(options.excludePattern[0].pattern, 'glob/**'); // exclude folder is ignored...984return null;985}986});987988const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());989await ws.findTextInFiles({ pattern: 'foo' }, { exclude: new RelativePattern('/other/folder', 'glob/**') }, () => { }, new ExtensionIdentifier('test'));990assert(mainThreadCalled, 'mainThreadCalled');991});992});993994suite('findTextInFiles2 -', function () {995test('no include', async () => {996const root = '/project/foo';997const rpcProtocol = new TestRPCProtocol();998999let mainThreadCalled = false;1000rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {1001override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {1002mainThreadCalled = true;1003assert.strictEqual(query.pattern, 'foo');1004assert.strictEqual(folder, null);1005assert.strictEqual(options.includePattern, undefined);1006assert.strictEqual(options.excludePattern, undefined);1007return null;1008}1009});10101011const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());1012await (ws.findTextInFiles2({ pattern: 'foo' }, {}, new ExtensionIdentifier('test'))).complete;1013assert(mainThreadCalled, 'mainThreadCalled');1014});10151016test('string include', async () => {1017const root = '/project/foo';1018const rpcProtocol = new TestRPCProtocol();10191020let mainThreadCalled = false;1021rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {1022override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {1023mainThreadCalled = true;1024assert.strictEqual(query.pattern, 'foo');1025assert.strictEqual(folder, null);1026assert.strictEqual(options.includePattern, '**/files');1027assert.strictEqual(options.excludePattern, undefined);1028return null;1029}1030});10311032const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());1033await (ws.findTextInFiles2({ pattern: 'foo' }, { include: ['**/files'] }, new ExtensionIdentifier('test'))).complete;1034assert(mainThreadCalled, 'mainThreadCalled');1035});10361037test('RelativePattern include', async () => {1038const root = '/project/foo';1039const rpcProtocol = new TestRPCProtocol();10401041let mainThreadCalled = false;1042rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {1043override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {1044mainThreadCalled = true;1045assert.strictEqual(query.pattern, 'foo');1046assert.deepStrictEqual(URI.revive(folder!).toString(), URI.file('/other/folder').toString());1047assert.strictEqual(options.includePattern, 'glob/**');1048assert.strictEqual(options.excludePattern, undefined);1049return null;1050}1051});10521053const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());1054await (ws.findTextInFiles2({ pattern: 'foo' }, { include: [new RelativePattern('/other/folder', 'glob/**')] }, new ExtensionIdentifier('test'))).complete;1055assert(mainThreadCalled, 'mainThreadCalled');1056});10571058test('with cancelled token', async () => {1059const root = '/project/foo';1060const rpcProtocol = new TestRPCProtocol();10611062let mainThreadCalled = false;1063rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {1064override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {1065mainThreadCalled = true;1066return null;1067}1068});10691070const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());1071const token = CancellationToken.Cancelled;1072await (ws.findTextInFiles2({ pattern: 'foo' }, undefined, new ExtensionIdentifier('test'), token)).complete;1073assert(!mainThreadCalled, '!mainThreadCalled');1074});10751076test('RelativePattern exclude', async () => {1077const root = '/project/foo';1078const rpcProtocol = new TestRPCProtocol();10791080let mainThreadCalled = false;1081rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {1082override async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {1083mainThreadCalled = true;1084assert.strictEqual(query.pattern, 'foo');1085assert.deepStrictEqual(folder, null);1086assert.strictEqual(options.includePattern, undefined);1087assert.strictEqual(options.excludePattern?.length, 1);1088assert.strictEqual(options.excludePattern[0].pattern, 'glob/**'); // exclude folder is ignored...1089return null;1090}1091});10921093const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());1094await (ws.findTextInFiles2({ pattern: 'foo' }, { exclude: [new RelativePattern('/other/folder', 'glob/**')] }, new ExtensionIdentifier('test'))).complete;1095assert(mainThreadCalled, 'mainThreadCalled');1096});10971098// TODO: test multiple includes/excludess1099});1100});110111021103