github.com/gnolang/gno@v0.0.0-20240520182011-228e9d0192ce/gnovm/stdlibs/testing/match.gno (about) 1 package testing 2 3 // Most of the code in this file is extracted from golang's src/testing/match.go. 4 // 5 // Copyright 2015 The Go Authors. All rights reserved. 6 // Use of this source code is governed by a BSD-style 7 // license that can be found in the LICENSE file. 8 9 import ( 10 "fmt" 11 "regexp" 12 "strconv" 13 "strings" 14 "unicode" 15 ) 16 17 type filterMatch interface { 18 // matches checks the name against the receiver's pattern strings using the 19 // given match function. 20 matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) 21 22 // verify checks that the receiver's pattern strings are valid filters by 23 // calling the given match function. 24 verify(name string, matchString func(pat, str string) (bool, error)) error 25 } 26 27 // simpleMatch matches a test name if all of the pattern strings match in 28 // sequence. 29 type simpleMatch []string 30 31 // alternationMatch matches a test name if one of the alternations match. 32 type alternationMatch []filterMatch 33 34 func (m simpleMatch) matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) { 35 for i, s := range name { 36 if i >= len(m) { 37 break 38 } 39 if ok, _ := matchString(m[i], s); !ok { 40 return false, false 41 } 42 } 43 return true, len(name) < len(m) 44 } 45 46 func (m simpleMatch) verify(name string, matchString func(pat, str string) (bool, error)) error { 47 for i, s := range m { 48 m[i] = rewrite(s) 49 } 50 // Verify filters before doing any processing. 51 for i, s := range m { 52 if _, err := matchString(s, "non-empty"); err != nil { 53 return fmt.Errorf("element %d of %s (%q): %s", i, name, s, err) 54 } 55 } 56 return nil 57 } 58 59 func (m alternationMatch) matches(name []string, matchString func(pat, str string) (bool, error)) (ok, partial bool) { 60 for _, m := range m { 61 if ok, partial = m.matches(name, matchString); ok { 62 return ok, partial 63 } 64 } 65 return false, false 66 } 67 68 func (m alternationMatch) verify(name string, matchString func(pat, str string) (bool, error)) error { 69 for i, m := range m { 70 if err := m.verify(name, matchString); err != nil { 71 return fmt.Errorf("alternation %d of %s", i, err) 72 } 73 } 74 return nil 75 } 76 77 func splitRegexp(s string) filterMatch { 78 a := make(simpleMatch, 0, strings.Count(s, "/")) 79 b := make(alternationMatch, 0, strings.Count(s, "|")) 80 cs := 0 81 cp := 0 82 for i := 0; i < len(s); { 83 switch s[i] { 84 case '[': 85 cs++ 86 case ']': 87 if cs--; cs < 0 { // An unmatched ']' is legal. 88 cs = 0 89 } 90 case '(': 91 if cs == 0 { 92 cp++ 93 } 94 case ')': 95 if cs == 0 { 96 cp-- 97 } 98 case '\\': 99 i++ 100 case '/': 101 if cs == 0 && cp == 0 { 102 a = append(a, s[:i]) 103 s = s[i+1:] 104 i = 0 105 continue 106 } 107 case '|': 108 if cs == 0 && cp == 0 { 109 a = append(a, s[:i]) 110 s = s[i+1:] 111 i = 0 112 b = append(b, a) 113 a = make(simpleMatch, 0, len(a)) 114 continue 115 } 116 } 117 i++ 118 } 119 120 a = append(a, s) 121 if len(b) == 0 { 122 return a 123 } 124 return append(b, a) 125 } 126 127 // rewrite rewrites a subname to having only printable characters and no white 128 // space. 129 func rewrite(s string) string { 130 b := []byte{} 131 for _, r := range s { 132 switch { 133 case isSpace(r): 134 b = append(b, '_') 135 case !unicode.IsPrint(r): 136 s := simpleQuoteRune(r) 137 b = append(b, s[1:len(s)-1]...) 138 default: 139 b = append(b, string(r)...) 140 } 141 } 142 return string(b) 143 } 144 145 // simpleQuoteRune does not follow the original strconv.QuoteRune. 146 func simpleQuoteRune(r rune) string { 147 return "." 148 } 149 150 func isSpace(r rune) bool { 151 if r < 0x2000 { 152 switch r { 153 // Note: not the same as Unicode Z class. 154 case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0, 0x1680: 155 return true 156 } 157 } else { 158 if r <= 0x200a { 159 return true 160 } 161 switch r { 162 case 0x2028, 0x2029, 0x202f, 0x205f, 0x3000: 163 return true 164 } 165 } 166 return false 167 } 168 169 var ( 170 matchPat string 171 matchRe *regexp.Regexp 172 ) 173 174 // based on testing/internal/testdeps.TestDeps.MatchString. 175 func matchString(pat, str string) (result bool, err error) { 176 if matchRe == nil || matchPat != pat { 177 matchPat = pat 178 matchRe, err = regexp.Compile(matchPat) 179 if err != nil { 180 return 181 } 182 } 183 return matchRe.MatchString(str), nil 184 }