Add debugTestAtCursor command (#2059)
This commit is contained in:
Родитель
e7b8beafd5
Коммит
bcc6407ef6
|
@ -24,7 +24,7 @@ before_install:
|
|||
fi
|
||||
|
||||
install:
|
||||
- TRAVIS_NODE_VERSION="6";
|
||||
- TRAVIS_NODE_VERSION="6"; GOMETALINTER_RELEASE_TAG="v2.0.12"; GOMETALIMTER_INSTALL_SCRIPT_COMMIT="83891259ab664a6d96066685f7f07431375ca8e5";
|
||||
# Clear out whatever version of NVM Travis has as it is old.
|
||||
- rm -rf ~/.nvm;
|
||||
# Grab NVM.
|
||||
|
@ -49,7 +49,8 @@ install:
|
|||
- go get -u -v github.com/cweill/gotests/...
|
||||
- go get -u -v github.com/haya14busa/goplay/cmd/goplay
|
||||
- go get -u -v github.com/davidrjenni/reftools/cmd/fillstruct
|
||||
- curl -fsSL https://git.io/vp6lP | sh -s -- -b $GOPATH/bin
|
||||
# The latest script at https://git.io/vp6lP seems to have broken us as some checkers have been removed. Locking to previous version.
|
||||
- curl -fsSL https://raw.githubusercontent.com/alecthomas/gometalinter/$GOMETALIMTER_INSTALL_SCRIPT_COMMIT/scripts/install.sh | sh -s $GOMETALINTER_RELEASE_TAG -- -b $GOPATH/bin
|
||||
|
||||
script:
|
||||
- npm run lint
|
||||
|
|
20
package.json
20
package.json
|
@ -101,6 +101,11 @@
|
|||
"title": "Go: Benchmark Function At Cursor",
|
||||
"description": "Runs a benchmark at the cursor."
|
||||
},
|
||||
{
|
||||
"command": "go.debug.cursor",
|
||||
"title": "Go: Debug Test At Cursor",
|
||||
"description": "Debug test at the cursor."
|
||||
},
|
||||
{
|
||||
"command": "go.test.file",
|
||||
"title": "Go: Test File",
|
||||
|
@ -1155,6 +1160,11 @@
|
|||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "If true, adds command to upload the current file or selection to the Go Playground"
|
||||
},
|
||||
"debugTestAtCursor": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "If true, adds command to debug the test under the cursor to the editor context menu"
|
||||
}
|
||||
},
|
||||
"default": {
|
||||
|
@ -1169,7 +1179,8 @@
|
|||
"generateTestForPackage": false,
|
||||
"addImport": true,
|
||||
"testCoverage": true,
|
||||
"playground": true
|
||||
"playground": true,
|
||||
"debugTestAtCursor": true
|
||||
},
|
||||
"description": "Experimental Feature: Enable/Disable entries from the context menu in the editor.",
|
||||
"scope": "resource"
|
||||
|
@ -1308,6 +1319,11 @@
|
|||
"command": "go.benchmark.cursor",
|
||||
"group": "Go group 1"
|
||||
},
|
||||
{
|
||||
"when": "editorTextFocus && config.go.editorContextMenuCommands.debugTestAtCursor && resourceLangId == go && !config.editor.codeLens",
|
||||
"command": "go.debug.cursor",
|
||||
"group": "Go group 1"
|
||||
},
|
||||
{
|
||||
"when": "editorTextFocus && config.go.editorContextMenuCommands.testFile && resourceLangId == go",
|
||||
"command": "go.test.file",
|
||||
|
@ -1351,4 +1367,4 @@
|
|||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -326,15 +326,18 @@ export function activate(ctx: vscode.ExtensionContext): void {
|
|||
}));
|
||||
|
||||
ctx.subscriptions.push(vscode.commands.registerCommand('go.test.cursor', (args) => {
|
||||
let goConfig = vscode.workspace.getConfiguration('go', vscode.window.activeTextEditor ? vscode.window.activeTextEditor.document.uri : null);
|
||||
let isBenchmark = false;
|
||||
testAtCursor(goConfig, isBenchmark, args);
|
||||
const goConfig = vscode.workspace.getConfiguration('go', vscode.window.activeTextEditor ? vscode.window.activeTextEditor.document.uri : null);
|
||||
testAtCursor(goConfig, 'test', args);
|
||||
}));
|
||||
|
||||
ctx.subscriptions.push(vscode.commands.registerCommand('go.debug.cursor', (args) => {
|
||||
const goConfig = vscode.workspace.getConfiguration('go', vscode.window.activeTextEditor ? vscode.window.activeTextEditor.document.uri : null);
|
||||
testAtCursor(goConfig, 'debug', args);
|
||||
}));
|
||||
|
||||
ctx.subscriptions.push(vscode.commands.registerCommand('go.benchmark.cursor', (args) => {
|
||||
let goConfig = vscode.workspace.getConfiguration('go', vscode.window.activeTextEditor ? vscode.window.activeTextEditor.document.uri : null);
|
||||
let isBenchmark = true;
|
||||
testAtCursor(goConfig, isBenchmark, args);
|
||||
const goConfig = vscode.workspace.getConfiguration('go', vscode.window.activeTextEditor ? vscode.window.activeTextEditor.document.uri : null);
|
||||
testAtCursor(goConfig, 'benchmark', args);
|
||||
}));
|
||||
|
||||
ctx.subscriptions.push(vscode.commands.registerCommand('go.test.package', (args) => {
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
|
||||
import vscode = require('vscode');
|
||||
import path = require('path');
|
||||
import { TextDocument, CancellationToken, CodeLens, Command } from 'vscode';
|
||||
import { getTestFunctions, getBenchmarkFunctions, getTestFlags, extractInstanceTestName, findAllTestSuiteRuns } from './testUtils';
|
||||
import { GoDocumentSymbolProvider } from './goOutline';
|
||||
import { getCurrentGoPath } from './util';
|
||||
import { CancellationToken, CodeLens, Command, TextDocument } from 'vscode';
|
||||
import { GoBaseCodeLensProvider } from './goBaseCodelens';
|
||||
import { GoDocumentSymbolProvider } from './goOutline';
|
||||
import { getBenchmarkFunctions, getTestFlags, getTestFunctionDebugArgs, getTestFunctions } from './testUtils';
|
||||
import { getCurrentGoPath } from './util';
|
||||
|
||||
export class GoRunTestCodeLensProvider extends GoBaseCodeLensProvider {
|
||||
private readonly benchmarkRegex = /^Benchmark.+/;
|
||||
|
@ -101,39 +101,26 @@ export class GoRunTestCodeLensProvider extends GoBaseCodeLensProvider {
|
|||
|
||||
const testPromise = getTestFunctions(document, token).then(testFunctions => {
|
||||
testFunctions.forEach(func => {
|
||||
let runTestCmd: Command = {
|
||||
const runTestCmd: Command = {
|
||||
title: 'run test',
|
||||
command: 'go.test.cursor',
|
||||
arguments: [{ functionName: func.name }]
|
||||
};
|
||||
|
||||
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 = {
|
||||
const args = getTestFunctionDebugArgs(document, func.name, testFunctions);
|
||||
const debugTestCmd: Command = {
|
||||
title: 'debug test',
|
||||
command: 'go.debug.startSession',
|
||||
arguments: [Object.assign({}, currentDebugConfig, { args: args })]
|
||||
arguments: [Object.assign({}, currentDebugConfig, { args })]
|
||||
};
|
||||
|
||||
codelens.push(new CodeLens(func.location.range, debugTestCmd));
|
||||
});
|
||||
});
|
||||
|
||||
const benchmarkPromise = getBenchmarkFunctions(document, token).then(benchmarkFunctions => {
|
||||
benchmarkFunctions.forEach(func => {
|
||||
let runBenchmarkCmd: Command = {
|
||||
const runBenchmarkCmd: Command = {
|
||||
title: 'run benchmark',
|
||||
command: 'go.benchmark.cursor',
|
||||
arguments: [{ functionName: func.name }]
|
||||
|
@ -141,7 +128,7 @@ export class GoRunTestCodeLensProvider extends GoBaseCodeLensProvider {
|
|||
|
||||
codelens.push(new CodeLens(func.location.range, runBenchmarkCmd));
|
||||
|
||||
let debugTestCmd: Command = {
|
||||
const debugTestCmd: Command = {
|
||||
title: 'debug benchmark',
|
||||
command: 'go.debug.startSession',
|
||||
arguments: [Object.assign({}, currentDebugConfig, { args: ['-test.bench', '^' + func.name + '$', '-test.run', 'a^'] })]
|
||||
|
|
137
src/goTest.ts
137
src/goTest.ts
|
@ -2,29 +2,40 @@
|
|||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import path = require('path');
|
||||
import vscode = require('vscode');
|
||||
import os = require('os');
|
||||
import { getTempFilePath } from './util';
|
||||
import { goTest, TestConfig, getTestFlags, getTestFunctions, getBenchmarkFunctions, extractInstanceTestName, findAllTestSuiteRuns } from './testUtils';
|
||||
|
||||
import { applyCodeCoverageToAllEditors } from './goCover';
|
||||
import { isModSupported } from './goModules';
|
||||
import {
|
||||
extractInstanceTestName,
|
||||
findAllTestSuiteRuns,
|
||||
getBenchmarkFunctions,
|
||||
getTestFlags,
|
||||
getTestFunctionDebugArgs,
|
||||
getTestFunctions,
|
||||
goTest,
|
||||
TestConfig,
|
||||
} from './testUtils';
|
||||
import { getTempFilePath } from './util';
|
||||
|
||||
// lastTestConfig holds a reference to the last executed TestConfig which allows
|
||||
// the last test to be easily re-executed.
|
||||
let lastTestConfig: TestConfig;
|
||||
|
||||
export type TestAtCursorCmd = 'debug' | 'test' | 'benchmark';
|
||||
|
||||
/**
|
||||
* Executes the unit test at the primary cursor using `go test`. Output
|
||||
* is sent to the 'Go' channel.
|
||||
*
|
||||
* @param goConfig Configuration for the Go extension.
|
||||
* @param cmd Whether the command is test , benchmark or debug.
|
||||
*/
|
||||
export function testAtCursor(goConfig: vscode.WorkspaceConfiguration, isBenchmark: boolean, args: any) {
|
||||
let editor = vscode.window.activeTextEditor;
|
||||
export function testAtCursor(goConfig: vscode.WorkspaceConfiguration, cmd: TestAtCursorCmd, args: any) {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) {
|
||||
vscode.window.showInformationMessage('No editor is active.');
|
||||
return;
|
||||
|
@ -34,68 +45,82 @@ export function testAtCursor(goConfig: vscode.WorkspaceConfiguration, isBenchmar
|
|||
return;
|
||||
}
|
||||
|
||||
const getFunctions = isBenchmark ? getBenchmarkFunctions : getTestFunctions;
|
||||
|
||||
const { tmpCoverPath, testFlags } = makeCoverData(goConfig, 'coverOnSingleTest', args);
|
||||
|
||||
editor.document.save().then(() => {
|
||||
return getFunctions(editor.document, null).then(testFunctions => {
|
||||
let testFunctionName: string;
|
||||
const getFunctions = cmd === 'benchmark' ? getBenchmarkFunctions : getTestFunctions;
|
||||
|
||||
editor.document.save().then(async () => {
|
||||
try {
|
||||
const testFunctions = await getFunctions(editor.document, null);
|
||||
// We use functionName if it was provided as argument
|
||||
// Otherwise find any test function containing the cursor.
|
||||
if (args && args.functionName) {
|
||||
testFunctionName = args.functionName;
|
||||
} else {
|
||||
for (let func of testFunctions) {
|
||||
let selection = editor.selection;
|
||||
if (selection && func.location.range.contains(selection.start)) {
|
||||
testFunctionName = func.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const testFunctionName = args && args.functionName
|
||||
? args.functionName
|
||||
: testFunctions.filter(func => func.location.range.contains(editor.selection.start))
|
||||
.map(el => el.name)[0];
|
||||
if (!testFunctionName) {
|
||||
vscode.window.showInformationMessage('No test function found at cursor.');
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
if (cmd === 'debug') {
|
||||
await debugTestAtCursor(editor, testFunctionName, testFunctions, goConfig);
|
||||
} else if (cmd === 'benchmark' || cmd === 'test') {
|
||||
await runTestAtCursor(editor, testFunctionName, testFunctions, goConfig, args, cmd);
|
||||
} else {
|
||||
throw 'Unsupported command.';
|
||||
}
|
||||
|
||||
const testConfig: TestConfig = {
|
||||
goConfig: goConfig,
|
||||
dir: path.dirname(editor.document.fileName),
|
||||
flags: testFlags,
|
||||
functions: testConfigFns,
|
||||
isBenchmark: isBenchmark,
|
||||
};
|
||||
|
||||
// Remember this config as the last executed test.
|
||||
lastTestConfig = testConfig;
|
||||
|
||||
return isModSupported(editor.document.uri).then(isMod => {
|
||||
testConfig.isMod = isMod;
|
||||
return goTest(testConfig).then(success => {
|
||||
if (success && tmpCoverPath) {
|
||||
return applyCodeCoverageToAllEditors(tmpCoverPath, testConfig.dir);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}).then(null, err => {
|
||||
console.error(err);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the test at cursor.
|
||||
*/
|
||||
async function runTestAtCursor(editor: vscode.TextEditor, testFunctionName: string, testFunctions: vscode.SymbolInformation[], goConfig: vscode.WorkspaceConfiguration, cmd: TestAtCursorCmd, args: any) {
|
||||
const { tmpCoverPath, testFlags } = makeCoverData(goConfig, 'coverOnSingleTest', args);
|
||||
|
||||
const testConfigFns = cmd !== 'benchmark' && extractInstanceTestName(testFunctionName)
|
||||
? [testFunctionName, ...findAllTestSuiteRuns(editor.document, testFunctions).map(t => t.name)]
|
||||
: [testFunctionName];
|
||||
|
||||
const isMod = await isModSupported(editor.document.uri);
|
||||
const testConfig: TestConfig = {
|
||||
goConfig: goConfig,
|
||||
dir: path.dirname(editor.document.fileName),
|
||||
flags: testFlags,
|
||||
functions: testConfigFns,
|
||||
isBenchmark: cmd === 'benchmark',
|
||||
isMod
|
||||
};
|
||||
// Remember this config as the last executed test.
|
||||
lastTestConfig = testConfig;
|
||||
await goTest(testConfig);
|
||||
if (tmpCoverPath) {
|
||||
return applyCodeCoverageToAllEditors(tmpCoverPath, testConfig.dir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Debugs the test at cursor.
|
||||
*/
|
||||
async function debugTestAtCursor(editor: vscode.TextEditor, testFunctionName: string, testFunctions: vscode.SymbolInformation[], goConfig: vscode.WorkspaceConfiguration) {
|
||||
|
||||
const args = getTestFunctionDebugArgs(editor.document, testFunctionName, testFunctions);
|
||||
const workspaceFolder = vscode.workspace.getWorkspaceFolder(editor.document.uri);
|
||||
const debugConfig: vscode.DebugConfiguration = {
|
||||
name: 'Debug Test',
|
||||
type: 'go',
|
||||
request: 'launch',
|
||||
mode: 'auto',
|
||||
program: editor.document.fileName,
|
||||
env: goConfig.get('testEnvVars', {}),
|
||||
envFile: goConfig.get('testEnvFile'),
|
||||
args
|
||||
};
|
||||
return await vscode.debug.startDebugging(workspaceFolder, debugConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs all tests in the package of the source of the active editor.
|
||||
*
|
||||
|
|
|
@ -2,16 +2,17 @@
|
|||
* Copyright (C) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------*/
|
||||
|
||||
import cp = require('child_process');
|
||||
import path = require('path');
|
||||
import vscode = require('vscode');
|
||||
import util = require('util');
|
||||
import { parseEnvFile, getCurrentGoWorkspaceFromGOPATH } from './goPath';
|
||||
import { getToolsEnvVars, getGoVersion, LineBuffer, SemVersion, resolvePath, getCurrentGoPath, getBinPath } from './util';
|
||||
import vscode = require('vscode');
|
||||
|
||||
import { getCurrentPackage } from './goModules';
|
||||
import { GoDocumentSymbolProvider } from './goOutline';
|
||||
import { getNonVendorPackages } from './goPackages';
|
||||
import { getCurrentPackage } from './goModules';
|
||||
import { getCurrentGoWorkspaceFromGOPATH, parseEnvFile } from './goPath';
|
||||
import { getBinPath, getCurrentGoPath, getGoVersion, getToolsEnvVars, LineBuffer, resolvePath } from './util';
|
||||
|
||||
|
||||
const sendSignal = 'SIGKILL';
|
||||
const outputChannel = vscode.window.createOutputChannel('Go Tests');
|
||||
|
@ -126,6 +127,23 @@ export function extractInstanceTestName(symbolName: string): string {
|
|||
return match[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the appropriate debug arguments for a debug session on a test function.
|
||||
* @param document The document containing the tests
|
||||
* @param testFunctionName The test function to get the debug args
|
||||
* @param testFunctions The test functions found in the document
|
||||
*/
|
||||
export function getTestFunctionDebugArgs(document: vscode.TextDocument, testFunctionName: string, testFunctions: vscode.SymbolInformation[]): string[] {
|
||||
const instanceMethod = extractInstanceTestName(testFunctionName);
|
||||
if (instanceMethod) {
|
||||
const testFns = findAllTestSuiteRuns(document, testFunctions);
|
||||
const testSuiteRuns = ['-test.run', `^${testFns.map(t => t.name).join('|')}$`];
|
||||
const testSuiteTests = ['-testify.m', `^${instanceMethod}$`];
|
||||
return [...testSuiteRuns, ...testSuiteTests];
|
||||
} else {
|
||||
return ['-test.run', `^${testFunctionName}$`];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Finds test methods containing "suite.Run()" call.
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче