mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-12 11:08:31 -05:00
* Initial VS Code 1.21 file copy with patches * A few more merges * Post npm install * Fix batch of build breaks * Fix more build breaks * Fix more build errors * Fix more build breaks * Runtime fixes 1 * Get connection dialog working with some todos * Fix a few packaging issues * Copy several node_modules to package build to fix loader issues * Fix breaks from master * A few more fixes * Make tests pass * First pass of license header updates * Second pass of license header updates * Fix restore dialog issues * Remove add additional themes menu items * fix select box issues where the list doesn't show up * formatting * Fix editor dispose issue * Copy over node modules to correct location on all platforms
399 lines
13 KiB
TypeScript
399 lines
13 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
'use strict';
|
|
|
|
import * as assert from 'assert';
|
|
import URI from 'vs/base/common/uri';
|
|
import { TPromise } from 'vs/base/common/winjs.base';
|
|
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
|
|
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
|
import { TextDocumentSaveReason, TextEdit, Position, EndOfLine } from 'vs/workbench/api/node/extHostTypes';
|
|
import { MainThreadTextEditorsShape, WorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
|
|
import { ExtHostDocumentSaveParticipant } from 'vs/workbench/api/node/extHostDocumentSaveParticipant';
|
|
import { SingleProxyRPCProtocol } from './testRPCProtocol';
|
|
import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles';
|
|
import * as vscode from 'vscode';
|
|
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
|
|
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
|
import { NullLogService } from 'vs/platform/log/common/log';
|
|
import { isResourceTextEdit, ResourceTextEdit } from 'vs/editor/common/modes';
|
|
|
|
suite('ExtHostDocumentSaveParticipant', () => {
|
|
|
|
let resource = URI.parse('foo:bar');
|
|
let mainThreadEditors = new class extends mock<MainThreadTextEditorsShape>() { };
|
|
let documents: ExtHostDocuments;
|
|
let nullLogService = new NullLogService();
|
|
let nullExtensionDescription: IExtensionDescription = {
|
|
id: 'nullExtensionDescription',
|
|
name: 'Null Extension Description',
|
|
publisher: 'vscode',
|
|
enableProposedApi: false,
|
|
engines: undefined,
|
|
extensionFolderPath: undefined,
|
|
isBuiltin: false,
|
|
version: undefined
|
|
};
|
|
|
|
setup(() => {
|
|
const documentsAndEditors = new ExtHostDocumentsAndEditors(SingleProxyRPCProtocol(null));
|
|
documentsAndEditors.$acceptDocumentsAndEditorsDelta({
|
|
addedDocuments: [{
|
|
isDirty: false,
|
|
modeId: 'foo',
|
|
uri: resource,
|
|
versionId: 1,
|
|
lines: ['foo'],
|
|
EOL: '\n',
|
|
}]
|
|
});
|
|
documents = new ExtHostDocuments(SingleProxyRPCProtocol(null), documentsAndEditors);
|
|
});
|
|
|
|
test('no listeners, no problem', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => assert.ok(true));
|
|
});
|
|
|
|
test('event delivery', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
|
|
|
let event: vscode.TextDocumentWillSaveEvent;
|
|
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
event = e;
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
|
sub.dispose();
|
|
|
|
assert.ok(event);
|
|
assert.equal(event.reason, TextDocumentSaveReason.Manual);
|
|
assert.equal(typeof event.waitUntil, 'function');
|
|
});
|
|
});
|
|
|
|
test('event delivery, immutable', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
|
|
|
let event: vscode.TextDocumentWillSaveEvent;
|
|
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
event = e;
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
|
sub.dispose();
|
|
|
|
assert.ok(event);
|
|
assert.throws(() => event.document = null);
|
|
});
|
|
});
|
|
|
|
test('event delivery, bad listener', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
|
|
|
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
throw new Error('💀');
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {
|
|
sub.dispose();
|
|
|
|
const [first] = values;
|
|
assert.equal(first, false);
|
|
});
|
|
});
|
|
|
|
test('event delivery, bad listener doesn\'t prevent more events', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
|
|
|
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
throw new Error('💀');
|
|
});
|
|
let event: vscode.TextDocumentWillSaveEvent;
|
|
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
event = e;
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
|
sub1.dispose();
|
|
sub2.dispose();
|
|
|
|
assert.ok(event);
|
|
});
|
|
});
|
|
|
|
test('event delivery, in subscriber order', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
|
|
|
let counter = 0;
|
|
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
|
assert.equal(counter++, 0);
|
|
});
|
|
|
|
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
|
assert.equal(counter++, 1);
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
|
sub1.dispose();
|
|
sub2.dispose();
|
|
});
|
|
});
|
|
|
|
test('event delivery, ignore bad listeners', async () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors, { timeout: 5, errors: 1 });
|
|
|
|
let callCount = 0;
|
|
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
|
callCount += 1;
|
|
throw new Error('boom');
|
|
});
|
|
|
|
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
|
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
|
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
|
await participant.$participateInSave(resource, SaveReason.EXPLICIT);
|
|
|
|
sub.dispose();
|
|
assert.equal(callCount, 2);
|
|
});
|
|
|
|
test('event delivery, overall timeout', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors, { timeout: 20, errors: 5 });
|
|
|
|
let callCount = 0;
|
|
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
|
callCount += 1;
|
|
event.waitUntil(TPromise.timeout(17));
|
|
});
|
|
|
|
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
|
callCount += 1;
|
|
event.waitUntil(TPromise.timeout(17));
|
|
});
|
|
|
|
let sub3 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
|
callCount += 1;
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {
|
|
sub1.dispose();
|
|
sub2.dispose();
|
|
sub3.dispose();
|
|
|
|
assert.equal(callCount, 2);
|
|
assert.equal(values.length, 2);
|
|
});
|
|
});
|
|
|
|
test('event delivery, waitUntil', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
|
|
|
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
|
|
|
event.waitUntil(TPromise.timeout(10));
|
|
event.waitUntil(TPromise.timeout(10));
|
|
event.waitUntil(TPromise.timeout(10));
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
|
sub.dispose();
|
|
});
|
|
|
|
});
|
|
|
|
test('event delivery, waitUntil must be called sync', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
|
|
|
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
|
|
|
event.waitUntil(new TPromise((resolve, reject) => {
|
|
setTimeout(() => {
|
|
try {
|
|
assert.throws(() => event.waitUntil(TPromise.timeout(10)));
|
|
resolve(void 0);
|
|
} catch (e) {
|
|
reject(e);
|
|
}
|
|
|
|
}, 10);
|
|
}));
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
|
sub.dispose();
|
|
});
|
|
});
|
|
|
|
test('event delivery, waitUntil will timeout', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors, { timeout: 5, errors: 3 });
|
|
|
|
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
|
|
event.waitUntil(TPromise.timeout(15));
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {
|
|
sub.dispose();
|
|
|
|
const [first] = values;
|
|
assert.equal(first, false);
|
|
});
|
|
});
|
|
|
|
test('event delivery, waitUntil failure handling', () => {
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
|
|
|
|
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
e.waitUntil(TPromise.wrapError(new Error('dddd')));
|
|
});
|
|
|
|
let event: vscode.TextDocumentWillSaveEvent;
|
|
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
event = e;
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
|
assert.ok(event);
|
|
sub1.dispose();
|
|
sub2.dispose();
|
|
});
|
|
});
|
|
|
|
test('event delivery, pushEdits sync', () => {
|
|
|
|
let dto: WorkspaceEditDto;
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
|
|
$tryApplyWorkspaceEdit(_edits: WorkspaceEditDto) {
|
|
dto = _edits;
|
|
return TPromise.as(true);
|
|
}
|
|
});
|
|
|
|
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
e.waitUntil(TPromise.as([TextEdit.insert(new Position(0, 0), 'bar')]));
|
|
e.waitUntil(TPromise.as([TextEdit.setEndOfLine(EndOfLine.CRLF)]));
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
|
sub.dispose();
|
|
|
|
assert.equal(dto.edits.length, 1);
|
|
assert.ok(isResourceTextEdit(dto.edits[0]));
|
|
assert.equal((<ResourceTextEdit>dto.edits[0]).edits.length, 2);
|
|
});
|
|
});
|
|
|
|
test('event delivery, concurrent change', () => {
|
|
|
|
let edits: WorkspaceEditDto;
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
|
|
$tryApplyWorkspaceEdit(_edits: WorkspaceEditDto) {
|
|
edits = _edits;
|
|
return TPromise.as(true);
|
|
}
|
|
});
|
|
|
|
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
|
|
// concurrent change from somewhere
|
|
documents.$acceptModelChanged(resource, {
|
|
changes: [{
|
|
range: { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 },
|
|
rangeLength: undefined,
|
|
text: 'bar'
|
|
}],
|
|
eol: undefined,
|
|
versionId: 2
|
|
}, true);
|
|
|
|
e.waitUntil(TPromise.as([TextEdit.insert(new Position(0, 0), 'bar')]));
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {
|
|
sub.dispose();
|
|
|
|
assert.equal(edits, undefined);
|
|
assert.equal(values[0], false);
|
|
});
|
|
|
|
});
|
|
|
|
test('event delivery, two listeners -> two document states', () => {
|
|
|
|
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
|
|
$tryApplyWorkspaceEdit(dto: WorkspaceEditDto) {
|
|
|
|
for (const edit of dto.edits) {
|
|
if (!isResourceTextEdit(edit)) {
|
|
continue;
|
|
}
|
|
const { resource, edits } = edit;
|
|
const uri = URI.revive(resource);
|
|
for (const { text, range } of edits) {
|
|
documents.$acceptModelChanged(uri, {
|
|
changes: [{
|
|
range,
|
|
text,
|
|
rangeLength: undefined,
|
|
}],
|
|
eol: undefined,
|
|
versionId: documents.getDocumentData(uri).version + 1
|
|
}, true);
|
|
}
|
|
}
|
|
|
|
return TPromise.as(true);
|
|
}
|
|
});
|
|
|
|
const document = documents.getDocumentData(resource).document;
|
|
|
|
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
// the document state we started with
|
|
assert.equal(document.version, 1);
|
|
assert.equal(document.getText(), 'foo');
|
|
|
|
e.waitUntil(TPromise.as([TextEdit.insert(new Position(0, 0), 'bar')]));
|
|
});
|
|
|
|
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
// the document state AFTER the first listener kicked in
|
|
assert.equal(document.version, 2);
|
|
assert.equal(document.getText(), 'barfoo');
|
|
|
|
e.waitUntil(TPromise.as([TextEdit.insert(new Position(0, 0), 'bar')]));
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {
|
|
sub1.dispose();
|
|
sub2.dispose();
|
|
|
|
// the document state AFTER eventing is done
|
|
assert.equal(document.version, 3);
|
|
assert.equal(document.getText(), 'barbarfoo');
|
|
});
|
|
|
|
});
|
|
|
|
test('Log failing listener', function () {
|
|
let didLogSomething = false;
|
|
let participant = new ExtHostDocumentSaveParticipant(new class extends NullLogService {
|
|
error(message: string | Error, ...args: any[]): void {
|
|
didLogSomething = true;
|
|
}
|
|
}, documents, mainThreadEditors);
|
|
|
|
|
|
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
|
|
throw new Error('boom');
|
|
});
|
|
|
|
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
|
|
sub.dispose();
|
|
assert.equal(didLogSomething, true);
|
|
});
|
|
});
|
|
});
|