Commit ba8ff87d authored by Brandon Bennett's avatar Brandon Bennett Committed by Marcel van Lohuizen

testing: add argument to list tests, benchmarks, and examples

Some large testing/build systems require some form of test discovery before
running tests.  This usually allows for analytics, history, and stats on a per
tests basis.  Typically these systems are meant used in multi-language
environments and the original source code is not known or available.

This adds a -test.list option which takes a regular expression as an
argument. Any tests, benchmarks, or examples that match that regular
expression will be printed, one per line, to stdout and then the program
will exit.

Since subtests are named/discovered at run time this will only show
top-level tests names and is a known limitation.

Fixes #17209

Change-Id: I7e607f5f4f084d623a1cae88a1f70e7d92b7f13e
Reviewed-on: https://go-review.googlesource.com/41195Reviewed-by: default avatarMarcel van Lohuizen <mpvl@golang.org>
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 6e2c4bc0
...@@ -184,6 +184,11 @@ const testFlag2 = ` ...@@ -184,6 +184,11 @@ const testFlag2 = `
benchmarks should be executed. The default is the current value benchmarks should be executed. The default is the current value
of GOMAXPROCS. of GOMAXPROCS.
-list regexp
List tests, benchmarks, or examples matching the regular expression.
No tests, benchmarks or examples will be run. This will only
list top-level tests. No subtest or subbenchmarks will be shown.
-parallel n -parallel n
Allow parallel execution of test functions that call t.Parallel. Allow parallel execution of test functions that call t.Parallel.
The value of this flag is the maximum number of tests to run The value of this flag is the maximum number of tests to run
...@@ -400,6 +405,7 @@ var ( ...@@ -400,6 +405,7 @@ var (
testTimeout string // -timeout flag testTimeout string // -timeout flag
testArgs []string testArgs []string
testBench bool testBench bool
testList bool
testStreamOutput bool // show output as it is generated testStreamOutput bool // show output as it is generated
testShowPass bool // show passing output testShowPass bool // show passing output
...@@ -447,7 +453,7 @@ func runTest(cmd *base.Command, args []string) { ...@@ -447,7 +453,7 @@ func runTest(cmd *base.Command, args []string) {
// show passing test output (after buffering) with -v flag. // show passing test output (after buffering) with -v flag.
// must buffer because tests are running in parallel, and // must buffer because tests are running in parallel, and
// otherwise the output will get mixed. // otherwise the output will get mixed.
testShowPass = testV testShowPass = testV || testList
// stream test output (no buffering) when no package has // stream test output (no buffering) when no package has
// been given on the command line (implicit current directory) // been given on the command line (implicit current directory)
......
...@@ -42,6 +42,7 @@ var testFlagDefn = []*cmdflag.Defn{ ...@@ -42,6 +42,7 @@ var testFlagDefn = []*cmdflag.Defn{
{Name: "coverprofile", PassToTest: true}, {Name: "coverprofile", PassToTest: true},
{Name: "cpu", PassToTest: true}, {Name: "cpu", PassToTest: true},
{Name: "cpuprofile", PassToTest: true}, {Name: "cpuprofile", PassToTest: true},
{Name: "list", PassToTest: true},
{Name: "memprofile", PassToTest: true}, {Name: "memprofile", PassToTest: true},
{Name: "memprofilerate", PassToTest: true}, {Name: "memprofilerate", PassToTest: true},
{Name: "blockprofile", PassToTest: true}, {Name: "blockprofile", PassToTest: true},
...@@ -145,6 +146,8 @@ func testFlags(args []string) (packageNames, passToTest []string) { ...@@ -145,6 +146,8 @@ func testFlags(args []string) (packageNames, passToTest []string) {
case "bench": case "bench":
// record that we saw the flag; don't care about the value // record that we saw the flag; don't care about the value
testBench = true testBench = true
case "list":
testList = true
case "timeout": case "timeout":
testTimeout = value testTimeout = value
case "blockprofile", "cpuprofile", "memprofile", "mutexprofile": case "blockprofile", "cpuprofile", "memprofile", "mutexprofile":
......
...@@ -252,6 +252,7 @@ var ( ...@@ -252,6 +252,7 @@ var (
chatty = flag.Bool("test.v", false, "verbose: print additional output") chatty = flag.Bool("test.v", false, "verbose: print additional output")
count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times") count = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`") coverProfile = flag.String("test.coverprofile", "", "write a coverage profile to `file`")
matchList = flag.String("test.list", "", "list tests, examples, and benchmarch maching `regexp` then exit")
match = flag.String("test.run", "", "run only tests and examples matching `regexp`") match = flag.String("test.run", "", "run only tests and examples matching `regexp`")
memProfile = flag.String("test.memprofile", "", "write a memory profile to `file`") memProfile = flag.String("test.memprofile", "", "write a memory profile to `file`")
memProfileRate = flag.Int("test.memprofilerate", 0, "set memory profiling `rate` (see runtime.MemProfileRate)") memProfileRate = flag.Int("test.memprofilerate", 0, "set memory profiling `rate` (see runtime.MemProfileRate)")
...@@ -907,6 +908,11 @@ func (m *M) Run() int { ...@@ -907,6 +908,11 @@ func (m *M) Run() int {
flag.Parse() flag.Parse()
} }
if len(*matchList) != 0 {
listTests(m.deps.MatchString, m.tests, m.benchmarks, m.examples)
return 0
}
parseCpuList() parseCpuList()
m.before() m.before()
...@@ -946,6 +952,29 @@ func (t *T) report() { ...@@ -946,6 +952,29 @@ func (t *T) report() {
} }
} }
func listTests(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
if _, err := matchString(*matchList, "non-empty"); err != nil {
fmt.Fprintf(os.Stderr, "testing: invalid regexp in -test.list (%q): %s\n", *matchList, err)
os.Exit(1)
}
for _, test := range tests {
if ok, _ := matchString(*matchList, test.Name); ok {
fmt.Println(test.Name)
}
}
for _, bench := range benchmarks {
if ok, _ := matchString(*matchList, bench.Name); ok {
fmt.Println(bench.Name)
}
}
for _, example := range examples {
if ok, _ := matchString(*matchList, example.Name); ok && example.Output != "" {
fmt.Println(example.Name)
}
}
}
// An internal function but exported because it is cross-package; part of the implementation // An internal function but exported because it is cross-package; part of the implementation
// of the "go test" command. // of the "go test" command.
func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) { func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment