blob: e8f43dcddb342c97768128705ed6336999a3d731 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package timing
import (
"bytes"
"fmt"
"math/rand"
"reflect"
"strings"
"testing"
"time"
)
func sec(d int) time.Duration {
return time.Second * time.Duration(d)
}
func tsec(d int) time.Time {
return time.Time{}.Add(sec(d))
}
// fakeNow is a simulated clock where now is set manually.
type fakeNow struct{ now int }
func (f *fakeNow) Now() time.Time { return tsec(f.now) }
// stepNow is a simulated clock where now increments in 1 second steps.
type stepNow struct{ now int }
func (s *stepNow) Now() time.Time {
s.now++
return tsec(s.now)
}
type (
// op represents the operations that can be performed on a Timer, with a fake
// clock. This makes it easy to construct test cases.
op interface {
run(f *fakeNow, t *Timer)
}
push struct {
now int
name string
}
pop struct {
now int
}
finish struct {
now int
}
)
func (x push) run(f *fakeNow, t *Timer) {
f.now = x.now
t.Push(x.name)
}
func (x pop) run(f *fakeNow, t *Timer) {
f.now = x.now
t.Pop()
}
func (x finish) run(f *fakeNow, t *Timer) {
f.now = x.now
t.Finish()
}
// stripGaps strips out leading newlines, and also strips any line with an
// asterisk (*). Asterisks appear in lines with gaps, as shown here:
//
// 00:00:01.000 root 98.000s 00:01:39.000
// 00:00:01.000 * 9.000s 00:00:10.000
// 00:00:10.000 abc 89.000s 00:01:39.000
func stripGaps(out string) string {
out = strings.TrimLeft(out, "\n")
var lines []string
for _, line := range strings.Split(out, "\n") {
if !strings.ContainsRune(line, '*') {
lines = append(lines, line)
}
}
return strings.Join(lines, "\n")
}
func TestTimer(t *testing.T) {
t.Parallel()
tests := []struct {
ops []op
intervals []Interval
str string
}{
{
nil,
[]Interval{{"root", 0, sec(0), InvalidDuration}},
`
00:00:01.000 root 999.000s ---------now
`,
},
{
[]op{pop{123}},
[]Interval{{"root", 0, sec(0), InvalidDuration}},
`
00:00:01.000 root 999.000s ---------now
`,
},
{
[]op{finish{99}},
[]Interval{{"root", 0, sec(0), sec(98)}},
`
00:00:01.000 root 98.000s 00:01:39.000
`,
},
{
[]op{finish{99}, pop{123}},
[]Interval{{"root", 0, sec(0), sec(98)}},
`
00:00:01.000 root 98.000s 00:01:39.000
`,
},
{
[]op{push{10, "abc"}},
[]Interval{
{"root", 0, sec(0), InvalidDuration},
{"abc", 1, sec(9), InvalidDuration},
},
`
00:00:01.000 root 999.000s ---------now
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 abc 990.000s ---------now
`,
},
{
[]op{push{10, "abc"}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"abc", 1, sec(9), sec(98)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 abc 89.000s 00:01:39.000
`,
},
{
[]op{push{10, "abc"}, pop{20}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"abc", 1, sec(9), sec(19)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 abc 10.000s 00:00:20.000
00:00:20.000 * 79.000s 00:01:39.000
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}},
[]Interval{
{"root", 0, sec(0), InvalidDuration},
{"A1", 1, sec(9), InvalidDuration},
{"A1_1", 2, sec(19), InvalidDuration},
},
`
00:00:01.000 root 999.000s ---------now
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 990.000s ---------now
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 980.000s ---------now
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"A1", 1, sec(9), sec(98)},
{"A1_1", 2, sec(19), sec(98)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 89.000s 00:01:39.000
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 79.000s 00:01:39.000
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}, pop{30}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"A1", 1, sec(9), sec(98)},
{"A1_1", 2, sec(19), sec(29)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 89.000s 00:01:39.000
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 10.000s 00:00:30.000
00:00:30.000 * 69.000s 00:01:39.000
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}, pop{30}, pop{40}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"A1", 1, sec(9), sec(39)},
{"A1_1", 2, sec(19), sec(29)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 30.000s 00:00:40.000
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 10.000s 00:00:30.000
00:00:30.000 * 10.000s 00:00:40.000
00:00:40.000 * 59.000s 00:01:39.000
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}, push{30, "A1_1_1"}},
[]Interval{
{"root", 0, sec(0), InvalidDuration},
{"A1", 1, sec(9), InvalidDuration},
{"A1_1", 2, sec(19), InvalidDuration},
{"A1_1_1", 3, sec(29), InvalidDuration},
},
`
00:00:01.000 root 999.000s ---------now
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 990.000s ---------now
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 980.000s ---------now
00:00:20.000 * 10.000s 00:00:30.000
00:00:30.000 A1_1_1 970.000s ---------now
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}, push{30, "A1_1_1"}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"A1", 1, sec(9), sec(98)},
{"A1_1", 2, sec(19), sec(98)},
{"A1_1_1", 3, sec(29), sec(98)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 89.000s 00:01:39.000
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 79.000s 00:01:39.000
00:00:20.000 * 10.000s 00:00:30.000
00:00:30.000 A1_1_1 69.000s 00:01:39.000
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}, push{30, "A1_1_1"}, pop{40}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"A1", 1, sec(9), sec(98)},
{"A1_1", 2, sec(19), sec(98)},
{"A1_1_1", 3, sec(29), sec(39)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 89.000s 00:01:39.000
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 79.000s 00:01:39.000
00:00:20.000 * 10.000s 00:00:30.000
00:00:30.000 A1_1_1 10.000s 00:00:40.000
00:00:40.000 * 59.000s 00:01:39.000
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}, push{30, "A1_1_1"}, pop{40}, pop{55}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"A1", 1, sec(9), sec(98)},
{"A1_1", 2, sec(19), sec(54)},
{"A1_1_1", 3, sec(29), sec(39)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 89.000s 00:01:39.000
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 35.000s 00:00:55.000
00:00:20.000 * 10.000s 00:00:30.000
00:00:30.000 A1_1_1 10.000s 00:00:40.000
00:00:40.000 * 15.000s 00:00:55.000
00:00:55.000 * 44.000s 00:01:39.000
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}, push{30, "A1_1_1"}, pop{40}, pop{55}, pop{75}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"A1", 1, sec(9), sec(74)},
{"A1_1", 2, sec(19), sec(54)},
{"A1_1_1", 3, sec(29), sec(39)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 65.000s 00:01:15.000
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 35.000s 00:00:55.000
00:00:20.000 * 10.000s 00:00:30.000
00:00:30.000 A1_1_1 10.000s 00:00:40.000
00:00:40.000 * 15.000s 00:00:55.000
00:00:55.000 * 20.000s 00:01:15.000
00:01:15.000 * 24.000s 00:01:39.000
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}, finish{30}, push{40, "B1"}},
[]Interval{
{"root", 0, sec(0), InvalidDuration},
{"A1", 1, sec(9), sec(29)},
{"A1_1", 2, sec(19), sec(29)},
{"B1", 1, sec(39), InvalidDuration},
},
`
00:00:01.000 root 999.000s ---------now
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 20.000s 00:00:30.000
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 10.000s 00:00:30.000
00:00:30.000 * 10.000s 00:00:40.000
00:00:40.000 B1 960.000s ---------now
`,
},
{
[]op{push{10, "A1"}, push{20, "A1_1"}, finish{30}, push{40, "B1"}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"A1", 1, sec(9), sec(29)},
{"A1_1", 2, sec(19), sec(29)},
{"B1", 1, sec(39), sec(98)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 20.000s 00:00:30.000
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 10.000s 00:00:30.000
00:00:30.000 * 10.000s 00:00:40.000
00:00:40.000 B1 59.000s 00:01:39.000
`,
},
{
[]op{push{10, "foo"}, push{15, "foo1"}, pop{37}, push{37, "foo2"}, pop{55}, pop{55}, push{55, "bar"}, pop{80}, push{80, "baz"}, pop{99}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"foo", 1, sec(9), sec(54)},
{"foo1", 2, sec(14), sec(36)},
{"foo2", 2, sec(36), sec(54)},
{"bar", 1, sec(54), sec(79)},
{"baz", 1, sec(79), sec(98)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 foo 45.000s 00:00:55.000
00:00:10.000 * 5.000s 00:00:15.000
00:00:15.000 foo1 22.000s 00:00:37.000
00:00:37.000 foo2 18.000s 00:00:55.000
00:00:55.000 bar 25.000s 00:01:20.000
00:01:20.000 baz 19.000s 00:01:39.000
`,
},
{
[]op{push{10, "foo"}, push{15, "foo1"}, pop{30}, push{37, "foo2"}, pop{50}, pop{53}, push{55, "bar"}, pop{75}, push{80, "baz"}, pop{90}, finish{99}},
[]Interval{
{"root", 0, sec(0), sec(98)},
{"foo", 1, sec(9), sec(52)},
{"foo1", 2, sec(14), sec(29)},
{"foo2", 2, sec(36), sec(49)},
{"bar", 1, sec(54), sec(74)},
{"baz", 1, sec(79), sec(89)},
},
`
00:00:01.000 root 98.000s 00:01:39.000
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 foo 43.000s 00:00:53.000
00:00:10.000 * 5.000s 00:00:15.000
00:00:15.000 foo1 15.000s 00:00:30.000
00:00:30.000 * 7.000s 00:00:37.000
00:00:37.000 foo2 13.000s 00:00:50.000
00:00:50.000 * 3.000s 00:00:53.000
00:00:53.000 * 2.000s 00:00:55.000
00:00:55.000 bar 20.000s 00:01:15.000
00:01:15.000 * 5.000s 00:01:20.000
00:01:20.000 baz 10.000s 00:01:30.000
00:01:30.000 * 9.000s 00:01:39.000
`,
},
}
for _, test := range tests {
// Run all ops.
now := &fakeNow{1}
nowFunc = now.Now
timer := NewTimer("root")
for _, op := range test.ops {
op.run(now, timer)
}
name := fmt.Sprintf("%#v", test.ops)
// Check all intervals.
if got, want := timer.Intervals, test.intervals; !reflect.DeepEqual(got, want) {
t.Errorf("%s got intervals %v, want %v", name, got, want)
}
// Check string output.
now.now = 1000
if got, want := timer.String(), strings.TrimLeft(test.str, "\n"); got != want {
t.Errorf("%s GOT STRING\n%sWANT\n%s", name, got, want)
}
// Check print output hiding all gaps.
var buf bytes.Buffer
printer := IntervalPrinter{Zero: timer.Zero, MinGap: time.Hour}
if err := printer.Print(&buf, timer.Intervals, nowFunc().Sub(timer.Zero)); err != nil {
t.Errorf("%s got printer error: %v", name, err)
}
if got, want := buf.String(), stripGaps(test.str); got != want {
t.Errorf("%s GOT PRINT\n%sWANT\n%s", name, got, want)
}
}
nowFunc = time.Now
}
// TestIntervalPrinterCornerCases tests corner cases for the printer. These are
// all cases where only a subset of the full Timer intervals is printed.
func TestIntervalPrinterCornerCases(t *testing.T) {
t.Parallel()
tests := []struct {
intervals []Interval
str string
}{
{
[]Interval{{"abc", 1, sec(9), InvalidDuration}},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 abc 990.000s ---------now
`,
},
{
[]Interval{{"abc", 1, sec(9), sec(98)}},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 abc 89.000s 00:01:39.000
`,
},
{
[]Interval{
{"A1", 1, sec(9), InvalidDuration},
{"A1_1", 2, sec(19), InvalidDuration},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 990.000s ---------now
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 980.000s ---------now
`,
},
{
[]Interval{
{"A1", 1, sec(9), InvalidDuration},
{"A1_1", 2, sec(19), sec(49)},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 990.000s ---------now
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 30.000s 00:00:50.000
00:00:50.000 * 950.000s ---------now
`,
},
{
[]Interval{
{"A1", 1, sec(9), sec(98)},
{"A1_1", 2, sec(19), sec(49)},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1 89.000s 00:01:39.000
00:00:10.000 * 10.000s 00:00:20.000
00:00:20.000 A1_1 30.000s 00:00:50.000
00:00:50.000 * 49.000s 00:01:39.000
`,
},
{
[]Interval{
{"A1_1", 2, sec(9), sec(19)},
{"B1", 1, sec(39), InvalidDuration},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1_1 10.000s 00:00:20.000
00:00:20.000 * 20.000s 00:00:40.000
00:00:40.000 B1 960.000s ---------now
`,
},
{
[]Interval{
{"A1_1", 2, sec(9), sec(19)},
{"B1", 1, sec(39), sec(64)},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1_1 10.000s 00:00:20.000
00:00:20.000 * 20.000s 00:00:40.000
00:00:40.000 B1 25.000s 00:01:05.000
`,
},
{
[]Interval{
{"A1_1", 2, sec(9), sec(19)},
{"B1", 1, sec(39), sec(64)},
{"C1", 1, sec(69), sec(84)},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1_1 10.000s 00:00:20.000
00:00:20.000 * 20.000s 00:00:40.000
00:00:40.000 B1 25.000s 00:01:05.000
00:01:05.000 * 5.000s 00:01:10.000
00:01:10.000 C1 15.000s 00:01:25.000
`,
},
{
[]Interval{
{"A1_1", 2, sec(9), sec(19)},
{"B1", 1, sec(39), sec(84)},
{"B1_1", 2, sec(64), sec(69)},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1_1 10.000s 00:00:20.000
00:00:20.000 * 20.000s 00:00:40.000
00:00:40.000 B1 45.000s 00:01:25.000
00:00:40.000 * 25.000s 00:01:05.000
00:01:05.000 B1_1 5.000s 00:01:10.000
00:01:10.000 * 15.000s 00:01:25.000
`,
},
{
[]Interval{
{"A1_1", 2, sec(9), sec(19)},
{"B1", 1, sec(39), sec(89)},
{"B1_1", 2, sec(64), sec(69)},
{"B1_2", 2, sec(79), sec(87)},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1_1 10.000s 00:00:20.000
00:00:20.000 * 20.000s 00:00:40.000
00:00:40.000 B1 50.000s 00:01:30.000
00:00:40.000 * 25.000s 00:01:05.000
00:01:05.000 B1_1 5.000s 00:01:10.000
00:01:10.000 * 10.000s 00:01:20.000
00:01:20.000 B1_2 8.000s 00:01:28.000
00:01:28.000 * 2.000s 00:01:30.000
`,
},
{
[]Interval{
{"A1_1_1", 3, sec(9), sec(19)},
{"B1", 1, sec(39), InvalidDuration},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1_1_1 10.000s 00:00:20.000
00:00:20.000 * 20.000s 00:00:40.000
00:00:40.000 B1 960.000s ---------now
`,
},
{
[]Interval{
{"A1_1_1", 3, sec(9), sec(19)},
{"B1", 1, sec(39), sec(64)},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1_1_1 10.000s 00:00:20.000
00:00:20.000 * 20.000s 00:00:40.000
00:00:40.000 B1 25.000s 00:01:05.000
`,
},
{
[]Interval{
{"A1_1_1", 3, sec(9), sec(19)},
{"B1", 1, sec(39), sec(64)},
{"C1", 1, sec(69), sec(84)},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1_1_1 10.000s 00:00:20.000
00:00:20.000 * 20.000s 00:00:40.000
00:00:40.000 B1 25.000s 00:01:05.000
00:01:05.000 * 5.000s 00:01:10.000
00:01:10.000 C1 15.000s 00:01:25.000
`,
},
{
[]Interval{
{"A1_1_1", 3, sec(9), sec(19)},
{"B1", 1, sec(39), sec(84)},
{"B1_1", 2, sec(59), sec(69)},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1_1_1 10.000s 00:00:20.000
00:00:20.000 * 20.000s 00:00:40.000
00:00:40.000 B1 45.000s 00:01:25.000
00:00:40.000 * 20.000s 00:01:00.000
00:01:00.000 B1_1 10.000s 00:01:10.000
00:01:10.000 * 15.000s 00:01:25.000
`,
},
{
[]Interval{
{"A1_1", 2, sec(9), sec(84)},
{"A1_1_1", 3, sec(39), sec(79)},
{"A1_1_1_1", 4, sec(54), sec(69)},
{"B1", 1, sec(89), sec(99)},
},
`
00:00:01.000 * 9.000s 00:00:10.000
00:00:10.000 A1_1 75.000s 00:01:25.000
00:00:10.000 * 30.000s 00:00:40.000
00:00:40.000 A1_1_1 40.000s 00:01:20.000
00:00:40.000 * 15.000s 00:00:55.000
00:00:55.000 A1_1_1_1 15.000s 00:01:10.000
00:01:10.000 * 10.000s 00:01:20.000
00:01:20.000 * 5.000s 00:01:25.000
00:01:25.000 * 5.000s 00:01:30.000
00:01:30.000 B1 10.000s 00:01:40.000
`,
},
}
for _, test := range tests {
name := fmt.Sprintf("%#v", test.intervals)
// Check print output with gaps.
var buf bytes.Buffer
printer := IntervalPrinter{Zero: tsec(1)}
if err := printer.Print(&buf, test.intervals, sec(999)); err != nil {
t.Errorf("%s got printer error: %v", name, err)
}
if got, want := buf.String(), strings.TrimLeft(test.str, "\n"); got != want {
t.Errorf("%s GOT STRING\n%sWANT\n%s", name, got, want)
}
}
}
func BenchmarkTimerPush(b *testing.B) {
t := NewTimer("root")
for i := 0; i < b.N; i++ {
t.Push("child")
}
}
func BenchmarkTimerPushPop(b *testing.B) {
t := NewTimer("root")
for i := 0; i < b.N; i++ {
timerPushPop(t)
}
}
func timerPushPop(t *Timer) {
t.Push("child1")
t.Pop()
t.Push("child2")
t.Push("child2_1")
t.Pop()
t.Push("child2_2")
t.Pop()
t.Pop()
t.Push("child3")
t.Pop()
}
var randSource = rand.NewSource(123)
func BenchmarkTimerRandom(b *testing.B) {
t, rng := NewTimer("root"), rand.New(randSource)
for i := 0; i < b.N; i++ {
timerRandom(rng, t)
}
}
func timerRandom(rng *rand.Rand, t *Timer) {
switch pct := rng.Intn(100); {
case pct < 60:
timerPushPop(t)
case pct < 90:
t.Push("foo")
case pct < 99:
t.Pop()
default:
t.Finish()
}
}
func BenchmarkTimerString(b *testing.B) {
t, rng, now := NewTimer("root"), rand.New(randSource), &stepNow{0}
nowFunc = now.Now
for i := 0; i < 1000; i++ {
timerRandom(rng, t)
}
t.Finish() // Make sure all intervals are closed.
want := t.String()
b.ResetTimer()
for i := 0; i < b.N; i++ {
if got := t.String(); got != want {
b.Fatalf("GOT\n%sWANT\n%s\nTIMER\n%#v", got, want, t)
}
}
nowFunc = time.Now
}