blob: 31c1fcdb3abf70087b074a8b2e576489151acbb2 [file] [log] [blame]
/*---------------------------------------------------------
* Copyright 2020 The Go Authors. All rights reserved.
* Licensed under the MIT License. See LICENSE in the project root for license information.
*--------------------------------------------------------*/
'use strict';
import assert from 'assert';
import path = require('path');
import sinon = require('sinon');
import vscode = require('vscode');
import { updateGoVarsFromConfig } from '../../src/goInstallTools';
import { GoRunTestCodeLensProvider } from '../../src/goRunTestCodelens';
import { subTestAtCursor } from '../../src/goTest';
import { MockExtensionContext } from '../mocks/MockContext';
import { Env } from './goplsTestEnv.utils';
suite('Code lenses for testing and benchmarking', function () {
this.timeout(20000);
let document: vscode.TextDocument;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const ctx = new MockExtensionContext() as any;
const cancellationTokenSource = new vscode.CancellationTokenSource();
const projectDir = path.join(__dirname, '..', '..', '..');
const testdataDir = path.join(projectDir, 'test', 'testdata', 'codelens');
const env = new Env();
this.afterEach(async function () {
// Note: this shouldn't use () => {...}. Arrow functions do not have 'this'.
// I don't know why but this.currentTest.state does not have the expected value when
// used with teardown.
env.flushTrace(this.currentTest?.state === 'failed');
sinon.restore();
});
suiteSetup(async () => {
await updateGoVarsFromConfig({});
const uri = vscode.Uri.file(path.join(testdataDir, 'codelens_test.go'));
await env.startGopls(uri.fsPath);
document = await vscode.workspace.openTextDocument(uri);
});
suiteTeardown(async () => {
await env.teardown();
});
test('Subtests - runs a test with cursor on t.Run line', async () => {
const editor = await vscode.window.showTextDocument(document);
editor.selection = new vscode.Selection(7, 4, 7, 4);
const result = await subTestAtCursor('test')(ctx, env.goCtx)([]);
assert.equal(result, true);
});
test('Subtests - runs a test with cursor within t.Run function', async () => {
const editor = await vscode.window.showTextDocument(document);
editor.selection = new vscode.Selection(8, 4, 8, 4);
const result = await subTestAtCursor('test')(ctx, env.goCtx)([]);
assert.equal(result, true);
});
test('Subtests - returns false for a failing test', async () => {
const editor = await vscode.window.showTextDocument(document);
editor.selection = new vscode.Selection(11, 4, 11, 4);
const result = await subTestAtCursor('test')(ctx, env.goCtx)([]);
assert.equal(result, false);
});
test('Subtests - does nothing for a dynamically defined subtest', async () => {
const editor = await vscode.window.showTextDocument(document);
editor.selection = new vscode.Selection(17, 4, 17, 4);
sinon.stub(vscode.window, 'showInputBox').onFirstCall().resolves(undefined);
const result = await subTestAtCursor('test')(ctx, env.goCtx)([]);
assert.equal(result, undefined);
});
test('Subtests - runs a test with curson on t.Run line and dynamic test name is passed in input box', async () => {
const editor = await vscode.window.showTextDocument(document);
editor.selection = new vscode.Selection(17, 4, 17, 4);
sinon.stub(vscode.window, 'showInputBox').onFirstCall().resolves('dynamic test name');
const result = await subTestAtCursor('test')(ctx, env.goCtx)([]);
assert.equal(result, false);
});
test('Subtests - does nothing when cursor outside of a test function', async () => {
const editor = await vscode.window.showTextDocument(document);
editor.selection = new vscode.Selection(5, 0, 5, 0);
const result = await subTestAtCursor('test')(ctx, env.goCtx)([]);
assert.equal(result, undefined);
});
test('Subtests - does nothing when no test function covers the cursor and a function name is passed in', async () => {
const editor = await vscode.window.showTextDocument(document);
editor.selection = new vscode.Selection(5, 0, 5, 0);
const result = await subTestAtCursor('test')(ctx, env.goCtx)({ functionName: 'TestMyFunction' });
assert.equal(result, undefined);
});
test('Test codelenses', async () => {
const codeLensProvider = new GoRunTestCodeLensProvider(env.goCtx);
const codeLenses = await codeLensProvider.provideCodeLenses(document, cancellationTokenSource.token);
assert.equal(codeLenses.length, 8);
const wantCommands = [
'go.test.package',
'go.test.file',
'go.test.cursor',
'go.debug.cursor',
'go.subtest.cursor',
'go.debug.subtest.cursor',
'go.subtest.cursor',
'go.debug.subtest.cursor'
];
for (let i = 0; i < codeLenses.length; i++) {
assert.equal(codeLenses[i].command?.command, wantCommands[i]);
}
});
test('Benchmark codelenses', async () => {
const codeLensProvider = new GoRunTestCodeLensProvider(env.goCtx);
const uri = vscode.Uri.file(path.join(testdataDir, 'codelens_benchmark_test.go'));
const benchmarkDocument = await vscode.workspace.openTextDocument(uri);
const codeLenses = await codeLensProvider.provideCodeLenses(benchmarkDocument, cancellationTokenSource.token);
assert.equal(codeLenses.length, 6);
const wantCommands = [
'go.test.package',
'go.test.file',
'go.benchmark.package',
'go.benchmark.file',
'go.benchmark.cursor',
'go.debug.cursor'
];
for (let i = 0; i < codeLenses.length; i++) {
assert.equal(codeLenses[i].command?.command, wantCommands[i]);
}
});
test('Test codelenses include only valid test function names', async () => {
const codeLensProvider = new GoRunTestCodeLensProvider(env.goCtx);
const uri = vscode.Uri.file(path.join(testdataDir, 'codelens2_test.go'));
const benchmarkDocument = await vscode.workspace.openTextDocument(uri);
const codeLenses = await codeLensProvider.provideCodeLenses(benchmarkDocument, cancellationTokenSource.token);
assert.equal(codeLenses.length, 20, JSON.stringify(codeLenses, null, 2));
const found = [] as string[];
for (let i = 0; i < codeLenses.length; i++) {
const lens = codeLenses[i];
if (lens.command?.command === 'go.test.cursor') {
found.push(lens.command.arguments?.[0].functionName);
}
}
found.sort();
// Results should match `go test -list`.
assert.deepStrictEqual(found, [
'Example',
'ExampleFunction',
'Test',
'Test1Function',
'TestFunction',
'TestMain',
'Test_foobar',
'TestΣυνάρτηση',
'Test함수'
]);
});
test('Test codelenses include valid fuzz function names', async () => {
const codeLensProvider = new GoRunTestCodeLensProvider(env.goCtx);
const uri = vscode.Uri.file(path.join(testdataDir, 'codelens_go118_test.go'));
const testDocument = await vscode.workspace.openTextDocument(uri);
const codeLenses = await codeLensProvider.provideCodeLenses(testDocument, cancellationTokenSource.token);
assert.equal(codeLenses.length, 8, JSON.stringify(codeLenses, null, 2));
const found = [] as string[];
for (let i = 0; i < codeLenses.length; i++) {
const lens = codeLenses[i];
if (lens.command?.command === 'go.test.cursor') {
found.push(lens.command.arguments?.[0].functionName);
}
}
found.sort();
// Results should match `go test -list`.
assert.deepStrictEqual(found, ['Fuzz', 'FuzzFunc', 'TestGo118']);
});
test('Test codelenses skip TestMain', async () => {
const codeLensProvider = new GoRunTestCodeLensProvider(env.goCtx);
const uri = vscode.Uri.file(path.join(testdataDir, 'testmain/testmain_test.go'));
const testDocument = await vscode.workspace.openTextDocument(uri);
const codeLenses = await codeLensProvider.provideCodeLenses(testDocument, cancellationTokenSource.token);
assert.equal(codeLenses.length, 4, JSON.stringify(codeLenses, null, 2));
const found = [] as string[];
for (let i = 0; i < codeLenses.length; i++) {
const lens = codeLenses[i];
if (lens.command?.command === 'go.test.cursor') {
found.push(lens.command.arguments?.[0].functionName);
}
}
found.sort();
// Results should match `go test -list`.
assert.deepStrictEqual(found, ['TestNotMain']);
});
});