Issue
- go version: 1.13.5
複数のパッケージが同じ名前のフラグを定義している時、 go test -coverpkg=all ./...
のように -coverpkg
をつけて go test
すると、 flag redefined
でpanicする問題。
- cmd/go: test coverpkg panics when defining the same flag in multiple packages · Issue #27336 · golang/go
- Go 1.13 にアップデートするとテスト時に "flag provided but not defined" エラーが発生するケース - blog.syfm
$ go test -v -cover -coverpkg=all ./...
? _/Users/y-goto/dev/go/flag-for-test/cmd1 [no test files]
? _/Users/y-goto/dev/go/flag-for-test/cmd2 [no test files]
/var/folders/k7/2f4m6jwx6jjc2js45m62y9b00000gp/T/go-build687459203/b034/conf.test flag redefined: foo
panic: /var/folders/k7/2f4m6jwx6jjc2js45m62y9b00000gp/T/go-build687459203/b034/conf.test flag redefined: foo
TL;DR
とりあえず以下で避けられる。
-
init()
でのフラグパースを避ける -
flag.NewFlagSet
を使う
How to reproduce
- cmd1
- main.go // defines "foo" flag
- cmd2
- main.go // defines "foo" flag
- cfg
- conf_test.go // no-op _test
cmd1/main.go
package main
import (
"flag"
"fmt"
)
var foo = flag.String("foo", "", "flag foo")
func main() {
flag.Parse()
fmt.Println("foo", *foo)
}
cmd2/main.go
same as cmd1/main.go
cfg/conf_test.go
package conf
go test -coverpkg
$ go test -v -cover -coverpkg=all ./...
? _/Users/y-goto/dev/go/flag-for-test/cmd1 [no test files]
? _/Users/y-goto/dev/go/flag-for-test/cmd2 [no test files]
/var/folders/k7/2f4m6jwx6jjc2js45m62y9b00000gp/T/go-build687459203/b034/conf.test flag redefined: foo
panic: /var/folders/k7/2f4m6jwx6jjc2js45m62y9b00000gp/T/go-build687459203/b034/conf.test flag redefined: foo
goroutine 1 [running]:
flag.(*FlagSet).Var(0xc0000221e0, 0x11b58e0, 0xc0000523a0, 0x118c9d9, 0x3, 0x118d345, 0x8)
/usr/local/go/src/flag/flag.go:848 +0x521
flag.(*FlagSet).StringVar(0xc0000221e0, 0xc0000523a0, 0x118c9d9, 0x3, 0x0, 0x0, 0x118d345, 0x8)
/usr/local/go/src/flag/flag.go:751 +0x9e
flag.(*FlagSet).String(...)
/usr/local/go/src/flag/flag.go:764
flag.String(0x118c9d9, 0x3, 0x0, 0x0, 0x118d345, 0x8, 0xc000052390)
/usr/local/go/src/flag/flag.go:771 +0xab
_/Users/y-goto/dev/go/flag-for-test/cmd2.init()
/Users/y-goto/dev/go/flag-for-test/cmd2/main.go:9 +0x53
FAIL _/Users/y-goto/dev/go/flag-for-test/conf 0.227s
FAIL
"flag redefined: foo" と怒られる。
Workaround
どうも flag.CommandLine
(デフォルトのFlagSet) に同名のFlagをセットしているとして怒られているっぽい(go testの初期化ロジックが変わった影響?)。そこで、各パッケージで個別のFlagSetを作ってそこにフラグをセットするように変更した。あと init() でフラグをパースしてもダメなのでmain()でやってください。
package main
import (
"flag"
"fmt"
"os"
)
var (
command = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
foo = command.String("foo", "", "flag foo")
)
func main() {
command.Parse(os.Args[1:])
fmt.Println("foo", *foo)
}