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

Commit

Permalink
Added support for tests using stretchr/testify (#1707)
Browse files Browse the repository at this point in the history
* Added support for testify

* Refactoring

* Add an explanation why we're skipping the -run param

* Find matching test functions

* Return all candidates

* Refactor per review comments
  • Loading branch information
mhr3 authored and ramya-rao-a committed Jun 20, 2018
1 parent 70f6555 commit 47464f0
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 16 deletions.
16 changes: 14 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, findAllTestSuiteRuns } from './testUtils';
import { GoDocumentSymbolProvider } from './goOutline';
import { getCurrentGoPath } from './util';
import { GoBaseCodeLensProvider } from './goBaseCodelens';
Expand Down Expand Up @@ -94,10 +94,22 @@ export class GoRunTestCodeLensProvider extends GoBaseCodeLensProvider {

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

let args: string[] = [];
let instanceMethod = extractInstanceTestName(func.name);
if (instanceMethod) {
const testFns = findAllTestSuiteRuns(document, testFunctions);
if (testFns && testFns.length > 0) {
args = args.concat('-test.run', `^${testFns.map(t => t.name).join('|')}$`);
}
args = args.concat('-testify.m', `^${instanceMethod}$`);
} else {
args = args.concat('-test.run', `^${func.name}$`);
}

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
30 changes: 19 additions & 11 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, extractInstanceTestName, findAllTestSuiteRuns } from './testUtils';
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,22 @@ export function testAtCursor(goConfig: vscode.WorkspaceConfiguration, isBenchmar
return;
}

const testConfig = {
let testConfigFns = [testFunctionName];

if (!isBenchmark && extractInstanceTestName(testFunctionName)) {
// find test function with corresponding suite.Run
const testFns = findAllTestSuiteRuns(editor.document, testFunctions);
if (testFns) {
testConfigFns = testConfigFns.concat(testFns.map(t => t.name));
}
}

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

// Remember this config as the last executed test.
Expand Down Expand Up @@ -94,13 +103,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 +168,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 +211,5 @@ function makeCoverData(goConfig: vscode.WorkspaceConfiguration, confFlag: string
testFlags.push('-coverprofile=' + tmpCoverPath);
}

return {tmpCoverPath, testFlags};
return { tmpCoverPath, testFlags };
}
57 changes: 54 additions & 3 deletions src/testUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ statusBarItem.text = '$(x) Cancel Running Tests';
*/
const runningTestProcesses: cp.ChildProcess[] = [];

const testSuiteMethodRegex = /^\(([^)]+)\)\.(Test.*)$/;

/**
* Input to goTest.
Expand Down Expand Up @@ -98,10 +99,38 @@ 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') || testSuiteMethodRegex.test(sym.name))
)
);
}

/**
* Extracts test method name of a suite test function.
* For example a symbol with name "(*testSuite).TestMethod" will return "TestMethod".
*
* @param symbolName Symbol Name to extract method name from.
*/
export function extractInstanceTestName(symbolName: string): string {
const match = symbolName.match(testSuiteMethodRegex);
if (!match || match.length !== 3) {
return null;
}
return match[2];
}

/**
* Finds test methods containing "suite.Run()" call.
*
* @param doc Editor document
* @param allTests All test functions
*/
export function findAllTestSuiteRuns(doc: vscode.TextDocument, allTests: vscode.SymbolInformation[]): vscode.SymbolInformation[] {
// get non-instance test functions
const testFunctions = allTests.filter(t => !testSuiteMethodRegex.test(t.name));
// filter further to ones containing suite.Run()
return testFunctions.filter(t => doc.getText(t.location.range).includes('suite.Run('));
}

/**
* Returns all Benchmark functions in the given source file.
*
Expand Down Expand Up @@ -166,7 +195,7 @@ export function goTest(testconfig: TestConfig): Thenable<boolean> {

targetArgs(testconfig).then(targets => {
let outTargets = args.slice(0);
if (targets.length > 2) {
if (targets.length > 4) {
outTargets.push('<long arguments omitted>');
} else {
outTargets.push(...targets);
Expand Down Expand Up @@ -287,7 +316,29 @@ 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(fn => testSuiteMethodRegex.test(fn));
if (testifyMethods.length > 0) {
// filter out testify methods
testFunctions = testFunctions.filter(fn => !testSuiteMethodRegex.test(fn));
testifyMethods = testifyMethods.map(extractInstanceTestName);
}

// we might skip the '-run' param when running only testify methods, which will result
// in running all the test methods, but one of them should call testify's `suite.Run(...)`
// which will result in the correct thing to happen
if (testFunctions.length > 0) {
params = params.concat(['-run', util.format('^%s$', testFunctions.join('|'))]);
}
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

0 comments on commit 47464f0

Please sign in to comment.