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  func init() {
    16  	testingTesting = true
    17  }
    18  
    19  // Verify that our IsSpace agrees with unicode.IsSpace.
    20  func TestIsSpace(t *T) {
    21  	n := 0
    22  	for r := rune(0); r <= unicode.MaxRune; r++ {
    23  		if isSpace(r) != unicode.IsSpace(r) {
    24  			t.Errorf("IsSpace(%U)=%t incorrect", r, isSpace(r))
    25  			n++
    26  			if n > 10 {
    27  				return
    28  			}
    29  		}
    30  	}
    31  }
    32  
    33  func TestSplitRegexp(t *T) {
    34  	res := func(s ...string) filterMatch { return simpleMatch(s) }
    35  	alt := func(m ...filterMatch) filterMatch { return alternationMatch(m) }
    36  	testCases := []struct {
    37  		pattern string
    38  		result  filterMatch
    39  	}{
    40  		// Correct patterns
    41  		// If a regexp pattern is correct, all split regexps need to be correct
    42  		// as well.
    43  		{"", res("")},
    44  		{"/", res("", "")},
    45  		{"//", res("", "", "")},
    46  		{"A", res("A")},
    47  		{"A/B", res("A", "B")},
    48  		{"A/B/", res("A", "B", "")},
    49  		{"/A/B/", res("", "A", "B", "")},
    50  		{"[A]/(B)", res("[A]", "(B)")},
    51  		{"[/]/[/]", res("[/]", "[/]")},
    52  		{"[/]/[:/]", res("[/]", "[:/]")},
    53  		{"/]", res("", "]")},
    54  		{"]/", res("]", "")},
    55  		{"]/[/]", res("]", "[/]")},
    56  		{`([)/][(])`, res(`([)/][(])`)},
    57  		{"[(]/[)]", res("[(]", "[)]")},
    58  
    59  		{"A/B|C/D", alt(res("A", "B"), res("C", "D"))},
    60  
    61  		// Faulty patterns
    62  		// Errors in original should produce at least one faulty regexp in results.
    63  		{")/", res(")/")},
    64  		{")/(/)", res(")/(", ")")},
    65  		{"a[/)b", res("a[/)b")},
    66  		{"(/]", res("(/]")},
    67  		{"(/", res("(/")},
    68  		{"[/]/[/", res("[/]", "[/")},
    69  		{`\p{/}`, res(`\p{`, "}")},
    70  		{`\p/`, res(`\p`, "")},
    71  		{`[[:/:]]`, res(`[[:/:]]`)},
    72  	}
    73  	for _, tc := range testCases {
    74  		a := splitRegexp(tc.pattern)
    75  		if !reflect.DeepEqual(a, tc.result) {
    76  			t.Errorf("splitRegexp(%q) = %#v; want %#v", tc.pattern, a, tc.result)
    77  		}
    78  
    79  		// If there is any error in the pattern, one of the returned subpatterns
    80  		// needs to have an error as well.
    81  		if _, err := regexp.Compile(tc.pattern); err != nil {
    82  			ok := true
    83  			if err := a.verify("", regexp.MatchString); err != nil {
    84  				ok = false
    85  			}
    86  			if ok {
    87  				t.Errorf("%s: expected error in any of %q", tc.pattern, a)
    88  			}
    89  		}
    90  	}
    91  }
    92  
    93  func TestMatcher(t *T) {
    94  	testCases := []struct {
    95  		pattern     string
    96  		skip        string
    97  		parent, sub string
    98  		ok          bool
    99  		partial     bool
   100  	}{
   101  		// Behavior without subtests.
   102  		{"", "", "", "TestFoo", true, false},
   103  		{"TestFoo", "", "", "TestFoo", true, false},
   104  		{"TestFoo/", "", "", "TestFoo", true, true},
   105  		{"TestFoo/bar/baz", "", "", "TestFoo", true, true},
   106  		{"TestFoo", "", "", "TestBar", false, false},
   107  		{"TestFoo/", "", "", "TestBar", false, false},
   108  		{"TestFoo/bar/baz", "", "", "TestBar/bar/baz", false, false},
   109  		{"", "TestBar", "", "TestFoo", true, false},
   110  		{"", "TestBar", "", "TestBar", false, false},
   111  
   112  		// Skipping a non-existent test doesn't change anything.
   113  		{"", "TestFoo/skipped", "", "TestFoo", true, false},
   114  		{"TestFoo", "TestFoo/skipped", "", "TestFoo", true, false},
   115  		{"TestFoo/", "TestFoo/skipped", "", "TestFoo", true, true},
   116  		{"TestFoo/bar/baz", "TestFoo/skipped", "", "TestFoo", true, true},
   117  		{"TestFoo", "TestFoo/skipped", "", "TestBar", false, false},
   118  		{"TestFoo/", "TestFoo/skipped", "", "TestBar", false, false},
   119  		{"TestFoo/bar/baz", "TestFoo/skipped", "", "TestBar/bar/baz", false, false},
   120  
   121  		// with subtests
   122  		{"", "", "TestFoo", "x", true, false},
   123  		{"TestFoo", "", "TestFoo", "x", true, false},
   124  		{"TestFoo/", "", "TestFoo", "x", true, false},
   125  		{"TestFoo/bar/baz", "", "TestFoo", "bar", true, true},
   126  
   127  		{"", "TestFoo/skipped", "TestFoo", "x", true, false},
   128  		{"TestFoo", "TestFoo/skipped", "TestFoo", "x", true, false},
   129  		{"TestFoo", "TestFoo/skipped", "TestFoo", "skipped", false, false},
   130  		{"TestFoo/", "TestFoo/skipped", "TestFoo", "x", true, false},
   131  		{"TestFoo/bar/baz", "TestFoo/skipped", "TestFoo", "bar", true, true},
   132  
   133  		// Subtest with a '/' in its name still allows for copy and pasted names
   134  		// to match.
   135  		{"TestFoo/bar/baz", "", "TestFoo", "bar/baz", true, false},
   136  		{"TestFoo/bar/baz", "TestFoo/bar/baz", "TestFoo", "bar/baz", false, false},
   137  		{"TestFoo/bar/baz", "TestFoo/bar/baz/skip", "TestFoo", "bar/baz", true, false},
   138  		{"TestFoo/bar/baz", "", "TestFoo/bar", "baz", true, false},
   139  		{"TestFoo/bar/baz", "", "TestFoo", "x", false, false},
   140  		{"TestFoo", "", "TestBar", "x", false, false},
   141  		{"TestFoo/", "", "TestBar", "x", false, false},
   142  		{"TestFoo/bar/baz", "", "TestBar", "x/bar/baz", false, false},
   143  
   144  		{"A/B|C/D", "", "TestA", "B", true, false},
   145  		{"A/B|C/D", "", "TestC", "D", true, false},
   146  		{"A/B|C/D", "", "TestA", "C", false, false},
   147  
   148  		// subtests only
   149  		{"", "", "TestFoo", "x", true, false},
   150  		{"/", "", "TestFoo", "x", true, false},
   151  		{"./", "", "TestFoo", "x", true, false},
   152  		{"./.", "", "TestFoo", "x", true, false},
   153  		{"/bar/baz", "", "TestFoo", "bar", true, true},
   154  		{"/bar/baz", "", "TestFoo", "bar/baz", true, false},
   155  		{"//baz", "", "TestFoo", "bar/baz", true, false},
   156  		{"//", "", "TestFoo", "bar/baz", true, false},
   157  		{"/bar/baz", "", "TestFoo/bar", "baz", true, false},
   158  		{"//foo", "", "TestFoo", "bar/baz", false, false},
   159  		{"/bar/baz", "", "TestFoo", "x", false, false},
   160  		{"/bar/baz", "", "TestBar", "x/bar/baz", false, false},
   161  	}
   162  
   163  	for _, tc := range testCases {
   164  		m := newMatcher(regexp.MatchString, tc.pattern, "-test.run", tc.skip)
   165  
   166  		parent := &common{name: tc.parent}
   167  		if tc.parent != "" {
   168  			parent.level = 1
   169  		}
   170  		if n, ok, partial := m.fullName(parent, tc.sub); ok != tc.ok || partial != tc.partial {
   171  			t.Errorf("for pattern %q, fullName(parent=%q, sub=%q) = %q, ok %v partial %v; want ok %v partial %v",
   172  				tc.pattern, tc.parent, tc.sub, n, ok, partial, tc.ok, tc.partial)
   173  		}
   174  	}
   175  }
   176  
   177  var namingTestCases = []struct{ name, want string }{
   178  	// Uniqueness
   179  	{"", "x/#00"},
   180  	{"", "x/#01"},
   181  	{"#0", "x/#0"},      // Doesn't conflict with #00 because the number of digits differs.
   182  	{"#00", "x/#00#01"}, // Conflicts with implicit #00 (used above), so add a suffix.
   183  	{"#", "x/#"},
   184  	{"#", "x/##01"},
   185  
   186  	{"t", "x/t"},
   187  	{"t", "x/t#01"},
   188  	{"t", "x/t#02"},
   189  	{"t#00", "x/t#00"}, // Explicit "#00" doesn't conflict with the unsuffixed first subtest.
   190  
   191  	{"a#01", "x/a#01"},    // user has subtest with this name.
   192  	{"a", "x/a"},          // doesn't conflict with this name.
   193  	{"a", "x/a#02"},       // This string is claimed now, so resume
   194  	{"a", "x/a#03"},       // with counting.
   195  	{"a#02", "x/a#02#01"}, // We already used a#02 once, so add a suffix.
   196  
   197  	{"b#00", "x/b#00"},
   198  	{"b", "x/b"}, // Implicit 0 doesn't conflict with explicit "#00".
   199  	{"b", "x/b#01"},
   200  	{"b#9223372036854775807", "x/b#9223372036854775807"}, // MaxInt64
   201  	{"b", "x/b#02"},
   202  	{"b", "x/b#03"},
   203  
   204  	// Sanitizing
   205  	{"A:1 B:2", "x/A:1_B:2"},
   206  	{"s\t\r\u00a0", "x/s___"},
   207  	{"\x01", `x/\x01`},
   208  	{"\U0010ffff", `x/\U0010ffff`},
   209  }
   210  
   211  func TestNaming(t *T) {
   212  	m := newMatcher(regexp.MatchString, "", "", "")
   213  	parent := &common{name: "x", level: 1} // top-level test.
   214  
   215  	for i, tc := range namingTestCases {
   216  		if got, _, _ := m.fullName(parent, tc.name); got != tc.want {
   217  			t.Errorf("%d:%s: got %q; want %q", i, tc.name, got, tc.want)
   218  		}
   219  	}
   220  }
   221  
   222  func FuzzNaming(f *F) {
   223  	for _, tc := range namingTestCases {
   224  		f.Add(tc.name)
   225  	}
   226  	parent := &common{name: "x", level: 1}
   227  	var m *matcher
   228  	var seen map[string]string
   229  	reset := func() {
   230  		m = allMatcher()
   231  		seen = make(map[string]string)
   232  	}
   233  	reset()
   234  
   235  	f.Fuzz(func(t *T, subname string) {
   236  		if len(subname) > 10 {
   237  			// Long names attract the OOM killer.
   238  			t.Skip()
   239  		}
   240  		name := m.unique(parent.name, subname)
   241  		if !strings.Contains(name, "/"+subname) {
   242  			t.Errorf("name %q does not contain subname %q", name, subname)
   243  		}
   244  		if prev, ok := seen[name]; ok {
   245  			t.Errorf("name %q generated by both %q and %q", name, prev, subname)
   246  		}
   247  		if len(seen) > 1e6 {
   248  			// Free up memory.
   249  			reset()
   250  		}
   251  		seen[name] = subname
   252  	})
   253  }
   254  
   255  // GoString returns a string that is more readable than the default, which makes
   256  // it easier to read test errors.
   257  func (m alternationMatch) GoString() string {
   258  	s := make([]string, len(m))
   259  	for i, m := range m {
   260  		s[i] = fmt.Sprintf("%#v", m)
   261  	}
   262  	return fmt.Sprintf("(%s)", strings.Join(s, " | "))
   263  }
   264  

View as plain text