x/tools/gopls: incorrect varargs handling for add test action
What version of Go are you using (go version)?
$ go version go version go1.25.5 darwin/arm64
Does this issue reproduce with the latest release?
Yes, I checked with: golang.org/x/tools/gopls v0.20.0
What operating system and processor architecture are you using (go env)?
go env Output
$ go env AR='ar' CC='cc' CGO_CFLAGS='-O2 -g' CGO_CPPFLAGS='' CGO_CXXFLAGS='-O2 -g' CGO_ENABLED='1' CGO_FFLAGS='-O2 -g' CGO_LDFLAGS='-O2 -g' CXX='c++' GCCGO='gccgo' GO111MODULE='on' GOARCH='arm64' GOARM64='v8.0' GOAUTH='netrc' GOBIN='' GOCACHE='/Users/ilyasyoy/Library/Caches/go-build' GOCACHEPROG='' GODEBUG='' GOENV='/Users/ilyasyoy/Library/Application Support/go/env' GOEXE='' GOEXPERIMENT='' GOFIPS140='off' GOFLAGS='' GOGCCFLAGS='-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -ffile-prefix-map=/var/folders/f2/s841xw414zqfscfkvn76cfv40000gn/T/go-build1666804876=/tmp/go-build -gno-record-gcc-switches -fno-common' GOHOSTARCH='arm64' GOHOSTOS='darwin' GOINSECURE='' GOMOD='/Users/ilyasyoy/Projects/IlyasYOY/experiments/varargs-generate-test-gopls/go.mod' GOMODCACHE='/Users/ilyasyoy/go/pkg/mod' GONOPROXY='' GONOSUMDB='' GOOS='darwin' GOPATH='/Users/ilyasyoy/go' GOPRIVATE='' GOPROXY='direct' GOROOT='/opt/homebrew/Cellar/go/1.25.5/libexec' GOSUMDB='off' GOTELEMETRY='local' GOTELEMETRYDIR='/Users/ilyasyoy/Library/Application Support/go/telemetry' GOTMPDIR='' GOTOOLCHAIN='auto' GOTOOLDIR='/opt/homebrew/Cellar/go/1.25.5/libexec/pkg/tool/darwin_arm64' GOVCS='' GOVERSION='go1.25.5' GOWORK='' PKG_CONFIG='pkg-config' uname -v: Darwin Kernel Version 25.1.0: Mon Oct 20 19:34:03 PDT 2025; root:xnu-12377.41.6~2/RELEASE_ARM64_T8112 ProductName: macOS ProductVersion: 26.1 BuildVersion: 25B78 lldb --version: lldb-1703.0.234.3 Apple Swift version 6.2.1 (swiftlang-6.2.1.4.8 clang-1700.4.4.1)
What did you do?
- created a file with the code:
package varargsgeneratetestgopls
import (
"fmt"
"strings"
)
func VarArgsFunc(args ...string) string {
joined := strings.Join(args, ", ")
return fmt.Sprintf("VarArgsFunc: %s", joined)
}
- called the add test action.
What did you expect to see?
func TestVarArgsFunc(t *testing.T) {
tests := []struct {
name string // description of this test case
// Named input parameters for target function.
args []string
want string
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := varargsgeneratetestgopls.VarArgsFunc(tt.args...)
// TODO: update the condition below to compare got with tt.want.
if true {
t.Errorf("VarArgsFunc() = %v, want %v", got, tt.want)
}
})
}
}
What did you see instead?
I've got the test with syntax error:
package varargsgeneratetestgopls_test
import (
"testing"
"github.com/IlyasYOY/varargs-generate-test-gopls"
)
func TestVarArgsFunc(t *testing.T) {
tests := []struct {
name string // description of this test case
// Named input parameters for target function.
args []string
want string
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := varargsgeneratetestgopls.VarArgsFunc(tt.args) // <- error here, must be: tt.args...
// TODO: update the condition below to compare got with tt.want.
if true {
t.Errorf("VarArgsFunc() = %v, want %v", got, tt.want)
}
})
}
}
I'd be glad to provide the fix for this case. Maybe there are caveats that I need to know in advance, or I can proceed straight to solving the issue?
Related Issues
- x/tools/gopls: "Split arguments into separate lines" loses variadic ellipsis #70519 (closed)
- x/tools/gopls: panic in stubmethods with variadic args #61693 (closed)
- x/tools/gopls: Extract Function refactor doesn't put testing.T/B first #69341 (closed)
(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)
cc: @h9jiang. See golang/vscode-go#1594 for original feature issue.
Thanks for reporting this, I did no catch this in the first place. Really appreciate it!
Most of the code generation is defined in addtest.go.
Particularly, we go through the function signature and figure out each input parameter's type at line 489. While going through the input parameters, we realize the input parameter is type []string.
So we need to handle it as a special case. We need to figure out whether the last input parameter is a purely []string or a []string which is actually sig.Variadic(). The piece of information is not available when we traverse through the input parameters but available from function signature level.
To make this work, we need to have a CL to read the info Variadic, add a special value to the function
type function struct {
Name string
Args []field
Results []field
+ isVariadic bool
}
When generating the function call
{{- /* Input parameters. */ -}}
(
{{- range $index, $arg := .Func.Args}}
{{- if ne $index 0}}, {{end}}
{{- if .Name}}tt.{{.Name}}{{else}}{{.Value}}{{end}}
{{- end -}}
+ // insert "..." if the function is variadic
)
To make it more comprehensive, you should also do the same for the constructor.
Thank you so much. If you are interested, feel free to draft a CL to us and we will review!
@h9jiang Hello! Thank you for the valuable advice. I prepared the changes and I'll open a PR soon.
UPD. Opened up a PR: https://github.com/golang/tools/pull/609
A little bit off‑topic here. As a heavy user of TDD I am a big fan of black‑box testing and I really appreciate that gopls encourages it.
I have a Draft PR in gotests that implements it: https://github.com/cweill/gotests/pull/199. I've been missing it a lot.
It is not my original idea but I hope this would be shared here in case it helps.
Writing test for un-exported functions increase the test coverages but sometimes is not convenient for contributions. Imagine a contributor notice a bug and is willing to fix it for you, a single line of change could result in 10+ small test case changes.
Test only the exported function or test only the E2E behavior would encourage such contribution. gopls will prefer generating test function using foo_test package as much as possible.
Change https://go.dev/cl/727280 mentions this issue: gopls/internal/golang: add support for variadic functions and constructors in generated tests