extHostTreeViews.test.ts 25.0 KB
Newer Older
S
Sandeep Somavarapu 已提交
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';
S
Sandeep Somavarapu 已提交
7
import * as sinon from 'sinon';
S
Sandeep Somavarapu 已提交
8
import { Emitter } from 'vs/base/common/event';
J
Johannes Rieken 已提交
9 10
import { ExtHostTreeViews } from 'vs/workbench/api/common/extHostTreeViews';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
11
import { MainThreadTreeViewsShape, MainContext } from 'vs/workbench/api/common/extHost.protocol';
S
Sandeep Somavarapu 已提交
12
import { TreeDataProvider, TreeItem } from 'vscode';
A
Alex Dima 已提交
13
import { TestRPCProtocol } from './testRPCProtocol';
S
Sandeep Somavarapu 已提交
14
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
J
Johannes Rieken 已提交
15
import { MainThreadCommands } from 'vs/workbench/api/browser/mainThreadCommands';
B
Benjamin Pasero 已提交
16
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
17
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
S
Sandeep Somavarapu 已提交
18
import { TreeItemCollapsibleState, ITreeItem } from 'vs/workbench/common/views';
19
import { NullLogService } from 'vs/platform/log/common/log';
20
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
S
Sandeep Somavarapu 已提交
21

S
Sandeep Somavarapu 已提交
22
suite('ExtHostTreeView', function () {
S
Sandeep Somavarapu 已提交
23

24
	class RecordingShape extends mock<MainThreadTreeViewsShape>() {
S
Sandeep Somavarapu 已提交
25

S
Sandeep Somavarapu 已提交
26
		onRefresh = new Emitter<{ [treeItemHandle: string]: ITreeItem }>();
S
Sandeep Somavarapu 已提交
27

S
Sandeep Somavarapu 已提交
28
		$registerTreeViewDataProvider(treeViewId: string): void {
S
Sandeep Somavarapu 已提交
29 30
		}

S
Sandeep Somavarapu 已提交
31
		$refresh(viewId: string, itemsToRefresh: { [treeItemHandle: string]: ITreeItem }): Promise<void> {
32
			return Promise.resolve(null).then(() => this.onRefresh.fire(itemsToRefresh));
S
Sandeep Somavarapu 已提交
33
		}
S
Sandeep Somavarapu 已提交
34

35
		$reveal(): Promise<void> {
S
Sandeep Somavarapu 已提交
36
			return Promise.resolve();
S
Sandeep Somavarapu 已提交
37 38
		}

39
	}
S
Sandeep Somavarapu 已提交
40 41 42

	let testObject: ExtHostTreeViews;
	let target: RecordingShape;
43
	let onDidChangeTreeNode: Emitter<{ key: string } | undefined>;
S
Sandeep Somavarapu 已提交
44
	let onDidChangeTreeNodeWithId: Emitter<{ key: string }>;
M
Matt Bierner 已提交
45 46 47
	let tree: { [key: string]: any };
	let labels: { [key: string]: string };
	let nodes: { [key: string]: { key: string } };
S
Sandeep Somavarapu 已提交
48 49

	setup(() => {
S
Sandeep Somavarapu 已提交
50 51 52 53 54 55 56 57 58 59 60 61
		tree = {
			'a': {
				'aa': {},
				'ab': {}
			},
			'b': {
				'ba': {},
				'bb': {}
			}
		};

		labels = {};
62
		nodes = {};
S
Sandeep Somavarapu 已提交
63

A
Alex Dima 已提交
64
		let rpcProtocol = new TestRPCProtocol();
65 66 67 68 69 70
		// Use IInstantiationService to get typechecking when instantiating
		let inst: IInstantiationService;
		{
			let instantiationService = new TestInstantiationService();
			inst = instantiationService;
		}
S
Sandeep Somavarapu 已提交
71

A
Alex Dima 已提交
72
		rpcProtocol.set(MainContext.MainThreadCommands, inst.createInstance(MainThreadCommands, rpcProtocol));
S
Sandeep Somavarapu 已提交
73
		target = new RecordingShape();
74
		testObject = new ExtHostTreeViews(target, new ExtHostCommands(
75
			rpcProtocol,
76 77
			new NullLogService()
		), new NullLogService());
78
		onDidChangeTreeNode = new Emitter<{ key: string }>();
S
Sandeep Somavarapu 已提交
79
		onDidChangeTreeNodeWithId = new Emitter<{ key: string }>();
S
Sandeep Somavarapu 已提交
80 81 82
		testObject.createTreeView('testNodeTreeProvider', { treeDataProvider: aNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
		testObject.createTreeView('testNodeWithIdTreeProvider', { treeDataProvider: aNodeWithIdTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
		testObject.createTreeView('testNodeWithHighlightsTreeProvider', { treeDataProvider: aNodeWithHighlightedLabelTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
S
Sandeep Somavarapu 已提交
83

S
Sandeep Somavarapu 已提交
84
		return loadCompleteTree('testNodeTreeProvider');
S
Sandeep Somavarapu 已提交
85 86
	});

87
	test('construct node tree', () => {
88
		return testObject.$getChildren('testNodeTreeProvider')
S
Sandeep Somavarapu 已提交
89 90
			.then(elements => {
				const actuals = elements.map(e => e.handle);
91
				assert.deepEqual(actuals, ['0/0:a', '0/0:b']);
92
				return Promise.all([
S
Sandeep Somavarapu 已提交
93
					testObject.$getChildren('testNodeTreeProvider', '0/0:a')
S
Sandeep Somavarapu 已提交
94 95
						.then(children => {
							const actuals = children.map(e => e.handle);
96
							assert.deepEqual(actuals, ['0/0:a/0:aa', '0/0:a/0:ab']);
97
							return Promise.all([
S
Sandeep Somavarapu 已提交
98
								testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:aa').then(children => assert.equal(children.length, 0)),
99
								testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:ab').then(children => assert.equal(children.length, 0))
S
Sandeep Somavarapu 已提交
100 101
							]);
						}),
102
					testObject.$getChildren('testNodeTreeProvider', '0/0:b')
S
Sandeep Somavarapu 已提交
103 104
						.then(children => {
							const actuals = children.map(e => e.handle);
105
							assert.deepEqual(actuals, ['0/0:b/0:ba', '0/0:b/0:bb']);
106
							return Promise.all([
107 108
								testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:ba').then(children => assert.equal(children.length, 0)),
								testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:bb').then(children => assert.equal(children.length, 0))
109 110 111 112 113 114
							]);
						})
				]);
			});
	});

S
Sandeep Somavarapu 已提交
115
	test('construct id tree', () => {
116
		return testObject.$getChildren('testNodeWithIdTreeProvider')
117 118
			.then(elements => {
				const actuals = elements.map(e => e.handle);
119
				assert.deepEqual(actuals, ['1/a', '1/b']);
120
				return Promise.all([
S
Sandeep Somavarapu 已提交
121
					testObject.$getChildren('testNodeWithIdTreeProvider', '1/a')
122 123
						.then(children => {
							const actuals = children.map(e => e.handle);
124
							assert.deepEqual(actuals, ['1/aa', '1/ab']);
125
							return Promise.all([
S
Sandeep Somavarapu 已提交
126 127
								testObject.$getChildren('testNodeWithIdTreeProvider', '1/aa').then(children => assert.equal(children.length, 0)),
								testObject.$getChildren('testNodeWithIdTreeProvider', '1/ab').then(children => assert.equal(children.length, 0))
128 129
							]);
						}),
S
Sandeep Somavarapu 已提交
130
					testObject.$getChildren('testNodeWithIdTreeProvider', '1/b')
131 132
						.then(children => {
							const actuals = children.map(e => e.handle);
133
							assert.deepEqual(actuals, ['1/ba', '1/bb']);
134
							return Promise.all([
S
Sandeep Somavarapu 已提交
135 136
								testObject.$getChildren('testNodeWithIdTreeProvider', '1/ba').then(children => assert.equal(children.length, 0)),
								testObject.$getChildren('testNodeWithIdTreeProvider', '1/bb').then(children => assert.equal(children.length, 0))
S
Sandeep Somavarapu 已提交
137 138 139 140 141 142
							]);
						})
				]);
			});
	});

S
Sandeep Somavarapu 已提交
143 144 145 146 147
	test('construct highlights tree', () => {
		return testObject.$getChildren('testNodeWithHighlightsTreeProvider')
			.then(elements => {
				assert.deepEqual(removeUnsetKeys(elements), [{
					handle: '1/a',
S
Sandeep Somavarapu 已提交
148
					label: { label: 'a', highlights: [[0, 2], [3, 5]] },
S
Sandeep Somavarapu 已提交
149 150 151
					collapsibleState: TreeItemCollapsibleState.Collapsed
				}, {
					handle: '1/b',
S
Sandeep Somavarapu 已提交
152
					label: { label: 'b', highlights: [[0, 2], [3, 5]] },
S
Sandeep Somavarapu 已提交
153 154 155 156 157 158 159 160
					collapsibleState: TreeItemCollapsibleState.Collapsed
				}]);
				return Promise.all([
					testObject.$getChildren('testNodeWithHighlightsTreeProvider', '1/a')
						.then(children => {
							assert.deepEqual(removeUnsetKeys(children), [{
								handle: '1/aa',
								parentHandle: '1/a',
S
Sandeep Somavarapu 已提交
161
								label: { label: 'aa', highlights: [[0, 2], [3, 5]] },
S
Sandeep Somavarapu 已提交
162 163 164 165
								collapsibleState: TreeItemCollapsibleState.None
							}, {
								handle: '1/ab',
								parentHandle: '1/a',
S
Sandeep Somavarapu 已提交
166
								label: { label: 'ab', highlights: [[0, 2], [3, 5]] },
S
Sandeep Somavarapu 已提交
167 168 169 170 171 172 173 174
								collapsibleState: TreeItemCollapsibleState.None
							}]);
						}),
					testObject.$getChildren('testNodeWithHighlightsTreeProvider', '1/b')
						.then(children => {
							assert.deepEqual(removeUnsetKeys(children), [{
								handle: '1/ba',
								parentHandle: '1/b',
S
Sandeep Somavarapu 已提交
175
								label: { label: 'ba', highlights: [[0, 2], [3, 5]] },
S
Sandeep Somavarapu 已提交
176 177 178 179
								collapsibleState: TreeItemCollapsibleState.None
							}, {
								handle: '1/bb',
								parentHandle: '1/b',
S
Sandeep Somavarapu 已提交
180
								label: { label: 'bb', highlights: [[0, 2], [3, 5]] },
S
Sandeep Somavarapu 已提交
181 182 183 184 185 186 187
								collapsibleState: TreeItemCollapsibleState.None
							}]);
						})
				]);
			});
	});

188
	test('error is thrown if id is not unique', (done) => {
S
Sandeep Somavarapu 已提交
189
		tree['a'] = {
190
			'aa': {},
S
Sandeep Somavarapu 已提交
191
		};
192 193 194 195 196 197 198 199 200 201 202 203 204 205
		tree['b'] = {
			'aa': {},
			'ba': {}
		};
		target.onRefresh.event(() => {
			testObject.$getChildren('testNodeWithIdTreeProvider')
				.then(elements => {
					const actuals = elements.map(e => e.handle);
					assert.deepEqual(actuals, ['1/a', '1/b']);
					return testObject.$getChildren('testNodeWithIdTreeProvider', '1/a')
						.then(() => testObject.$getChildren('testNodeWithIdTreeProvider', '1/b'))
						.then(() => { assert.fail('Should fail with duplicate id'); done(); }, () => done());
				});
		});
206
		onDidChangeTreeNode.fire(undefined);
S
Sandeep Somavarapu 已提交
207 208
	});

S
Sandeep Somavarapu 已提交
209 210
	test('refresh root', function (done) {
		target.onRefresh.event(actuals => {
S
Sandeep Somavarapu 已提交
211
			assert.equal(undefined, actuals);
S
Sandeep Somavarapu 已提交
212 213
			done();
		});
214
		onDidChangeTreeNode.fire(undefined);
S
Sandeep Somavarapu 已提交
215 216
	});

S
Sandeep Somavarapu 已提交
217
	test('refresh a parent node', () => {
218
		return new Promise((c, e) => {
S
Sandeep Somavarapu 已提交
219
			target.onRefresh.event(actuals => {
220 221 222
				assert.deepEqual(['0/0:b'], Object.keys(actuals));
				assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), {
					handle: '0/0:b',
S
Sandeep Somavarapu 已提交
223
					label: { label: 'b' },
S
Sandeep Somavarapu 已提交
224
					collapsibleState: TreeItemCollapsibleState.Collapsed
S
Sandeep Somavarapu 已提交
225
				});
R
Rob Lourens 已提交
226
				c(undefined);
S
Sandeep Somavarapu 已提交
227
			});
228
			onDidChangeTreeNode.fire(getNode('b'));
S
Sandeep Somavarapu 已提交
229 230 231 232 233
		});
	});

	test('refresh a leaf node', function (done) {
		target.onRefresh.event(actuals => {
234 235 236 237
			assert.deepEqual(['0/0:b/0:bb'], Object.keys(actuals));
			assert.deepEqual(removeUnsetKeys(actuals['0/0:b/0:bb']), {
				handle: '0/0:b/0:bb',
				parentHandle: '0/0:b',
S
Sandeep Somavarapu 已提交
238
				label: { label: 'bb' },
S
Sandeep Somavarapu 已提交
239
				collapsibleState: TreeItemCollapsibleState.None
S
Sandeep Somavarapu 已提交
240
			});
S
Sandeep Somavarapu 已提交
241 242
			done();
		});
243
		onDidChangeTreeNode.fire(getNode('bb'));
S
Sandeep Somavarapu 已提交
244 245
	});

246 247
	test('refresh parent and child node trigger refresh only on parent - scenario 1', function (done) {
		target.onRefresh.event(actuals => {
248 249 250
			assert.deepEqual(['0/0:b', '0/0:a/0:aa'], Object.keys(actuals));
			assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), {
				handle: '0/0:b',
S
Sandeep Somavarapu 已提交
251
				label: { label: 'b' },
S
Sandeep Somavarapu 已提交
252
				collapsibleState: TreeItemCollapsibleState.Collapsed
S
Sandeep Somavarapu 已提交
253
			});
S
Sandeep Somavarapu 已提交
254 255 256
			assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), {
				handle: '0/0:a/0:aa',
				parentHandle: '0/0:a',
S
Sandeep Somavarapu 已提交
257
				label: { label: 'aa' },
S
Sandeep Somavarapu 已提交
258
				collapsibleState: TreeItemCollapsibleState.None
S
Sandeep Somavarapu 已提交
259
			});
260 261
			done();
		});
262 263 264
		onDidChangeTreeNode.fire(getNode('b'));
		onDidChangeTreeNode.fire(getNode('aa'));
		onDidChangeTreeNode.fire(getNode('bb'));
265 266 267 268
	});

	test('refresh parent and child node trigger refresh only on parent - scenario 2', function (done) {
		target.onRefresh.event(actuals => {
269 270 271
			assert.deepEqual(['0/0:a/0:aa', '0/0:b'], Object.keys(actuals));
			assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), {
				handle: '0/0:b',
S
Sandeep Somavarapu 已提交
272
				label: { label: 'b' },
S
Sandeep Somavarapu 已提交
273
				collapsibleState: TreeItemCollapsibleState.Collapsed
S
Sandeep Somavarapu 已提交
274
			});
S
Sandeep Somavarapu 已提交
275 276 277
			assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), {
				handle: '0/0:a/0:aa',
				parentHandle: '0/0:a',
S
Sandeep Somavarapu 已提交
278
				label: { label: 'aa' },
S
Sandeep Somavarapu 已提交
279
				collapsibleState: TreeItemCollapsibleState.None
S
Sandeep Somavarapu 已提交
280
			});
281 282
			done();
		});
283 284 285
		onDidChangeTreeNode.fire(getNode('bb'));
		onDidChangeTreeNode.fire(getNode('aa'));
		onDidChangeTreeNode.fire(getNode('b'));
286 287
	});

S
Sandeep Somavarapu 已提交
288 289 290
	test('refresh an element for label change', function (done) {
		labels['a'] = 'aa';
		target.onRefresh.event(actuals => {
S
Sandeep Somavarapu 已提交
291 292
			assert.deepEqual(['0/0:a'], Object.keys(actuals));
			assert.deepEqual(removeUnsetKeys(actuals['0/0:a']), {
293
				handle: '0/0:aa',
S
Sandeep Somavarapu 已提交
294
				label: { label: 'aa' },
S
Sandeep Somavarapu 已提交
295
				collapsibleState: TreeItemCollapsibleState.Collapsed
S
Sandeep Somavarapu 已提交
296 297 298
			});
			done();
		});
299
		onDidChangeTreeNode.fire(getNode('a'));
S
Sandeep Somavarapu 已提交
300 301
	});

S
Sandeep Somavarapu 已提交
302 303
	test('refresh calls are throttled on roots', function (done) {
		target.onRefresh.event(actuals => {
S
Sandeep Somavarapu 已提交
304
			assert.equal(undefined, actuals);
S
Sandeep Somavarapu 已提交
305
			done();
S
Sandeep Somavarapu 已提交
306
		});
307 308 309 310
		onDidChangeTreeNode.fire(undefined);
		onDidChangeTreeNode.fire(undefined);
		onDidChangeTreeNode.fire(undefined);
		onDidChangeTreeNode.fire(undefined);
S
Sandeep Somavarapu 已提交
311 312 313 314
	});

	test('refresh calls are throttled on elements', function (done) {
		target.onRefresh.event(actuals => {
S
Sandeep Somavarapu 已提交
315 316
			assert.deepEqual(['0/0:a', '0/0:b'], Object.keys(actuals));
			done();
S
Sandeep Somavarapu 已提交
317 318
		});

319 320 321 322
		onDidChangeTreeNode.fire(getNode('a'));
		onDidChangeTreeNode.fire(getNode('b'));
		onDidChangeTreeNode.fire(getNode('b'));
		onDidChangeTreeNode.fire(getNode('a'));
S
Sandeep Somavarapu 已提交
323 324
	});

325 326
	test('refresh calls are throttled on unknown elements', function (done) {
		target.onRefresh.event(actuals => {
327
			assert.deepEqual(['0/0:a', '0/0:b'], Object.keys(actuals));
328 329 330
			done();
		});

331 332 333 334
		onDidChangeTreeNode.fire(getNode('a'));
		onDidChangeTreeNode.fire(getNode('b'));
		onDidChangeTreeNode.fire(getNode('g'));
		onDidChangeTreeNode.fire(getNode('a'));
335 336 337 338
	});

	test('refresh calls are throttled on unknown elements and root', function (done) {
		target.onRefresh.event(actuals => {
S
Sandeep Somavarapu 已提交
339
			assert.equal(undefined, actuals);
340 341 342
			done();
		});

343 344 345
		onDidChangeTreeNode.fire(getNode('a'));
		onDidChangeTreeNode.fire(getNode('b'));
		onDidChangeTreeNode.fire(getNode('g'));
346
		onDidChangeTreeNode.fire(undefined);
347 348
	});

S
Sandeep Somavarapu 已提交
349 350
	test('refresh calls are throttled on elements and root', function (done) {
		target.onRefresh.event(actuals => {
S
Sandeep Somavarapu 已提交
351
			assert.equal(undefined, actuals);
S
Sandeep Somavarapu 已提交
352 353 354
			done();
		});

355 356
		onDidChangeTreeNode.fire(getNode('a'));
		onDidChangeTreeNode.fire(getNode('b'));
357
		onDidChangeTreeNode.fire(undefined);
358
		onDidChangeTreeNode.fire(getNode('a'));
S
Sandeep Somavarapu 已提交
359 360
	});

361
	test('generate unique handles from labels by escaping them', (done) => {
S
Sandeep Somavarapu 已提交
362 363 364 365
		tree = {
			'a/0:b': {}
		};

366 367 368 369 370 371 372
		target.onRefresh.event(() => {
			testObject.$getChildren('testNodeTreeProvider')
				.then(elements => {
					assert.deepEqual(elements.map(e => e.handle), ['0/0:a//0:b']);
					done();
				});
		});
373
		onDidChangeTreeNode.fire(undefined);
S
Sandeep Somavarapu 已提交
374 375
	});

376
	test('tree with duplicate labels', (done) => {
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396

		const dupItems = {
			'adup1': 'c',
			'adup2': 'g',
			'bdup1': 'e',
			'hdup1': 'i',
			'hdup2': 'l',
			'jdup1': 'k'
		};

		labels['c'] = 'a';
		labels['e'] = 'b';
		labels['g'] = 'a';
		labels['i'] = 'h';
		labels['l'] = 'h';
		labels['k'] = 'j';

		tree[dupItems['adup1']] = {};
		tree['d'] = {};

M
Matt Bierner 已提交
397
		const bdup1Tree: { [key: string]: any } = {};
398 399 400 401 402 403 404 405 406 407
		bdup1Tree['h'] = {};
		bdup1Tree[dupItems['hdup1']] = {};
		bdup1Tree['j'] = {};
		bdup1Tree[dupItems['jdup1']] = {};
		bdup1Tree[dupItems['hdup2']] = {};

		tree[dupItems['bdup1']] = bdup1Tree;
		tree['f'] = {};
		tree[dupItems['adup2']] = {};

408 409 410 411 412 413 414 415 416 417 418 419 420
		target.onRefresh.event(() => {
			testObject.$getChildren('testNodeTreeProvider')
				.then(elements => {
					const actuals = elements.map(e => e.handle);
					assert.deepEqual(actuals, ['0/0:a', '0/0:b', '0/1:a', '0/0:d', '0/1:b', '0/0:f', '0/2:a']);
					return testObject.$getChildren('testNodeTreeProvider', '0/1:b')
						.then(elements => {
							const actuals = elements.map(e => e.handle);
							assert.deepEqual(actuals, ['0/1:b/0:h', '0/1:b/1:h', '0/1:b/0:j', '0/1:b/1:j', '0/1:b/2:h']);
							done();
						});
				});
		});
S
Sandeep Somavarapu 已提交
421

422
		onDidChangeTreeNode.fire(undefined);
423 424 425 426 427 428 429 430 431 432 433 434 435 436
	});

	test('getChildren is not returned from cache if refreshed', (done) => {
		tree = {
			'c': {}
		};

		target.onRefresh.event(() => {
			testObject.$getChildren('testNodeTreeProvider')
				.then(elements => {
					assert.deepEqual(elements.map(e => e.handle), ['0/0:c']);
					done();
				});
		});
S
Sandeep Somavarapu 已提交
437

438
		onDidChangeTreeNode.fire(undefined);
439 440 441 442 443 444 445
	});

	test('getChildren is returned from cache if not refreshed', () => {
		tree = {
			'c': {}
		};

446
		return testObject.$getChildren('testNodeTreeProvider')
447
			.then(elements => {
448
				assert.deepEqual(elements.map(e => e.handle), ['0/0:a', '0/0:b']);
449 450 451
			});
	});

S
Sandeep Somavarapu 已提交
452
	test('reveal will throw an error if getParent is not implemented', () => {
S
Sandeep Somavarapu 已提交
453
		const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
S
Sandeep Somavarapu 已提交
454 455 456 457 458 459
		return treeView.reveal({ key: 'a' })
			.then(() => assert.fail('Reveal should throw an error as getParent is not implemented'), () => null);
	});

	test('reveal will return empty array for root element', () => {
		const revealTarget = sinon.spy(target, '$reveal');
S
Sandeep Somavarapu 已提交
460
		const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
S
Sandeep Somavarapu 已提交
461 462 463 464
		return treeView.reveal({ key: 'a' })
			.then(() => {
				assert.ok(revealTarget.calledOnce);
				assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
S
Sandeep Somavarapu 已提交
465
				assert.deepEqual({ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }, removeUnsetKeys(revealTarget.args[0][1]));
S
Sandeep Somavarapu 已提交
466
				assert.deepEqual([], revealTarget.args[0][2]);
S
Sandeep Somavarapu 已提交
467
				assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]);
S
Sandeep Somavarapu 已提交
468 469 470
			});
	});

S
Sandeep Somavarapu 已提交
471
	test('reveal will return parents array for an element when hierarchy is not loaded', () => {
S
Sandeep Somavarapu 已提交
472
		const revealTarget = sinon.spy(target, '$reveal');
S
Sandeep Somavarapu 已提交
473
		const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
S
Sandeep Somavarapu 已提交
474 475 476 477
		return treeView.reveal({ key: 'aa' })
			.then(() => {
				assert.ok(revealTarget.calledOnce);
				assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
S
Sandeep Somavarapu 已提交
478 479
				assert.deepEqual({ handle: '0/0:a/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1]));
				assert.deepEqual([{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
S
Sandeep Somavarapu 已提交
480
				assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]);
S
Sandeep Somavarapu 已提交
481 482 483
			});
	});

S
Sandeep Somavarapu 已提交
484 485
	test('reveal will return parents array for an element when hierarchy is loaded', () => {
		const revealTarget = sinon.spy(target, '$reveal');
S
Sandeep Somavarapu 已提交
486
		const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
S
Sandeep Somavarapu 已提交
487 488 489 490 491 492
		return testObject.$getChildren('treeDataProvider')
			.then(() => testObject.$getChildren('treeDataProvider', '0/0:a'))
			.then(() => treeView.reveal({ key: 'aa' })
				.then(() => {
					assert.ok(revealTarget.calledOnce);
					assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
S
Sandeep Somavarapu 已提交
493 494
					assert.deepEqual({ handle: '0/0:a/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1]));
					assert.deepEqual([{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
S
Sandeep Somavarapu 已提交
495
					assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]);
S
Sandeep Somavarapu 已提交
496 497 498
				}));
	});

S
Sandeep Somavarapu 已提交
499 500 501 502 503 504 505 506 507
	test('reveal will return parents array for deeper element with no selection', () => {
		tree = {
			'b': {
				'ba': {
					'bac': {}
				}
			}
		};
		const revealTarget = sinon.spy(target, '$reveal');
S
Sandeep Somavarapu 已提交
508
		const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
S
Sandeep Somavarapu 已提交
509
		return treeView.reveal({ key: 'bac' }, { select: false, focus: false, expand: false })
S
Sandeep Somavarapu 已提交
510 511 512
			.then(() => {
				assert.ok(revealTarget.calledOnce);
				assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
S
Sandeep Somavarapu 已提交
513
				assert.deepEqual({ handle: '0/0:b/0:ba/0:bac', label: { label: 'bac' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b/0:ba' }, removeUnsetKeys(revealTarget.args[0][1]));
S
Sandeep Somavarapu 已提交
514
				assert.deepEqual([
S
Sandeep Somavarapu 已提交
515 516
					{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed },
					{ handle: '0/0:b/0:ba', label: { label: 'ba' }, collapsibleState: TreeItemCollapsibleState.Collapsed, parentHandle: '0/0:b' }
S
Sandeep Somavarapu 已提交
517
				], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
S
Sandeep Somavarapu 已提交
518
				assert.deepEqual({ select: false, focus: false, expand: false }, revealTarget.args[0][3]);
S
Sandeep Somavarapu 已提交
519 520 521
			});
	});

S
Sandeep Somavarapu 已提交
522 523
	test('reveal after first udpate', () => {
		const revealTarget = sinon.spy(target, '$reveal');
S
Sandeep Somavarapu 已提交
524
		const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
S
Sandeep Somavarapu 已提交
525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542
		return loadCompleteTree('treeDataProvider')
			.then(() => {
				tree = {
					'a': {
						'aa': {},
						'ac': {}
					},
					'b': {
						'ba': {},
						'bb': {}
					}
				};
				onDidChangeTreeNode.fire(getNode('a'));

				return treeView.reveal({ key: 'ac' })
					.then(() => {
						assert.ok(revealTarget.calledOnce);
						assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
S
Sandeep Somavarapu 已提交
543 544
						assert.deepEqual({ handle: '0/0:a/0:ac', label: { label: 'ac' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1]));
						assert.deepEqual([{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
S
Sandeep Somavarapu 已提交
545
						assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]);
S
Sandeep Somavarapu 已提交
546 547 548 549 550 551
					});
			});
	});

	test('reveal after second udpate', () => {
		const revealTarget = sinon.spy(target, '$reveal');
S
Sandeep Somavarapu 已提交
552
		const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
S
Sandeep Somavarapu 已提交
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
		return loadCompleteTree('treeDataProvider')
			.then(() => {
				tree = {
					'a': {
						'aa': {},
						'ac': {}
					},
					'b': {
						'ba': {},
						'bb': {}
					}
				};
				onDidChangeTreeNode.fire(getNode('a'));
				tree = {
					'a': {
						'aa': {},
						'ac': {}
					},
					'b': {
						'ba': {},
						'bc': {}
					}
				};
				onDidChangeTreeNode.fire(getNode('b'));

				return treeView.reveal({ key: 'bc' })
					.then(() => {
						assert.ok(revealTarget.calledOnce);
						assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
S
Sandeep Somavarapu 已提交
582 583
						assert.deepEqual({ handle: '0/0:b/0:bc', label: { label: 'bc' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b' }, removeUnsetKeys(revealTarget.args[0][1]));
						assert.deepEqual([{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
S
Sandeep Somavarapu 已提交
584
						assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]);
S
Sandeep Somavarapu 已提交
585 586 587 588
					});
			});
	});

M
Matt Bierner 已提交
589
	function loadCompleteTree(treeId: string, element?: string): Promise<null> {
S
Sandeep Somavarapu 已提交
590 591 592 593 594
		return testObject.$getChildren(treeId, element)
			.then(elements => elements.map(e => loadCompleteTree(treeId, e.handle)))
			.then(() => null);
	}

S
Sandeep Somavarapu 已提交
595
	function removeUnsetKeys(obj: any): any {
S
Sandeep Somavarapu 已提交
596 597 598 599 600
		if (Array.isArray(obj)) {
			return obj.map(o => removeUnsetKeys(o));
		}

		if (typeof obj === 'object') {
M
Matt Bierner 已提交
601
			const result: { [key: string]: any } = {};
S
Sandeep Somavarapu 已提交
602
			for (const key of Object.keys(obj)) {
R
Rob Lourens 已提交
603
				if (obj[key] !== undefined) {
S
Sandeep Somavarapu 已提交
604 605
					result[key] = removeUnsetKeys(obj[key]);
				}
S
Sandeep Somavarapu 已提交
606
			}
S
Sandeep Somavarapu 已提交
607
			return result;
S
Sandeep Somavarapu 已提交
608
		}
S
Sandeep Somavarapu 已提交
609
		return obj;
S
Sandeep Somavarapu 已提交
610 611
	}

612 613 614 615 616 617 618 619 620
	function aNodeTreeDataProvider(): TreeDataProvider<{ key: string }> {
		return {
			getChildren: (element: { key: string }): { key: string }[] => {
				return getChildren(element ? element.key : undefined).map(key => getNode(key));
			},
			getTreeItem: (element: { key: string }): TreeItem => {
				return getTreeItem(element.key);
			},
			onDidChangeTreeData: onDidChangeTreeNode.event
S
Sandeep Somavarapu 已提交
621
		};
622 623
	}

S
Sandeep Somavarapu 已提交
624 625 626 627 628 629 630 631
	function aCompleteNodeTreeDataProvider(): TreeDataProvider<{ key: string }> {
		return {
			getChildren: (element: { key: string }): { key: string }[] => {
				return getChildren(element ? element.key : undefined).map(key => getNode(key));
			},
			getTreeItem: (element: { key: string }): TreeItem => {
				return getTreeItem(element.key);
			},
M
Matt Bierner 已提交
632
			getParent: ({ key }: { key: string }): { key: string } | undefined => {
S
Sandeep Somavarapu 已提交
633
				const parentKey = key.substring(0, key.length - 1);
R
Rob Lourens 已提交
634
				return parentKey ? new Key(parentKey) : undefined;
S
Sandeep Somavarapu 已提交
635 636 637 638 639
			},
			onDidChangeTreeData: onDidChangeTreeNode.event
		};
	}

S
Sandeep Somavarapu 已提交
640
	function aNodeWithIdTreeDataProvider(): TreeDataProvider<{ key: string }> {
641
		return {
S
Sandeep Somavarapu 已提交
642 643
			getChildren: (element: { key: string }): { key: string }[] => {
				return getChildren(element ? element.key : undefined).map(key => getNode(key));
S
Sandeep Somavarapu 已提交
644
			},
S
Sandeep Somavarapu 已提交
645 646 647 648
			getTreeItem: (element: { key: string }): TreeItem => {
				const treeItem = getTreeItem(element.key);
				treeItem.id = element.key;
				return treeItem;
S
Sandeep Somavarapu 已提交
649
			},
S
Sandeep Somavarapu 已提交
650
			onDidChangeTreeData: onDidChangeTreeNodeWithId.event
651 652 653
		};
	}

S
Sandeep Somavarapu 已提交
654 655 656 657 658 659
	function aNodeWithHighlightedLabelTreeDataProvider(): TreeDataProvider<{ key: string }> {
		return {
			getChildren: (element: { key: string }): { key: string }[] => {
				return getChildren(element ? element.key : undefined).map(key => getNode(key));
			},
			getTreeItem: (element: { key: string }): TreeItem => {
S
Sandeep Somavarapu 已提交
660
				const treeItem = getTreeItem(element.key, [[0, 2], [3, 5]]);
S
Sandeep Somavarapu 已提交
661 662 663 664 665 666 667
				treeItem.id = element.key;
				return treeItem;
			},
			onDidChangeTreeData: onDidChangeTreeNodeWithId.event
		};
	}

M
Matt Bierner 已提交
668
	function getTreeElement(element: string): any {
669 670 671 672 673 674 675 676 677 678
		let parent = tree;
		for (let i = 0; i < element.length; i++) {
			parent = parent[element.substring(0, i + 1)];
			if (!parent) {
				return null;
			}
		}
		return parent;
	}

M
Matt Bierner 已提交
679
	function getChildren(key: string | undefined): string[] {
680 681 682 683 684
		if (!key) {
			return Object.keys(tree);
		}
		let treeElement = getTreeElement(key);
		if (treeElement) {
S
Sandeep Somavarapu 已提交
685
			return Object.keys(treeElement);
686 687 688 689
		}
		return [];
	}

S
Sandeep Somavarapu 已提交
690
	function getTreeItem(key: string, highlights?: [number, number][]): TreeItem {
691 692
		const treeElement = getTreeElement(key);
		return {
S
Sandeep Somavarapu 已提交
693
			label: <any>{ label: labels[key] || key, highlights },
S
Sandeep Somavarapu 已提交
694
			collapsibleState: treeElement && Object.keys(treeElement).length ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None
S
Sandeep Somavarapu 已提交
695 696 697
		};
	}

698 699
	function getNode(key: string): { key: string } {
		if (!nodes[key]) {
700
			nodes[key] = new Key(key);
701 702 703 704
		}
		return nodes[key];
	}

705 706 707 708
	class Key {
		constructor(readonly key: string) { }
	}

709
});