diff options
Diffstat (limited to 'src/pkg/testing')
-rw-r--r-- | src/pkg/testing/quick/quick.go | 114 | ||||
-rw-r--r-- | src/pkg/testing/script/script.go | 16 | ||||
-rw-r--r-- | src/pkg/testing/testing.go | 99 |
3 files changed, 158 insertions, 71 deletions
diff --git a/src/pkg/testing/quick/quick.go b/src/pkg/testing/quick/quick.go index a5568b048..52fd38d9c 100644 --- a/src/pkg/testing/quick/quick.go +++ b/src/pkg/testing/quick/quick.go @@ -53,96 +53,93 @@ const complexSize = 50 // If the type implements the Generator interface, that will be used. // Note: in order to create arbitrary values for structs, all the members must be public. func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) { - if m, ok := reflect.MakeZero(t).Interface().(Generator); ok { + if m, ok := reflect.Zero(t).Interface().(Generator); ok { return m.Generate(rand, complexSize), true } - switch concrete := t.(type) { - case *reflect.BoolType: + switch concrete := t; concrete.Kind() { + case reflect.Bool: return reflect.NewValue(rand.Int()&1 == 0), true - case *reflect.FloatType, *reflect.IntType, *reflect.UintType, *reflect.ComplexType: - switch t.Kind() { - case reflect.Float32: - return reflect.NewValue(randFloat32(rand)), true - case reflect.Float64: - return reflect.NewValue(randFloat64(rand)), true - case reflect.Complex64: - return reflect.NewValue(complex(randFloat32(rand), randFloat32(rand))), true - case reflect.Complex128: - return reflect.NewValue(complex(randFloat64(rand), randFloat64(rand))), true - case reflect.Int16: - return reflect.NewValue(int16(randInt64(rand))), true - case reflect.Int32: - return reflect.NewValue(int32(randInt64(rand))), true - case reflect.Int64: - return reflect.NewValue(randInt64(rand)), true - case reflect.Int8: - return reflect.NewValue(int8(randInt64(rand))), true - case reflect.Int: - return reflect.NewValue(int(randInt64(rand))), true - case reflect.Uint16: - return reflect.NewValue(uint16(randInt64(rand))), true - case reflect.Uint32: - return reflect.NewValue(uint32(randInt64(rand))), true - case reflect.Uint64: - return reflect.NewValue(uint64(randInt64(rand))), true - case reflect.Uint8: - return reflect.NewValue(uint8(randInt64(rand))), true - case reflect.Uint: - return reflect.NewValue(uint(randInt64(rand))), true - case reflect.Uintptr: - return reflect.NewValue(uintptr(randInt64(rand))), true - } - case *reflect.MapType: + case reflect.Float32: + return reflect.NewValue(randFloat32(rand)), true + case reflect.Float64: + return reflect.NewValue(randFloat64(rand)), true + case reflect.Complex64: + return reflect.NewValue(complex(randFloat32(rand), randFloat32(rand))), true + case reflect.Complex128: + return reflect.NewValue(complex(randFloat64(rand), randFloat64(rand))), true + case reflect.Int16: + return reflect.NewValue(int16(randInt64(rand))), true + case reflect.Int32: + return reflect.NewValue(int32(randInt64(rand))), true + case reflect.Int64: + return reflect.NewValue(randInt64(rand)), true + case reflect.Int8: + return reflect.NewValue(int8(randInt64(rand))), true + case reflect.Int: + return reflect.NewValue(int(randInt64(rand))), true + case reflect.Uint16: + return reflect.NewValue(uint16(randInt64(rand))), true + case reflect.Uint32: + return reflect.NewValue(uint32(randInt64(rand))), true + case reflect.Uint64: + return reflect.NewValue(uint64(randInt64(rand))), true + case reflect.Uint8: + return reflect.NewValue(uint8(randInt64(rand))), true + case reflect.Uint: + return reflect.NewValue(uint(randInt64(rand))), true + case reflect.Uintptr: + return reflect.NewValue(uintptr(randInt64(rand))), true + case reflect.Map: numElems := rand.Intn(complexSize) m := reflect.MakeMap(concrete) for i := 0; i < numElems; i++ { key, ok1 := Value(concrete.Key(), rand) value, ok2 := Value(concrete.Elem(), rand) if !ok1 || !ok2 { - return nil, false + return reflect.Value{}, false } - m.SetElem(key, value) + m.SetMapIndex(key, value) } return m, true - case *reflect.PtrType: + case reflect.Ptr: v, ok := Value(concrete.Elem(), rand) if !ok { - return nil, false + return reflect.Value{}, false } - p := reflect.MakeZero(concrete) - p.(*reflect.PtrValue).PointTo(v) + p := reflect.Zero(concrete) + p.Set(v.Addr()) return p, true - case *reflect.SliceType: + case reflect.Slice: numElems := rand.Intn(complexSize) s := reflect.MakeSlice(concrete, numElems, numElems) for i := 0; i < numElems; i++ { v, ok := Value(concrete.Elem(), rand) if !ok { - return nil, false + return reflect.Value{}, false } - s.Elem(i).SetValue(v) + s.Index(i).Set(v) } return s, true - case *reflect.StringType: + case reflect.String: numChars := rand.Intn(complexSize) codePoints := make([]int, numChars) for i := 0; i < numChars; i++ { codePoints[i] = rand.Intn(0x10ffff) } return reflect.NewValue(string(codePoints)), true - case *reflect.StructType: - s := reflect.MakeZero(t).(*reflect.StructValue) + case reflect.Struct: + s := reflect.Zero(t) for i := 0; i < s.NumField(); i++ { v, ok := Value(concrete.Field(i).Type, rand) if !ok { - return nil, false + return reflect.Value{}, false } - s.Field(i).SetValue(v) + s.Field(i).Set(v) } return s, true default: - return nil, false + return reflect.Value{}, false } return @@ -247,7 +244,7 @@ func Check(function interface{}, config *Config) (err os.Error) { err = SetupError("function returns more than one value.") return } - if _, ok := fType.Out(0).(*reflect.BoolType); !ok { + if fType.Out(0).Kind() != reflect.Bool { err = SetupError("function does not return a bool") return } @@ -262,7 +259,7 @@ func Check(function interface{}, config *Config) (err os.Error) { return } - if !f.Call(arguments)[0].(*reflect.BoolValue).Get() { + if !f.Call(arguments)[0].Bool() { err = &CheckError{i + 1, toInterfaces(arguments)} return } @@ -320,7 +317,7 @@ func CheckEqual(f, g interface{}, config *Config) (err os.Error) { // arbitraryValues writes Values to args such that args contains Values // suitable for calling f. -func arbitraryValues(args []reflect.Value, f *reflect.FuncType, config *Config, rand *rand.Rand) (err os.Error) { +func arbitraryValues(args []reflect.Value, f reflect.Type, config *Config, rand *rand.Rand) (err os.Error) { if config.Values != nil { config.Values(args, rand) return @@ -338,12 +335,13 @@ func arbitraryValues(args []reflect.Value, f *reflect.FuncType, config *Config, return } -func functionAndType(f interface{}) (v *reflect.FuncValue, t *reflect.FuncType, ok bool) { - v, ok = reflect.NewValue(f).(*reflect.FuncValue) +func functionAndType(f interface{}) (v reflect.Value, t reflect.Type, ok bool) { + v = reflect.NewValue(f) + ok = v.Kind() == reflect.Func if !ok { return } - t = v.Type().(*reflect.FuncType) + t = v.Type() return } diff --git a/src/pkg/testing/script/script.go b/src/pkg/testing/script/script.go index 11f5a7425..b18018497 100644 --- a/src/pkg/testing/script/script.go +++ b/src/pkg/testing/script/script.go @@ -134,16 +134,16 @@ type empty struct { } func newEmptyInterface(e empty) reflect.Value { - return reflect.NewValue(e).(*reflect.StructValue).Field(0) + return reflect.NewValue(e).Field(0) } func (s Send) send() { // With reflect.ChanValue.Send, we must match the types exactly. So, if // s.Channel is a chan interface{} we convert s.Value to an interface{} // first. - c := reflect.NewValue(s.Channel).(*reflect.ChanValue) + c := reflect.NewValue(s.Channel) var v reflect.Value - if iface, ok := c.Type().(*reflect.ChanType).Elem().(*reflect.InterfaceType); ok && iface.NumMethod() == 0 { + if iface := c.Type().Elem(); iface.Kind() == reflect.Interface && iface.NumMethod() == 0 { v = newEmptyInterface(empty{s.Value}) } else { v = reflect.NewValue(s.Value) @@ -162,7 +162,7 @@ func (s Close) getSend() sendAction { return s } func (s Close) getChannel() interface{} { return s.Channel } -func (s Close) send() { reflect.NewValue(s.Channel).(*reflect.ChanValue).Close() } +func (s Close) send() { reflect.NewValue(s.Channel).Close() } // A ReceivedUnexpected error results if no active Events match a value // received from a channel. @@ -278,7 +278,7 @@ func getChannels(events []*Event) ([]interface{}, os.Error) { continue } c := event.action.getChannel() - if _, ok := reflect.NewValue(c).(*reflect.ChanValue); !ok { + if reflect.NewValue(c).Kind() != reflect.Chan { return nil, SetupError("one of the channel values is not a channel") } @@ -303,11 +303,11 @@ func getChannels(events []*Event) ([]interface{}, os.Error) { // channel repeatedly, wrapping them up as either a channelRecv or // channelClosed structure, and forwards them to the multiplex channel. func recvValues(multiplex chan<- interface{}, channel interface{}) { - c := reflect.NewValue(channel).(*reflect.ChanValue) + c := reflect.NewValue(channel) for { - v := c.Recv() - if c.Closed() { + v, ok := c.Recv() + if !ok { multiplex <- channelClosed{channel} return } diff --git a/src/pkg/testing/testing.go b/src/pkg/testing/testing.go index 324b5a70e..1e65528ef 100644 --- a/src/pkg/testing/testing.go +++ b/src/pkg/testing/testing.go @@ -43,12 +43,31 @@ import ( "fmt" "os" "runtime" + "runtime/pprof" "time" ) -// Report as tests are run; default is silent for success. -var chatty = flag.Bool("test.v", false, "verbose: print additional output") -var match = flag.String("test.run", "", "regular expression to select tests to run") +var ( + // The short flag requests that tests run more quickly, but its functionality + // is provided by test writers themselves. The testing package is just its + // home. The all.bash installation script sets it to make installation more + // efficient, but by default the flag is off so a plain "gotest" will do a + // full test of the package. + short = flag.Bool("test.short", false, "run smaller test suite to save time") + + // Report as tests are run; default is silent for success. + chatty = flag.Bool("test.v", false, "verbose: print additional output") + match = flag.String("test.run", "", "regular expression to select tests to run") + memProfile = flag.String("test.memprofile", "", "write a memory profile to the named file after execution") + memProfileRate = flag.Int("test.memprofilerate", 0, "if >=0, sets runtime.MemProfileRate") + cpuProfile = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution") + timeout = flag.Int64("test.timeout", 0, "if > 0, sets time limit for tests in seconds") +) + +// Short reports whether the -test.short flag is set. +func Short() bool { + return *short +} // Insert final newline if needed and tabs after internal newlines. @@ -136,8 +155,18 @@ func tRunner(t *T, test *InternalTest) { // An internal function but exported because it is cross-package; part of the implementation // of gotest. -func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTest) { +func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTest, benchmarks []InternalBenchmark) { flag.Parse() + + before() + startAlarm() + RunTests(matchString, tests) + stopAlarm() + RunBenchmarks(matchString, benchmarks) + after() +} + +func RunTests(matchString func(pat, str string) (bool, os.Error), tests []InternalTest) { ok := true if len(tests) == 0 { println("testing: warning: no tests to run") @@ -160,7 +189,7 @@ func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTe go tRunner(t, &tests[i]) <-t.ch ns += time.Nanoseconds() - tstr := fmt.Sprintf("(%.1f seconds)", float64(ns)/1e9) + tstr := fmt.Sprintf("(%.2f seconds)", float64(ns)/1e9) if t.failed { println("--- FAIL:", tests[i].Name, tstr) print(t.errors) @@ -176,3 +205,63 @@ func Main(matchString func(pat, str string) (bool, os.Error), tests []InternalTe } println("PASS") } + +// before runs before all testing. +func before() { + if *memProfileRate > 0 { + runtime.MemProfileRate = *memProfileRate + } + if *cpuProfile != "" { + f, err := os.Create(*cpuProfile) + if err != nil { + fmt.Fprintf(os.Stderr, "testing: %s", err) + return + } + if err := pprof.StartCPUProfile(f); err != nil { + fmt.Fprintf(os.Stderr, "testing: can't start cpu profile: %s", err) + f.Close() + return + } + // Could save f so after can call f.Close; not worth the effort. + } + +} + +// after runs after all testing. +func after() { + if *cpuProfile != "" { + pprof.StopCPUProfile() // flushes profile to disk + } + if *memProfile != "" { + f, err := os.Create(*memProfile) + if err != nil { + fmt.Fprintf(os.Stderr, "testing: %s", err) + return + } + if err = pprof.WriteHeapProfile(f); err != nil { + fmt.Fprintf(os.Stderr, "testing: can't write %s: %s", *memProfile, err) + } + f.Close() + } +} + +var timer *time.Timer + +// startAlarm starts an alarm if requested. +func startAlarm() { + if *timeout > 0 { + timer = time.AfterFunc(*timeout*1e9, alarm) + } +} + +// stopAlarm turns off the alarm. +func stopAlarm() { + if *timeout > 0 { + timer.Stop() + } +} + +// alarm is called if the timeout expires. +func alarm() { + panic("test timed out") +} |