1// Copyright 2015 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	"fmt"
9	"reflect"
10	"regexp"
11	"strings"
12	"unicode"
13)
14
15func init() {
16	testingTesting = true
17}
18
19// Verify that our IsSpace agrees with unicode.IsSpace.
20func TestIsSpace(t *T) {
21	n := 0
22	for r := rune(0); r <= unicode.MaxRune; r++ {
23		if isSpace(r) != unicode.IsSpace(r) {
24			t.Errorf("IsSpace(%U)=%t incorrect", r, isSpace(r))
25			n++
26			if n > 10 {
27				return
28			}
29		}
30	}
31}
32
33func TestSplitRegexp(t *T) {
34	res := func(s ...string) filterMatch { return simpleMatch(s) }
35	alt := func(m ...filterMatch) filterMatch { return alternationMatch(m) }
36	testCases := []struct {
37		pattern string
38		result  filterMatch
39	}{
40		// Correct patterns
41		// If a regexp pattern is correct, all split regexps need to be correct
42		// as well.
43		{"", res("")},
44		{"/", res("", "")},
45		{"//", res("", "", "")},
46		{"A", res("A")},
47		{"A/B", res("A", "B")},
48		{"A/B/", res("A", "B", "")},
49		{"/A/B/", res("", "A", "B", "")},
50		{"[A]/(B)", res("[A]", "(B)")},
51		{"[/]/[/]", res("[/]", "[/]")},
52		{"[/]/[:/]", res("[/]", "[:/]")},
53		{"/]", res("", "]")},
54		{"]/", res("]", "")},
55		{"]/[/]", res("]", "[/]")},
56		{`([)/][(])`, res(`([)/][(])`)},
57		{"[(]/[)]", res("[(]", "[)]")},
58
59		{"A/B|C/D", alt(res("A", "B"), res("C", "D"))},
60
61		// Faulty patterns
62		// Errors in original should produce at least one faulty regexp in results.
63		{")/", res(")/")},
64		{")/(/)", res(")/(", ")")},
65		{"a[/)b", res("a[/)b")},
66		{"(/]", res("(/]")},
67		{"(/", res("(/")},
68		{"[/]/[/", res("[/]", "[/")},
69		{`\p{/}`, res(`\p{`, "}")},
70		{`\p/`, res(`\p`, "")},
71		{`[[:/:]]`, res(`[[:/:]]`)},
72	}
73	for _, tc := range testCases {
74		a := splitRegexp(tc.pattern)
75		if !reflect.DeepEqual(a, tc.result) {
76			t.Errorf("splitRegexp(%q) = %#v; want %#v", tc.pattern, a, tc.result)
77		}
78
79		// If there is any error in the pattern, one of the returned subpatterns
80		// needs to have an error as well.
81		if _, err := regexp.Compile(tc.pattern); err != nil {
82			ok := true
83			if err := a.verify("", regexp.MatchString); err != nil {
84				ok = false
85			}
86			if ok {
87				t.Errorf("%s: expected error in any of %q", tc.pattern, a)
88			}
89		}
90	}
91}
92
93func TestMatcher(t *T) {
94	testCases := []struct {
95		pattern     string
96		skip        string
97		parent, sub string
98		ok          bool
99		partial     bool
100	}{
101		// Behavior without subtests.
102		{"", "", "", "TestFoo", true, false},
103		{"TestFoo", "", "", "TestFoo", true, false},
104		{"TestFoo/", "", "", "TestFoo", true, true},
105		{"TestFoo/bar/baz", "", "", "TestFoo", true, true},
106		{"TestFoo", "", "", "TestBar", false, false},
107		{"TestFoo/", "", "", "TestBar", false, false},
108		{"TestFoo/bar/baz", "", "", "TestBar/bar/baz", false, false},
109		{"", "TestBar", "", "TestFoo", true, false},
110		{"", "TestBar", "", "TestBar", false, false},
111
112		// Skipping a non-existent test doesn't change anything.
113		{"", "TestFoo/skipped", "", "TestFoo", true, false},
114		{"TestFoo", "TestFoo/skipped", "", "TestFoo", true, false},
115		{"TestFoo/", "TestFoo/skipped", "", "TestFoo", true, true},
116		{"TestFoo/bar/baz", "TestFoo/skipped", "", "TestFoo", true, true},
117		{"TestFoo", "TestFoo/skipped", "", "TestBar", false, false},
118		{"TestFoo/", "TestFoo/skipped", "", "TestBar", false, false},
119		{"TestFoo/bar/baz", "TestFoo/skipped", "", "TestBar/bar/baz", false, false},
120
121		// with subtests
122		{"", "", "TestFoo", "x", true, false},
123		{"TestFoo", "", "TestFoo", "x", true, false},
124		{"TestFoo/", "", "TestFoo", "x", true, false},
125		{"TestFoo/bar/baz", "", "TestFoo", "bar", true, true},
126
127		{"", "TestFoo/skipped", "TestFoo", "x", true, false},
128		{"TestFoo", "TestFoo/skipped", "TestFoo", "x", true, false},
129		{"TestFoo", "TestFoo/skipped", "TestFoo", "skipped", false, false},
130		{"TestFoo/", "TestFoo/skipped", "TestFoo", "x", true, false},
131		{"TestFoo/bar/baz", "TestFoo/skipped", "TestFoo", "bar", true, true},
132
133		// Subtest with a '/' in its name still allows for copy and pasted names
134		// to match.
135		{"TestFoo/bar/baz", "", "TestFoo", "bar/baz", true, false},
136		{"TestFoo/bar/baz", "TestFoo/bar/baz", "TestFoo", "bar/baz", false, false},
137		{"TestFoo/bar/baz", "TestFoo/bar/baz/skip", "TestFoo", "bar/baz", true, false},
138		{"TestFoo/bar/baz", "", "TestFoo/bar", "baz", true, false},
139		{"TestFoo/bar/baz", "", "TestFoo", "x", false, false},
140		{"TestFoo", "", "TestBar", "x", false, false},
141		{"TestFoo/", "", "TestBar", "x", false, false},
142		{"TestFoo/bar/baz", "", "TestBar", "x/bar/baz", false, false},
143
144		{"A/B|C/D", "", "TestA", "B", true, false},
145		{"A/B|C/D", "", "TestC", "D", true, false},
146		{"A/B|C/D", "", "TestA", "C", false, false},
147
148		// subtests only
149		{"", "", "TestFoo", "x", true, false},
150		{"/", "", "TestFoo", "x", true, false},
151		{"./", "", "TestFoo", "x", true, false},
152		{"./.", "", "TestFoo", "x", true, false},
153		{"/bar/baz", "", "TestFoo", "bar", true, true},
154		{"/bar/baz", "", "TestFoo", "bar/baz", true, false},
155		{"//baz", "", "TestFoo", "bar/baz", true, false},
156		{"//", "", "TestFoo", "bar/baz", true, false},
157		{"/bar/baz", "", "TestFoo/bar", "baz", true, false},
158		{"//foo", "", "TestFoo", "bar/baz", false, false},
159		{"/bar/baz", "", "TestFoo", "x", false, false},
160		{"/bar/baz", "", "TestBar", "x/bar/baz", false, false},
161	}
162
163	for _, tc := range testCases {
164		m := newMatcher(regexp.MatchString, tc.pattern, "-test.run", tc.skip)
165
166		parent := &common{name: tc.parent}
167		if tc.parent != "" {
168			parent.level = 1
169		}
170		if n, ok, partial := m.fullName(parent, tc.sub); ok != tc.ok || partial != tc.partial {
171			t.Errorf("for pattern %q, fullName(parent=%q, sub=%q) = %q, ok %v partial %v; want ok %v partial %v",
172				tc.pattern, tc.parent, tc.sub, n, ok, partial, tc.ok, tc.partial)
173		}
174	}
175}
176
177var namingTestCases = []struct{ name, want string }{
178	// Uniqueness
179	{"", "x/#00"},
180	{"", "x/#01"},
181	{"#0", "x/#0"},      // Doesn't conflict with #00 because the number of digits differs.
182	{"#00", "x/#00#01"}, // Conflicts with implicit #00 (used above), so add a suffix.
183	{"#", "x/#"},
184	{"#", "x/##01"},
185
186	{"t", "x/t"},
187	{"t", "x/t#01"},
188	{"t", "x/t#02"},
189	{"t#00", "x/t#00"}, // Explicit "#00" doesn't conflict with the unsuffixed first subtest.
190
191	{"a#01", "x/a#01"},    // user has subtest with this name.
192	{"a", "x/a"},          // doesn't conflict with this name.
193	{"a", "x/a#02"},       // This string is claimed now, so resume
194	{"a", "x/a#03"},       // with counting.
195	{"a#02", "x/a#02#01"}, // We already used a#02 once, so add a suffix.
196
197	{"b#00", "x/b#00"},
198	{"b", "x/b"}, // Implicit 0 doesn't conflict with explicit "#00".
199	{"b", "x/b#01"},
200	{"b#9223372036854775807", "x/b#9223372036854775807"}, // MaxInt64
201	{"b", "x/b#02"},
202	{"b", "x/b#03"},
203
204	// Sanitizing
205	{"A:1 B:2", "x/A:1_B:2"},
206	{"s\t\r\u00a0", "x/s___"},
207	{"\x01", `x/\x01`},
208	{"\U0010ffff", `x/\U0010ffff`},
209}
210
211func TestNaming(t *T) {
212	m := newMatcher(regexp.MatchString, "", "", "")
213	parent := &common{name: "x", level: 1} // top-level test.
214
215	for i, tc := range namingTestCases {
216		if got, _, _ := m.fullName(parent, tc.name); got != tc.want {
217			t.Errorf("%d:%s: got %q; want %q", i, tc.name, got, tc.want)
218		}
219	}
220}
221
222func FuzzNaming(f *F) {
223	for _, tc := range namingTestCases {
224		f.Add(tc.name)
225	}
226	parent := &common{name: "x", level: 1}
227	var m *matcher
228	var seen map[string]string
229	reset := func() {
230		m = allMatcher()
231		seen = make(map[string]string)
232	}
233	reset()
234
235	f.Fuzz(func(t *T, subname string) {
236		if len(subname) > 10 {
237			// Long names attract the OOM killer.
238			t.Skip()
239		}
240		name := m.unique(parent.name, subname)
241		if !strings.Contains(name, "/"+subname) {
242			t.Errorf("name %q does not contain subname %q", name, subname)
243		}
244		if prev, ok := seen[name]; ok {
245			t.Errorf("name %q generated by both %q and %q", name, prev, subname)
246		}
247		if len(seen) > 1e6 {
248			// Free up memory.
249			reset()
250		}
251		seen[name] = subname
252	})
253}
254
255// GoString returns a string that is more readable than the default, which makes
256// it easier to read test errors.
257func (m alternationMatch) GoString() string {
258	s := make([]string, len(m))
259	for i, m := range m {
260		s[i] = fmt.Sprintf("%#v", m)
261	}
262	return fmt.Sprintf("(%s)", strings.Join(s, " | "))
263}
264