| // Copyright 2020 The Go 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 eventtest | 
 |  | 
 | import ( | 
 | 	"context" | 
 | 	"io" | 
 | 	"strings" | 
 | 	"testing" | 
 |  | 
 | 	"github.com/google/go-cmp/cmp" | 
 | 	"golang.org/x/exp/event/adapter/logfmt" | 
 | ) | 
 |  | 
 | type Info struct { | 
 | 	Name string | 
 | 	Msg  string | 
 | 	Msgf string | 
 | } | 
 |  | 
 | type Hooks struct { | 
 | 	AStart func(ctx context.Context, a int) context.Context | 
 | 	AEnd   func(ctx context.Context) | 
 | 	BStart func(ctx context.Context, b string) context.Context | 
 | 	BEnd   func(ctx context.Context) | 
 | } | 
 |  | 
 | var ( | 
 | 	initialList = []int{0, 1, 22, 333, 4444, 55555, 666666, 7777777} | 
 | 	stringList  = []string{ | 
 | 		"A value", | 
 | 		"Some other value", | 
 | 		"A nice longer value but not too long", | 
 | 		"V", | 
 | 		" ", | 
 | 		"ı", | 
 | 		"prime count of values", | 
 | 	} | 
 |  | 
 | 	A = Info{ | 
 | 		Name: "A", | 
 | 		Msg:  "a", | 
 | 		Msgf: "a where A=%d", | 
 | 	} | 
 |  | 
 | 	B = Info{ | 
 | 		Name: "B", | 
 | 		Msg:  "b", | 
 | 		Msgf: "b where B=%q", | 
 | 	} | 
 | ) | 
 |  | 
 | const ( | 
 | 	TimeFormat = logfmt.TimeFormat | 
 |  | 
 | 	LogfmtOutput = ` | 
 | time="2020/03/05 14:27:48" level=info A=0 msg=a | 
 | time="2020/03/05 14:27:49" level=info B="A value" msg=b | 
 | time="2020/03/05 14:27:50" level=info A=1 msg=a | 
 | time="2020/03/05 14:27:51" level=info B="Some other value" msg=b | 
 | time="2020/03/05 14:27:52" level=info A=22 msg=a | 
 | time="2020/03/05 14:27:53" level=info B="Some other value" msg=b | 
 | time="2020/03/05 14:27:54" level=info A=333 msg=a | 
 | time="2020/03/05 14:27:55" level=info B=" " msg=b | 
 | time="2020/03/05 14:27:56" level=info A=4444 msg=a | 
 | time="2020/03/05 14:27:57" level=info B="prime count of values" msg=b | 
 | time="2020/03/05 14:27:58" level=info A=55555 msg=a | 
 | time="2020/03/05 14:27:59" level=info B=V msg=b | 
 | time="2020/03/05 14:28:00" level=info A=666666 msg=a | 
 | time="2020/03/05 14:28:01" level=info B="A value" msg=b | 
 | time="2020/03/05 14:28:02" level=info A=7777777 msg=a | 
 | time="2020/03/05 14:28:03" level=info B="A value" msg=b | 
 | ` | 
 |  | 
 | 	LogfOutput = ` | 
 | time="2020/03/05 14:27:48" level=info msg="a where A=0" | 
 | time="2020/03/05 14:27:49" level=info msg="b where B=\"A value\"" | 
 | time="2020/03/05 14:27:50" level=info msg="a where A=1" | 
 | time="2020/03/05 14:27:51" level=info msg="b where B=\"Some other value\"" | 
 | time="2020/03/05 14:27:52" level=info msg="a where A=22" | 
 | time="2020/03/05 14:27:53" level=info msg="b where B=\"Some other value\"" | 
 | time="2020/03/05 14:27:54" level=info msg="a where A=333" | 
 | time="2020/03/05 14:27:55" level=info msg="b where B=\" \"" | 
 | time="2020/03/05 14:27:56" level=info msg="a where A=4444" | 
 | time="2020/03/05 14:27:57" level=info msg="b where B=\"prime count of values\"" | 
 | time="2020/03/05 14:27:58" level=info msg="a where A=55555" | 
 | time="2020/03/05 14:27:59" level=info msg="b where B=\"V\"" | 
 | time="2020/03/05 14:28:00" level=info msg="a where A=666666" | 
 | time="2020/03/05 14:28:01" level=info msg="b where B=\"A value\"" | 
 | time="2020/03/05 14:28:02" level=info msg="a where A=7777777" | 
 | time="2020/03/05 14:28:03" level=info msg="b where B=\"A value\"" | 
 | ` | 
 | ) | 
 |  | 
 | type namedBenchmark struct { | 
 | 	name string | 
 | 	test func(ctx context.Context) func(*testing.B) | 
 | } | 
 |  | 
 | func benchA(ctx context.Context, hooks Hooks, a int) int { | 
 | 	ctx = hooks.AStart(ctx, a) | 
 | 	defer hooks.AEnd(ctx) | 
 | 	return benchB(ctx, hooks, a, stringList[a%len(stringList)]) | 
 | } | 
 |  | 
 | func benchB(ctx context.Context, hooks Hooks, a int, b string) int { | 
 | 	ctx = hooks.BStart(ctx, b) | 
 | 	defer hooks.BEnd(ctx) | 
 | 	return a + len(b) | 
 | } | 
 |  | 
 | func runOnce(ctx context.Context, hooks Hooks) { | 
 | 	var acc int | 
 | 	for _, value := range initialList { | 
 | 		acc += benchA(ctx, hooks, value) | 
 | 	} | 
 | } | 
 |  | 
 | func RunBenchmark(b *testing.B, ctx context.Context, hooks Hooks) { | 
 | 	b.ResetTimer() | 
 | 	for i := 0; i < b.N; i++ { | 
 | 		runOnce(ctx, hooks) | 
 | 	} | 
 | } | 
 |  | 
 | func TestBenchmark(t *testing.T, f func(io.Writer) context.Context, hooks Hooks, expect string) { | 
 | 	buf := strings.Builder{} | 
 | 	ctx := f(&buf) | 
 | 	runOnce(ctx, hooks) | 
 | 	got := strings.TrimSpace(buf.String()) | 
 | 	expect = strings.TrimSpace(expect) | 
 | 	if diff := cmp.Diff(got, expect); diff != "" { | 
 | 		t.Error(diff) | 
 | 	} | 
 | } | 
 |  | 
 | func TestAllocs(t *testing.T, f func(io.Writer) context.Context, hooks Hooks, expect int) { | 
 | 	t.Helper() | 
 | 	var acc int | 
 | 	ctx := f(io.Discard) | 
 | 	got := int(testing.AllocsPerRun(5, func() { | 
 | 		for _, value := range initialList { | 
 | 			acc += benchA(ctx, hooks, value) | 
 | 		} | 
 | 	})) | 
 | 	if got != expect { | 
 | 		t.Errorf("Got %d allocs, expect %d", got, expect) | 
 | 	} | 
 | } |