Source file src/testing/match_test.go

     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  }
   239  

View as plain text