Merge from master

This commit is contained in:
Raj Musuku
2019-02-21 17:56:04 -08:00
parent 5a146e34fa
commit 666ae11639
11482 changed files with 119352 additions and 255574 deletions

View File

@@ -3,10 +3,8 @@
* 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 { URI } from 'vs/base/common/uri';
import { originalFSPath } from 'vs/workbench/api/node/extHost.api.impl';
suite('ExtHost API', function () {

View File

@@ -3,13 +3,10 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { setUnexpectedErrorHandler, errorHandler } from 'vs/base/common/errors';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import URI from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { URI } from 'vs/base/common/uri';
import * as types from 'vs/workbench/api/node/extHostTypes';
import { TextModel as EditorModel } from 'vs/editor/common/model/textModel';
import { TestRPCProtocol } from './testRPCProtocol';
@@ -33,6 +30,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import 'vs/workbench/parts/search/electron-browser/search.contribution';
import { NullLogService } from 'vs/platform/log/common/log';
import { ITextModel } from 'vs/editor/common/model';
import { nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
const defaultSelector = { scheme: 'far' };
const model: ITextModel = EditorModel.createFromString(
@@ -52,6 +50,10 @@ let commands: ExtHostCommands;
let disposables: vscode.Disposable[] = [];
let originalErrorHandler: (e: any) => any;
function assertRejects(fn: () => Thenable<any>, message: string = 'Expected rejection') {
return fn().then(() => assert.ok(false, message), _err => assert.ok(true));
}
suite('ExtHostLanguageFeatureCommands', function () {
suiteSetup(() => {
@@ -75,10 +77,10 @@ suite('ExtHostLanguageFeatureCommands', function () {
_serviceBrand: undefined,
executeCommand(id: string, args: any): any {
if (!CommandsRegistry.getCommands()[id]) {
return TPromise.wrapError(new Error(id + ' NOT known'));
return Promise.reject(new Error(id + ' NOT known'));
}
let { handler } = CommandsRegistry.getCommands()[id];
return TPromise.as(instantiationService.invokeFunction(handler, args));
return Promise.resolve(instantiationService.invokeFunction(handler, args));
}
});
instantiationService.stub(IMarkerService, new MarkerService());
@@ -147,20 +149,17 @@ suite('ExtHostLanguageFeatureCommands', function () {
test('WorkspaceSymbols, invalid arguments', function () {
let promises = [
commands.executeCommand('vscode.executeWorkspaceSymbolProvider'),
commands.executeCommand('vscode.executeWorkspaceSymbolProvider', null),
commands.executeCommand('vscode.executeWorkspaceSymbolProvider', undefined),
commands.executeCommand('vscode.executeWorkspaceSymbolProvider', true)
assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider')),
assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider', null)),
assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider', undefined)),
assertRejects(() => commands.executeCommand('vscode.executeWorkspaceSymbolProvider', true))
];
return TPromise.join(<any[]>promises).then(undefined, (err: any[]) => {
assert.equal(err.length, 4);
});
return Promise.all(promises);
});
test('WorkspaceSymbols, back and forth', function () {
disposables.push(extHost.registerWorkspaceSymbolProvider(<vscode.WorkspaceSymbolProvider>{
disposables.push(extHost.registerWorkspaceSymbolProvider(nullExtensionDescription, <vscode.WorkspaceSymbolProvider>{
provideWorkspaceSymbols(query): any {
return [
new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first')),
@@ -169,7 +168,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
}
}));
disposables.push(extHost.registerWorkspaceSymbolProvider(<vscode.WorkspaceSymbolProvider>{
disposables.push(extHost.registerWorkspaceSymbolProvider(nullExtensionDescription, <vscode.WorkspaceSymbolProvider>{
provideWorkspaceSymbols(query): any {
return [
new types.SymbolInformation(query, types.SymbolKind.Array, new types.Range(0, 0, 1, 1), URI.parse('far://testing/first'))
@@ -192,7 +191,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
test('executeWorkspaceSymbolProvider should accept empty string, #39522', async function () {
disposables.push(extHost.registerWorkspaceSymbolProvider({
disposables.push(extHost.registerWorkspaceSymbolProvider(nullExtensionDescription, {
provideWorkspaceSymbols(query) {
return [new types.SymbolInformation('hello', types.SymbolKind.Array, new types.Range(0, 0, 0, 0), URI.parse('foo:bar'))];
}
@@ -211,25 +210,23 @@ suite('ExtHostLanguageFeatureCommands', function () {
test('Definition, invalid arguments', function () {
let promises = [
commands.executeCommand('vscode.executeDefinitionProvider'),
commands.executeCommand('vscode.executeDefinitionProvider', null),
commands.executeCommand('vscode.executeDefinitionProvider', undefined),
commands.executeCommand('vscode.executeDefinitionProvider', true, false)
assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider')),
assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider', null)),
assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider', undefined)),
assertRejects(() => commands.executeCommand('vscode.executeDefinitionProvider', true, false))
];
return TPromise.join(<any[]>promises).then(undefined, (err: any[]) => {
assert.equal(err.length, 4);
});
return Promise.all(promises);
});
test('Definition, back and forth', function () {
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(doc: any): any {
return new types.Location(doc.uri, new types.Range(0, 0, 0, 0));
}
}));
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
disposables.push(extHost.registerDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(doc: any): any {
return [
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
@@ -250,29 +247,57 @@ suite('ExtHostLanguageFeatureCommands', function () {
});
});
// --- declaration
test('Declaration, back and forth', function () {
disposables.push(extHost.registerDeclarationProvider(nullExtensionDescription, defaultSelector, <vscode.DeclarationProvider>{
provideDeclaration(doc: any): any {
return new types.Location(doc.uri, new types.Range(0, 0, 0, 0));
}
}));
disposables.push(extHost.registerDeclarationProvider(nullExtensionDescription, defaultSelector, <vscode.DeclarationProvider>{
provideDeclaration(doc: any): any {
return [
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
];
}
}));
return rpcProtocol.sync().then(() => {
return commands.executeCommand<vscode.Location[]>('vscode.executeDeclarationProvider', model.uri, new types.Position(0, 0)).then(values => {
assert.equal(values.length, 4);
for (let v of values) {
assert.ok(v.uri instanceof URI);
assert.ok(v.range instanceof types.Range);
}
});
});
});
// --- type definition
test('Type Definition, invalid arguments', function () {
const promises = [
commands.executeCommand('vscode.executeTypeDefinitionProvider'),
commands.executeCommand('vscode.executeTypeDefinitionProvider', null),
commands.executeCommand('vscode.executeTypeDefinitionProvider', undefined),
commands.executeCommand('vscode.executeTypeDefinitionProvider', true, false)
assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider')),
assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider', null)),
assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider', undefined)),
assertRejects(() => commands.executeCommand('vscode.executeTypeDefinitionProvider', true, false))
];
return TPromise.join(<any[]>promises).then(undefined, (err: any[]) => {
assert.equal(err.length, 4);
});
return Promise.all(promises);
});
test('Type Definition, back and forth', function () {
disposables.push(extHost.registerTypeDefinitionProvider(defaultSelector, <vscode.TypeDefinitionProvider>{
disposables.push(extHost.registerTypeDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.TypeDefinitionProvider>{
provideTypeDefinition(doc: any): any {
return new types.Location(doc.uri, new types.Range(0, 0, 0, 0));
}
}));
disposables.push(extHost.registerTypeDefinitionProvider(defaultSelector, <vscode.TypeDefinitionProvider>{
disposables.push(extHost.registerTypeDefinitionProvider(nullExtensionDescription, defaultSelector, <vscode.TypeDefinitionProvider>{
provideTypeDefinition(doc: any): any {
return [
new types.Location(doc.uri, new types.Range(0, 0, 0, 0)),
@@ -297,7 +322,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
test('reference search, back and forth', function () {
disposables.push(extHost.registerReferenceProvider(defaultSelector, <vscode.ReferenceProvider>{
disposables.push(extHost.registerReferenceProvider(nullExtensionDescription, defaultSelector, <vscode.ReferenceProvider>{
provideReferences(doc: any) {
return [
new types.Location(URI.parse('some:uri/path'), new types.Range(0, 1, 0, 5))
@@ -319,7 +344,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
// --- outline
test('Outline, back and forth', function () {
disposables.push(extHost.registerDocumentSymbolProvider(defaultSelector, <vscode.DocumentSymbolProvider>{
disposables.push(extHost.registerDocumentSymbolProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentSymbolProvider>{
provideDocumentSymbols(): any {
return [
new types.SymbolInformation('testing1', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0)),
@@ -340,10 +365,40 @@ suite('ExtHostLanguageFeatureCommands', function () {
});
});
test('vscode.executeDocumentSymbolProvider command only returns SymbolInformation[] rather than DocumentSymbol[] #57984', function () {
disposables.push(extHost.registerDocumentSymbolProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentSymbolProvider>{
provideDocumentSymbols(): any {
return [
new types.SymbolInformation('SymbolInformation', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0))
];
}
}));
disposables.push(extHost.registerDocumentSymbolProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentSymbolProvider>{
provideDocumentSymbols(): any {
let root = new types.DocumentSymbol('DocumentSymbol', 'DocumentSymbol#detail', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0), new types.Range(1, 0, 1, 0));
root.children = [new types.DocumentSymbol('DocumentSymbol#child', 'DocumentSymbol#detail#child', types.SymbolKind.Enum, new types.Range(1, 0, 1, 0), new types.Range(1, 0, 1, 0))];
return [root];
}
}));
return rpcProtocol.sync().then(() => {
return commands.executeCommand<(vscode.SymbolInformation & vscode.DocumentSymbol)[]>('vscode.executeDocumentSymbolProvider', model.uri).then(values => {
assert.equal(values.length, 2);
let [first, second] = values;
assert.ok(first instanceof types.SymbolInformation);
assert.ok(!(first instanceof types.DocumentSymbol));
assert.ok(second instanceof types.SymbolInformation);
assert.equal(first.name, 'DocumentSymbol');
assert.equal(first.children.length, 1);
assert.equal(second.name, 'SymbolInformation');
});
});
});
// --- suggest
test('Suggest, back and forth', function () {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(doc, pos): any {
let a = new types.CompletionItem('item1');
let b = new types.CompletionItem('item2');
@@ -401,7 +456,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
});
test('Suggest, return CompletionList !array', function () {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
let a = new types.CompletionItem('item1');
let b = new types.CompletionItem('item2');
@@ -421,7 +476,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
let resolveCount = 0;
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
let a = new types.CompletionItem('item1');
let b = new types.CompletionItem('item2');
@@ -451,7 +506,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
});
test('"vscode.executeCompletionItemProvider" doesnot return a preselect field #53749', async function () {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
let a = new types.CompletionItem('item1');
a.preselect = true;
@@ -482,10 +537,37 @@ suite('ExtHostLanguageFeatureCommands', function () {
assert.equal(d.preselect, undefined);
});
test('executeCompletionItemProvider doesn\'t capture commitCharacters #58228', async function () {
disposables.push(extHost.registerCompletionItemProvider(nullExtensionDescription, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
let a = new types.CompletionItem('item1');
a.commitCharacters = ['a', 'b'];
let b = new types.CompletionItem('item2');
return new types.CompletionList([a, b], false);
}
}, []));
await rpcProtocol.sync();
let list = await commands.executeCommand<vscode.CompletionList>(
'vscode.executeCompletionItemProvider',
model.uri,
new types.Position(0, 4),
undefined
);
assert.ok(list instanceof types.CompletionList);
assert.equal(list.items.length, 2);
let [a, b] = list.items;
assert.deepEqual(a.commitCharacters, ['a', 'b']);
assert.equal(b.commitCharacters, undefined);
});
// --- quickfix
test('QuickFix, back and forth', function () {
disposables.push(extHost.registerCodeActionProvider(defaultSelector, {
disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {
provideCodeActions(): vscode.Command[] {
return [{ command: 'testing', title: 'Title', arguments: [1, 2, true] }];
}
@@ -503,7 +585,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
});
test('vscode.executeCodeActionProvider results seem to be missing their `command` property #45124', function () {
disposables.push(extHost.registerCodeActionProvider(defaultSelector, {
disposables.push(extHost.registerCodeActionProvider(nullExtensionDescription, defaultSelector, {
provideCodeActions(document, range): vscode.CodeAction[] {
return [{
command: {
@@ -541,7 +623,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
big: extHost
};
disposables.push(extHost.registerCodeLensProvider(defaultSelector, <vscode.CodeLensProvider>{
disposables.push(extHost.registerCodeLensProvider(nullExtensionDescription, defaultSelector, <vscode.CodeLensProvider>{
provideCodeLenses(): any {
return [new types.CodeLens(new types.Range(0, 0, 1, 1), { title: 'Title', command: 'cmd', arguments: [1, true, complexArg] })];
}
@@ -565,7 +647,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
let resolveCount = 0;
disposables.push(extHost.registerCodeLensProvider(defaultSelector, <vscode.CodeLensProvider>{
disposables.push(extHost.registerCodeLensProvider(nullExtensionDescription, defaultSelector, <vscode.CodeLensProvider>{
provideCodeLenses(): any {
return [
new types.CodeLens(new types.Range(0, 0, 1, 1)),
@@ -597,7 +679,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
test('Links, back and forth', function () {
disposables.push(extHost.registerDocumentLinkProvider(defaultSelector, <vscode.DocumentLinkProvider>{
disposables.push(extHost.registerDocumentLinkProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentLinkProvider>{
provideDocumentLinks(): any {
return [new types.DocumentLink(new types.Range(0, 0, 0, 20), URI.parse('foo:bar'))];
}
@@ -620,7 +702,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
test('Color provider', function () {
disposables.push(extHost.registerColorProvider(defaultSelector, <vscode.DocumentColorProvider>{
disposables.push(extHost.registerColorProvider(nullExtensionDescription, defaultSelector, <vscode.DocumentColorProvider>{
provideDocumentColors(): vscode.ColorInformation[] {
return [new types.ColorInformation(new types.Range(0, 0, 0, 20), new types.Color(0.1, 0.2, 0.3, 0.4))];
},
@@ -670,7 +752,7 @@ suite('ExtHostLanguageFeatureCommands', function () {
test('"TypeError: e.onCancellationRequested is not a function" calling hover provider in Insiders #54174', function () {
disposables.push(extHost.registerHoverProvider(defaultSelector, <vscode.HoverProvider>{
disposables.push(extHost.registerHoverProvider(nullExtensionDescription, defaultSelector, <vscode.HoverProvider>{
provideHover(): any {
return new types.Hover('fofofofo');
}
@@ -683,4 +765,20 @@ suite('ExtHostLanguageFeatureCommands', function () {
});
});
});
// --- selection ranges
test('Links, back and forth', async function () {
disposables.push(extHost.registerSelectionRangeProvider(nullExtensionDescription, defaultSelector, <vscode.SelectionRangeProvider>{
provideSelectionRanges() {
return [new types.Range(0, 10, 0, 18), new types.Range(0, 2, 0, 20)];
}
}));
await rpcProtocol.sync();
let value = await commands.executeCommand<vscode.DocumentLink[]>('vscode.executeSelectionRangeProvider', model.uri, new types.Position(0, 10));
assert.ok(value.length >= 2);
});
});

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { ExtHostCommands } from 'vs/workbench/api/node/extHostCommands';
import { MainThreadCommandsShape } from 'vs/workbench/api/node/extHost.protocol';

View File

@@ -3,14 +3,11 @@
* 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 { URI } from 'vs/base/common/uri';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
import { MainThreadConfigurationShape, IConfigurationInitData } from 'vs/workbench/api/node/extHost.protocol';
import { TPromise } from 'vs/base/common/winjs.base';
import { ConfigurationModel } from 'vs/platform/configuration/common/configurationModels';
import { TestRPCProtocol } from './testRPCProtocol';
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
@@ -18,14 +15,15 @@ import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/
import { ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { NullLogService } from 'vs/platform/log/common/log';
import { assign } from 'vs/base/common/objects';
import { Counter } from 'vs/base/common/numbers';
suite('ExtHostConfiguration', function () {
class RecordingShape extends mock<MainThreadConfigurationShape>() {
lastArgs: [ConfigurationTarget, string, any];
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): TPromise<void> {
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): Promise<void> {
this.lastArgs = [target, key, value];
return TPromise.as(void 0);
return Promise.resolve(void 0);
}
}
@@ -33,7 +31,7 @@ suite('ExtHostConfiguration', function () {
if (!shape) {
shape = new class extends mock<MainThreadConfigurationShape>() { };
}
return new ExtHostConfiguration(shape, new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService()), createConfigurationData(contents));
return new ExtHostConfiguration(shape, new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService(), new Counter()), createConfigurationData(contents));
}
function createConfigurationData(contents: any): IConfigurationInitData {
@@ -64,7 +62,7 @@ suite('ExtHostConfiguration', function () {
assert.equal(extHostConfig.getConfiguration('search').has('exclude.**/node_modules'), true);
});
test('has/get', function () {
test('has/get', () => {
const all = createExtHostConfiguration({
'farboo': {
@@ -267,7 +265,7 @@ suite('ExtHostConfiguration', function () {
test('inspect in no workspace context', function () {
const testObject = new ExtHostConfiguration(
new class extends mock<MainThreadConfigurationShape>() { },
new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService()),
new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService(), new Counter()),
{
defaults: new ConfigurationModel({
'editor': {
@@ -314,7 +312,7 @@ suite('ExtHostConfiguration', function () {
'id': 'foo',
'folders': [aWorkspaceFolder(URI.file('foo'), 0)],
'name': 'foo'
}, new NullLogService()),
}, new NullLogService(), new Counter()),
{
defaults: new ConfigurationModel({
'editor': {
@@ -388,7 +386,7 @@ suite('ExtHostConfiguration', function () {
'id': 'foo',
'folders': [aWorkspaceFolder(firstRoot, 0), aWorkspaceFolder(secondRoot, 1)],
'name': 'foo'
}, new NullLogService()),
}, new NullLogService(), new Counter()),
{
defaults: new ConfigurationModel({
'editor': {
@@ -577,8 +575,8 @@ suite('ExtHostConfiguration', function () {
test('update/error-state not OK', function () {
const shape = new class extends mock<MainThreadConfigurationShape>() {
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): TPromise<any> {
return TPromise.wrapError(new Error('Unknown Key')); // something !== OK
$updateConfigurationOption(target: ConfigurationTarget, key: string, value: any): Promise<any> {
return Promise.reject(new Error('Unknown Key')); // something !== OK
}
};
@@ -597,7 +595,7 @@ suite('ExtHostConfiguration', function () {
'id': 'foo',
'folders': [workspaceFolder],
'name': 'foo'
}, new NullLogService()),
}, new NullLogService(), new Counter()),
createConfigurationData({
'farboo': {
'config': false,

View File

@@ -3,10 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import URI, { UriComponents } from 'vs/base/common/uri';
import { URI, UriComponents } from 'vs/base/common/uri';
import { DiagnosticCollection, ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import { Diagnostic, DiagnosticSeverity, Range, DiagnosticRelatedInformation, Location } from 'vs/workbench/api/node/extHostTypes';
import { MainThreadDiagnosticsShape, IMainContext } from 'vs/workbench/api/node/extHost.protocol';
@@ -25,7 +23,7 @@ suite('ExtHostDiagnostics', () => {
}
}
test('disposeCheck', function () {
test('disposeCheck', () => {
const collection = new DiagnosticCollection('test', 'test', 100, new DiagnosticsShape(), new Emitter());
@@ -190,6 +188,31 @@ suite('ExtHostDiagnostics', () => {
lastEntries = undefined;
});
test('don\'t send message when not making a change', function () {
let changeCount = 0;
let eventCount = 0;
const emitter = new Emitter<any>();
emitter.event(_ => eventCount += 1);
const collection = new DiagnosticCollection('test', 'test', 100, new class extends DiagnosticsShape {
$changeMany() {
changeCount += 1;
}
}, emitter);
let uri = URI.parse('sc:hightower');
let diag = new Diagnostic(new Range(0, 0, 0, 1), 'ffff');
collection.set(uri, [diag]);
assert.equal(changeCount, 1);
assert.equal(eventCount, 1);
collection.set(uri, [diag]);
assert.equal(changeCount, 1);
assert.equal(eventCount, 2);
});
test('diagnostics collection, tuples and undefined (small array), #15585', function () {
const collection = new DiagnosticCollection('test', 'test', 100, new DiagnosticsShape(), new Emitter());
@@ -376,4 +399,29 @@ suite('ExtHostDiagnostics', () => {
assert.equal(ownerHistory[0], 'foo');
assert.equal(ownerHistory[1], 'foo0');
});
test('Error updating diagnostics from extension #60394', function () {
let callCount = 0;
let collection = new DiagnosticCollection('ddd', 'test', 100, new class extends DiagnosticsShape {
$changeMany(owner: string, entries: [UriComponents, IMarkerData[]][]) {
callCount += 1;
}
}, new Emitter<any>());
let array: Diagnostic[] = [];
let diag1 = new Diagnostic(new Range(0, 0, 1, 1), 'Foo');
let diag2 = new Diagnostic(new Range(0, 0, 1, 1), 'Bar');
array.push(diag1, diag2);
collection.set(URI.parse('test:me'), array);
assert.equal(callCount, 1);
collection.set(URI.parse('test:me'), array);
assert.equal(callCount, 1); // equal array
array.push(diag2);
collection.set(URI.parse('test:me'), array);
assert.equal(callCount, 2); // same but un-equal array
});
});

View File

@@ -3,15 +3,12 @@
* 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 { URI } from 'vs/base/common/uri';
import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData';
import { Position } from 'vs/workbench/api/node/extHostTypes';
import { Range } from 'vs/editor/common/core/range';
import { MainThreadDocumentsShape } from 'vs/workbench/api/node/extHost.protocol';
import { TPromise } from 'vs/base/common/winjs.base';
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
@@ -41,7 +38,7 @@ suite('ExtHostDocumentData', () => {
], '\n', 'text', 1, false);
});
test('readonly-ness', function () {
test('readonly-ness', () => {
assert.throws((): void => (data as any).document.uri = null);
assert.throws(() => (data as any).document.fileName = 'foofile');
assert.throws(() => (data as any).document.isDirty = false);
@@ -56,7 +53,7 @@ suite('ExtHostDocumentData', () => {
$trySaveDocument(uri: URI) {
assert.ok(!saved);
saved = uri;
return TPromise.as(true);
return Promise.resolve(true);
}
}, URI.parse('foo:bar'), [], '\n', 'text', 1, true);
@@ -81,7 +78,7 @@ suite('ExtHostDocumentData', () => {
assert.equal(document.lineAt(0).text, 'This is line one');
});
test('lines', function () {
test('lines', () => {
assert.equal(data.document.lineCount, 4);
@@ -138,7 +135,7 @@ suite('ExtHostDocumentData', () => {
});
test('offsetAt', function () {
test('offsetAt', () => {
assertOffsetAt(0, 0, 0);
assertOffsetAt(0, 1, 1);
assertOffsetAt(0, 16, 16);
@@ -228,7 +225,7 @@ suite('ExtHostDocumentData', () => {
assertOffsetAt(1, 0, 25);
});
test('positionAt', function () {
test('positionAt', () => {
assertPositionAt(0, 0, 0);
assertPositionAt(Number.MIN_VALUE, 0, 0);
assertPositionAt(1, 0, 1);
@@ -242,7 +239,7 @@ suite('ExtHostDocumentData', () => {
assertPositionAt(Number.MAX_VALUE, 3, 29);
});
test('getWordRangeAtPosition', function () {
test('getWordRangeAtPosition', () => {
data = new ExtHostDocumentData(undefined, URI.file(''), [
'aaaa bbbb+cccc abc'
], '\n', 'text', 1, false);

View File

@@ -2,11 +2,8 @@
* 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 { URI } from 'vs/base/common/uri';
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';
@@ -211,7 +208,7 @@ suite('ExtHostDocumentSaveParticipant', () => {
let sub = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (event) {
event.waitUntil(new TPromise((resolve, reject) => {
event.waitUntil(new Promise((resolve, reject) => {
setTimeout(() => {
try {
assert.throws(() => event.waitUntil(timeout(10)));
@@ -248,7 +245,7 @@ suite('ExtHostDocumentSaveParticipant', () => {
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, mainThreadEditors);
let sub1 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
e.waitUntil(TPromise.wrapError(new Error('dddd')));
e.waitUntil(Promise.reject(new Error('dddd')));
});
let event: vscode.TextDocumentWillSaveEvent;
@@ -269,13 +266,13 @@ suite('ExtHostDocumentSaveParticipant', () => {
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
$tryApplyWorkspaceEdit(_edits: WorkspaceEditDto) {
dto = _edits;
return TPromise.as(true);
return Promise.resolve(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)]));
e.waitUntil(Promise.resolve([TextEdit.insert(new Position(0, 0), 'bar')]));
e.waitUntil(Promise.resolve([TextEdit.setEndOfLine(EndOfLine.CRLF)]));
});
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(() => {
@@ -293,7 +290,7 @@ suite('ExtHostDocumentSaveParticipant', () => {
const participant = new ExtHostDocumentSaveParticipant(nullLogService, documents, new class extends mock<MainThreadTextEditorsShape>() {
$tryApplyWorkspaceEdit(_edits: WorkspaceEditDto) {
edits = _edits;
return TPromise.as(true);
return Promise.resolve(true);
}
});
@@ -311,7 +308,7 @@ suite('ExtHostDocumentSaveParticipant', () => {
versionId: 2
}, true);
e.waitUntil(TPromise.as([TextEdit.insert(new Position(0, 0), 'bar')]));
e.waitUntil(Promise.resolve([TextEdit.insert(new Position(0, 0), 'bar')]));
});
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {
@@ -348,7 +345,7 @@ suite('ExtHostDocumentSaveParticipant', () => {
}
}
return TPromise.as(true);
return Promise.resolve(true);
}
});
@@ -359,7 +356,7 @@ suite('ExtHostDocumentSaveParticipant', () => {
assert.equal(document.version, 1);
assert.equal(document.getText(), 'foo');
e.waitUntil(TPromise.as([TextEdit.insert(new Position(0, 0), 'bar')]));
e.waitUntil(Promise.resolve([TextEdit.insert(new Position(0, 0), 'bar')]));
});
let sub2 = participant.getOnWillSaveTextDocumentEvent(nullExtensionDescription)(function (e) {
@@ -367,7 +364,7 @@ suite('ExtHostDocumentSaveParticipant', () => {
assert.equal(document.version, 2);
assert.equal(document.getText(), 'barfoo');
e.waitUntil(TPromise.as([TextEdit.insert(new Position(0, 0), 'bar')]));
e.waitUntil(Promise.resolve([TextEdit.insert(new Position(0, 0), 'bar')]));
});
return participant.$participateInSave(resource, SaveReason.EXPLICIT).then(values => {

View File

@@ -3,10 +3,8 @@
* 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 { URI } from 'vs/base/common/uri';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
suite('ExtHostDocumentsAndEditors', () => {

View File

@@ -2,8 +2,6 @@
* 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 { ExtHostFileSystemEventService } from 'vs/workbench/api/node/extHostFileSystemEventService';
import { IMainContext } from 'vs/workbench/api/node/extHost.protocol';

View File

@@ -3,15 +3,13 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { setUnexpectedErrorHandler, errorHandler } from 'vs/base/common/errors';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import * as types from 'vs/workbench/api/node/extHostTypes';
import { TextModel as EditorModel } from 'vs/editor/common/model/textModel';
import { Position as EditorPosition } from 'vs/editor/common/core/position';
import { Position as EditorPosition, Position } from 'vs/editor/common/core/position';
import { Range as EditorRange } from 'vs/editor/common/core/range';
import { TestRPCProtocol } from './testRPCProtocol';
import { IMarkerService } from 'vs/platform/markers/common/markers';
@@ -24,9 +22,9 @@ import { IHeapService } from 'vs/workbench/api/electron-browser/mainThreadHeapSe
import { ExtHostDocuments } from 'vs/workbench/api/node/extHostDocuments';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
import { getDocumentSymbols } from 'vs/editor/contrib/quickOpen/quickOpen';
import { DocumentSymbolProviderRegistry, DocumentHighlightKind, Hover, ResourceTextEdit } from 'vs/editor/common/modes';
import * as modes from 'vs/editor/common/modes';
import { getCodeLensData } from 'vs/editor/contrib/codelens/codelens';
import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition } from 'vs/editor/contrib/goToDefinition/goToDefinition';
import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition } from 'vs/editor/contrib/goToDefinition/goToDefinition';
import { getHover } from 'vs/editor/contrib/hover/getHover';
import { getOccurrencesAtPosition } from 'vs/editor/contrib/wordHighlighter/wordHighlighter';
import { provideReferences } from 'vs/editor/contrib/referenceSearch/referenceSearch';
@@ -37,7 +35,6 @@ import { provideSignatureHelp } from 'vs/editor/contrib/parameterHints/provideSi
import { provideSuggestionItems } from 'vs/editor/contrib/suggest/suggest';
import { getDocumentFormattingEdits, getDocumentRangeFormattingEdits, getOnTypeFormattingEdits } from 'vs/editor/contrib/format/format';
import { getLinks } from 'vs/editor/contrib/links/getLinks';
import { asWinJsPromise } from 'vs/base/common/async';
import { MainContext, ExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostDiagnostics } from 'vs/workbench/api/node/extHostDiagnostics';
import { ExtHostHeapService } from 'vs/workbench/api/node/extHostHeapService';
@@ -47,6 +44,8 @@ import { NullLogService } from 'vs/platform/log/common/log';
import { ITextModel, EndOfLineSequence } from 'vs/editor/common/model';
import { getColors } from 'vs/editor/contrib/colorPicker/color';
import { CancellationToken } from 'vs/base/common/cancellation';
import { nullExtensionDescription as defaultExtension } from 'vs/workbench/services/extensions/common/extensions';
import { provideSelectionRanges } from 'vs/editor/contrib/smartSelect/smartSelect';
const defaultSelector = { scheme: 'far' };
const model: ITextModel = EditorModel.createFromString(
@@ -134,15 +133,15 @@ suite('ExtHostLanguageFeatures', function () {
// --- outline
test('DocumentSymbols, register/deregister', function () {
assert.equal(DocumentSymbolProviderRegistry.all(model).length, 0);
let d1 = extHost.registerDocumentSymbolProvider(defaultSelector, <vscode.DocumentSymbolProvider>{
assert.equal(modes.DocumentSymbolProviderRegistry.all(model).length, 0);
let d1 = extHost.registerDocumentSymbolProvider(defaultExtension, defaultSelector, <vscode.DocumentSymbolProvider>{
provideDocumentSymbols() {
return <vscode.SymbolInformation[]>[];
}
});
return rpcProtocol.sync().then(() => {
assert.equal(DocumentSymbolProviderRegistry.all(model).length, 1);
assert.equal(modes.DocumentSymbolProviderRegistry.all(model).length, 1);
d1.dispose();
return rpcProtocol.sync();
});
@@ -150,12 +149,12 @@ suite('ExtHostLanguageFeatures', function () {
});
test('DocumentSymbols, evil provider', function () {
disposables.push(extHost.registerDocumentSymbolProvider(defaultSelector, <vscode.DocumentSymbolProvider>{
disposables.push(extHost.registerDocumentSymbolProvider(defaultExtension, defaultSelector, <vscode.DocumentSymbolProvider>{
provideDocumentSymbols(): any {
throw new Error('evil document symbol provider');
}
}));
disposables.push(extHost.registerDocumentSymbolProvider(defaultSelector, <vscode.DocumentSymbolProvider>{
disposables.push(extHost.registerDocumentSymbolProvider(defaultExtension, defaultSelector, <vscode.DocumentSymbolProvider>{
provideDocumentSymbols(): any {
return [new types.SymbolInformation('test', types.SymbolKind.Field, new types.Range(0, 0, 0, 0))];
}
@@ -163,14 +162,14 @@ suite('ExtHostLanguageFeatures', function () {
return rpcProtocol.sync().then(() => {
return getDocumentSymbols(model).then(value => {
return getDocumentSymbols(model, true, CancellationToken.None).then(value => {
assert.equal(value.length, 1);
});
});
});
test('DocumentSymbols, data conversion', function () {
disposables.push(extHost.registerDocumentSymbolProvider(defaultSelector, <vscode.DocumentSymbolProvider>{
disposables.push(extHost.registerDocumentSymbolProvider(defaultExtension, defaultSelector, <vscode.DocumentSymbolProvider>{
provideDocumentSymbols(): any {
return [new types.SymbolInformation('test', types.SymbolKind.Field, new types.Range(0, 0, 0, 0))];
}
@@ -178,7 +177,7 @@ suite('ExtHostLanguageFeatures', function () {
return rpcProtocol.sync().then(() => {
return getDocumentSymbols(model).then(value => {
return getDocumentSymbols(model, true, CancellationToken.None).then(value => {
assert.equal(value.length, 1);
let entry = value[0];
@@ -192,12 +191,12 @@ suite('ExtHostLanguageFeatures', function () {
test('CodeLens, evil provider', function () {
disposables.push(extHost.registerCodeLensProvider(defaultSelector, <vscode.CodeLensProvider>{
disposables.push(extHost.registerCodeLensProvider(defaultExtension, defaultSelector, <vscode.CodeLensProvider>{
provideCodeLenses(): any {
throw new Error('evil');
}
}));
disposables.push(extHost.registerCodeLensProvider(defaultSelector, <vscode.CodeLensProvider>{
disposables.push(extHost.registerCodeLensProvider(defaultExtension, defaultSelector, <vscode.CodeLensProvider>{
provideCodeLenses() {
return [new types.CodeLens(new types.Range(0, 0, 0, 0))];
}
@@ -212,7 +211,7 @@ suite('ExtHostLanguageFeatures', function () {
test('CodeLens, do not resolve a resolved lens', function () {
disposables.push(extHost.registerCodeLensProvider(defaultSelector, <vscode.CodeLensProvider>{
disposables.push(extHost.registerCodeLensProvider(defaultExtension, defaultSelector, <vscode.CodeLensProvider>{
provideCodeLenses(): any {
return [new types.CodeLens(
new types.Range(0, 0, 0, 0),
@@ -228,10 +227,7 @@ suite('ExtHostLanguageFeatures', function () {
return getCodeLensData(model, CancellationToken.None).then(value => {
assert.equal(value.length, 1);
let data = value[0];
return asWinJsPromise((token) => {
return data.provider.resolveCodeLens(model, data.symbol, token);
}).then(symbol => {
return Promise.resolve(data.provider.resolveCodeLens(model, data.symbol, CancellationToken.None)).then(symbol => {
assert.equal(symbol.command.id, 'id');
assert.equal(symbol.command.title, 'Title');
});
@@ -241,7 +237,7 @@ suite('ExtHostLanguageFeatures', function () {
test('CodeLens, missing command', function () {
disposables.push(extHost.registerCodeLensProvider(defaultSelector, <vscode.CodeLensProvider>{
disposables.push(extHost.registerCodeLensProvider(defaultExtension, defaultSelector, <vscode.CodeLensProvider>{
provideCodeLenses() {
return [new types.CodeLens(new types.Range(0, 0, 0, 0))];
}
@@ -253,9 +249,7 @@ suite('ExtHostLanguageFeatures', function () {
assert.equal(value.length, 1);
let data = value[0];
return asWinJsPromise((token) => {
return data.provider.resolveCodeLens(model, data.symbol, token);
}).then(symbol => {
return Promise.resolve(data.provider.resolveCodeLens(model, data.symbol, CancellationToken.None)).then(symbol => {
assert.equal(symbol.command.id, 'missing');
assert.equal(symbol.command.title, '<<MISSING COMMAND>>');
@@ -268,7 +262,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Definition, data conversion', function () {
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
disposables.push(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(): any {
return [new types.Location(model.uri, new types.Range(1, 2, 3, 4))];
}
@@ -276,7 +270,7 @@ suite('ExtHostLanguageFeatures', function () {
return rpcProtocol.sync().then(() => {
return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => {
return getDefinitionsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
assert.equal(value.length, 1);
let [entry] = value;
assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 });
@@ -287,12 +281,12 @@ suite('ExtHostLanguageFeatures', function () {
test('Definition, one or many', function () {
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
disposables.push(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(): any {
return [new types.Location(model.uri, new types.Range(1, 1, 1, 1))];
}
}));
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
disposables.push(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(): any {
return new types.Location(model.uri, new types.Range(1, 1, 1, 1));
}
@@ -300,7 +294,7 @@ suite('ExtHostLanguageFeatures', function () {
return rpcProtocol.sync().then(() => {
return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => {
return getDefinitionsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
assert.equal(value.length, 2);
});
});
@@ -308,13 +302,13 @@ suite('ExtHostLanguageFeatures', function () {
test('Definition, registration order', function () {
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
disposables.push(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(): any {
return [new types.Location(URI.parse('far://first'), new types.Range(2, 3, 4, 5))];
}
}));
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
disposables.push(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(): any {
return new types.Location(URI.parse('far://second'), new types.Range(1, 2, 3, 4));
}
@@ -322,7 +316,7 @@ suite('ExtHostLanguageFeatures', function () {
return rpcProtocol.sync().then(() => {
return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => {
return getDefinitionsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
assert.equal(value.length, 2);
// let [first, second] = value;
@@ -334,12 +328,12 @@ suite('ExtHostLanguageFeatures', function () {
test('Definition, evil provider', function () {
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
disposables.push(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(): any {
throw new Error('evil provider');
}
}));
disposables.push(extHost.registerDefinitionProvider(defaultSelector, <vscode.DefinitionProvider>{
disposables.push(extHost.registerDefinitionProvider(defaultExtension, defaultSelector, <vscode.DefinitionProvider>{
provideDefinition(): any {
return new types.Location(model.uri, new types.Range(1, 1, 1, 1));
}
@@ -347,24 +341,45 @@ suite('ExtHostLanguageFeatures', function () {
return rpcProtocol.sync().then(() => {
return getDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => {
return getDefinitionsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
assert.equal(value.length, 1);
});
});
});
// -- declaration
test('Declaration, data conversion', function () {
disposables.push(extHost.registerDeclarationProvider(defaultExtension, defaultSelector, <vscode.DeclarationProvider>{
provideDeclaration(): any {
return [new types.Location(model.uri, new types.Range(1, 2, 3, 4))];
}
}));
return rpcProtocol.sync().then(() => {
return getDeclarationsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
assert.equal(value.length, 1);
let [entry] = value;
assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 });
assert.equal(entry.uri.toString(), model.uri.toString());
});
});
});
// --- implementation
test('Implementation, data conversion', function () {
disposables.push(extHost.registerImplementationProvider(defaultSelector, <vscode.ImplementationProvider>{
disposables.push(extHost.registerImplementationProvider(defaultExtension, defaultSelector, <vscode.ImplementationProvider>{
provideImplementation(): any {
return [new types.Location(model.uri, new types.Range(1, 2, 3, 4))];
}
}));
return rpcProtocol.sync().then(() => {
return getImplementationsAtPosition(model, new EditorPosition(1, 1)).then(value => {
return getImplementationsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
assert.equal(value.length, 1);
let [entry] = value;
assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 });
@@ -377,14 +392,14 @@ suite('ExtHostLanguageFeatures', function () {
test('Type Definition, data conversion', function () {
disposables.push(extHost.registerTypeDefinitionProvider(defaultSelector, <vscode.TypeDefinitionProvider>{
disposables.push(extHost.registerTypeDefinitionProvider(defaultExtension, defaultSelector, <vscode.TypeDefinitionProvider>{
provideTypeDefinition(): any {
return [new types.Location(model.uri, new types.Range(1, 2, 3, 4))];
}
}));
return rpcProtocol.sync().then(() => {
return getTypeDefinitionsAtPosition(model, new EditorPosition(1, 1)).then(value => {
return getTypeDefinitionsAtPosition(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
assert.equal(value.length, 1);
let [entry] = value;
assert.deepEqual(entry.range, { startLineNumber: 2, startColumn: 3, endLineNumber: 4, endColumn: 5 });
@@ -397,7 +412,7 @@ suite('ExtHostLanguageFeatures', function () {
test('HoverProvider, word range at pos', function () {
disposables.push(extHost.registerHoverProvider(defaultSelector, <vscode.HoverProvider>{
disposables.push(extHost.registerHoverProvider(defaultExtension, defaultSelector, <vscode.HoverProvider>{
provideHover(): any {
return new types.Hover('Hello');
}
@@ -415,7 +430,7 @@ suite('ExtHostLanguageFeatures', function () {
test('HoverProvider, given range', function () {
disposables.push(extHost.registerHoverProvider(defaultSelector, <vscode.HoverProvider>{
disposables.push(extHost.registerHoverProvider(defaultExtension, defaultSelector, <vscode.HoverProvider>{
provideHover(): any {
return new types.Hover('Hello', new types.Range(3, 0, 8, 7));
}
@@ -433,14 +448,14 @@ suite('ExtHostLanguageFeatures', function () {
test('HoverProvider, registration order', function () {
disposables.push(extHost.registerHoverProvider(defaultSelector, <vscode.HoverProvider>{
disposables.push(extHost.registerHoverProvider(defaultExtension, defaultSelector, <vscode.HoverProvider>{
provideHover(): any {
return new types.Hover('registered first');
}
}));
disposables.push(extHost.registerHoverProvider(defaultSelector, <vscode.HoverProvider>{
disposables.push(extHost.registerHoverProvider(defaultExtension, defaultSelector, <vscode.HoverProvider>{
provideHover(): any {
return new types.Hover('registered second');
}
@@ -449,7 +464,7 @@ suite('ExtHostLanguageFeatures', function () {
return rpcProtocol.sync().then(() => {
return getHover(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
assert.equal(value.length, 2);
let [first, second] = value as Hover[];
let [first, second] = value as modes.Hover[];
assert.equal(first.contents[0].value, 'registered second');
assert.equal(second.contents[0].value, 'registered first');
});
@@ -459,12 +474,12 @@ suite('ExtHostLanguageFeatures', function () {
test('HoverProvider, evil provider', function () {
disposables.push(extHost.registerHoverProvider(defaultSelector, <vscode.HoverProvider>{
disposables.push(extHost.registerHoverProvider(defaultExtension, defaultSelector, <vscode.HoverProvider>{
provideHover(): any {
throw new Error('evil');
}
}));
disposables.push(extHost.registerHoverProvider(defaultSelector, <vscode.HoverProvider>{
disposables.push(extHost.registerHoverProvider(defaultExtension, defaultSelector, <vscode.HoverProvider>{
provideHover(): any {
return new types.Hover('Hello');
}
@@ -483,7 +498,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Occurrences, data conversion', function () {
disposables.push(extHost.registerDocumentHighlightProvider(defaultSelector, <vscode.DocumentHighlightProvider>{
disposables.push(extHost.registerDocumentHighlightProvider(defaultExtension, defaultSelector, <vscode.DocumentHighlightProvider>{
provideDocumentHighlights(): any {
return [new types.DocumentHighlight(new types.Range(0, 0, 0, 4))];
}
@@ -495,19 +510,19 @@ suite('ExtHostLanguageFeatures', function () {
assert.equal(value.length, 1);
let [entry] = value;
assert.deepEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 });
assert.equal(entry.kind, DocumentHighlightKind.Text);
assert.equal(entry.kind, modes.DocumentHighlightKind.Text);
});
});
});
test('Occurrences, order 1/2', function () {
disposables.push(extHost.registerDocumentHighlightProvider(defaultSelector, <vscode.DocumentHighlightProvider>{
disposables.push(extHost.registerDocumentHighlightProvider(defaultExtension, defaultSelector, <vscode.DocumentHighlightProvider>{
provideDocumentHighlights(): any {
return [];
}
}));
disposables.push(extHost.registerDocumentHighlightProvider('*', <vscode.DocumentHighlightProvider>{
disposables.push(extHost.registerDocumentHighlightProvider(defaultExtension, '*', <vscode.DocumentHighlightProvider>{
provideDocumentHighlights(): any {
return [new types.DocumentHighlight(new types.Range(0, 0, 0, 4))];
}
@@ -519,19 +534,19 @@ suite('ExtHostLanguageFeatures', function () {
assert.equal(value.length, 1);
let [entry] = value;
assert.deepEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 5 });
assert.equal(entry.kind, DocumentHighlightKind.Text);
assert.equal(entry.kind, modes.DocumentHighlightKind.Text);
});
});
});
test('Occurrences, order 2/2', function () {
disposables.push(extHost.registerDocumentHighlightProvider(defaultSelector, <vscode.DocumentHighlightProvider>{
disposables.push(extHost.registerDocumentHighlightProvider(defaultExtension, defaultSelector, <vscode.DocumentHighlightProvider>{
provideDocumentHighlights(): any {
return [new types.DocumentHighlight(new types.Range(0, 0, 0, 2))];
}
}));
disposables.push(extHost.registerDocumentHighlightProvider('*', <vscode.DocumentHighlightProvider>{
disposables.push(extHost.registerDocumentHighlightProvider(defaultExtension, '*', <vscode.DocumentHighlightProvider>{
provideDocumentHighlights(): any {
return [new types.DocumentHighlight(new types.Range(0, 0, 0, 4))];
}
@@ -543,20 +558,20 @@ suite('ExtHostLanguageFeatures', function () {
assert.equal(value.length, 1);
let [entry] = value;
assert.deepEqual(entry.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 3 });
assert.equal(entry.kind, DocumentHighlightKind.Text);
assert.equal(entry.kind, modes.DocumentHighlightKind.Text);
});
});
});
test('Occurrences, evil provider', function () {
disposables.push(extHost.registerDocumentHighlightProvider(defaultSelector, <vscode.DocumentHighlightProvider>{
disposables.push(extHost.registerDocumentHighlightProvider(defaultExtension, defaultSelector, <vscode.DocumentHighlightProvider>{
provideDocumentHighlights(): any {
throw new Error('evil');
}
}));
disposables.push(extHost.registerDocumentHighlightProvider(defaultSelector, <vscode.DocumentHighlightProvider>{
disposables.push(extHost.registerDocumentHighlightProvider(defaultExtension, defaultSelector, <vscode.DocumentHighlightProvider>{
provideDocumentHighlights(): any {
return [new types.DocumentHighlight(new types.Range(0, 0, 0, 4))];
}
@@ -574,13 +589,13 @@ suite('ExtHostLanguageFeatures', function () {
test('References, registration order', function () {
disposables.push(extHost.registerReferenceProvider(defaultSelector, <vscode.ReferenceProvider>{
disposables.push(extHost.registerReferenceProvider(defaultExtension, defaultSelector, <vscode.ReferenceProvider>{
provideReferences(): any {
return [new types.Location(URI.parse('far://register/first'), new types.Range(0, 0, 0, 0))];
}
}));
disposables.push(extHost.registerReferenceProvider(defaultSelector, <vscode.ReferenceProvider>{
disposables.push(extHost.registerReferenceProvider(defaultExtension, defaultSelector, <vscode.ReferenceProvider>{
provideReferences(): any {
return [new types.Location(URI.parse('far://register/second'), new types.Range(0, 0, 0, 0))];
}
@@ -600,7 +615,7 @@ suite('ExtHostLanguageFeatures', function () {
test('References, data conversion', function () {
disposables.push(extHost.registerReferenceProvider(defaultSelector, <vscode.ReferenceProvider>{
disposables.push(extHost.registerReferenceProvider(defaultExtension, defaultSelector, <vscode.ReferenceProvider>{
provideReferences(): any {
return [new types.Location(model.uri, new types.Position(0, 0))];
}
@@ -621,12 +636,12 @@ suite('ExtHostLanguageFeatures', function () {
test('References, evil provider', function () {
disposables.push(extHost.registerReferenceProvider(defaultSelector, <vscode.ReferenceProvider>{
disposables.push(extHost.registerReferenceProvider(defaultExtension, defaultSelector, <vscode.ReferenceProvider>{
provideReferences(): any {
throw new Error('evil');
}
}));
disposables.push(extHost.registerReferenceProvider(defaultSelector, <vscode.ReferenceProvider>{
disposables.push(extHost.registerReferenceProvider(defaultExtension, defaultSelector, <vscode.ReferenceProvider>{
provideReferences(): any {
return [new types.Location(model.uri, new types.Range(0, 0, 0, 0))];
}
@@ -645,7 +660,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Quick Fix, command data conversion', function () {
disposables.push(extHost.registerCodeActionProvider(defaultSelector, {
disposables.push(extHost.registerCodeActionProvider(defaultExtension, defaultSelector, {
provideCodeActions(): vscode.Command[] {
return [
{ command: 'test1', title: 'Testing1' },
@@ -669,7 +684,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Quick Fix, code action data conversion', function () {
disposables.push(extHost.registerCodeActionProvider(defaultSelector, {
disposables.push(extHost.registerCodeActionProvider(defaultExtension, defaultSelector, {
provideCodeActions(): vscode.CodeAction[] {
return [
{
@@ -697,7 +712,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Cannot read property \'id\' of undefined, #29469', function () {
disposables.push(extHost.registerCodeActionProvider(defaultSelector, <vscode.CodeActionProvider>{
disposables.push(extHost.registerCodeActionProvider(defaultExtension, defaultSelector, <vscode.CodeActionProvider>{
provideCodeActions(): any {
return [
undefined,
@@ -716,12 +731,12 @@ suite('ExtHostLanguageFeatures', function () {
test('Quick Fix, evil provider', function () {
disposables.push(extHost.registerCodeActionProvider(defaultSelector, <vscode.CodeActionProvider>{
disposables.push(extHost.registerCodeActionProvider(defaultExtension, defaultSelector, <vscode.CodeActionProvider>{
provideCodeActions(): any {
throw new Error('evil');
}
}));
disposables.push(extHost.registerCodeActionProvider(defaultSelector, <vscode.CodeActionProvider>{
disposables.push(extHost.registerCodeActionProvider(defaultExtension, defaultSelector, <vscode.CodeActionProvider>{
provideCodeActions(): any {
return [<vscode.Command>{ command: 'test', title: 'Testing' }];
}
@@ -738,13 +753,13 @@ suite('ExtHostLanguageFeatures', function () {
test('Navigate types, evil provider', function () {
disposables.push(extHost.registerWorkspaceSymbolProvider(<vscode.WorkspaceSymbolProvider>{
disposables.push(extHost.registerWorkspaceSymbolProvider(defaultExtension, <vscode.WorkspaceSymbolProvider>{
provideWorkspaceSymbols(): any {
throw new Error('evil');
}
}));
disposables.push(extHost.registerWorkspaceSymbolProvider(<vscode.WorkspaceSymbolProvider>{
disposables.push(extHost.registerWorkspaceSymbolProvider(defaultExtension, <vscode.WorkspaceSymbolProvider>{
provideWorkspaceSymbols(): any {
return [new types.SymbolInformation('testing', types.SymbolKind.Array, new types.Range(0, 0, 1, 1))];
}
@@ -766,7 +781,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Rename, evil provider 0/2', function () {
disposables.push(extHost.registerRenameProvider(defaultSelector, <vscode.RenameProvider>{
disposables.push(extHost.registerRenameProvider(defaultExtension, defaultSelector, <vscode.RenameProvider>{
provideRenameEdits(): any {
throw new class Foo { };
}
@@ -784,7 +799,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Rename, evil provider 1/2', function () {
disposables.push(extHost.registerRenameProvider(defaultSelector, <vscode.RenameProvider>{
disposables.push(extHost.registerRenameProvider(defaultExtension, defaultSelector, <vscode.RenameProvider>{
provideRenameEdits(): any {
throw Error('evil');
}
@@ -800,13 +815,13 @@ suite('ExtHostLanguageFeatures', function () {
test('Rename, evil provider 2/2', function () {
disposables.push(extHost.registerRenameProvider('*', <vscode.RenameProvider>{
disposables.push(extHost.registerRenameProvider(defaultExtension, '*', <vscode.RenameProvider>{
provideRenameEdits(): any {
throw Error('evil');
}
}));
disposables.push(extHost.registerRenameProvider(defaultSelector, <vscode.RenameProvider>{
disposables.push(extHost.registerRenameProvider(defaultExtension, defaultSelector, <vscode.RenameProvider>{
provideRenameEdits(): any {
let edit = new types.WorkspaceEdit();
edit.replace(model.uri, new types.Range(0, 0, 0, 0), 'testing');
@@ -824,7 +839,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Rename, ordering', function () {
disposables.push(extHost.registerRenameProvider('*', <vscode.RenameProvider>{
disposables.push(extHost.registerRenameProvider(defaultExtension, '*', <vscode.RenameProvider>{
provideRenameEdits(): any {
let edit = new types.WorkspaceEdit();
edit.replace(model.uri, new types.Range(0, 0, 0, 0), 'testing');
@@ -833,7 +848,7 @@ suite('ExtHostLanguageFeatures', function () {
}
}));
disposables.push(extHost.registerRenameProvider(defaultSelector, <vscode.RenameProvider>{
disposables.push(extHost.registerRenameProvider(defaultExtension, defaultSelector, <vscode.RenameProvider>{
provideRenameEdits(): any {
return;
}
@@ -844,8 +859,8 @@ suite('ExtHostLanguageFeatures', function () {
return rename(model, new EditorPosition(1, 1), 'newName').then(value => {
// least relevant rename provider
assert.equal(value.edits.length, 2);
assert.equal((<ResourceTextEdit>value.edits[0]).edits.length, 1);
assert.equal((<ResourceTextEdit>value.edits[1]).edits.length, 1);
assert.equal((<modes.ResourceTextEdit>value.edits[0]).edits.length, 1);
assert.equal((<modes.ResourceTextEdit>value.edits[1]).edits.length, 1);
});
});
});
@@ -854,13 +869,13 @@ suite('ExtHostLanguageFeatures', function () {
test('Parameter Hints, order', function () {
disposables.push(extHost.registerSignatureHelpProvider(defaultSelector, <vscode.SignatureHelpProvider>{
disposables.push(extHost.registerSignatureHelpProvider(defaultExtension, defaultSelector, <vscode.SignatureHelpProvider>{
provideSignatureHelp(): any {
return undefined;
}
}, []));
disposables.push(extHost.registerSignatureHelpProvider(defaultSelector, <vscode.SignatureHelpProvider>{
disposables.push(extHost.registerSignatureHelpProvider(defaultExtension, defaultSelector, <vscode.SignatureHelpProvider>{
provideSignatureHelp(): vscode.SignatureHelp {
return {
signatures: [],
@@ -872,14 +887,14 @@ suite('ExtHostLanguageFeatures', function () {
return rpcProtocol.sync().then(() => {
return provideSignatureHelp(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
return provideSignatureHelp(model, new EditorPosition(1, 1), { triggerKind: modes.SignatureHelpTriggerKind.Invoke, isRetrigger: false }, CancellationToken.None).then(value => {
assert.ok(value);
});
});
});
test('Parameter Hints, evil provider', function () {
disposables.push(extHost.registerSignatureHelpProvider(defaultSelector, <vscode.SignatureHelpProvider>{
disposables.push(extHost.registerSignatureHelpProvider(defaultExtension, defaultSelector, <vscode.SignatureHelpProvider>{
provideSignatureHelp(): any {
throw new Error('evil');
}
@@ -887,7 +902,7 @@ suite('ExtHostLanguageFeatures', function () {
return rpcProtocol.sync().then(() => {
return provideSignatureHelp(model, new EditorPosition(1, 1), CancellationToken.None).then(value => {
return provideSignatureHelp(model, new EditorPosition(1, 1), { triggerKind: modes.SignatureHelpTriggerKind.Invoke, isRetrigger: false }, CancellationToken.None).then(value => {
assert.equal(value, undefined);
});
});
@@ -897,13 +912,13 @@ suite('ExtHostLanguageFeatures', function () {
test('Suggest, order 1/3', function () {
disposables.push(extHost.registerCompletionItemProvider('*', <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(defaultExtension, '*', <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('testing1')];
}
}, []));
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('testing2')];
}
@@ -919,13 +934,13 @@ suite('ExtHostLanguageFeatures', function () {
test('Suggest, order 2/3', function () {
disposables.push(extHost.registerCompletionItemProvider('*', <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(defaultExtension, '*', <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('weak-selector')]; // weaker selector but result
}
}, []));
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return []; // stronger selector but not a good result;
}
@@ -941,13 +956,13 @@ suite('ExtHostLanguageFeatures', function () {
test('Suggest, order 2/3', function () {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('strong-1')];
}
}, []));
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('strong-2')];
}
@@ -964,13 +979,13 @@ suite('ExtHostLanguageFeatures', function () {
test('Suggest, evil provider', function () {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
throw new Error('evil');
}
}, []));
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return [new types.CompletionItem('testing')];
}
@@ -987,7 +1002,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Suggest, CompletionList', function () {
disposables.push(extHost.registerCompletionItemProvider(defaultSelector, <vscode.CompletionItemProvider>{
disposables.push(extHost.registerCompletionItemProvider(defaultExtension, defaultSelector, <vscode.CompletionItemProvider>{
provideCompletionItems(): any {
return new types.CompletionList([<any>new types.CompletionItem('hello')], true);
}
@@ -1004,14 +1019,14 @@ suite('ExtHostLanguageFeatures', function () {
// --- format
test('Format Doc, data conversion', function () {
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultSelector, <vscode.DocumentFormattingEditProvider>{
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, <vscode.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits(): any {
return [new types.TextEdit(new types.Range(0, 0, 0, 0), 'testing'), types.TextEdit.setEndOfLine(types.EndOfLine.LF)];
}
}));
return rpcProtocol.sync().then(() => {
return getDocumentFormattingEdits(model, { insertSpaces: true, tabSize: 4 }).then(value => {
return getDocumentFormattingEdits(model, { insertSpaces: true, tabSize: 4 }, CancellationToken.None).then(value => {
assert.equal(value.length, 2);
let [first, second] = value;
assert.equal(first.text, 'testing');
@@ -1019,45 +1034,45 @@ suite('ExtHostLanguageFeatures', function () {
assert.equal(second.eol, EndOfLineSequence.LF);
assert.equal(second.text, '');
assert.equal(second.range, undefined);
assert.deepEqual(second.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 1 });
});
});
});
test('Format Doc, evil provider', function () {
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultSelector, <vscode.DocumentFormattingEditProvider>{
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, <vscode.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits(): any {
throw new Error('evil');
}
}));
return rpcProtocol.sync().then(() => {
return getDocumentFormattingEdits(model, { insertSpaces: true, tabSize: 4 });
return getDocumentFormattingEdits(model, { insertSpaces: true, tabSize: 4 }, CancellationToken.None);
});
});
test('Format Doc, order', function () {
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultSelector, <vscode.DocumentFormattingEditProvider>{
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, <vscode.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits(): any {
return undefined;
}
}));
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultSelector, <vscode.DocumentFormattingEditProvider>{
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, <vscode.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits(): any {
return [new types.TextEdit(new types.Range(0, 0, 0, 0), 'testing')];
}
}));
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultSelector, <vscode.DocumentFormattingEditProvider>{
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, <vscode.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits(): any {
return undefined;
}
}));
return rpcProtocol.sync().then(() => {
return getDocumentFormattingEdits(model, { insertSpaces: true, tabSize: 4 }).then(value => {
return getDocumentFormattingEdits(model, { insertSpaces: true, tabSize: 4 }, CancellationToken.None).then(value => {
assert.equal(value.length, 1);
let [first] = value;
assert.equal(first.text, 'testing');
@@ -1067,14 +1082,14 @@ suite('ExtHostLanguageFeatures', function () {
});
test('Format Range, data conversion', function () {
disposables.push(extHost.registerDocumentRangeFormattingEditProvider(defaultSelector, <vscode.DocumentRangeFormattingEditProvider>{
disposables.push(extHost.registerDocumentRangeFormattingEditProvider(defaultExtension, defaultSelector, <vscode.DocumentRangeFormattingEditProvider>{
provideDocumentRangeFormattingEdits(): any {
return [new types.TextEdit(new types.Range(0, 0, 0, 0), 'testing')];
}
}));
return rpcProtocol.sync().then(() => {
return getDocumentRangeFormattingEdits(model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }).then(value => {
return getDocumentRangeFormattingEdits(model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }, CancellationToken.None).then(value => {
assert.equal(value.length, 1);
let [first] = value;
assert.equal(first.text, 'testing');
@@ -1084,23 +1099,23 @@ suite('ExtHostLanguageFeatures', function () {
});
test('Format Range, + format_doc', function () {
disposables.push(extHost.registerDocumentRangeFormattingEditProvider(defaultSelector, <vscode.DocumentRangeFormattingEditProvider>{
disposables.push(extHost.registerDocumentRangeFormattingEditProvider(defaultExtension, defaultSelector, <vscode.DocumentRangeFormattingEditProvider>{
provideDocumentRangeFormattingEdits(): any {
return [new types.TextEdit(new types.Range(0, 0, 0, 0), 'range')];
}
}));
disposables.push(extHost.registerDocumentRangeFormattingEditProvider(defaultSelector, <vscode.DocumentRangeFormattingEditProvider>{
disposables.push(extHost.registerDocumentRangeFormattingEditProvider(defaultExtension, defaultSelector, <vscode.DocumentRangeFormattingEditProvider>{
provideDocumentRangeFormattingEdits(): any {
return [new types.TextEdit(new types.Range(2, 3, 4, 5), 'range2')];
}
}));
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultSelector, <vscode.DocumentFormattingEditProvider>{
disposables.push(extHost.registerDocumentFormattingEditProvider(defaultExtension, defaultSelector, <vscode.DocumentFormattingEditProvider>{
provideDocumentFormattingEdits(): any {
return [new types.TextEdit(new types.Range(0, 0, 1, 1), 'doc')];
}
}));
return rpcProtocol.sync().then(() => {
return getDocumentRangeFormattingEdits(model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }).then(value => {
return getDocumentRangeFormattingEdits(model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }, CancellationToken.None).then(value => {
assert.equal(value.length, 1);
let [first] = value;
assert.equal(first.text, 'range2');
@@ -1113,20 +1128,20 @@ suite('ExtHostLanguageFeatures', function () {
});
test('Format Range, evil provider', function () {
disposables.push(extHost.registerDocumentRangeFormattingEditProvider(defaultSelector, <vscode.DocumentRangeFormattingEditProvider>{
disposables.push(extHost.registerDocumentRangeFormattingEditProvider(defaultExtension, defaultSelector, <vscode.DocumentRangeFormattingEditProvider>{
provideDocumentRangeFormattingEdits(): any {
throw new Error('evil');
}
}));
return rpcProtocol.sync().then(() => {
return getDocumentRangeFormattingEdits(model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 });
return getDocumentRangeFormattingEdits(model, new EditorRange(1, 1, 1, 1), { insertSpaces: true, tabSize: 4 }, CancellationToken.None);
});
});
test('Format on Type, data conversion', function () {
disposables.push(extHost.registerOnTypeFormattingEditProvider(defaultSelector, <vscode.OnTypeFormattingEditProvider>{
disposables.push(extHost.registerOnTypeFormattingEditProvider(defaultExtension, defaultSelector, <vscode.OnTypeFormattingEditProvider>{
provideOnTypeFormattingEdits(): any {
return [new types.TextEdit(new types.Range(0, 0, 0, 0), arguments[2])];
}
@@ -1145,7 +1160,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Links, data conversion', function () {
disposables.push(extHost.registerDocumentLinkProvider(defaultSelector, <vscode.DocumentLinkProvider>{
disposables.push(extHost.registerDocumentLinkProvider(defaultExtension, defaultSelector, <vscode.DocumentLinkProvider>{
provideDocumentLinks() {
return [new types.DocumentLink(new types.Range(0, 0, 1, 1), URI.parse('foo:bar#3'))];
}
@@ -1164,13 +1179,13 @@ suite('ExtHostLanguageFeatures', function () {
test('Links, evil provider', function () {
disposables.push(extHost.registerDocumentLinkProvider(defaultSelector, <vscode.DocumentLinkProvider>{
disposables.push(extHost.registerDocumentLinkProvider(defaultExtension, defaultSelector, <vscode.DocumentLinkProvider>{
provideDocumentLinks() {
return [new types.DocumentLink(new types.Range(0, 0, 1, 1), URI.parse('foo:bar#3'))];
}
}));
disposables.push(extHost.registerDocumentLinkProvider(defaultSelector, <vscode.DocumentLinkProvider>{
disposables.push(extHost.registerDocumentLinkProvider(defaultExtension, defaultSelector, <vscode.DocumentLinkProvider>{
provideDocumentLinks(): any {
throw new Error();
}
@@ -1189,7 +1204,7 @@ suite('ExtHostLanguageFeatures', function () {
test('Document colors, data conversion', function () {
disposables.push(extHost.registerColorProvider(defaultSelector, <vscode.DocumentColorProvider>{
disposables.push(extHost.registerColorProvider(defaultExtension, defaultSelector, <vscode.DocumentColorProvider>{
provideDocumentColors(): vscode.ColorInformation[] {
return [new types.ColorInformation(new types.Range(0, 0, 0, 20), new types.Color(0.1, 0.2, 0.3, 0.4))];
},
@@ -1208,4 +1223,20 @@ suite('ExtHostLanguageFeatures', function () {
});
});
});
// -- selection ranges
test('Selection Ranges, data conversion', async function () {
disposables.push(extHost.registerSelectionRangeProvider(defaultExtension, defaultSelector, <vscode.SelectionRangeProvider>{
provideSelectionRanges() {
return [new types.Range(0, 10, 0, 18), new types.Range(0, 2, 0, 20)];
}
}));
await rpcProtocol.sync();
provideSelectionRanges(model, new Position(1, 17), CancellationToken.None).then(ranges => {
assert.ok(ranges.length >= 2);
});
});
});

View File

@@ -3,14 +3,12 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { MainThreadMessageService } from 'vs/workbench/api/electron-browser/mainThreadMessageService';
import { TPromise as Promise, TPromise } from 'vs/base/common/winjs.base';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice } from 'vs/platform/notification/common/notification';
import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
const emptyDialogService = new class implements IDialogService {
_serviceBrand: 'dialogService';
@@ -26,8 +24,8 @@ const emptyDialogService = new class implements IDialogService {
const emptyCommandService: ICommandService = {
_serviceBrand: undefined,
onWillExecuteCommand: () => ({ dispose: () => { } }),
executeCommand: (commandId: string, ...args: any[]): TPromise<any> => {
return TPromise.as(void 0);
executeCommand: (commandId: string, ...args: any[]): Promise<any> => {
return Promise.resolve(void 0);
}
};
@@ -45,7 +43,7 @@ const emptyNotificationService = new class implements INotificationService {
error(...args: any[]): never {
throw new Error('not implemented');
}
prompt(severity: Severity, message: string, choices: IPromptChoice[], onCancel?: () => void): INotificationHandle {
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
throw new Error('not implemented');
}
};
@@ -71,65 +69,61 @@ class EmptyNotificationService implements INotificationService {
error(message: any): void {
throw new Error('Method not implemented.');
}
prompt(severity: Severity, message: string, choices: IPromptChoice[], onCancel?: () => void): INotificationHandle {
prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle {
throw new Error('not implemented');
}
}
suite('ExtHostMessageService', function () {
test('propagte handle on select', function () {
test('propagte handle on select', async function () {
let service = new MainThreadMessageService(null, new EmptyNotificationService(notification => {
assert.equal(notification.actions.primary.length, 1);
setImmediate(() => notification.actions.primary[0].run());
}), emptyCommandService, emptyDialogService);
return service.$showMessage(1, 'h', {}, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]).then(handle => {
assert.equal(handle, 42);
});
const handle = await service.$showMessage(1, 'h', {}, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]);
assert.equal(handle, 42);
});
suite('modal', () => {
test('calls dialog service', () => {
const service = new MainThreadMessageService(null, emptyNotificationService, emptyCommandService, {
test('calls dialog service', async () => {
const service = new MainThreadMessageService(null, emptyNotificationService, emptyCommandService, new class extends mock<IDialogService>() {
show(severity, message, buttons) {
assert.equal(severity, 1);
assert.equal(message, 'h');
assert.equal(buttons.length, 2);
assert.equal(buttons[1], 'Cancel');
return Promise.as(0);
return Promise.resolve(0);
}
} as IDialogService);
return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]).then(handle => {
assert.equal(handle, 42);
});
const handle = await service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]);
assert.equal(handle, 42);
});
test('returns undefined when cancelled', () => {
const service = new MainThreadMessageService(null, emptyNotificationService, emptyCommandService, {
test('returns undefined when cancelled', async () => {
const service = new MainThreadMessageService(null, emptyNotificationService, emptyCommandService, new class extends mock<IDialogService>() {
show(severity, message, buttons) {
return Promise.as(1);
return Promise.resolve(1);
}
} as IDialogService);
return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]).then(handle => {
assert.equal(handle, undefined);
});
const handle = await service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: false }]);
assert.equal(handle, undefined);
});
test('hides Cancel button when not needed', () => {
const service = new MainThreadMessageService(null, emptyNotificationService, emptyCommandService, {
test('hides Cancel button when not needed', async () => {
const service = new MainThreadMessageService(null, emptyNotificationService, emptyCommandService, new class extends mock<IDialogService>() {
show(severity, message, buttons) {
assert.equal(buttons.length, 1);
return Promise.as(0);
return Promise.resolve(0);
}
} as IDialogService);
return service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]).then(handle => {
assert.equal(handle, 42);
});
const handle = await service.$showMessage(1, 'h', { modal: true }, [{ handle: 42, title: 'a thing', isCloseAffordance: true }]);
assert.equal(handle, 42);
});
});
});

View File

@@ -2,20 +2,22 @@
* 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 { mapArrayOrNot } from 'vs/base/common/arrays';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { dispose } from 'vs/base/common/lifecycle';
import { joinPath } from 'vs/base/common/resources';
import URI, { UriComponents } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { URI, UriComponents } from 'vs/base/common/uri';
import * as extfs from 'vs/base/node/extfs';
import { IFileMatch, IPatternInfo, IRawFileMatch2, IRawSearchQuery, ISearchCompleteStats, ISearchQuery, QueryType } from 'vs/platform/search/common/search';
import { IFileMatch, IFileQuery, IPatternInfo, IRawFileMatch2, ISearchCompleteStats, ISearchQuery, ITextQuery, QueryType, resultIsMatch } from 'vs/platform/search/common/search';
import { MainContext, MainThreadSearchShape } from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch';
import { Range } from 'vs/workbench/api/node/extHostTypes';
import { extensionResultIsMatch } from 'vs/workbench/services/search/node/textSearchManager';
import { TestRPCProtocol } from 'vs/workbench/test/electron-browser/api/testRPCProtocol';
import { TestLogService } from 'vs/workbench/test/workbenchTestServices';
import * as vscode from 'vscode';
let rpcProtocol: TestRPCProtocol;
@@ -58,6 +60,12 @@ class MockMainThreadSearch implements MainThreadSearchShape {
}
}
class MockExtHostConfiguration {
getConfiguration(section?: string, resource?: URI, extensionId?: string): vscode.WorkspaceConfiguration {
return <vscode.WorkspaceConfiguration>{};
}
}
let mockExtfs: Partial<typeof extfs>;
suite('ExtHostSearch', () => {
@@ -71,13 +79,14 @@ suite('ExtHostSearch', () => {
await rpcProtocol.sync();
}
async function runFileSearch(query: IRawSearchQuery, cancel = false): Promise<{ results: URI[]; stats: ISearchCompleteStats }> {
async function runFileSearch(query: IFileQuery, cancel = false): Promise<{ results: URI[]; stats: ISearchCompleteStats }> {
let stats: ISearchCompleteStats;
try {
const p = extHostSearch.$provideFileSearchResults(mockMainThreadSearch.lastHandle, 0, query);
const cancellation = new CancellationTokenSource();
const p = extHostSearch.$provideFileSearchResults(mockMainThreadSearch.lastHandle, 0, query, cancellation.token);
if (cancel) {
await new TPromise(resolve => process.nextTick(resolve));
p.cancel();
await new Promise(resolve => process.nextTick(resolve));
cancellation.cancel();
}
stats = await p;
@@ -95,13 +104,14 @@ suite('ExtHostSearch', () => {
};
}
async function runTextSearch(pattern: IPatternInfo, query: IRawSearchQuery, cancel = false): Promise<{ results: IFileMatch[], stats: ISearchCompleteStats }> {
async function runTextSearch(query: ITextQuery, cancel = false): Promise<{ results: IFileMatch[], stats: ISearchCompleteStats }> {
let stats: ISearchCompleteStats;
try {
const p = extHostSearch.$provideTextSearchResults(mockMainThreadSearch.lastHandle, 0, pattern, query);
const cancellation = new CancellationTokenSource();
const p = extHostSearch.$provideTextSearchResults(mockMainThreadSearch.lastHandle, 0, query, cancellation.token);
if (cancel) {
await new TPromise(resolve => process.nextTick(resolve));
p.cancel();
await new Promise(resolve => process.nextTick(resolve));
cancellation.cancel();
}
stats = await p;
@@ -127,11 +137,13 @@ suite('ExtHostSearch', () => {
rpcProtocol = new TestRPCProtocol();
mockMainThreadSearch = new MockMainThreadSearch();
const logService = new TestLogService();
const ehConfiguration: ExtHostConfiguration = new MockExtHostConfiguration() as any;
rpcProtocol.set(MainContext.MainThreadSearch, mockMainThreadSearch);
mockExtfs = {};
extHostSearch = new ExtHostSearch(rpcProtocol, null, mockExtfs as typeof extfs);
extHostSearch = new ExtHostSearch(rpcProtocol, null, logService, ehConfiguration, mockExtfs as typeof extfs);
});
teardown(() => {
@@ -146,7 +158,7 @@ suite('ExtHostSearch', () => {
suite('File:', () => {
function getSimpleQuery(filePattern = ''): ISearchQuery {
function getSimpleQuery(filePattern = ''): IFileQuery {
return {
type: QueryType.File,
@@ -168,7 +180,7 @@ suite('ExtHostSearch', () => {
test('no results', async () => {
await registerTestFileSearchProvider({
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Thenable<URI[]> {
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
@@ -186,7 +198,7 @@ suite('ExtHostSearch', () => {
await registerTestFileSearchProvider({
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Thenable<URI[]> {
return TPromise.wrap(reportedResults);
return Promise.resolve(reportedResults);
}
});
@@ -200,7 +212,7 @@ suite('ExtHostSearch', () => {
let cancelRequested = false;
await registerTestFileSearchProvider({
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Thenable<URI[]> {
return new TPromise((resolve, reject) => {
return new Promise((resolve, reject) => {
token.onCancellationRequested(() => {
cancelRequested = true;
@@ -234,7 +246,7 @@ suite('ExtHostSearch', () => {
await registerTestFileSearchProvider({
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Thenable<URI[]> {
assert(options.excludes.length === 2 && options.includes.length === 2, 'Missing global include/excludes');
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
@@ -270,7 +282,7 @@ suite('ExtHostSearch', () => {
assert.deepEqual(options.excludes.sort(), ['*.js']);
}
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
@@ -307,7 +319,7 @@ suite('ExtHostSearch', () => {
assert.deepEqual(options.includes.sort(), ['*.jsx', '*.ts']);
assert.deepEqual(options.excludes.sort(), []);
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
@@ -347,7 +359,7 @@ suite('ExtHostSearch', () => {
await registerTestFileSearchProvider({
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Thenable<URI[]> {
return TPromise.wrap(reportedResults
return Promise.resolve(reportedResults
.map(relativePath => joinPath(options.folder, relativePath)));
}
});
@@ -393,7 +405,7 @@ suite('ExtHostSearch', () => {
].map(relativePath => joinPath(rootFolderB, relativePath));
}
return TPromise.wrap(reportedResults);
return Promise.resolve(reportedResults);
}
});
@@ -450,7 +462,7 @@ suite('ExtHostSearch', () => {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Thenable<URI[]> {
token.onCancellationRequested(() => wasCanceled = true);
return TPromise.wrap(reportedResults);
return Promise.resolve(reportedResults);
}
});
@@ -486,7 +498,7 @@ suite('ExtHostSearch', () => {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Thenable<URI[]> {
token.onCancellationRequested(() => wasCanceled = true);
return TPromise.wrap(reportedResults);
return Promise.resolve(reportedResults);
}
});
@@ -521,7 +533,7 @@ suite('ExtHostSearch', () => {
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Thenable<URI[]> {
token.onCancellationRequested(() => wasCanceled = true);
return TPromise.wrap(reportedResults);
return Promise.resolve(reportedResults);
}
});
@@ -548,18 +560,16 @@ suite('ExtHostSearch', () => {
test('multiroot max results', async () => {
let cancels = 0;
await registerTestFileSearchProvider({
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Thenable<URI[]> {
async provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Promise<URI[]> {
token.onCancellationRequested(() => cancels++);
// Provice results async so it has a chance to invoke every provider
return new TPromise(r => process.nextTick(r))
.then(() => {
return [
'file1.ts',
'file2.ts',
'file3.ts',
].map(relativePath => joinPath(options.folder, relativePath));
});
await new Promise(r => process.nextTick(r));
return [
'file1.ts',
'file2.ts',
'file3.ts',
].map(relativePath => joinPath(options.folder, relativePath));
}
});
@@ -594,7 +604,7 @@ suite('ExtHostSearch', () => {
await registerTestFileSearchProvider({
provideFileSearchResults(query: vscode.FileSearchQuery, options: vscode.FileSearchOptions, token: vscode.CancellationToken): Thenable<URI[]> {
return TPromise.wrap(reportedResults);
return Promise.resolve(reportedResults);
}
}, fancyScheme);
@@ -615,24 +625,25 @@ suite('ExtHostSearch', () => {
suite('Text:', () => {
function makePreview(text: string): vscode.TextSearchResult['preview'] {
function makePreview(text: string): vscode.TextSearchMatch['preview'] {
return {
match: new Range(0, 0, 0, text.length),
matches: new Range(0, 0, 0, text.length),
text
};
}
function makeTextResult(baseFolder: URI, relativePath: string): vscode.TextSearchResult {
function makeTextResult(baseFolder: URI, relativePath: string): vscode.TextSearchMatch {
return {
preview: makePreview('foo'),
range: new Range(0, 0, 0, 3),
ranges: new Range(0, 0, 0, 3),
uri: joinPath(baseFolder, relativePath)
};
}
function getSimpleQuery(): ISearchQuery {
function getSimpleQuery(queryText: string): ITextQuery {
return {
type: QueryType.Text,
contentPattern: getPattern(queryText),
folderQueries: [
{ folder: rootFolderA }
@@ -650,11 +661,25 @@ suite('ExtHostSearch', () => {
const actualTextSearchResults: vscode.TextSearchResult[] = [];
for (let fileMatch of actual) {
// Make relative
for (let lineMatch of fileMatch.lineMatches) {
for (let [offset, length] of lineMatch.offsetAndLengths) {
for (let lineResult of fileMatch.results) {
if (resultIsMatch(lineResult)) {
actualTextSearchResults.push({
preview: { text: lineMatch.preview, match: null },
range: new Range(lineMatch.lineNumber, offset, lineMatch.lineNumber, length + offset),
preview: {
text: lineResult.preview.text,
matches: mapArrayOrNot(
lineResult.preview.matches,
m => new Range(m.startLineNumber, m.startColumn, m.endLineNumber, m.endColumn))
},
ranges: mapArrayOrNot(
lineResult.ranges,
r => new Range(r.startLineNumber, r.startColumn, r.endLineNumber, r.endColumn),
),
uri: fileMatch.resource
});
} else {
actualTextSearchResults.push(<vscode.TextSearchContext>{
text: lineResult.text,
lineNumber: lineResult.lineNumber,
uri: fileMatch.resource
});
}
@@ -664,18 +689,23 @@ suite('ExtHostSearch', () => {
const rangeToString = (r: vscode.Range) => `(${r.start.line}, ${r.start.character}), (${r.end.line}, ${r.end.character})`;
const makeComparable = (results: vscode.TextSearchResult[]) => results
.sort((a, b) => b.preview.text.localeCompare(a.preview.text))
.map(r => ({
...r,
...{
uri: r.uri.toString(),
range: rangeToString(r.range),
preview: {
text: r.preview.text,
match: null // Don't care about this right now
}
.sort((a, b) => {
const compareKeyA = a.uri.toString() + ': ' + (extensionResultIsMatch(a) ? a.preview.text : a.text);
const compareKeyB = b.uri.toString() + ': ' + (extensionResultIsMatch(b) ? b.preview.text : b.text);
return compareKeyB.localeCompare(compareKeyA);
})
.map(r => extensionResultIsMatch(r) ? {
uri: r.uri.toString(),
range: mapArrayOrNot(r.ranges, rangeToString),
preview: {
text: r.preview.text,
match: null // Don't care about this right now
}
}));
} : {
uri: r.uri.toString(),
text: r.text,
lineNumber: r.lineNumber
});
return assert.deepEqual(
makeComparable(actualTextSearchResults),
@@ -684,12 +714,12 @@ suite('ExtHostSearch', () => {
test('no results', async () => {
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
return TPromise.wrap(null);
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
return Promise.resolve(null);
}
});
const { results, stats } = await runTextSearch(getPattern('foo'), getSimpleQuery());
const { results, stats } = await runTextSearch(getSimpleQuery('foo'));
assert(!stats.limitHit);
assert(!results.length);
});
@@ -701,28 +731,29 @@ suite('ExtHostSearch', () => {
];
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
providedResults.forEach(r => progress.report(r));
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
const { results, stats } = await runTextSearch(getPattern('foo'), getSimpleQuery());
const { results, stats } = await runTextSearch(getSimpleQuery('foo'));
assert(!stats.limitHit);
assertResults(results, providedResults);
});
test('all provider calls get global include/excludes', async () => {
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
assert.equal(options.includes.length, 1);
assert.equal(options.excludes.length, 1);
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
const query: IRawSearchQuery = {
const query: ITextQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
includePattern: {
'*.ts': true
@@ -738,12 +769,12 @@ suite('ExtHostSearch', () => {
]
};
await runTextSearch(getPattern('foo'), query);
await runTextSearch(query);
});
test('global/local include/excludes combined', async () => {
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
if (options.folder.toString() === rootFolderA.toString()) {
assert.deepEqual(options.includes.sort(), ['*.ts', 'foo']);
assert.deepEqual(options.excludes.sort(), ['*.js', 'bar']);
@@ -752,12 +783,13 @@ suite('ExtHostSearch', () => {
assert.deepEqual(options.excludes.sort(), ['*.js']);
}
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
const query: IRawSearchQuery = {
const query: ITextQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
includePattern: {
'*.ts': true
@@ -779,21 +811,22 @@ suite('ExtHostSearch', () => {
]
};
await runTextSearch(getPattern('foo'), query);
await runTextSearch(query);
});
test('include/excludes resolved correctly', async () => {
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
assert.deepEqual(options.includes.sort(), ['*.jsx', '*.ts']);
assert.deepEqual(options.excludes.sort(), []);
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
const query: ISearchQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
includePattern: {
'*.ts': true,
@@ -816,18 +849,18 @@ suite('ExtHostSearch', () => {
]
};
await runTextSearch(getPattern('foo'), query);
await runTextSearch(query);
});
test('provider fail', async () => {
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
throw new Error('Provider fail');
}
});
try {
await runTextSearch(getPattern('foo'), getSimpleQuery());
await runTextSearch(getSimpleQuery('foo'));
assert(false, 'Expected to fail');
} catch {
// expected to fail
@@ -852,14 +885,15 @@ suite('ExtHostSearch', () => {
];
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
providedResults.forEach(r => progress.report(r));
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
const query: ISearchQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
excludePattern: {
'*.js': {
@@ -872,7 +906,7 @@ suite('ExtHostSearch', () => {
]
};
const { results } = await runTextSearch(getPattern('foo'), query);
const { results } = await runTextSearch(query);
assertResults(results, providedResults.slice(1));
});
@@ -896,7 +930,7 @@ suite('ExtHostSearch', () => {
};
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
let reportedResults;
if (options.folder.fsPath === rootFolderA.fsPath) {
reportedResults = [
@@ -913,12 +947,13 @@ suite('ExtHostSearch', () => {
}
reportedResults.forEach(r => progress.report(r));
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
const query: ISearchQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
excludePattern: {
'*.js': {
@@ -944,7 +979,7 @@ suite('ExtHostSearch', () => {
]
};
const { results } = await runTextSearch(getPattern('foo'), query);
const { results } = await runTextSearch(query);
assertResults(results, [
makeTextResult(rootFolderA, 'folder/fileA.scss'),
makeTextResult(rootFolderA, 'folder/file2.css'),
@@ -960,14 +995,15 @@ suite('ExtHostSearch', () => {
];
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
providedResults.forEach(r => progress.report(r));
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
const query: ISearchQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
includePattern: {
'*.ts': true
@@ -978,7 +1014,7 @@ suite('ExtHostSearch', () => {
]
};
const { results } = await runTextSearch(getPattern('foo'), query);
const { results } = await runTextSearch(query);
assertResults(results, providedResults.slice(1));
});
@@ -990,15 +1026,16 @@ suite('ExtHostSearch', () => {
let wasCanceled = false;
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
token.onCancellationRequested(() => wasCanceled = true);
providedResults.forEach(r => progress.report(r));
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
const query: ISearchQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
maxResults: 1,
@@ -1007,7 +1044,7 @@ suite('ExtHostSearch', () => {
]
};
const { results, stats } = await runTextSearch(getPattern('foo'), query);
const { results, stats } = await runTextSearch(query);
assert(stats.limitHit, 'Expected to return limitHit');
assertResults(results, providedResults.slice(0, 1));
assert(wasCanceled, 'Expected to be canceled');
@@ -1022,15 +1059,16 @@ suite('ExtHostSearch', () => {
let wasCanceled = false;
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
token.onCancellationRequested(() => wasCanceled = true);
providedResults.forEach(r => progress.report(r));
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
const query: ISearchQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
maxResults: 2,
@@ -1039,7 +1077,7 @@ suite('ExtHostSearch', () => {
]
};
const { results, stats } = await runTextSearch(getPattern('foo'), query);
const { results, stats } = await runTextSearch(query);
assert(stats.limitHit, 'Expected to return limitHit');
assertResults(results, providedResults.slice(0, 2));
assert(wasCanceled, 'Expected to be canceled');
@@ -1053,15 +1091,16 @@ suite('ExtHostSearch', () => {
let wasCanceled = false;
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
token.onCancellationRequested(() => wasCanceled = true);
providedResults.forEach(r => progress.report(r));
return TPromise.wrap(null);
return Promise.resolve(null);
}
});
const query: ISearchQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
maxResults: 2,
@@ -1070,30 +1109,60 @@ suite('ExtHostSearch', () => {
]
};
const { results, stats } = await runTextSearch(getPattern('foo'), query);
const { results, stats } = await runTextSearch(query);
assert(!stats.limitHit, 'Expected not to return limitHit');
assertResults(results, providedResults);
assert(!wasCanceled, 'Expected not to be canceled');
});
test('multiroot max results', async () => {
let cancels = 0;
test('provider returns early with limitHit', async () => {
const providedResults: vscode.TextSearchResult[] = [
makeTextResult(rootFolderA, 'file1.ts'),
makeTextResult(rootFolderA, 'file2.ts'),
makeTextResult(rootFolderA, 'file3.ts')
];
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
token.onCancellationRequested(() => cancels++);
return new TPromise(r => process.nextTick(r))
.then(() => {
[
'file1.ts',
'file2.ts',
'file3.ts',
].forEach(f => progress.report(makeTextResult(options.folder, f)));
});
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
providedResults.forEach(r => progress.report(r));
return Promise.resolve({ limitHit: true });
}
});
const query: ISearchQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
maxResults: 1000,
folderQueries: [
{ folder: rootFolderA }
]
};
const { results, stats } = await runTextSearch(query);
assert(stats.limitHit, 'Expected to return limitHit');
assertResults(results, providedResults);
});
test('multiroot max results', async () => {
let cancels = 0;
await registerTestTextSearchProvider({
async provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Promise<vscode.TextSearchComplete> {
token.onCancellationRequested(() => cancels++);
await new Promise(r => process.nextTick(r));
[
'file1.ts',
'file2.ts',
'file3.ts',
].forEach(f => progress.report(makeTextResult(options.folder, f)));
return null;
}
});
const query: ISearchQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
maxResults: 2,
@@ -1103,7 +1172,7 @@ suite('ExtHostSearch', () => {
]
};
const { results } = await runTextSearch(getPattern('foo'), query);
const { results } = await runTextSearch(query);
assert.equal(results.length, 2);
assert.equal(cancels, 2);
});
@@ -1116,21 +1185,22 @@ suite('ExtHostSearch', () => {
];
await registerTestTextSearchProvider({
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<void> {
provideTextSearchResults(query: vscode.TextSearchQuery, options: vscode.TextSearchOptions, progress: vscode.Progress<vscode.TextSearchResult>, token: vscode.CancellationToken): Thenable<vscode.TextSearchComplete> {
providedResults.forEach(r => progress.report(r));
return TPromise.wrap(null);
return Promise.resolve(null);
}
}, fancyScheme);
const query: ISearchQuery = {
type: QueryType.Text,
contentPattern: getPattern('foo'),
folderQueries: [
{ folder: fancySchemeFolderA }
]
};
const { results } = await runTextSearch(getPattern('foo'), query);
const { results } = await runTextSearch(query);
assertResults(results, providedResults);
});
});

View File

@@ -2,16 +2,13 @@
* 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 { TPromise } from 'vs/base/common/winjs.base';
import { TextEditorLineNumbersStyle, Range } from 'vs/workbench/api/node/extHostTypes';
import { TextEditorCursorStyle } from 'vs/editor/common/config/editorOptions';
import { MainThreadTextEditorsShape, IResolvedTextEditorConfiguration, ITextEditorConfigurationUpdate } from 'vs/workbench/api/node/extHost.protocol';
import { ExtHostTextEditorOptions, ExtHostTextEditor } from 'vs/workbench/api/node/extHostTextEditor';
import { ExtHostDocumentData } from 'vs/workbench/api/node/extHostDocumentData';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
suite('ExtHostTextEditor', () => {
@@ -44,9 +41,9 @@ suite('ExtHostTextEditor', () => {
test('API [bug]: registerTextEditorCommand clears redo stack even if no edits are made #55163', async function () {
let applyCount = 0;
let editor = new ExtHostTextEditor(new class extends mock<MainThreadTextEditorsShape>() {
$tryApplyEdits(): TPromise<boolean> {
$tryApplyEdits(): Promise<boolean> {
applyCount += 1;
return TPromise.wrap(true);
return Promise.resolve(true);
}
}, 'edt1', doc, [], { cursorStyle: 0, insertSpaces: true, lineNumbers: 1, tabSize: 4 }, [], 1);
@@ -73,7 +70,7 @@ suite('ExtHostTextEditorOptions', () => {
$trySetOptions: (id: string, options: ITextEditorConfigurationUpdate) => {
assert.equal(id, '1');
calls.push(options);
return TPromise.as(void 0);
return Promise.resolve(void 0);
},
$tryShowTextDocument: undefined,
$registerTextEditorDecorationType: undefined,

View File

@@ -2,13 +2,10 @@
* 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 { TPromise } from 'vs/base/common/winjs.base';
import * as extHostTypes from 'vs/workbench/api/node/extHostTypes';
import { MainContext, MainThreadTextEditorsShape, WorkspaceEditDto } from 'vs/workbench/api/node/extHost.protocol';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
import { SingleProxyRPCProtocol, TestRPCProtocol } from 'vs/workbench/test/electron-browser/api/testRPCProtocol';
@@ -26,9 +23,9 @@ suite('ExtHostTextEditors.applyWorkspaceEdit', () => {
let rpcProtocol = new TestRPCProtocol();
rpcProtocol.set(MainContext.MainThreadTextEditors, new class extends mock<MainThreadTextEditorsShape>() {
$tryApplyWorkspaceEdit(_workspaceResourceEdits: WorkspaceEditDto): TPromise<boolean> {
$tryApplyWorkspaceEdit(_workspaceResourceEdits: WorkspaceEditDto): Promise<boolean> {
workspaceResourceEdits = _workspaceResourceEdits;
return TPromise.as(true);
return Promise.resolve(true);
}
});
const documentsAndEditors = new ExtHostDocumentsAndEditors(SingleProxyRPCProtocol(null));
@@ -45,22 +42,20 @@ suite('ExtHostTextEditors.applyWorkspaceEdit', () => {
editors = new ExtHostEditors(rpcProtocol, documentsAndEditors);
});
test('uses version id if document available', () => {
test('uses version id if document available', async () => {
let edit = new extHostTypes.WorkspaceEdit();
edit.replace(resource, new extHostTypes.Range(0, 0, 0, 0), 'hello');
return editors.applyWorkspaceEdit(edit).then((result) => {
assert.equal(workspaceResourceEdits.edits.length, 1);
assert.equal((<ResourceTextEdit>workspaceResourceEdits.edits[0]).modelVersionId, 1337);
});
await editors.applyWorkspaceEdit(edit);
assert.equal(workspaceResourceEdits.edits.length, 1);
assert.equal((<ResourceTextEdit>workspaceResourceEdits.edits[0]).modelVersionId, 1337);
});
test('does not use version id if document is not available', () => {
test('does not use version id if document is not available', async () => {
let edit = new extHostTypes.WorkspaceEdit();
edit.replace(URI.parse('foo:bar2'), new extHostTypes.Range(0, 0, 0, 0), 'hello');
return editors.applyWorkspaceEdit(edit).then((result) => {
assert.equal(workspaceResourceEdits.edits.length, 1);
assert.ok(typeof (<ResourceTextEdit>workspaceResourceEdits.edits[0]).modelVersionId === 'undefined');
});
await editors.applyWorkspaceEdit(edit);
assert.equal(workspaceResourceEdits.edits.length, 1);
assert.ok(typeof (<ResourceTextEdit>workspaceResourceEdits.edits[0]).modelVersionId === 'undefined');
});
});

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import * as sinon from 'sinon';
import { Emitter } from 'vs/base/common/event';
@@ -18,9 +16,9 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/
import { MainThreadCommands } from 'vs/workbench/api/electron-browser/mainThreadCommands';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
import { TPromise } from 'vs/base/common/winjs.base';
import { TreeItemCollapsibleState, ITreeItem } from 'vs/workbench/common/views';
import { NullLogService } from 'vs/platform/log/common/log';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
suite('ExtHostTreeView', function () {
@@ -31,11 +29,11 @@ suite('ExtHostTreeView', function () {
$registerTreeViewDataProvider(treeViewId: string): void {
}
$refresh(viewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): TPromise<void> {
return TPromise.as(null).then(() => this.onRefresh.fire(itemsToRefresh));
$refresh(viewId: string, itemsToRefresh?: { [treeItemHandle: string]: ITreeItem }): Promise<void> {
return Promise.resolve(null).then(() => this.onRefresh.fire(itemsToRefresh));
}
$reveal(): TPromise<void> {
$reveal(): Promise<void> {
return null;
}
@@ -75,8 +73,9 @@ suite('ExtHostTreeView', function () {
testObject = new ExtHostTreeViews(target, new ExtHostCommands(rpcProtocol, new ExtHostHeapService(), new NullLogService()), new NullLogService());
onDidChangeTreeNode = new Emitter<{ key: string }>();
onDidChangeTreeNodeWithId = new Emitter<{ key: string }>();
testObject.createTreeView('testNodeTreeProvider', { treeDataProvider: aNodeTreeDataProvider() });
testObject.createTreeView('testNodeWithIdTreeProvider', { treeDataProvider: aNodeWithIdTreeDataProvider() });
testObject.createTreeView('testNodeTreeProvider', { treeDataProvider: aNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
testObject.createTreeView('testNodeWithIdTreeProvider', { treeDataProvider: aNodeWithIdTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
testObject.createTreeView('testNodeWithHighlightsTreeProvider', { treeDataProvider: aNodeWithHighlightedLabelTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
return loadCompleteTree('testNodeTreeProvider');
});
@@ -86,12 +85,12 @@ suite('ExtHostTreeView', function () {
.then(elements => {
const actuals = elements.map(e => e.handle);
assert.deepEqual(actuals, ['0/0:a', '0/0:b']);
return TPromise.join([
return Promise.all([
testObject.$getChildren('testNodeTreeProvider', '0/0:a')
.then(children => {
const actuals = children.map(e => e.handle);
assert.deepEqual(actuals, ['0/0:a/0:aa', '0/0:a/0:ab']);
return TPromise.join([
return Promise.all([
testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:aa').then(children => assert.equal(children.length, 0)),
testObject.$getChildren('testNodeTreeProvider', '0/0:a/0:ab').then(children => assert.equal(children.length, 0))
]);
@@ -100,7 +99,7 @@ suite('ExtHostTreeView', function () {
.then(children => {
const actuals = children.map(e => e.handle);
assert.deepEqual(actuals, ['0/0:b/0:ba', '0/0:b/0:bb']);
return TPromise.join([
return Promise.all([
testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:ba').then(children => assert.equal(children.length, 0)),
testObject.$getChildren('testNodeTreeProvider', '0/0:b/0:bb').then(children => assert.equal(children.length, 0))
]);
@@ -114,12 +113,12 @@ suite('ExtHostTreeView', function () {
.then(elements => {
const actuals = elements.map(e => e.handle);
assert.deepEqual(actuals, ['1/a', '1/b']);
return TPromise.join([
return Promise.all([
testObject.$getChildren('testNodeWithIdTreeProvider', '1/a')
.then(children => {
const actuals = children.map(e => e.handle);
assert.deepEqual(actuals, ['1/aa', '1/ab']);
return TPromise.join([
return Promise.all([
testObject.$getChildren('testNodeWithIdTreeProvider', '1/aa').then(children => assert.equal(children.length, 0)),
testObject.$getChildren('testNodeWithIdTreeProvider', '1/ab').then(children => assert.equal(children.length, 0))
]);
@@ -128,7 +127,7 @@ suite('ExtHostTreeView', function () {
.then(children => {
const actuals = children.map(e => e.handle);
assert.deepEqual(actuals, ['1/ba', '1/bb']);
return TPromise.join([
return Promise.all([
testObject.$getChildren('testNodeWithIdTreeProvider', '1/ba').then(children => assert.equal(children.length, 0)),
testObject.$getChildren('testNodeWithIdTreeProvider', '1/bb').then(children => assert.equal(children.length, 0))
]);
@@ -137,6 +136,51 @@ suite('ExtHostTreeView', function () {
});
});
test('construct highlights tree', () => {
return testObject.$getChildren('testNodeWithHighlightsTreeProvider')
.then(elements => {
assert.deepEqual(removeUnsetKeys(elements), [{
handle: '1/a',
label: { label: 'a', highlights: [[0, 2], [3, 5]] },
collapsibleState: TreeItemCollapsibleState.Collapsed
}, {
handle: '1/b',
label: { label: 'b', highlights: [[0, 2], [3, 5]] },
collapsibleState: TreeItemCollapsibleState.Collapsed
}]);
return Promise.all([
testObject.$getChildren('testNodeWithHighlightsTreeProvider', '1/a')
.then(children => {
assert.deepEqual(removeUnsetKeys(children), [{
handle: '1/aa',
parentHandle: '1/a',
label: { label: 'aa', highlights: [[0, 2], [3, 5]] },
collapsibleState: TreeItemCollapsibleState.None
}, {
handle: '1/ab',
parentHandle: '1/a',
label: { label: 'ab', highlights: [[0, 2], [3, 5]] },
collapsibleState: TreeItemCollapsibleState.None
}]);
}),
testObject.$getChildren('testNodeWithHighlightsTreeProvider', '1/b')
.then(children => {
assert.deepEqual(removeUnsetKeys(children), [{
handle: '1/ba',
parentHandle: '1/b',
label: { label: 'ba', highlights: [[0, 2], [3, 5]] },
collapsibleState: TreeItemCollapsibleState.None
}, {
handle: '1/bb',
parentHandle: '1/b',
label: { label: 'bb', highlights: [[0, 2], [3, 5]] },
collapsibleState: TreeItemCollapsibleState.None
}]);
})
]);
});
});
test('error is thrown if id is not unique', (done) => {
tree['a'] = {
'aa': {},
@@ -167,12 +211,12 @@ suite('ExtHostTreeView', function () {
});
test('refresh a parent node', () => {
return new TPromise((c, e) => {
return new Promise((c, e) => {
target.onRefresh.event(actuals => {
assert.deepEqual(['0/0:b'], Object.keys(actuals));
assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), {
handle: '0/0:b',
label: 'b',
label: { label: 'b' },
collapsibleState: TreeItemCollapsibleState.Collapsed
});
c(null);
@@ -187,7 +231,7 @@ suite('ExtHostTreeView', function () {
assert.deepEqual(removeUnsetKeys(actuals['0/0:b/0:bb']), {
handle: '0/0:b/0:bb',
parentHandle: '0/0:b',
label: 'bb',
label: { label: 'bb' },
collapsibleState: TreeItemCollapsibleState.None
});
done();
@@ -200,13 +244,13 @@ suite('ExtHostTreeView', function () {
assert.deepEqual(['0/0:b', '0/0:a/0:aa'], Object.keys(actuals));
assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), {
handle: '0/0:b',
label: 'b',
label: { label: 'b' },
collapsibleState: TreeItemCollapsibleState.Collapsed
});
assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), {
handle: '0/0:a/0:aa',
parentHandle: '0/0:a',
label: 'aa',
label: { label: 'aa' },
collapsibleState: TreeItemCollapsibleState.None
});
done();
@@ -221,13 +265,13 @@ suite('ExtHostTreeView', function () {
assert.deepEqual(['0/0:a/0:aa', '0/0:b'], Object.keys(actuals));
assert.deepEqual(removeUnsetKeys(actuals['0/0:b']), {
handle: '0/0:b',
label: 'b',
label: { label: 'b' },
collapsibleState: TreeItemCollapsibleState.Collapsed
});
assert.deepEqual(removeUnsetKeys(actuals['0/0:a/0:aa']), {
handle: '0/0:a/0:aa',
parentHandle: '0/0:a',
label: 'aa',
label: { label: 'aa' },
collapsibleState: TreeItemCollapsibleState.None
});
done();
@@ -243,7 +287,7 @@ suite('ExtHostTreeView', function () {
assert.deepEqual(['0/0:a'], Object.keys(actuals));
assert.deepEqual(removeUnsetKeys(actuals['0/0:a']), {
handle: '0/0:aa',
label: 'aa',
label: { label: 'aa' },
collapsibleState: TreeItemCollapsibleState.Collapsed
});
done();
@@ -402,49 +446,49 @@ suite('ExtHostTreeView', function () {
});
test('reveal will throw an error if getParent is not implemented', () => {
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aNodeTreeDataProvider() });
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
return treeView.reveal({ key: 'a' })
.then(() => assert.fail('Reveal should throw an error as getParent is not implemented'), () => null);
});
test('reveal will return empty array for root element', () => {
const revealTarget = sinon.spy(target, '$reveal');
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() });
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
return treeView.reveal({ key: 'a' })
.then(() => {
assert.ok(revealTarget.calledOnce);
assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
assert.deepEqual({ handle: '0/0:a', label: 'a', collapsibleState: TreeItemCollapsibleState.Collapsed }, removeUnsetKeys(revealTarget.args[0][1]));
assert.deepEqual({ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }, removeUnsetKeys(revealTarget.args[0][1]));
assert.deepEqual([], revealTarget.args[0][2]);
assert.deepEqual({ select: true, focus: false }, revealTarget.args[0][3]);
assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]);
});
});
test('reveal will return parents array for an element when hierarchy is not loaded', () => {
const revealTarget = sinon.spy(target, '$reveal');
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() });
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
return treeView.reveal({ key: 'aa' })
.then(() => {
assert.ok(revealTarget.calledOnce);
assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
assert.deepEqual({ handle: '0/0:a/0:aa', label: 'aa', collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1]));
assert.deepEqual([{ handle: '0/0:a', label: 'a', collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
assert.deepEqual({ select: true, focus: false }, revealTarget.args[0][3]);
assert.deepEqual({ handle: '0/0:a/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1]));
assert.deepEqual([{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]);
});
});
test('reveal will return parents array for an element when hierarchy is loaded', () => {
const revealTarget = sinon.spy(target, '$reveal');
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() });
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
return testObject.$getChildren('treeDataProvider')
.then(() => testObject.$getChildren('treeDataProvider', '0/0:a'))
.then(() => treeView.reveal({ key: 'aa' })
.then(() => {
assert.ok(revealTarget.calledOnce);
assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
assert.deepEqual({ handle: '0/0:a/0:aa', label: 'aa', collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1]));
assert.deepEqual([{ handle: '0/0:a', label: 'a', collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
assert.deepEqual({ select: true, focus: false }, revealTarget.args[0][3]);
assert.deepEqual({ handle: '0/0:a/0:aa', label: { label: 'aa' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1]));
assert.deepEqual([{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]);
}));
});
@@ -457,34 +501,108 @@ suite('ExtHostTreeView', function () {
}
};
const revealTarget = sinon.spy(target, '$reveal');
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() });
return treeView.reveal({ key: 'bac' }, { select: false, focus: false })
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
return treeView.reveal({ key: 'bac' }, { select: false, focus: false, expand: false })
.then(() => {
assert.ok(revealTarget.calledOnce);
assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
assert.deepEqual({ handle: '0/0:b/0:ba/0:bac', label: 'bac', collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b/0:ba' }, removeUnsetKeys(revealTarget.args[0][1]));
assert.deepEqual({ handle: '0/0:b/0:ba/0:bac', label: { label: 'bac' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b/0:ba' }, removeUnsetKeys(revealTarget.args[0][1]));
assert.deepEqual([
{ handle: '0/0:b', label: 'b', collapsibleState: TreeItemCollapsibleState.Collapsed },
{ handle: '0/0:b/0:ba', label: 'ba', collapsibleState: TreeItemCollapsibleState.Collapsed, parentHandle: '0/0:b' }
{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed },
{ handle: '0/0:b/0:ba', label: { label: 'ba' }, collapsibleState: TreeItemCollapsibleState.Collapsed, parentHandle: '0/0:b' }
], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
assert.deepEqual({ select: false, focus: false }, revealTarget.args[0][3]);
assert.deepEqual({ select: false, focus: false, expand: false }, revealTarget.args[0][3]);
});
});
function loadCompleteTree(treeId, element?: string): TPromise<void> {
test('reveal after first udpate', () => {
const revealTarget = sinon.spy(target, '$reveal');
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
return loadCompleteTree('treeDataProvider')
.then(() => {
tree = {
'a': {
'aa': {},
'ac': {}
},
'b': {
'ba': {},
'bb': {}
}
};
onDidChangeTreeNode.fire(getNode('a'));
return treeView.reveal({ key: 'ac' })
.then(() => {
assert.ok(revealTarget.calledOnce);
assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
assert.deepEqual({ handle: '0/0:a/0:ac', label: { label: 'ac' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:a' }, removeUnsetKeys(revealTarget.args[0][1]));
assert.deepEqual([{ handle: '0/0:a', label: { label: 'a' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]);
});
});
});
test('reveal after second udpate', () => {
const revealTarget = sinon.spy(target, '$reveal');
const treeView = testObject.createTreeView('treeDataProvider', { treeDataProvider: aCompleteNodeTreeDataProvider() }, { enableProposedApi: true } as IExtensionDescription);
return loadCompleteTree('treeDataProvider')
.then(() => {
tree = {
'a': {
'aa': {},
'ac': {}
},
'b': {
'ba': {},
'bb': {}
}
};
onDidChangeTreeNode.fire(getNode('a'));
tree = {
'a': {
'aa': {},
'ac': {}
},
'b': {
'ba': {},
'bc': {}
}
};
onDidChangeTreeNode.fire(getNode('b'));
return treeView.reveal({ key: 'bc' })
.then(() => {
assert.ok(revealTarget.calledOnce);
assert.deepEqual('treeDataProvider', revealTarget.args[0][0]);
assert.deepEqual({ handle: '0/0:b/0:bc', label: { label: 'bc' }, collapsibleState: TreeItemCollapsibleState.None, parentHandle: '0/0:b' }, removeUnsetKeys(revealTarget.args[0][1]));
assert.deepEqual([{ handle: '0/0:b', label: { label: 'b' }, collapsibleState: TreeItemCollapsibleState.Collapsed }], (<Array<any>>revealTarget.args[0][2]).map(arg => removeUnsetKeys(arg)));
assert.deepEqual({ select: true, focus: false, expand: false }, revealTarget.args[0][3]);
});
});
});
function loadCompleteTree(treeId, element?: string) {
return testObject.$getChildren(treeId, element)
.then(elements => elements.map(e => loadCompleteTree(treeId, e.handle)))
.then(() => null);
}
function removeUnsetKeys(obj: any): any {
const result = {};
for (const key of Object.keys(obj)) {
if (obj[key] !== void 0) {
result[key] = obj[key];
}
if (Array.isArray(obj)) {
return obj.map(o => removeUnsetKeys(o));
}
return result;
if (typeof obj === 'object') {
const result = {};
for (const key of Object.keys(obj)) {
if (obj[key] !== void 0) {
result[key] = removeUnsetKeys(obj[key]);
}
}
return result;
}
return obj;
}
function aNodeTreeDataProvider(): TreeDataProvider<{ key: string }> {
@@ -529,6 +647,20 @@ suite('ExtHostTreeView', function () {
};
}
function aNodeWithHighlightedLabelTreeDataProvider(): TreeDataProvider<{ key: string }> {
return {
getChildren: (element: { key: string }): { key: string }[] => {
return getChildren(element ? element.key : undefined).map(key => getNode(key));
},
getTreeItem: (element: { key: string }): TreeItem => {
const treeItem = getTreeItem(element.key, [[0, 2], [3, 5]]);
treeItem.id = element.key;
return treeItem;
},
onDidChangeTreeData: onDidChangeTreeNodeWithId.event
};
}
function getTreeElement(element): any {
let parent = tree;
for (let i = 0; i < element.length; i++) {
@@ -551,10 +683,10 @@ suite('ExtHostTreeView', function () {
return [];
}
function getTreeItem(key: string): TreeItem {
function getTreeItem(key: string, highlights?: [number, number][]): TreeItem {
const treeElement = getTreeElement(key);
return {
label: labels[key] || key,
label: <any>{ label: labels[key] || key, highlights },
collapsibleState: treeElement && Object.keys(treeElement).length ? TreeItemCollapsibleState.Collapsed : TreeItemCollapsibleState.None
};
}
@@ -570,4 +702,4 @@ suite('ExtHostTreeView', function () {
constructor(readonly key: string) { }
}
});
});

View File

@@ -0,0 +1,71 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { MarkdownString, LogLevel } from 'vs/workbench/api/node/extHostTypeConverters';
import { isEmptyObject } from 'vs/base/common/types';
import { size } from 'vs/base/common/collections';
import * as types from 'vs/workbench/api/node/extHostTypes';
import { LogLevel as _MainLogLevel } from 'vs/platform/log/common/log';
suite('ExtHostTypeConverter', function () {
test('MarkdownConvert - uris', function () {
let data = MarkdownString.from('Hello');
assert.equal(isEmptyObject(data.uris), true);
assert.equal(data.value, 'Hello');
data = MarkdownString.from('Hello [link](foo)');
assert.equal(data.value, 'Hello [link](foo)');
assert.equal(isEmptyObject(data.uris), true); // no scheme, no uri
data = MarkdownString.from('Hello [link](www.noscheme.bad)');
assert.equal(data.value, 'Hello [link](www.noscheme.bad)');
assert.equal(isEmptyObject(data.uris), true); // no scheme, no uri
data = MarkdownString.from('Hello [link](foo:path)');
assert.equal(data.value, 'Hello [link](foo:path)');
assert.equal(size(data.uris), 1);
assert.ok(!!data.uris['foo:path']);
data = MarkdownString.from('hello@foo.bar');
assert.equal(data.value, 'hello@foo.bar');
assert.equal(size(data.uris), 1);
assert.ok(!!data.uris['mailto:hello@foo.bar']);
data = MarkdownString.from('*hello* [click](command:me)');
assert.equal(data.value, '*hello* [click](command:me)');
assert.equal(size(data.uris), 1);
assert.ok(!!data.uris['command:me']);
data = MarkdownString.from('*hello* [click](file:///somepath/here). [click](file:///somepath/here)');
assert.equal(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here)');
assert.equal(size(data.uris), 1);
assert.ok(!!data.uris['file:///somepath/here']);
data = MarkdownString.from('*hello* [click](file:///somepath/here). [click](file:///somepath/here)');
assert.equal(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here)');
assert.equal(size(data.uris), 1);
assert.ok(!!data.uris['file:///somepath/here']);
data = MarkdownString.from('*hello* [click](file:///somepath/here). [click](file:///somepath/here2)');
assert.equal(data.value, '*hello* [click](file:///somepath/here). [click](file:///somepath/here2)');
assert.equal(size(data.uris), 2);
assert.ok(!!data.uris['file:///somepath/here']);
assert.ok(!!data.uris['file:///somepath/here2']);
});
test('LogLevel', () => {
assert.equal(LogLevel.from(types.LogLevel.Error), _MainLogLevel.Error);
assert.equal(LogLevel.from(types.LogLevel.Info), _MainLogLevel.Info);
assert.equal(LogLevel.from(types.LogLevel.Off), _MainLogLevel.Off);
assert.equal(LogLevel.to(_MainLogLevel.Error), types.LogLevel.Error);
assert.equal(LogLevel.to(_MainLogLevel.Info), types.LogLevel.Info);
assert.equal(LogLevel.to(_MainLogLevel.Off), types.LogLevel.Off);
});
});

View File

@@ -3,10 +3,8 @@
* 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 { URI } from 'vs/base/common/uri';
import * as types from 'vs/workbench/api/node/extHostTypes';
import { isWindows } from 'vs/base/common/platform';
@@ -45,7 +43,7 @@ suite('ExtHostTypes', function () {
});
});
test('Disposable', function () {
test('Disposable', () => {
let count = 0;
let d = new types.Disposable(() => {
@@ -72,7 +70,7 @@ suite('ExtHostTypes', function () {
});
test('Position', function () {
test('Position', () => {
assert.throws(() => new types.Position(-1, 0));
assert.throws(() => new types.Position(0, -1));
@@ -187,7 +185,7 @@ suite('ExtHostTypes', function () {
assert.throws(() => p1.with({ character: -1 }));
});
test('Range', function () {
test('Range', () => {
assert.throws(() => new types.Range(-1, 0, 0, 0));
assert.throws(() => new types.Range(0, -1, 0, 0));
assert.throws(() => new types.Range(new types.Position(0, 0), undefined));
@@ -331,7 +329,7 @@ suite('ExtHostTypes', function () {
assert.throws(() => range.with(undefined, null));
});
test('TextEdit', function () {
test('TextEdit', () => {
let range = new types.Range(1, 1, 2, 11);
let edit = new types.TextEdit(range, undefined);
@@ -345,7 +343,7 @@ suite('ExtHostTypes', function () {
assert.equal(edit.newText, '');
});
test('WorkspaceEdit', function () {
test('WorkspaceEdit', () => {
let a = URI.file('a.ts');
let b = URI.file('b.ts');
@@ -386,12 +384,12 @@ suite('ExtHostTypes', function () {
const all = edit._allEntries();
assert.equal(all.length, 4);
function isFileChange(thing: [URI, types.TextEdit[]] | [URI, URI, { overwrite?: boolean }]): thing is [URI, URI, { overwrite?: boolean }] {
function isFileChange(thing: [URI, types.TextEdit[]] | [URI?, URI?, { overwrite?: boolean }?]): thing is [URI?, URI?, { overwrite?: boolean }?] {
const [f, s] = thing;
return URI.isUri(f) && URI.isUri(s);
}
function isTextChange(thing: [URI, types.TextEdit[]] | [URI, URI, { overwrite?: boolean }]): thing is [URI, types.TextEdit[]] {
function isTextChange(thing: [URI, types.TextEdit[]] | [URI?, URI?, { overwrite?: boolean }?]): thing is [URI, types.TextEdit[]] {
const [f, s] = thing;
return URI.isUri(f) && Array.isArray(s);
}
@@ -424,7 +422,7 @@ suite('ExtHostTypes', function () {
assert.equal((second as [URI, types.TextEdit[]])[1][0].newText, 'Foo');
});
test('DocumentLink', function () {
test('DocumentLink', () => {
assert.throws(() => new types.DocumentLink(null, null));
assert.throws(() => new types.DocumentLink(new types.Range(1, 1, 1, 1), null));
});

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { MainThreadWebviews } from 'vs/workbench/api/electron-browser/mainThreadWebview';
import { ExtHostWebviews } from 'vs/workbench/api/node/extHostWebview';

View File

@@ -3,10 +3,8 @@
* 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 { URI } from 'vs/base/common/uri';
import { basename } from 'path';
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
import { TestRPCProtocol } from './testRPCProtocol';
@@ -15,6 +13,7 @@ import { IWorkspaceFolderData } from 'vs/platform/workspace/common/workspace';
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
import { NullLogService } from 'vs/platform/log/common/log';
import { IMainContext } from 'vs/workbench/api/node/extHost.protocol';
import { Counter } from 'vs/base/common/numbers';
suite('ExtHostWorkspace', function () {
@@ -39,9 +38,9 @@ suite('ExtHostWorkspace', function () {
}
}
test('asRelativePath', function () {
test('asRelativePath', () => {
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService());
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/Applications/NewsWoWBot'), 0)], name: 'Test' }, new NullLogService(), new Counter());
assertAsRelativePath(ws, '/Coding/Applications/NewsWoWBot/bernd/das/brot', 'bernd/das/brot');
assertAsRelativePath(ws, '/Apps/DartPubCache/hosted/pub.dartlang.org/convert-2.0.1/lib/src/hex.dart',
@@ -55,7 +54,7 @@ suite('ExtHostWorkspace', function () {
test('asRelativePath, same paths, #11402', function () {
const root = '/home/aeschli/workspaces/samples/docker';
const input = '/home/aeschli/workspaces/samples/docker';
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService());
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter());
assertAsRelativePath(ws, (input), input);
@@ -64,20 +63,20 @@ suite('ExtHostWorkspace', function () {
});
test('asRelativePath, no workspace', function () {
const ws = new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService());
const ws = new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService(), new Counter());
assertAsRelativePath(ws, (''), '');
assertAsRelativePath(ws, ('/foo/bar'), '/foo/bar');
});
test('asRelativePath, multiple folders', function () {
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter());
assertAsRelativePath(ws, '/Coding/One/file.txt', 'One/file.txt');
assertAsRelativePath(ws, '/Coding/Two/files/out.txt', 'Two/files/out.txt');
assertAsRelativePath(ws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt');
});
test('slightly inconsistent behaviour of asRelativePath and getWorkspaceFolder, #31553', function () {
const mrws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
const mrws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter());
assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt');
assertAsRelativePath(mrws, '/Coding/One/file.txt', 'One/file.txt', true);
@@ -89,7 +88,7 @@ suite('ExtHostWorkspace', function () {
assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', true);
assertAsRelativePath(mrws, '/Coding/Two2/files/out.txt', '/Coding/Two2/files/out.txt', false);
const srws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService());
const srws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0)], name: 'Test' }, new NullLogService(), new Counter());
assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt');
assertAsRelativePath(srws, '/Coding/One/file.txt', 'file.txt', false);
assertAsRelativePath(srws, '/Coding/One/file.txt', 'One/file.txt', true);
@@ -99,24 +98,24 @@ suite('ExtHostWorkspace', function () {
});
test('getPath, legacy', function () {
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter());
assert.equal(ws.getPath(), undefined);
ws = new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService());
ws = new ExtHostWorkspace(new TestRPCProtocol(), null, new NullLogService(), new Counter());
assert.equal(ws.getPath(), undefined);
ws = new ExtHostWorkspace(new TestRPCProtocol(), undefined, new NullLogService());
ws = new ExtHostWorkspace(new TestRPCProtocol(), undefined, new NullLogService(), new Counter());
assert.equal(ws.getPath(), undefined);
ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService());
ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('Folder'), 0), aWorkspaceFolderData(URI.file('Another/Folder'), 1)] }, new NullLogService(), new Counter());
assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder');
ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService());
ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.file('/Folder'), 0)] }, new NullLogService(), new Counter());
assert.equal(ws.getPath().replace(/\\/g, '/'), '/Folder');
});
test('WorkspaceFolder has name and index', function () {
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService());
const ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', folders: [aWorkspaceFolderData(URI.file('/Coding/One'), 0), aWorkspaceFolderData(URI.file('/Coding/Two'), 1)], name: 'Test' }, new NullLogService(), new Counter());
const [one, two] = ws.getWorkspaceFolders();
@@ -126,7 +125,7 @@ suite('ExtHostWorkspace', function () {
assert.equal(two.index, 1);
});
test('getContainingWorkspaceFolder', function () {
test('getContainingWorkspaceFolder', () => {
const ws = new ExtHostWorkspace(new TestRPCProtocol(), {
id: 'foo',
name: 'Test',
@@ -135,7 +134,7 @@ suite('ExtHostWorkspace', function () {
aWorkspaceFolderData(URI.file('/Coding/Two'), 1),
aWorkspaceFolderData(URI.file('/Coding/Two/Nested'), 2)
]
}, new NullLogService());
}, new NullLogService(), new Counter());
let folder = ws.getWorkspaceFolder(URI.file('/foo/bar'));
assert.equal(folder, undefined);
@@ -175,7 +174,7 @@ suite('ExtHostWorkspace', function () {
});
test('Multiroot change event should have a delta, #29641', function (done) {
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter());
let finished = false;
const finish = (error?: any) => {
@@ -238,7 +237,7 @@ suite('ExtHostWorkspace', function () {
});
test('Multiroot change keeps existing workspaces live', function () {
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService());
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter());
let firstFolder = ws.getWorkspaceFolders()[0];
ws.$acceptWorkspaceData({ id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar2'), 0), aWorkspaceFolderData(URI.parse('foo:bar'), 1, 'renamed')] });
@@ -258,7 +257,7 @@ suite('ExtHostWorkspace', function () {
});
test('updateWorkspaceFolders - invalid arguments', function () {
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
let ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter());
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, null, null));
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 0));
@@ -267,7 +266,7 @@ suite('ExtHostWorkspace', function () {
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, 0));
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, -1, -1));
ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService());
ws = new ExtHostWorkspace(new TestRPCProtocol(), { id: 'foo', name: 'Test', folders: [aWorkspaceFolderData(URI.parse('foo:bar'), 0)] }, new NullLogService(), new Counter());
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 1, 1));
assert.equal(false, ws.updateWorkspaceFolders(extensionDescriptor, 0, 2));
@@ -276,20 +275,20 @@ suite('ExtHostWorkspace', function () {
test('updateWorkspaceFolders - valid arguments', function (done) {
let finished = false;
const finish = (error?) => {
const finish = (error?: any) => {
if (!finished) {
finished = true;
done(error);
}
};
const protocol = {
const protocol: IMainContext = {
getProxy: () => { return undefined; },
set: undefined,
assertRegistered: undefined
};
const ws = new ExtHostWorkspace(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService());
const ws = new ExtHostWorkspace(protocol, { id: 'foo', name: 'Test', folders: [] }, new NullLogService(), new Counter());
//
// Add one folder
@@ -512,7 +511,7 @@ suite('ExtHostWorkspace', function () {
finish();
});
// {{SQL CARBON EDIT}} remove broken test
test('`vscode.workspace.getWorkspaceFolder(file)` don\'t return workspace folder when file open from command line. #36221', function () {
@@ -520,7 +519,7 @@ suite('ExtHostWorkspace', function () {
id: 'foo', name: 'Test', folders: [
aWorkspaceFolderData(URI.file('c:/Users/marek/Desktop/vsc_test/'), 0)
]
}, new NullLogService());
}, new NullLogService(), new Counter());
assert.ok(ws.getWorkspaceFolder(URI.file('c:/Users/marek/Desktop/vsc_test/a.txt')));
assert.ok(ws.getWorkspaceFolder(URI.file('C:/Users/marek/Desktop/vsc_test/b.txt')));

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { MainThreadCommands } from 'vs/workbench/api/electron-browser/mainThreadCommands';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';

View File

@@ -3,11 +3,9 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import * as sinon from 'sinon';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions, IConfigurationRegistry, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';

View File

@@ -3,12 +3,10 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { MarkerService } from 'vs/platform/markers/common/markerService';
import { MainThreadDiagnostics } from 'vs/workbench/api/electron-browser/mainThreadDiagnostics';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
suite('MainThreadDiagnostics', function () {

View File

@@ -0,0 +1,54 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { URI } from 'vs/base/common/uri';
import { MainThreadDocumentContentProviders } from 'vs/workbench/api/electron-browser/mainThreadDocumentContentProviders';
import { TextModel } from 'vs/editor/common/model/textModel';
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorkerService';
import { TestRPCProtocol } from 'vs/workbench/test/electron-browser/api/testRPCProtocol';
suite('MainThreadDocumentContentProviders', function () {
test('events are processed properly', function () {
let uri = URI.parse('test:uri');
let model = TextModel.createFromString('1', undefined, undefined, uri);
let providers = new MainThreadDocumentContentProviders(new TestRPCProtocol(), null, null,
new class extends mock<IModelService>() {
getModel(_uri) {
assert.equal(uri.toString(), _uri.toString());
return model;
}
},
new class extends mock<IEditorWorkerService>() {
computeMoreMinimalEdits(_uri, data) {
assert.equal(model.getValue(), '1');
return Promise.resolve(data);
}
},
);
return new Promise((resolve, reject) => {
let expectedEvents = 1;
model.onDidChangeContent(e => {
expectedEvents -= 1;
try {
assert.ok(expectedEvents >= 0);
} catch (err) {
reject(err);
}
if (model.getValue() === '1\n2\n3') {
resolve();
}
});
providers.$onVirtualDocumentChange(uri, '1\n2');
providers.$onVirtualDocumentChange(uri, '1\n2\n3');
});
});
});

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { BoundModelReferenceCollection } from 'vs/workbench/api/electron-browser/mainThreadDocuments';
import { TextModel } from 'vs/editor/common/model/textModel';
@@ -18,7 +16,7 @@ suite('BoundModelReferenceCollection', () => {
col.dispose();
});
test('max age', () => {
test('max age', async () => {
let didDispose = false;
@@ -29,9 +27,8 @@ suite('BoundModelReferenceCollection', () => {
}
});
return timeout(30).then(() => {
assert.equal(didDispose, true);
});
await timeout(30);
assert.equal(didDispose, true);
});
test('max size', () => {

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors';
import { SingleProxyRPCProtocol } from './testRPCProtocol';
@@ -15,12 +13,13 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile
import { ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta } from 'vs/workbench/api/node/extHost.protocol';
import { createTestCodeEditor, TestCodeEditor } from 'vs/editor/test/browser/testCodeEditor';
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
import { TestEditorService, TestEditorGroupsService } from 'vs/workbench/test/workbenchTestServices';
import { TestEditorService, TestEditorGroupsService, TestTextResourcePropertiesService } from 'vs/workbench/test/workbenchTestServices';
import { Event } from 'vs/base/common/event';
import { ITextModel } from 'vs/editor/common/model';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { IFileService } from 'vs/platform/files/common/files';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
suite('MainThreadDocumentsAndEditors', () => {
@@ -43,7 +42,7 @@ suite('MainThreadDocumentsAndEditors', () => {
deltas.length = 0;
const configService = new TestConfigurationService();
configService.setUserConfiguration('editor', { 'detectIndentation': false });
modelService = new ModelServiceImpl(null, configService);
modelService = new ModelServiceImpl(null, configService, new TestTextResourcePropertiesService(configService));
codeEditorService = new TestCodeEditorService();
textFileService = new class extends mock<ITextFileService>() {
isDirty() { return false; }
@@ -74,7 +73,15 @@ suite('MainThreadDocumentsAndEditors', () => {
null,
null,
editorGroupService,
null
null,
new class extends mock<IPanelService>() implements IPanelService {
_serviceBrand: any;
onDidPanelOpen = Event.None;
onDidPanelClose = Event.None;
getActivePanel() {
return null;
}
}
);
/* tslint:enable */
});

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/electron-browser/mainThreadDocumentsAndEditors';
import { SingleProxyRPCProtocol, TestRPCProtocol } from './testRPCProtocol';
@@ -16,19 +14,19 @@ import { ExtHostDocumentsAndEditorsShape, ExtHostContext, ExtHostDocumentsShape
import { mock } from 'vs/workbench/test/electron-browser/api/mock';
import { Event } from 'vs/base/common/event';
import { MainThreadTextEditors } from 'vs/workbench/api/electron-browser/mainThreadEditors';
import URI from 'vs/base/common/uri';
import { URI } from 'vs/base/common/uri';
import { Range } from 'vs/editor/common/core/range';
import { Position } from 'vs/editor/common/core/position';
import { IModelService } from 'vs/editor/common/services/modelService';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { TestFileService, TestEditorService, TestEditorGroupsService, TestEnvironmentService, TestContextService } from 'vs/workbench/test/workbenchTestServices';
import { TPromise } from 'vs/base/common/winjs.base';
import { TestFileService, TestEditorService, TestEditorGroupsService, TestEnvironmentService, TestContextService, TestTextResourcePropertiesService, TestWindowService } from 'vs/workbench/test/workbenchTestServices';
import { ResourceTextEdit } from 'vs/editor/common/modes';
import { BulkEditService } from 'vs/workbench/services/bulkEdit/electron-browser/bulkEditService';
import { NullLogService } from 'vs/platform/log/common/log';
import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService';
import { IReference, ImmortalReference } from 'vs/base/common/lifecycle';
import { UriDisplayService } from 'vs/platform/uriDisplay/common/uriDisplay';
import { LabelService } from 'vs/platform/label/common/label';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
suite('MainThreadEditors', () => {
@@ -43,7 +41,7 @@ suite('MainThreadEditors', () => {
setup(() => {
const configService = new TestConfigurationService();
modelService = new ModelServiceImpl(null, configService);
modelService = new ModelServiceImpl(null, configService, new TestTextResourcePropertiesService(configService));
const codeEditorService = new TestCodeEditorService();
movedResources.clear();
@@ -56,15 +54,15 @@ suite('MainThreadEditors', () => {
isDirty() { return false; }
create(uri: URI, contents?: string, options?: any) {
createdResources.add(uri);
return TPromise.as(void 0);
return Promise.resolve(void 0);
}
delete(resource: URI) {
deletedResources.add(resource);
return TPromise.as(void 0);
return Promise.resolve(void 0);
}
move(source: URI, target: URI) {
movedResources.set(source, target);
return TPromise.as(void 0);
return Promise.resolve(void 0);
}
models = <any>{
onModelSaved: Event.None,
@@ -75,15 +73,16 @@ suite('MainThreadEditors', () => {
const workbenchEditorService = new TestEditorService();
const editorGroupService = new TestEditorGroupsService();
const textModelService = new class extends mock<ITextModelService>() {
createModelReference(resource: URI): TPromise<IReference<ITextEditorModel>> {
createModelReference(resource: URI): Promise<IReference<ITextEditorModel>> {
const textEditorModel: ITextEditorModel = new class extends mock<ITextEditorModel>() {
textEditorModel = modelService.getModel(resource);
};
return TPromise.as(new ImmortalReference(textEditorModel));
textEditorModel.isReadonly = () => false;
return Promise.resolve(new ImmortalReference(textEditorModel));
}
};
const bulkEditService = new BulkEditService(new NullLogService(), modelService, new TestEditorService(), textModelService, new TestFileService(), textFileService, new UriDisplayService(TestEnvironmentService, new TestContextService()));
const bulkEditService = new BulkEditService(new NullLogService(), modelService, new TestEditorService(), textModelService, new TestFileService(), textFileService, new LabelService(TestEnvironmentService, new TestContextService(), new TestWindowService()), configService);
const rpcProtocol = new TestRPCProtocol();
rpcProtocol.set(ExtHostContext.ExtHostDocuments, new class extends mock<ExtHostDocumentsShape>() {
@@ -107,6 +106,14 @@ suite('MainThreadEditors', () => {
null,
editorGroupService,
bulkEditService,
new class extends mock<IPanelService>() implements IPanelService {
_serviceBrand: any;
onDidPanelOpen = Event.None;
onDidPanelClose = Event.None;
getActivePanel() {
return null;
}
}
);
editors = new MainThreadTextEditors(
@@ -169,7 +176,7 @@ suite('MainThreadEditors', () => {
// second edit request fails
assert.equal(result, false);
});
return TPromise.join([p1, p2]);
return Promise.all([p1, p2]);
});
test(`applyWorkspaceEdit with only resource edit`, () => {

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { FinalNewLineParticipant, TrimFinalNewLinesParticipant } from 'vs/workbench/api/electron-browser/mainThreadSaveParticipant';
@@ -39,131 +37,125 @@ suite('MainThreadSaveParticipant', function () {
TextFileEditorModel.setSaveParticipant(null); // reset any set participant
});
test('insert final new line', function () {
test('insert final new line', async function () {
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/final_new_line.txt'), 'utf8');
return model.load().then(() => {
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'insertFinalNewline': true });
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'insertFinalNewline': true });
const participant = new FinalNewLineParticipant(configService, undefined);
const participant = new FinalNewLineParticipant(configService, undefined);
// No new line for empty lines
let lineContent = '';
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
// No new line for empty lines
let lineContent = '';
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
// No new line if last line already empty
lineContent = `Hello New Line${model.textEditorModel.getEOL()}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
// No new line if last line already empty
lineContent = `Hello New Line${model.textEditorModel.getEOL()}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
// New empty line added (single line)
lineContent = 'Hello New Line';
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${lineContent}${model.textEditorModel.getEOL()}`);
// New empty line added (single line)
lineContent = 'Hello New Line';
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${lineContent}${model.textEditorModel.getEOL()}`);
// New empty line added (multi line)
lineContent = `Hello New Line${model.textEditorModel.getEOL()}Hello New Line${model.textEditorModel.getEOL()}Hello New Line`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${lineContent}${model.textEditorModel.getEOL()}`);
});
// New empty line added (multi line)
lineContent = `Hello New Line${model.textEditorModel.getEOL()}Hello New Line${model.textEditorModel.getEOL()}Hello New Line`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${lineContent}${model.textEditorModel.getEOL()}`);
});
test('trim final new lines', function () {
test('trim final new lines', async function () {
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8');
return model.load().then(() => {
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
const textContent = 'Trim New Line';
const eol = `${model.textEditorModel.getEOL()}`;
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
// No new line removal if last line is not new line
let lineContent = `${textContent}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
const textContent = 'Trim New Line';
const eol = `${model.textEditorModel.getEOL()}`;
// No new line removal if last line is single new line
lineContent = `${textContent}${eol}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
// No new line removal if last line is not new line
let lineContent = `${textContent}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
// Remove new line (single line with two new lines)
lineContent = `${textContent}${eol}${eol}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`);
// No new line removal if last line is single new line
lineContent = `${textContent}${eol}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), lineContent);
// Remove new line (single line with two new lines)
lineContent = `${textContent}${eol}${eol}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`);
// Remove new lines (multiple lines with multiple new lines)
lineContent = `${textContent}${eol}${textContent}${eol}${eol}${eol}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}${textContent}${eol}`);
});
// Remove new lines (multiple lines with multiple new lines)
lineContent = `${textContent}${eol}${textContent}${eol}${eol}${eol}`;
model.textEditorModel.setValue(lineContent);
participant.participate(model, { reason: SaveReason.EXPLICIT });
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}${textContent}${eol}`);
});
test('trim final new lines bug#39750', function () {
test('trim final new lines bug#39750', async function () {
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8');
return model.load().then(() => {
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
const textContent = 'Trim New Line';
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
// single line
let lineContent = `${textContent}`;
model.textEditorModel.setValue(lineContent);
const textContent = 'Trim New Line';
// apply edits and push to undo stack.
let textEdits = [{ range: new Range(1, 14, 1, 14), text: '.', forceMoveMarkers: false }];
model.textEditorModel.pushEditOperations([new Selection(1, 14, 1, 14)], textEdits, () => { return [new Selection(1, 15, 1, 15)]; });
// single line
let lineContent = `${textContent}`;
model.textEditorModel.setValue(lineContent);
// apply edits and push to undo stack.
let textEdits = [{ range: new Range(1, 14, 1, 14), text: '.', forceMoveMarkers: false }];
model.textEditorModel.pushEditOperations([new Selection(1, 14, 1, 14)], textEdits, () => { return [new Selection(1, 15, 1, 15)]; });
// undo
model.textEditorModel.undo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}`);
// trim final new lines should not mess the undo stack
participant.participate(model, { reason: SaveReason.EXPLICIT });
model.textEditorModel.redo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}.`);
});
// undo
model.textEditorModel.undo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}`);
// trim final new lines should not mess the undo stack
participant.participate(model, { reason: SaveReason.EXPLICIT });
model.textEditorModel.redo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}.`);
});
test('trim final new lines bug#46075', function () {
test('trim final new lines bug#46075', async function () {
const model: TextFileEditorModel = instantiationService.createInstance(TextFileEditorModel, toResource.call(this, '/path/trim_final_new_line.txt'), 'utf8');
return model.load().then(() => {
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
await model.load();
const configService = new TestConfigurationService();
configService.setUserConfiguration('files', { 'trimFinalNewlines': true });
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
const textContent = 'Test';
const eol = `${model.textEditorModel.getEOL()}`;
let content = `${textContent}${eol}${eol}`;
model.textEditorModel.setValue(content);
const participant = new TrimFinalNewLinesParticipant(configService, undefined);
// save many times
for (let i = 0; i < 10; i++) {
participant.participate(model, { reason: SaveReason.EXPLICIT });
}
const textContent = 'Test';
const eol = `${model.textEditorModel.getEOL()}`;
// confirm trimming
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`);
let content = `${textContent}${eol}${eol}`;
model.textEditorModel.setValue(content);
// save many times
for (let i = 0; i < 10; i++) {
participant.participate(model, { reason: SaveReason.EXPLICIT });
}
// confirm trimming
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`);
// undo should go back to previous content immediately
model.textEditorModel.undo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}${eol}`);
model.textEditorModel.redo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`);
});
// undo should go back to previous content immediately
model.textEditorModel.undo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}${eol}`);
model.textEditorModel.redo();
assert.equal(snapshotToString(model.createSnapshot()), `${textContent}${eol}`);
});
});

View File

@@ -3,8 +3,6 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
export interface Ctor<T> {
new(): T;
}

View File

@@ -3,15 +3,14 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { ProxyIdentifier } from 'vs/workbench/services/extensions/node/proxyIdentifier';
import { CharCode } from 'vs/base/common/charCode';
import { IExtHostContext } from 'vs/workbench/api/node/extHost.protocol';
import { isThenable } from 'vs/base/common/async';
export function SingleProxyRPCProtocol(thing: any): IExtHostContext {
return {
remoteAuthority: null,
getProxy<T>(): T {
return thing;
},
@@ -22,10 +21,10 @@ export function SingleProxyRPCProtocol(thing: any): IExtHostContext {
};
}
declare var Proxy: any; // TODO@TypeScript
export class TestRPCProtocol implements IExtHostContext {
public remoteAuthority = null;
private _callCountValue: number = 0;
private _idle: Promise<any>;
private _completeIdle: Function;
@@ -69,10 +68,10 @@ export class TestRPCProtocol implements IExtHostContext {
}
public getProxy<T>(identifier: ProxyIdentifier<T>): T {
if (!this._proxies[identifier.id]) {
this._proxies[identifier.id] = this._createProxy(identifier.id);
if (!this._proxies[identifier.sid]) {
this._proxies[identifier.sid] = this._createProxy(identifier.sid);
}
return this._proxies[identifier.id];
return this._proxies[identifier.sid];
}
private _createProxy<T>(proxyId: string): T {
@@ -90,14 +89,14 @@ export class TestRPCProtocol implements IExtHostContext {
}
public set<T, R extends T>(identifier: ProxyIdentifier<T>, value: R): R {
this._locals[identifier.id] = value;
this._locals[identifier.sid] = value;
return value;
}
protected _remoteCall(proxyId: string, path: string, args: any[]): TPromise<any> {
protected _remoteCall(proxyId: string, path: string, args: any[]): Promise<any> {
this._callCount++;
return new TPromise<any>((c) => {
return new Promise<any>((c) => {
setTimeout(c, 0);
}).then(() => {
const instance = this._locals[proxyId];
@@ -106,9 +105,9 @@ export class TestRPCProtocol implements IExtHostContext {
let p: Thenable<any>;
try {
let result = (<Function>instance[path]).apply(instance, wireArgs);
p = TPromise.is(result) ? result : TPromise.as(result);
p = isThenable(result) ? result : Promise.resolve(result);
} catch (err) {
p = TPromise.wrapError(err);
p = Promise.reject(err);
}
return p.then(result => {
@@ -118,7 +117,7 @@ export class TestRPCProtocol implements IExtHostContext {
return wireResult;
}, err => {
this._callCount--;
return TPromise.wrapError(err);
return Promise.reject(err);
});
});
}