提交 86b7936c 编写于 作者: B Benjamin Pasero

tests - add more tests for uncovered areas

上级 a808018f
......@@ -6,6 +6,7 @@
import * as assert from 'assert';
import * as extpath from 'vs/base/common/extpath';
import * as platform from 'vs/base/common/platform';
import { CharCode } from 'vs/base/common/charCode';
suite('Paths', () => {
......@@ -114,4 +115,19 @@ suite('Paths', () => {
assert.ok(!extpath.isRootOrDriveLetter('/path'));
}
});
test('isWindowsDriveLetter', () => {
assert.ok(!extpath.isWindowsDriveLetter(0));
assert.ok(!extpath.isWindowsDriveLetter(-1));
assert.ok(extpath.isWindowsDriveLetter(CharCode.A));
assert.ok(extpath.isWindowsDriveLetter(CharCode.z));
});
test('indexOfPath', () => {
assert.equal(extpath.indexOfPath('/foo', '/bar', true), -1);
assert.equal(extpath.indexOfPath('/foo', '/FOO', false), -1);
assert.equal(extpath.indexOfPath('/foo', '/FOO', true), 0);
assert.equal(extpath.indexOfPath('/some/long/path', '/some/long', false), 0);
assert.equal(extpath.indexOfPath('/some/long/path', '/PATH', true), 10);
});
});
......@@ -163,7 +163,7 @@ class MinimapOptions {
&& this.fontScale === other.fontScale
&& this.minimapLineHeight === other.minimapLineHeight
&& this.minimapCharWidth === other.minimapCharWidth
&& this.backgroundColor.equals(other.backgroundColor)
&& this.backgroundColor && this.backgroundColor.equals(other.backgroundColor)
);
}
}
......
......@@ -7,7 +7,7 @@ import * as assert from 'assert';
import { tmpdir } from 'os';
import { FileService } from 'vs/platform/files/common/fileService';
import { Schemas } from 'vs/base/common/network';
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider';
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { generateUuid } from 'vs/base/common/uuid';
import { join, basename, dirname, posix } from 'vs/base/common/path';
......@@ -67,6 +67,7 @@ export class TestDiskFileSystemProvider extends DiskFileSystemProvider {
FileSystemProviderCapabilities.FileReadWrite |
FileSystemProviderCapabilities.FileOpenReadWriteClose |
FileSystemProviderCapabilities.FileReadStream |
FileSystemProviderCapabilities.Trash |
FileSystemProviderCapabilities.FileFolderCopy;
if (isLinux) {
......@@ -459,13 +460,21 @@ suite('Disk File Service', function () {
});
test('deleteFile', async () => {
return testDeleteFile(false);
});
test('deleteFile (useTrash)', async () => {
return testDeleteFile(true);
});
async function testDeleteFile(useTrash: boolean): Promise<void> {
let event: FileOperationEvent;
disposables.add(service.onDidRunOperation(e => event = e));
const resource = URI.file(join(testDir, 'deep', 'conway.js'));
const source = await service.resolve(resource);
await service.del(source.resource);
await service.del(source.resource, { useTrash });
assert.equal(existsSync(source.resource.fsPath), false);
......@@ -475,14 +484,14 @@ suite('Disk File Service', function () {
let error: Error | undefined = undefined;
try {
await service.del(source.resource);
await service.del(source.resource, { useTrash });
} catch (e) {
error = e;
}
assert.ok(error);
assert.equal((<FileOperationError>error).fileOperationResult, FileOperationResult.FILE_NOT_FOUND);
});
}
test('deleteFile - symbolic link (exists)', async () => {
if (isWindows) {
......@@ -531,19 +540,27 @@ suite('Disk File Service', function () {
});
test('deleteFolder (recursive)', async () => {
return testDeleteFolderRecursive(false);
});
test('deleteFolder (recursive, useTrash)', async () => {
return testDeleteFolderRecursive(true);
});
async function testDeleteFolderRecursive(useTrash: boolean): Promise<void> {
let event: FileOperationEvent;
disposables.add(service.onDidRunOperation(e => event = e));
const resource = URI.file(join(testDir, 'deep'));
const source = await service.resolve(resource);
await service.del(source.resource, { recursive: true });
await service.del(source.resource, { recursive: true, useTrash });
assert.equal(existsSync(source.resource.fsPath), false);
assert.ok(event!);
assert.equal(event!.resource.fsPath, resource.fsPath);
assert.equal(event!.operation, FileOperation.DELETE);
});
}
test('deleteFolder (non recursive)', async () => {
const resource = URI.file(join(testDir, 'deep'));
......
......@@ -38,12 +38,14 @@ export interface IWorkbenchContributionsRegistry {
}
class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry {
private instantiationService: IInstantiationService | undefined;
private lifecycleService: ILifecycleService | undefined;
private readonly toBeInstantiated: Map<LifecyclePhase, IConstructorSignature0<IWorkbenchContribution>[]> = new Map<LifecyclePhase, IConstructorSignature0<IWorkbenchContribution>[]>();
private readonly toBeInstantiated = new Map<LifecyclePhase, IConstructorSignature0<IWorkbenchContribution>[]>();
registerWorkbenchContribution<Services extends BrandedService[]>(ctor: new (...services: Services) => IWorkbenchContribution, phase: LifecyclePhase = LifecyclePhase.Starting): void {
// Instantiate directly if we are already matching the provided phase
if (this.instantiationService && this.lifecycleService && this.lifecycleService.phase >= phase) {
this.instantiationService.createInstance<Services, typeof ctor, IWorkbenchContribution>(ctor);
......
......@@ -40,6 +40,11 @@ import { BackupTracker } from 'vs/workbench/contrib/backup/common/backupTracker'
import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench/test/electron-browser/workbenchTestServices';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TestFilesConfigurationService, TestEnvironmentService } from 'vs/workbench/test/browser/workbenchTestServices';
import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
const userdataDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'backuprestorer');
const backupHome = path.join(userdataDir, 'Backups');
......@@ -113,11 +118,23 @@ suite('BackupTracker', () => {
return pfs.rimraf(backupHome, pfs.RimRafMode.MOVE);
});
async function createTracker(): Promise<[TestServiceAccessor, EditorPart, BackupTracker, IInstantiationService]> {
async function createTracker(autoSaveEnabled = false): Promise<[TestServiceAccessor, EditorPart, BackupTracker, IInstantiationService]> {
const backupFileService = new NodeTestBackupFileService(workspaceBackupPath);
const instantiationService = workbenchInstantiationService();
instantiationService.stub(IBackupFileService, backupFileService);
const configurationService = new TestConfigurationService();
if (autoSaveEnabled) {
configurationService.setUserConfiguration('files', { autoSave: 'afterDelay', autoSaveDelay: 1 });
}
instantiationService.stub(IConfigurationService, configurationService);
instantiationService.stub(IFilesConfigurationService, new TestFilesConfigurationService(
<IContextKeyService>instantiationService.createInstance(MockContextKeyService),
configurationService,
TestEnvironmentService
));
const part = instantiationService.createInstance(EditorPart);
part.create(document.createElement('div'));
part.layout(400, 300);
......@@ -234,7 +251,41 @@ suite('BackupTracker', () => {
const event = new BeforeShutdownEventImpl();
accessor.lifecycleService.fireWillShutdown(event);
assert.ok(event.value);
const veto = event.value;
if (typeof veto === 'boolean') {
assert.ok(veto);
} else {
assert.ok((await veto));
}
part.dispose();
tracker.dispose();
});
test('onWillShutdown - no veto if auto save is on', async function () {
const [accessor, part, tracker] = await createTracker(true /* auto save enabled */);
const resource = toResource.call(this, '/path/index.txt');
await accessor.editorService.openEditor({ resource, options: { pinned: true } });
const model = accessor.textFileService.files.get(resource);
await model?.load();
model?.textEditorModel?.setValue('foo');
assert.equal(accessor.workingCopyService.dirtyCount, 1);
const event = new BeforeShutdownEventImpl();
accessor.lifecycleService.fireWillShutdown(event);
const veto = event.value;
if (typeof veto === 'boolean') {
assert.ok(!veto);
} else {
assert.ok(!(await veto));
}
assert.equal(accessor.workingCopyService.dirtyCount, 0);
part.dispose();
tracker.dispose();
......
......@@ -30,7 +30,7 @@ import { IWorkbenchContribution, Extensions as WorkbenchContributionsExtensions,
import { Registry } from 'vs/platform/registry/common/platform';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
class TrimWhitespaceParticipant implements ITextFileSaveParticipant {
export class TrimWhitespaceParticipant implements ITextFileSaveParticipant {
constructor(
@IConfigurationService private readonly configurationService: IConfigurationService,
......
......@@ -5,7 +5,7 @@
import * as assert from 'assert';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { FinalNewLineParticipant, TrimFinalNewLinesParticipant } from 'vs/workbench/contrib/codeEditor/browser/saveParticipants';
import { FinalNewLineParticipant, TrimFinalNewLinesParticipant, TrimWhitespaceParticipant } from 'vs/workbench/contrib/codeEditor/browser/saveParticipants';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench/test/browser/workbenchTestServices';
import { toResource } from 'vs/base/test/common/utils';
......@@ -16,7 +16,7 @@ import { IResolvedTextFileEditorModel, snapshotToString } from 'vs/workbench/ser
import { SaveReason } from 'vs/workbench/common/editor';
import { TextFileEditorModelManager } from 'vs/workbench/services/textfile/common/textFileEditorModelManager';
suite('MainThreadSaveParticipant', function () {
suite('Save Participants', function () {
let instantiationService: IInstantiationService;
let accessor: TestServiceAccessor;
......@@ -151,4 +151,24 @@ suite('MainThreadSaveParticipant', function () {
model.textEditorModel.redo();
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}${eol}`);
});
test('trim whitespace', async function () {
const model = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8', undefined) as IResolvedTextFileEditorModel;
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimTrailingWhitespace': true });
const participant = new TrimWhitespaceParticipant(configService, undefined!);
const textContent = 'Test';
let content = `${textContent} `;
model.textEditorModel.setValue(content);
// save many times
for (let i = 0; i < 10; i++) {
await participant.participate(model, { reason: SaveReason.EXPLICIT });
}
// confirm trimming
assert.equal(snapshotToString(model.createSnapshot()!), `${textContent}`);
});
});
......@@ -47,11 +47,11 @@ suite('EditorAutoSave', () => {
disposables = [];
});
test('editor auto saves after short delay if configured', async function () {
async function createEditorAutoSave(autoSaveConfig: object): Promise<[TestServiceAccessor, EditorPart, EditorAutoSave]> {
const instantiationService = workbenchInstantiationService();
const configurationService = new TestConfigurationService();
configurationService.setUserConfiguration('files', { autoSave: 'afterDelay', autoSaveDelay: 1 });
configurationService.setUserConfiguration('files', autoSaveConfig);
instantiationService.stub(IConfigurationService, configurationService);
instantiationService.stub(IFilesConfigurationService, new TestFilesConfigurationService(
......@@ -73,14 +73,41 @@ suite('EditorAutoSave', () => {
const editorAutoSave = instantiationService.createInstance(EditorAutoSave);
return [accessor, part, editorAutoSave];
}
test('editor auto saves after short delay if configured', async function () {
const [accessor, part, editorAutoSave] = await createEditorAutoSave({ autoSave: 'afterDelay', autoSaveDelay: 1 });
const resource = toResource.call(this, '/path/index.txt');
const model = await accessor.textFileService.files.resolve(resource) as IResolvedTextFileEditorModel;
model.textEditorModel.setValue('Super Good');
assert.ok(model.isDirty());
await awaitModelSaved(model);
assert.ok(!model.isDirty());
part.dispose();
editorAutoSave.dispose();
(<TextFileEditorModelManager>accessor.textFileService.files).dispose();
});
test('editor auto saves on focus change if configured', async function () {
const [accessor, part, editorAutoSave] = await createEditorAutoSave({ autoSave: 'onFocusChange' });
const resource = toResource.call(this, '/path/index.txt');
await accessor.editorService.openEditor({ resource, forceFile: true });
const model = await accessor.textFileService.files.resolve(resource) as IResolvedTextFileEditorModel;
model.textEditorModel.setValue('Super Good');
assert.ok(model.isDirty());
await accessor.editorService.openEditor({ resource: toResource.call(this, '/path/index_other.txt') });
await awaitModelSaved(model);
assert.ok(!model.isDirty());
......
......@@ -16,6 +16,7 @@ import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textF
import { timeout } from 'vs/base/common/async';
import { ModesRegistry, PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { BinaryEditorModel } from 'vs/workbench/common/editor/binaryEditorModel';
suite('Files - FileEditorInput', () => {
let instantiationService: IInstantiationService;
......@@ -196,4 +197,19 @@ suite('Files - FileEditorInput', () => {
input.dispose();
listener.dispose();
});
test('force open text/binary', async function () {
const input = instantiationService.createInstance(FileEditorInput, toResource.call(this, '/foo/bar/updatefile.js'), undefined, undefined);
input.setForceOpenAsBinary();
let resolved = await input.resolve();
assert.ok(resolved instanceof BinaryEditorModel);
input.setForceOpenAsText();
resolved = await input.resolve();
assert.ok(resolved instanceof TextFileEditorModel);
resolved.dispose();
});
});
......@@ -9,7 +9,7 @@ import { TextFileEditorTracker } from 'vs/workbench/contrib/files/browser/editor
import { toResource } from 'vs/base/test/common/utils';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { workbenchInstantiationService, TestServiceAccessor } from 'vs/workbench/test/browser/workbenchTestServices';
import { IResolvedTextFileEditorModel, snapshotToString } from 'vs/workbench/services/textfile/common/textfiles';
import { IResolvedTextFileEditorModel, snapshotToString, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { FileChangesEvent, FileChangeType } from 'vs/platform/files/common/files';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { timeout } from 'vs/base/common/async';
......@@ -25,6 +25,8 @@ import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
import { EditorService } from 'vs/workbench/services/editor/browser/editorService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { UntitledTextEditorInput } from 'vs/workbench/services/untitled/common/untitledTextEditorInput';
import { isEqual } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
suite('Files - TextFileEditorTracker', () => {
......@@ -46,12 +48,30 @@ suite('Files - TextFileEditorTracker', () => {
disposables = [];
});
test('file change event updates model', async function () {
async function createTracker(): Promise<[EditorPart, TestServiceAccessor, TextFileEditorTracker, IInstantiationService, IEditorService]> {
const instantiationService = workbenchInstantiationService();
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);
const accessor = instantiationService.createInstance(TestServiceAccessor);
await part.whenRestored;
const tracker = instantiationService.createInstance(TextFileEditorTracker);
return [part, accessor, tracker, instantiationService, editorService];
}
test('file change event updates model', async function () {
const [, accessor, tracker] = await createTracker();
const resource = toResource.call(this, '/path/index.txt');
const model = await accessor.textFileService.files.resolve(resource) as IResolvedTextFileEditorModel;
......@@ -72,27 +92,6 @@ suite('Files - TextFileEditorTracker', () => {
(<TextFileEditorModelManager>accessor.textFileService.files).dispose();
});
async function createTracker(): Promise<[EditorPart, TestServiceAccessor, TextFileEditorTracker, IInstantiationService, IEditorService]> {
const instantiationService = workbenchInstantiationService();
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);
const accessor = instantiationService.createInstance(TestServiceAccessor);
await part.whenRestored;
const tracker = instantiationService.createInstance(TextFileEditorTracker);
return [part, accessor, tracker, instantiationService, editorService];
}
test('dirty text file model opens as editor', async function () {
const [part, accessor, tracker] = await createTracker();
......@@ -135,4 +134,32 @@ suite('Files - TextFileEditorTracker', () => {
Event.once(editorService.onDidActiveEditorChange)(c);
});
}
test('non-dirty files reload on window focus', async function () {
const [part, accessor, tracker] = await createTracker();
const resource = toResource.call(this, '/path/index.txt');
await accessor.editorService.openEditor(accessor.editorService.createInput({ resource, forceFile: true }));
accessor.hostService.setFocus(false);
accessor.hostService.setFocus(true);
await awaitModelLoadEvent(accessor.textFileService, resource);
part.dispose();
tracker.dispose();
(<TextFileEditorModelManager>accessor.textFileService.files).dispose();
});
function awaitModelLoadEvent(textFileService: ITextFileService, resource: URI): Promise<void> {
return new Promise(c => {
const listener = textFileService.files.onDidLoad(e => {
if (isEqual(e.model.resource, resource)) {
listener.dispose();
c();
}
});
});
}
});
......@@ -4,8 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
import { workbenchInstantiationService, registerTestEditor, TestFileEditorInput } from 'vs/workbench/test/browser/workbenchTestServices';
import { workbenchInstantiationService, registerTestEditor, TestFileEditorInput, TestEditorPart, ITestInstantiationService } from 'vs/workbench/test/browser/workbenchTestServices';
import { GroupDirection, GroupsOrder, MergeGroupMode, GroupOrientation, GroupChangeKind, GroupLocation } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { EditorOptions, CloseDirection, IEditorPartOptions, EditorsOrder } from 'vs/workbench/common/editor';
......@@ -29,18 +28,16 @@ suite('EditorGroupsService', () => {
disposables = [];
});
function createPart(): EditorPart {
const instantiationService = workbenchInstantiationService();
const part = instantiationService.createInstance(EditorPart);
function createPart(instantiationService = workbenchInstantiationService()): [TestEditorPart, ITestInstantiationService] {
const part = instantiationService.createInstance(TestEditorPart);
part.create(document.createElement('div'));
part.layout(400, 300);
return part;
return [part, instantiationService];
}
test('groups basics', async function () {
const part = createPart();
const [part] = createPart();
let activeGroupChangeCounter = 0;
const activeGroupChangeListener = part.onDidActiveGroupChange(() => {
......@@ -201,8 +198,37 @@ suite('EditorGroupsService', () => {
part.dispose();
});
test('save & restore state', async function () {
let [part, instantiationService] = createPart();
const rootGroup = part.groups[0];
const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT);
const downGroup = part.addGroup(rightGroup, GroupDirection.DOWN);
const rootGroupInput = new TestFileEditorInput(URI.file('foo/bar1'), TEST_EDITOR_INPUT_ID);
await rootGroup.openEditor(rootGroupInput, EditorOptions.create({ pinned: true }));
const rightGroupInput = new TestFileEditorInput(URI.file('foo/bar2'), TEST_EDITOR_INPUT_ID);
await rightGroup.openEditor(rightGroupInput, EditorOptions.create({ pinned: true }));
assert.equal(part.groups.length, 3);
part.saveState();
part.dispose();
let [restoredPart] = createPart(instantiationService);
assert.equal(restoredPart.groups.length, 3);
assert.ok(restoredPart.getGroup(rootGroup.id));
assert.ok(restoredPart.getGroup(rightGroup.id));
assert.ok(restoredPart.getGroup(downGroup.id));
restoredPart.clearState();
restoredPart.dispose();
});
test('groups index / labels', function () {
const part = createPart();
const [part] = createPart();
const rootGroup = part.groups[0];
const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT);
......@@ -260,7 +286,7 @@ suite('EditorGroupsService', () => {
});
test('copy/merge groups', async () => {
const part = createPart();
const [part] = createPart();
let groupAddedCounter = 0;
const groupAddedListener = part.onDidAddGroup(() => {
......@@ -301,7 +327,7 @@ suite('EditorGroupsService', () => {
});
test('whenRestored', async () => {
const part = createPart();
const [part] = createPart();
await part.whenRestored;
assert.ok(true);
......@@ -309,7 +335,7 @@ suite('EditorGroupsService', () => {
});
test('options', () => {
const part = createPart();
const [part] = createPart();
let oldOptions!: IEditorPartOptions;
let newOptions!: IEditorPartOptions;
......@@ -330,7 +356,7 @@ suite('EditorGroupsService', () => {
});
test('editor basics', async function () {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -428,7 +454,7 @@ suite('EditorGroupsService', () => {
});
test('openEditors / closeEditors', async () => {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -446,7 +472,7 @@ suite('EditorGroupsService', () => {
});
test('closeEditors (except one)', async () => {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -467,7 +493,7 @@ suite('EditorGroupsService', () => {
});
test('closeEditors (saved only)', async () => {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -487,7 +513,7 @@ suite('EditorGroupsService', () => {
});
test('closeEditors (direction: right)', async () => {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -509,7 +535,7 @@ suite('EditorGroupsService', () => {
});
test('closeEditors (direction: left)', async () => {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -531,7 +557,7 @@ suite('EditorGroupsService', () => {
});
test('closeAllEditors', async () => {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -549,7 +575,7 @@ suite('EditorGroupsService', () => {
});
test('moveEditor (same group)', async () => {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -577,7 +603,7 @@ suite('EditorGroupsService', () => {
});
test('moveEditor (across groups)', async () => {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -599,7 +625,7 @@ suite('EditorGroupsService', () => {
});
test('copyEditor (across groups)', async () => {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -622,7 +648,7 @@ suite('EditorGroupsService', () => {
});
test('replaceEditors', async () => {
const part = createPart();
const [part] = createPart();
const group = part.activeGroup;
assert.equal(group.isEmpty, true);
......@@ -640,7 +666,7 @@ suite('EditorGroupsService', () => {
});
test('find neighbour group (left/right)', function () {
const part = createPart();
const [part] = createPart();
const rootGroup = part.activeGroup;
const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT);
......@@ -651,7 +677,7 @@ suite('EditorGroupsService', () => {
});
test('find neighbour group (up/down)', function () {
const part = createPart();
const [part] = createPart();
const rootGroup = part.activeGroup;
const downGroup = part.addGroup(rootGroup, GroupDirection.DOWN);
......@@ -662,7 +688,7 @@ suite('EditorGroupsService', () => {
});
test('find group by location (left/right)', function () {
const part = createPart();
const [part] = createPart();
const rootGroup = part.activeGroup;
const rightGroup = part.addGroup(rootGroup, GroupDirection.RIGHT);
const downGroup = part.addGroup(rightGroup, GroupDirection.DOWN);
......@@ -678,4 +704,24 @@ suite('EditorGroupsService', () => {
part.dispose();
});
test('applyLayout (2x2)', function () {
const [part] = createPart();
part.applyLayout({ groups: [{ groups: [{}, {}] }, { groups: [{}, {}] }], orientation: GroupOrientation.HORIZONTAL });
assert.equal(part.groups.length, 4);
part.dispose();
});
test('centeredLayout', function () {
const [part] = createPart();
part.centerLayout(true);
assert.equal(part.isLayoutCentered(), true);
part.dispose();
});
});
......@@ -710,9 +710,9 @@ suite('EditorService', () => {
test('save, saveAll, revertAll', async function () {
const [part, service] = createEditorService();
const input1 = new TestFileEditorInput(URI.parse('my://resource1-openside'), TEST_EDITOR_INPUT_ID);
const input1 = new TestFileEditorInput(URI.parse('my://resource1'), TEST_EDITOR_INPUT_ID);
input1.dirty = true;
const input2 = new TestFileEditorInput(URI.parse('my://resource2-openside'), TEST_EDITOR_INPUT_ID);
const input2 = new TestFileEditorInput(URI.parse('my://resource2'), TEST_EDITOR_INPUT_ID);
input2.dirty = true;
const rootGroup = part.activeGroup;
......@@ -753,9 +753,9 @@ suite('EditorService', () => {
async function testFileDeleteEditorClose(dirty: boolean): Promise<void> {
const [part, service, accessor] = createEditorService();
const input1 = new TestFileEditorInput(URI.parse('my://resource1-openside'), TEST_EDITOR_INPUT_ID);
const input1 = new TestFileEditorInput(URI.parse('my://resource1'), TEST_EDITOR_INPUT_ID);
input1.dirty = dirty;
const input2 = new TestFileEditorInput(URI.parse('my://resource2-openside'), TEST_EDITOR_INPUT_ID);
const input2 = new TestFileEditorInput(URI.parse('my://resource2'), TEST_EDITOR_INPUT_ID);
input2.dirty = dirty;
const rootGroup = part.activeGroup;
......@@ -785,8 +785,8 @@ suite('EditorService', () => {
test('file move asks input to move', async function () {
const [part, service, accessor] = createEditorService();
const input1 = new TestFileEditorInput(URI.parse('my://resource1-openside'), TEST_EDITOR_INPUT_ID);
const movedInput = new TestFileEditorInput(URI.parse('my://resource2-openside'), TEST_EDITOR_INPUT_ID);
const input1 = new TestFileEditorInput(URI.parse('my://resource1'), TEST_EDITOR_INPUT_ID);
const movedInput = new TestFileEditorInput(URI.parse('my://resource2'), TEST_EDITOR_INPUT_ID);
input1.movedEditor = { editor: movedInput };
const rootGroup = part.activeGroup;
......@@ -803,7 +803,7 @@ suite('EditorService', () => {
isDirectory: false,
isFile: true,
mtime: 0,
name: 'resource2-openside',
name: 'resource2',
size: 0,
isSymbolicLink: false
}));
......@@ -823,8 +823,8 @@ suite('EditorService', () => {
test('file watcher gets installed for out of workspace files', async function () {
const [part, service, accessor] = createEditorService();
const input1 = new TestFileEditorInput(URI.parse('file://resource1-openside'), TEST_EDITOR_INPUT_ID);
const input2 = new TestFileEditorInput(URI.parse('file://resource2-openside'), TEST_EDITOR_INPUT_ID);
const input1 = new TestFileEditorInput(URI.parse('file://resource1'), TEST_EDITOR_INPUT_ID);
const input2 = new TestFileEditorInput(URI.parse('file://resource2'), TEST_EDITOR_INPUT_ID);
await part.whenRestored;
......@@ -841,4 +841,53 @@ suite('EditorService', () => {
part.dispose();
});
test('invokeWithinEditorContext', async function () {
const [part, service] = createEditorService();
const input1 = new TestFileEditorInput(URI.parse('file://resource1'), TEST_EDITOR_INPUT_ID);
new TestFileEditorInput(URI.parse('file://resource2'), TEST_EDITOR_INPUT_ID);
await part.whenRestored;
await service.openEditor(input1, { pinned: true });
let hasAccessor = false;
service.invokeWithinEditorContext(accessor => {
hasAccessor = true;
});
assert.ok(hasAccessor);
part.dispose();
});
test('overrideOpenEditor', async function () {
const [part, service] = createEditorService();
const input1 = new TestFileEditorInput(URI.parse('file://resource1'), TEST_EDITOR_INPUT_ID);
const input2 = new TestFileEditorInput(URI.parse('file://resource2'), TEST_EDITOR_INPUT_ID);
await part.whenRestored;
let overrideCalled = false;
const handler = service.overrideOpenEditor(editor => {
if (editor === input1) {
overrideCalled = true;
return { override: service.openEditor(input2, { pinned: true }) };
}
return undefined;
});
await service.openEditor(input1, { pinned: true });
assert.ok(overrideCalled);
assert.equal(service.activeEditor, input2);
handler.dispose();
part.dispose();
});
});
......@@ -80,6 +80,12 @@ suite('Files - TextFileEditorModel', () => {
assert.equal(accessor.workingCopyService.dirtyCount, 0);
let savedEvent = false;
model.onDidSave(() => savedEvent = true);
await model.save();
assert.ok(!savedEvent);
model.updateTextEditorModel(createTextBufferFactory('bar'));
assert.ok(getLastModifiedTime(model) <= Date.now());
assert.ok(model.hasState(TextFileEditorModelState.DIRTY));
......@@ -87,9 +93,6 @@ suite('Files - TextFileEditorModel', () => {
assert.equal(accessor.workingCopyService.dirtyCount, 1);
assert.equal(accessor.workingCopyService.isDirty(model.resource), true);
let savedEvent = false;
model.onDidSave(() => savedEvent = true);
let workingCopyEvent = false;
accessor.workingCopyService.onDidChangeDirty(e => {
if (e.resource.toString() === model.resource.toString()) {
......@@ -110,6 +113,11 @@ suite('Files - TextFileEditorModel', () => {
assert.equal(accessor.workingCopyService.dirtyCount, 0);
assert.equal(accessor.workingCopyService.isDirty(model.resource), false);
savedEvent = false;
await model.save({ force: true });
assert.ok(savedEvent);
model.dispose();
assert.ok(!accessor.modelService.getModel(model.resource));
});
......@@ -404,7 +412,7 @@ suite('Files - TextFileEditorModel', () => {
model.dispose();
});
test('No Dirty for readonly models', async function () {
test('No Dirty or saving for readonly models', async function () {
let workingCopyEvent = false;
accessor.workingCopyService.onDidChangeDirty(e => {
if (e.resource.toString() === model.resource.toString()) {
......@@ -414,10 +422,18 @@ suite('Files - TextFileEditorModel', () => {
const model = instantiationService.createInstance(TestReadonlyTextFileEditorModel, toResource.call(this, '/path/index_async.txt'), 'utf8', undefined);
let saveEvent = false;
model.onDidSave(() => {
saveEvent = true;
});
await model.load();
model.updateTextEditorModel(createTextBufferFactory('foo'));
assert.ok(!model.isDirty());
await model.save({ force: true });
assert.equal(saveEvent, false);
await model.revert({ soft: true });
assert.ok(!model.isDirty());
......
......@@ -42,7 +42,7 @@ import { IPosition, Position as EditorPosition } from 'vs/editor/common/core/pos
import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { MockContextKeyService, MockKeybindingService } from 'vs/platform/keybinding/test/common/mockKeybindingService';
import { ITextBufferFactory, DefaultEndOfLine, EndOfLinePreference, IModelDecorationOptions, ITextModel, ITextSnapshot } from 'vs/editor/common/model';
import { ITextBufferFactory, DefaultEndOfLine, EndOfLinePreference, ITextSnapshot } from 'vs/editor/common/model';
import { Range } from 'vs/editor/common/core/range';
import { IDialogService, IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService, ConfirmResult } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification';
......@@ -54,9 +54,7 @@ import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/
import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IAddGroupOptions, IMergeGroupOptions, IMoveEditorOptions, ICopyEditorOptions, IEditorReplacement, IGroupChangeEvent, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService, IOpenEditorOverrideHandler, IVisibleEditor, ISaveEditorsOptions, IRevertAllEditorsOptions, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorRegistry, EditorDescriptor, Extensions } from 'vs/workbench/browser/editor';
import { IDecorationRenderOptions } from 'vs/editor/common/editorCommon';
import { EditorGroup } from 'vs/workbench/common/editor/editorGroup';
import { Dimension } from 'vs/base/browser/dom';
import { ILogService, NullLogService } from 'vs/platform/log/common/log';
......@@ -65,7 +63,7 @@ import { timeout } from 'vs/base/common/async';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { ViewletDescriptor, Viewlet } from 'vs/workbench/browser/viewlet';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { isLinux } from 'vs/base/common/platform';
import { LabelService } from 'vs/workbench/services/label/common/labelService';
import { IDimension } from 'vs/platform/layout/browser/layoutService';
......@@ -99,6 +97,8 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { CancellationToken } from 'vs/base/common/cancellation';
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { TestDialogService } from 'vs/platform/dialogs/test/common/testDialogService';
import { CodeEditorService } from 'vs/workbench/services/editor/browser/codeEditorService';
import { EditorPart } from 'vs/workbench/browser/parts/editor/editorPart';
export import TestTextResourcePropertiesService = CommonWorkbenchTestServices.TestTextResourcePropertiesService;
export import TestContextService = CommonWorkbenchTestServices.TestContextService;
......@@ -151,14 +151,15 @@ export function workbenchInstantiationService(overrides?: { textFileService?: (i
instantiationService.stub(ITextFileService, overrides?.textFileService ? overrides.textFileService(instantiationService) : <ITextFileService>instantiationService.createInstance(TestTextFileService));
instantiationService.stub(IHostService, <IHostService>instantiationService.createInstance(TestHostService));
instantiationService.stub(ITextModelService, <ITextModelService>instantiationService.createInstance(TextModelResolverService));
instantiationService.stub(IThemeService, new TestThemeService());
const themeService = new TestThemeService();
instantiationService.stub(IThemeService, themeService);
instantiationService.stub(ILogService, new NullLogService());
const editorGroupService = new TestEditorGroupsService([new TestEditorGroupView(0)]);
instantiationService.stub(IEditorGroupsService, editorGroupService);
instantiationService.stub(ILabelService, <ILabelService>instantiationService.createInstance(LabelService));
const editorService = new TestEditorService(editorGroupService);
instantiationService.stub(IEditorService, editorService);
instantiationService.stub(ICodeEditorService, new TestCodeEditorService());
instantiationService.stub(ICodeEditorService, new CodeEditorService(editorService, themeService));
instantiationService.stub(IViewletService, new TestViewletService());
return instantiationService;
......@@ -181,7 +182,8 @@ export class TestServiceAccessor {
@ITextModelService public textModelResolverService: ITextModelService,
@IUntitledTextEditorService public untitledTextEditorService: UntitledTextEditorService,
@IConfigurationService public testConfigurationService: TestConfigurationService,
@IBackupFileService public backupFileService: TestBackupFileService
@IBackupFileService public backupFileService: TestBackupFileService,
@IHostService public hostService: TestHostService
) { }
}
......@@ -791,32 +793,6 @@ export class TestBackupFileService implements IBackupFileService {
}
}
export class TestCodeEditorService implements ICodeEditorService {
_serviceBrand: undefined;
onCodeEditorAdd: Event<ICodeEditor> = Event.None;
onCodeEditorRemove: Event<ICodeEditor> = Event.None;
onDiffEditorAdd: Event<IDiffEditor> = Event.None;
onDiffEditorRemove: Event<IDiffEditor> = Event.None;
onDidChangeTransientModelProperty: Event<ITextModel> = Event.None;
addCodeEditor(_editor: ICodeEditor): void { }
removeCodeEditor(_editor: ICodeEditor): void { }
listCodeEditors(): ICodeEditor[] { return []; }
addDiffEditor(_editor: IDiffEditor): void { }
removeDiffEditor(_editor: IDiffEditor): void { }
listDiffEditors(): IDiffEditor[] { return []; }
getFocusedCodeEditor(): ICodeEditor | null { return null; }
registerDecorationType(_key: string, _options: IDecorationRenderOptions, _parentTypeKey?: string): void { }
removeDecorationType(_key: string): void { }
resolveDecorationOptions(_typeKey: string, _writable: boolean): IModelDecorationOptions { return Object.create(null); }
setTransientModelProperty(_model: ITextModel, _key: string, _value: any): void { }
getTransientModelProperty(_model: ITextModel, _key: string) { }
getTransientModelProperties(_model: ITextModel) { return undefined; }
getActiveCodeEditor(): ICodeEditor | null { return null; }
openCodeEditor(_input: IResourceInput, _source: ICodeEditor, _sideBySide?: boolean): Promise<ICodeEditor | null> { return Promise.resolve(null); }
}
export class TestLifecycleService implements ILifecycleService {
_serviceBrand: undefined;
......@@ -906,9 +882,17 @@ export class TestHostService implements IHostService {
_serviceBrand: undefined;
readonly hasFocus: boolean = true;
async hadLastFocus(): Promise<boolean> { return true; }
readonly onDidChangeFocus: Event<boolean> = Event.None;
private _hasFocus = true;
get hasFocus() { return this._hasFocus; }
async hadLastFocus(): Promise<boolean> { return this._hasFocus; }
private _onDidChangeFocus = new Emitter<boolean>();
readonly onDidChangeFocus = this._onDidChangeFocus.event;
setFocus(focus: boolean) {
this._hasFocus = focus;
this._onDidChangeFocus.fire(this._hasFocus);
}
async restart(): Promise<void> { }
async reload(): Promise<void> { }
......@@ -1059,3 +1043,22 @@ export class TestFileEditorInput extends EditorInput implements IFileEditorInput
movedEditor: IMoveResult | undefined = undefined;
move(): IMoveResult | undefined { return this.movedEditor; }
}
export class TestEditorPart extends EditorPart {
saveState(): void {
return super.saveState();
}
clearState(): void {
const workspaceMemento = this.getMemento(StorageScope.WORKSPACE);
for (const key of Object.keys(workspaceMemento)) {
delete workspaceMemento[key];
}
const globalMemento = this.getMemento(StorageScope.GLOBAL);
for (const key of Object.keys(globalMemento)) {
delete globalMemento[key];
}
}
}
......@@ -35,14 +35,20 @@ export class TestTextResourcePropertiesService implements ITextResourcePropertie
}
export class TestContextService implements IWorkspaceContextService {
_serviceBrand: undefined;
private workspace: Workspace;
private options: any;
private readonly _onDidChangeWorkspaceName: Emitter<void>;
get onDidChangeWorkspaceName(): Event<void> { return this._onDidChangeWorkspaceName.event; }
private readonly _onDidChangeWorkspaceFolders: Emitter<IWorkspaceFoldersChangeEvent>;
get onDidChangeWorkspaceFolders(): Event<IWorkspaceFoldersChangeEvent> { return this._onDidChangeWorkspaceFolders.event; }
private readonly _onDidChangeWorkbenchState: Emitter<WorkbenchState>;
get onDidChangeWorkbenchState(): Event<WorkbenchState> { return this._onDidChangeWorkbenchState.event; }
constructor(workspace: any = TestWorkspace, options: any = null) {
this.workspace = workspace;
......@@ -52,18 +58,6 @@ export class TestContextService implements IWorkspaceContextService {
this._onDidChangeWorkbenchState = new Emitter<WorkbenchState>();
}
get onDidChangeWorkspaceName(): Event<void> {
return this._onDidChangeWorkspaceName.event;
}
get onDidChangeWorkspaceFolders(): Event<IWorkspaceFoldersChangeEvent> {
return this._onDidChangeWorkspaceFolders.event;
}
get onDidChangeWorkbenchState(): Event<WorkbenchState> {
return this._onDidChangeWorkbenchState.event;
}
getFolders(): IWorkspaceFolder[] {
return this.workspace ? this.workspace.folders : [];
}
......@@ -100,9 +94,7 @@ export class TestContextService implements IWorkspaceContextService {
return this.options;
}
updateOptions() {
}
updateOptions() { }
isInsideWorkspace(resource: URI): boolean {
if (resource && this.workspace) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册