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