aboutsummaryrefslogtreecommitdiff
path: root/src/testing/sub_test.go
diff options
context:
space:
mode:
authorMarcel van Lohuizen <mpvl@golang.org>2016-01-20 15:47:54 +0100
committerMarcel van Lohuizen <mpvl@golang.org>2016-03-18 12:05:55 +0000
commit1857bfca134261ab2e0fc1adcf6a974f550d430a (patch)
tree9d554848630428f01735098d6afd63b3f557393d /src/testing/sub_test.go
parent89cda2db007c8389ba39d292c6372ff0c6a7622f (diff)
downloadgo-1857bfca134261ab2e0fc1adcf6a974f550d430a.tar.xz
testing: implementation of subbenchmarks
API is not exposed yet. Change-Id: I729360ef2be1d8ea683ca93cdb1763897cc8657c Reviewed-on: https://go-review.googlesource.com/18895 Reviewed-by: Russ Cox <rsc@golang.org>
Diffstat (limited to 'src/testing/sub_test.go')
-rw-r--r--src/testing/sub_test.go97
1 files changed, 97 insertions, 0 deletions
diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go
index 8cb13ee101..c98ce58307 100644
--- a/src/testing/sub_test.go
+++ b/src/testing/sub_test.go
@@ -4,6 +4,10 @@
package testing
+import (
+ "time"
+)
+
func TestTestContext(t *T) {
const (
add1 = 0
@@ -99,3 +103,96 @@ func TestTestContext(t *T) {
}
}
}
+
+// TODO: remove this stub when API is exposed
+func (b *B) Run(name string, f func(b *B)) bool { return b.runBench(name, f) }
+
+func TestBRun(t *T) {
+ work := func(b *B) {
+ for i := 0; i < b.N; i++ {
+ time.Sleep(time.Nanosecond)
+ }
+ }
+ testCases := []struct {
+ desc string
+ failed bool
+ f func(*B)
+ }{{
+ desc: "simulate sequential run of subbenchmarks.",
+ f: func(b *B) {
+ b.Run("", func(b *B) { work(b) })
+ time1 := b.result.NsPerOp()
+ b.Run("", func(b *B) { work(b) })
+ time2 := b.result.NsPerOp()
+ if time1 >= time2 {
+ t.Errorf("no time spent in benchmark t1 >= t2 (%d >= %d)", time1, time2)
+ }
+ },
+ }, {
+ desc: "bytes set by all benchmarks",
+ f: func(b *B) {
+ b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+ b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+ if b.result.Bytes != 20 {
+ t.Errorf("bytes: got: %d; want 20", b.result.Bytes)
+ }
+ },
+ }, {
+ desc: "bytes set by some benchmarks",
+ // In this case the bytes result is meaningless, so it must be 0.
+ f: func(b *B) {
+ b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+ b.Run("", func(b *B) { work(b) })
+ b.Run("", func(b *B) { b.SetBytes(10); work(b) })
+ if b.result.Bytes != 0 {
+ t.Errorf("bytes: got: %d; want 0", b.result.Bytes)
+ }
+ },
+ }, {
+ desc: "failure carried over to root",
+ failed: true,
+ f: func(b *B) { b.Fail() },
+ }, {
+ desc: "memory allocation",
+ f: func(b *B) {
+ const bufSize = 256
+ alloc := func(b *B) {
+ var buf [bufSize]byte
+ for i := 0; i < b.N; i++ {
+ _ = append([]byte(nil), buf[:]...)
+ }
+ }
+ b.Run("", func(b *B) { alloc(b) })
+ b.Run("", func(b *B) { alloc(b) })
+ if got := b.result.MemAllocs; got != 2 {
+ t.Errorf("MemAllocs was %v; want 2", got)
+ }
+ if got := b.result.MemBytes; got != 2*bufSize {
+ t.Errorf("MemBytes was %v; want %v", got, 2*bufSize)
+ }
+ },
+ }}
+ for _, tc := range testCases {
+ var ok bool
+ // This is almost like the Benchmark function, except that we override
+ // the benchtime and catch the failure result of the subbenchmark.
+ root := &B{
+ common: common{
+ signal: make(chan bool),
+ },
+ benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure.
+ benchTime: time.Microsecond,
+ }
+ root.run()
+ if ok != !tc.failed {
+ t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed)
+ }
+ if !ok != root.Failed() {
+ t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
+ }
+ // All tests are run as subtests
+ if root.result.N != 1 {
+ t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N)
+ }
+ }
+}