[release-v0.56] extension/test/gopls: add implement interface test Make vscode command "go.impl.cursor" await the completion of the document edit before resolving. This test is testing the behavior for the vscode command execution using the third party tool impl. The test is added to make sure the behavior remain mostly the same before and after the future change. For golang/vscode-go#4063 Change-Id: Ib1d8c40c92ce878c35ec153dfbe1aa06ef8c8a36 Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/815540 Auto-Submit: Hongxiang Jiang <hxjiang@golang.org> LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Madeline Kalil <mkalil@google.com> (cherry picked from commit 0264783fd77c2a59aa8a0f149c45cf3ce0c0ce35) Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/820340
diff --git a/extension/src/goImpl.ts b/extension/src/goImpl.ts index 61ac926..576bf83 100644 --- a/extension/src/goImpl.ts +++ b/extension/src/goImpl.ts
@@ -18,6 +18,8 @@ // Supports only passing interface, see TODO in implCursor to finish const inputRegex = /^(\w+\ \*?\w+\ )?([\w\.\-\/]+)$/; +// implCursor generates method stubs for implementing the provided interface +// based on the type defined at cursor. export const implCursor: CommandFactory = () => () => { const editor = vscode.window.activeTextEditor; if (!editor) { @@ -44,33 +46,40 @@ // if matches[1] is undefined then detect receiver type // take first character and use as receiver name - runGoImpl([matches[1], matches[2]], cursor.start, editor); + return runGoImpl([matches[1], matches[2]], cursor.start, editor); }); }; -function runGoImpl(args: string[], insertPos: vscode.Position, editor: vscode.TextEditor) { - const goimpl = getBinPath('impl'); - const p = cp.execFile( - goimpl, - args, - { env: toolExecutionEnvironment(), cwd: dirname(editor.document.fileName) }, - (err, stdout, stderr) => { - if (err && (<any>err).code === 'ENOENT') { - promptForMissingTool('impl'); - return; - } +function runGoImpl(args: string[], insertPos: vscode.Position, editor: vscode.TextEditor): Promise<void> { + return new Promise((resolve) => { + const goimpl = getBinPath('impl'); + const p = cp.execFile( + goimpl, + args, + { env: toolExecutionEnvironment(), cwd: dirname(editor.document.fileName) }, + (err, stdout, stderr) => { + if (err && (<any>err).code === 'ENOENT') { + void promptForMissingTool('impl'); + return resolve(); + } - if (err) { - vscode.window.showInformationMessage(`Cannot stub interface: ${stderr}`); - return; - } + if (err) { + vscode.window.showInformationMessage(`Cannot stub interface: ${stderr}`); + return resolve(); + } - editor.edit((editBuilder) => { - editBuilder.insert(insertPos, stdout); - }); + editor + .edit((editBuilder) => { + editBuilder.insert(insertPos, stdout); + }) + .then( + () => resolve(), + () => resolve() + ); + } + ); + if (p.pid) { + p.stdin?.end(); } - ); - if (p.pid) { - p.stdin?.end(); - } + }); }
diff --git a/extension/test/gopls/interactive.test.ts b/extension/test/gopls/interactive.test.ts index bf7e62e..2f738f4 100644 --- a/extension/test/gopls/interactive.test.ts +++ b/extension/test/gopls/interactive.test.ts
@@ -11,6 +11,7 @@ import { Env } from './goplsTestEnv.utils'; import { updateGoVarsFromConfig } from '../../src/goInstallTools'; import { addTags } from '../../src/goModifytags'; +import { implCursor } from '../../src/goImpl'; import { MockExtensionContext } from '../mocks/MockContext'; suite('Interactive Refactoring', function () { @@ -147,4 +148,24 @@ assert.match(docText, /Foo string `json:"foo,omitempty" xml:"foo"`/); ctx.teardown(); }); + + test('Implement interface via implCursor', async () => { + const ctx = MockExtensionContext.new(); + const editor = await vscode.window.showTextDocument(document); + + // type Foo struct { + // Foo string //@loc(editor.selection, "Foo string") + // } + editor.selection = new vscode.Selection(3, 1, 3, 11); + + sandbox.stub(vscode.window, 'showInputBox').resolves('f *Foo net.Error'); + + await implCursor(ctx, env.goCtx)(); + + const docText = document.getText(); + assert.match(docText, /func \(f \*Foo\) Error\(\) string/); + assert.match(docText, /func \(f \*Foo\) Temporary\(\) bool/); + assert.match(docText, /func \(f \*Foo\) Timeout\(\) bool/); + ctx.teardown(); + }); });
diff --git a/extension/tools/installtools/main.go b/extension/tools/installtools/main.go index f954817..cdb41db 100644 --- a/extension/tools/installtools/main.go +++ b/extension/tools/installtools/main.go
@@ -34,19 +34,16 @@ path string dest string preferPreview bool - // versions is a list of supportedVersions sorted by - // goMinorVersion. If we want to pin a tool's version - // add a fake entry with a large goMinorVersion - // value and the pinned tool version as the last entry. - // Nil of empty list indicates we can use the `latest` version. - versions []finalVersion + version string // pinned version, or empty string to use "latest" (or preview if preferPreview) }{ // TODO: auto-generate based on allTools.ts.in. - {"golang.org/x/tools/gopls", "", true, nil}, - {"github.com/cweill/gotests/gotests", "", false, nil}, - {"github.com/haya14busa/goplay/cmd/goplay", "", false, nil}, - {"honnef.co/go/tools/cmd/staticcheck", "", false, []finalVersion{{21, "v0.4.7"}}}, - {"github.com/go-delve/delve/cmd/dlv", "", false, nil}, + {"golang.org/x/tools/gopls", "", true, ""}, + {"github.com/cweill/gotests/gotests", "", false, ""}, + {"github.com/haya14busa/goplay/cmd/goplay", "", false, ""}, + {"honnef.co/go/tools/cmd/staticcheck", "", false, ""}, + // TODO(hxjiang): remove from test environment later. + {"github.com/josharian/impl", "", false, "v1.5.0"}, + {"github.com/go-delve/delve/cmd/dlv", "", false, ""}, } // pickVersion returns the version to install based on the supported @@ -134,7 +131,10 @@ // For tools installation, ensure GOTOOLCHAIN=auto. env := append(os.Environ(), "GO111MODULE=on", "GOTOOLCHAIN=auto") for _, tool := range tools { - ver := pickVersion(goMinorVersion, tool.versions, pickLatest(tool.path, tool.preferPreview)) + ver := tool.version + if ver == "" { + ver = pickLatest(tool.path, tool.preferPreview) + } path := tool.path + "@" + ver cmd := exec.Command("go", installCmd, path) cmd.Env = env