1package check
2
3import (
4	"bufio"
5	"flag"
6	"fmt"
7	"os"
8	"testing"
9	"time"
10)
11
12// -----------------------------------------------------------------------
13// Test suite registry.
14
15var allSuites []interface{}
16
17// Suite registers the given value as a test suite to be run. Any methods
18// starting with the Test prefix in the given value will be considered as
19// a test method.
20func Suite(suite interface{}) interface{} {
21	allSuites = append(allSuites, suite)
22	return suite
23}
24
25// -----------------------------------------------------------------------
26// Public running interface.
27
28var (
29	oldFilterFlag  = flag.String("gocheck.f", "", "Regular expression selecting which tests and/or suites to run")
30	oldVerboseFlag = flag.Bool("gocheck.v", false, "Verbose mode")
31	oldStreamFlag  = flag.Bool("gocheck.vv", false, "Super verbose mode (disables output caching)")
32	oldBenchFlag   = flag.Bool("gocheck.b", false, "Run benchmarks")
33	oldBenchTime   = flag.Duration("gocheck.btime", 1*time.Second, "approximate run time for each benchmark")
34	oldListFlag    = flag.Bool("gocheck.list", false, "List the names of all tests that will be run")
35	oldWorkFlag    = flag.Bool("gocheck.work", false, "Display and do not remove the test working directory")
36
37	newFilterFlag  = flag.String("check.f", "", "Regular expression selecting which tests and/or suites to run")
38	newVerboseFlag = flag.Bool("check.v", false, "Verbose mode")
39	newStreamFlag  = flag.Bool("check.vv", false, "Super verbose mode (disables output caching)")
40	newBenchFlag   = flag.Bool("check.b", false, "Run benchmarks")
41	newBenchTime   = flag.Duration("check.btime", 1*time.Second, "approximate run time for each benchmark")
42	newBenchMem    = flag.Bool("check.bmem", false, "Report memory benchmarks")
43	newListFlag    = flag.Bool("check.list", false, "List the names of all tests that will be run")
44	newWorkFlag    = flag.Bool("check.work", false, "Display and do not remove the test working directory")
45)
46
47// TestingT runs all test suites registered with the Suite function,
48// printing results to stdout, and reporting any failures back to
49// the "testing" package.
50func TestingT(testingT *testing.T) {
51	benchTime := *newBenchTime
52	if benchTime == 1*time.Second {
53		benchTime = *oldBenchTime
54	}
55	conf := &RunConf{
56		Filter:        *oldFilterFlag + *newFilterFlag,
57		Verbose:       *oldVerboseFlag || *newVerboseFlag,
58		Stream:        *oldStreamFlag || *newStreamFlag,
59		Benchmark:     *oldBenchFlag || *newBenchFlag,
60		BenchmarkTime: benchTime,
61		BenchmarkMem:  *newBenchMem,
62		KeepWorkDir:   *oldWorkFlag || *newWorkFlag,
63	}
64	if *oldListFlag || *newListFlag {
65		w := bufio.NewWriter(os.Stdout)
66		for _, name := range ListAll(conf) {
67			fmt.Fprintln(w, name)
68		}
69		w.Flush()
70		return
71	}
72	result := RunAll(conf)
73	println(result.String())
74	if !result.Passed() {
75		testingT.Fail()
76	}
77}
78
79// RunAll runs all test suites registered with the Suite function, using the
80// provided run configuration.
81func RunAll(runConf *RunConf) *Result {
82	result := Result{}
83	for _, suite := range allSuites {
84		result.Add(Run(suite, runConf))
85	}
86	return &result
87}
88
89// Run runs the provided test suite using the provided run configuration.
90func Run(suite interface{}, runConf *RunConf) *Result {
91	runner := newSuiteRunner(suite, runConf)
92	return runner.run()
93}
94
95// ListAll returns the names of all the test functions registered with the
96// Suite function that will be run with the provided run configuration.
97func ListAll(runConf *RunConf) []string {
98	var names []string
99	for _, suite := range allSuites {
100		names = append(names, List(suite, runConf)...)
101	}
102	return names
103}
104
105// List returns the names of the test functions in the given
106// suite that will be run with the provided run configuration.
107func List(suite interface{}, runConf *RunConf) []string {
108	var names []string
109	runner := newSuiteRunner(suite, runConf)
110	for _, t := range runner.tests {
111		names = append(names, t.String())
112	}
113	return names
114}
115
116// -----------------------------------------------------------------------
117// Result methods.
118
119func (r *Result) Add(other *Result) {
120	r.Succeeded += other.Succeeded
121	r.Skipped += other.Skipped
122	r.Failed += other.Failed
123	r.Panicked += other.Panicked
124	r.FixturePanicked += other.FixturePanicked
125	r.ExpectedFailures += other.ExpectedFailures
126	r.Missed += other.Missed
127	if r.WorkDir != "" && other.WorkDir != "" {
128		r.WorkDir += ":" + other.WorkDir
129	} else if other.WorkDir != "" {
130		r.WorkDir = other.WorkDir
131	}
132}
133
134func (r *Result) Passed() bool {
135	return (r.Failed == 0 && r.Panicked == 0 &&
136		r.FixturePanicked == 0 && r.Missed == 0 &&
137		r.RunError == nil)
138}
139
140func (r *Result) String() string {
141	if r.RunError != nil {
142		return "ERROR: " + r.RunError.Error()
143	}
144
145	var value string
146	if r.Failed == 0 && r.Panicked == 0 && r.FixturePanicked == 0 &&
147		r.Missed == 0 {
148		value = "OK: "
149	} else {
150		value = "OOPS: "
151	}
152	value += fmt.Sprintf("%d passed", r.Succeeded)
153	if r.Skipped != 0 {
154		value += fmt.Sprintf(", %d skipped", r.Skipped)
155	}
156	if r.ExpectedFailures != 0 {
157		value += fmt.Sprintf(", %d expected failures", r.ExpectedFailures)
158	}
159	if r.Failed != 0 {
160		value += fmt.Sprintf(", %d FAILED", r.Failed)
161	}
162	if r.Panicked != 0 {
163		value += fmt.Sprintf(", %d PANICKED", r.Panicked)
164	}
165	if r.FixturePanicked != 0 {
166		value += fmt.Sprintf(", %d FIXTURE-PANICKED", r.FixturePanicked)
167	}
168	if r.Missed != 0 {
169		value += fmt.Sprintf(", %d MISSED", r.Missed)
170	}
171	if r.WorkDir != "" {
172		value += "\nWORK=" + r.WorkDir
173	}
174	return value
175}
176