backupMainService.test.ts 24.5 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*---------------------------------------------------------------------------------------------
 *  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';
import * as platform from 'vs/base/common/platform';
D
Daniel Imms 已提交
10
import fs = require('fs');
11 12 13 14 15
import os = require('os');
import path = require('path');
import extfs = require('vs/base/node/extfs');
import pfs = require('vs/base/node/pfs');
import Uri from 'vs/base/common/uri';
16 17
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { parseArgs } from 'vs/platform/environment/node/argv';
D
Daniel Imms 已提交
18
import { BackupMainService } from 'vs/platform/backup/electron-main/backupMainService';
19
import { IBackupWorkspacesFormat } from 'vs/platform/backup/common/backup';
20 21
import { HotExitConfiguration } from 'vs/platform/files/common/files';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
B
Benjamin Pasero 已提交
22
import { LogMainService } from "vs/platform/log/common/log";
23
import { IWorkspaceIdentifier } from "vs/platform/workspaces/common/workspaces";
24
import { createHash } from "crypto";
25
import { WorkspacesMainService } from "vs/platform/workspaces/electron-main/workspacesMainService";
26 27
import { LifecycleService } from "vs/platform/lifecycle/electron-main/lifecycleMain";
import { StorageService } from "vs/platform/storage/node/storage";
28

29 30 31 32
suite('BackupMainService', () => {
	const parentDir = path.join(os.tmpdir(), 'vsctests', 'service');
	const backupHome = path.join(parentDir, 'Backups');
	const backupWorkspacesPath = path.join(backupHome, 'workspaces.json');
33

34
	class TestEnvironmentService extends EnvironmentService {
B
Benjamin Pasero 已提交
35

36 37 38 39
		get userDataPath(): string {
			return parentDir;
		}
	}
40

41 42
	const environmentService = new TestEnvironmentService(parseArgs(process.argv), process.execPath);
	const logService = new LogMainService(environmentService);
43

44
	class TestBackupMainService extends BackupMainService {
45

46 47
		constructor(backupHome: string, backupWorkspacesPath: string, configService: TestConfigurationService) {
			super(environmentService, configService, new LogMainService(environmentService), new WorkspacesMainService(environmentService, logService, new LifecycleService(environmentService, logService, new StorageService(environmentService))));
48

49 50
			this.backupHome = backupHome;
			this.workspacesJsonPath = backupWorkspacesPath;
51

52 53 54
			// Force a reload with the new paths
			this.loadSync();
		}
55

56 57 58
		public get backupsData(): IBackupWorkspacesFormat {
			return this.backups;
		}
D
Daniel Imms 已提交
59

60 61 62
		public removeBackupPathSync(workspaceIdentifier: string | IWorkspaceIdentifier, target: (string | IWorkspaceIdentifier)[]): void {
			return super.removeBackupPathSync(workspaceIdentifier, target);
		}
63

64 65 66
		public loadSync(): void {
			super.loadSync();
		}
67

68 69 70
		public dedupeBackups(backups: IBackupWorkspacesFormat): IBackupWorkspacesFormat {
			return super.dedupeBackups(backups);
		}
71

72 73 74
		public toBackupPath(workspacePath: string): string {
			return path.join(this.backupHome, super.getFolderHash(workspacePath));
		}
75

76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
		public getFolderHash(folderPath: string): string {
			return super.getFolderHash(folderPath);
		}
	}

	function toWorkspace(path: string): IWorkspaceIdentifier {
		return {
			id: createHash('md5').update(sanitizePath(path)).digest('hex'),
			configPath: path
		};
	}

	function sanitizePath(p: string): string {
		return platform.isLinux ? p : p.toLowerCase();
	}
91 92 93 94

	const fooFile = Uri.file(platform.isWindows ? 'C:\\foo' : '/foo');
	const barFile = Uri.file(platform.isWindows ? 'C:\\bar' : '/bar');

95
	let service: TestBackupMainService;
96
	let configService: TestConfigurationService;
97 98

	setup(done => {
99 100
		configService = new TestConfigurationService();
		service = new TestBackupMainService(backupHome, backupWorkspacesPath, configService);
101 102 103 104

		// Delete any existing backups completely and then re-create it.
		extfs.del(backupHome, os.tmpdir(), () => {
			pfs.mkdirp(backupHome).then(() => {
D
Daniel Imms 已提交
105
				done();
106 107 108 109 110 111 112 113
			});
		});
	});

	teardown(done => {
		extfs.del(backupHome, os.tmpdir(), done);
	});

114
	test('service validates backup workspaces on startup and cleans up (folder workspaces)', done => {
115

116
		// 1) backup workspace path does not exist
B
Benjamin Pasero 已提交
117 118
		service.registerFolderBackupSync(fooFile.fsPath);
		service.registerFolderBackupSync(barFile.fsPath);
119
		service.loadSync();
120
		assert.deepEqual(service.getFolderBackupPaths(), []);
121 122 123 124

		// 2) backup workspace path exists with empty contents within
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
B
Benjamin Pasero 已提交
125 126
		service.registerFolderBackupSync(fooFile.fsPath);
		service.registerFolderBackupSync(barFile.fsPath);
127
		service.loadSync();
128
		assert.deepEqual(service.getFolderBackupPaths(), []);
129 130 131 132 133 134 135 136
		assert.ok(!fs.exists(service.toBackupPath(fooFile.fsPath)));
		assert.ok(!fs.exists(service.toBackupPath(barFile.fsPath)));

		// 3) backup workspace path exists with empty folders within
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
		fs.mkdirSync(path.join(service.toBackupPath(fooFile.fsPath), 'file'));
		fs.mkdirSync(path.join(service.toBackupPath(barFile.fsPath), 'untitled'));
B
Benjamin Pasero 已提交
137 138
		service.registerFolderBackupSync(fooFile.fsPath);
		service.registerFolderBackupSync(barFile.fsPath);
139
		service.loadSync();
140
		assert.deepEqual(service.getFolderBackupPaths(), []);
141 142 143
		assert.ok(!fs.exists(service.toBackupPath(fooFile.fsPath)));
		assert.ok(!fs.exists(service.toBackupPath(barFile.fsPath)));

144 145 146 147 148 149
		// 4) backup workspace path points to a workspace that no longer exists
		// so it should convert the backup worspace to an empty workspace backup
		const fileBackups = path.join(service.toBackupPath(fooFile.fsPath), 'file');
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
		fs.mkdirSync(fileBackups);
B
Benjamin Pasero 已提交
150
		service.registerFolderBackupSync(fooFile.fsPath);
151 152 153 154 155 156 157 158 159 160 161 162 163
		assert.equal(service.getFolderBackupPaths().length, 1);
		assert.equal(service.getEmptyWindowBackupPaths().length, 0);
		fs.writeFileSync(path.join(fileBackups, 'backup.txt'), '');
		service.loadSync();
		assert.equal(service.getFolderBackupPaths().length, 0);
		assert.equal(service.getEmptyWindowBackupPaths().length, 1);

		done();
	});

	test('service validates backup workspaces on startup and cleans up (root workspaces)', done => {

		// 1) backup workspace path does not exist
164 165
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath));
166
		service.loadSync();
167
		assert.deepEqual(service.getWorkspaceBackups(), []);
168 169 170 171

		// 2) backup workspace path exists with empty contents within
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
172 173
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath));
174
		service.loadSync();
175
		assert.deepEqual(service.getWorkspaceBackups(), []);
176 177 178 179 180 181 182 183
		assert.ok(!fs.exists(service.toBackupPath(fooFile.fsPath)));
		assert.ok(!fs.exists(service.toBackupPath(barFile.fsPath)));

		// 3) backup workspace path exists with empty folders within
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
		fs.mkdirSync(path.join(service.toBackupPath(fooFile.fsPath), 'file'));
		fs.mkdirSync(path.join(service.toBackupPath(barFile.fsPath), 'untitled'));
184 185
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath));
186
		service.loadSync();
187
		assert.deepEqual(service.getWorkspaceBackups(), []);
188 189 190 191 192 193 194 195 196
		assert.ok(!fs.exists(service.toBackupPath(fooFile.fsPath)));
		assert.ok(!fs.exists(service.toBackupPath(barFile.fsPath)));

		// 4) backup workspace path points to a workspace that no longer exists
		// so it should convert the backup worspace to an empty workspace backup
		const fileBackups = path.join(service.toBackupPath(fooFile.fsPath), 'file');
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
		fs.mkdirSync(fileBackups);
197 198
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		assert.equal(service.getWorkspaceBackups().length, 1);
199
		assert.equal(service.getEmptyWindowBackupPaths().length, 0);
200 201
		fs.writeFileSync(path.join(fileBackups, 'backup.txt'), '');
		service.loadSync();
202
		assert.equal(service.getWorkspaceBackups().length, 0);
203
		assert.equal(service.getEmptyWindowBackupPaths().length, 1);
204

205 206 207
		done();
	});

208
	suite('loadSync', () => {
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259
		test('getFolderBackupPaths() should return [] when workspaces.json doesn\'t exist', () => {
			assert.deepEqual(service.getFolderBackupPaths(), []);
		});

		test('getFolderBackupPaths() should return [] when workspaces.json is not properly formed JSON', () => {
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
		});

		test('getFolderBackupPaths() should return [] when folderWorkspaces in workspaces.json is absent', () => {
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
		});

		test('getFolderBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', () => {
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{}}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{"foo": ["bar"]}}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{"foo": []}}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":{"foo": "bar"}}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":"foo"}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
			fs.writeFileSync(backupWorkspacesPath, '{"folderWorkspaces":1}');
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
		});

		test('getFolderBackupPaths() should return [] when files.hotExit = "onExitAndWindowClose"', () => {
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath.toUpperCase()]);
			configService.setUserConfiguration('files.hotExit', HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE);
			service.loadSync();
			assert.deepEqual(service.getFolderBackupPaths(), []);
		});

260 261
		test('getWorkspaceBackups() should return [] when workspaces.json doesn\'t exist', () => {
			assert.deepEqual(service.getWorkspaceBackups(), []);
262
		});
D
Daniel Imms 已提交
263

264
		test('getWorkspaceBackups() should return [] when workspaces.json is not properly formed JSON', () => {
265 266
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
267
			assert.deepEqual(service.getWorkspaceBackups(), []);
268 269
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
270
			assert.deepEqual(service.getWorkspaceBackups(), []);
271 272
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
273
			assert.deepEqual(service.getWorkspaceBackups(), []);
274
		});
D
Daniel Imms 已提交
275

276
		test('getWorkspaceBackups() should return [] when folderWorkspaces in workspaces.json is absent', () => {
277 278
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
279
			assert.deepEqual(service.getWorkspaceBackups(), []);
280 281
		});

282
		test('getWorkspaceBackups() should return [] when rootWorkspaces in workspaces.json is not a object array', () => {
283
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{}}');
284
			service.loadSync();
285
			assert.deepEqual(service.getWorkspaceBackups(), []);
286
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": ["bar"]}}');
287
			service.loadSync();
288
			assert.deepEqual(service.getWorkspaceBackups(), []);
289
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": []}}');
290
			service.loadSync();
291
			assert.deepEqual(service.getWorkspaceBackups(), []);
292
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": "bar"}}');
293
			service.loadSync();
294
			assert.deepEqual(service.getWorkspaceBackups(), []);
295
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":"foo"}');
296
			service.loadSync();
297
			assert.deepEqual(service.getWorkspaceBackups(), []);
298
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":1}');
299
			service.loadSync();
300
			assert.deepEqual(service.getWorkspaceBackups(), []);
301
		});
D
Daniel Imms 已提交
302

303 304 305 306
		test('getWorkspaceBackups() should return [] when files.hotExit = "onExitAndWindowClose"', () => {
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
			assert.equal(service.getWorkspaceBackups().length, 1);
			assert.deepEqual(service.getWorkspaceBackups().map(r => r.configPath), [fooFile.fsPath.toUpperCase()]);
307 308
			configService.setUserConfiguration('files.hotExit', HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE);
			service.loadSync();
309
			assert.deepEqual(service.getWorkspaceBackups(), []);
310 311
		});

312
		test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json doesn\'t exist', () => {
313
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
314 315
		});

316
		test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json is not properly formed JSON', () => {
317 318
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
319
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
320 321
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
322
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
323 324
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
325
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
326 327
		});

328
		test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is absent', () => {
329 330
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
331
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
332 333
		});

334
		test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', () => {
335 336
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{}}');
			service.loadSync();
337
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
338 339
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": ["bar"]}}');
			service.loadSync();
340
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
341 342
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": []}}');
			service.loadSync();
343
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
344 345
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": "bar"}}');
			service.loadSync();
346
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
347 348
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":"foo"}');
			service.loadSync();
349
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
350 351
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":1}');
			service.loadSync();
352
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
353
		});
D
Daniel Imms 已提交
354
	});
355

356
	suite('dedupeFolderWorkspaces', () => {
357
		test('should ignore duplicates on Windows and Mac (folder workspace)', () => {
358 359 360 361 362
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}

D
Daniel Imms 已提交
363
			const backups: IBackupWorkspacesFormat = {
364
				rootWorkspaces: [],
365
				folderWorkspaces: platform.isWindows ? ['c:\\FOO', 'C:\\FOO', 'c:\\foo'] : ['/FOO', '/foo'],
D
Daniel Imms 已提交
366 367 368
				emptyWorkspaces: []
			};

369
			service.dedupeBackups(backups);
370

371
			assert.equal(backups.folderWorkspaces.length, 1);
372
			if (platform.isWindows) {
373
				assert.deepEqual(backups.folderWorkspaces, ['c:\\FOO'], 'should return the first duplicated entry');
D
Daniel Imms 已提交
374
			} else {
375
				assert.deepEqual(backups.folderWorkspaces, ['/FOO'], 'should return the first duplicated entry');
376 377
			}
		});
378 379 380 381 382 383 384 385

		test('should ignore duplicates on Windows and Mac (root workspace)', () => {
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}

			const backups: IBackupWorkspacesFormat = {
386
				rootWorkspaces: platform.isWindows ? [toWorkspace('c:\\FOO'), toWorkspace('C:\\FOO'), toWorkspace('c:\\foo')] : [toWorkspace('/FOO'), toWorkspace('/foo')],
387 388 389 390 391 392 393 394
				folderWorkspaces: [],
				emptyWorkspaces: []
			};

			service.dedupeBackups(backups);

			assert.equal(backups.rootWorkspaces.length, 1);
			if (platform.isWindows) {
395
				assert.deepEqual(backups.rootWorkspaces.map(r => r.configPath), ['c:\\FOO'], 'should return the first duplicated entry');
396
			} else {
397
				assert.deepEqual(backups.rootWorkspaces.map(r => r.configPath), ['/FOO'], 'should return the first duplicated entry');
398 399
			}
		});
D
Daniel Imms 已提交
400 401
	});

402
	suite('registerWindowForBackups', () => {
403
		test('should persist paths to workspaces.json (folder workspace)', done => {
B
Benjamin Pasero 已提交
404 405
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(barFile.fsPath);
406
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath, barFile.fsPath]);
407 408 409
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath, barFile.fsPath]);
D
Daniel Imms 已提交
410
				done();
411 412
			});
		});
D
Daniel Imms 已提交
413

414
		test('should persist paths to workspaces.json (root workspace)', done => {
415 416 417 418 419 420 421 422 423
			const ws1 = toWorkspace(fooFile.fsPath);
			service.registerWorkspaceBackupSync(ws1);
			const ws2 = toWorkspace(barFile.fsPath);
			service.registerWorkspaceBackupSync(ws2);

			assert.deepEqual(service.getWorkspaceBackups().map(b => b.configPath), [fooFile.fsPath, barFile.fsPath]);
			assert.equal(ws1.id, service.getWorkspaceBackups()[0].id);
			assert.equal(ws2.id, service.getWorkspaceBackups()[1].id);

424 425
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
426 427 428 429 430

				assert.deepEqual(json.rootWorkspaces.map(b => b.configPath), [fooFile.fsPath, barFile.fsPath]);
				assert.equal(ws1.id, json.rootWorkspaces[0].id);
				assert.equal(ws2.id, json.rootWorkspaces[1].id);

431 432 433 434 435
				done();
			});
		});

		test('should always store the workspace path in workspaces.json using the case given, regardless of whether the file system is case-sensitive (folder workspace)', done => {
B
Benjamin Pasero 已提交
436
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
437
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath.toUpperCase()]);
D
Daniel Imms 已提交
438 439 440 441 442 443
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath.toUpperCase()]);
				done();
			});
		});
444 445

		test('should always store the workspace path in workspaces.json using the case given, regardless of whether the file system is case-sensitive (root workspace)', done => {
446 447
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
			assert.deepEqual(service.getWorkspaceBackups().map(b => b.configPath), [fooFile.fsPath.toUpperCase()]);
448 449
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
450
				assert.deepEqual(json.rootWorkspaces.map(b => b.configPath), [fooFile.fsPath.toUpperCase()]);
451 452 453
				done();
			});
		});
454 455
	});

456
	suite('removeBackupPathSync', () => {
457
		test('should remove folder workspaces from workspaces.json (folder workspace)', done => {
B
Benjamin Pasero 已提交
458 459
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(barFile.fsPath);
460
			service.removeBackupPathSync(fooFile.fsPath, service.backupsData.folderWorkspaces);
461 462 463
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [barFile.fsPath]);
464
				service.removeBackupPathSync(barFile.fsPath, service.backupsData.folderWorkspaces);
465 466 467 468 469
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.folderWorkspaces, []);
					done();
				});
470 471
			});
		});
472

473
		test('should remove folder workspaces from workspaces.json (root workspace)', done => {
474 475 476 477 478
			const ws1 = toWorkspace(fooFile.fsPath);
			service.registerWorkspaceBackupSync(ws1);
			const ws2 = toWorkspace(barFile.fsPath);
			service.registerWorkspaceBackupSync(ws2);
			service.removeBackupPathSync(ws1, service.backupsData.rootWorkspaces);
479 480
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
481 482
				assert.deepEqual(json.rootWorkspaces.map(r => r.configPath), [barFile.fsPath]);
				service.removeBackupPathSync(ws2, service.backupsData.rootWorkspaces);
483 484 485 486 487 488 489 490
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.rootWorkspaces, []);
					done();
				});
			});
		});

D
Daniel Imms 已提交
491
		test('should remove empty workspaces from workspaces.json', done => {
B
Benjamin Pasero 已提交
492 493
			service.registerEmptyWindowBackupSync('foo');
			service.registerEmptyWindowBackupSync('bar');
494
			service.removeBackupPathSync('foo', service.backupsData.emptyWorkspaces);
D
Daniel Imms 已提交
495 496 497
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.emptyWorkspaces, ['bar']);
498
				service.removeBackupPathSync('bar', service.backupsData.emptyWorkspaces);
D
Daniel Imms 已提交
499 500 501 502 503 504 505 506
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.emptyWorkspaces, []);
					done();
				});
			});
		});

507
		test('should fail gracefully when removing a path that doesn\'t exist', done => {
508
			const workspacesJson: IBackupWorkspacesFormat = { rootWorkspaces: [], folderWorkspaces: [fooFile.fsPath], emptyWorkspaces: [] };
509
			pfs.writeFile(backupWorkspacesPath, JSON.stringify(workspacesJson)).then(() => {
510 511
				service.removeBackupPathSync(barFile.fsPath, service.backupsData.folderWorkspaces);
				service.removeBackupPathSync('test', service.backupsData.emptyWorkspaces);
512 513 514 515 516 517 518
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath]);
					done();
				});
			});
		});
519
	});
D
Daniel Imms 已提交
520

521
	suite('getWorkspaceHash', () => {
D
Daniel Imms 已提交
522
		test('should perform an md5 hash on the path', () => {
523
			assert.equal(service.getFolderHash('/foo'), '1effb2475fcfba4f9e8b8a1dbc8f3caf');
D
Daniel Imms 已提交
524 525
		});

526 527 528 529 530
		test('should ignore case on Windows and Mac', () => {
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}
D
Daniel Imms 已提交
531

532
			if (platform.isMacintosh) {
533
				assert.equal(service.getFolderHash('/foo'), service.getFolderHash('/FOO'));
534
			}
D
Daniel Imms 已提交
535

536
			if (platform.isWindows) {
537
				assert.equal(service.getFolderHash('c:\\foo'), service.getFolderHash('C:\\FOO'));
538 539
			}
		});
D
Daniel Imms 已提交
540
	});
541

542
	suite('mixed path casing', () => {
543
		test('should handle case insensitive paths properly (registerWindowForBackupsSync) (folder workspace)', done => {
B
Benjamin Pasero 已提交
544 545
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
546

547 548 549 550 551 552 553 554 555 556
			if (platform.isLinux) {
				assert.equal(service.getFolderBackupPaths().length, 2);
			} else {
				assert.equal(service.getFolderBackupPaths().length, 1);
			}

			done();
		});

		test('should handle case insensitive paths properly (registerWindowForBackupsSync) (root workspace)', done => {
557 558
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
559

560
			if (platform.isLinux) {
561
				assert.equal(service.getWorkspaceBackups().length, 2);
562
			} else {
563
				assert.equal(service.getWorkspaceBackups().length, 1);
564 565 566 567 568
			}

			done();
		});

569
		test('should handle case insensitive paths properly (removeBackupPathSync) (folder workspace)', done => {
570 571

			// same case
B
Benjamin Pasero 已提交
572
			service.registerFolderBackupSync(fooFile.fsPath);
573 574
			service.removeBackupPathSync(fooFile.fsPath, service.backupsData.folderWorkspaces);
			assert.equal(service.getFolderBackupPaths().length, 0);
575 576

			// mixed case
B
Benjamin Pasero 已提交
577
			service.registerFolderBackupSync(fooFile.fsPath);
578 579 580 581 582 583 584 585 586 587
			service.removeBackupPathSync(fooFile.fsPath.toUpperCase(), service.backupsData.folderWorkspaces);

			if (platform.isLinux) {
				assert.equal(service.getFolderBackupPaths().length, 1);
			} else {
				assert.equal(service.getFolderBackupPaths().length, 0);
			}

			done();
		});
588
	});
589
});