diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 14a78336fb8..0fc9dd189ca 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -37,13 +37,27 @@ import { exists } from 'vs/base/node/pfs'; import { getComparisonKey, isEqual, normalizePath, basename as resourcesBasename, fsPath } from 'vs/base/common/resources'; import { endsWith } from 'vs/base/common/strings'; import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; -import { IWindowsState, restoreWindowsState, WindowsStateStoreData, IWindowState, getWindowsStateStoreData } from 'vs/code/electron-main/windowsState'; +import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage'; const enum WindowError { UNRESPONSIVE = 1, CRASHED = 2 } +export interface IWindowState { + workspace?: IWorkspaceIdentifier; + folderUri?: URI; + backupPath?: string; + remoteAuthority?: string; + uiState: ISingleWindowState; +} + +export interface IWindowsState { + lastActiveWindow?: IWindowState; + lastPluginDevelopmentHostWindow?: IWindowState; + openedWindows: IWindowState[]; +} + interface INewWindowState extends ISingleWindowState { hasDefaultState?: boolean; } @@ -144,7 +158,7 @@ export class WindowsManager implements IWindowsMainService { @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IInstantiationService private readonly instantiationService: IInstantiationService ) { - const windowsStateStoreData = this.stateService.getItem(WindowsManager.windowsStateStorageKey); + const windowsStateStoreData = this.stateService.getItem(WindowsManager.windowsStateStorageKey); this.windowsState = restoreWindowsState(windowsStateStoreData); if (!Array.isArray(this.windowsState.openedWindows)) { diff --git a/src/vs/code/electron-main/windowsState.ts b/src/vs/code/electron-main/windowsStateStorage.ts similarity index 83% rename from src/vs/code/electron-main/windowsState.ts rename to src/vs/code/electron-main/windowsStateStorage.ts index 22b4ff725b2..16eac66cc20 100644 --- a/src/vs/code/electron-main/windowsState.ts +++ b/src/vs/code/electron-main/windowsStateStorage.ts @@ -4,24 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { URI, UriComponents } from 'vs/base/common/uri'; -import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; -import { IWindowState as IWindowUIState, } from 'vs/platform/windows/electron-main/windows'; +import { IWindowState as IWindowUIState } from 'vs/platform/windows/electron-main/windows'; +import { IWindowState, IWindowsState } from 'vs/code/electron-main/windows'; -export interface IWindowState { - workspace?: IWorkspaceIdentifier; - folderUri?: URI; - backupPath?: string; - remoteAuthority?: string; - uiState: IWindowUIState; -} - -export interface IWindowsState { - lastActiveWindow?: IWindowState; - lastPluginDevelopmentHostWindow?: IWindowState; - openedWindows: IWindowState[]; -} - -export type WindowsStateStoreData = object; +export type WindowsStateStorageData = object; interface ISerializedWindowsState { lastActiveWindow?: ISerializedWindowState; @@ -42,7 +28,7 @@ interface ISerializedWindowState { workspace?: { id: string; configPath: string }; } -export function restoreWindowsState(data: WindowsStateStoreData | undefined): IWindowsState { +export function restoreWindowsState(data: WindowsStateStorageData | undefined): IWindowsState { const result: IWindowsState = { openedWindows: [] }; const windowsState = data as ISerializedWindowsState || { openedWindows: [] }; @@ -81,7 +67,7 @@ function restoreWindowState(windowState: ISerializedWindowState): IWindowState { return result; } -export function getWindowsStateStoreData(windowsState: IWindowsState): WindowsStateStoreData { +export function getWindowsStateStoreData(windowsState: IWindowsState): WindowsStateStorageData { return { lastActiveWindow: windowsState.lastActiveWindow && serializeWindowState(windowsState.lastActiveWindow), lastPluginDevelopmentHostWindow: windowsState.lastPluginDevelopmentHostWindow && serializeWindowState(windowsState.lastPluginDevelopmentHostWindow), diff --git a/src/vs/code/test/electron-main/windowsState.test.ts b/src/vs/code/test/electron-main/windowsStateStorage.test.ts similarity index 81% rename from src/vs/code/test/electron-main/windowsState.test.ts rename to src/vs/code/test/electron-main/windowsStateStorage.test.ts index 4ab638a5b34..798d0f90dcf 100644 --- a/src/vs/code/test/electron-main/windowsState.test.ts +++ b/src/vs/code/test/electron-main/windowsStateStorage.test.ts @@ -5,11 +5,12 @@ import * as assert from 'assert'; import * as os from 'os'; -import { IWindowsState, restoreWindowsState, getWindowsStateStoreData, IWindowState } from 'vs/code/electron-main/windowsState'; +import { restoreWindowsState, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage'; import { IWindowState as IWindowUIState, WindowMode } from 'vs/platform/windows/electron-main/windows'; import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { URI } from 'vs/base/common/uri'; +import { IWindowsState, IWindowState } from 'vs/code/electron-main/windows'; function getUIState(): IWindowUIState { return { @@ -121,9 +122,9 @@ suite('Windows State Storing', () => { "lastActiveWindow": { "workspace": { "id": "a41787288b5e9cc1a61ba2dd84cd0d80", - "configPath": "/home/aeschli/workspaces/code-and-docs.code-workspace" + "configPath": "/home/user/workspaces/code-and-docs.code-workspace" }, - "backupPath": "/home/aeschli/.config/Code - Insiders/Backups/a41787288b5e9cc1a61ba2dd84cd0d80", + "backupPath": "/home/user/.config/Code - Insiders/Backups/a41787288b5e9cc1a61ba2dd84cd0d80", "uiState": { "mode": 0, "x": 0, @@ -138,9 +139,9 @@ suite('Windows State Storing', () => { let expected: IWindowsState = { openedWindows: [], lastActiveWindow: { - backupPath: '/home/aeschli/.config/Code - Insiders/Backups/a41787288b5e9cc1a61ba2dd84cd0d80', + backupPath: '/home/user/.config/Code - Insiders/Backups/a41787288b5e9cc1a61ba2dd84cd0d80', uiState: { mode: WindowMode.Maximized, x: 0, y: 27, width: 2560, height: 1364 }, - workspace: { id: 'a41787288b5e9cc1a61ba2dd84cd0d80', configPath: URI.file('/home/aeschli/workspaces/code-and-docs.code-workspace') } + workspace: { id: 'a41787288b5e9cc1a61ba2dd84cd0d80', configPath: URI.file('/home/user/workspaces/code-and-docs.code-workspace') } } }; @@ -151,9 +152,9 @@ suite('Windows State Storing', () => { "lastPluginDevelopmentHostWindow": { "folderUri": { "$mid": 1, - "fsPath": "/home/aeschli/workspaces/testing/customdata", - "external": "file:///home/aeschli/workspaces/testing/customdata", - "path": "/home/aeschli/workspaces/testing/customdata", + "fsPath": "/home/user/workspaces/testing/customdata", + "external": "file:///home/user/workspaces/testing/customdata", + "path": "/home/user/workspaces/testing/customdata", "scheme": "file" }, "uiState": { @@ -171,7 +172,7 @@ suite('Windows State Storing', () => { openedWindows: [], lastPluginDevelopmentHostWindow: { uiState: { mode: WindowMode.Normal, x: 593, y: 617, width: 1625, height: 595 }, - folderUri: URI.parse('file:///home/aeschli/workspaces/testing/customdata') + folderUri: URI.parse('file:///home/user/workspaces/testing/customdata') } }; assertEqualWindowsState(expected, windowsState, 'v1_31_folder'); @@ -180,7 +181,7 @@ suite('Windows State Storing', () => { "openedWindows": [ ], "lastActiveWindow": { - "backupPath": "C:\\\\Users\\\\martinae\\\\AppData\\\\Roaming\\\\Code\\\\Backups\\\\1549538599815", + "backupPath": "C:\\\\Users\\\\Mike\\\\AppData\\\\Roaming\\\\Code\\\\Backups\\\\1549538599815", "uiState": { "mode": 0, "x": -8, @@ -195,7 +196,7 @@ suite('Windows State Storing', () => { expected = { openedWindows: [], lastActiveWindow: { - backupPath: 'C:\\Users\\martinae\\AppData\\Roaming\\Code\\Backups\\1549538599815', + backupPath: 'C:\\Users\\Mike\\AppData\\Roaming\\Code\\Backups\\1549538599815', uiState: { mode: WindowMode.Maximized, x: -8, y: -8, width: 2576, height: 1344 } } }; @@ -209,9 +210,9 @@ suite('Windows State Storing', () => { "lastActiveWindow": { "workspaceIdentifier": { "id": "53b714b46ef1a2d4346568b4f591028c", - "configURIPath": "file:///home/aeschli/workspaces/testing/custom.code-workspace" + "configURIPath": "file:///home/user/workspaces/testing/custom.code-workspace" }, - "backupPath": "/home/aeschli/.config/code-oss-dev/Backups/53b714b46ef1a2d4346568b4f591028c", + "backupPath": "/home/user/.config/code-oss-dev/Backups/53b714b46ef1a2d4346568b4f591028c", "uiState": { "mode": 0, "x": 0, @@ -226,9 +227,9 @@ suite('Windows State Storing', () => { let expected: IWindowsState = { openedWindows: [], lastActiveWindow: { - backupPath: '/home/aeschli/.config/code-oss-dev/Backups/53b714b46ef1a2d4346568b4f591028c', + backupPath: '/home/user/.config/code-oss-dev/Backups/53b714b46ef1a2d4346568b4f591028c', uiState: { mode: WindowMode.Maximized, x: 0, y: 27, width: 2560, height: 1364 }, - workspace: { id: '53b714b46ef1a2d4346568b4f591028c', configPath: URI.parse('file:///home/aeschli/workspaces/testing/custom.code-workspace') } + workspace: { id: '53b714b46ef1a2d4346568b4f591028c', configPath: URI.parse('file:///home/user/workspaces/testing/custom.code-workspace') } } }; @@ -237,8 +238,8 @@ suite('Windows State Storing', () => { const v1_32_folder = `{ "openedWindows": [], "lastActiveWindow": { - "folder": "file:///home/aeschli/workspaces/testing/folding", - "backupPath": "/home/aeschli/.config/code-oss-dev/Backups/1daac1621c6c06f9e916ac8062e5a1b5", + "folder": "file:///home/user/workspaces/testing/folding", + "backupPath": "/home/user/.config/code-oss-dev/Backups/1daac1621c6c06f9e916ac8062e5a1b5", "uiState": { "mode": 1, "x": 625, @@ -253,9 +254,9 @@ suite('Windows State Storing', () => { expected = { openedWindows: [], lastActiveWindow: { - backupPath: '/home/aeschli/.config/code-oss-dev/Backups/1daac1621c6c06f9e916ac8062e5a1b5', + backupPath: '/home/user/.config/code-oss-dev/Backups/1daac1621c6c06f9e916ac8062e5a1b5', uiState: { mode: WindowMode.Normal, x: 625, y: 263, width: 1718, height: 953 }, - folderUri: URI.parse('file:///home/aeschli/workspaces/testing/folding') + folderUri: URI.parse('file:///home/user/workspaces/testing/folding') } }; assertEqualWindowsState(expected, windowsState, 'v1_32_folder'); @@ -264,7 +265,7 @@ suite('Windows State Storing', () => { "openedWindows": [ ], "lastActiveWindow": { - "backupPath": "/home/aeschli/.config/code-oss-dev/Backups/1549539668998", + "backupPath": "/home/user/.config/code-oss-dev/Backups/1549539668998", "uiState": { "mode": 1, "x": 768, @@ -279,7 +280,7 @@ suite('Windows State Storing', () => { expected = { openedWindows: [], lastActiveWindow: { - backupPath: '/home/aeschli/.config/code-oss-dev/Backups/1549539668998', + backupPath: '/home/user/.config/code-oss-dev/Backups/1549539668998', uiState: { mode: WindowMode.Normal, x: 768, y: 336, width: 1024, height: 768 } } }; diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index 92d9d4f80e0..4e854d1a1e5 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -17,24 +17,11 @@ import { IHistoryMainService, IRecentlyOpened } from 'vs/platform/history/common import { isEqual } from 'vs/base/common/paths'; import { RunOnceScheduler } from 'vs/base/common/async'; import { getComparisonKey, isEqual as areResourcesEqual, dirname, fsPath } from 'vs/base/common/resources'; -import { URI, UriComponents } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; import { Schemas } from 'vs/base/common/network'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { getSimpleWorkspaceLabel } from 'vs/platform/label/common/label'; - -interface ISerializedRecentlyOpened { - workspaces3: Array; // workspace or URI.toString() - files2: string[]; // files as URI.toString() -} - -interface ILegacySerializedRecentlyOpened { - workspaces2: Array; // legacy, configPath as file path - workspaces: Array; // legacy (UriComponents was also supported for a few insider builds) - files: string[]; // files as paths -} - -interface ISerializedWorkspace { id: string; configURIPath: string; } -interface ILegacySerializedWorkspace { id: string; configPath: string; } +import { toStoreData, restoreRecentlyOpened, RecentlyOpenedStorageData } from 'vs/platform/history/electron-main/historyStorage'; export class HistoryMainService implements IHistoryMainService { @@ -213,18 +200,9 @@ export class HistoryMainService implements IHistoryMainService { } getRecentlyOpened(currentWorkspace?: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier, currentFiles?: IPath[]): IRecentlyOpened { - let workspaces: Array; - let files: URI[]; // Get from storage - const storedRecents = this.getRecentlyOpenedFromStorage(); - if (storedRecents) { - workspaces = storedRecents.workspaces || []; - files = storedRecents.files || []; - } else { - workspaces = []; - files = []; - } + let { workspaces, files } = this.getRecentlyOpenedFromStorage(); // Add current workspace to beginning if set if (currentWorkspace) { @@ -255,73 +233,12 @@ export class HistoryMainService implements IHistoryMainService { } private getRecentlyOpenedFromStorage(): IRecentlyOpened { - const storedRecents = this.stateService.getItem(HistoryMainService.recentlyOpenedStorageKey); - const result: IRecentlyOpened = { workspaces: [], files: [] }; - if (storedRecents) { - if (Array.isArray(storedRecents.workspaces3)) { - for (const workspace of storedRecents.workspaces3) { - if (typeof workspace === 'object' && typeof workspace.id === 'string' && typeof workspace.configURIPath === 'string') { - result.workspaces.push({ id: workspace.id, configPath: URI.parse(workspace.configURIPath) }); - } else if (typeof workspace === 'string') { - result.workspaces.push(URI.parse(workspace)); - } - } - } else if (Array.isArray(storedRecents.workspaces2)) { - for (const workspace of storedRecents.workspaces2) { - if (typeof workspace === 'object' && typeof workspace.id === 'string' && typeof workspace.configPath === 'string') { - result.workspaces.push({ id: workspace.id, configPath: URI.file(workspace.configPath) }); - } else if (typeof workspace === 'string') { - result.workspaces.push(URI.parse(workspace)); - } - } - } else if (Array.isArray(storedRecents.workspaces)) { - // TODO@martin legacy support can be removed at some point (6 month?) - // format of 1.25 and before - for (const workspace of storedRecents.workspaces) { - if (typeof workspace === 'string') { - result.workspaces.push(URI.file(workspace)); - } else if (typeof workspace === 'object' && typeof workspace['id'] === 'string' && typeof workspace['configPath'] === 'string') { - result.workspaces.push({ id: workspace['id'], configPath: URI.file(workspace['configPath']) }); - } else if (workspace && typeof workspace['path'] === 'string' && typeof workspace['scheme'] === 'string') { - // added by 1.26-insiders - result.workspaces.push(URI.revive(workspace)); - } - } - } - - if (Array.isArray(storedRecents.files2)) { - for (const file of storedRecents.files2) { - if (typeof file === 'string') { - result.files.push(URI.parse(file)); - } - } - } else if (Array.isArray(storedRecents.files)) { - for (const file of storedRecents.files) { - if (typeof file === 'string') { - result.files.push(URI.file(file)); - } - } - } - } - - return result; + const storedRecents = this.stateService.getItem(HistoryMainService.recentlyOpenedStorageKey); + return restoreRecentlyOpened(storedRecents); } private saveRecentlyOpened(recent: IRecentlyOpened): void { - const serialized: ISerializedRecentlyOpened = { workspaces3: [], files2: [] }; - - for (const workspace of recent.workspaces) { - if (isSingleFolderWorkspaceIdentifier(workspace)) { - serialized.workspaces3.push(workspace.toString()); - } else { - serialized.workspaces3.push({ id: workspace.id, configURIPath: workspace.configPath.toString() }); - } - } - - for (const file of recent.files) { - serialized.files2.push(file.toString()); - } - + const serialized = toStoreData(recent); this.stateService.setItem(HistoryMainService.recentlyOpenedStorageKey, serialized); } @@ -359,7 +276,7 @@ export class HistoryMainService implements IHistoryMainService { for (let item of app.getJumpListSettings().removedItems) { const args = item.args; if (args) { - const match = /^--(folder|workspace)-uri\s+"([^"]+)"$/.exec(args); + const match = /^--(folder|file)-uri\s+"([^"]+)"$/.exec(args); if (match) { toRemove.push(URI.parse(match[2])); } @@ -381,7 +298,7 @@ export class HistoryMainService implements IHistoryMainService { args = `--folder-uri "${workspace.toString()}"`; } else { description = nls.localize('codeWorkspace', "Code Workspace"); - args = `--workspace-uri "${workspace.configPath.toString()}"`; + args = `--file-uri "${workspace.configPath.toString()}"`; } return { type: 'task', diff --git a/src/vs/platform/history/electron-main/historyStorage.ts b/src/vs/platform/history/electron-main/historyStorage.ts new file mode 100644 index 00000000000..b0bf75abd51 --- /dev/null +++ b/src/vs/platform/history/electron-main/historyStorage.ts @@ -0,0 +1,94 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import { UriComponents, URI } from 'vs/base/common/uri'; +import { IRecentlyOpened } from 'vs/platform/history/common/history'; +import { isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; + +interface ISerializedRecentlyOpened { + workspaces3: Array; // workspace or URI.toString() + files2: string[]; // files as URI.toString() +} + +interface ILegacySerializedRecentlyOpened { + workspaces2: Array; // legacy, configPath as file path + workspaces: Array; // legacy (UriComponents was also supported for a few insider builds) + files: string[]; // files as paths +} + +interface ISerializedWorkspace { id: string; configURIPath: string; } +interface ILegacySerializedWorkspace { id: string; configPath: string; } + +export type RecentlyOpenedStorageData = object; + +export function restoreRecentlyOpened(data: RecentlyOpenedStorageData): IRecentlyOpened { + const storedRecents = data as ISerializedRecentlyOpened & ILegacySerializedRecentlyOpened; + const result: IRecentlyOpened = { workspaces: [], files: [] }; + if (storedRecents) { + if (Array.isArray(storedRecents.workspaces3)) { + for (const workspace of storedRecents.workspaces3) { + if (typeof workspace === 'object' && typeof workspace.id === 'string' && typeof workspace.configURIPath === 'string') { + result.workspaces.push({ id: workspace.id, configPath: URI.parse(workspace.configURIPath) }); + } else if (typeof workspace === 'string') { + result.workspaces.push(URI.parse(workspace)); + } + } + } else if (Array.isArray(storedRecents.workspaces2)) { + for (const workspace of storedRecents.workspaces2) { + if (typeof workspace === 'object' && typeof workspace.id === 'string' && typeof workspace.configPath === 'string') { + result.workspaces.push({ id: workspace.id, configPath: URI.file(workspace.configPath) }); + } else if (typeof workspace === 'string') { + result.workspaces.push(URI.parse(workspace)); + } + } + } else if (Array.isArray(storedRecents.workspaces)) { + // TODO@martin legacy support can be removed at some point (6 month?) + // format of 1.25 and before + for (const workspace of storedRecents.workspaces) { + if (typeof workspace === 'string') { + result.workspaces.push(URI.file(workspace)); + } else if (typeof workspace === 'object' && typeof workspace['id'] === 'string' && typeof workspace['configPath'] === 'string') { + result.workspaces.push({ id: workspace['id'], configPath: URI.file(workspace['configPath']) }); + } else if (workspace && typeof workspace['path'] === 'string' && typeof workspace['scheme'] === 'string') { + // added by 1.26-insiders + result.workspaces.push(URI.revive(workspace)); + } + } + } + + if (Array.isArray(storedRecents.files2)) { + for (const file of storedRecents.files2) { + if (typeof file === 'string') { + result.files.push(URI.parse(file)); + } + } + } else if (Array.isArray(storedRecents.files)) { + for (const file of storedRecents.files) { + if (typeof file === 'string') { + result.files.push(URI.file(file)); + } + } + } + } + + return result; +} + +export function toStoreData(recent: IRecentlyOpened): RecentlyOpenedStorageData { + const serialized: ISerializedRecentlyOpened = { workspaces3: [], files2: [] }; + + for (const workspace of recent.workspaces) { + if (isSingleFolderWorkspaceIdentifier(workspace)) { + serialized.workspaces3.push(workspace.toString()); + } else { + serialized.workspaces3.push({ id: workspace.id, configURIPath: workspace.configPath.toString() }); + } + } + + for (const file of recent.files) { + serialized.files2.push(file.toString()); + } + + return serialized; +} diff --git a/src/vs/platform/history/test/electron-main/historyStorage.test.ts b/src/vs/platform/history/test/electron-main/historyStorage.test.ts new file mode 100644 index 00000000000..71a8266d865 --- /dev/null +++ b/src/vs/platform/history/test/electron-main/historyStorage.test.ts @@ -0,0 +1,180 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as assert from 'assert'; +import * as os from 'os'; + +import { getRandomTestPath } from 'vs/workbench/test/workbenchTestServices'; +import { IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { URI } from 'vs/base/common/uri'; +import { IRecentlyOpened } from 'vs/platform/history/common/history'; +import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/electron-main/historyStorage'; + +function toWorkspace(uri: URI): IWorkspaceIdentifier { + return { + id: '1234', + configPath: uri + }; +} +function assertEqualURI(u1: URI, u2: URI, message?: string): void { + assert.equal(u1 && u1.toString(), u2 && u2.toString(), message); +} + +function assertEqualWorkspace(w1: IWorkspaceIdentifier, w2: IWorkspaceIdentifier, message?: string): void { + if (!w1 || !w2) { + assert.equal(w1, w2, message); + return; + } + assert.equal(w1.id, w2.id, message); + assertEqualURI(w1.configPath, w2.configPath, message); +} + +function assertEqualRecentlyOpened(expected: IRecentlyOpened, actual: IRecentlyOpened, message?: string) { + assert.equal(expected.files.length, actual.files.length, message); + for (let i = 0; i < expected.files.length; i++) { + assertEqualURI(expected.files[i], actual.files[i], message); + } + assert.equal(expected.workspaces.length, actual.workspaces.length, message); + for (let i = 0; i < expected.workspaces.length; i++) { + if (expected.workspaces[i] instanceof URI) { + assertEqualURI(expected.workspaces[i], actual.workspaces[i], message); + } else { + assertEqualWorkspace(expected.workspaces[i], actual.workspaces[i], message); + } + } +} + +function assertRestoring(state: IRecentlyOpened, message?: string) { + const stored = toStoreData(state); + const restored = restoreRecentlyOpened(stored); + assertEqualRecentlyOpened(state, restored, message); +} + +const testWSPath = URI.file(getRandomTestPath(os.tmpdir(), 'windowStateTest', 'test.code-workspace')); +const testFileURI = URI.file(getRandomTestPath(os.tmpdir(), 'windowStateTest', 'testFile.txt')); +const testFolderURI = URI.file(getRandomTestPath(os.tmpdir(), 'windowStateTest', 'testFolder')); + +const testRemoteFolderURI = URI.parse('foo://bar/c/e'); +const testRemoteFileURI = URI.parse('foo://bar/c/d.txt'); +const testRemoteWSURI = URI.parse('foo://bar/c/test.code-workspace'); + +suite('History Storage', () => { + test('storing and restoring', () => { + let ro: IRecentlyOpened; + ro = { + files: [], + workspaces: [] + }; + assertRestoring(ro, 'empty'); + ro = { + files: [testFileURI], + workspaces: [] + }; + assertRestoring(ro, 'file'); + ro = { + files: [], + workspaces: [testFolderURI] + }; + assertRestoring(ro, 'folder'); + ro = { + files: [], + workspaces: [toWorkspace(testWSPath), testFolderURI] + }; + assertRestoring(ro, 'workspaces and folders'); + + ro = { + files: [testRemoteFileURI], + workspaces: [toWorkspace(testRemoteWSURI), testRemoteFolderURI] + }; + assertRestoring(ro, 'remote workspaces and folders'); + }); + + test('open 1_25', () => { + const v1_25_win = `{ + "workspaces": [ + { + "id": "2fa677dbdf5f771e775af84dea9feaea", + "configPath": "C:\\\\workspaces\\\\testing\\\\test.code-workspace" + }, + "C:\\\\workspaces\\\\testing\\\\test-ext", + { + "id": "d87a0241f8abc86b95c4e5481ebcbf56", + "configPath": "C:\\\\workspaces\\\\test.code-workspace" + } + ], + "files": [ + "C:\\\\workspaces\\\\test.code-workspace", + "C:\\\\workspaces\\\\testing\\\\test-ext\\\\.gitignore" + ] + }`; + + let actual = restoreRecentlyOpened(JSON.parse(v1_25_win)); + let expected: IRecentlyOpened = { + files: [URI.file('C:\\workspaces\\test.code-workspace'), URI.file('C:\\workspaces\\testing\\test-ext\\.gitignore')], + workspaces: [ + { id: '2fa677dbdf5f771e775af84dea9feaea', configPath: URI.file('C:\\workspaces\\testing\\test.code-workspace') }, + URI.file('C:\\workspaces\\testing\\test-ext'), + { id: 'd87a0241f8abc86b95c4e5481ebcbf56', configPath: URI.file('C:\\workspaces\\test.code-workspace') } + ] + }; + + assertEqualRecentlyOpened(expected, actual, 'v1_31_win'); + }); + + test('open 1_31', () => { + const v1_31_win = `{ + "workspaces2": [ + "file:///c%3A/workspaces/testing/test-ext", + "file:///c%3A/WINDOWS/system32", + { + "id": "d87a0241f8abc86b95c4e5481ebcbf56", + "configPath": "c:\\\\workspaces\\\\test.code-workspace" + } + ], + "files2": [ + "file:///c%3A/workspaces/vscode/.yarnrc" + ] + }`; + + let actual = restoreRecentlyOpened(JSON.parse(v1_31_win)); + let expected: IRecentlyOpened = { + files: [URI.parse('file:///c%3A/workspaces/vscode/.yarnrc')], + workspaces: [ + URI.parse('file:///c%3A/workspaces/testing/test-ext'), + URI.parse('file:///c%3A/WINDOWS/system32'), + { id: 'd87a0241f8abc86b95c4e5481ebcbf56', configPath: URI.file('c:\\workspaces\\test.code-workspace') } + ] + }; + + assertEqualRecentlyOpened(expected, actual, 'v1_31_win'); + }); + + test('open 1_32', () => { + const v1_32 = `{ + "workspaces3": [ + { + "id": "53b714b46ef1a2d4346568b4f591028c", + "configURIPath": "file:///home/user/workspaces/testing/custom.code-workspace" + }, + "file:///home/user/workspaces/testing/folding" + ], + "files2": [ + "file:///home/user/.config/code-oss-dev/storage.json" + ] + }`; + + let windowsState = restoreRecentlyOpened(JSON.parse(v1_32)); + let expected: IRecentlyOpened = { + files: [URI.parse('file:///home/user/.config/code-oss-dev/storage.json')], + workspaces: [ + { id: '53b714b46ef1a2d4346568b4f591028c', configPath: URI.parse('file:///home/user/workspaces/testing/custom.code-workspace') }, + URI.parse('file:///home/user/workspaces/testing/folding') + ] + }; + + assertEqualRecentlyOpened(expected, windowsState, 'v1_32'); + + }); + +}); \ No newline at end of file