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  }