backupMainService.test.ts 25.9 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 23 24
import { LogMainService } from 'vs/platform/log/common/log';
import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { createHash } from 'crypto';
25
import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService';
26

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

32
	const environmentService = new EnvironmentService(parseArgs(process.argv), process.execPath);
33
	const logService = new LogMainService(environmentService);
34

35
	class TestBackupMainService extends BackupMainService {
36

37
		constructor(backupHome: string, backupWorkspacesPath: string, configService: TestConfigurationService) {
38
			super(environmentService, configService, new LogMainService(environmentService), new WorkspacesMainService(environmentService, logService));
39

40 41
			this.backupHome = backupHome;
			this.workspacesJsonPath = backupWorkspacesPath;
42

43 44 45
			// Force a reload with the new paths
			this.loadSync();
		}
46

47 48 49
		public get backupsData(): IBackupWorkspacesFormat {
			return this.backups;
		}
D
Daniel Imms 已提交
50

51 52 53
		public removeBackupPathSync(workspaceIdentifier: string | IWorkspaceIdentifier, target: (string | IWorkspaceIdentifier)[]): void {
			return super.removeBackupPathSync(workspaceIdentifier, target);
		}
54

55 56 57
		public loadSync(): void {
			super.loadSync();
		}
58

59 60 61
		public dedupeBackups(backups: IBackupWorkspacesFormat): IBackupWorkspacesFormat {
			return super.dedupeBackups(backups);
		}
62

63 64 65
		public toBackupPath(workspacePath: string): string {
			return path.join(this.backupHome, super.getFolderHash(workspacePath));
		}
66

67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
		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();
	}
82 83 84 85

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

86
	let service: TestBackupMainService;
87
	let configService: TestConfigurationService;
88 89

	setup(done => {
90 91
		configService = new TestConfigurationService();
		service = new TestBackupMainService(backupHome, backupWorkspacesPath, configService);
92 93 94 95

		// Delete any existing backups completely and then re-create it.
		extfs.del(backupHome, os.tmpdir(), () => {
			pfs.mkdirp(backupHome).then(() => {
D
Daniel Imms 已提交
96
				done();
97 98 99 100 101 102 103 104
			});
		});
	});

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

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

107
		// 1) backup workspace path does not exist
B
Benjamin Pasero 已提交
108 109
		service.registerFolderBackupSync(fooFile.fsPath);
		service.registerFolderBackupSync(barFile.fsPath);
110
		service.loadSync();
111
		assert.deepEqual(service.getFolderBackupPaths(), []);
112 113 114 115

		// 2) backup workspace path exists with empty contents within
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
B
Benjamin Pasero 已提交
116 117
		service.registerFolderBackupSync(fooFile.fsPath);
		service.registerFolderBackupSync(barFile.fsPath);
118
		service.loadSync();
119
		assert.deepEqual(service.getFolderBackupPaths(), []);
120 121 122 123 124 125 126 127
		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 已提交
128 129
		service.registerFolderBackupSync(fooFile.fsPath);
		service.registerFolderBackupSync(barFile.fsPath);
130
		service.loadSync();
131
		assert.deepEqual(service.getFolderBackupPaths(), []);
132 133 134
		assert.ok(!fs.exists(service.toBackupPath(fooFile.fsPath)));
		assert.ok(!fs.exists(service.toBackupPath(barFile.fsPath)));

135 136 137 138 139 140
		// 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 已提交
141
		service.registerFolderBackupSync(fooFile.fsPath);
142 143 144 145 146 147 148 149 150 151 152 153 154
		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
155 156
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath));
157
		service.loadSync();
158
		assert.deepEqual(service.getWorkspaceBackups(), []);
159 160 161 162

		// 2) backup workspace path exists with empty contents within
		fs.mkdirSync(service.toBackupPath(fooFile.fsPath));
		fs.mkdirSync(service.toBackupPath(barFile.fsPath));
163 164
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath));
165
		service.loadSync();
166
		assert.deepEqual(service.getWorkspaceBackups(), []);
167 168 169 170 171 172 173 174
		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'));
175 176
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath));
177
		service.loadSync();
178
		assert.deepEqual(service.getWorkspaceBackups(), []);
179 180 181 182 183 184 185 186 187
		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);
188 189
		service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
		assert.equal(service.getWorkspaceBackups().length, 1);
190
		assert.equal(service.getEmptyWindowBackupPaths().length, 0);
191 192
		fs.writeFileSync(path.join(fileBackups, 'backup.txt'), '');
		service.loadSync();
193
		assert.equal(service.getWorkspaceBackups().length, 0);
194
		assert.equal(service.getEmptyWindowBackupPaths().length, 1);
195

196 197 198
		done();
	});

199 200 201 202 203 204 205 206 207 208 209 210
	test('service supports to migrate backup data from another location', done => {
		const backupPathToMigrate = service.toBackupPath(fooFile.fsPath);
		fs.mkdirSync(backupPathToMigrate);
		fs.writeFileSync(path.join(backupPathToMigrate, 'backup.txt'), 'Some Data');
		service.registerFolderBackupSync(backupPathToMigrate);

		const workspaceBackupPath = service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath), backupPathToMigrate);

		assert.ok(fs.existsSync(workspaceBackupPath));
		assert.ok(fs.existsSync(path.join(workspaceBackupPath, 'backup.txt')));
		assert.ok(!fs.existsSync(backupPathToMigrate));

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
		const emptyBackups = service.getEmptyWindowBackupPaths();
		assert.equal(0, emptyBackups.length);

		done();
	});

	test('service backup migration makes sure to preserve existing backups', done => {
		const backupPathToMigrate = service.toBackupPath(fooFile.fsPath);
		fs.mkdirSync(backupPathToMigrate);
		fs.writeFileSync(path.join(backupPathToMigrate, 'backup.txt'), 'Some Data');
		service.registerFolderBackupSync(backupPathToMigrate);

		const backupPathToPreserve = service.toBackupPath(barFile.fsPath);
		fs.mkdirSync(backupPathToPreserve);
		fs.writeFileSync(path.join(backupPathToPreserve, 'backup.txt'), 'Some Data');
		service.registerFolderBackupSync(backupPathToPreserve);

		const workspaceBackupPath = service.registerWorkspaceBackupSync(toWorkspace(barFile.fsPath), backupPathToMigrate);

		assert.ok(fs.existsSync(workspaceBackupPath));
		assert.ok(fs.existsSync(path.join(workspaceBackupPath, 'backup.txt')));
		assert.ok(!fs.existsSync(backupPathToMigrate));

		const emptyBackups = service.getEmptyWindowBackupPaths();
		assert.equal(1, emptyBackups.length);
		assert.equal(1, fs.readdirSync(path.join(backupHome, emptyBackups[0])).length);

238 239 240
		done();
	});

241
	suite('loadSync', () => {
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292
		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(), []);
		});

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

297
		test('getWorkspaceBackups() should return [] when workspaces.json is not properly formed JSON', () => {
298 299
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
300
			assert.deepEqual(service.getWorkspaceBackups(), []);
301 302
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
303
			assert.deepEqual(service.getWorkspaceBackups(), []);
304 305
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
306
			assert.deepEqual(service.getWorkspaceBackups(), []);
307
		});
D
Daniel Imms 已提交
308

309
		test('getWorkspaceBackups() should return [] when folderWorkspaces in workspaces.json is absent', () => {
310 311
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
312
			assert.deepEqual(service.getWorkspaceBackups(), []);
313 314
		});

315
		test('getWorkspaceBackups() should return [] when rootWorkspaces in workspaces.json is not a object array', () => {
316
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{}}');
317
			service.loadSync();
318
			assert.deepEqual(service.getWorkspaceBackups(), []);
319
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": ["bar"]}}');
320
			service.loadSync();
321
			assert.deepEqual(service.getWorkspaceBackups(), []);
322
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": []}}');
323
			service.loadSync();
324
			assert.deepEqual(service.getWorkspaceBackups(), []);
325
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{"foo": "bar"}}');
326
			service.loadSync();
327
			assert.deepEqual(service.getWorkspaceBackups(), []);
328
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":"foo"}');
329
			service.loadSync();
330
			assert.deepEqual(service.getWorkspaceBackups(), []);
331
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":1}');
332
			service.loadSync();
333
			assert.deepEqual(service.getWorkspaceBackups(), []);
334
		});
D
Daniel Imms 已提交
335

336 337 338 339
		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()]);
340 341
			configService.setUserConfiguration('files.hotExit', HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE);
			service.loadSync();
342
			assert.deepEqual(service.getWorkspaceBackups(), []);
343 344
		});

345
		test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json doesn\'t exist', () => {
346
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
347 348
		});

349
		test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json is not properly formed JSON', () => {
350 351
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
352
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
353 354
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
355
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
356 357
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
358
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
359 360
		});

361
		test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is absent', () => {
362 363
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
364
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
365 366
		});

367
		test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', () => {
368 369
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{}}');
			service.loadSync();
370
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
371 372
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": ["bar"]}}');
			service.loadSync();
373
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
374 375
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": []}}');
			service.loadSync();
376
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
377 378
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{"foo": "bar"}}');
			service.loadSync();
379
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
380 381
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":"foo"}');
			service.loadSync();
382
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
383 384
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":1}');
			service.loadSync();
385
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
386
		});
D
Daniel Imms 已提交
387
	});
388

389
	suite('dedupeFolderWorkspaces', () => {
390
		test('should ignore duplicates on Windows and Mac (folder workspace)', () => {
391 392 393 394 395
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}

D
Daniel Imms 已提交
396
			const backups: IBackupWorkspacesFormat = {
397
				rootWorkspaces: [],
398
				folderWorkspaces: platform.isWindows ? ['c:\\FOO', 'C:\\FOO', 'c:\\foo'] : ['/FOO', '/foo'],
D
Daniel Imms 已提交
399 400 401
				emptyWorkspaces: []
			};

402
			service.dedupeBackups(backups);
403

404
			assert.equal(backups.folderWorkspaces.length, 1);
405
			if (platform.isWindows) {
406
				assert.deepEqual(backups.folderWorkspaces, ['c:\\FOO'], 'should return the first duplicated entry');
D
Daniel Imms 已提交
407
			} else {
408
				assert.deepEqual(backups.folderWorkspaces, ['/FOO'], 'should return the first duplicated entry');
409 410
			}
		});
411 412 413 414 415 416 417 418

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

			const backups: IBackupWorkspacesFormat = {
419
				rootWorkspaces: platform.isWindows ? [toWorkspace('c:\\FOO'), toWorkspace('C:\\FOO'), toWorkspace('c:\\foo')] : [toWorkspace('/FOO'), toWorkspace('/foo')],
420 421 422 423 424 425 426 427
				folderWorkspaces: [],
				emptyWorkspaces: []
			};

			service.dedupeBackups(backups);

			assert.equal(backups.rootWorkspaces.length, 1);
			if (platform.isWindows) {
428
				assert.deepEqual(backups.rootWorkspaces.map(r => r.configPath), ['c:\\FOO'], 'should return the first duplicated entry');
429
			} else {
430
				assert.deepEqual(backups.rootWorkspaces.map(r => r.configPath), ['/FOO'], 'should return the first duplicated entry');
431 432
			}
		});
D
Daniel Imms 已提交
433 434
	});

435
	suite('registerWindowForBackups', () => {
436
		test('should persist paths to workspaces.json (folder workspace)', done => {
B
Benjamin Pasero 已提交
437 438
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(barFile.fsPath);
439
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath, barFile.fsPath]);
440 441 442
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath, barFile.fsPath]);
D
Daniel Imms 已提交
443
				done();
444 445
			});
		});
D
Daniel Imms 已提交
446

447
		test('should persist paths to workspaces.json (root workspace)', done => {
448 449 450 451 452 453 454 455 456
			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);

457 458
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
459 460 461 462 463

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

464 465 466 467 468
				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 已提交
469
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
470
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath.toUpperCase()]);
D
Daniel Imms 已提交
471 472 473 474 475 476
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath.toUpperCase()]);
				done();
			});
		});
477 478

		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 => {
479 480
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
			assert.deepEqual(service.getWorkspaceBackups().map(b => b.configPath), [fooFile.fsPath.toUpperCase()]);
481 482
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
483
				assert.deepEqual(json.rootWorkspaces.map(b => b.configPath), [fooFile.fsPath.toUpperCase()]);
484 485 486
				done();
			});
		});
487 488
	});

489
	suite('removeBackupPathSync', () => {
490
		test('should remove folder workspaces from workspaces.json (folder workspace)', done => {
B
Benjamin Pasero 已提交
491 492
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(barFile.fsPath);
493
			service.removeBackupPathSync(fooFile.fsPath, service.backupsData.folderWorkspaces);
494 495 496
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [barFile.fsPath]);
497
				service.removeBackupPathSync(barFile.fsPath, service.backupsData.folderWorkspaces);
498 499 500 501 502
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.folderWorkspaces, []);
					done();
				});
503 504
			});
		});
505

506
		test('should remove folder workspaces from workspaces.json (root workspace)', done => {
507 508 509 510 511
			const ws1 = toWorkspace(fooFile.fsPath);
			service.registerWorkspaceBackupSync(ws1);
			const ws2 = toWorkspace(barFile.fsPath);
			service.registerWorkspaceBackupSync(ws2);
			service.removeBackupPathSync(ws1, service.backupsData.rootWorkspaces);
512 513
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
514 515
				assert.deepEqual(json.rootWorkspaces.map(r => r.configPath), [barFile.fsPath]);
				service.removeBackupPathSync(ws2, service.backupsData.rootWorkspaces);
516 517 518 519 520 521 522 523
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.rootWorkspaces, []);
					done();
				});
			});
		});

D
Daniel Imms 已提交
524
		test('should remove empty workspaces from workspaces.json', done => {
B
Benjamin Pasero 已提交
525 526
			service.registerEmptyWindowBackupSync('foo');
			service.registerEmptyWindowBackupSync('bar');
527
			service.removeBackupPathSync('foo', service.backupsData.emptyWorkspaces);
D
Daniel Imms 已提交
528 529 530
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.emptyWorkspaces, ['bar']);
531
				service.removeBackupPathSync('bar', service.backupsData.emptyWorkspaces);
D
Daniel Imms 已提交
532 533 534 535 536 537 538 539
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json2 = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json2.emptyWorkspaces, []);
					done();
				});
			});
		});

540
		test('should fail gracefully when removing a path that doesn\'t exist', done => {
541
			const workspacesJson: IBackupWorkspacesFormat = { rootWorkspaces: [], folderWorkspaces: [fooFile.fsPath], emptyWorkspaces: [] };
542
			pfs.writeFile(backupWorkspacesPath, JSON.stringify(workspacesJson)).then(() => {
543 544
				service.removeBackupPathSync(barFile.fsPath, service.backupsData.folderWorkspaces);
				service.removeBackupPathSync('test', service.backupsData.emptyWorkspaces);
545 546 547 548 549 550 551
				pfs.readFile(backupWorkspacesPath, 'utf-8').then(content => {
					const json = <IBackupWorkspacesFormat>JSON.parse(content);
					assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath]);
					done();
				});
			});
		});
552
	});
D
Daniel Imms 已提交
553

554
	suite('getWorkspaceHash', () => {
D
Daniel Imms 已提交
555
		test('should perform an md5 hash on the path', () => {
556
			assert.equal(service.getFolderHash('/foo'), '1effb2475fcfba4f9e8b8a1dbc8f3caf');
D
Daniel Imms 已提交
557 558
		});

559 560 561 562 563
		test('should ignore case on Windows and Mac', () => {
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}
D
Daniel Imms 已提交
564

565
			if (platform.isMacintosh) {
566
				assert.equal(service.getFolderHash('/foo'), service.getFolderHash('/FOO'));
567
			}
D
Daniel Imms 已提交
568

569
			if (platform.isWindows) {
570
				assert.equal(service.getFolderHash('c:\\foo'), service.getFolderHash('C:\\FOO'));
571 572
			}
		});
D
Daniel Imms 已提交
573
	});
574

575
	suite('mixed path casing', () => {
576
		test('should handle case insensitive paths properly (registerWindowForBackupsSync) (folder workspace)', done => {
B
Benjamin Pasero 已提交
577 578
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
579

580 581 582 583 584 585 586 587 588 589
			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 => {
590 591
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
592

593
			if (platform.isLinux) {
594
				assert.equal(service.getWorkspaceBackups().length, 2);
595
			} else {
596
				assert.equal(service.getWorkspaceBackups().length, 1);
597 598 599 600 601
			}

			done();
		});

602
		test('should handle case insensitive paths properly (removeBackupPathSync) (folder workspace)', done => {
603 604

			// same case
B
Benjamin Pasero 已提交
605
			service.registerFolderBackupSync(fooFile.fsPath);
606 607
			service.removeBackupPathSync(fooFile.fsPath, service.backupsData.folderWorkspaces);
			assert.equal(service.getFolderBackupPaths().length, 0);
608 609

			// mixed case
B
Benjamin Pasero 已提交
610
			service.registerFolderBackupSync(fooFile.fsPath);
611 612 613 614 615 616 617 618 619 620
			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();
		});
621
	});
622
});