backupMainService.test.ts 24.7 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 26
import { WorkspacesMainService } from "vs/platform/workspaces/electron-main/workspacesMainService";

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 211 212 213
	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));

		done();
	});

214
	suite('loadSync', () => {
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 260 261 262 263 264 265
		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(), []);
		});

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

270
		test('getWorkspaceBackups() should return [] when workspaces.json is not properly formed JSON', () => {
271 272
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
273
			assert.deepEqual(service.getWorkspaceBackups(), []);
274 275
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
276
			assert.deepEqual(service.getWorkspaceBackups(), []);
277 278
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
279
			assert.deepEqual(service.getWorkspaceBackups(), []);
280
		});
D
Daniel Imms 已提交
281

282
		test('getWorkspaceBackups() should return [] when folderWorkspaces in workspaces.json is absent', () => {
283 284
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
285
			assert.deepEqual(service.getWorkspaceBackups(), []);
286 287
		});

288
		test('getWorkspaceBackups() should return [] when rootWorkspaces in workspaces.json is not a object array', () => {
289
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":{}}');
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":{"foo": "bar"}}');
299
			service.loadSync();
300
			assert.deepEqual(service.getWorkspaceBackups(), []);
301
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":"foo"}');
302
			service.loadSync();
303
			assert.deepEqual(service.getWorkspaceBackups(), []);
304
			fs.writeFileSync(backupWorkspacesPath, '{"rootWorkspaces":1}');
305
			service.loadSync();
306
			assert.deepEqual(service.getWorkspaceBackups(), []);
307
		});
D
Daniel Imms 已提交
308

309 310 311 312
		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()]);
313 314
			configService.setUserConfiguration('files.hotExit', HotExitConfiguration.ON_EXIT_AND_WINDOW_CLOSE);
			service.loadSync();
315
			assert.deepEqual(service.getWorkspaceBackups(), []);
316 317
		});

318
		test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json doesn\'t exist', () => {
319
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
320 321
		});

322
		test('getEmptyWorkspaceBackupPaths() should return [] when workspaces.json is not properly formed JSON', () => {
323 324
			fs.writeFileSync(backupWorkspacesPath, '');
			service.loadSync();
325
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
326 327
			fs.writeFileSync(backupWorkspacesPath, '{]');
			service.loadSync();
328
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
329 330
			fs.writeFileSync(backupWorkspacesPath, 'foo');
			service.loadSync();
331
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
332 333
		});

334
		test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is absent', () => {
335 336
			fs.writeFileSync(backupWorkspacesPath, '{}');
			service.loadSync();
337
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
338 339
		});

340
		test('getEmptyWorkspaceBackupPaths() should return [] when folderWorkspaces in workspaces.json is not a string array', () => {
341 342
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":{}}');
			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":{"foo": "bar"}}');
			service.loadSync();
352
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
353 354
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":"foo"}');
			service.loadSync();
355
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
356 357
			fs.writeFileSync(backupWorkspacesPath, '{"emptyWorkspaces":1}');
			service.loadSync();
358
			assert.deepEqual(service.getEmptyWindowBackupPaths(), []);
359
		});
D
Daniel Imms 已提交
360
	});
361

362
	suite('dedupeFolderWorkspaces', () => {
363
		test('should ignore duplicates on Windows and Mac (folder workspace)', () => {
364 365 366 367 368
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}

D
Daniel Imms 已提交
369
			const backups: IBackupWorkspacesFormat = {
370
				rootWorkspaces: [],
371
				folderWorkspaces: platform.isWindows ? ['c:\\FOO', 'C:\\FOO', 'c:\\foo'] : ['/FOO', '/foo'],
D
Daniel Imms 已提交
372 373 374
				emptyWorkspaces: []
			};

375
			service.dedupeBackups(backups);
376

377
			assert.equal(backups.folderWorkspaces.length, 1);
378
			if (platform.isWindows) {
379
				assert.deepEqual(backups.folderWorkspaces, ['c:\\FOO'], 'should return the first duplicated entry');
D
Daniel Imms 已提交
380
			} else {
381
				assert.deepEqual(backups.folderWorkspaces, ['/FOO'], 'should return the first duplicated entry');
382 383
			}
		});
384 385 386 387 388 389 390 391

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

			const backups: IBackupWorkspacesFormat = {
392
				rootWorkspaces: platform.isWindows ? [toWorkspace('c:\\FOO'), toWorkspace('C:\\FOO'), toWorkspace('c:\\foo')] : [toWorkspace('/FOO'), toWorkspace('/foo')],
393 394 395 396 397 398 399 400
				folderWorkspaces: [],
				emptyWorkspaces: []
			};

			service.dedupeBackups(backups);

			assert.equal(backups.rootWorkspaces.length, 1);
			if (platform.isWindows) {
401
				assert.deepEqual(backups.rootWorkspaces.map(r => r.configPath), ['c:\\FOO'], 'should return the first duplicated entry');
402
			} else {
403
				assert.deepEqual(backups.rootWorkspaces.map(r => r.configPath), ['/FOO'], 'should return the first duplicated entry');
404 405
			}
		});
D
Daniel Imms 已提交
406 407
	});

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

420
		test('should persist paths to workspaces.json (root workspace)', done => {
421 422 423 424 425 426 427 428 429
			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);

430 431
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
432 433 434 435 436

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

437 438 439 440 441
				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 已提交
442
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
443
			assert.deepEqual(service.getFolderBackupPaths(), [fooFile.fsPath.toUpperCase()]);
D
Daniel Imms 已提交
444 445 446 447 448 449
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
				assert.deepEqual(json.folderWorkspaces, [fooFile.fsPath.toUpperCase()]);
				done();
			});
		});
450 451

		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 => {
452 453
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
			assert.deepEqual(service.getWorkspaceBackups().map(b => b.configPath), [fooFile.fsPath.toUpperCase()]);
454 455
			pfs.readFile(backupWorkspacesPath, 'utf-8').then(buffer => {
				const json = <IBackupWorkspacesFormat>JSON.parse(buffer);
456
				assert.deepEqual(json.rootWorkspaces.map(b => b.configPath), [fooFile.fsPath.toUpperCase()]);
457 458 459
				done();
			});
		});
460 461
	});

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

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

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

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

527
	suite('getWorkspaceHash', () => {
D
Daniel Imms 已提交
528
		test('should perform an md5 hash on the path', () => {
529
			assert.equal(service.getFolderHash('/foo'), '1effb2475fcfba4f9e8b8a1dbc8f3caf');
D
Daniel Imms 已提交
530 531
		});

532 533 534 535 536
		test('should ignore case on Windows and Mac', () => {
			// Skip test on Linux
			if (platform.isLinux) {
				return;
			}
D
Daniel Imms 已提交
537

538
			if (platform.isMacintosh) {
539
				assert.equal(service.getFolderHash('/foo'), service.getFolderHash('/FOO'));
540
			}
D
Daniel Imms 已提交
541

542
			if (platform.isWindows) {
543
				assert.equal(service.getFolderHash('c:\\foo'), service.getFolderHash('C:\\FOO'));
544 545
			}
		});
D
Daniel Imms 已提交
546
	});
547

548
	suite('mixed path casing', () => {
549
		test('should handle case insensitive paths properly (registerWindowForBackupsSync) (folder workspace)', done => {
B
Benjamin Pasero 已提交
550 551
			service.registerFolderBackupSync(fooFile.fsPath);
			service.registerFolderBackupSync(fooFile.fsPath.toUpperCase());
552

553 554 555 556 557 558 559 560 561 562
			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 => {
563 564
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath));
			service.registerWorkspaceBackupSync(toWorkspace(fooFile.fsPath.toUpperCase()));
565

566
			if (platform.isLinux) {
567
				assert.equal(service.getWorkspaceBackups().length, 2);
568
			} else {
569
				assert.equal(service.getWorkspaceBackups().length, 1);
570 571 572 573 574
			}

			done();
		});

575
		test('should handle case insensitive paths properly (removeBackupPathSync) (folder workspace)', done => {
576 577

			// same case
B
Benjamin Pasero 已提交
578
			service.registerFolderBackupSync(fooFile.fsPath);
579 580
			service.removeBackupPathSync(fooFile.fsPath, service.backupsData.folderWorkspaces);
			assert.equal(service.getFolderBackupPaths().length, 0);
581 582

			// mixed case
B
Benjamin Pasero 已提交
583
			service.registerFolderBackupSync(fooFile.fsPath);
584 585 586 587 588 589 590 591 592 593
			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();
		});
594
	});
595
});