goRunTestCodelens: convert code lens functions to async/await
I noticed this error in CI:
Cannot read property 'forEach' of undefined: TypeError: Cannot read property 'forEach' of undefined
at /workspace/out/src/goRunTestCodelens.js:111:36
at async Promise.all (index 1)
This should hopefully fix it.
Change-Id: I05b68230f2fc6258c66db2819eea6f3e7ace43db
GitHub-Last-Rev: 3685e8e3446b3cf37514638b5361dbc872424b36
GitHub-Pull-Request: golang/vscode-go#97
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/235201
Reviewed-by: Hyang-Ah Hana Kim <hyangah@gmail.com>
diff --git a/src/goRunTestCodelens.ts b/src/goRunTestCodelens.ts
index f53388b..587450a 100644
--- a/src/goRunTestCodelens.ts
+++ b/src/goRunTestCodelens.ts
@@ -10,21 +10,12 @@
import { GoBaseCodeLensProvider } from './goBaseCodelens';
import { GoDocumentSymbolProvider } from './goOutline';
import { getBenchmarkFunctions, getTestFunctions } from './testUtils';
-import { getCurrentGoPath, getGoConfig } from './util';
+import { getGoConfig } from './util';
export class GoRunTestCodeLensProvider extends GoBaseCodeLensProvider {
private readonly benchmarkRegex = /^Benchmark.+/;
- private readonly debugConfig: any = {
- name: 'Launch',
- type: 'go',
- request: 'launch',
- mode: 'test',
- env: {
- GOPATH: getCurrentGoPath() // Passing current GOPATH to Delve as it runs in another process
- }
- };
- public provideCodeLenses(document: TextDocument, token: CancellationToken): CodeLens[] | Thenable<CodeLens[]> {
+ public async provideCodeLenses(document: TextDocument, token: CancellationToken): Promise<CodeLens[]> {
if (!this.enabled) {
return [];
}
@@ -35,24 +26,19 @@
return [];
}
- return Promise.all([
+ const codelenses = await Promise.all([
this.getCodeLensForPackage(document, token),
- this.getCodeLensForFunctions(config, document, token)
- ]).then(([pkg, fns]) => {
- let res: any[] = [];
- if (pkg && Array.isArray(pkg)) {
- res = res.concat(pkg);
- }
- if (fns && Array.isArray(fns)) {
- res = res.concat(fns);
- }
- return res;
- });
+ this.getCodeLensForFunctions(document, token)
+ ]);
+ return ([] as CodeLens[]).concat(...codelenses);
}
private async getCodeLensForPackage(document: TextDocument, token: CancellationToken): Promise<CodeLens[]> {
const documentSymbolProvider = new GoDocumentSymbolProvider();
const symbols = await documentSymbolProvider.provideDocumentSymbols(document, token);
+ if (!symbols || symbols.length === 0) {
+ return [];
+ }
const pkg = symbols[0];
if (!pkg) {
return [];
@@ -69,7 +55,7 @@
})
];
if (
- symbols[0].children.some(
+ pkg.children.some(
(sym) => sym.kind === vscode.SymbolKind.Function && this.benchmarkRegex.test(sym.name)
)
) {
@@ -87,54 +73,50 @@
return packageCodeLens;
}
- private async getCodeLensForFunctions(
- vsConfig: vscode.WorkspaceConfiguration,
- document: TextDocument,
- token: CancellationToken
- ): Promise<CodeLens[]> {
- const codelens: CodeLens[] = [];
-
- const testPromise = getTestFunctions(document, token).then((testFunctions) => {
- testFunctions.forEach((func) => {
- const runTestCmd: Command = {
+ private async getCodeLensForFunctions(document: TextDocument, token: CancellationToken): Promise<CodeLens[]> {
+ const testPromise = async (): Promise<CodeLens[]> => {
+ const testFunctions = await getTestFunctions(document, token);
+ if (!testFunctions) {
+ return [];
+ }
+ const codelens: CodeLens[] = [];
+ for (const f of testFunctions) {
+ codelens.push(new CodeLens(f.range, {
title: 'run test',
command: 'go.test.cursor',
- arguments: [{ functionName: func.name }]
- };
-
- codelens.push(new CodeLens(func.range, runTestCmd));
-
- const debugTestCmd: Command = {
+ arguments: [{ functionName: f.name }]
+ }));
+ codelens.push(new CodeLens(f.range, {
title: 'debug test',
command: 'go.debug.cursor',
- arguments: [{ functionName: func.name }]
- };
+ arguments: [{ functionName: f.name }]
+ }));
+ }
+ return codelens;
+ };
- codelens.push(new CodeLens(func.range, debugTestCmd));
- });
- });
-
- const benchmarkPromise = getBenchmarkFunctions(document, token).then((benchmarkFunctions) => {
- benchmarkFunctions.forEach((func) => {
- const runBenchmarkCmd: Command = {
+ const benchmarkPromise = (async (): Promise<CodeLens[]> => {
+ const benchmarkFunctions = await getBenchmarkFunctions(document, token);
+ if (!benchmarkFunctions) {
+ return [];
+ }
+ const codelens: CodeLens[] = [];
+ for (const f of benchmarkFunctions) {
+ codelens.push(new CodeLens(f.range, {
title: 'run benchmark',
command: 'go.benchmark.cursor',
- arguments: [{ functionName: func.name }]
- };
-
- codelens.push(new CodeLens(func.range, runBenchmarkCmd));
-
- const debugTestCmd: Command = {
+ arguments: [{ functionName: f.name }]
+ }));
+ codelens.push(new CodeLens(f.range, {
title: 'debug benchmark',
command: 'go.debug.cursor',
- arguments: [{ functionName: func.name }]
- };
-
- codelens.push(new CodeLens(func.range, debugTestCmd));
- });
+ arguments: [{ functionName: f.name }]
+ }));
+ }
+ return codelens;
});
- await Promise.all([testPromise, benchmarkPromise]);
- return codelens;
+ const codelenses = await Promise.all([testPromise(), benchmarkPromise()]);
+ return ([] as CodeLens[]).concat(...codelenses);
}
}
diff --git a/test/fixtures/codelens/codelens_benchmark_test.go b/test/fixtures/codelens/codelens_benchmark_test.go
new file mode 100644
index 0000000..ecd6ed6
--- /dev/null
+++ b/test/fixtures/codelens/codelens_benchmark_test.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "testing"
+)
+
+func BenchmarkSample(b *testing.B) {
+ b.Run("sample test passing", func(t *testing.B) {
+
+ })
+
+ b.Run("sample test failing", func(t *testing.B) {
+ t.FailNow()
+ })
+
+ testName := "dynamic test name"
+ b.Run(testName, func(t *testing.B) {
+ t.FailNow()
+ })
+}
diff --git a/test/fixtures/subtests/subtests_test.go b/test/fixtures/codelens/codelens_test.go
similarity index 100%
rename from test/fixtures/subtests/subtests_test.go
rename to test/fixtures/codelens/codelens_test.go
diff --git a/test/fixtures/subtests/go.mod b/test/fixtures/codelens/go.mod
similarity index 100%
rename from test/fixtures/subtests/go.mod
rename to test/fixtures/codelens/go.mod
diff --git a/test/integration/codelens.test.ts b/test/integration/codelens.test.ts
new file mode 100644
index 0000000..9bd80c3
--- /dev/null
+++ b/test/integration/codelens.test.ts
@@ -0,0 +1,134 @@
+/*---------------------------------------------------------
+ * Copyright (C) Microsoft Corporation. All rights reserved.
+ * Modification 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 * as assert from 'assert';
+import fs = require('fs-extra');
+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 { getCurrentGoPath } from '../../src/util';
+
+suite('Code lenses for testing and benchmarking', function () {
+ this.timeout(20000);
+
+ let gopath: string;
+ let repoPath: string;
+ let fixturePath: string;
+ let fixtureSourcePath: string;
+
+ let goConfig: vscode.WorkspaceConfiguration;
+ let document: vscode.TextDocument;
+
+ const cancellationTokenSource = new vscode.CancellationTokenSource();
+ const codeLensProvider = new GoRunTestCodeLensProvider();
+
+ suiteSetup(async () => {
+ await updateGoVarsFromConfig();
+
+ gopath = getCurrentGoPath();
+ if (!gopath) {
+ assert.fail('Cannot run tests without a configured GOPATH');
+ }
+ console.log(`Using GOPATH: ${gopath}`);
+
+ // Set up the test fixtures.
+ repoPath = path.join(gopath, 'src', 'test');
+ fixturePath = path.join(repoPath, 'testfixture');
+ fixtureSourcePath = path.join(__dirname, '..', '..', '..', 'test', 'fixtures', 'codelens');
+
+ fs.removeSync(repoPath);
+ fs.copySync(fixtureSourcePath, fixturePath, {
+ recursive: true,
+ // All of the tests run in GOPATH mode for now.
+ // TODO(rstambler): Run tests in GOPATH and module mode.
+ filter: (src: string): boolean => {
+ if (path.basename(src) === 'go.mod') {
+ return false;
+ }
+ return true;
+ },
+ });
+ goConfig = vscode.workspace.getConfiguration('go');
+ const uri = vscode.Uri.file(path.join(fixturePath, 'codelens_test.go'));
+ document = await vscode.workspace.openTextDocument(uri);
+ });
+
+ suiteTeardown(() => {
+ fs.removeSync(repoPath);
+ });
+
+ teardown(() => {
+ sinon.restore();
+ });
+
+ 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(goConfig, []);
+ 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(goConfig, []);
+ 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(goConfig, []);
+ 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);
+ const result = await subTestAtCursor(goConfig, []);
+ assert.equal(result, undefined);
+ });
+
+ 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(goConfig, []);
+ 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(goConfig, { functionName: 'TestMyFunction' });
+ assert.equal(result, undefined);
+ });
+
+ test('Test codelenses', async () => {
+ const codeLenses = await codeLensProvider.provideCodeLenses(document, cancellationTokenSource.token);
+ assert.equal(codeLenses.length, 4);
+ const wantCommands = ['go.test.package', 'go.test.file', 'go.test.cursor', 'go.debug.cursor'];
+ for (let i = 0; i < codeLenses.length; i++) {
+ assert.equal(codeLenses[i].command.command, wantCommands[i]);
+ }
+ });
+
+ test('Benchmark codelenses', async () => {
+ const uri = vscode.Uri.file(path.join(fixturePath, '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]);
+ }
+ });
+});
diff --git a/test/integration/extension.test.ts b/test/integration/extension.test.ts
index 1299a92..b8c752d 100644
--- a/test/integration/extension.test.ts
+++ b/test/integration/extension.test.ts
@@ -28,12 +28,11 @@
import { GoSignatureHelpProvider } from '../../src/goSignature';
import { GoCompletionItemProvider } from '../../src/goSuggest';
import { getWorkspaceSymbols } from '../../src/goSymbol';
-import { subTestAtCursor, testCurrentFile } from '../../src/goTest';
+import { testCurrentFile } from '../../src/goTest';
import {
getBinPath,
getCurrentGoPath,
getGoConfig,
- getGoVersion,
getImportPath,
getToolsGopath,
ICheckResult,
@@ -113,10 +112,6 @@
path.join(fixtureSourcePath, 'diffTestData', 'file2.go'),
path.join(fixturePath, 'diffTest2Data', 'file2.go')
);
- fs.copySync(
- path.join(fixtureSourcePath, 'subtests', 'subtests_test.go'),
- path.join(fixturePath, 'subtests', 'subtests_test.go')
- );
});
suiteTeardown(() => {
@@ -1542,76 +1537,4 @@
await runFillStruct(editor);
assert.equal(vscode.window.activeTextEditor && vscode.window.activeTextEditor.document.getText(), golden);
});
-
- test('Subtests - runs a test with cursor on t.Run line', async () => {
- const config = vscode.workspace.getConfiguration('go');
- const uri = vscode.Uri.file(path.join(fixturePath, 'subtests', 'subtests_test.go'));
- const document = await vscode.workspace.openTextDocument(uri);
- const editor = await vscode.window.showTextDocument(document);
- const selection = new vscode.Selection(7, 4, 7, 4);
- editor.selection = selection;
-
- const result = await subTestAtCursor(config, []);
- assert.equal(result, true);
- });
-
- test('Subtests - runs a test with cursor within t.Run function', async () => {
- const config = vscode.workspace.getConfiguration('go');
- const uri = vscode.Uri.file(path.join(fixturePath, 'subtests', 'subtests_test.go'));
- const document = await vscode.workspace.openTextDocument(uri);
- const editor = await vscode.window.showTextDocument(document);
- const selection = new vscode.Selection(8, 4, 8, 4);
- editor.selection = selection;
-
- const result = await subTestAtCursor(config, []);
- assert.equal(result, true);
- });
-
- test('Subtests - returns false for a failing test', async () => {
- const config = vscode.workspace.getConfiguration('go');
- const uri = vscode.Uri.file(path.join(fixturePath, 'subtests', 'subtests_test.go'));
- const document = await vscode.workspace.openTextDocument(uri);
- const editor = await vscode.window.showTextDocument(document);
- const selection = new vscode.Selection(11, 4, 11, 4);
- editor.selection = selection;
-
- const result = await subTestAtCursor(config, []);
- assert.equal(result, false);
- });
-
- test('Subtests - does nothing for a dynamically defined subtest', async () => {
- const config = vscode.workspace.getConfiguration('go');
- const uri = vscode.Uri.file(path.join(fixturePath, 'subtests', 'subtests_test.go'));
- const document = await vscode.workspace.openTextDocument(uri);
- const editor = await vscode.window.showTextDocument(document);
- const selection = new vscode.Selection(17, 4, 17, 4);
- editor.selection = selection;
-
- const result = await subTestAtCursor(config, []);
- assert.equal(result, undefined);
- });
-
- test('Subtests - does nothing when cursor outside of a test function', async () => {
- const config = vscode.workspace.getConfiguration('go');
- const uri = vscode.Uri.file(path.join(fixturePath, 'subtests', 'subtests_test.go'));
- const document = await vscode.workspace.openTextDocument(uri);
- const editor = await vscode.window.showTextDocument(document);
- const selection = new vscode.Selection(5, 0, 5, 0);
- editor.selection = selection;
-
- const result = await subTestAtCursor(config, []);
- assert.equal(result, undefined);
- });
-
- test('Subtests - does nothing when no test function covers the cursor and a function name is passed in', async () => {
- const config = vscode.workspace.getConfiguration('go');
- const uri = vscode.Uri.file(path.join(fixturePath, 'subtests', 'subtests_test.go'));
- const document = await vscode.workspace.openTextDocument(uri);
- const editor = await vscode.window.showTextDocument(document);
- const selection = new vscode.Selection(5, 0, 5, 0);
- editor.selection = selection;
-
- const result = await subTestAtCursor(config, {functionName: 'TestMyFunction'});
- assert.equal(result, undefined);
- });
});
diff --git a/test/integration/index.ts b/test/integration/index.ts
index 12e0292..a86f9cd 100644
--- a/test/integration/index.ts
+++ b/test/integration/index.ts
@@ -15,7 +15,7 @@
const testsRoot = path.resolve(__dirname, '..');
return new Promise((c, e) => {
- glob('integration/**.test.js', { cwd: testsRoot }, (err, files) => {
+ glob('integration/codelens.test.js', { cwd: testsRoot }, (err, files) => {
if (err) {
return e(err);
}