extHostWorkspace.test.ts 34.7 KB
Newer Older
1 2 3 4 5 6
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import * as assert from 'assert';
R
Rob Lourens 已提交
7
import { CancellationToken } from 'vs/base/common/cancellation';
8
import { basename } from 'vs/base/common/path';
R
Rob Lourens 已提交
9
import { URI, UriComponents } from 'vs/base/common/uri';
10
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
R
Rob Lourens 已提交
11
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
12
import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace';
J
Johannes Rieken 已提交
13
import { MainThreadWorkspace } from 'vs/workbench/api/browser/mainThreadWorkspace';
14
import { IMainContext, IWorkspaceData, MainContext, ITextSearchComplete } from 'vs/workbench/api/common/extHost.protocol';
J
Johannes Rieken 已提交
15 16
import { RelativePattern } from 'vs/workbench/api/common/extHostTypes';
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
A
Alex Dima 已提交
17
import { mock } from 'vs/base/test/common/mock';
R
Rob Lourens 已提交
18
import { TestRPCProtocol } from './testRPCProtocol';
19
import { ExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
20
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
21 22
import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder';
import { IPatternInfo } from 'vs/workbench/services/search/common/search';
23
import { isWindows } from 'vs/base/common/platform';
24
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
25

J
Johannes Rieken 已提交
26
function createExtHostWorkspace(mainContext: IMainContext, data: IWorkspaceData, logService: ILogService): ExtHostWorkspace {
27 28 29
	const result = new ExtHostWorkspace(
		new ExtHostRpcService(mainContext),
		new class extends mock<IExtHostInitDataService>() { workspace = data; },
30 31
		new class extends mock<IExtHostFileSystemInfo>() { },
		logService,
32
	);
33 34 35 36
	result.$initializeWorkspace(data);
	return result;
}

37 38
suite('ExtHostWorkspace', function () {

B
Benjamin Pasero 已提交
39
	const extensionDescriptor: IExtensionDescription = {
40
		identifier: new ExtensionIdentifier('nullExtensionDescription'),
B
Benjamin Pasero 已提交
41 42 43
		name: 'ext',
		publisher: 'vscode',
		enableProposedApi: false,
44 45
		engines: undefined!,
		extensionLocation: undefined!,
B
Benjamin Pasero 已提交
46
		isBuiltin: false,
47
		isUserBuiltin: false,
48
		isUnderDevelopment: false,
49
		version: undefined!
B
Benjamin Pasero 已提交
50 51
	};

52
	function assertAsRelativePath(workspace: ExtHostWorkspace, input: string, expected: string, includeWorkspace?: boolean) {
53
		const actual = workspace.getRelativePath(input, includeWorkspace);
54
		assert.equal(actual, expected);
55 56
	}

57
	test('asRelativePath', () => {
58

J
Johannes Rieken 已提交
59
		const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService());
60

61 62
		assertAsRelativePath(ws, '/Coding/Applications/NewsWoWBot/bernd/das/brot', 'bernd/das/brot');
		assertAsRelativePath(ws, '/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart',
J
Johannes Rieken 已提交
63
			'/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart');
64

65 66 67
		assertAsRelativePath(ws, '', '');
		assertAsRelativePath(ws, '/foo/bar', '/foo/bar');
		assertAsRelativePath(ws, 'in/out', 'in/out');
68
	});
J
Johannes Rieken 已提交
69 70 71 72

	test('asRelativePath, same paths, #11402', function () {
		const root = '/home/aeschli/workspaces/samples/docker';
		const input = '/home/aeschli/workspaces/samples/docker';
J
Johannes Rieken 已提交
73
		const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
J
Johannes Rieken 已提交
74

75
		assertAsRelativePath(ws, input, input);
J
Johannes Rieken 已提交
76 77

		const input2 = '/home/aeschli/workspaces/samples/docker/a.file';
78
		assertAsRelativePath(ws, input2, 'a.file');
79 80 81
	});

	test('asRelativePath, no workspace', function () {
J
Johannes Rieken 已提交
82
		const ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService());
83 84
		assertAsRelativePath(ws, '', '');
		assertAsRelativePath(ws, '/foo/bar', '/foo/bar');
85
	});
J
Johannes Rieken 已提交
86

87
	test('asRelativePath, multiple folders', function () {
J
Johannes Rieken 已提交
88
		const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
89 90 91
		assertAsRelativePath(ws, '/Coding/One/file.txt', 'One/file.txt');
		assertAsRelativePath(ws, '/Coding/Two/files/out.txt', 'Two/files/out.txt');
		assertAsRelativePath(ws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');
J
Johannes Rieken 已提交
92
	});
93

J
Johannes Rieken 已提交
94
	test('slightly inconsistent behaviour of asRelativePath and getWorkspaceFolder, #31553', function () {
J
Johannes Rieken 已提交
95
		const mrws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
J
Johannes Rieken 已提交
96

97 98 99 100 101 102 103 104 105
		assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt');
		assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt', true);
		assertAsRelativePath(mrws, '/Coding/One/file.txt', 'file.txt', false);
		assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'Two/files/out.txt');
		assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'Two/files/out.txt', true);
		assertAsRelativePath(mrws, '/Coding/Two/files/out.txt', 'files/out.txt', false);
		assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');
		assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true);
		assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false);
J
Johannes Rieken 已提交
106

J
Johannes Rieken 已提交
107
		const srws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService());
108 109 110 111 112 113
		assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt');
		assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt', false);
		assertAsRelativePath(srws, '/Coding/One/file.txt', 'One/file.txt', true);
		assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');
		assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true);
		assertAsRelativePath(srws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false);
J
Johannes Rieken 已提交
114 115
	});

116
	test('getPath, legacy', function () {
J
Johannes Rieken 已提交
117
		let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
118 119
		assert.equal(ws.getPath(), undefined);

J
Johannes Rieken 已提交
120
		ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService());
121 122
		assert.equal(ws.getPath(), undefined);

J
Johannes Rieken 已提交
123
		ws = createExtHostWorkspace(new TestRPCProtocol(), undefined!, new NullLogService());
124 125
		assert.equal(ws.getPath(), undefined);

J
Johannes Rieken 已提交
126
		ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService());
R
Rob Lourens 已提交
127
		assert.equal(ws.getPath()!.replace(/\\/g, '/'), '/Folder');
128

J
Johannes Rieken 已提交
129
		ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService());
M
Matt Bierner 已提交
130
		assert.equal(ws.getPath()!.replace(/\\/g, '/'), '/Folder');
131
	});
J
Johannes Rieken 已提交
132

133
	test('WorkspaceFolder has name and index', function () {
J
Johannes Rieken 已提交
134
		const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
135

M
Matt Bierner 已提交
136
		const [one, two] = ws.getWorkspaceFolders()!;
137 138 139 140 141 142 143

		assert.equal(one.name, 'One');
		assert.equal(one.index, 0);
		assert.equal(two.name, 'Two');
		assert.equal(two.index, 1);
	});

144
	test('getContainingWorkspaceFolder', () => {
145
		const ws = createExtHostWorkspace(new TestRPCProtocol(), {
146 147 148 149 150 151 152
			id: 'foo',
			name: 'Test',
			folders: [
				aWorkspaceFolderData(URI.file('/Coding/One'), 0),
				aWorkspaceFolderData(URI.file('/Coding/Two'), 1),
				aWorkspaceFolderData(URI.file('/Coding/Two/Nested'), 2)
			]
J
Johannes Rieken 已提交
153
		}, new NullLogService());
154

155
		let folder = ws.getWorkspaceFolder(URI.file('/foo/bar'));
156 157
		assert.equal(folder, undefined);

M
Matt Bierner 已提交
158
		folder = ws.getWorkspaceFolder(URI.file('/Coding/One/file/path.txt'))!;
159 160
		assert.equal(folder.name, 'One');

M
Matt Bierner 已提交
161
		folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/file/path.txt'))!;
162 163
		assert.equal(folder.name, 'Two');

M
Matt Bierner 已提交
164
		folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nest'))!;
165 166
		assert.equal(folder.name, 'Two');

M
Matt Bierner 已提交
167
		folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/file'))!;
168 169
		assert.equal(folder.name, 'Nested');

M
Matt Bierner 已提交
170
		folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/f'))!;
171 172
		assert.equal(folder.name, 'Nested');

M
Matt Bierner 已提交
173
		folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'), true)!;
174 175
		assert.equal(folder.name, 'Two');

M
Matt Bierner 已提交
176
		folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'), true)!;
177
		assert.equal(folder.name, 'Two');
178

M
Matt Bierner 已提交
179
		folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested'))!;
180 181
		assert.equal(folder.name, 'Nested');

M
Matt Bierner 已提交
182
		folder = ws.getWorkspaceFolder(URI.file('/Coding/Two/Nested/'))!;
183 184
		assert.equal(folder.name, 'Nested');

M
Matt Bierner 已提交
185
		folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), true)!;
186
		assert.equal(folder, undefined);
187

M
Matt Bierner 已提交
188
		folder = ws.getWorkspaceFolder(URI.file('/Coding/Two'), false)!;
189
		assert.equal(folder.name, 'Two');
190 191
	});

B
Benjamin Pasero 已提交
192
	test('Multiroot change event should have a delta, #29641', function (done) {
J
Johannes Rieken 已提交
193
		let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
J
Johannes Rieken 已提交
194

B
Benjamin Pasero 已提交
195
		let finished = false;
A
Alex Dima 已提交
196
		const finish = (error?: any) => {
B
Benjamin Pasero 已提交
197 198 199 200 201 202
			if (!finished) {
				finished = true;
				done(error);
			}
		};

J
Johannes Rieken 已提交
203
		let sub = ws.onDidChangeWorkspace(e => {
204 205 206 207 208 209
			try {
				assert.deepEqual(e.added, []);
				assert.deepEqual(e.removed, []);
			} catch (error) {
				finish(error);
			}
J
Johannes Rieken 已提交
210
		});
S
Sandeep Somavarapu 已提交
211
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] });
J
Johannes Rieken 已提交
212 213 214
		sub.dispose();

		sub = ws.onDidChangeWorkspace(e => {
B
Benjamin Pasero 已提交
215 216 217 218 219 220 221
			try {
				assert.deepEqual(e.removed, []);
				assert.equal(e.added.length, 1);
				assert.equal(e.added[0].uri.toString(), 'foo:bar');
			} catch (error) {
				finish(error);
			}
J
Johannes Rieken 已提交
222
		});
223
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] });
J
Johannes Rieken 已提交
224 225 226
		sub.dispose();

		sub = ws.onDidChangeWorkspace(e => {
B
Benjamin Pasero 已提交
227 228 229 230 231 232 233
			try {
				assert.deepEqual(e.removed, []);
				assert.equal(e.added.length, 1);
				assert.equal(e.added[0].uri.toString(), 'foo:bar2');
			} catch (error) {
				finish(error);
			}
J
Johannes Rieken 已提交
234
		});
235
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1)] });
J
Johannes Rieken 已提交
236 237 238
		sub.dispose();

		sub = ws.onDidChangeWorkspace(e => {
B
Benjamin Pasero 已提交
239 240 241 242 243 244 245 246 247 248
			try {
				assert.equal(e.removed.length, 2);
				assert.equal(e.removed[0].uri.toString(), 'foo:bar');
				assert.equal(e.removed[1].uri.toString(), 'foo:bar2');

				assert.equal(e.added.length, 1);
				assert.equal(e.added[0].uri.toString(), 'foo:bar3');
			} catch (error) {
				finish(error);
			}
J
Johannes Rieken 已提交
249
		});
250
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] });
J
Johannes Rieken 已提交
251
		sub.dispose();
B
Benjamin Pasero 已提交
252
		finish();
J
Johannes Rieken 已提交
253 254
	});

255
	test('Multiroot change keeps existing workspaces live', function () {
J
Johannes Rieken 已提交
256
		let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService());
257

M
Matt Bierner 已提交
258
		let firstFolder = ws.getWorkspaceFolders()![0];
259 260
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar2'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1, 'renamed')] });

M
Matt Bierner 已提交
261
		assert.equal(ws.getWorkspaceFolders()![1], firstFolder);
262 263 264 265
		assert.equal(firstFolder.index, 1);
		assert.equal(firstFolder.name, 'renamed');

		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1), aWorkspaceFolderData(URI.parse('foo:bar'), 2)] });
M
Matt Bierner 已提交
266
		assert.equal(ws.getWorkspaceFolders()![2], firstFolder);
267
		assert.equal(firstFolder.index, 2);
B
Benjamin Pasero 已提交
268 269 270 271

		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] });
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1)] });

M
Matt Bierner 已提交
272
		assert.notEqual(firstFolder, ws.workspace!.folders[0]);
B
Benjamin Pasero 已提交
273 274 275
	});

	test('updateWorkspaceFolders - invalid arguments', function () {
J
Johannes Rieken 已提交
276
		let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
B
Benjamin Pasero 已提交
277

278
		assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, null!, null!));
B
Benjamin Pasero 已提交
279 280 281 282 283
		assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0));
		assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1));
		assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0));
		assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, 0));
		assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, -1));
B
Benjamin Pasero 已提交
284

J
Johannes Rieken 已提交
285
		ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService());
B
Benjamin Pasero 已提交
286

B
Benjamin Pasero 已提交
287 288 289
		assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 1));
		assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2));
		assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 1, asUpdateWorkspaceFolderData(URI.parse('foo:bar'))));
B
Benjamin Pasero 已提交
290 291 292 293
	});

	test('updateWorkspaceFolders - valid arguments', function (done) {
		let finished = false;
A
Alex Dima 已提交
294
		const finish = (error?: any) => {
B
Benjamin Pasero 已提交
295 296 297 298 299 300
			if (!finished) {
				finished = true;
				done(error);
			}
		};

A
Alex Dima 已提交
301
		const protocol: IMainContext = {
302
			getProxy: () => { return undefined!; },
J
Johannes Rieken 已提交
303
			set: () => { return undefined!; },
304 305
			assertRegistered: () => { },
			drain: () => { return undefined!; },
B
Benjamin Pasero 已提交
306 307
		};

J
Johannes Rieken 已提交
308
		const ws = createExtHostWorkspace(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
B
Benjamin Pasero 已提交
309 310 311 312 313

		//
		// Add one folder
		//

B
Benjamin Pasero 已提交
314
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar'))));
M
Matt Bierner 已提交
315 316
		assert.equal(1, ws.workspace!.folders.length);
		assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());
B
Benjamin Pasero 已提交
317

M
Matt Bierner 已提交
318
		const firstAddedFolder = ws.getWorkspaceFolders()![0];
319

320
		let gotEvent = false;
B
Benjamin Pasero 已提交
321 322 323 324 325
		let sub = ws.onDidChangeWorkspace(e => {
			try {
				assert.deepEqual(e.removed, []);
				assert.equal(e.added.length, 1);
				assert.equal(e.added[0].uri.toString(), 'foo:bar');
326
				assert.equal(e.added[0], firstAddedFolder); // verify object is still live
327
				gotEvent = true;
B
Benjamin Pasero 已提交
328 329 330 331 332
			} catch (error) {
				finish(error);
			}
		});
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }); // simulate acknowledgement from main side
333
		assert.equal(gotEvent, true);
B
Benjamin Pasero 已提交
334
		sub.dispose();
M
Matt Bierner 已提交
335
		assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live
B
Benjamin Pasero 已提交
336 337 338 339 340

		//
		// Add two more folders
		//

B
Benjamin Pasero 已提交
341
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar1')), asUpdateWorkspaceFolderData(URI.parse('foo:bar2'))));
M
Matt Bierner 已提交
342 343 344 345
		assert.equal(3, ws.workspace!.folders.length);
		assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());
		assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString());
		assert.equal(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar2').toString());
B
Benjamin Pasero 已提交
346

M
Matt Bierner 已提交
347 348
		const secondAddedFolder = ws.getWorkspaceFolders()![1];
		const thirdAddedFolder = ws.getWorkspaceFolders()![2];
349 350

		gotEvent = false;
B
Benjamin Pasero 已提交
351 352 353 354 355 356
		sub = ws.onDidChangeWorkspace(e => {
			try {
				assert.deepEqual(e.removed, []);
				assert.equal(e.added.length, 2);
				assert.equal(e.added[0].uri.toString(), 'foo:bar1');
				assert.equal(e.added[1].uri.toString(), 'foo:bar2');
357 358 359
				assert.equal(e.added[0], secondAddedFolder);
				assert.equal(e.added[1], thirdAddedFolder);
				gotEvent = true;
B
Benjamin Pasero 已提交
360 361 362 363 364
			} catch (error) {
				finish(error);
			}
		});
		ws.$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 side
365
		assert.equal(gotEvent, true);
B
Benjamin Pasero 已提交
366
		sub.dispose();
M
Matt Bierner 已提交
367 368 369
		assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![2], thirdAddedFolder); // verify object is still live
B
Benjamin Pasero 已提交
370 371 372 373 374

		//
		// Remove one folder
		//

B
Benjamin Pasero 已提交
375
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 1));
M
Matt Bierner 已提交
376 377 378
		assert.equal(2, ws.workspace!.folders.length);
		assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());
		assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString());
B
Benjamin Pasero 已提交
379

380
		gotEvent = false;
B
Benjamin Pasero 已提交
381 382 383 384
		sub = ws.onDidChangeWorkspace(e => {
			try {
				assert.deepEqual(e.added, []);
				assert.equal(e.removed.length, 1);
385 386
				assert.equal(e.removed[0], thirdAddedFolder);
				gotEvent = true;
B
Benjamin Pasero 已提交
387 388 389 390 391
			} catch (error) {
				finish(error);
			}
		});
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar1'), 1)] }); // simulate acknowledgement from main side
392
		assert.equal(gotEvent, true);
B
Benjamin Pasero 已提交
393
		sub.dispose();
M
Matt Bierner 已提交
394 395
		assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live
B
Benjamin Pasero 已提交
396 397 398 399 400

		//
		// Rename folder
		//

B
Benjamin Pasero 已提交
401
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar'), 'renamed 1'), asUpdateWorkspaceFolderData(URI.parse('foo:bar1'), 'renamed 2')));
M
Matt Bierner 已提交
402 403 404 405 406 407 408
		assert.equal(2, ws.workspace!.folders.length);
		assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar').toString());
		assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar1').toString());
		assert.equal(ws.workspace!.folders[0].name, 'renamed 1');
		assert.equal(ws.workspace!.folders[1].name, 'renamed 2');
		assert.equal(ws.getWorkspaceFolders()![0].name, 'renamed 1');
		assert.equal(ws.getWorkspaceFolders()![1].name, 'renamed 2');
B
Benjamin Pasero 已提交
409

410
		gotEvent = false;
B
Benjamin Pasero 已提交
411
		sub = ws.onDidChangeWorkspace(e => {
412 413 414 415 416 417 418
			try {
				assert.deepEqual(e.added, []);
				assert.equal(e.removed.length, []);
				gotEvent = true;
			} catch (error) {
				finish(error);
			}
B
Benjamin Pasero 已提交
419 420
		});
		ws.$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 side
421
		assert.equal(gotEvent, true);
B
Benjamin Pasero 已提交
422
		sub.dispose();
M
Matt Bierner 已提交
423 424 425 426 427 428
		assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![1], secondAddedFolder); // verify object is still live
		assert.equal(ws.workspace!.folders[0].name, 'renamed 1');
		assert.equal(ws.workspace!.folders[1].name, 'renamed 2');
		assert.equal(ws.getWorkspaceFolders()![0].name, 'renamed 1');
		assert.equal(ws.getWorkspaceFolders()![1].name, 'renamed 2');
B
Benjamin Pasero 已提交
429 430 431 432 433

		//
		// Add and remove folders
		//

B
Benjamin Pasero 已提交
434
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar3')), asUpdateWorkspaceFolderData(URI.parse('foo:bar4'))));
M
Matt Bierner 已提交
435 436 437
		assert.equal(2, ws.workspace!.folders.length);
		assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar3').toString());
		assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar4').toString());
B
Benjamin Pasero 已提交
438

M
Matt Bierner 已提交
439 440
		const fourthAddedFolder = ws.getWorkspaceFolders()![0];
		const fifthAddedFolder = ws.getWorkspaceFolders()![1];
441 442

		gotEvent = false;
B
Benjamin Pasero 已提交
443 444
		sub = ws.onDidChangeWorkspace(e => {
			try {
445 446 447
				assert.equal(e.added.length, 2);
				assert.equal(e.added[0], fourthAddedFolder);
				assert.equal(e.added[1], fifthAddedFolder);
B
Benjamin Pasero 已提交
448
				assert.equal(e.removed.length, 2);
449 450 451
				assert.equal(e.removed[0], firstAddedFolder);
				assert.equal(e.removed[1], secondAddedFolder);
				gotEvent = true;
B
Benjamin Pasero 已提交
452 453 454 455 456
			} catch (error) {
				finish(error);
			}
		});
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0), aWorkspaceFolderData(URI.parse('foo:bar4'), 1)] }); // simulate acknowledgement from main side
457
		assert.equal(gotEvent, true);
B
Benjamin Pasero 已提交
458
		sub.dispose();
M
Matt Bierner 已提交
459 460
		assert.equal(ws.getWorkspaceFolders()![0], fourthAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![1], fifthAddedFolder); // verify object is still live
B
Benjamin Pasero 已提交
461

462 463 464 465
		//
		// Swap folders
		//

B
Benjamin Pasero 已提交
466
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar4')), asUpdateWorkspaceFolderData(URI.parse('foo:bar3'))));
M
Matt Bierner 已提交
467 468 469
		assert.equal(2, ws.workspace!.folders.length);
		assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString());
		assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString());
470

M
Matt Bierner 已提交
471 472
		assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live
473 474 475 476 477 478 479 480 481 482 483 484 485 486

		gotEvent = false;
		sub = ws.onDidChangeWorkspace(e => {
			try {
				assert.equal(e.added.length, 0);
				assert.equal(e.removed.length, 0);
				gotEvent = true;
			} catch (error) {
				finish(error);
			}
		});
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar4'), 0), aWorkspaceFolderData(URI.parse('foo:bar3'), 1)] }); // simulate acknowledgement from main side
		assert.equal(gotEvent, true);
		sub.dispose();
M
Matt Bierner 已提交
487 488
		assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live
489 490 491
		assert.equal(fifthAddedFolder.index, 0);
		assert.equal(fourthAddedFolder.index, 1);

B
Benjamin Pasero 已提交
492
		//
B
Benjamin Pasero 已提交
493
		// Add one folder after the other without waiting for confirmation (not supported currently)
B
Benjamin Pasero 已提交
494 495
		//

B
Benjamin Pasero 已提交
496
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar5'))));
B
Benjamin Pasero 已提交
497

M
Matt Bierner 已提交
498 499 500 501
		assert.equal(3, ws.workspace!.folders.length);
		assert.equal(ws.workspace!.folders[0].uri.toString(), URI.parse('foo:bar4').toString());
		assert.equal(ws.workspace!.folders[1].uri.toString(), URI.parse('foo:bar3').toString());
		assert.equal(ws.workspace!.folders[2].uri.toString(), URI.parse('foo:bar5').toString());
B
Benjamin Pasero 已提交
502

M
Matt Bierner 已提交
503
		const sixthAddedFolder = ws.getWorkspaceFolders()![2];
B
Benjamin Pasero 已提交
504 505 506 507

		gotEvent = false;
		sub = ws.onDidChangeWorkspace(e => {
			try {
B
Benjamin Pasero 已提交
508
				assert.equal(e.added.length, 1);
B
Benjamin Pasero 已提交
509 510 511 512 513 514 515 516 517 518
				assert.equal(e.added[0], sixthAddedFolder);
				gotEvent = true;
			} catch (error) {
				finish(error);
			}
		});
		ws.$acceptWorkspaceData({
			id: 'foo', name: 'Test', folders: [
				aWorkspaceFolderData(URI.parse('foo:bar4'), 0),
				aWorkspaceFolderData(URI.parse('foo:bar3'), 1),
B
Benjamin Pasero 已提交
519
				aWorkspaceFolderData(URI.parse('foo:bar5'), 2)
B
Benjamin Pasero 已提交
520 521 522 523 524
			]
		}); // simulate acknowledgement from main side
		assert.equal(gotEvent, true);
		sub.dispose();

M
Matt Bierner 已提交
525 526 527
		assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![2], sixthAddedFolder); // verify object is still live
B
Benjamin Pasero 已提交
528

B
Benjamin Pasero 已提交
529
		finish();
530 531
	});

B
Benjamin Pasero 已提交
532 533
	test('Multiroot change event is immutable', function (done) {
		let finished = false;
A
Alex Dima 已提交
534
		const finish = (error?: any) => {
B
Benjamin Pasero 已提交
535 536 537 538 539 540
			if (!finished) {
				finished = true;
				done(error);
			}
		};

J
Johannes Rieken 已提交
541
		let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
J
Johannes Rieken 已提交
542
		let sub = ws.onDidChangeWorkspace(e => {
B
Benjamin Pasero 已提交
543 544 545 546
			try {
				assert.throws(() => {
					(<any>e).added = [];
				});
547 548 549
				// assert.throws(() => {
				// 	(<any>e.added)[0] = null;
				// });
B
Benjamin Pasero 已提交
550 551 552
			} catch (error) {
				finish(error);
			}
J
Johannes Rieken 已提交
553
		});
S
Sandeep Somavarapu 已提交
554
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] });
J
Johannes Rieken 已提交
555
		sub.dispose();
B
Benjamin Pasero 已提交
556
		finish();
J
Johannes Rieken 已提交
557
	});
558

559
	test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () {
560 561 562 563 564 565 566
		if (isWindows) {

			let ws = createExtHostWorkspace(new TestRPCProtocol(), {
				id: 'foo', name: 'Test', folders: [
					aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0)
				]
			}, new NullLogService());
567

568 569 570
			assert.ok(ws.getWorkspaceFolder(URI.file('c:/Users/marek/Desktop/vsc_test/a.txt')));
			assert.ok(ws.getWorkspaceFolder(URI.file('C:/Users/marek/Desktop/vsc_test/b.txt')));
		}
571 572
	});

573
	function aWorkspaceFolderData(uri: URI, index: number, name: string = ''): IWorkspaceFolderData {
574 575 576 577 578 579
		return {
			uri,
			index,
			name: name || basename(uri.path)
		};
	}
B
Benjamin Pasero 已提交
580 581 582 583

	function asUpdateWorkspaceFolderData(uri: URI, name?: string): { uri: URI, name?: string } {
		return { uri, name };
	}
R
Rob Lourens 已提交
584 585 586 587 588 589 590

	test('findFiles - string include', () => {
		const root = '/project/foo';
		const rpcProtocol = new TestRPCProtocol();

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
R
Rob Lourens 已提交
591
			$startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
R
Rob Lourens 已提交
592 593
				mainThreadCalled = true;
				assert.equal(includePattern, 'foo');
R
Rob Lourens 已提交
594 595
				assert.equal(_includeFolder, null);
				assert.equal(excludePatternOrDisregardExcludes, null);
R
Rob Lourens 已提交
596
				assert.equal(maxResults, 10);
R
Rob Lourens 已提交
597
				return Promise.resolve(null);
R
Rob Lourens 已提交
598 599 600
			}
		});

J
Johannes Rieken 已提交
601
		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
R
Rob Lourens 已提交
602
		return ws.findFiles('foo', undefined, 10, new ExtensionIdentifier('test')).then(() => {
R
Rob Lourens 已提交
603 604 605 606 607 608 609 610 611 612
			assert(mainThreadCalled, 'mainThreadCalled');
		});
	});

	test('findFiles - RelativePattern include', () => {
		const root = '/project/foo';
		const rpcProtocol = new TestRPCProtocol();

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
R
Rob Lourens 已提交
613
			$startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
R
Rob Lourens 已提交
614 615 616
				mainThreadCalled = true;
				assert.equal(includePattern, 'glob/**');
				assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON());
R
Rob Lourens 已提交
617 618
				assert.equal(excludePatternOrDisregardExcludes, null);
				return Promise.resolve(null);
R
Rob Lourens 已提交
619 620 621
			}
		});

J
Johannes Rieken 已提交
622
		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
R
Rob Lourens 已提交
623
		return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), undefined, 10, new ExtensionIdentifier('test')).then(() => {
R
Rob Lourens 已提交
624 625 626 627 628 629 630 631 632 633
			assert(mainThreadCalled, 'mainThreadCalled');
		});
	});

	test('findFiles - no excludes', () => {
		const root = '/project/foo';
		const rpcProtocol = new TestRPCProtocol();

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
R
Rob Lourens 已提交
634
			$startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
R
Rob Lourens 已提交
635 636 637 638
				mainThreadCalled = true;
				assert.equal(includePattern, 'glob/**');
				assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON());
				assert.equal(excludePatternOrDisregardExcludes, false);
R
Rob Lourens 已提交
639
				return Promise.resolve(null);
R
Rob Lourens 已提交
640 641 642
			}
		});

J
Johannes Rieken 已提交
643
		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
R
Rob Lourens 已提交
644 645 646 647 648 649 650 651 652 653 654
		return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), null!, 10, new ExtensionIdentifier('test')).then(() => {
			assert(mainThreadCalled, 'mainThreadCalled');
		});
	});

	test('findFiles - with cancelled token', () => {
		const root = '/project/foo';
		const rpcProtocol = new TestRPCProtocol();

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
R
Rob Lourens 已提交
655
			$startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
R
Rob Lourens 已提交
656
				mainThreadCalled = true;
R
Rob Lourens 已提交
657
				return Promise.resolve(null);
R
Rob Lourens 已提交
658 659 660
			}
		});

J
Johannes Rieken 已提交
661
		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
R
Rob Lourens 已提交
662 663 664 665 666 667 668 669 670 671 672 673 674

		const token = CancellationToken.Cancelled;
		return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), null!, 10, new ExtensionIdentifier('test'), token).then(() => {
			assert(!mainThreadCalled, '!mainThreadCalled');
		});
	});

	test('findFiles - RelativePattern exclude', () => {
		const root = '/project/foo';
		const rpcProtocol = new TestRPCProtocol();

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
R
Rob Lourens 已提交
675
			$startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | null> {
R
Rob Lourens 已提交
676 677
				mainThreadCalled = true;
				assert(excludePatternOrDisregardExcludes, 'glob/**'); // Note that the base portion is ignored, see #52651
R
Rob Lourens 已提交
678
				return Promise.resolve(null);
R
Rob Lourens 已提交
679 680 681
			}
		});

J
Johannes Rieken 已提交
682
		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
R
Rob Lourens 已提交
683 684 685 686
		return ws.findFiles('', new RelativePattern(root, 'glob/**'), 10, new ExtensionIdentifier('test')).then(() => {
			assert(mainThreadCalled, 'mainThreadCalled');
		});
	});
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788

	test('findTextInFiles - no include', async () => {
		const root = '/project/foo';
		const rpcProtocol = new TestRPCProtocol();

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
			async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
				mainThreadCalled = true;
				assert.equal(query.pattern, 'foo');
				assert.equal(folder, null);
				assert.equal(options.includePattern, null);
				assert.equal(options.excludePattern, null);
				return null;
			}
		});

		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
		await ws.findTextInFiles({ pattern: 'foo' }, {}, () => { }, new ExtensionIdentifier('test'));
		assert(mainThreadCalled, 'mainThreadCalled');
	});

	test('findTextInFiles - string include', async () => {
		const root = '/project/foo';
		const rpcProtocol = new TestRPCProtocol();

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
			async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
				mainThreadCalled = true;
				assert.equal(query.pattern, 'foo');
				assert.equal(folder, null);
				assert.equal(options.includePattern, '**/files');
				assert.equal(options.excludePattern, null);
				return null;
			}
		});

		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
		await ws.findTextInFiles({ pattern: 'foo' }, { include: '**/files' }, () => { }, new ExtensionIdentifier('test'));
		assert(mainThreadCalled, 'mainThreadCalled');
	});

	test('findTextInFiles - RelativePattern include', async () => {
		const root = '/project/foo';
		const rpcProtocol = new TestRPCProtocol();

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
			async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
				mainThreadCalled = true;
				assert.equal(query.pattern, 'foo');
				assert.deepEqual(folder, URI.file('/other/folder').toJSON());
				assert.equal(options.includePattern, 'glob/**');
				assert.equal(options.excludePattern, null);
				return null;
			}
		});

		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
		await ws.findTextInFiles({ pattern: 'foo' }, { include: new RelativePattern('/other/folder', 'glob/**') }, () => { }, new ExtensionIdentifier('test'));
		assert(mainThreadCalled, 'mainThreadCalled');
	});

	test('findTextInFiles - with cancelled token', async () => {
		const root = '/project/foo';
		const rpcProtocol = new TestRPCProtocol();

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
			async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
				mainThreadCalled = true;
				return null;
			}
		});

		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
		const token = CancellationToken.Cancelled;
		await ws.findTextInFiles({ pattern: 'foo' }, {}, () => { }, new ExtensionIdentifier('test'), token);
		assert(!mainThreadCalled, '!mainThreadCalled');
	});

	test('findTextInFiles - RelativePattern exclude', async () => {
		const root = '/project/foo';
		const rpcProtocol = new TestRPCProtocol();

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
			async $startTextSearch(query: IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise<ITextSearchComplete | null> {
				mainThreadCalled = true;
				assert.equal(query.pattern, 'foo');
				assert.deepEqual(folder, null);
				assert.equal(options.includePattern, null);
				assert.equal(options.excludePattern, 'glob/**'); // exclude folder is ignored...
				return null;
			}
		});

		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
		await ws.findTextInFiles({ pattern: 'foo' }, { exclude: new RelativePattern('/other/folder', 'glob/**') }, () => { }, new ExtensionIdentifier('test'));
		assert(mainThreadCalled, 'mainThreadCalled');
	});
789
});