Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Added support for tests using stretchr/testify #1707

Merged
merged 6 commits into from
Jun 20, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/goRunTestCodelens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import vscode = require('vscode');
import path = require('path');
import { TextDocument, CancellationToken, CodeLens, Command } from 'vscode';
import { getTestFunctions, getBenchmarkFunctions, getTestFlags } from './testUtils';
import { getTestFunctions, getBenchmarkFunctions, getTestFlags, extractInstanceTestName } from './testUtils';
import { GoDocumentSymbolProvider } from './goOutline';
import { getCurrentGoPath } from './util';
import { GoBaseCodeLensProvider } from './goBaseCodelens';
Expand Down Expand Up @@ -94,10 +94,13 @@ export class GoRunTestCodeLensProvider extends GoBaseCodeLensProvider {

codelens.push(new CodeLens(func.location.range, runTestCmd));

let instanceMethod = extractInstanceTestName(func.name);
let args = !instanceMethod ? ['-test.run', `^${func.name}$`] : ['-testify.m', `^${instanceMethod}$`];

let debugTestCmd: Command = {
title: 'debug test',
command: 'go.debug.startSession',
arguments: [Object.assign({}, currentDebugConfig, { args: ['-test.run', '^' + func.name + '$'] })]
arguments: [Object.assign({}, currentDebugConfig, { args: args })]
};

codelens.push(new CodeLens(func.location.range, debugTestCmd));
Expand Down
18 changes: 8 additions & 10 deletions src/goTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import path = require('path');
import vscode = require('vscode');
import os = require('os');
import { goTest, TestConfig, getTestFlags, getTestFunctions, getBenchmarkFunctions } from './testUtils';
import { goTest, TestConfig, getTestFlags, getTestFunctions, getBenchmarkFunctions, isInstanceTestMethod } from './testUtils';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isInstanceTestMethod is an unused import here

import { getCoverage } from './goCover';

// lastTestConfig holds a reference to the last executed TestConfig which allows
Expand All @@ -34,7 +34,7 @@ export function testAtCursor(goConfig: vscode.WorkspaceConfiguration, isBenchmar

const getFunctions = isBenchmark ? getBenchmarkFunctions : getTestFunctions;

const {tmpCoverPath, testFlags } = makeCoverData(goConfig, 'coverOnSingleTest', args);
const { tmpCoverPath, testFlags } = makeCoverData(goConfig, 'coverOnSingleTest', args);

editor.document.save().then(() => {
return getFunctions(editor.document, null).then(testFunctions => {
Expand All @@ -59,13 +59,12 @@ export function testAtCursor(goConfig: vscode.WorkspaceConfiguration, isBenchmar
return;
}

const testConfig = {
const testConfig: TestConfig = {
goConfig: goConfig,
dir: path.dirname(editor.document.fileName),
flags: testFlags,
functions: [testFunctionName],
isBenchmark: isBenchmark,
showTestCoverage: true
};

// Remember this config as the last executed test.
Expand Down Expand Up @@ -94,13 +93,12 @@ export function testCurrentPackage(goConfig: vscode.WorkspaceConfiguration, args
return;
}

const {tmpCoverPath, testFlags } = makeCoverData(goConfig, 'coverOnTestPackage', args);
const { tmpCoverPath, testFlags } = makeCoverData(goConfig, 'coverOnTestPackage', args);

const testConfig = {
const testConfig: TestConfig = {
goConfig: goConfig,
dir: path.dirname(editor.document.fileName),
flags: testFlags,
showTestCoverage: true
};
// Remember this config as the last executed test.
lastTestConfig = testConfig;
Expand Down Expand Up @@ -160,11 +158,11 @@ export function testCurrentFile(goConfig: vscode.WorkspaceConfiguration, args: s

return editor.document.save().then(() => {
return getTestFunctions(editor.document, null).then(testFunctions => {
const testConfig = {
const testConfig: TestConfig = {
goConfig: goConfig,
dir: path.dirname(editor.document.fileName),
flags: getTestFlags(goConfig, args),
functions: testFunctions.map(func => { return func.name; })
functions: testFunctions.map(sym => sym.name),
};
// Remember this config as the last executed test.
lastTestConfig = testConfig;
Expand Down Expand Up @@ -203,5 +201,5 @@ function makeCoverData(goConfig: vscode.WorkspaceConfiguration, confFlag: string
testFlags.push('-coverprofile=' + tmpCoverPath);
}

return {tmpCoverPath, testFlags};
return { tmpCoverPath, testFlags };
}
50 changes: 48 additions & 2 deletions src/testUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { getNonVendorPackages } from './goPackages';

let outputChannel = vscode.window.createOutputChannel('Go Tests');

const testSuiteMethodRe = /^\([^)]+\)\.Test/;

/**
* Input to goTest.
Expand Down Expand Up @@ -89,10 +90,36 @@ export function getTestFunctions(doc: vscode.TextDocument, token: vscode.Cancell
.then(symbols =>
symbols.filter(sym =>
sym.kind === vscode.SymbolKind.Function
&& (sym.name.startsWith('Test') || sym.name.startsWith('Example')))
&& (sym.name.startsWith('Test') || sym.name.startsWith('Example') || isInstanceTestMethod(sym))
)
);
}

/**
* Checks whether given symbol is a test method of a test suite instance.
*
* @param symbol Symbol to check.
*/
export function isInstanceTestMethod(symbol: vscode.SymbolInformation | string): boolean {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this function isn't used anywhere, it need not be exported.

let symbolName = typeof symbol === 'string' ? symbol : symbol.name;
return testSuiteMethodRe.test(symbolName);
}

/**
* Extracts test method name of a suite test function.
* For example a symbol with name "(*testSuite).TestMethod" will return "TestMethod".
*
* @param symbol Symbol to extract method name from.
*/
export function extractInstanceTestName(symbol: vscode.SymbolInformation | string): string {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All uses of this function passes in a string. So we don't need to support both string and vscode.SymbolInformation

let symbolName = typeof symbol === 'string' ? symbol : symbol.name;
const match = symbolName.match(/\.(Test.*)$/);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not re-use the testSuiteMethodRe regex here? We can do that if it is updated to /^\([^)]+\)\.(Test.*)$/.

if (!match) {
return null;
}
return match[1];
}

/**
* Returns all Benchmark functions in the given source file.
*
Expand Down Expand Up @@ -242,7 +269,26 @@ function expandFilePathInOutput(output: string, cwd: string): string {
*/
function targetArgs(testconfig: TestConfig): Thenable<Array<string>> {
if (testconfig.functions) {
return Promise.resolve([testconfig.isBenchmark ? '-bench' : '-run', util.format('^%s$', testconfig.functions.join('|'))]);
let params: string[] = [];
if (testconfig.isBenchmark) {
params = ['-bench', util.format('^%s$', testconfig.functions.join('|'))];
} else {
let testFunctions = testconfig.functions;
let testifyMethods = testFunctions.filter(isInstanceTestMethod);
if (testifyMethods.length > 0) {
// filter out testify methods
testFunctions = testFunctions.filter(fn => !isInstanceTestMethod(fn));
testifyMethods = testifyMethods.map(extractInstanceTestName);
}

if (testFunctions.length > 0) {
params = params.concat(['-run', util.format('^%s$', testFunctions.join('|'))]);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to pass -run ^$ even if test.Functions array is empty. Otherwise all tests will be run

}
if (testifyMethods.length > 0) {
params = params.concat(['-testify.m', util.format('^%s$', testifyMethods.join('|'))]);
}
}
return Promise.resolve(params);
} else if (testconfig.includeSubDirectories && !testconfig.isBenchmark) {
return getGoVersion().then((ver: SemVersion) => {
if (ver && (ver.major > 1 || (ver.major === 1 && ver.minor >= 9))) {
Expand Down