OSDN Git Service

libgo: Update to weekly.2011-11-02.
[pf3gnuchains/gcc-fork.git] / libgo / go / testing / testing.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package testing provides support for automated testing of Go packages.
6 // It is intended to be used in concert with the ``gotest'' utility, which automates
7 // execution of any function of the form
8 //     func TestXxx(*testing.T)
9 // where Xxx can be any alphanumeric string (but the first letter must not be in
10 // [a-z]) and serves to identify the test routine.
11 // These TestXxx routines should be declared within the package they are testing.
12 //
13 // Functions of the form
14 //     func BenchmarkXxx(*testing.B)
15 // are considered benchmarks, and are executed by gotest when the -test.bench
16 // flag is provided.
17 //
18 // A sample benchmark function looks like this:
19 //     func BenchmarkHello(b *testing.B) {
20 //         for i := 0; i < b.N; i++ {
21 //             fmt.Sprintf("hello")
22 //         }
23 //     }
24 // The benchmark package will vary b.N until the benchmark function lasts
25 // long enough to be timed reliably.  The output
26 //     testing.BenchmarkHello   500000        4076 ns/op
27 // means that the loop ran 500000 times at a speed of 4076 ns per loop.
28 //
29 // If a benchmark needs some expensive setup before running, the timer
30 // may be stopped:
31 //     func BenchmarkBigLen(b *testing.B) {
32 //         b.StopTimer()
33 //         big := NewBig()
34 //         b.StartTimer()
35 //         for i := 0; i < b.N; i++ {
36 //             big.Len()
37 //         }
38 //     }
39 package testing
40
41 import (
42         "flag"
43         "fmt"
44         "os"
45         "runtime"
46         "runtime/pprof"
47         "strconv"
48         "strings"
49         "time"
50 )
51
52 var (
53         // The short flag requests that tests run more quickly, but its functionality
54         // is provided by test writers themselves.  The testing package is just its
55         // home.  The all.bash installation script sets it to make installation more
56         // efficient, but by default the flag is off so a plain "gotest" will do a
57         // full test of the package.
58         short = flag.Bool("test.short", false, "run smaller test suite to save time")
59
60         // Report as tests are run; default is silent for success.
61         chatty         = flag.Bool("test.v", false, "verbose: print additional output")
62         match          = flag.String("test.run", "", "regular expression to select tests to run")
63         memProfile     = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
64         memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate")
65         cpuProfile     = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
66         timeout        = flag.Int64("test.timeout", 0, "if > 0, sets time limit for tests in seconds")
67         cpuListStr     = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
68         parallel       = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
69
70         cpuList []int
71 )
72
73 // Short reports whether the -test.short flag is set.
74 func Short() bool {
75         return *short
76 }
77
78 // Insert final newline if needed and tabs after internal newlines.
79 func tabify(s string) string {
80         n := len(s)
81         if n > 0 && s[n-1] != '\n' {
82                 s += "\n"
83                 n++
84         }
85         for i := 0; i < n-1; i++ { // -1 to avoid final newline
86                 if s[i] == '\n' {
87                         return s[0:i+1] + "\t" + tabify(s[i+1:n])
88                 }
89         }
90         return s
91 }
92
93 // T is a type passed to Test functions to manage test state and support formatted test logs.
94 // Logs are accumulated during execution and dumped to standard error when done.
95 type T struct {
96         name          string    // Name of test.
97         errors        string    // Error string from test.
98         failed        bool      // Test has failed.
99         ch            chan *T   // Output for serial tests.
100         startParallel chan bool // Parallel tests will wait on this.
101         ns            int64     // Duration of test in nanoseconds.
102 }
103
104 // Fail marks the Test function as having failed but continues execution.
105 func (t *T) Fail() { t.failed = true }
106
107 // Failed returns whether the Test function has failed.
108 func (t *T) Failed() bool { return t.failed }
109
110 // FailNow marks the Test function as having failed and stops its execution.
111 // Execution will continue at the next Test.
112 func (t *T) FailNow() {
113         t.ns = time.Nanoseconds() - t.ns
114         t.Fail()
115         t.ch <- t
116         runtime.Goexit()
117 }
118
119 // Log formats its arguments using default formatting, analogous to Print(),
120 // and records the text in the error log.
121 func (t *T) Log(args ...interface{}) { t.errors += "\t" + tabify(fmt.Sprintln(args...)) }
122
123 // Logf formats its arguments according to the format, analogous to Printf(),
124 // and records the text in the error log.
125 func (t *T) Logf(format string, args ...interface{}) {
126         t.errors += "\t" + tabify(fmt.Sprintf(format, args...))
127 }
128
129 // Error is equivalent to Log() followed by Fail().
130 func (t *T) Error(args ...interface{}) {
131         t.Log(args...)
132         t.Fail()
133 }
134
135 // Errorf is equivalent to Logf() followed by Fail().
136 func (t *T) Errorf(format string, args ...interface{}) {
137         t.Logf(format, args...)
138         t.Fail()
139 }
140
141 // Fatal is equivalent to Log() followed by FailNow().
142 func (t *T) Fatal(args ...interface{}) {
143         t.Log(args...)
144         t.FailNow()
145 }
146
147 // Fatalf is equivalent to Logf() followed by FailNow().
148 func (t *T) Fatalf(format string, args ...interface{}) {
149         t.Logf(format, args...)
150         t.FailNow()
151 }
152
153 // Parallel signals that this test is to be run in parallel with (and only with) 
154 // other parallel tests in this CPU group.
155 func (t *T) Parallel() {
156         t.ch <- nil       // Release main testing loop
157         <-t.startParallel // Wait for serial tests to finish
158 }
159
160 // An internal type but exported because it is cross-package; part of the implementation
161 // of gotest.
162 type InternalTest struct {
163         Name string
164         F    func(*T)
165 }
166
167 func tRunner(t *T, test *InternalTest) {
168         t.ns = time.Nanoseconds()
169         test.F(t)
170         t.ns = time.Nanoseconds() - t.ns
171         t.ch <- t
172 }
173
174 // An internal function but exported because it is cross-package; part of the implementation
175 // of gotest.
176 func Main(matchString func(pat, str string) (bool, error), tests []InternalTest, benchmarks []InternalBenchmark, examples []InternalExample) {
177         flag.Parse()
178         parseCpuList()
179
180         before()
181         startAlarm()
182         testOk := RunTests(matchString, tests)
183         exampleOk := RunExamples(examples)
184         if !testOk || !exampleOk {
185                 fmt.Fprintln(os.Stderr, "FAIL")
186                 os.Exit(1)
187         }
188         fmt.Fprintln(os.Stderr, "PASS")
189         stopAlarm()
190         RunBenchmarks(matchString, benchmarks)
191         after()
192 }
193
194 func report(t *T) {
195         tstr := fmt.Sprintf("(%.2f seconds)", float64(t.ns)/1e9)
196         format := "--- %s: %s %s\n%s"
197         if t.failed {
198                 fmt.Fprintf(os.Stderr, format, "FAIL", t.name, tstr, t.errors)
199         } else if *chatty {
200                 fmt.Fprintf(os.Stderr, format, "PASS", t.name, tstr, t.errors)
201         }
202 }
203
204 func RunTests(matchString func(pat, str string) (bool, error), tests []InternalTest) (ok bool) {
205         ok = true
206         if len(tests) == 0 {
207                 fmt.Fprintln(os.Stderr, "testing: warning: no tests to run")
208                 return
209         }
210         ch := make(chan *T)
211         for _, procs := range cpuList {
212                 runtime.GOMAXPROCS(procs)
213
214                 numParallel := 0
215                 startParallel := make(chan bool)
216
217                 for i := 0; i < len(tests); i++ {
218                         matched, err := matchString(*match, tests[i].Name)
219                         if err != nil {
220                                 println("invalid regexp for -test.run:", err.Error())
221                                 os.Exit(1)
222                         }
223                         if !matched {
224                                 continue
225                         }
226                         testName := tests[i].Name
227                         if procs != 1 {
228                                 testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
229                         }
230                         t := &T{ch: ch, name: testName, startParallel: startParallel}
231                         if *chatty {
232                                 println("=== RUN", t.name)
233                         }
234                         go tRunner(t, &tests[i])
235                         out := <-t.ch
236                         if out == nil { // Parallel run.
237                                 numParallel++
238                                 continue
239                         }
240                         report(t)
241                         ok = ok && !out.failed
242                 }
243
244                 running := 0
245                 for numParallel+running > 0 {
246                         if running < *parallel && numParallel > 0 {
247                                 startParallel <- true
248                                 running++
249                                 numParallel--
250                                 continue
251                         }
252                         t := <-ch
253                         report(t)
254                         ok = ok && !t.failed
255                         running--
256                 }
257         }
258         return
259 }
260
261 // before runs before all testing.
262 func before() {
263         if *memProfileRate > 0 {
264                 runtime.MemProfileRate = *memProfileRate
265         }
266         if *cpuProfile != "" {
267                 f, err := os.Create(*cpuProfile)
268                 if err != nil {
269                         fmt.Fprintf(os.Stderr, "testing: %s", err)
270                         return
271                 }
272                 if err := pprof.StartCPUProfile(f); err != nil {
273                         fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err)
274                         f.Close()
275                         return
276                 }
277                 // Could save f so after can call f.Close; not worth the effort.
278         }
279
280 }
281
282 // after runs after all testing.
283 func after() {
284         if *cpuProfile != "" {
285                 pprof.StopCPUProfile() // flushes profile to disk
286         }
287         if *memProfile != "" {
288                 f, err := os.Create(*memProfile)
289                 if err != nil {
290                         fmt.Fprintf(os.Stderr, "testing: %s", err)
291                         return
292                 }
293                 if err = pprof.WriteHeapProfile(f); err != nil {
294                         fmt.Fprintf(os.Stderr, "testing: can't write %s: %s", *memProfile, err)
295                 }
296                 f.Close()
297         }
298 }
299
300 var timer *time.Timer
301
302 // startAlarm starts an alarm if requested.
303 func startAlarm() {
304         if *timeout > 0 {
305                 timer = time.AfterFunc(*timeout*1e9, alarm)
306         }
307 }
308
309 // stopAlarm turns off the alarm.
310 func stopAlarm() {
311         if *timeout > 0 {
312                 timer.Stop()
313         }
314 }
315
316 // alarm is called if the timeout expires.
317 func alarm() {
318         panic("test timed out")
319 }
320
321 func parseCpuList() {
322         if len(*cpuListStr) == 0 {
323                 cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
324         } else {
325                 for _, val := range strings.Split(*cpuListStr, ",") {
326                         cpu, err := strconv.Atoi(val)
327                         if err != nil || cpu <= 0 {
328                                 println("invalid value for -test.cpu")
329                                 os.Exit(1)
330                         }
331                         cpuList = append(cpuList, cpu)
332                 }
333         }
334 }