editors - add tests for capability change events

This commit is contained in:
Benjamin Pasero 2021-05-28 11:05:47 +02:00
parent 004f6609f8
commit 3a857fc436
No known key found for this signature in database
GPG key ID: E6380CC4C8219E65
14 changed files with 242 additions and 79 deletions

View file

@ -9,9 +9,9 @@ import { toResource } from 'vs/base/test/common/utils';
import { FileEditorInput } from 'vs/workbench/contrib/files/browser/editors/fileEditorInput';
import { workbenchInstantiationService, TestServiceAccessor, TestEditorService, getLastResolvedFileStat } from 'vs/workbench/test/browser/workbenchTestServices';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IEditorInputFactoryRegistry, Verbosity, EditorExtensions } from 'vs/workbench/common/editor';
import { IEditorInputFactoryRegistry, Verbosity, EditorExtensions, EditorInputCapabilities } from 'vs/workbench/common/editor';
import { EncodingMode, TextFileOperationError, TextFileOperationResult } from 'vs/workbench/services/textfile/common/textfiles';
import { FileOperationResult, FileOperationError } from 'vs/platform/files/common/files';
import { FileOperationResult, FileOperationError, NotModifiedSinceFileOperationError } from 'vs/platform/files/common/files';
import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel';
import { timeout } from 'vs/base/common/async';
import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
@ -371,4 +371,45 @@ suite('Files - FileEditorInput', () => {
fileInput.dispose();
});
test('reports readonly changes', async function () {
const input = createFileInput(toResource.call(this, '/foo/bar/updatefile.js'));
let listenerCount = 0;
const listener = input.onDidChangeCapabilities(() => {
listenerCount++;
});
const model = await accessor.textFileService.files.resolve(input.resource);
assert.strictEqual(model.isReadonly(), false);
assert.strictEqual(input.hasCapability(EditorInputCapabilities.Readonly), false);
const stat = await accessor.fileService.resolve(input.resource, { resolveMetadata: true });
try {
accessor.fileService.readShouldThrowError = new NotModifiedSinceFileOperationError('file not modified since', { ...stat, readonly: true });
await input.resolve();
} finally {
accessor.fileService.readShouldThrowError = undefined;
}
assert.strictEqual(model.isReadonly(), true);
assert.strictEqual(input.hasCapability(EditorInputCapabilities.Readonly), true);
assert.strictEqual(listenerCount, 1);
try {
accessor.fileService.readShouldThrowError = new NotModifiedSinceFileOperationError('file not modified since', { ...stat, readonly: false });
await input.resolve();
} finally {
accessor.fileService.readShouldThrowError = undefined;
}
assert.strictEqual(model.isReadonly(), false);
assert.strictEqual(input.hasCapability(EditorInputCapabilities.Readonly), false);
assert.strictEqual(listenerCount, 2);
input.dispose();
listener.dispose();
});
});

View file

@ -6,7 +6,7 @@
import * as assert from 'assert';
import { workbenchInstantiationService, registerTestEditor, TestFileEditorInput, TestEditorPart, ITestInstantiationService, TestServiceAccessor, createEditorPart } from 'vs/workbench/test/browser/workbenchTestServices';
import { GroupDirection, GroupsOrder, MergeGroupMode, GroupOrientation, GroupChangeKind, GroupLocation } from 'vs/workbench/services/editor/common/editorGroupsService';
import { CloseDirection, IEditorPartOptions, EditorsOrder } from 'vs/workbench/common/editor';
import { CloseDirection, IEditorPartOptions, EditorsOrder, EditorInputCapabilities } from 'vs/workbench/common/editor';
import { URI } from 'vs/base/common/uri';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { DisposableStore } from 'vs/base/common/lifecycle';
@ -378,6 +378,7 @@ suite('EditorGroupsService', () => {
let editorCloseCounter = 0;
let editorPinCounter = 0;
let editorStickyCounter = 0;
let editorCapabilitiesCounter = 0;
const editorGroupChangeListener = group.onDidGroupChange(e => {
if (e.kind === GroupChangeKind.EDITOR_OPEN) {
assert.ok(e.editor);
@ -391,6 +392,9 @@ suite('EditorGroupsService', () => {
} else if (e.kind === GroupChangeKind.EDITOR_PIN) {
assert.ok(e.editor);
editorPinCounter++;
} else if (e.kind === GroupChangeKind.EDITOR_CAPABILITIES) {
assert.ok(e.editor);
editorCapabilitiesCounter++;
} else if (e.kind === GroupChangeKind.EDITOR_STICKY) {
assert.ok(e.editor);
editorStickyCounter++;
@ -419,6 +423,7 @@ suite('EditorGroupsService', () => {
assert.strictEqual(group.contains(inputInactive), true);
assert.strictEqual(group.isEmpty, false);
assert.strictEqual(group.count, 2);
assert.strictEqual(editorCapabilitiesCounter, 0);
assert.strictEqual(editorDidOpenCounter, 2);
assert.strictEqual(activeEditorChangeCounter, 1);
assert.strictEqual(group.getEditorByIndex(0), input);
@ -426,6 +431,12 @@ suite('EditorGroupsService', () => {
assert.strictEqual(group.getIndexOfEditor(input), 0);
assert.strictEqual(group.getIndexOfEditor(inputInactive), 1);
input.capabilities = EditorInputCapabilities.RequiresTrust;
assert.strictEqual(editorCapabilitiesCounter, 1);
inputInactive.capabilities = EditorInputCapabilities.Singleton;
assert.strictEqual(editorCapabilitiesCounter, 2);
assert.strictEqual(group.previewEditor, inputInactive);
assert.strictEqual(group.isPinned(inputInactive), false);
group.pinEditor(inputInactive);

View file

@ -14,6 +14,7 @@ import { FileChangesEvent, FileChangeType, FileOperationError, FileOperationResu
import { timeout } from 'vs/base/common/async';
import { TestStoredFileWorkingCopyModel, TestStoredFileWorkingCopyModelFactory } from 'vs/workbench/services/workingCopy/test/browser/storedFileWorkingCopy.test';
import { CancellationToken } from 'vs/base/common/cancellation';
import { InMemoryFileSystemProvider } from 'vs/platform/files/common/inMemoryFilesystemProvider';
suite('StoredFileWorkingCopyManager', () => {
@ -385,6 +386,28 @@ suite('StoredFileWorkingCopyManager', () => {
assert.strictEqual(didResolve, true);
});
test('file system provider change triggers working copy resolve', async () => {
const resource = URI.file('/path/index.txt');
const workingCopy = await manager.resolve(resource);
let didResolve = false;
const onDidResolve = new Promise<void>(resolve => {
manager.onDidResolve(() => {
if (workingCopy.resource.toString() === resource.toString()) {
didResolve = true;
resolve();
}
});
});
accessor.fileService.fireFileSystemProviderCapabilitiesChangeEvent({ provider: new InMemoryFileSystemProvider(), scheme: resource.scheme });
await onDidResolve;
assert.strictEqual(didResolve, true);
});
test('working copy file event handling: create', async () => {
const resource = URI.file('/path/source.txt');

View file

@ -0,0 +1,75 @@
/*---------------------------------------------------------------------------------------------
* 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 { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
suite('Diff editor input', () => {
class MyEditorInput extends EditorInput {
readonly resource = undefined;
override get typeId(): string { return 'myEditorInput'; }
override resolve(): any { return null; }
}
test('basics', () => {
const instantiationService = workbenchInstantiationService();
let counter = 0;
let input = new MyEditorInput();
input.onWillDispose(() => {
assert(true);
counter++;
});
let otherInput = new MyEditorInput();
otherInput.onWillDispose(() => {
assert(true);
counter++;
});
let diffInput = instantiationService.createInstance(DiffEditorInput, 'name', 'description', input, otherInput, undefined);
assert.strictEqual(diffInput.originalInput, input);
assert.strictEqual(diffInput.modifiedInput, otherInput);
assert(diffInput.matches(diffInput));
assert(!diffInput.matches(otherInput));
assert(!diffInput.matches(null));
diffInput.dispose();
assert.strictEqual(counter, 0);
});
test('disposes when input inside disposes', function () {
const instantiationService = workbenchInstantiationService();
let counter = 0;
let input = new MyEditorInput();
let otherInput = new MyEditorInput();
let diffInput = instantiationService.createInstance(DiffEditorInput, 'name', 'description', input, otherInput, undefined);
diffInput.onWillDispose(() => {
counter++;
assert(true);
});
input.dispose();
input = new MyEditorInput();
otherInput = new MyEditorInput();
let diffInput2 = instantiationService.createInstance(DiffEditorInput, 'name', 'description', input, otherInput, undefined);
diffInput2.onWillDispose(() => {
counter++;
assert(true);
});
otherInput.dispose();
assert.strictEqual(counter, 2);
});
});

View file

@ -20,7 +20,7 @@ import { EditorService } from 'vs/workbench/services/editor/browser/editorServic
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
suite('Workbench editor', () => {
suite('Workbench editor utils', () => {
class TestEditorInputWithPreferredResource extends TestEditorInput implements IEditorInputWithPreferredResource {

View file

@ -12,7 +12,7 @@ import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench
import { ITextModel } from 'vs/editor/common/model';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
suite('Workbench editor model', () => {
suite('TextDiffEditorModel', () => {
let instantiationService: IInstantiationService;
let accessor: TestServiceAccessor;
@ -22,7 +22,7 @@ suite('Workbench editor model', () => {
accessor = instantiationService.createInstance(TestServiceAccessor);
});
test('TextDiffEditorModel', async () => {
test('basics', async () => {
const dispose = accessor.textModelResolverService.registerTextModelContentProvider('test', {
provideTextContent: async function (resource: URI): Promise<ITextModel | null> {
if (resource.scheme === 'test') {

View file

@ -24,7 +24,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle';
import { TestContextService, TestStorageService } from 'vs/workbench/test/common/workbenchTestServices';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
suite('Workbench editor group model', () => {
suite('EditorGroupModel', () => {
function inst(): IInstantiationService {
let inst = new TestInstantiationService();

View file

@ -5,10 +5,8 @@
import * as assert from 'assert';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { workbenchInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
suite('Workbench editor input', () => {
suite('EditorInput', () => {
class MyEditorInput extends EditorInput {
readonly resource = undefined;
@ -17,7 +15,7 @@ suite('Workbench editor input', () => {
override resolve(): any { return null; }
}
test('EditorInput', () => {
test('basics', () => {
let counter = 0;
let input = new MyEditorInput();
let otherInput = new MyEditorInput();
@ -35,60 +33,4 @@ suite('Workbench editor input', () => {
input.dispose();
assert.strictEqual(counter, 1);
});
test('DiffEditorInput', () => {
const instantiationService = workbenchInstantiationService();
let counter = 0;
let input = new MyEditorInput();
input.onWillDispose(() => {
assert(true);
counter++;
});
let otherInput = new MyEditorInput();
otherInput.onWillDispose(() => {
assert(true);
counter++;
});
let diffInput = instantiationService.createInstance(DiffEditorInput, 'name', 'description', input, otherInput, undefined);
assert.strictEqual(diffInput.originalInput, input);
assert.strictEqual(diffInput.modifiedInput, otherInput);
assert(diffInput.matches(diffInput));
assert(!diffInput.matches(otherInput));
assert(!diffInput.matches(null));
diffInput.dispose();
assert.strictEqual(counter, 0);
});
test('DiffEditorInput disposes when input inside disposes', function () {
const instantiationService = workbenchInstantiationService();
let counter = 0;
let input = new MyEditorInput();
let otherInput = new MyEditorInput();
let diffInput = instantiationService.createInstance(DiffEditorInput, 'name', 'description', input, otherInput, undefined);
diffInput.onWillDispose(() => {
counter++;
assert(true);
});
input.dispose();
input = new MyEditorInput();
otherInput = new MyEditorInput();
let diffInput2 = instantiationService.createInstance(DiffEditorInput, 'name', 'description', input, otherInput, undefined);
diffInput2.onWillDispose(() => {
counter++;
assert(true);
});
otherInput.dispose();
assert.strictEqual(counter, 2);
});
});

View file

@ -27,7 +27,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService';
import { EditorModel } from 'vs/workbench/common/editor/editorModel';
suite('Workbench editor model', () => {
suite('EditorModel', () => {
class MyEditorModel extends EditorModel { }
class MyTextEditorModel extends BaseTextEditorModel {
@ -62,7 +62,7 @@ suite('Workbench editor model', () => {
modeService = instantiationService.stub(IModeService, ModeServiceImpl);
});
test('EditorModel', async () => {
test('basics', async () => {
let counter = 0;
const model = new MyEditorModel();

View file

@ -103,7 +103,7 @@ class OtherTestInput extends EditorInput {
}
class TestResourceEditorInput extends TextResourceEditorInput { }
suite('Workbench EditorPane', () => {
suite('EditorPane', () => {
test('EditorPane API', async () => {
const editor = new TestEditor(NullTelemetryService);

View file

@ -12,7 +12,7 @@ import { ILabelService } from 'vs/platform/label/common/label';
import { IFileService } from 'vs/platform/files/common/files';
import { EditorInputCapabilities, Verbosity } from 'vs/workbench/common/editor';
suite('Resource editors', () => {
suite('ResourceEditorInput', () => {
let instantiationService: IInstantiationService;

View file

@ -0,0 +1,61 @@
/*---------------------------------------------------------------------------------------------
* 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 { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
suite('SideBySideEditorInput', () => {
class MyEditorInput extends EditorInput {
readonly resource = undefined;
override get typeId(): string { return 'myEditorInput'; }
override resolve(): any { return null; }
fireCapabilitiesChangeEvent(): void {
this._onDidChangeCapabilities.fire();
}
fireDirtyChangeEvent(): void {
this._onDidChangeDirty.fire();
}
fireLabelChangeEvent(): void {
this._onDidChangeLabel.fire();
}
}
test('events dispatching', () => {
let input = new MyEditorInput();
let otherInput = new MyEditorInput();
const sideBySideInut = new SideBySideEditorInput('name', 'description', otherInput, input);
let capabilitiesChangeCounter = 0;
sideBySideInut.onDidChangeCapabilities(() => capabilitiesChangeCounter++);
let dirtyChangeCounter = 0;
sideBySideInut.onDidChangeDirty(() => dirtyChangeCounter++);
let labelChangeCounter = 0;
sideBySideInut.onDidChangeLabel(() => labelChangeCounter++);
input.fireCapabilitiesChangeEvent();
assert.strictEqual(capabilitiesChangeCounter, 1);
otherInput.fireCapabilitiesChangeEvent();
assert.strictEqual(capabilitiesChangeCounter, 2);
input.fireDirtyChangeEvent();
otherInput.fireDirtyChangeEvent();
assert.strictEqual(dirtyChangeCounter, 1);
input.fireLabelChangeEvent();
otherInput.fireLabelChangeEvent();
assert.strictEqual(labelChangeCounter, 1);
});
});

View file

@ -12,7 +12,7 @@ import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench
import { snapshotToString } from 'vs/workbench/services/textfile/common/textfiles';
import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
suite('Resource text editors', () => {
suite('TextResourceEditorInput', () => {
let instantiationService: IInstantiationService;
let accessor: TestServiceAccessor;

View file

@ -23,7 +23,7 @@ import { IUntitledTextEditorService, UntitledTextEditorService } from 'vs/workbe
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { ILifecycleService, BeforeShutdownEvent, ShutdownReason, StartupKind, LifecyclePhase, WillShutdownEvent } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { FileOperationEvent, IFileService, IFileStat, IResolveFileResult, FileChangesEvent, IResolveFileOptions, ICreateFileOptions, IFileSystemProvider, FileSystemProviderCapabilities, IFileChange, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, IFileStatWithMetadata, IResolveMetadataFileOptions, IWriteFileOptions, IReadFileOptions, IFileContent, IFileStreamContent, FileOperationError, IFileSystemProviderWithFileReadStreamCapability, FileReadStreamOptions, IReadFileStreamOptions } from 'vs/platform/files/common/files';
import { FileOperationEvent, IFileService, IFileStat, IResolveFileResult, FileChangesEvent, IResolveFileOptions, ICreateFileOptions, IFileSystemProvider, FileSystemProviderCapabilities, IFileChange, IWatchOptions, IStat, FileType, FileDeleteOptions, FileOverwriteOptions, FileWriteOptions, FileOpenOptions, IFileStatWithMetadata, IResolveMetadataFileOptions, IWriteFileOptions, IReadFileOptions, IFileContent, IFileStreamContent, FileOperationError, IFileSystemProviderWithFileReadStreamCapability, FileReadStreamOptions, IReadFileStreamOptions, IFileSystemProviderCapabilitiesChangeEvent } from 'vs/platform/files/common/files';
import { IModelService } from 'vs/editor/common/services/modelService';
import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl';
import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl';
@ -833,10 +833,18 @@ export class TestFileService implements IFileService {
declare readonly _serviceBrand: undefined;
private readonly _onDidFilesChange = new Emitter<FileChangesEvent>();
get onDidFilesChange(): Event<FileChangesEvent> { return this._onDidFilesChange.event; }
fireFileChanges(event: FileChangesEvent): void { this._onDidFilesChange.fire(event); }
private readonly _onDidRunOperation = new Emitter<FileOperationEvent>();
get onDidRunOperation(): Event<FileOperationEvent> { return this._onDidRunOperation.event; }
fireAfterOperation(event: FileOperationEvent): void { this._onDidRunOperation.fire(event); }
private readonly _onDidChangeFileSystemProviderCapabilities = new Emitter<IFileSystemProviderCapabilitiesChangeEvent>();
get onDidChangeFileSystemProviderCapabilities(): Event<IFileSystemProviderCapabilitiesChangeEvent> { return this._onDidChangeFileSystemProviderCapabilities.event; }
fireFileSystemProviderCapabilitiesChangeEvent(event: IFileSystemProviderCapabilitiesChangeEvent): void { this._onDidChangeFileSystemProviderCapabilities.fire(event); }
readonly onWillActivateFileSystemProvider = Event.None;
readonly onDidChangeFileSystemProviderCapabilities = Event.None;
readonly onError: Event<Error> = Event.None;
private content = 'Hello Html';
@ -847,10 +855,7 @@ export class TestFileService implements IFileService {
setContent(content: string): void { this.content = content; }
getContent(): string { return this.content; }
getLastReadFileUri(): URI { return this.lastReadFileUri; }
get onDidFilesChange(): Event<FileChangesEvent> { return this._onDidFilesChange.event; }
fireFileChanges(event: FileChangesEvent): void { this._onDidFilesChange.fire(event); }
get onDidRunOperation(): Event<FileOperationEvent> { return this._onDidRunOperation.event; }
fireAfterOperation(event: FileOperationEvent): void { this._onDidRunOperation.fire(event); }
resolve(resource: URI, _options: IResolveMetadataFileOptions): Promise<IFileStatWithMetadata>;
resolve(resource: URI, _options?: IResolveFileOptions): Promise<IFileStat>;
resolve(resource: URI, _options?: IResolveFileOptions): Promise<IFileStat> {
@ -1431,7 +1436,12 @@ export class TestFileEditorInput extends EditorInput implements IFileEditorInput
private _capabilities: EditorInputCapabilities = EditorInputCapabilities.None;
override get capabilities(): EditorInputCapabilities { return this._capabilities; }
override set capabilities(capabilities: EditorInputCapabilities) { this._capabilities = capabilities; }
override set capabilities(capabilities: EditorInputCapabilities) {
if (this._capabilities !== capabilities) {
this._capabilities = capabilities;
this._onDidChangeCapabilities.fire();
}
}
override resolve(): Promise<IEditorModel | null> { return !this.fails ? Promise.resolve(null) : Promise.reject(new Error('fails')); }
override matches(other: EditorInput): boolean { return !!(other?.resource && this.resource.toString() === other.resource.toString() && other instanceof TestFileEditorInput && other.typeId === this.typeId); }