1// Copyright 2017 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
5package testing
6
7import (
8	"bytes"
9	"regexp"
10	"strings"
11)
12
13func TestTBHelper(t *T) {
14	var buf bytes.Buffer
15	ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
16	t1 := &T{
17		common: common{
18			signal: make(chan bool),
19			w:      &buf,
20		},
21		context: ctx,
22	}
23	t1.Run("Test", testHelper)
24
25	want := `--- FAIL: Test (?s)
26helperfuncs_test.go:12: 0
27helperfuncs_test.go:33: 1
28helperfuncs_test.go:21: 2
29helperfuncs_test.go:35: 3
30helperfuncs_test.go:42: 4
31--- FAIL: Test/sub (?s)
32helperfuncs_test.go:45: 5
33helperfuncs_test.go:21: 6
34helperfuncs_test.go:44: 7
35helperfuncs_test.go:56: 8
36helperfuncs_test.go:64: 9
37helperfuncs_test.go:60: 10
38`
39	lines := strings.Split(buf.String(), "\n")
40	durationRE := regexp.MustCompile(`\(.*\)$`)
41	for i, line := range lines {
42		line = strings.TrimSpace(line)
43		line = durationRE.ReplaceAllString(line, "(?s)")
44		lines[i] = line
45	}
46	got := strings.Join(lines, "\n")
47	if got != want {
48		t.Errorf("got output:\n\n%s\nwant:\n\n%s", got, want)
49	}
50}
51
52func TestTBHelperParallel(t *T) {
53	var buf bytes.Buffer
54	ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
55	t1 := &T{
56		common: common{
57			signal: make(chan bool),
58			w:      &buf,
59		},
60		context: ctx,
61	}
62	t1.Run("Test", parallelTestHelper)
63
64	lines := strings.Split(strings.TrimSpace(buf.String()), "\n")
65	if len(lines) != 6 {
66		t.Fatalf("parallelTestHelper gave %d lines of output; want 6", len(lines))
67	}
68	want := "helperfuncs_test.go:21: parallel"
69	if got := strings.TrimSpace(lines[1]); got != want {
70		t.Errorf("got output line %q; want %q", got, want)
71	}
72}
73
74func TestTBHelperLineNumer(t *T) {
75	var buf bytes.Buffer
76	ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
77	t1 := &T{
78		common: common{
79			signal: make(chan bool),
80			w:      &buf,
81		},
82		context: ctx,
83	}
84	t1.Run("Test", func(t *T) {
85		helperA := func(t *T) {
86			t.Helper()
87			t.Run("subtest", func(t *T) {
88				t.Helper()
89				t.Fatal("fatal error message")
90			})
91		}
92		helperA(t)
93	})
94
95	want := "helper_test.go:92: fatal error message"
96	got := ""
97	lines := strings.Split(strings.TrimSpace(buf.String()), "\n")
98	if len(lines) > 0 {
99		got = strings.TrimSpace(lines[len(lines)-1])
100	}
101	if got != want {
102		t.Errorf("got output:\n\n%v\nwant:\n\n%v", got, want)
103	}
104}
105
106type noopWriter int
107
108func (nw *noopWriter) Write(b []byte) (int, error) { return len(b), nil }
109
110func BenchmarkTBHelper(b *B) {
111	w := noopWriter(0)
112	ctx := newTestContext(1, newMatcher(regexp.MatchString, "", ""))
113	t1 := &T{
114		common: common{
115			signal: make(chan bool),
116			w:      &w,
117		},
118		context: ctx,
119	}
120	f1 := func() {
121		t1.Helper()
122	}
123	f2 := func() {
124		t1.Helper()
125	}
126	b.ResetTimer()
127	b.ReportAllocs()
128	for i := 0; i < b.N; i++ {
129		if i&1 == 0 {
130			f1()
131		} else {
132			f2()
133		}
134	}
135}
136