add API tests that run on a workspace

This commit is contained in:
Benjamin Pasero
2018-01-26 16:16:36 +01:00
parent faa7f4c659
commit 86244d39a7
16 changed files with 128 additions and 12 deletions

View File

@@ -0,0 +1,138 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import 'mocha';
import * as assert from 'assert';
import { join } from 'path';
import { commands, workspace, window, Uri, ViewColumn, Range, Position } from 'vscode';
suite('commands namespace tests', () => {
test('getCommands', function (done) {
let p1 = commands.getCommands().then(commands => {
let hasOneWithUnderscore = false;
for (let command of commands) {
if (command[0] === '_') {
hasOneWithUnderscore = true;
break;
}
}
assert.ok(hasOneWithUnderscore);
}, done);
let p2 = commands.getCommands(true).then(commands => {
let hasOneWithUnderscore = false;
for (let command of commands) {
if (command[0] === '_') {
hasOneWithUnderscore = true;
break;
}
}
assert.ok(!hasOneWithUnderscore);
}, done);
Promise.all([p1, p2]).then(() => {
done();
}, done);
});
test('command with args', function () {
let args: IArguments;
let registration = commands.registerCommand('t1', function () {
args = arguments;
});
return commands.executeCommand('t1', 'start').then(() => {
registration.dispose();
assert.ok(args);
assert.equal(args.length, 1);
assert.equal(args[0], 'start');
});
});
test('editorCommand with extra args', function () {
let args: IArguments;
let registration = commands.registerTextEditorCommand('t1', function () {
args = arguments;
});
return workspace.openTextDocument(join(workspace.rootPath || '', './far.js')).then(doc => {
return window.showTextDocument(doc).then(editor => {
return commands.executeCommand('t1', 12345, commands);
}).then(() => {
assert.ok(args);
assert.equal(args.length, 4);
assert.ok(args[2] === 12345);
assert.ok(args[3] === commands);
registration.dispose();
});
});
});
test('api-command: vscode.previewHtm', function () {
let registration = workspace.registerTextDocumentContentProvider('speciale', {
provideTextDocumentContent(uri) {
return `content of URI <b>${uri.toString()}</b>`;
}
});
let virtualDocumentUri = Uri.parse('speciale://authority/path');
let title = 'A title';
return commands.executeCommand('vscode.previewHtml', virtualDocumentUri, ViewColumn.Three, title).then(success => {
assert.ok(success);
registration.dispose();
});
});
test('api-command: vscode.diff', function () {
let registration = workspace.registerTextDocumentContentProvider('sc', {
provideTextDocumentContent(uri) {
return `content of URI <b>${uri.toString()}</b>#${Math.random()}`;
}
});
let a = commands.executeCommand('vscode.diff', Uri.parse('sc:a'), Uri.parse('sc:b'), 'DIFF').then(value => {
assert.ok(value === void 0);
registration.dispose();
});
let b = commands.executeCommand('vscode.diff', Uri.parse('sc:a'), Uri.parse('sc:b')).then(value => {
assert.ok(value === void 0);
registration.dispose();
});
let c = commands.executeCommand('vscode.diff', Uri.parse('sc:a'), Uri.parse('sc:b'), 'Title', { selection: new Range(new Position(1, 1), new Position(1, 2)) }).then(value => {
assert.ok(value === void 0);
registration.dispose();
});
let d = commands.executeCommand('vscode.diff').then(() => assert.ok(false), () => assert.ok(true));
let e = commands.executeCommand('vscode.diff', 1, 2, 3).then(() => assert.ok(false), () => assert.ok(true));
return Promise.all([a, b, c, d, e]);
});
test('api-command: vscode.open', function () {
let uri = Uri.file(join(workspace.rootPath || '', './image.png'));
let a = commands.executeCommand('vscode.open', uri).then(() => assert.ok(true), () => assert.ok(false));
let b = commands.executeCommand('vscode.open', uri, ViewColumn.Two).then(() => assert.ok(true), () => assert.ok(false));
let c = commands.executeCommand('vscode.open').then(() => assert.ok(false), () => assert.ok(true));
let d = commands.executeCommand('vscode.open', uri, true).then(() => assert.ok(false), () => assert.ok(true));
return Promise.all([a, b, c, d]);
});
});

View File

@@ -0,0 +1,46 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'mocha';
import * as assert from 'assert';
import * as vscode from 'vscode';
suite('Configuration tests', () => {
test('configurations, language defaults', function () {
const defaultLanguageSettings = vscode.workspace.getConfiguration().get('[abcLang]');
assert.deepEqual(defaultLanguageSettings, {
'editor.lineNumbers': 'off',
'editor.tabSize': 2
});
});
test('configuration, defaults', () => {
const config = vscode.workspace.getConfiguration('farboo');
assert.ok(config.has('config0'));
assert.equal(config.get('config0'), true);
assert.equal(config.get('config4'), '');
assert.equal(config['config0'], true);
assert.equal(config['config4'], '');
assert.throws(() => (<any>config)['config4'] = 'valuevalue');
assert.ok(config.has('nested.config1'));
assert.equal(config.get('nested.config1'), 42);
assert.ok(config.has('nested.config2'));
assert.equal(config.get('nested.config2'), 'Das Pferd frisst kein Reis.');
});
test('configuration, name vs property', () => {
const config = vscode.workspace.getConfiguration('farboo');
assert.ok(config.has('get'));
assert.equal(config.get('get'), 'get-prop');
assert.deepEqual(config['get'], config.get);
assert.throws(() => config['get'] = <any>'get-prop');
});
});

View File

@@ -0,0 +1,200 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { workspace, window, Position, Range, commands, TextEditor, TextDocument, TextEditorCursorStyle, TextEditorLineNumbersStyle, SnippetString, Selection } from 'vscode';
import { createRandomFile, deleteFile, closeAllEditors } from '../utils';
suite('editor tests', () => {
teardown(closeAllEditors);
function withRandomFileEditor(initialContents: string, run: (editor: TextEditor, doc: TextDocument) => Thenable<void>): Thenable<boolean> {
return createRandomFile(initialContents).then(file => {
return workspace.openTextDocument(file).then(doc => {
return window.showTextDocument(doc).then((editor) => {
return run(editor, doc).then(_ => {
if (doc.isDirty) {
return doc.save().then(saved => {
assert.ok(saved);
assert.ok(!doc.isDirty);
return deleteFile(file);
});
} else {
return deleteFile(file);
}
});
});
});
});
}
test('insert snippet', () => {
const snippetString = new SnippetString()
.appendText('This is a ')
.appendTabstop()
.appendPlaceholder('placeholder')
.appendText(' snippet');
return withRandomFileEditor('', (editor, doc) => {
return editor.insertSnippet(snippetString).then(inserted => {
assert.ok(inserted);
assert.equal(doc.getText(), 'This is a placeholder snippet');
assert.ok(doc.isDirty);
});
});
});
test('insert snippet with replacement, editor selection', () => {
const snippetString = new SnippetString()
.appendText('has been');
return withRandomFileEditor('This will be replaced', (editor, doc) => {
editor.selection = new Selection(
new Position(0, 5),
new Position(0, 12)
);
return editor.insertSnippet(snippetString).then(inserted => {
assert.ok(inserted);
assert.equal(doc.getText(), 'This has been replaced');
assert.ok(doc.isDirty);
});
});
});
test('insert snippet with replacement, selection as argument', () => {
const snippetString = new SnippetString()
.appendText('has been');
return withRandomFileEditor('This will be replaced', (editor, doc) => {
const selection = new Selection(
new Position(0, 5),
new Position(0, 12)
);
return editor.insertSnippet(snippetString, selection).then(inserted => {
assert.ok(inserted);
assert.equal(doc.getText(), 'This has been replaced');
assert.ok(doc.isDirty);
});
});
});
test('make edit', () => {
return withRandomFileEditor('', (editor, doc) => {
return editor.edit((builder) => {
builder.insert(new Position(0, 0), 'Hello World');
}).then(applied => {
assert.ok(applied);
assert.equal(doc.getText(), 'Hello World');
assert.ok(doc.isDirty);
});
});
});
test('issue #6281: Edits fail to validate ranges correctly before applying', () => {
return withRandomFileEditor('Hello world!', (editor, doc) => {
return editor.edit((builder) => {
builder.replace(new Range(0, 0, Number.MAX_VALUE, Number.MAX_VALUE), 'new');
}).then(applied => {
assert.ok(applied);
assert.equal(doc.getText(), 'new');
assert.ok(doc.isDirty);
});
});
});
function executeReplace(editor: TextEditor, range: Range, text: string, undoStopBefore: boolean, undoStopAfter: boolean): Thenable<boolean> {
return editor.edit((builder) => {
builder.replace(range, text);
}, { undoStopBefore: undoStopBefore, undoStopAfter: undoStopAfter });
}
test('TextEditor.edit can control undo/redo stack 1', () => {
return withRandomFileEditor('Hello world!', (editor, doc) => {
return executeReplace(editor, new Range(0, 0, 0, 1), 'h', false, false).then(applied => {
assert.ok(applied);
assert.equal(doc.getText(), 'hello world!');
assert.ok(doc.isDirty);
return executeReplace(editor, new Range(0, 1, 0, 5), 'ELLO', false, false);
}).then(applied => {
assert.ok(applied);
assert.equal(doc.getText(), 'hELLO world!');
assert.ok(doc.isDirty);
return commands.executeCommand('undo');
}).then(_ => {
assert.equal(doc.getText(), 'Hello world!');
});
});
});
test('TextEditor.edit can control undo/redo stack 2', () => {
return withRandomFileEditor('Hello world!', (editor, doc) => {
return executeReplace(editor, new Range(0, 0, 0, 1), 'h', false, false).then(applied => {
assert.ok(applied);
assert.equal(doc.getText(), 'hello world!');
assert.ok(doc.isDirty);
return executeReplace(editor, new Range(0, 1, 0, 5), 'ELLO', true, false);
}).then(applied => {
assert.ok(applied);
assert.equal(doc.getText(), 'hELLO world!');
assert.ok(doc.isDirty);
return commands.executeCommand('undo');
}).then(_ => {
assert.equal(doc.getText(), 'hello world!');
});
});
});
test('issue #16573: Extension API: insertSpaces and tabSize are undefined', () => {
return withRandomFileEditor('Hello world!\n\tHello world!', (editor, doc) => {
assert.equal(editor.options.tabSize, 4);
assert.equal(editor.options.insertSpaces, false);
assert.equal(editor.options.cursorStyle, TextEditorCursorStyle.Line);
assert.equal(editor.options.lineNumbers, TextEditorLineNumbersStyle.On);
editor.options = {
tabSize: 2
};
assert.equal(editor.options.tabSize, 2);
assert.equal(editor.options.insertSpaces, false);
assert.equal(editor.options.cursorStyle, TextEditorCursorStyle.Line);
assert.equal(editor.options.lineNumbers, TextEditorLineNumbersStyle.On);
editor.options.tabSize = 'invalid';
assert.equal(editor.options.tabSize, 2);
assert.equal(editor.options.insertSpaces, false);
assert.equal(editor.options.cursorStyle, TextEditorCursorStyle.Line);
assert.equal(editor.options.lineNumbers, TextEditorLineNumbersStyle.On);
return Promise.resolve();
});
});
test('issue #20757: Overlapping ranges are not allowed!', () => {
return withRandomFileEditor('Hello world!\n\tHello world!', (editor, doc) => {
return editor.edit((builder) => {
// create two edits that overlap (i.e. are illegal)
builder.replace(new Range(0, 0, 0, 2), 'He');
builder.replace(new Range(0, 1, 0, 3), 'el');
}).then(
(applied) => {
assert.ok(false, 'edit with overlapping ranges should fail');
},
(err) => {
assert.ok(true, 'edit with overlapping ranges should fail');
}
);
});
});
});

View File

@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { env } from 'vscode';
suite('env-namespace', () => {
test('env is set', function () {
assert.equal(typeof env.language, 'string');
assert.equal(typeof env.appRoot, 'string');
assert.equal(typeof env.appName, 'string');
assert.equal(typeof env.machineId, 'string');
assert.equal(typeof env.sessionId, 'string');
});
test('env is readonly', function () {
assert.throws(() => env.language = '234');
assert.throws(() => env.appRoot = '234');
assert.throws(() => env.appName = '234');
assert.throws(() => env.machineId = '234');
assert.throws(() => env.sessionId = '234');
});
});

View File

@@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
//
// PLEASE DO NOT MODIFY / DELETE UNLESS YOU KNOW WHAT YOU ARE DOING
//
// This file is providing the test runner to use when running extension tests.
// By default the test runner in use is Mocha based.
//
// You can provide your own test runner if you want to override it by exporting
// a function run(testRoot: string, clb: (error:Error) => void) that the extension
// host can call to run the tests. The test runner is expected to use console.log
// to report the results back to the caller. When the tests are finished, return
// a possible error to the callback or null if none.
const testRunner = require('vscode/lib/testrunner');
// You can directly control Mocha options by uncommenting the following lines
// See https://github.com/mochajs/mocha/wiki/Using-mocha-programmatically#set-options for more info
testRunner.configure({
ui: 'tdd', // the TDD UI is being used in extension.test.ts (suite, test, etc.)
useColors: process.platform !== 'win32', // colored output from test results (only windows cannot handle)
timeout: 60000
});
export = testRunner;

View File

@@ -0,0 +1,89 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { join } from 'path';
import {
languages, workspace, commands, Uri, Diagnostic, Range, Command, Disposable, CancellationToken,
CompletionList, CompletionItem, CompletionItemKind, TextDocument, Position
} from 'vscode';
suite('languages namespace tests', () => {
test('diagnostics & CodeActionProvider', function () {
class D2 extends Diagnostic {
customProp = { complex() { } };
constructor() {
super(new Range(0, 2, 0, 7), 'sonntag');
}
}
let diag1 = new Diagnostic(new Range(0, 0, 0, 5), 'montag');
let diag2 = new D2();
let ran = false;
let uri = Uri.parse('ttt:path.far');
let r1 = languages.registerCodeActionsProvider({ pattern: '*.far', scheme: 'ttt' }, {
provideCodeActions(document, range, ctx): Command[] {
assert.equal(ctx.diagnostics.length, 2);
let [first, second] = ctx.diagnostics;
assert.ok(first === diag1);
assert.ok(second === diag2);
assert.ok(diag2 instanceof D2);
ran = true;
return [];
}
});
let r2 = workspace.registerTextDocumentContentProvider('ttt', {
provideTextDocumentContent() {
return 'this is some text';
}
});
let r3 = languages.createDiagnosticCollection();
r3.set(uri, [diag1]);
let r4 = languages.createDiagnosticCollection();
r4.set(uri, [diag2]);
return workspace.openTextDocument(uri).then(doc => {
return commands.executeCommand('vscode.executeCodeActionProvider', uri, new Range(0, 0, 0, 10));
}).then(commands => {
assert.ok(ran);
Disposable.from(r1, r2, r3, r4).dispose();
});
});
test('completions with document filters', function () {
let ran = false;
let uri = Uri.file(join(workspace.rootPath || '', './bower.json'));
let jsonDocumentFilter = [{ language: 'json', pattern: '**/package.json' }, { language: 'json', pattern: '**/bower.json' }, { language: 'json', pattern: '**/.bower.json' }];
let r1 = languages.registerCompletionItemProvider(jsonDocumentFilter, {
provideCompletionItems: (document: TextDocument, position: Position, token: CancellationToken): CompletionItem[] => {
let proposal = new CompletionItem('foo');
proposal.kind = CompletionItemKind.Property;
ran = true;
return [proposal];
}
});
return workspace.openTextDocument(uri).then(doc => {
return commands.executeCommand<CompletionList>('vscode.executeCompletionItemProvider', uri, new Position(1, 0));
}).then((result: CompletionList | undefined) => {
r1.dispose();
assert.ok(ran);
console.log(result!.items);
assert.equal(result!.items[0].label, 'foo');
});
});
});

View File

@@ -0,0 +1,434 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import { workspace, window, commands, ViewColumn, TextEditorViewColumnChangeEvent, Uri, Selection, Position, CancellationTokenSource, TextEditorSelectionChangeKind } from 'vscode';
import { join } from 'path';
import { closeAllEditors, pathEquals, createRandomFile } from '../utils';
suite('window namespace tests', () => {
teardown(closeAllEditors);
test('editor, active text editor', () => {
return workspace.openTextDocument(join(workspace.rootPath || '', './far.js')).then(doc => {
return window.showTextDocument(doc).then((editor) => {
const active = window.activeTextEditor;
assert.ok(active);
assert.ok(pathEquals(active!.document.uri.fsPath, doc.uri.fsPath));
});
});
});
test('editor, opened via resource', () => {
const uri = Uri.file(join(workspace.rootPath || '', './far.js'));
return window.showTextDocument(uri).then((editor) => {
const active = window.activeTextEditor;
assert.ok(active);
assert.ok(pathEquals(active!.document.uri.fsPath, uri.fsPath));
});
});
// test('editor, UN-active text editor', () => {
// assert.equal(window.visibleTextEditors.length, 0);
// assert.ok(window.activeTextEditor === undefined);
// });
test('editor, assign and check view columns', () => {
return workspace.openTextDocument(join(workspace.rootPath || '', './far.js')).then(doc => {
let p1 = window.showTextDocument(doc, ViewColumn.One).then(editor => {
assert.equal(editor.viewColumn, ViewColumn.One);
});
let p2 = window.showTextDocument(doc, ViewColumn.Two).then(editor => {
assert.equal(editor.viewColumn, ViewColumn.Two);
});
let p3 = window.showTextDocument(doc, ViewColumn.Three).then(editor => {
assert.equal(editor.viewColumn, ViewColumn.Three);
});
return Promise.all([p1, p2, p3]);
});
});
test('editor, onDidChangeVisibleTextEditors', () => {
let eventCounter = 0;
let reg = window.onDidChangeVisibleTextEditors(editor => {
eventCounter += 1;
});
return workspace.openTextDocument(join(workspace.rootPath || '', './far.js')).then(doc => {
return window.showTextDocument(doc, ViewColumn.One).then(editor => {
assert.equal(eventCounter, 1);
return doc;
});
}).then(doc => {
return window.showTextDocument(doc, ViewColumn.Two).then(editor => {
assert.equal(eventCounter, 2);
return doc;
});
}).then(doc => {
return window.showTextDocument(doc, ViewColumn.Three).then(editor => {
assert.equal(eventCounter, 3);
return doc;
});
}).then(doc => {
reg.dispose();
});
});
test('editor, onDidChangeTextEditorViewColumn', () => {
let actualEvent: TextEditorViewColumnChangeEvent;
let registration1 = workspace.registerTextDocumentContentProvider('bikes', {
provideTextDocumentContent() {
return 'mountainbiking,roadcycling';
}
});
return Promise.all([
workspace.openTextDocument(Uri.parse('bikes://testing/one')).then(doc => window.showTextDocument(doc, ViewColumn.One)),
workspace.openTextDocument(Uri.parse('bikes://testing/two')).then(doc => window.showTextDocument(doc, ViewColumn.Two))
]).then(editors => {
let [one, two] = editors;
return new Promise(resolve => {
let registration2 = window.onDidChangeTextEditorViewColumn(event => {
actualEvent = event;
registration2.dispose();
resolve();
});
// close editor 1, wait a little for the event to bubble
one.hide();
}).then(() => {
assert.ok(actualEvent);
assert.ok(actualEvent.textEditor === two);
assert.ok(actualEvent.viewColumn === two.viewColumn);
registration1.dispose();
});
});
});
test('issue #25801 - default column when opening a file', async () => {
const [docA, docB, docC] = await Promise.all([
workspace.openTextDocument(await createRandomFile()),
workspace.openTextDocument(await createRandomFile()),
workspace.openTextDocument(await createRandomFile())
]);
await window.showTextDocument(docA, ViewColumn.One);
await window.showTextDocument(docB, ViewColumn.Two);
assert.ok(window.activeTextEditor);
assert.ok(window.activeTextEditor!.document === docB);
assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two);
await window.showTextDocument(docC);
assert.ok(window.activeTextEditor!.document === docC);
assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.One);
});
test('issue #27408 - showTextDocument & vscode.diff always default to ViewColumn.One', async () => {
const [docA, docB, docC] = await Promise.all([
workspace.openTextDocument(await createRandomFile()),
workspace.openTextDocument(await createRandomFile()),
workspace.openTextDocument(await createRandomFile())
]);
await window.showTextDocument(docA, ViewColumn.One);
await window.showTextDocument(docB, ViewColumn.Two);
assert.ok(window.activeTextEditor);
assert.ok(window.activeTextEditor!.document === docB);
assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two);
await window.showTextDocument(docC, ViewColumn.Active);
assert.ok(window.activeTextEditor!.document === docC);
assert.equal(window.activeTextEditor!.viewColumn, ViewColumn.Two);
});
test('issue #5362 - Incorrect TextEditor passed by onDidChangeTextEditorSelection', (done) => {
const file10Path = join(workspace.rootPath || '', './10linefile.ts');
const file30Path = join(workspace.rootPath || '', './30linefile.ts');
let finished = false;
let failOncePlease = (err: Error) => {
if (finished) {
return;
}
finished = true;
done(err);
};
let passOncePlease = () => {
if (finished) {
return;
}
finished = true;
done(null);
};
let subscription = window.onDidChangeTextEditorSelection((e) => {
let lineCount = e.textEditor.document.lineCount;
let pos1 = e.textEditor.selections[0].active.line;
let pos2 = e.selections[0].active.line;
if (pos1 !== pos2) {
failOncePlease(new Error('received invalid selection changed event!'));
return;
}
if (pos1 >= lineCount) {
failOncePlease(new Error(`Cursor position (${pos1}) is not valid in the document ${e.textEditor.document.fileName} that has ${lineCount} lines.`));
return;
}
});
// Open 10 line file, show it in slot 1, set cursor to line 10
// Open 30 line file, show it in slot 1, set cursor to line 30
// Open 10 line file, show it in slot 1
// Open 30 line file, show it in slot 1
workspace.openTextDocument(file10Path).then((doc) => {
return window.showTextDocument(doc, ViewColumn.One);
}).then((editor10line) => {
editor10line.selection = new Selection(new Position(9, 0), new Position(9, 0));
}).then(() => {
return workspace.openTextDocument(file30Path);
}).then((doc) => {
return window.showTextDocument(doc, ViewColumn.One);
}).then((editor30line) => {
editor30line.selection = new Selection(new Position(29, 0), new Position(29, 0));
}).then(() => {
return workspace.openTextDocument(file10Path);
}).then((doc) => {
return window.showTextDocument(doc, ViewColumn.One);
}).then(() => {
return workspace.openTextDocument(file30Path);
}).then((doc) => {
return window.showTextDocument(doc, ViewColumn.One);
}).then(() => {
subscription.dispose();
}).then(passOncePlease, failOncePlease);
});
test('#7013 - input without options', function () {
const source = new CancellationTokenSource();
let p = window.showInputBox(undefined, source.token);
assert.ok(typeof p === 'object');
source.dispose();
});
test('showInputBox - undefined on cancel', function () {
const source = new CancellationTokenSource();
const p = window.showInputBox(undefined, source.token);
source.cancel();
return p.then(value => {
assert.equal(value, undefined);
});
});
test('showInputBox - cancel early', function () {
const source = new CancellationTokenSource();
source.cancel();
const p = window.showInputBox(undefined, source.token);
return p.then(value => {
assert.equal(value, undefined);
});
});
test('showInputBox - \'\' on Enter', function () {
const p = window.showInputBox();
return Promise.all<any>([
commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'),
p.then(value => assert.equal(value, ''))
]);
});
test('showInputBox - default value on Enter', function () {
const p = window.showInputBox({ value: 'farboo' });
return Promise.all<any>([
p.then(value => assert.equal(value, 'farboo')),
commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'),
]);
});
test('showInputBox - `undefined` on Esc', function () {
const p = window.showInputBox();
return Promise.all<any>([
commands.executeCommand('workbench.action.closeQuickOpen'),
p.then(value => assert.equal(value, undefined))
]);
});
test('showInputBox - `undefined` on Esc (despite default)', function () {
const p = window.showInputBox({ value: 'farboo' });
return Promise.all<any>([
commands.executeCommand('workbench.action.closeQuickOpen'),
p.then(value => assert.equal(value, undefined))
]);
});
test('showQuickPick, undefined on cancel', function () {
const source = new CancellationTokenSource();
const p = window.showQuickPick(['eins', 'zwei', 'drei'], undefined, source.token);
source.cancel();
return p.then(value => {
assert.equal(value, undefined);
});
});
test('showQuickPick, cancel early', function () {
const source = new CancellationTokenSource();
source.cancel();
const p = window.showQuickPick(['eins', 'zwei', 'drei'], undefined, source.token);
return p.then(value => {
assert.equal(value, undefined);
});
});
test('showQuickPick, canceled by another picker', function () {
const result = window.showQuickPick(['eins', 'zwei', 'drei'], { ignoreFocusOut: true }).then(result => {
assert.equal(result, undefined);
});
const source = new CancellationTokenSource();
source.cancel();
window.showQuickPick(['eins', 'zwei', 'drei'], undefined, source.token);
return result;
});
test('showQuickPick, canceled by input', function () {
const result = window.showQuickPick(['eins', 'zwei', 'drei'], { ignoreFocusOut: true }).then(result => {
assert.equal(result, undefined);
});
const source = new CancellationTokenSource();
source.cancel();
window.showInputBox(undefined, source.token);
return result;
});
test('showQuickPick, native promise - #11754', function () {
const data = new Promise<string[]>(resolve => {
resolve(['a', 'b', 'c']);
});
const source = new CancellationTokenSource();
const result = window.showQuickPick(data, undefined, source.token);
source.cancel();
return result.then(value => {
assert.equal(value, undefined);
});
});
test('showQuickPick, never resolve promise and cancel - #22453', function () {
const result = window.showQuickPick(new Promise<string[]>(resolve => { }));
const a = result.then(value => {
assert.equal(value, undefined);
});
const b = commands.executeCommand('workbench.action.closeQuickOpen');
return Promise.all([a, b]);
});
test('showWorkspaceFolderPick', function () {
const p = window.showWorkspaceFolderPick(undefined);
return commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem').then(() => {
return p.then(workspace => {
assert.ok(true);
}, error => {
assert.ok(false);
});
});
});
test('Default value for showInput Box accepted even if fails validateInput, #33691', function () {
const result = window.showInputBox({
validateInput: (value: string) => {
if (!value || value.trim().length === 0) {
return 'Cannot set empty description';
}
return null;
}
}).then(value => {
assert.equal(value, undefined);
});
const exec = commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem');
return Promise.all([result, exec]);
});
test('editor, selection change kind', () => {
return workspace.openTextDocument(join(workspace.rootPath || '', './far.js')).then(doc => window.showTextDocument(doc)).then(editor => {
return new Promise((resolve, reject) => {
let subscription = window.onDidChangeTextEditorSelection(e => {
assert.ok(e.textEditor === editor);
assert.equal(e.kind, TextEditorSelectionChangeKind.Command);
subscription.dispose();
resolve();
});
editor.selection = new Selection(editor.selection.anchor, editor.selection.active.translate(2));
});
});
});
test('createTerminal, Terminal.name', () => {
const terminal = window.createTerminal('foo');
assert.equal(terminal.name, 'foo');
assert.throws(() => {
(<any>terminal).name = 'bar';
}, 'Terminal.name should be readonly');
});
test('terminal, sendText immediately after createTerminal should not throw', () => {
const terminal = window.createTerminal();
assert.doesNotThrow(terminal.sendText.bind(terminal, 'echo "foo"'));
});
test('terminal, onDidCloseTerminal event fires when terminal is disposed', (done) => {
const terminal = window.createTerminal();
window.onDidCloseTerminal((eventTerminal) => {
assert.equal(terminal, eventTerminal);
done();
});
terminal.dispose();
});
test('terminal, processId immediately after createTerminal should fetch the pid', (done) => {
window.createTerminal().processId.then(id => {
assert.ok(id > 0);
done();
});
});
test('terminal, name should set terminal.name', () => {
assert.equal(window.createTerminal('foo').name, 'foo');
});
});

View File

@@ -0,0 +1,564 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as assert from 'assert';
import * as vscode from 'vscode';
import { createRandomFile, deleteFile, closeAllEditors, pathEquals } from '../utils';
import { join, basename } from 'path';
import * as fs from 'fs';
suite('workspace-namespace', () => {
teardown(closeAllEditors);
test('MarkdownString', function () {
let md = new vscode.MarkdownString();
assert.equal(md.value, '');
assert.equal(md.isTrusted, undefined);
md = new vscode.MarkdownString('**bold**');
assert.equal(md.value, '**bold**');
md.appendText('**bold?**');
assert.equal(md.value, '**bold**\\*\\*bold?\\*\\*');
md.appendMarkdown('**bold**');
assert.equal(md.value, '**bold**\\*\\*bold?\\*\\***bold**');
});
test('textDocuments', () => {
assert.ok(Array.isArray(vscode.workspace.textDocuments));
assert.throws(() => (<any>vscode.workspace).textDocuments = null);
});
test('rootPath', () => {
if (vscode.workspace.rootPath) {
assert.ok(pathEquals(vscode.workspace.rootPath, join(__dirname, '../../testWorkspace')));
}
assert.throws(() => vscode.workspace.rootPath = 'farboo');
});
test('workspaceFolders', () => {
if (vscode.workspace.workspaceFolders) {
assert.equal(vscode.workspace.workspaceFolders.length, 1);
assert.ok(pathEquals(vscode.workspace.workspaceFolders[0].uri.fsPath, join(__dirname, '../../testWorkspace')));
}
});
test('getWorkspaceFolder', () => {
const folder = vscode.workspace.getWorkspaceFolder(vscode.Uri.file(join(__dirname, '../../testWorkspace/far.js')));
assert.ok(!!folder);
if (folder) {
assert.ok(pathEquals(folder.uri.fsPath, join(__dirname, '../../testWorkspace')));
}
});
test('openTextDocument', () => {
let len = vscode.workspace.textDocuments.length;
return vscode.workspace.openTextDocument(join(vscode.workspace.rootPath || '', './simple.txt')).then(doc => {
assert.ok(doc);
assert.equal(vscode.workspace.textDocuments.length, len + 1);
});
});
test('openTextDocument, illegal path', () => {
return vscode.workspace.openTextDocument('funkydonky.txt').then(doc => {
throw new Error('missing error');
}, err => {
// good!
});
});
test('openTextDocument, untitled is dirty', function () {
return vscode.workspace.openTextDocument(vscode.Uri.parse('untitled:' + join(vscode.workspace.rootPath || '', './newfile.txt'))).then(doc => {
assert.equal(doc.uri.scheme, 'untitled');
assert.ok(doc.isDirty);
});
});
test('openTextDocument, untitled with host', function () {
const uri = vscode.Uri.parse('untitled://localhost/c%24/Users/jrieken/code/samples/foobar.txt');
return vscode.workspace.openTextDocument(uri).then(doc => {
assert.equal(doc.uri.scheme, 'untitled');
});
});
test('openTextDocument, untitled without path', function () {
return vscode.workspace.openTextDocument().then(doc => {
assert.equal(doc.uri.scheme, 'untitled');
assert.ok(doc.isDirty);
});
});
test('openTextDocument, untitled without path but language ID', function () {
return vscode.workspace.openTextDocument({ language: 'xml' }).then(doc => {
assert.equal(doc.uri.scheme, 'untitled');
assert.equal(doc.languageId, 'xml');
assert.ok(doc.isDirty);
});
});
test('openTextDocument, untitled without path but language ID and content', function () {
return vscode.workspace.openTextDocument({ language: 'html', content: '<h1>Hello world!</h1>' }).then(doc => {
assert.equal(doc.uri.scheme, 'untitled');
assert.equal(doc.languageId, 'html');
assert.ok(doc.isDirty);
assert.equal(doc.getText(), '<h1>Hello world!</h1>');
});
});
test('openTextDocument, untitled closes on save', function () {
const path = join(vscode.workspace.rootPath || '', './newfile.txt');
return vscode.workspace.openTextDocument(vscode.Uri.parse('untitled:' + path)).then(doc => {
assert.equal(doc.uri.scheme, 'untitled');
assert.ok(doc.isDirty);
let closed: vscode.TextDocument;
let d0 = vscode.workspace.onDidCloseTextDocument(e => closed = e);
return vscode.window.showTextDocument(doc).then(() => {
return doc.save().then(() => {
assert.ok(closed === doc);
assert.ok(!doc.isDirty);
assert.ok(fs.existsSync(path));
d0.dispose();
return deleteFile(vscode.Uri.file(join(vscode.workspace.rootPath || '', './newfile.txt')));
});
});
});
});
test('openTextDocument, uri scheme/auth/path', function () {
let registration = vscode.workspace.registerTextDocumentContentProvider('sc', {
provideTextDocumentContent() {
return 'SC';
}
});
return Promise.all([
vscode.workspace.openTextDocument(vscode.Uri.parse('sc://auth')).then(doc => {
assert.equal(doc.uri.authority, 'auth');
assert.equal(doc.uri.path, '');
}),
vscode.workspace.openTextDocument(vscode.Uri.parse('sc:///path')).then(doc => {
assert.equal(doc.uri.authority, '');
assert.equal(doc.uri.path, '/path');
}),
vscode.workspace.openTextDocument(vscode.Uri.parse('sc://auth/path')).then(doc => {
assert.equal(doc.uri.authority, 'auth');
assert.equal(doc.uri.path, '/path');
})
]).then(() => {
registration.dispose();
});
});
test('eol, read', () => {
const a = createRandomFile('foo\nbar\nbar').then(file => {
return vscode.workspace.openTextDocument(file).then(doc => {
assert.equal(doc.eol, vscode.EndOfLine.LF);
});
});
const b = createRandomFile('foo\nbar\nbar\r\nbaz').then(file => {
return vscode.workspace.openTextDocument(file).then(doc => {
assert.equal(doc.eol, vscode.EndOfLine.LF);
});
});
const c = createRandomFile('foo\r\nbar\r\nbar').then(file => {
return vscode.workspace.openTextDocument(file).then(doc => {
assert.equal(doc.eol, vscode.EndOfLine.CRLF);
});
});
return Promise.all([a, b, c]);
});
test('eol, change via editor', () => {
return createRandomFile('foo\nbar\nbar').then(file => {
return vscode.workspace.openTextDocument(file).then(doc => {
assert.equal(doc.eol, vscode.EndOfLine.LF);
return vscode.window.showTextDocument(doc).then(editor => {
return editor.edit(builder => builder.setEndOfLine(vscode.EndOfLine.CRLF));
}).then(value => {
assert.ok(value);
assert.ok(doc.isDirty);
assert.equal(doc.eol, vscode.EndOfLine.CRLF);
});
});
});
});
test('eol, change via applyEdit', () => {
return createRandomFile('foo\nbar\nbar').then(file => {
return vscode.workspace.openTextDocument(file).then(doc => {
assert.equal(doc.eol, vscode.EndOfLine.LF);
const edit = new vscode.WorkspaceEdit();
edit.set(file, [vscode.TextEdit.setEndOfLine(vscode.EndOfLine.CRLF)]);
return vscode.workspace.applyEdit(edit).then(value => {
assert.ok(value);
assert.ok(doc.isDirty);
assert.equal(doc.eol, vscode.EndOfLine.CRLF);
});
});
});
});
test('eol, change via onWillSave', () => {
let called = false;
let sub = vscode.workspace.onWillSaveTextDocument(e => {
called = true;
e.waitUntil(Promise.resolve([vscode.TextEdit.setEndOfLine(vscode.EndOfLine.LF)]));
});
return createRandomFile('foo\r\nbar\r\nbar').then(file => {
return vscode.workspace.openTextDocument(file).then(doc => {
assert.equal(doc.eol, vscode.EndOfLine.CRLF);
const edit = new vscode.WorkspaceEdit();
edit.set(file, [vscode.TextEdit.insert(new vscode.Position(0, 0), '-changes-')]);
return vscode.workspace.applyEdit(edit).then(success => {
assert.ok(success);
return doc.save();
}).then(success => {
assert.ok(success);
assert.ok(called);
assert.ok(!doc.isDirty);
assert.equal(doc.eol, vscode.EndOfLine.LF);
sub.dispose();
});
});
});
});
test('events: onDidOpenTextDocument, onDidChangeTextDocument, onDidSaveTextDocument', () => {
return createRandomFile().then(file => {
let disposables: vscode.Disposable[] = [];
let onDidOpenTextDocument = false;
disposables.push(vscode.workspace.onDidOpenTextDocument(e => {
assert.ok(pathEquals(e.uri.fsPath, file.fsPath));
onDidOpenTextDocument = true;
}));
let onDidChangeTextDocument = false;
disposables.push(vscode.workspace.onDidChangeTextDocument(e => {
assert.ok(pathEquals(e.document.uri.fsPath, file.fsPath));
onDidChangeTextDocument = true;
}));
let onDidSaveTextDocument = false;
disposables.push(vscode.workspace.onDidSaveTextDocument(e => {
assert.ok(pathEquals(e.uri.fsPath, file.fsPath));
onDidSaveTextDocument = true;
}));
return vscode.workspace.openTextDocument(file).then(doc => {
return vscode.window.showTextDocument(doc).then((editor) => {
return editor.edit((builder) => {
builder.insert(new vscode.Position(0, 0), 'Hello World');
}).then(applied => {
return doc.save().then(saved => {
assert.ok(onDidOpenTextDocument);
assert.ok(onDidChangeTextDocument);
assert.ok(onDidSaveTextDocument);
while (disposables.length) {
const item = disposables.pop();
if (item) {
item.dispose();
}
}
return deleteFile(file);
});
});
});
});
});
});
test('openTextDocument, with selection', function () {
return createRandomFile('foo\nbar\nbar').then(file => {
return vscode.workspace.openTextDocument(file).then(doc => {
return vscode.window.showTextDocument(doc, { selection: new vscode.Range(new vscode.Position(1, 1), new vscode.Position(1, 2)) }).then(editor => {
assert.equal(editor.selection.start.line, 1);
assert.equal(editor.selection.start.character, 1);
assert.equal(editor.selection.end.line, 1);
assert.equal(editor.selection.end.character, 2);
});
});
});
});
test('registerTextDocumentContentProvider, simple', function () {
let registration = vscode.workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
return uri.toString();
}
});
const uri = vscode.Uri.parse('foo://testing/virtual.js');
return vscode.workspace.openTextDocument(uri).then(doc => {
assert.equal(doc.getText(), uri.toString());
assert.equal(doc.isDirty, false);
assert.equal(doc.uri.toString(), uri.toString());
registration.dispose();
});
});
test('registerTextDocumentContentProvider, constrains', function () {
// built-in
assert.throws(function () {
vscode.workspace.registerTextDocumentContentProvider('untitled', { provideTextDocumentContent() { return null; } });
});
// built-in
assert.throws(function () {
vscode.workspace.registerTextDocumentContentProvider('file', { provideTextDocumentContent() { return null; } });
});
// missing scheme
return vscode.workspace.openTextDocument(vscode.Uri.parse('notThere://foo/far/boo/bar')).then(() => {
assert.ok(false, 'expected failure');
}, err => {
// expected
});
});
test('registerTextDocumentContentProvider, multiple', function () {
// duplicate registration
let registration1 = vscode.workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
if (uri.authority === 'foo') {
return '1';
}
}
});
let registration2 = vscode.workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
if (uri.authority === 'bar') {
return '2';
}
}
});
return Promise.all([
vscode.workspace.openTextDocument(vscode.Uri.parse('foo://foo/bla')).then(doc => { assert.equal(doc.getText(), '1'); }),
vscode.workspace.openTextDocument(vscode.Uri.parse('foo://bar/bla')).then(doc => { assert.equal(doc.getText(), '2'); })
]).then(() => {
registration1.dispose();
registration2.dispose();
});
});
test('registerTextDocumentContentProvider, evil provider', function () {
// duplicate registration
let registration1 = vscode.workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
return '1';
}
});
let registration2 = vscode.workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri): string {
throw new Error('fail');
}
});
return vscode.workspace.openTextDocument(vscode.Uri.parse('foo://foo/bla')).then(doc => {
assert.equal(doc.getText(), '1');
registration1.dispose();
registration2.dispose();
});
});
test('registerTextDocumentContentProvider, invalid text', function () {
let registration = vscode.workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
return <any>123;
}
});
return vscode.workspace.openTextDocument(vscode.Uri.parse('foo://auth/path')).then(() => {
assert.ok(false, 'expected failure');
}, err => {
// expected
registration.dispose();
});
});
test('registerTextDocumentContentProvider, show virtual document', function () {
let registration = vscode.workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
return 'I am virtual';
}
});
return vscode.workspace.openTextDocument(vscode.Uri.parse('foo://something/path')).then(doc => {
return vscode.window.showTextDocument(doc).then(editor => {
assert.ok(editor.document === doc);
assert.equal(editor.document.getText(), 'I am virtual');
registration.dispose();
});
});
});
test('registerTextDocumentContentProvider, open/open document', function () {
let callCount = 0;
let registration = vscode.workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
callCount += 1;
return 'I am virtual';
}
});
const uri = vscode.Uri.parse('foo://testing/path');
return Promise.all([vscode.workspace.openTextDocument(uri), vscode.workspace.openTextDocument(uri)]).then(docs => {
let [first, second] = docs;
assert.ok(first === second);
assert.ok(vscode.workspace.textDocuments.some(doc => doc.uri.toString() === uri.toString()));
assert.equal(callCount, 1);
registration.dispose();
});
});
test('registerTextDocumentContentProvider, empty doc', function () {
let registration = vscode.workspace.registerTextDocumentContentProvider('foo', {
provideTextDocumentContent(uri) {
return '';
}
});
const uri = vscode.Uri.parse('foo:doc/empty');
return vscode.workspace.openTextDocument(uri).then(doc => {
assert.equal(doc.getText(), '');
assert.equal(doc.uri.toString(), uri.toString());
registration.dispose();
});
});
test('registerTextDocumentContentProvider, change event', function () {
let callCount = 0;
let emitter = new vscode.EventEmitter<vscode.Uri>();
let registration = vscode.workspace.registerTextDocumentContentProvider('foo', {
onDidChange: emitter.event,
provideTextDocumentContent(uri) {
return 'call' + (callCount++);
}
});
const uri = vscode.Uri.parse('foo://testing/path3');
return vscode.workspace.openTextDocument(uri).then(doc => {
assert.equal(callCount, 1);
assert.equal(doc.getText(), 'call0');
return new Promise((resolve, reject) => {
let subscription = vscode.workspace.onDidChangeTextDocument(event => {
subscription.dispose();
assert.ok(event.document === doc);
assert.equal(event.document.getText(), 'call1');
resolve();
});
emitter.fire(doc.uri);
registration.dispose();
});
});
});
test('findFiles', () => {
return vscode.workspace.findFiles('*.js').then((res) => {
assert.equal(res.length, 1);
assert.equal(basename(vscode.workspace.asRelativePath(res[0])), 'far.js');
});
});
// TODO@Joh this test fails randomly
// test('findFiles, cancellation', () => {
// const source = new CancellationTokenSource();
// const token = source.token; // just to get an instance first
// source.cancel();
// return vscode.workspace.findFiles('*.js', null, 100, token).then((res) => {
// assert.equal(res, void 0);
// });
// });
test('applyEdit', () => {
return vscode.workspace.openTextDocument(vscode.Uri.parse('untitled:' + join(vscode.workspace.rootPath || '', './new2.txt'))).then(doc => {
let edit = new vscode.WorkspaceEdit();
edit.insert(doc.uri, new vscode.Position(0, 0), new Array(1000).join('Hello World'));
return vscode.workspace.applyEdit(edit);
});
});
test('applyEdit should fail when editing deleted resource', async () => {
const resource = await createRandomFile();
const edit = new vscode.WorkspaceEdit();
edit.deleteResource(resource);
try {
edit.insert(resource, new vscode.Position(0, 0), '');
assert.fail(false, 'Should disallow edit of deleted resource');
} catch {
// noop
}
});
test('applyEdit should fail when renaming deleted resource', async () => {
const resource = await createRandomFile();
const edit = new vscode.WorkspaceEdit();
edit.deleteResource(resource);
try {
edit.renameResource(resource, resource);
assert.fail(false, 'Should disallow rename of deleted resource');
} catch {
// noop
}
});
test('applyEdit should fail when editing renamed from resource', async () => {
const resource = await createRandomFile();
const newResource = vscode.Uri.parse(resource.fsPath + '.1');
const edit = new vscode.WorkspaceEdit();
edit.renameResource(resource, newResource);
try {
edit.insert(resource, new vscode.Position(0, 0), '');
assert.fail(false, 'Should disallow editing renamed file');
} catch {
// noop
}
});
});