-
Notifications
You must be signed in to change notification settings - Fork 646
Added support for tests using stretchr/testify #1707
Changes from 4 commits
1d4f9eb
b109cab
29f7268
273966b
8d0721e
714dd3a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ import { getNonVendorPackages } from './goPackages'; | |
|
||
let outputChannel = vscode.window.createOutputChannel('Go Tests'); | ||
|
||
const testSuiteMethodRegex = /^\(([^)]+)\)\.(Test.*)$/; | ||
|
||
/** | ||
* Input to goTest. | ||
|
@@ -89,10 +90,64 @@ 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 method containing suite.Run() call for the given instance test name. | ||
* | ||
* @param symbolName Instance test function name (including the type name) | ||
* @param doc Editor document | ||
* @param allTests All test functions | ||
*/ | ||
export function findTestFnForInstanceTest(symbolName: string, 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() | ||
const candidates = testFunctions.filter(t => { | ||
const text = doc.getText(t.location.range); | ||
return /suite\.Run\(/.test(text); | ||
}); | ||
|
||
switch (candidates.length) { | ||
case 0: return null; | ||
case 1: return candidates[0]; | ||
} | ||
|
||
// we have multiple matches, filter even more | ||
const match = symbolName.match(testSuiteMethodRegex); | ||
if (!match || match.length !== 3) { | ||
return candidates[0]; | ||
} | ||
// drop pointers, lowercase for more lenient matching | ||
const instanceType = match[1].replace(/[*]/g, '').toLowerCase(); | ||
const filtered = candidates.filter(t => { | ||
const text = doc.getText(t.location.range).toLowerCase(); | ||
if (text.includes(instanceType)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This may give false positives if say there is a comment inside the function with another suite's name. Why not return all the functions that have a Since we also pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed, clearly this isn't going to work in 100% of cases, but should be close enough. |
||
return true; | ||
} | ||
// try the test name as well | ||
return t.name.substring(4).includes(instanceType); | ||
}); | ||
return filtered.length > 0 ? filtered[0] : candidates[0]; | ||
} | ||
|
||
/** | ||
* Returns all Benchmark functions in the given source file. | ||
* | ||
|
@@ -152,7 +207,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); | ||
|
@@ -242,7 +297,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'll skip the '-run' param when running only testify methods, which will result | ||
// in running all the test methods, but that is necessary, cause one of them should | ||
// call testify's `suite.Run(...)` | ||
if (testFunctions.length > 0) { | ||
params = params.concat(['-run', util.format('^%s$', testFunctions.join('|'))]); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We have to pass |
||
} | ||
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))) { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since this is a simple string check, wont
text.includes('suite.Run(')
be simpler?Unless we make this a useful regex like `/suite.Run([^\)]+)/