in src/testUtils.ts [275:383]
export async function goTest(testconfig: TestConfig): Promise<boolean> {
let outputChannel = testOutputChannel;
if (testconfig.outputChannel) {
outputChannel = testconfig.outputChannel;
}
const goRuntimePath = getBinPath('go');
if (!goRuntimePath) {
vscode.window.showErrorMessage(
`Failed to run "go test" as the "go" binary cannot be found in either GOROOT(${getCurrentGoRoot()}) or PATH(${getEnvPath()})`
);
return Promise.resolve(false);
}
// We do not want to clear it if tests are already running, as that could
// lose valuable output.
if (runningTestProcesses.length < 1) {
outputChannel.clear();
}
if (testconfig.goConfig['disableConcurrentTests']) {
await cancelRunningTests();
}
if (!testconfig.background) {
outputChannel.show(true);
}
const testType: string = testconfig.isBenchmark ? 'Benchmarks' : 'Tests';
// compute test target package
const { targets, pkgMap, currentGoWorkspace } = await getTestTargetPackages(testconfig, outputChannel);
// generate full test args.
const { args, outArgs, tmpCoverPath, addJSONFlag } = computeTestCommand(testconfig, targets);
outputChannel.appendLine(['Running tool:', goRuntimePath, ...outArgs].join(' '));
outputChannel.appendLine('');
let testResult = false;
try {
testResult = await new Promise<boolean>(async (resolve, reject) => {
const testEnvVars = getTestEnvVars(testconfig.goConfig);
const tp = cp.spawn(goRuntimePath, args, { env: testEnvVars, cwd: testconfig.dir });
const outBuf = new LineBuffer();
const errBuf = new LineBuffer();
testconfig.cancel?.onCancellationRequested(() => killProcessTree(tp));
const testResultLines: string[] = [];
const processTestResultLine = addJSONFlag
? processTestResultLineInJSONMode(
pkgMap,
currentGoWorkspace,
outputChannel,
testconfig.goTestOutputConsumer
)
: processTestResultLineInStandardMode(pkgMap, currentGoWorkspace, testResultLines, outputChannel);
outBuf.onLine((line) => processTestResultLine(line));
outBuf.onDone((last) => {
if (last) {
processTestResultLine(last);
}
// If there are any remaining test result lines, emit them to the output channel.
if (testResultLines.length > 0) {
testResultLines.forEach((line) => outputChannel.appendLine(line));
}
});
// go test emits build errors on stderr, which contain paths relative to the cwd
errBuf.onLine((line) => outputChannel.appendLine(expandFilePathInOutput(line, testconfig.dir)));
errBuf.onDone((last) => last && outputChannel.appendLine(expandFilePathInOutput(last, testconfig.dir)));
tp.stdout.on('data', (chunk) => outBuf.append(chunk.toString()));
tp.stderr.on('data', (chunk) => errBuf.append(chunk.toString()));
statusBarItem.show();
tp.on('close', (code, signal) => {
outBuf.done();
errBuf.done();
const index = runningTestProcesses.indexOf(tp, 0);
if (index > -1) {
runningTestProcesses.splice(index, 1);
}
if (!runningTestProcesses.length) {
statusBarItem.hide();
}
resolve(code === 0);
});
runningTestProcesses.push(tp);
});
} catch (err) {
outputChannel.appendLine(`Error: ${testType} failed.`);
if (err instanceof Error) {
outputChannel.appendLine((err as Error).message);
}
}
if (tmpCoverPath) {
await applyCodeCoverageToAllEditors(tmpCoverPath, testconfig.dir);
}
return testResult;
}