merge trunk;
diff --git a/.bzrignore b/.bzrignore
index 340cde7..e39772e 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -1,2 +1,3 @@
_*
[856].out
+[856].out.exe
diff --git a/LICENSE b/LICENSE
index d106fac..545cf2d 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,29 +1,25 @@
Gocheck - A rich testing framework for Go
-
-Copyright (c) 2010, Gustavo Niemeyer <gustavo@niemeyer.net>
+
+Copyright (c) 2010-2013 Gustavo Niemeyer <gustavo@niemeyer.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
+modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimer in the documentation
- and/or other materials provided with the distribution.
- * Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/benchmark.go b/benchmark.go
index 58fc41a..dcd426f 100644
--- a/benchmark.go
+++ b/benchmark.go
@@ -6,8 +6,6 @@
import (
"fmt"
- "reflect"
- "runtime"
"time"
)
@@ -136,41 +134,3 @@
}
return 10 * base
}
-
-// benchmarkN runs a single benchmark for the specified number of iterations.
-func benchmarkN(c *C, n int) {
- // Try to get a comparable environment for each run
- // by clearing garbage from previous runs.
- runtime.GC()
- c.N = n
- c.ResetTimer()
- c.StartTimer()
- c.method.Call([]reflect.Value{reflect.ValueOf(c)})
- c.StopTimer()
-}
-
-// benchmark runs the benchmark function. It gradually increases the number
-// of benchmark iterations until the benchmark runs for a second in order
-// to get a reasonable measurement.
-func benchmark(c *C) {
- // Run the benchmark for a single iteration in case it's expensive.
- n := 1
- benchmarkN(c, n)
- // Run the benchmark for at least the specified amount of time.
- for c.status == succeededSt && c.duration < c.benchTime && n < 1e9 {
- last := n
- // Predict iterations/sec.
- if c.nsPerOp() == 0 {
- n = 1e9
- } else {
- n = int(c.benchTime.Nanoseconds() / c.nsPerOp())
- }
- // Run more iterations than we think we'll need for a second (1.5x).
- // Don't grow too fast in case we had timing errors previously.
- // Be sure to run at least one more than last time.
- n = max(min(n+n/2, 100*last), last+1)
- // Round up to something easy to read.
- n = roundUp(n)
- benchmarkN(c, n)
- }
-}
diff --git a/benchmark_test.go b/benchmark_test.go
index ed6a8fa..336243f 100644
--- a/benchmark_test.go
+++ b/benchmark_test.go
@@ -36,8 +36,6 @@
c.Assert(output.value, Matches, expected)
}
-// Quite unfortunate that these two tests alone account for most of the
-
func (s *BenchmarkS) TestBenchmark(c *C) {
helper := FixtureHelper{sleep: 100000}
output := String{}
@@ -48,6 +46,14 @@
Filter: "Benchmark1",
}
Run(&helper, &runConf)
+ c.Check(helper.calls[0], Equals, "SetUpSuite")
+ c.Check(helper.calls[1], Equals, "SetUpTest")
+ c.Check(helper.calls[2], Equals, "Benchmark1")
+ c.Check(helper.calls[3], Equals, "TearDownTest")
+ c.Check(helper.calls[4], Equals, "SetUpTest")
+ c.Check(helper.calls[5], Equals, "Benchmark1")
+ c.Check(helper.calls[6], Equals, "TearDownTest")
+ // ... and more.
expected := "PASS: gocheck_test\\.go:[0-9]+: FixtureHelper\\.Benchmark1\t *100\t *[12][0-9]{5} ns/op\n"
c.Assert(output.value, Matches, expected)
diff --git a/fixture_test.go b/fixture_test.go
index cd66118..63f392e 100644
--- a/fixture_test.go
+++ b/fixture_test.go
@@ -31,7 +31,7 @@
c.Check(helper.calls[5], Equals, "Test2")
c.Check(helper.calls[6], Equals, "TearDownTest")
c.Check(helper.calls[7], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 8)
+ c.Check(len(helper.calls), Equals, 8)
}
// -----------------------------------------------------------------------
@@ -49,7 +49,7 @@
c.Check(helper.calls[5], Equals, "Test2")
c.Check(helper.calls[6], Equals, "TearDownTest")
c.Check(helper.calls[7], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 8)
+ c.Check(len(helper.calls), Equals, 8)
expected := "^\n-+\n" +
"PANIC: gocheck_test\\.go:[0-9]+: FixtureHelper.Test1\n\n" +
@@ -72,7 +72,7 @@
c.Check(helper.calls[1], Equals, "SetUpTest")
c.Check(helper.calls[2], Equals, "TearDownTest")
c.Check(helper.calls[3], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 4)
+ c.Check(len(helper.calls), Equals, 4)
expected := "^\n-+\n" +
"PANIC: gocheck_test\\.go:[0-9]+: " +
@@ -102,7 +102,7 @@
c.Check(helper.calls[2], Equals, "Test1")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 5)
+ c.Check(len(helper.calls), Equals, 5)
expected := "^\n-+\n" +
"PANIC: gocheck_test\\.go:[0-9]+: " +
@@ -129,7 +129,7 @@
Run(&helper, &RunConf{Output: &output})
c.Check(helper.calls[0], Equals, "SetUpSuite")
c.Check(helper.calls[1], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 2)
+ c.Check(len(helper.calls), Equals, 2)
expected := "^\n-+\n" +
"PANIC: gocheck_test\\.go:[0-9]+: " +
@@ -157,7 +157,7 @@
c.Check(helper.calls[5], Equals, "Test2")
c.Check(helper.calls[6], Equals, "TearDownTest")
c.Check(helper.calls[7], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 8)
+ c.Check(len(helper.calls), Equals, 8)
expected := "^\n-+\n" +
"PANIC: gocheck_test\\.go:[0-9]+: " +
@@ -187,7 +187,7 @@
c.Check(helper.calls[4], Equals, "Test2")
c.Check(helper.calls[5], Equals, "TearDownTest")
c.Check(helper.calls[6], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 7)
+ c.Check(len(helper.calls), Equals, 7)
expected := "^\n-+\n" +
"PANIC: fixture_test\\.go:[0-9]+: " +
@@ -202,7 +202,7 @@
helper := WrongSetUpTestArgHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
- c.Check(helper.n, Equals, 0)
+ c.Check(len(helper.calls), Equals, 0)
expected :=
"^\n-+\n" +
@@ -218,7 +218,7 @@
helper := WrongSetUpSuiteArgHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
- c.Check(helper.n, Equals, 0)
+ c.Check(len(helper.calls), Equals, 0)
expected :=
"^\n-+\n" +
@@ -244,7 +244,7 @@
c.Check(helper.calls[4], Equals, "Test2")
c.Check(helper.calls[5], Equals, "TearDownTest")
c.Check(helper.calls[6], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 7)
+ c.Check(len(helper.calls), Equals, 7)
expected := "^\n-+\n" +
"PANIC: fixture_test\\.go:[0-9]+: " +
@@ -259,7 +259,7 @@
helper := WrongSetUpTestArgCountHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
- c.Check(helper.n, Equals, 0)
+ c.Check(len(helper.calls), Equals, 0)
expected :=
"^\n-+\n" +
@@ -275,7 +275,7 @@
helper := WrongSetUpSuiteArgCountHelper{}
output := String{}
Run(&helper, &RunConf{Output: &output})
- c.Check(helper.n, Equals, 0)
+ c.Check(len(helper.calls), Equals, 0)
expected :=
"^\n-+\n" +
@@ -460,7 +460,7 @@
c.Assert(output.value, Equals, "")
c.Assert(helper.calls[0], Equals, "SetUpSuite")
c.Assert(helper.calls[1], Equals, "TearDownSuite")
- c.Assert(helper.n, Equals, 2)
+ c.Assert(len(helper.calls), Equals, 2)
c.Assert(result.Skipped, Equals, 2)
}
@@ -474,6 +474,6 @@
c.Assert(helper.calls[3], Equals, "Test2")
c.Assert(helper.calls[4], Equals, "TearDownTest")
c.Assert(helper.calls[5], Equals, "TearDownSuite")
- c.Assert(helper.n, Equals, 6)
+ c.Assert(len(helper.calls), Equals, 6)
c.Assert(result.Skipped, Equals, 1)
}
diff --git a/gocheck.go b/gocheck.go
index e5403ac..90ad97e 100644
--- a/gocheck.go
+++ b/gocheck.go
@@ -53,11 +53,29 @@
return method.Info.Func.Pointer()
}
+func (method *methodType) suiteName() string {
+ t := method.Info.Type.In(0)
+ if t.Kind() == reflect.Ptr {
+ t = t.Elem()
+ }
+ return t.Name()
+}
+
+func (method *methodType) String() string {
+ return method.suiteName()+"."+method.Info.Name
+}
+
+func (method *methodType) matches(re *regexp.Regexp) bool {
+ return (re.MatchString(method.Info.Name) ||
+ re.MatchString(method.suiteName()) ||
+ re.MatchString(method.String()))
+}
+
type C struct {
method *methodType
kind funcKind
status funcStatus
- logb *bytes.Buffer
+ logb *logger
logw io.Writer
done chan *C
reason string
@@ -71,6 +89,30 @@
runtime.Goexit()
}
+// logger is a concurrency safe byte.Buffer
+type logger struct {
+ sync.Mutex
+ writer bytes.Buffer
+}
+
+func (l *logger) Write(buf []byte) (int, error) {
+ l.Lock()
+ defer l.Unlock()
+ return l.writer.Write(buf)
+}
+
+func (l *logger) WriteTo(w io.Writer) (int64, error) {
+ l.Lock()
+ defer l.Unlock()
+ return l.writer.WriteTo(w)
+}
+
+func (l *logger) String() string {
+ l.Lock()
+ defer l.Unlock()
+ return l.writer.String()
+}
+
// -----------------------------------------------------------------------
// Handling of temporary files and directories.
@@ -294,10 +336,16 @@
var initWD, initWDErr = os.Getwd()
+func init() {
+ if initWDErr == nil {
+ initWD = strings.Replace(initWD, "\\", "/", -1) + "/"
+ }
+}
+
func nicePath(path string) string {
if initWDErr == nil {
- if strings.HasPrefix(path, initWD+"/") {
- return path[len(initWD)+1:]
+ if strings.HasPrefix(path, initWD) {
+ return path[len(initWD):]
}
}
return path
@@ -499,24 +547,8 @@
}
}
- // This map will be used to filter out duplicated methods. This
- // looks like a bug in Go, described on issue 906:
- // http://code.google.com/p/go/issues/detail?id=906
- seen := make(map[uintptr]bool, suiteNumMethods)
-
- // XXX Shouldn't Name() work here? Why does it return an empty string?
- suiteName := suiteType.String()
- if index := strings.LastIndex(suiteName, "."); index != -1 {
- suiteName = suiteName[index+1:]
- }
-
for i := 0; i != suiteNumMethods; i++ {
method := newMethod(suiteValue, i)
- methodPC := method.PC()
- if _, found := seen[methodPC]; found {
- continue
- }
- seen[methodPC] = true
switch method.Info.Name {
case "SetUpSuite":
runner.setUpSuite = method
@@ -527,7 +559,14 @@
case "TearDownTest":
runner.tearDownTest = method
default:
- if isWanted(conf.Benchmark, suiteName, method.Info.Name, filterRegexp) {
+ prefix := "Test"
+ if conf.Benchmark {
+ prefix = "Benchmark"
+ }
+ if !strings.HasPrefix(method.Info.Name, prefix) {
+ continue
+ }
+ if filterRegexp == nil || method.matches(filterRegexp) {
runner.tests = append(runner.tests, method)
}
}
@@ -535,25 +574,6 @@
return runner
}
-// isWanted returns true if the given suite and method names should be run.
-// The bench result indicates whether the method is a benchmark rather than
-// a test.
-func isWanted(benchmark bool, suiteName, methodName string, filterRegexp *regexp.Regexp) bool {
- prefix := "Test"
- if benchmark {
- prefix = "Benchmark"
- }
- if !strings.HasPrefix(methodName, prefix) {
- return false
- }
- if filterRegexp == nil {
- return true
- }
- return (filterRegexp.MatchString(methodName) ||
- filterRegexp.MatchString(suiteName) ||
- filterRegexp.MatchString(suiteName+"."+methodName))
-}
-
// Run all methods in the given suite.
func (runner *suiteRunner) run() *Result {
if runner.tracker.result.RunError == nil && len(runner.tests) > 0 {
@@ -585,13 +605,13 @@
// Create a call object with the given suite method, and fork a
// goroutine with the provided dispatcher for running it.
-func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, logb *bytes.Buffer, dispatcher func(c *C)) *C {
+func (runner *suiteRunner) forkCall(method *methodType, kind funcKind, logb *logger, dispatcher func(c *C)) *C {
var logw io.Writer
if runner.output.Stream {
logw = runner.output
}
if logb == nil {
- logb = bytes.NewBuffer(nil)
+ logb = new(logger)
}
c := &C{
method: method,
@@ -613,7 +633,7 @@
}
// Same as forkCall(), but wait for call to finish before returning.
-func (runner *suiteRunner) runFunc(method *methodType, kind funcKind, logb *bytes.Buffer, dispatcher func(c *C)) *C {
+func (runner *suiteRunner) runFunc(method *methodType, kind funcKind, logb *logger, dispatcher func(c *C)) *C {
c := runner.forkCall(method, kind, logb, dispatcher)
<-c.done
return c
@@ -656,7 +676,7 @@
// goroutine like all suite methods, but this method will not return
// while the fixture goroutine is not done, because the fixture must be
// run in a desired order.
-func (runner *suiteRunner) runFixture(method *methodType, logb *bytes.Buffer) *C {
+func (runner *suiteRunner) runFixture(method *methodType, logb *logger) *C {
if method != nil {
c := runner.runFunc(method, fixtureKd, logb, func(c *C) {
c.ResetTimer()
@@ -672,13 +692,15 @@
// Run the fixture method with runFixture(), but panic with a fixturePanic{}
// in case the fixture method panics. This makes it easier to track the
// fixture panic together with other call panics within forkTest().
-func (runner *suiteRunner) runFixtureWithPanic(method *methodType, logb *bytes.Buffer, skipped *bool) *C {
- if *skipped {
+func (runner *suiteRunner) runFixtureWithPanic(method *methodType, logb *logger, skipped *bool) *C {
+ if skipped != nil && *skipped {
return nil
}
c := runner.runFixture(method, logb)
if c != nil && c.status != succeededSt {
- *skipped = c.status == skippedSt
+ if skipped != nil {
+ *skipped = c.status == skippedSt
+ }
panic(&fixturePanic{c.status, method})
}
return c
@@ -695,27 +717,53 @@
return runner.forkCall(method, testKd, nil, func(c *C) {
var skipped bool
defer runner.runFixtureWithPanic(runner.tearDownTest, nil, &skipped)
- runner.runFixtureWithPanic(runner.setUpTest, c.logb, &skipped)
- mt := c.method.Type()
- if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) {
- // Rather than a plain panic, provide a more helpful message when
- // the argument type is incorrect.
- c.status = panickedSt
- c.logArgPanic(c.method, "*gocheck.C")
- return
- }
- if strings.HasPrefix(c.method.Info.Name, "Test") {
+ defer c.StopTimer()
+ benchN := 1
+ for {
+ runner.runFixtureWithPanic(runner.setUpTest, c.logb, &skipped)
+ mt := c.method.Type()
+ if mt.NumIn() != 1 || mt.In(0) != reflect.TypeOf(c) {
+ // Rather than a plain panic, provide a more helpful message when
+ // the argument type is incorrect.
+ c.status = panickedSt
+ c.logArgPanic(c.method, "*gocheck.C")
+ return
+ }
+ if strings.HasPrefix(c.method.Info.Name, "Test") {
+ c.ResetTimer()
+ c.StartTimer()
+ c.method.Call([]reflect.Value{reflect.ValueOf(c)})
+ return
+ }
+ if !strings.HasPrefix(c.method.Info.Name, "Benchmark") {
+ panic("unexpected method prefix: " + c.method.Info.Name)
+ }
+
+ runtime.GC()
+ c.N = benchN
c.ResetTimer()
c.StartTimer()
- defer c.StopTimer()
c.method.Call([]reflect.Value{reflect.ValueOf(c)})
- return
+ c.StopTimer()
+ if c.status != succeededSt || c.duration >= c.benchTime || benchN >= 1e9 {
+ return
+ }
+ perOpN := int(1e9)
+ if c.nsPerOp() != 0 {
+ perOpN = int(c.benchTime.Nanoseconds() / c.nsPerOp())
+ }
+
+ // Logic taken from the stock testing package:
+ // - Run more iterations than we think we'll need for a second (1.5x).
+ // - Don't grow too fast in case we had timing errors previously.
+ // - Be sure to run at least one more than last time.
+ benchN = max(min(perOpN+perOpN/2, 100*benchN), benchN+1)
+ benchN = roundUp(benchN)
+
+ skipped = true // Don't run the deferred one if this panics.
+ runner.runFixtureWithPanic(runner.tearDownTest, nil, nil)
+ skipped = false
}
- if strings.HasPrefix(c.method.Info.Name, "Benchmark") {
- benchmark(c)
- return
- }
- panic("unexpected method prefix: " + c.method.Info.Name)
})
}
@@ -867,3 +915,4 @@
return fmt.Sprintf("%s%s: %s: %s%s", prefix, label, niceFuncPath(pc),
niceFuncName(pc), suffix)
}
+
diff --git a/gocheck_test.go b/gocheck_test.go
index 484832a..7575df4 100644
--- a/gocheck_test.go
+++ b/gocheck_test.go
@@ -94,27 +94,24 @@
// Helper suite for testing ordering and behavior of fixture.
type FixtureHelper struct {
- calls [64]string
- n int
- panicOn string
- skip bool
- skipOnN int
- sleepOn string
- sleep time.Duration
- bytes int64
+ calls []string
+ panicOn string
+ skip bool
+ skipOnN int
+ sleepOn string
+ sleep time.Duration
+ bytes int64
}
func (s *FixtureHelper) trace(name string, c *gocheck.C) {
- n := s.n
- s.calls[n] = name
- s.n += 1
+ s.calls = append(s.calls, name)
if name == s.panicOn {
panic(name)
}
if s.sleep > 0 && s.sleepOn == name {
time.Sleep(s.sleep)
}
- if s.skip && s.skipOnN == n {
+ if s.skip && s.skipOnN == len(s.calls)-1 {
c.Skip("skipOnN == n")
}
}
diff --git a/helpers_test.go b/helpers_test.go
index 79348bc..fb9ef8e 100644
--- a/helpers_test.go
+++ b/helpers_test.go
@@ -7,6 +7,8 @@
"launchpad.net/gocheck"
"os"
"reflect"
+ "runtime"
+ "sync"
)
var helpersS = gocheck.Suite(&HelpersS{})
@@ -428,6 +430,26 @@
return false
}
+// Concurrent logging should not corrupt the underling buffer.
+// Use go test -race to detect the race in this test.
+func (s *HelpersS) TestConcurrentLogging(c *gocheck.C) {
+ defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(runtime.NumCPU()))
+ var start, stop sync.WaitGroup
+ start.Add(1)
+ for i, n := 0, runtime.NumCPU()*2; i < n; i++ {
+ stop.Add(1)
+ go func(i int) {
+ start.Wait()
+ for j := 0; j < 30; j++ {
+ c.Logf("Worker %d: line %d", i, j)
+ }
+ stop.Done()
+ }(i)
+ }
+ start.Done()
+ stop.Wait()
+}
+
// -----------------------------------------------------------------------
// A couple of helper functions to test helper functions. :-)
diff --git a/run.go b/run.go
index 2f6ebed..9e08152 100644
--- a/run.go
+++ b/run.go
@@ -1,8 +1,10 @@
package gocheck
import (
+ "bufio"
"flag"
"fmt"
+ "os"
"testing"
"time"
)
@@ -24,11 +26,12 @@
// Public running interface.
var (
- filterFlag = flag.String("gocheck.f", "", "Regular expression selecting what to run")
+ filterFlag = flag.String("gocheck.f", "", "Regular expression selecting which tests and/or suites to run")
verboseFlag = flag.Bool("gocheck.v", false, "Verbose mode")
streamFlag = flag.Bool("gocheck.vv", false, "Super verbose mode (disables output caching)")
benchFlag = flag.Bool("gocheck.b", false, "Run benchmarks")
- benchTime = flag.Duration("gocheck.btime", 1*time.Second, "approximate run time for each benchmark")
+ benchTime = flag.Duration("gocheck.btime", 1 * time.Second, "approximate run time for each benchmark")
+ listFlag = flag.Bool("gocheck.list", false, "List the names of all tests that will be run")
)
// Run all test suites registered with the Suite() function, printing
@@ -42,6 +45,14 @@
Benchmark: *benchFlag,
BenchmarkTime: *benchTime,
}
+ if *listFlag {
+ w := bufio.NewWriter(os.Stdout)
+ for _, name := range ListAll(conf) {
+ fmt.Fprintln(w, name)
+ }
+ w.Flush()
+ return
+ }
result := RunAll(conf)
println(result.String())
if !result.Passed() {
@@ -49,7 +60,7 @@
}
}
-// Run all test suites registered with the Suite() function, using the
+// RunAll runs all test suites registered with the Suite() function, using the
// given run configuration.
func RunAll(runConf *RunConf) *Result {
result := Result{}
@@ -59,12 +70,34 @@
return &result
}
-// Run the given test suite using the provided run configuration.
+// Run runs the given test suite using the provided run configuration.
func Run(suite interface{}, runConf *RunConf) *Result {
runner := newSuiteRunner(suite, runConf)
return runner.run()
}
+// ListAll returns the names of all the test functions registered with the
+// Suite function that will be run with the provided run configuration.
+func ListAll(runConf *RunConf) []string {
+ var names []string
+ for _, suite := range allSuites {
+ names = append(names, List(suite, runConf)...)
+ }
+ return names
+}
+
+// List prints the names of the test functions in the given
+// suite that will be run with the provided run configuration
+// to the given Writer.
+func List(suite interface{}, runConf *RunConf) []string {
+ var names []string
+ runner := newSuiteRunner(suite, runConf)
+ for _, t := range runner.tests {
+ names = append(names, t.String())
+ }
+ return names
+}
+
// -----------------------------------------------------------------------
// Result methods.
diff --git a/run_test.go b/run_test.go
index 79f696d..6793e4c 100644
--- a/run_test.go
+++ b/run_test.go
@@ -2,6 +2,7 @@
package gocheck_test
+
import (
"errors"
. "launchpad.net/gocheck"
@@ -205,7 +206,7 @@
c.Check(helper.calls[2], Equals, "Test1")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 5)
+ c.Check(len(helper.calls), Equals, 5)
}
func (s *RunS) TestFilterTestNameWithAll(c *C) {
@@ -221,7 +222,7 @@
c.Check(helper.calls[5], Equals, "Test2")
c.Check(helper.calls[6], Equals, "TearDownTest")
c.Check(helper.calls[7], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 8)
+ c.Check(len(helper.calls), Equals, 8)
}
func (s *RunS) TestFilterSuiteName(c *C) {
@@ -237,7 +238,7 @@
c.Check(helper.calls[5], Equals, "Test2")
c.Check(helper.calls[6], Equals, "TearDownTest")
c.Check(helper.calls[7], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 8)
+ c.Check(len(helper.calls), Equals, 8)
}
func (s *RunS) TestFilterSuiteNameAndTestName(c *C) {
@@ -250,7 +251,7 @@
c.Check(helper.calls[2], Equals, "Test2")
c.Check(helper.calls[3], Equals, "TearDownTest")
c.Check(helper.calls[4], Equals, "TearDownSuite")
- c.Check(helper.n, Equals, 5)
+ c.Check(len(helper.calls), Equals, 5)
}
func (s *RunS) TestFilterAllOut(c *C) {
@@ -258,7 +259,7 @@
output := String{}
runConf := RunConf{Output: &output, Filter: "NotFound"}
Run(&helper, &runConf)
- c.Check(helper.n, Equals, 0)
+ c.Check(len(helper.calls), Equals, 0)
}
func (s *RunS) TestRequirePartialMatch(c *C) {
@@ -266,7 +267,7 @@
output := String{}
runConf := RunConf{Output: &output, Filter: "est"}
Run(&helper, &runConf)
- c.Check(helper.n, Equals, 8)
+ c.Check(len(helper.calls), Equals, 8)
}
func (s *RunS) TestFilterError(c *C) {
@@ -276,7 +277,25 @@
result := Run(&helper, &runConf)
c.Check(result.String(), Equals,
"ERROR: Bad filter expression: error parsing regexp: missing closing ]: `[`")
- c.Check(helper.n, Equals, 0)
+ c.Check(len(helper.calls), Equals, 0)
+}
+
+// -----------------------------------------------------------------------
+// Verify that List works correctly.
+
+func (s *RunS) TestListFiltered(c *C) {
+ names := List(&FixtureHelper{}, &RunConf{Filter: "1"})
+ c.Assert(names, DeepEquals, []string{
+ "FixtureHelper.Test1",
+ })
+}
+
+func (s *RunS) TestList(c *C) {
+ names := List(&FixtureHelper{}, &RunConf{})
+ c.Assert(names, DeepEquals, []string{
+ "FixtureHelper.Test1",
+ "FixtureHelper.Test2",
+ })
}
// -----------------------------------------------------------------------