github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/testing/match_test.go (about) 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 5 package testing 6 7 import ( 8 "fmt" 9 "reflect" 10 "regexp" 11 "strings" 12 "unicode" 13 ) 14 15 func init() { 16 testingTesting = true 17 } 18 19 // Verify that our IsSpace agrees with unicode.IsSpace. 20 func 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 33 func 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 93 func 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 177 var 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 211 func 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 222 func 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. 257 func (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 }