From 2eed87cb4804afc9e736074ea75f5e9bfe79cae3 Mon Sep 17 00:00:00 2001 From: Cedric Lamoriniere Date: Tue, 13 Sep 2016 08:17:21 +0200 Subject: [PATCH] Add support for gotests Implements three new commands that use gotests: - go.test.generate.package: generates all unit-test squeletons for the current package. - go.test.generate.file: generates all unit-test squeletons for the current file. - go.test.generate.function: generates unit-test squeleton for the selected function in the current file. --- .travis.yml | 1 + README.md | 6 +++ package.json | 15 ++++++ src/goInstallTools.ts | 3 +- src/goMain.ts | 13 +++++ src/goTests.ts | 113 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 src/goTests.ts diff --git a/.travis.yml b/.travis.yml index 8c635458d..507deae10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -31,6 +31,7 @@ install: - go get -u -v github.com/newhook/go-symbols - go get -u -v golang.org/x/tools/cmd/guru - go get -u -v github.com/alecthomas/gometalinter + - go get -u -v github.com/cweill/gotests - GO15VENDOREXPERIMENT=1 gometalinter --install script: diff --git a/README.md b/README.md index 8a0df2b82..6ed8f8b88 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ This extension adds rich language support for the Go language to VS Code, includ - Build-on-save (using `go build` and `go test`) - Lint-on-save (using `golint` or `gometalinter`) - Format (using `goreturns` or `goimports` or `gofmt`) +- Generate unit tests squeleton (using `gotests`) - Add Imports (using `gopkgs`) - [_partially implemented_] Debugging (using `delve`) @@ -98,6 +99,9 @@ In addition to integrated editing features, the extension also provides several * `Go: Run test at cursor` to run a test at the current cursor position in the active document * `Go: Run tests in current package` to run all tests in the package containing the active document * `Go: Run tests in current file` to run all tests in the current active document +* `Go: Generates unit tests (package)` Generates unit tests for the current package +* `Go: Generates unit tests (file)` Generates unit tests for the current file +* `Go: Generates unit tests (function)` Generates unit tests for the selected function in the current file ### _Optional_: Debugging @@ -200,6 +204,7 @@ The extension uses the following tools, installed in the current GOPATH. If any - gopkgs: `go get -u -v github.com/tpng/gopkgs` - go-symbols: `go get -u -v github.com/newhook/go-symbols` - guru: `go get -u -v golang.org/x/tools/cmd/guru` +- gotests: `go get -u -v github.com/cweill/gotests` To install them just paste and run: ```bash @@ -212,6 +217,7 @@ go get -u -v golang.org/x/tools/cmd/gorename go get -u -v github.com/tpng/gopkgs go get -u -v github.com/newhook/go-symbols go get -u -v golang.org/x/tools/cmd/guru +go get -u -v github.com/cweill/gotests ``` And for debugging: diff --git a/package.json b/package.json index 064d67ebf..f4fe0e5e2 100644 --- a/package.json +++ b/package.json @@ -101,6 +101,21 @@ "title": "Go: Test coverage in current package", "description": "Displays test coverage in the current package." }, + { + "command": "go.test.generate.package", + "title": "Go: Generates unit tests (package)", + "description": "Generates unit tests for the current package" + }, + { + "command": "go.test.generate.file", + "title": "Go: Generates unit tests (file)", + "description": "Generates unit tests for the current file" + }, + { + "command": "go.test.generate.function", + "title": "Go: Generates unit tests (function)", + "description": "Generates unit tests for the selected function in the current file" + }, { "command": "go.import.add", "title": "Go: Add Import", diff --git a/src/goInstallTools.ts b/src/goInstallTools.ts index 99aa4b9e6..1f1351a36 100644 --- a/src/goInstallTools.ts +++ b/src/goInstallTools.ts @@ -24,7 +24,8 @@ let tools: { [key: string]: string } = { 'go-symbols': 'github.com/newhook/go-symbols', 'guru': 'golang.org/x/tools/cmd/guru', 'gorename': 'golang.org/x/tools/cmd/gorename', - 'goimports': 'golang.org/x/tools/cmd/goimports' + 'goimports': 'golang.org/x/tools/cmd/goimports', + 'gotests': 'github.com/cweill/gotests' }; export function installAllTools() { diff --git a/src/goMain.ts b/src/goMain.ts index 30e24c8c3..7a3d866d4 100644 --- a/src/goMain.ts +++ b/src/goMain.ts @@ -24,6 +24,7 @@ import { updateGoPathGoRootFromConfig, setupGoPathAndOfferToInstallTools } from import { GO_MODE } from './goMode'; import { showHideStatus } from './goStatus'; import { coverageCurrentPackage, getCodeCoverage, removeCodeCoverage } from './goCover'; +import { generateTestCurrentPackage, generateTestCurrentFile, generateTestCurrentFunction } from './goTests'; import { testAtCursor, testCurrentPackage, testCurrentFile } from './goTest'; import { addImport } from './goImport'; import { installAllTools } from './goInstallTools'; @@ -88,6 +89,18 @@ export function activate(ctx: vscode.ExtensionContext): void { updateGoPathGoRootFromConfig(); })); + ctx.subscriptions.push(vscode.commands.registerCommand('go.test.generate.package', () => { + generateTestCurrentPackage(); + })); + + ctx.subscriptions.push(vscode.commands.registerCommand('go.test.generate.file', () => { + generateTestCurrentFile(); + })); + + ctx.subscriptions.push(vscode.commands.registerCommand('go.test.generate.function', () => { + generateTestCurrentFunction(); + })); + vscode.languages.setLanguageConfiguration(GO_MODE.language, { indentationRules: { // ^(.*\*/)?\s*\}.*$ diff --git a/src/goTests.ts b/src/goTests.ts new file mode 100644 index 000000000..19bcbf5f3 --- /dev/null +++ b/src/goTests.ts @@ -0,0 +1,113 @@ +/*--------------------------------------------------------- + * 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 cp = require('child_process'); +import path = require('path'); +import vscode = require('vscode'); +import util = require('util'); + +import { getBinPath } from './goPath'; +import { promptForMissingTool } from './goInstallTools'; +import { GoDocumentSymbolProvider } from './goOutline'; + +export function generateTestCurrentPackage() { + let editor = testEditor(); + let dir = path.dirname(editor.document.uri.fsPath); + generateTests({dir: dir}); + vscode.window.showInformationMessage('gotests: Unit tests generated for package:' + path.basename(dir)); +} + +export function generateTestCurrentFile() { + let editor = testEditor(); + let file = editor.document.uri.fsPath; + generateTests({dir: file}); + vscode.window.showInformationMessage('gotests: Unit tests generated for file:' + path.basename(file)); +} + +export function generateTestCurrentFunction() { + let editor = testEditor(); + let file = editor.document.uri.fsPath; + + getFunctions(editor.document).then(functions => { + let currentFunction: vscode.SymbolInformation; + for (let func of functions) { + let selection = editor.selection; + if (selection && func.location.range.contains(selection.start)) { + currentFunction = func; + break; + } + }; + if (!currentFunction) { + vscode.window.setStatusBarMessage('No function found at cursor.', 5000); + return; + } + generateTests({dir: file, func: currentFunction.name}); + vscode.window.showInformationMessage('gotests: Unit test generated for function: ' + currentFunction.name + ' in file:' + path.basename(file)); + }).then(null, err => { + console.error(err); + }); +} + +/** + * Input to goTests. + */ +interface Config { + /** + * The working directory for `gotests`. + */ + dir: string; + /** + * Specific function names to generate tests squeleton. + */ + func?: string; +} + +function generateTests(conf: Config): Thenable { + return new Promise((resolve, reject) => { + let cmd = getBinPath('gotests'); + let args; + if (conf.func) { + args = ['-w', '-only', conf.func, conf.dir]; + } else { + args = ['-w', '-all', conf.dir]; + } + cp.execFile(cmd, args, {}, (err, stdout, stderr) => { + try { + if (err && (err).code === 'ENOENT') { + promptForMissingTool('gotests'); + return resolve(null); + } + if (err) { + return reject('Cannot generate test due to errors: ' + stderr); + } + return resolve(new vscode.WorkspaceEdit()); + } catch (e) { + vscode.window.showInformationMessage(e.msg); + reject(e); + } + }); + }); +} + +function testEditor(): vscode.TextEditor { + let editor = vscode.window.activeTextEditor; + if (!editor) { + vscode.window.showInformationMessage('No editor is active.'); + return; + } + return editor; +} + +function getFunctions(doc: vscode.TextDocument): Thenable { + let documentSymbolProvider = new GoDocumentSymbolProvider(); + return documentSymbolProvider + .provideDocumentSymbols(doc, null) + .then(symbols => + symbols.filter(sym => + sym.kind === vscode.SymbolKind.Function) + ); +}