libgo: update to Go 1.11
[official-gcc.git] / libgo / go / testing / match.go
blobb18c6e7f389ac64bfa10056ac958f69c50003eb9
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.
5 package testing
7 import (
8 "fmt"
9 "os"
10 "strconv"
11 "strings"
12 "sync"
15 // matcher sanitizes, uniques, and filters names of subtests and subbenchmarks.
16 type matcher struct {
17 filter []string
18 matchFunc func(pat, str string) (bool, error)
20 mu sync.Mutex
21 subNames map[string]int64
24 // TODO: fix test_main to avoid race and improve caching, also allowing to
25 // eliminate this Mutex.
26 var matchMutex sync.Mutex
28 func newMatcher(matchString func(pat, str string) (bool, error), patterns, name string) *matcher {
29 var filter []string
30 if patterns != "" {
31 filter = splitRegexp(patterns)
32 for i, s := range filter {
33 filter[i] = rewrite(s)
35 // Verify filters before doing any processing.
36 for i, s := range filter {
37 if _, err := matchString(s, "non-empty"); err != nil {
38 fmt.Fprintf(os.Stderr, "testing: invalid regexp for element %d of %s (%q): %s\n", i, name, s, err)
39 os.Exit(1)
43 return &matcher{
44 filter: filter,
45 matchFunc: matchString,
46 subNames: map[string]int64{},
50 func (m *matcher) fullName(c *common, subname string) (name string, ok, partial bool) {
51 name = subname
53 m.mu.Lock()
54 defer m.mu.Unlock()
56 if c != nil && c.level > 0 {
57 name = m.unique(c.name, rewrite(subname))
60 matchMutex.Lock()
61 defer matchMutex.Unlock()
63 // We check the full array of paths each time to allow for the case that
64 // a pattern contains a '/'.
65 elem := strings.Split(name, "/")
66 for i, s := range elem {
67 if i >= len(m.filter) {
68 break
70 if ok, _ := m.matchFunc(m.filter[i], s); !ok {
71 return name, false, false
74 return name, true, len(elem) < len(m.filter)
77 func splitRegexp(s string) []string {
78 a := make([]string, 0, strings.Count(s, "/"))
79 cs := 0
80 cp := 0
81 for i := 0; i < len(s); {
82 switch s[i] {
83 case '[':
84 cs++
85 case ']':
86 if cs--; cs < 0 { // An unmatched ']' is legal.
87 cs = 0
89 case '(':
90 if cs == 0 {
91 cp++
93 case ')':
94 if cs == 0 {
95 cp--
97 case '\\':
98 i++
99 case '/':
100 if cs == 0 && cp == 0 {
101 a = append(a, s[:i])
102 s = s[i+1:]
103 i = 0
104 continue
109 return append(a, s)
112 // unique creates a unique name for the given parent and subname by affixing it
113 // with one or more counts, if necessary.
114 func (m *matcher) unique(parent, subname string) string {
115 name := fmt.Sprintf("%s/%s", parent, subname)
116 empty := subname == ""
117 for {
118 next, exists := m.subNames[name]
119 if !empty && !exists {
120 m.subNames[name] = 1 // next count is 1
121 return name
123 // Name was already used. We increment with the count and append a
124 // string with the count.
125 m.subNames[name] = next + 1
127 // Add a count to guarantee uniqueness.
128 name = fmt.Sprintf("%s#%02d", name, next)
129 empty = false
133 // rewrite rewrites a subname to having only printable characters and no white
134 // space.
135 func rewrite(s string) string {
136 b := []byte{}
137 for _, r := range s {
138 switch {
139 case isSpace(r):
140 b = append(b, '_')
141 case !strconv.IsPrint(r):
142 s := strconv.QuoteRune(r)
143 b = append(b, s[1:len(s)-1]...)
144 default:
145 b = append(b, string(r)...)
148 return string(b)
151 func isSpace(r rune) bool {
152 if r < 0x2000 {
153 switch r {
154 // Note: not the same as Unicode Z class.
155 case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0, 0x1680:
156 return true
158 } else {
159 if r <= 0x200a {
160 return true
162 switch r {
163 case 0x2028, 0x2029, 0x202f, 0x205f, 0x3000:
164 return true
167 return false