github.com/m10x/go/src@v0.0.0-20220112094212-ba61592315da/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 parent, sub string 93 ok bool 94 partial bool 95 }{ 96 // Behavior without subtests. 97 {"", "", "TestFoo", true, false}, 98 {"TestFoo", "", "TestFoo", true, false}, 99 {"TestFoo/", "", "TestFoo", true, true}, 100 {"TestFoo/bar/baz", "", "TestFoo", true, true}, 101 {"TestFoo", "", "TestBar", false, false}, 102 {"TestFoo/", "", "TestBar", false, false}, 103 {"TestFoo/bar/baz", "", "TestBar/bar/baz", false, false}, 104 105 // with subtests 106 {"", "TestFoo", "x", true, false}, 107 {"TestFoo", "TestFoo", "x", true, false}, 108 {"TestFoo/", "TestFoo", "x", true, false}, 109 {"TestFoo/bar/baz", "TestFoo", "bar", true, true}, 110 // Subtest with a '/' in its name still allows for copy and pasted names 111 // to match. 112 {"TestFoo/bar/baz", "TestFoo", "bar/baz", true, false}, 113 {"TestFoo/bar/baz", "TestFoo/bar", "baz", true, false}, 114 {"TestFoo/bar/baz", "TestFoo", "x", false, false}, 115 {"TestFoo", "TestBar", "x", false, false}, 116 {"TestFoo/", "TestBar", "x", false, false}, 117 {"TestFoo/bar/baz", "TestBar", "x/bar/baz", false, false}, 118 119 {"A/B|C/D", "TestA", "B", true, false}, 120 {"A/B|C/D", "TestC", "D", true, false}, 121 {"A/B|C/D", "TestA", "C", false, false}, 122 123 // subtests only 124 {"", "TestFoo", "x", true, false}, 125 {"/", "TestFoo", "x", true, false}, 126 {"./", "TestFoo", "x", true, false}, 127 {"./.", "TestFoo", "x", true, false}, 128 {"/bar/baz", "TestFoo", "bar", true, true}, 129 {"/bar/baz", "TestFoo", "bar/baz", true, false}, 130 {"//baz", "TestFoo", "bar/baz", true, false}, 131 {"//", "TestFoo", "bar/baz", true, false}, 132 {"/bar/baz", "TestFoo/bar", "baz", true, false}, 133 {"//foo", "TestFoo", "bar/baz", false, false}, 134 {"/bar/baz", "TestFoo", "x", false, false}, 135 {"/bar/baz", "TestBar", "x/bar/baz", false, false}, 136 } 137 138 for _, tc := range testCases { 139 m := newMatcher(regexp.MatchString, tc.pattern, "-test.run") 140 141 parent := &common{name: tc.parent} 142 if tc.parent != "" { 143 parent.level = 1 144 } 145 if n, ok, partial := m.fullName(parent, tc.sub); ok != tc.ok || partial != tc.partial { 146 t.Errorf("for pattern %q, fullName(parent=%q, sub=%q) = %q, ok %v partial %v; want ok %v partial %v", 147 tc.pattern, tc.parent, tc.sub, n, ok, partial, tc.ok, tc.partial) 148 } 149 } 150 } 151 152 var namingTestCases = []struct{ name, want string }{ 153 // Uniqueness 154 {"", "x/#00"}, 155 {"", "x/#01"}, 156 {"#0", "x/#0"}, // Doesn't conflict with #00 because the number of digits differs. 157 {"#00", "x/#00#01"}, // Conflicts with implicit #00 (used above), so add a suffix. 158 {"#", "x/#"}, 159 {"#", "x/##01"}, 160 161 {"t", "x/t"}, 162 {"t", "x/t#01"}, 163 {"t", "x/t#02"}, 164 {"t#00", "x/t#00"}, // Explicit "#00" doesn't conflict with the unsuffixed first subtest. 165 166 {"a#01", "x/a#01"}, // user has subtest with this name. 167 {"a", "x/a"}, // doesn't conflict with this name. 168 {"a", "x/a#02"}, // This string is claimed now, so resume 169 {"a", "x/a#03"}, // with counting. 170 {"a#02", "x/a#02#01"}, // We already used a#02 once, so add a suffix. 171 172 {"b#00", "x/b#00"}, 173 {"b", "x/b"}, // Implicit 0 doesn't conflict with explicit "#00". 174 {"b", "x/b#01"}, 175 {"b#9223372036854775807", "x/b#9223372036854775807"}, // MaxInt64 176 {"b", "x/b#02"}, 177 {"b", "x/b#03"}, 178 179 // Sanitizing 180 {"A:1 B:2", "x/A:1_B:2"}, 181 {"s\t\r\u00a0", "x/s___"}, 182 {"\x01", `x/\x01`}, 183 {"\U0010ffff", `x/\U0010ffff`}, 184 } 185 186 func TestNaming(t *T) { 187 m := newMatcher(regexp.MatchString, "", "") 188 parent := &common{name: "x", level: 1} // top-level test. 189 190 for i, tc := range namingTestCases { 191 if got, _, _ := m.fullName(parent, tc.name); got != tc.want { 192 t.Errorf("%d:%s: got %q; want %q", i, tc.name, got, tc.want) 193 } 194 } 195 } 196 197 func FuzzNaming(f *F) { 198 for _, tc := range namingTestCases { 199 f.Add(tc.name) 200 } 201 parent := &common{name: "x", level: 1} 202 var m *matcher 203 var seen map[string]string 204 reset := func() { 205 m = newMatcher(regexp.MatchString, "", "") 206 seen = make(map[string]string) 207 } 208 reset() 209 210 f.Fuzz(func(t *T, subname string) { 211 if len(subname) > 10 { 212 // Long names attract the OOM killer. 213 t.Skip() 214 } 215 name := m.unique(parent.name, subname) 216 if !strings.Contains(name, "/"+subname) { 217 t.Errorf("name %q does not contain subname %q", name, subname) 218 } 219 if prev, ok := seen[name]; ok { 220 t.Errorf("name %q generated by both %q and %q", name, prev, subname) 221 } 222 if len(seen) > 1e6 { 223 // Free up memory. 224 reset() 225 } 226 seen[name] = subname 227 }) 228 } 229 230 // GoString returns a string that is more readable than the default, which makes 231 // it easier to read test errors. 232 func (m alternationMatch) GoString() string { 233 s := make([]string, len(m)) 234 for i, m := range m { 235 s[i] = fmt.Sprintf("%#v", m) 236 } 237 return fmt.Sprintf("(%s)", strings.Join(s, " | ")) 238 }