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>
diff --git a/extension/src/goImpl.ts b/extension/src/goImpl.ts index 2a11d3b..b569211 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') { - void 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 066e80b..824939d 100644 --- a/extension/test/gopls/interactive.test.ts +++ b/extension/test/gopls/interactive.test.ts
@@ -10,6 +10,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 () { @@ -135,6 +136,10 @@ test('Add struct tags via addTags', 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('json,xml'); @@ -146,4 +151,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 81fe64d..ae568d0 100644 --- a/extension/tools/installtools/main.go +++ b/extension/tools/installtools/main.go
@@ -37,6 +37,8 @@ {"honnef.co/go/tools/cmd/staticcheck", "", false, ""}, // For regression test: golang/vscode-go#3511 {"github.com/golangci/golangci-lint/v2/cmd/golangci-lint", "golangci-lint-v2", false, "v2.12.2"}, + // TODO(hxjiang): remove from test environment later. + {"github.com/josharian/impl", "", false, "v1.5.0"}, {"github.com/go-delve/delve/cmd/dlv", "", false, ""}, }