extHostWorkspace.test.ts 29.5 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 8
import { CancellationToken } from 'vs/base/common/cancellation';
import { Counter } from 'vs/base/common/numbers';
9
import { basename } from 'vs/base/common/path';
R
Rob Lourens 已提交
10
import { URI, UriComponents } from 'vs/base/common/uri';
11
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
R
Rob Lourens 已提交
12
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
13
import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace';
J
Johannes Rieken 已提交
14
import { MainThreadWorkspace } from 'vs/workbench/api/browser/mainThreadWorkspace';
15
import { IMainContext, IWorkspaceData, MainContext } from 'vs/workbench/api/common/extHost.protocol';
J
Johannes Rieken 已提交
16 17
import { RelativePattern } from 'vs/workbench/api/common/extHostTypes';
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
R
Rob Lourens 已提交
18 19
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
import { TestRPCProtocol } from './testRPCProtocol';
20

21 22 23 24 25 26
function createExtHostWorkspace(mainContext: IMainContext, data: IWorkspaceData, logService: ILogService, requestIdProvider: Counter): ExtHostWorkspace {
	const result = new ExtHostWorkspace(mainContext, logService, requestIdProvider);
	result.$initializeWorkspace(data);
	return result;
}

27 28
suite('ExtHostWorkspace', function () {

B
Benjamin Pasero 已提交
29
	const extensionDescriptor: IExtensionDescription = {
30
		identifier: new ExtensionIdentifier('nullExtensionDescription'),
B
Benjamin Pasero 已提交
31 32 33
		name: 'ext',
		publisher: 'vscode',
		enableProposedApi: false,
34 35
		engines: undefined!,
		extensionLocation: undefined!,
B
Benjamin Pasero 已提交
36
		isBuiltin: false,
37
		isUnderDevelopment: false,
38
		version: undefined!
B
Benjamin Pasero 已提交
39 40
	};

41
	function assertAsRelativePath(workspace: ExtHostWorkspace, input: string, expected: string, includeWorkspace?: boolean) {
42
		const actual = workspace.getRelativePath(input, includeWorkspace);
43
		assert.equal(actual, expected);
44 45
	}

46
	test('asRelativePath', () => {
47

48
		const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService(), new Counter());
49

50 51
		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 已提交
52
			'/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart');
53

54 55 56
		assertAsRelativePath(ws, '', '');
		assertAsRelativePath(ws, '/foo/bar', '/foo/bar');
		assertAsRelativePath(ws, 'in/out', 'in/out');
57
	});
J
Johannes Rieken 已提交
58 59 60 61

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

64
		assertAsRelativePath(ws, input, input);
J
Johannes Rieken 已提交
65 66

		const input2 = '/home/aeschli/workspaces/samples/docker/a.file';
67
		assertAsRelativePath(ws, input2, 'a.file');
68 69 70
	});

	test('asRelativePath, no workspace', function () {
71
		const ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService(), new Counter());
72 73
		assertAsRelativePath(ws, '', '');
		assertAsRelativePath(ws, '/foo/bar', '/foo/bar');
74
	});
J
Johannes Rieken 已提交
75

76
	test('asRelativePath, multiple folders', function () {
77
		const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter());
78 79 80
		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 已提交
81
	});
82

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

86 87 88 89 90 91 92 93 94
		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 已提交
95

96
		const srws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService(), new Counter());
97 98 99 100 101 102
		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 已提交
103 104
	});

105
	test('getPath, legacy', function () {
106
		let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter());
107 108
		assert.equal(ws.getPath(), undefined);

109
		ws = createExtHostWorkspace(new TestRPCProtocol(), null!, new NullLogService(), new Counter());
110 111
		assert.equal(ws.getPath(), undefined);

112
		ws = createExtHostWorkspace(new TestRPCProtocol(), undefined!, new NullLogService(), new Counter());
113 114
		assert.equal(ws.getPath(), undefined);

115
		ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService(), new Counter());
M
Matt Bierner 已提交
116
		assert.equal(ws.getPath()!.replace(/\\/g, '/'), '/Folder');
117

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

122
	test('WorkspaceFolder has name and index', function () {
123
		const ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter());
124

M
Matt Bierner 已提交
125
		const [one, two] = ws.getWorkspaceFolders()!;
126 127 128 129 130 131 132

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

133
	test('getContainingWorkspaceFolder', () => {
134
		const ws = createExtHostWorkspace(new TestRPCProtocol(), {
135 136 137 138 139 140 141
			id: 'foo',
			name: 'Test',
			folders: [
				aWorkspaceFolderData(URI.file('/Coding/One'), 0),
				aWorkspaceFolderData(URI.file('/Coding/Two'), 1),
				aWorkspaceFolderData(URI.file('/Coding/Two/Nested'), 2)
			]
142
		}, new NullLogService(), new Counter());
143

144
		let folder = ws.getWorkspaceFolder(URI.file('/foo/bar'));
145 146
		assert.equal(folder, undefined);

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

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

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

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

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

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

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

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

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

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

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

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

B
Benjamin Pasero 已提交
184
		let finished = false;
A
Alex Dima 已提交
185
		const finish = (error?: any) => {
B
Benjamin Pasero 已提交
186 187 188 189 190 191
			if (!finished) {
				finished = true;
				done(error);
			}
		};

J
Johannes Rieken 已提交
192
		let sub = ws.onDidChangeWorkspace(e => {
193 194 195 196 197 198
			try {
				assert.deepEqual(e.added, []);
				assert.deepEqual(e.removed, []);
			} catch (error) {
				finish(error);
			}
J
Johannes Rieken 已提交
199
		});
S
Sandeep Somavarapu 已提交
200
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] });
J
Johannes Rieken 已提交
201 202 203
		sub.dispose();

		sub = ws.onDidChangeWorkspace(e => {
B
Benjamin Pasero 已提交
204 205 206 207 208 209 210
			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 已提交
211
		});
212
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] });
J
Johannes Rieken 已提交
213 214 215
		sub.dispose();

		sub = ws.onDidChangeWorkspace(e => {
B
Benjamin Pasero 已提交
216 217 218 219 220 221 222
			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 已提交
223
		});
224
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0), aWorkspaceFolderData(URI.parse('foo:bar2'), 1)] });
J
Johannes Rieken 已提交
225 226 227
		sub.dispose();

		sub = ws.onDidChangeWorkspace(e => {
B
Benjamin Pasero 已提交
228 229 230 231 232 233 234 235 236 237
			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 已提交
238
		});
239
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar3'), 0)] });
J
Johannes Rieken 已提交
240
		sub.dispose();
B
Benjamin Pasero 已提交
241
		finish();
J
Johannes Rieken 已提交
242 243
	});

244
	test('Multiroot change keeps existing workspaces live', function () {
245
		let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter());
246

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

M
Matt Bierner 已提交
250
		assert.equal(ws.getWorkspaceFolders()![1], firstFolder);
251 252 253 254
		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 已提交
255
		assert.equal(ws.getWorkspaceFolders()![2], firstFolder);
256
		assert.equal(firstFolder.index, 2);
B
Benjamin Pasero 已提交
257 258 259 260

		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 已提交
261
		assert.notEqual(firstFolder, ws.workspace!.folders[0]);
B
Benjamin Pasero 已提交
262 263 264
	});

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

267
		assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, null!, null!));
B
Benjamin Pasero 已提交
268 269 270 271 272
		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 已提交
273

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

B
Benjamin Pasero 已提交
276 277 278
		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 已提交
279 280 281 282
	});

	test('updateWorkspaceFolders - valid arguments', function (done) {
		let finished = false;
A
Alex Dima 已提交
283
		const finish = (error?: any) => {
B
Benjamin Pasero 已提交
284 285 286 287 288 289
			if (!finished) {
				finished = true;
				done(error);
			}
		};

A
Alex Dima 已提交
290
		const protocol: IMainContext = {
291 292 293
			getProxy: () => { return undefined!; },
			set: undefined!,
			assertRegistered: undefined!
B
Benjamin Pasero 已提交
294 295
		};

296
		const ws = createExtHostWorkspace(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter());
B
Benjamin Pasero 已提交
297 298 299 300 301

		//
		// Add one folder
		//

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

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

308
		let gotEvent = false;
B
Benjamin Pasero 已提交
309 310 311 312 313
		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');
314
				assert.equal(e.added[0], firstAddedFolder); // verify object is still live
315
				gotEvent = true;
B
Benjamin Pasero 已提交
316 317 318 319 320
			} catch (error) {
				finish(error);
			}
		});
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }); // simulate acknowledgement from main side
321
		assert.equal(gotEvent, true);
B
Benjamin Pasero 已提交
322
		sub.dispose();
M
Matt Bierner 已提交
323
		assert.equal(ws.getWorkspaceFolders()![0], firstAddedFolder); // verify object is still live
B
Benjamin Pasero 已提交
324 325 326 327 328

		//
		// Add two more folders
		//

B
Benjamin Pasero 已提交
329
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 1, 0, asUpdateWorkspaceFolderData(URI.parse('foo:bar1')), asUpdateWorkspaceFolderData(URI.parse('foo:bar2'))));
M
Matt Bierner 已提交
330 331 332 333
		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 已提交
334

M
Matt Bierner 已提交
335 336
		const secondAddedFolder = ws.getWorkspaceFolders()![1];
		const thirdAddedFolder = ws.getWorkspaceFolders()![2];
337 338

		gotEvent = false;
B
Benjamin Pasero 已提交
339 340 341 342 343 344
		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');
345 346 347
				assert.equal(e.added[0], secondAddedFolder);
				assert.equal(e.added[1], thirdAddedFolder);
				gotEvent = true;
B
Benjamin Pasero 已提交
348 349 350 351 352
			} 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
353
		assert.equal(gotEvent, true);
B
Benjamin Pasero 已提交
354
		sub.dispose();
M
Matt Bierner 已提交
355 356 357
		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 已提交
358 359 360 361 362

		//
		// Remove one folder
		//

B
Benjamin Pasero 已提交
363
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 2, 1));
M
Matt Bierner 已提交
364 365 366
		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 已提交
367

368
		gotEvent = false;
B
Benjamin Pasero 已提交
369 370 371 372
		sub = ws.onDidChangeWorkspace(e => {
			try {
				assert.deepEqual(e.added, []);
				assert.equal(e.removed.length, 1);
373 374
				assert.equal(e.removed[0], thirdAddedFolder);
				gotEvent = true;
B
Benjamin Pasero 已提交
375 376 377 378 379
			} 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
380
		assert.equal(gotEvent, true);
B
Benjamin Pasero 已提交
381
		sub.dispose();
M
Matt Bierner 已提交
382 383
		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 已提交
384 385 386 387 388

		//
		// Rename folder
		//

B
Benjamin Pasero 已提交
389
		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 已提交
390 391 392 393 394 395 396
		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 已提交
397

398
		gotEvent = false;
B
Benjamin Pasero 已提交
399
		sub = ws.onDidChangeWorkspace(e => {
400 401 402 403 404 405 406
			try {
				assert.deepEqual(e.added, []);
				assert.equal(e.removed.length, []);
				gotEvent = true;
			} catch (error) {
				finish(error);
			}
B
Benjamin Pasero 已提交
407 408
		});
		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
409
		assert.equal(gotEvent, true);
B
Benjamin Pasero 已提交
410
		sub.dispose();
M
Matt Bierner 已提交
411 412 413 414 415 416
		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 已提交
417 418 419 420 421

		//
		// Add and remove folders
		//

B
Benjamin Pasero 已提交
422
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar3')), asUpdateWorkspaceFolderData(URI.parse('foo:bar4'))));
M
Matt Bierner 已提交
423 424 425
		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 已提交
426

M
Matt Bierner 已提交
427 428
		const fourthAddedFolder = ws.getWorkspaceFolders()![0];
		const fifthAddedFolder = ws.getWorkspaceFolders()![1];
429 430

		gotEvent = false;
B
Benjamin Pasero 已提交
431 432
		sub = ws.onDidChangeWorkspace(e => {
			try {
433 434 435
				assert.equal(e.added.length, 2);
				assert.equal(e.added[0], fourthAddedFolder);
				assert.equal(e.added[1], fifthAddedFolder);
B
Benjamin Pasero 已提交
436
				assert.equal(e.removed.length, 2);
437 438 439
				assert.equal(e.removed[0], firstAddedFolder);
				assert.equal(e.removed[1], secondAddedFolder);
				gotEvent = true;
B
Benjamin Pasero 已提交
440 441 442 443 444
			} 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
445
		assert.equal(gotEvent, true);
B
Benjamin Pasero 已提交
446
		sub.dispose();
M
Matt Bierner 已提交
447 448
		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 已提交
449

450 451 452 453
		//
		// Swap folders
		//

B
Benjamin Pasero 已提交
454
		assert.equal(true, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2, asUpdateWorkspaceFolderData(URI.parse('foo:bar4')), asUpdateWorkspaceFolderData(URI.parse('foo:bar3'))));
M
Matt Bierner 已提交
455 456 457
		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());
458

M
Matt Bierner 已提交
459 460
		assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live
461 462 463 464 465 466 467 468 469 470 471 472 473 474

		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 已提交
475 476
		assert.equal(ws.getWorkspaceFolders()![0], fifthAddedFolder); // verify object is still live
		assert.equal(ws.getWorkspaceFolders()![1], fourthAddedFolder); // verify object is still live
477 478 479
		assert.equal(fifthAddedFolder.index, 0);
		assert.equal(fourthAddedFolder.index, 1);

B
Benjamin Pasero 已提交
480
		//
B
Benjamin Pasero 已提交
481
		// Add one folder after the other without waiting for confirmation (not supported currently)
B
Benjamin Pasero 已提交
482 483
		//

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

M
Matt Bierner 已提交
486 487 488 489
		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 已提交
490

M
Matt Bierner 已提交
491
		const sixthAddedFolder = ws.getWorkspaceFolders()![2];
B
Benjamin Pasero 已提交
492 493 494 495

		gotEvent = false;
		sub = ws.onDidChangeWorkspace(e => {
			try {
B
Benjamin Pasero 已提交
496
				assert.equal(e.added.length, 1);
B
Benjamin Pasero 已提交
497 498 499 500 501 502 503 504 505 506
				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 已提交
507
				aWorkspaceFolderData(URI.parse('foo:bar5'), 2)
B
Benjamin Pasero 已提交
508 509 510 511 512
			]
		}); // simulate acknowledgement from main side
		assert.equal(gotEvent, true);
		sub.dispose();

M
Matt Bierner 已提交
513 514 515
		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 已提交
516

B
Benjamin Pasero 已提交
517
		finish();
518 519
	});

B
Benjamin Pasero 已提交
520 521
	test('Multiroot change event is immutable', function (done) {
		let finished = false;
A
Alex Dima 已提交
522
		const finish = (error?: any) => {
B
Benjamin Pasero 已提交
523 524 525 526 527 528
			if (!finished) {
				finished = true;
				done(error);
			}
		};

529
		let ws = createExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter());
J
Johannes Rieken 已提交
530
		let sub = ws.onDidChangeWorkspace(e => {
B
Benjamin Pasero 已提交
531 532 533 534
			try {
				assert.throws(() => {
					(<any>e).added = [];
				});
535 536 537
				// assert.throws(() => {
				// 	(<any>e.added)[0] = null;
				// });
B
Benjamin Pasero 已提交
538 539 540
			} catch (error) {
				finish(error);
			}
J
Johannes Rieken 已提交
541
		});
S
Sandeep Somavarapu 已提交
542
		ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [] });
J
Johannes Rieken 已提交
543
		sub.dispose();
B
Benjamin Pasero 已提交
544
		finish();
J
Johannes Rieken 已提交
545
	});
546

547
	test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () {
548
		let ws = createExtHostWorkspace(new TestRPCProtocol(), {
549 550 551
			id: 'foo', name: 'Test', folders: [
				aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0)
			]
552
		}, new NullLogService(), new Counter());
553 554 555 556 557

		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')));
	});

558
	function aWorkspaceFolderData(uri: URI, index: number, name: string = ''): IWorkspaceFolderData {
559 560 561 562 563 564
		return {
			uri,
			index,
			name: name || basename(uri.path)
		};
	}
B
Benjamin Pasero 已提交
565 566 567 568

	function asUpdateWorkspaceFolderData(uri: URI, name?: string): { uri: URI, name?: string } {
		return { uri, name };
	}
R
Rob Lourens 已提交
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671

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

		let mainThreadCalled = false;
		rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock<MainThreadWorkspace>() {
			$startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> {
				mainThreadCalled = true;
				assert.equal(includePattern, 'foo');
				assert.equal(_includeFolder, undefined);
				assert.equal(excludePatternOrDisregardExcludes, undefined);
				assert.equal(maxResults, 10);
				return Promise.resolve(undefined);
			}
		});

		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter());
		return ws.findFiles('foo', undefined!, 10, new ExtensionIdentifier('test')).then(() => {
			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>() {
			$startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> {
				mainThreadCalled = true;
				assert.equal(includePattern, 'glob/**');
				assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON());
				assert.equal(excludePatternOrDisregardExcludes, undefined);
				return Promise.resolve(undefined);
			}
		});

		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter());
		return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), undefined!, 10, new ExtensionIdentifier('test')).then(() => {
			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>() {
			$startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> {
				mainThreadCalled = true;
				assert.equal(includePattern, 'glob/**');
				assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON());
				assert.equal(excludePatternOrDisregardExcludes, false);
				return Promise.resolve(undefined);
			}
		});

		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter());
		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>() {
			$startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> {
				mainThreadCalled = true;
				return Promise.resolve(undefined);
			}
		});

		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter());

		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>() {
			$startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise<URI[] | undefined> {
				mainThreadCalled = true;
				assert(excludePatternOrDisregardExcludes, 'glob/**'); // Note that the base portion is ignored, see #52651
				return Promise.resolve(undefined);
			}
		});

		const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter());
		return ws.findFiles('', new RelativePattern(root, 'glob/**'), 10, new ExtensionIdentifier('test')).then(() => {
			assert(mainThreadCalled, 'mainThreadCalled');
		});
	});
672
});