提交 16125bcb 编写于 作者: B Benjamin Pasero

debt - add a test for restoring dirty files from hot exit

上级 f4fc810f
......@@ -9,6 +9,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { IConstructorSignature0, IInstantiationService, BrandedService } from 'vs/platform/instantiation/common/instantiation';
import { find } from 'vs/base/common/arrays';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
export interface IEditorDescriptor {
instantiate(instantiationService: IInstantiationService): BaseEditor;
......@@ -30,7 +31,7 @@ export interface IEditorRegistry {
* @param inputDescriptors A set of constructor functions that return an instance of EditorInput for which the
* registered editor should be used for.
*/
registerEditor(descriptor: IEditorDescriptor, inputDescriptors: readonly SyncDescriptor<EditorInput>[]): void;
registerEditor(descriptor: IEditorDescriptor, inputDescriptors: readonly SyncDescriptor<EditorInput>[]): IDisposable;
/**
* Returns the editor descriptor for the given input or `undefined` if none.
......@@ -54,7 +55,7 @@ export interface IEditorRegistry {
*/
export class EditorDescriptor implements IEditorDescriptor {
public static create<Services extends BrandedService[]>(
static create<Services extends BrandedService[]>(
ctor: { new(...services: Services): BaseEditor },
id: string,
name: string
......@@ -87,14 +88,22 @@ export class EditorDescriptor implements IEditorDescriptor {
class EditorRegistry implements IEditorRegistry {
private editors: EditorDescriptor[] = [];
private readonly editors: EditorDescriptor[] = [];
private readonly mapEditorToInputs = new Map<EditorDescriptor, readonly SyncDescriptor<EditorInput>[]>();
registerEditor(descriptor: EditorDescriptor, inputDescriptors: readonly SyncDescriptor<EditorInput>[]): void {
// Register (Support multiple Editors per Input)
registerEditor(descriptor: EditorDescriptor, inputDescriptors: readonly SyncDescriptor<EditorInput>[]): IDisposable {
this.mapEditorToInputs.set(descriptor, inputDescriptors);
this.editors.push(descriptor);
return toDisposable(() => {
this.mapEditorToInputs.delete(descriptor);
const index = this.editors.indexOf(descriptor);
if (index !== -1) {
this.editors.splice(index, 1);
}
});
}
getEditor(input: EditorInput): EditorDescriptor | undefined {
......@@ -156,10 +165,6 @@ class EditorRegistry implements IEditorRegistry {
return this.editors.slice(0);
}
setEditors(editorsToSet: EditorDescriptor[]): void {
this.editors = editorsToSet;
}
getEditorInputs(): SyncDescriptor<EditorInput>[] {
const inputClasses: SyncDescriptor<EditorInput>[] = [];
for (const editor of this.editors) {
......
......@@ -7,7 +7,7 @@ import { Event, Emitter } from 'vs/base/common/event';
import { assign } from 'vs/base/common/objects';
import { isUndefinedOrNull, withNullAsUndefined, assertIsDefined } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { IEditor as ICodeEditor, IEditorViewState, ScrollType, IDiffEditor } from 'vs/editor/common/editorCommon';
import { IEditorModel, IEditorOptions, ITextEditorOptions, IBaseResourceInput, IResourceInput, EditorActivation, EditorOpenContext } from 'vs/platform/editor/common/editor';
import { IInstantiationService, IConstructorSignature0, ServicesAccessor, BrandedService } from 'vs/platform/instantiation/common/instantiation';
......@@ -181,7 +181,7 @@ export interface IEditorInputFactoryRegistry {
* @param editorInputId the identifier of the editor input
* @param factory the editor input factory for serialization/deserialization
*/
registerEditorInputFactory<Services extends BrandedService[]>(editorInputId: string, ctor: { new(...Services: Services): IEditorInputFactory }): void;
registerEditorInputFactory<Services extends BrandedService[]>(editorInputId: string, ctor: { new(...Services: Services): IEditorInputFactory }): IDisposable;
/**
* Returns the editor input factory for the given editor input.
......@@ -1232,6 +1232,7 @@ export interface IEditorMemento<T> {
class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry {
private instantiationService: IInstantiationService | undefined;
private fileInputFactory: IFileInputFactory | undefined;
private readonly editorInputFactoryConstructors: Map<string, IConstructorSignature0<IEditorInputFactory>> = new Map();
private readonly editorInputFactoryInstances: Map<string, IEditorInputFactory> = new Map();
......@@ -1258,12 +1259,18 @@ class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry {
return assertIsDefined(this.fileInputFactory);
}
registerEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0<IEditorInputFactory>): void {
registerEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0<IEditorInputFactory>): IDisposable {
if (!this.instantiationService) {
this.editorInputFactoryConstructors.set(editorInputId, ctor);
} else {
this.createEditorInputFactory(editorInputId, ctor, this.instantiationService);
}
return toDisposable(() => {
this.editorInputFactoryConstructors.delete(editorInputId);
this.editorInputFactoryInstances.delete(editorInputId);
});
}
getEditorInputFactory(editorInputId: string): IEditorInputFactory | undefined {
......
......@@ -31,7 +31,7 @@ export class BackupRestorer implements IWorkbenchContribution {
this.lifecycleService.when(LifecyclePhase.Restored).then(() => this.doRestoreBackups());
}
private async doRestoreBackups(): Promise<URI[] | undefined> {
protected async doRestoreBackups(): Promise<URI[] | undefined> {
// Find all files and untitled with backups
const backups = await this.backupFileService.getWorkspaceFileBackups();
......
/*---------------------------------------------------------------------------------------------
* 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 platform from 'vs/base/common/platform';
import * as os from 'os';
import * as path from 'vs/base/common/path';
import * as pfs from 'vs/base/node/pfs';
import { URI } from 'vs/base/common/uri';
import { createTextBufferFactory } from 'vs/editor/common/model/textModel';
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { DefaultEndOfLine } from 'vs/editor/common/model';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { hashPath } from 'vs/workbench/services/backup/node/backupFileService';
import { BackupModelTracker } from 'vs/workbench/contrib/backup/common/backupModelTracker';
import { TestTextFileService, workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices';
import { IUntitledTextEditorService } from 'vs/workbench/services/untitled/common/untitledTextEditorService';
import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager';
import { BackupRestorer } from 'vs/workbench/contrib/backup/common/backupRestorer';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { EditorService } from 'vs/workbench/services/editor/browser/editorService';
import { Registry } from 'vs/platform/registry/common/platform';
import { EditorInput } from 'vs/workbench/common/editor';
import { FileEditorInput } from 'vs/workbench/contrib/files/common/editors/fileEditorInput';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor';
import { TextFileEditor } from 'vs/workbench/contrib/files/browser/editors/textFileEditor';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { NodeTestBackupFileService } from 'vs/workbench/services/backup/test/electron-browser/backupFileService.test';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { isEqual } from 'vs/base/common/resources';
const userdataDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backuprestorer');
const backupHome = path.join(userdataDir, 'Backups');
const workspacesJsonPath = path.join(backupHome, 'workspaces.json');
const workspaceResource = URI.file(platform.isWindows ? 'c:\\workspace' : '/workspace');
const workspaceBackupPath = path.join(backupHome, hashPath(workspaceResource));
const fooFile = URI.file(platform.isWindows ? 'c:\\Foo' : '/Foo');
const barFile = URI.file(platform.isWindows ? 'c:\\Bar' : '/Bar');
const untitledFile1 = URI.from({ scheme: Schemas.untitled, path: 'Untitled-1' });
const untitledFile2 = URI.from({ scheme: Schemas.untitled, path: 'Untitled-2' });
class TestBackupRestorer extends BackupRestorer {
async doRestoreBackups(): Promise<URI[] | undefined> {
return super.doRestoreBackups();
}
}
class ServiceAccessor {
constructor(
@ITextFileService public textFileService: TestTextFileService,
@IUntitledTextEditorService public untitledTextEditorService: IUntitledTextEditorService
) {
}
}
suite('BackupModelRestorer', () => {
let accessor: ServiceAccessor;
let disposables: IDisposable[] = [];
setup(async () => {
disposables.push(Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
EditorDescriptor.create(
TextFileEditor,
TextFileEditor.ID,
'Text File Editor'
),
[new SyncDescriptor<EditorInput>(FileEditorInput)]
));
// Delete any existing backups completely and then re-create it.
await pfs.rimraf(backupHome, pfs.RimRafMode.MOVE);
await pfs.mkdirp(backupHome);
return pfs.writeFile(workspacesJsonPath, '');
});
teardown(async () => {
dispose(disposables);
disposables = [];
(<TextFileEditorModelManager>accessor.textFileService.models).clear();
(<TextFileEditorModelManager>accessor.textFileService.models).dispose();
accessor.untitledTextEditorService.revertAll();
return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE);
});
test('Restore backups', async () => {
const backupFileService = new NodeTestBackupFileService(workspaceBackupPath);
const instantiationService = workbenchInstantiationService();
instantiationService.stub(IBackupFileService, backupFileService);
const part = instantiationService.createInstance(EditorPart);
part.create(document.createElement('div'));
part.layout(400, 300);
instantiationService.stub(IEditorGroupsService, part);
const editorService: EditorService = instantiationService.createInstance(EditorService);
instantiationService.stub(IEditorService, editorService);
accessor = instantiationService.createInstance(ServiceAccessor);
const tracker = instantiationService.createInstance(BackupModelTracker);
const restorer = instantiationService.createInstance(TestBackupRestorer);
// Backup 2 normal files and 2 untitled file
await backupFileService.backupResource(untitledFile1, createTextBufferFactory('untitled-1').create(DefaultEndOfLine.LF).createSnapshot(false));
await backupFileService.backupResource(untitledFile2, createTextBufferFactory('untitled-2').create(DefaultEndOfLine.LF).createSnapshot(false));
await backupFileService.backupResource(fooFile, createTextBufferFactory('fooFile').create(DefaultEndOfLine.LF).createSnapshot(false));
await backupFileService.backupResource(barFile, createTextBufferFactory('barFile').create(DefaultEndOfLine.LF).createSnapshot(false));
// Verify backups restored and opened as dirty
await restorer.doRestoreBackups();
assert.equal(editorService.editors.length, 4);
assert.ok(editorService.editors.every(editor => editor.isDirty()));
let counter = 0;
for (const editor of editorService.editors) {
const resource = editor.getResource();
if (isEqual(resource, untitledFile1)) {
const model = await accessor.untitledTextEditorService.createOrGet(resource).resolve();
assert.equal(model.textEditorModel.getValue(), 'untitled-1');
counter++;
} else if (isEqual(resource, untitledFile2)) {
const model = await accessor.untitledTextEditorService.createOrGet(resource).resolve();
assert.equal(model.textEditorModel.getValue(), 'untitled-2');
counter++;
} else if (isEqual(resource, fooFile)) {
const model = await accessor.textFileService.models.get(resource!)?.load();
assert.equal(model?.textEditorModel?.getValue(), 'fooFile');
counter++;
} else {
const model = await accessor.textFileService.models.get(resource!)?.load();
assert.equal(model?.textEditorModel?.getValue(), 'barFile');
counter++;
}
}
assert.equal(counter, 4);
part.dispose();
tracker.dispose();
});
});
......@@ -51,14 +51,13 @@ class TestBackupEnvironmentService extends NativeWorkbenchEnvironmentService {
constructor(backupPath: string) {
super({ ...parseArgs(process.argv, OPTIONS), ...{ backupPath, 'user-data-dir': userdataDir } } as IWindowConfiguration, process.execPath, 0);
}
}
class TestBackupFileService extends BackupFileService {
export class NodeTestBackupFileService extends BackupFileService {
readonly fileService: IFileService;
constructor(workspace: URI, backupHome: string, workspacesJsonPath: string) {
constructor(workspaceBackupPath: string) {
const environmentService = new TestBackupEnvironmentService(workspaceBackupPath);
const fileService = new FileService(new NullLogService());
const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService());
......@@ -76,10 +75,10 @@ class TestBackupFileService extends BackupFileService {
}
suite('BackupFileService', () => {
let service: TestBackupFileService;
let service: NodeTestBackupFileService;
setup(async () => {
service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath);
service = new NodeTestBackupFileService(workspaceBackupPath);
// Delete any existing backups completely and then re-create it.
await pfs.rimraf(backupHome, pfs.RimRafMode.MOVE);
......@@ -141,7 +140,7 @@ suite('BackupFileService', () => {
test('should return whether a backup resource exists', async () => {
await pfs.mkdirp(path.dirname(fooBackupPath));
fs.writeFileSync(fooBackupPath, 'foo');
service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath);
service = new NodeTestBackupFileService(workspaceBackupPath);
const resource = await service.loadBackupResource(fooFile);
assert.ok(resource);
assert.equal(path.basename(resource!.fsPath), path.basename(fooBackupPath));
......@@ -528,10 +527,10 @@ suite('BackupFileService', () => {
suite('BackupFilesModel', () => {
let service: TestBackupFileService;
let service: NodeTestBackupFileService;
setup(async () => {
service = new TestBackupFileService(workspaceResource, backupHome, workspacesJsonPath);
service = new NodeTestBackupFileService(workspaceBackupPath);
// Delete any existing backups completely and then re-create it.
await pfs.rimraf(backupHome, pfs.RimRafMode.MOVE);
......
......@@ -19,10 +19,14 @@ import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtil
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
const TEST_EDITOR_ID = 'MyFileEditorForEditorGroupService';
const TEST_EDITOR_INPUT_ID = 'testEditorInputForEditorGroupService';
class TestEditorControl extends BaseEditor {
constructor(@ITelemetryService telemetryService: ITelemetryService) { super('MyFileEditorForEditorGroupService', NullTelemetryService, new TestThemeService(), new TestStorageService()); }
constructor(@ITelemetryService telemetryService: ITelemetryService) { super(TEST_EDITOR_ID, NullTelemetryService, new TestThemeService(), new TestStorageService()); }
async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
super.setInput(input, options, token);
......@@ -30,7 +34,7 @@ class TestEditorControl extends BaseEditor {
await input.resolve();
}
getId(): string { return 'MyFileEditorForEditorGroupService'; }
getId(): string { return TEST_EDITOR_ID; }
layout(): void { }
createEditor(): any { }
}
......@@ -39,7 +43,7 @@ class TestEditorInput extends EditorInput implements IFileEditorInput {
constructor(private resource: URI) { super(); }
getTypeId() { return 'testEditorInputForEditorGroupService'; }
getTypeId() { return TEST_EDITOR_INPUT_ID; }
resolve(): Promise<IEditorModel | null> { return Promise.resolve(null); }
matches(other: TestEditorInput): boolean { return other && this.resource.toString() === other.resource.toString() && other instanceof TestEditorInput; }
setEncoding(encoding: string) { }
......@@ -53,8 +57,9 @@ class TestEditorInput extends EditorInput implements IFileEditorInput {
suite('EditorGroupsService', () => {
function registerTestEditorInput(): void {
let disposables: IDisposable[] = [];
setup(() => {
interface ISerializedTestEditorInput {
resource: string;
}
......@@ -81,11 +86,14 @@ suite('EditorGroupsService', () => {
}
}
(Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories)).registerEditorInputFactory('testEditorInputForGroupsService', TestEditorInputFactory);
(Registry.as<IEditorRegistry>(Extensions.Editors)).registerEditor(EditorDescriptor.create(TestEditorControl, 'MyTestEditorForGroupsService', 'My Test File Editor'), [new SyncDescriptor(TestEditorInput)]);
}
disposables.push((Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories)).registerEditorInputFactory(TEST_EDITOR_INPUT_ID, TestEditorInputFactory));
disposables.push((Registry.as<IEditorRegistry>(Extensions.Editors)).registerEditor(EditorDescriptor.create(TestEditorControl, TEST_EDITOR_ID, 'My Test File Editor'), [new SyncDescriptor(TestEditorInput)]));
});
registerTestEditorInput();
teardown(() => {
dispose(disposables);
disposables = [];
});
function createPart(): EditorPart {
const instantiationService = workbenchInstantiationService();
......
......@@ -25,7 +25,7 @@ import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
import { timeout } from 'vs/base/common/async';
import { toResource } from 'vs/base/test/common/utils';
import { IFileService } from 'vs/platform/files/common/files';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry';
import { UntitledTextEditorModel } from 'vs/workbench/common/editor/untitledTextEditorModel';
import { NullFileSystemProvider } from 'vs/platform/files/test/common/nullFileSystemProvider';
......@@ -33,9 +33,12 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { CancellationToken } from 'vscode';
const TEST_EDITOR_ID = 'MyTestEditorForEditorService';
const TEST_EDITOR_INPUT_ID = 'testEditorInputForEditorService';
class TestEditorControl extends BaseEditor {
constructor(@ITelemetryService telemetryService: ITelemetryService) { super('MyTestEditorForEditorService', NullTelemetryService, new TestThemeService(), new TestStorageService()); }
constructor(@ITelemetryService telemetryService: ITelemetryService) { super(TEST_EDITOR_ID, NullTelemetryService, new TestThemeService(), new TestStorageService()); }
async setInput(input: EditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
super.setInput(input, options, token);
......@@ -43,7 +46,7 @@ class TestEditorControl extends BaseEditor {
await input.resolve();
}
getId(): string { return 'MyTestEditorForEditorService'; }
getId(): string { return TEST_EDITOR_ID; }
layout(): void { }
createEditor(): any { }
}
......@@ -57,7 +60,7 @@ class TestEditorInput extends EditorInput implements IFileEditorInput {
private fails = false;
constructor(public resource: URI) { super(); }
getTypeId() { return 'testEditorInputForEditorService'; }
getTypeId() { return TEST_EDITOR_INPUT_ID; }
resolve(): Promise<IEditorModel | null> { return !this.fails ? Promise.resolve(null) : Promise.reject(new Error('fails')); }
matches(other: TestEditorInput): boolean { return other && other.resource && this.resource.toString() === other.resource.toString() && other instanceof TestEditorInput; }
setEncoding(encoding: string) { }
......@@ -106,11 +109,16 @@ class FileServiceProvider extends Disposable {
suite('EditorService', () => {
function registerTestEditorInput(): void {
Registry.as<IEditorRegistry>(Extensions.Editors).registerEditor(EditorDescriptor.create(TestEditorControl, 'MyTestEditorForEditorService', 'My Test Editor For Next Editor Service'), [new SyncDescriptor(TestEditorInput)]);
}
let disposables: IDisposable[] = [];
registerTestEditorInput();
setup(() => {
disposables.push(Registry.as<IEditorRegistry>(Extensions.Editors).registerEditor(EditorDescriptor.create(TestEditorControl, TEST_EDITOR_ID, 'My Test Editor For Next Editor Service'), [new SyncDescriptor(TestEditorInput)]));
});
teardown(() => {
dispose(disposables);
disposables = [];
});
test('basics', async () => {
const partInstantiator = workbenchInstantiationService();
......
......@@ -6,7 +6,6 @@
import * as assert from 'assert';
import { BaseEditor, EditorMemento } from 'vs/workbench/browser/parts/editor/baseEditor';
import { EditorInput, EditorOptions, IEditorInputFactory, IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import * as Platform from 'vs/platform/registry/common/platform';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
......@@ -19,6 +18,7 @@ import { URI } from 'vs/base/common/uri';
import { IEditorRegistry, Extensions, EditorDescriptor } from 'vs/workbench/browser/editor';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IEditorModel } from 'vs/platform/editor/common/editor';
import { dispose } from 'vs/base/common/lifecycle';
const NullThemeService = new TestThemeService();
......@@ -131,8 +131,8 @@ suite('Workbench base editor', () => {
let oldEditorsCnt = EditorRegistry.getEditors().length;
let oldInputCnt = (<any>EditorRegistry).getEditorInputs().length;
EditorRegistry.registerEditor(d1, [new SyncDescriptor(MyInput)]);
EditorRegistry.registerEditor(d2, [new SyncDescriptor(MyInput), new SyncDescriptor(MyOtherInput)]);
const dispose1 = EditorRegistry.registerEditor(d1, [new SyncDescriptor(MyInput)]);
const dispose2 = EditorRegistry.registerEditor(d2, [new SyncDescriptor(MyInput), new SyncDescriptor(MyOtherInput)]);
assert.equal(EditorRegistry.getEditors().length, oldEditorsCnt + 2);
assert.equal((<any>EditorRegistry).getEditorInputs().length, oldInputCnt + 3);
......@@ -143,51 +143,41 @@ suite('Workbench base editor', () => {
assert.strictEqual(EditorRegistry.getEditorById('id1'), d1);
assert.strictEqual(EditorRegistry.getEditorById('id2'), d2);
assert(!EditorRegistry.getEditorById('id3'));
dispose([dispose1, dispose2]);
});
test('Editor Lookup favors specific class over superclass (match on specific class)', function () {
let d1 = EditorDescriptor.create(MyEditor, 'id1', 'name');
let d2 = EditorDescriptor.create(MyOtherEditor, 'id2', 'name');
let oldEditors = EditorRegistry.getEditors();
(<any>EditorRegistry).setEditors([]);
const disposable = EditorRegistry.registerEditor(d1, [new SyncDescriptor(MyResourceInput)]);
EditorRegistry.registerEditor(d2, [new SyncDescriptor(ResourceEditorInput)]);
EditorRegistry.registerEditor(d1, [new SyncDescriptor(MyResourceInput)]);
let inst = new TestInstantiationService();
let inst = workbenchInstantiationService();
const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake'), undefined))!.instantiate(inst);
assert.strictEqual(editor.getId(), 'myEditor');
const otherEditor = EditorRegistry.getEditor(inst.createInstance(ResourceEditorInput, 'fake', '', URI.file('/fake'), undefined))!.instantiate(inst);
assert.strictEqual(otherEditor.getId(), 'myOtherEditor');
assert.strictEqual(otherEditor.getId(), 'workbench.editors.textResourceEditor');
(<any>EditorRegistry).setEditors(oldEditors);
disposable.dispose();
});
test('Editor Lookup favors specific class over superclass (match on super class)', function () {
let d1 = EditorDescriptor.create(MyOtherEditor, 'id1', 'name');
let oldEditors = EditorRegistry.getEditors();
(<any>EditorRegistry).setEditors([]);
EditorRegistry.registerEditor(d1, [new SyncDescriptor(ResourceEditorInput)]);
let inst = new TestInstantiationService();
let inst = workbenchInstantiationService();
const editor = EditorRegistry.getEditor(inst.createInstance(MyResourceInput, 'fake', '', URI.file('/fake'), undefined))!.instantiate(inst);
assert.strictEqual('myOtherEditor', editor.getId());
(<any>EditorRegistry).setEditors(oldEditors);
assert.strictEqual('workbench.editors.textResourceEditor', editor.getId());
});
test('Editor Input Factory', function () {
workbenchInstantiationService().invokeFunction(accessor => EditorInputRegistry.start(accessor));
EditorInputRegistry.registerEditorInputFactory('myInputId', MyInputFactory);
const disposable = EditorInputRegistry.registerEditorInputFactory('myInputId', MyInputFactory);
let factory = EditorInputRegistry.getEditorInputFactory('myInputId');
assert(factory);
disposable.dispose();
});
test('EditorMemento - basics', function () {
......
......@@ -20,6 +20,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
function inst(): IInstantiationService {
let inst = new TestInstantiationService();
......@@ -160,13 +161,16 @@ class TestEditorInputFactory implements IEditorInputFactory {
suite('Workbench editor groups', () => {
function registerEditorInputFactory() {
Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).registerEditorInputFactory('testEditorInputForGroups', TestEditorInputFactory);
}
let disposables: IDisposable[] = [];
registerEditorInputFactory();
setup(() => {
disposables.push(Registry.as<IEditorInputFactoryRegistry>(EditorExtensions.EditorInputFactories).registerEditorInputFactory('testEditorInputForGroups', TestEditorInputFactory));
});
teardown(() => {
dispose(disposables);
disposables = [];
index = 1;
});
......
......@@ -33,7 +33,7 @@ import { ITextFileStreamContent, ITextFileService, IResourceEncoding, IReadTextF
import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IInstantiationService, ServicesAccessor, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { MenuBarVisibility, IWindowConfiguration, IWindowOpenable, IOpenWindowOptions, IOpenEmptyWindowOptions, IOpenedWindow } from 'vs/platform/windows/common/windows';
import { TestWorkspace } from 'vs/platform/workspace/test/common/testWorkspace';
......@@ -94,6 +94,7 @@ import { IDialogMainService } from 'vs/platform/dialogs/electron-main/dialogs';
import { find } from 'vs/base/common/arrays';
import { WorkingCopyService, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { IFilesConfigurationService, FilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService';
import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility';
export function createFileInput(instantiationService: IInstantiationService, resource: URI): FileEditorInput {
return instantiationService.createInstance(FileEditorInput, resource, undefined, undefined);
......@@ -276,7 +277,11 @@ export class TestTextFileService extends NativeTextFileService {
}
}
export function workbenchInstantiationService(): IInstantiationService {
export interface ITestInstantiationService extends IInstantiationService {
stub<T>(service: ServiceIdentifier<T>, ctor: any): T;
}
export function workbenchInstantiationService(): ITestInstantiationService {
let instantiationService = new TestInstantiationService(new ServiceCollection([ILifecycleService, new TestLifecycleService()]));
instantiationService.stub(IEnvironmentService, TestEnvironmentService);
const contextKeyService = <IContextKeyService>instantiationService.createInstance(MockContextKeyService);
......@@ -291,6 +296,7 @@ export function workbenchInstantiationService(): IInstantiationService {
instantiationService.stub(IStorageService, new TestStorageService());
instantiationService.stub(IWorkbenchLayoutService, new TestLayoutService());
instantiationService.stub(IDialogService, new TestDialogService());
instantiationService.stub(IAccessibilityService, new TestAccessibilityService());
instantiationService.stub(IFileDialogService, new TestFileDialogService());
instantiationService.stub(IElectronService, new TestElectronService());
instantiationService.stub(IModeService, instantiationService.createInstance(ModeServiceImpl));
......@@ -322,6 +328,17 @@ export function workbenchInstantiationService(): IInstantiationService {
return instantiationService;
}
export class TestAccessibilityService implements IAccessibilityService {
_serviceBrand: undefined;
onDidChangeAccessibilitySupport = Event.None;
alwaysUnderlineAccessKeys(): Promise<boolean> { return Promise.resolve(false); }
getAccessibilitySupport(): AccessibilitySupport { return AccessibilitySupport.Unknown; }
setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void { }
}
export class TestDecorationsService implements IDecorationsService {
_serviceBrand: undefined;
onDidChangeDecorations: Event<IResourceDecorationChangeEvent> = Event.None;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册