Copyright 2015 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package testing

import (
	
	
	
	
	
)
matcher sanitizes, uniques, and filters names of subtests and subbenchmarks.
type matcher struct {
	filter    []string
	matchFunc func(pat, str string) (bool, error)

	mu       sync.Mutex
	subNames map[string]int64
}
TODO: fix test_main to avoid race and improve caching, also allowing to eliminate this Mutex.
var matchMutex sync.Mutex

func ( func(,  string) (bool, error), ,  string) *matcher {
	var  []string
	if  != "" {
		 = splitRegexp()
		for ,  := range  {
			[] = rewrite()
Verify filters before doing any processing.
		for ,  := range  {
			if ,  := (, "non-empty");  != nil {
				fmt.Fprintf(os.Stderr, "testing: invalid regexp for element %d of %s (%q): %s\n", , , , )
				os.Exit(1)
			}
		}
	}
	return &matcher{
		filter:    ,
		matchFunc: ,
		subNames:  map[string]int64{},
	}
}

func ( *matcher) ( *common,  string) ( string, ,  bool) {
	 = 

	.mu.Lock()
	defer .mu.Unlock()

	if  != nil && .level > 0 {
		 = .unique(.name, rewrite())
	}

	matchMutex.Lock()
	defer matchMutex.Unlock()
We check the full array of paths each time to allow for the case that a pattern contains a '/'.
	 := strings.Split(, "/")
	for ,  := range  {
		if  >= len(.filter) {
			break
		}
		if ,  := .matchFunc(.filter[], ); ! {
			return , false, false
		}
	}
	return , true, len() < len(.filter)
}

func ( string) []string {
	 := make([]string, 0, strings.Count(, "/"))
	 := 0
	 := 0
	for  := 0;  < len(); {
		switch [] {
		case '[':
			++
		case ']':
			if --;  < 0 { // An unmatched ']' is legal.
				 = 0
			}
		case '(':
			if  == 0 {
				++
			}
		case ')':
			if  == 0 {
				--
			}
		case '\\':
			++
		case '/':
			if  == 0 &&  == 0 {
				 = append(, [:])
				 = [+1:]
				 = 0
				continue
			}
		}
		++
	}
	return append(, )
}
unique creates a unique name for the given parent and subname by affixing it with one or more counts, if necessary.
func ( *matcher) (,  string) string {
	 := fmt.Sprintf("%s/%s", , )
	 :=  == ""
	for {
		,  := .subNames[]
		if ! && ! {
			.subNames[] = 1 // next count is 1
			return 
Name was already used. We increment with the count and append a string with the count.
		.subNames[] =  + 1
Add a count to guarantee uniqueness.
		 = fmt.Sprintf("%s#%02d", , )
		 = false
	}
}
rewrite rewrites a subname to having only printable characters and no white space.
func ( string) string {
	 := []byte{}
	for ,  := range  {
		switch {
		case isSpace():
			 = append(, '_')
		case !strconv.IsPrint():
			 := strconv.QuoteRune()
			 = append(, [1:len()-1]...)
		default:
			 = append(, string()...)
		}
	}
	return string()
}

func ( rune) bool {
	if  < 0x2000 {
Note: not the same as Unicode Z class.
		case '\t', '\n', '\v', '\f', '\r', ' ', 0x85, 0xA0, 0x1680:
			return true
		}
	} else {
		if  <= 0x200a {
			return true
		}
		switch  {
		case 0x2028, 0x2029, 0x202f, 0x205f, 0x3000:
			return true
		}
	}
	return false