explorerModel.test.ts 11.4 KB
Newer Older
E
Erich Gamma 已提交
1 2 3 4 5 6 7 8
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

import * as assert from 'assert';
9
import { isUndefinedOrNull } from 'vs/base/common/types';
J
Johannes Rieken 已提交
10
import { isLinux, isWindows } from 'vs/base/common/platform';
E
Erich Gamma 已提交
11
import URI from 'vs/base/common/uri';
J
Johannes Rieken 已提交
12
import { join } from 'vs/base/common/paths';
13
import { validateFileName } from 'vs/workbench/parts/files/electron-browser/fileActions';
I
isidor 已提交
14
import { ExplorerItem } from 'vs/workbench/parts/files/common/explorerModel';
E
Erich Gamma 已提交
15

I
isidor 已提交
16
function createStat(path: string, name: string, isFolder: boolean, hasChildren: boolean, size: number, mtime: number): ExplorerItem {
I
isidor 已提交
17
	return new ExplorerItem(toResource(path), undefined, false, false, isFolder, name, mtime);
E
Erich Gamma 已提交
18 19 20
}

function toResource(path) {
21 22 23 24 25 26
	if (isWindows) {
		return URI.file(join('C:\\', path));
	} else {
		return URI.file(join('/home/john', path));
	}

E
Erich Gamma 已提交
27 28 29 30
}

suite('Files - View Model', () => {

B
Benjamin Pasero 已提交
31
	test('Properties', function () {
32
		const d = new Date().getTime();
B
Benjamin Pasero 已提交
33
		let s = createStat('/path/to/stat', 'sName', true, true, 8096, d);
E
Erich Gamma 已提交
34 35

		assert.strictEqual(s.isDirectoryResolved, false);
B
Benjamin Pasero 已提交
36 37
		assert.strictEqual(s.resource.fsPath, toResource('/path/to/stat').fsPath);
		assert.strictEqual(s.name, 'sName');
E
Erich Gamma 已提交
38 39
		assert.strictEqual(s.isDirectory, true);
		assert.strictEqual(s.mtime, new Date(d).getTime());
40
		assert.strictEqual(s.getChildrenArray().length, 0);
E
Erich Gamma 已提交
41

B
Benjamin Pasero 已提交
42
		s = createStat('/path/to/stat', 'sName', false, false, 8096, d);
43
		assert(isUndefinedOrNull(s.getChildrenArray()));
E
Erich Gamma 已提交
44 45
	});

B
Benjamin Pasero 已提交
46
	test('Add and Remove Child, check for hasChild', function () {
47 48
		const d = new Date().getTime();
		const s = createStat('/path/to/stat', 'sName', true, false, 8096, d);
E
Erich Gamma 已提交
49

50 51
		const child1 = createStat('/path/to/stat/foo', 'foo', true, false, 8096, d);
		const child4 = createStat('/otherpath/to/other/otherbar.html', 'otherbar.html', false, false, 8096, d);
E
Erich Gamma 已提交
52 53 54

		s.addChild(child1);

55
		assert(s.getChildrenArray().length === 1);
E
Erich Gamma 已提交
56

B
Benjamin Pasero 已提交
57
		s.removeChild(child1);
E
Erich Gamma 已提交
58
		s.addChild(child1);
59
		assert(s.getChildrenArray().length === 1);
E
Erich Gamma 已提交
60 61

		s.removeChild(child1);
62
		assert(s.getChildrenArray().length === 0);
E
Erich Gamma 已提交
63 64 65

		// Assert that adding a child updates its path properly
		s.addChild(child4);
B
Benjamin Pasero 已提交
66
		assert.strictEqual(child4.resource.fsPath, toResource('/path/to/stat/' + child4.name).fsPath);
E
Erich Gamma 已提交
67 68
	});

B
Benjamin Pasero 已提交
69
	test('Move', function () {
70
		const d = new Date().getTime();
E
Erich Gamma 已提交
71

72 73 74 75
		const s1 = createStat('/', '/', true, false, 8096, d);
		const s2 = createStat('/path', 'path', true, false, 8096, d);
		const s3 = createStat('/path/to', 'to', true, false, 8096, d);
		const s4 = createStat('/path/to/stat', 'stat', false, false, 8096, d);
E
Erich Gamma 已提交
76 77 78 79 80 81 82

		s1.addChild(s2);
		s2.addChild(s3);
		s3.addChild(s4);

		s4.move(s1);

83
		assert.strictEqual(s3.getChildrenArray().length, 0);
E
Erich Gamma 已提交
84

85
		assert.strictEqual(s1.getChildrenArray().length, 2);
E
Erich Gamma 已提交
86 87

		// Assert the new path of the moved element
B
Benjamin Pasero 已提交
88
		assert.strictEqual(s4.resource.fsPath, toResource('/' + s4.name).fsPath);
E
Erich Gamma 已提交
89 90

		// Move a subtree with children
91 92 93
		const leaf = createStat('/leaf', 'leaf', true, false, 8096, d);
		const leafC1 = createStat('/leaf/folder', 'folder', true, false, 8096, d);
		const leafCC2 = createStat('/leaf/folder/index.html', 'index.html', true, false, 8096, d);
E
Erich Gamma 已提交
94 95 96 97 98 99

		leaf.addChild(leafC1);
		leafC1.addChild(leafCC2);
		s1.addChild(leaf);

		leafC1.move(s3);
B
Benjamin Pasero 已提交
100 101
		assert.strictEqual(leafC1.resource.fsPath, URI.file(s3.resource.fsPath + '/' + leafC1.name).fsPath);
		assert.strictEqual(leafCC2.resource.fsPath, URI.file(leafC1.resource.fsPath + '/' + leafCC2.name).fsPath);
E
Erich Gamma 已提交
102 103
	});

B
Benjamin Pasero 已提交
104
	test('Rename', function () {
105
		const d = new Date().getTime();
E
Erich Gamma 已提交
106

107 108 109 110
		const s1 = createStat('/', '/', true, false, 8096, d);
		const s2 = createStat('/path', 'path', true, false, 8096, d);
		const s3 = createStat('/path/to', 'to', true, false, 8096, d);
		const s4 = createStat('/path/to/stat', 'stat', true, false, 8096, d);
E
Erich Gamma 已提交
111 112 113 114 115

		s1.addChild(s2);
		s2.addChild(s3);
		s3.addChild(s4);

116
		assert.strictEqual(s1.getChild(s2.name), s2);
117
		const s2renamed = createStat('/otherpath', 'otherpath', true, true, 8096, d);
E
Erich Gamma 已提交
118
		s2.rename(s2renamed);
119
		assert.strictEqual(s1.getChild(s2.name), s2);
E
Erich Gamma 已提交
120 121 122 123

		// Verify the paths have changed including children
		assert.strictEqual(s2.name, s2renamed.name);
		assert.strictEqual(s2.resource.fsPath, s2renamed.resource.fsPath);
B
Benjamin Pasero 已提交
124 125
		assert.strictEqual(s3.resource.fsPath, toResource('/otherpath/to').fsPath);
		assert.strictEqual(s4.resource.fsPath, toResource('/otherpath/to/stat').fsPath);
E
Erich Gamma 已提交
126

127
		const s4renamed = createStat('/otherpath/to/statother.js', 'statother.js', true, false, 8096, d);
E
Erich Gamma 已提交
128
		s4.rename(s4renamed);
129
		assert.strictEqual(s3.getChild(s4.name), s4);
E
Erich Gamma 已提交
130 131 132 133
		assert.strictEqual(s4.name, s4renamed.name);
		assert.strictEqual(s4.resource.fsPath, s4renamed.resource.fsPath);
	});

B
Benjamin Pasero 已提交
134
	test('Find', function () {
135
		const d = new Date().getTime();
E
Erich Gamma 已提交
136

137 138 139 140
		const s1 = createStat('/', '/', true, false, 8096, d);
		const s2 = createStat('/path', 'path', true, false, 8096, d);
		const s3 = createStat('/path/to', 'to', true, false, 8096, d);
		const s4 = createStat('/path/to/stat', 'stat', true, false, 8096, d);
B
Benjamin Pasero 已提交
141
		const s4Upper = createStat('/path/to/STAT', 'stat', true, false, 8096, d);
E
Erich Gamma 已提交
142

143 144
		const child1 = createStat('/path/to/stat/foo', 'foo', true, false, 8096, d);
		const child2 = createStat('/path/to/stat/foo/bar.html', 'bar.html', false, false, 8096, d);
E
Erich Gamma 已提交
145 146 147 148 149 150 151 152 153 154 155 156 157

		s1.addChild(s2);
		s2.addChild(s3);
		s3.addChild(s4);
		s4.addChild(child1);
		child1.addChild(child2);

		assert.strictEqual(s1.find(child2.resource), child2);
		assert.strictEqual(s1.find(child1.resource), child1);
		assert.strictEqual(s1.find(s4.resource), s4);
		assert.strictEqual(s1.find(s3.resource), s3);
		assert.strictEqual(s1.find(s2.resource), s2);

B
Benjamin Pasero 已提交
158 159 160 161 162 163
		if (isLinux) {
			assert.ok(!s1.find(s4Upper.resource));
		} else {
			assert.strictEqual(s1.find(s4Upper.resource), s4);
		}

E
Erich Gamma 已提交
164 165 166
		assert.strictEqual(s1.find(toResource('foobar')), null);

		assert.strictEqual(s1.find(toResource('/')), s1);
167
		assert.strictEqual(s1.find(toResource('')), s1);
E
Erich Gamma 已提交
168 169
	});

B
Benjamin Pasero 已提交
170
	test('Find with mixed case', function () {
171
		const d = new Date().getTime();
172

173 174 175 176
		const s1 = createStat('/', '/', true, false, 8096, d);
		const s2 = createStat('/path', 'path', true, false, 8096, d);
		const s3 = createStat('/path/to', 'to', true, false, 8096, d);
		const s4 = createStat('/path/to/stat', 'stat', true, false, 8096, d);
177

178 179
		const child1 = createStat('/path/to/stat/foo', 'foo', true, false, 8096, d);
		const child2 = createStat('/path/to/stat/foo/bar.html', 'bar.html', false, false, 8096, d);
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195

		s1.addChild(s2);
		s2.addChild(s3);
		s3.addChild(s4);
		s4.addChild(child1);
		child1.addChild(child2);

		if (isLinux) { // linux is case sensitive
			assert.ok(!s1.find(toResource('/path/to/stat/Foo')));
			assert.ok(!s1.find(toResource('/Path/to/stat/foo/bar.html')));
		} else {
			assert.ok(s1.find(toResource('/path/to/stat/Foo')));
			assert.ok(s1.find(toResource('/Path/to/stat/foo/bar.html')));
		}
	});

B
Benjamin Pasero 已提交
196
	test('Validate File Name (For Create)', function () {
197 198 199
		const d = new Date().getTime();
		const s = createStat('/path/to/stat', 'sName', true, true, 8096, d);
		const sChild = createStat('/path/to/stat/alles.klar', 'alles.klar', true, true, 8096, d);
E
Erich Gamma 已提交
200 201 202
		s.addChild(sChild);

		assert(validateFileName(s, null) !== null);
B
Benjamin Pasero 已提交
203 204 205
		assert(validateFileName(s, '') !== null);
		assert(validateFileName(s, '  ') !== null);
		assert(validateFileName(s, 'Read Me') === null, 'name containing space');
206

E
Erich Gamma 已提交
207
		if (isWindows) {
B
Benjamin Pasero 已提交
208 209 210 211 212 213
			assert(validateFileName(s, 'foo:bar') !== null);
			assert(validateFileName(s, 'foo*bar') !== null);
			assert(validateFileName(s, 'foo?bar') !== null);
			assert(validateFileName(s, 'foo<bar') !== null);
			assert(validateFileName(s, 'foo>bar') !== null);
			assert(validateFileName(s, 'foo|bar') !== null);
E
Erich Gamma 已提交
214
		}
B
Benjamin Pasero 已提交
215
		assert(validateFileName(s, 'alles.klar') !== null);
E
Erich Gamma 已提交
216

B
Benjamin Pasero 已提交
217 218 219
		assert(validateFileName(s, '.foo') === null);
		assert(validateFileName(s, 'foo.bar') === null);
		assert(validateFileName(s, 'foo') === null);
E
Erich Gamma 已提交
220 221
	});

B
Benjamin Pasero 已提交
222
	test('Validate File Name (For Rename)', function () {
223 224 225
		const d = new Date().getTime();
		const s = createStat('/path/to/stat', 'sName', true, true, 8096, d);
		const sChild = createStat('/path/to/stat/alles.klar', 'alles.klar', true, true, 8096, d);
E
Erich Gamma 已提交
226 227
		s.addChild(sChild);

B
Benjamin Pasero 已提交
228
		assert(validateFileName(s, 'alles.klar') !== null);
E
Erich Gamma 已提交
229 230

		if (isLinux) {
B
Benjamin Pasero 已提交
231 232
			assert(validateFileName(s, 'Alles.klar') === null);
			assert(validateFileName(s, 'Alles.Klar') === null);
E
Erich Gamma 已提交
233
		} else {
B
Benjamin Pasero 已提交
234 235
			assert(validateFileName(s, 'Alles.klar') !== null);
			assert(validateFileName(s, 'Alles.Klar') !== null);
E
Erich Gamma 已提交
236 237
		}

B
Benjamin Pasero 已提交
238 239 240
		assert(validateFileName(s, '.foo') === null);
		assert(validateFileName(s, 'foo.bar') === null);
		assert(validateFileName(s, 'foo') === null);
E
Erich Gamma 已提交
241 242
	});

243 244 245 246 247 248 249 250
	test('Validate Multi-Path File Names', function () {
		const d = new Date().getTime();
		const wsFolder = createStat('/', 'workspaceFolder', true, false, 8096, d);

		assert(validateFileName(wsFolder, 'foo/bar') === null);
		assert(validateFileName(wsFolder, 'foo\\bar') === null);
		assert(validateFileName(wsFolder, 'all/slashes/are/same') === null);
		assert(validateFileName(wsFolder, 'theres/one/different\\slash') === null);
T
Till Salinger 已提交
251
		assert(validateFileName(wsFolder, '/slashAtBeginning') !== null);
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268

		// attempting to add a child to a deeply nested file
		const s1 = createStat('/path', 'path', true, false, 8096, d);
		const s2 = createStat('/path/to', 'to', true, false, 8096, d);
		const s3 = createStat('/path/to/stat', 'stat', true, false, 8096, d);
		wsFolder.addChild(s1);
		s1.addChild(s2);
		s2.addChild(s3);
		const fileDeeplyNested = createStat('/path/to/stat/fileNested', 'fileNested', false, false, 8096, d);
		s3.addChild(fileDeeplyNested);
		assert(validateFileName(wsFolder, '/path/to/stat/fileNested/aChild') !== null);

		// detect if path already exists
		assert(validateFileName(wsFolder, '/path/to/stat/fileNested') !== null);
		assert(validateFileName(wsFolder, '/path/to/stat/') !== null);
	});

B
Benjamin Pasero 已提交
269
	test('Merge Local with Disk', function () {
270
		const d = new Date().toUTCString();
E
Erich Gamma 已提交
271

I
isidor 已提交
272 273
		const merge1 = new ExplorerItem(URI.file(join('C:\\', '/path/to')), undefined, false, false, true, 'to', Date.now(), d);
		const merge2 = new ExplorerItem(URI.file(join('C:\\', '/path/to')), undefined, false, false, true, 'to', Date.now(), new Date(0).toUTCString());
E
Erich Gamma 已提交
274 275

		// Merge Properties
I
isidor 已提交
276
		ExplorerItem.mergeLocalWithDisk(merge2, merge1);
E
Erich Gamma 已提交
277 278 279
		assert.strictEqual(merge1.mtime, merge2.mtime);

		// Merge Child when isDirectoryResolved=false is a no-op
I
isidor 已提交
280
		merge2.addChild(new ExplorerItem(URI.file(join('C:\\', '/path/to/foo.html')), undefined, false, false, true, 'foo.html', Date.now(), d));
I
isidor 已提交
281
		ExplorerItem.mergeLocalWithDisk(merge2, merge1);
282
		assert.strictEqual(merge1.getChildrenArray().length, 0);
E
Erich Gamma 已提交
283 284

		// Merge Child with isDirectoryResolved=true
I
isidor 已提交
285
		const child = new ExplorerItem(URI.file(join('C:\\', '/path/to/foo.html')), undefined, false, false, true, 'foo.html', Date.now(), d);
B
Benjamin Pasero 已提交
286 287
		merge2.removeChild(child);
		merge2.addChild(child);
E
Erich Gamma 已提交
288
		merge2.isDirectoryResolved = true;
I
isidor 已提交
289
		ExplorerItem.mergeLocalWithDisk(merge2, merge1);
290 291 292
		assert.strictEqual(merge1.getChildrenArray().length, 1);
		assert.strictEqual(merge1.getChild('foo.html').name, 'foo.html');
		assert.deepEqual(merge1.getChild('foo.html').parent, merge1, 'Check parent');
E
Erich Gamma 已提交
293 294

		// Verify that merge does not replace existing children, but updates properties in that case
295
		const existingChild = merge1.getChild('foo.html');
I
isidor 已提交
296
		ExplorerItem.mergeLocalWithDisk(merge2, merge1);
297
		assert.ok(existingChild === merge1.getChild(existingChild.name));
E
Erich Gamma 已提交
298
	});
299
});