github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/src/testing/match_test.go (about)

     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  		skip        string
    93  		parent, sub string
    94  		ok          bool
    95  		partial     bool
    96  	}{
    97  		// Behavior without subtests.
    98  		{"", "", "", "TestFoo", true, false},
    99  		{"TestFoo", "", "", "TestFoo", true, false},
   100  		{"TestFoo/", "", "", "TestFoo", true, true},
   101  		{"TestFoo/bar/baz", "", "", "TestFoo", true, true},
   102  		{"TestFoo", "", "", "TestBar", false, false},
   103  		{"TestFoo/", "", "", "TestBar", false, false},
   104  		{"TestFoo/bar/baz", "", "", "TestBar/bar/baz", false, false},
   105  		{"", "TestBar", "", "TestFoo", true, false},
   106  		{"", "TestBar", "", "TestBar", false, false},
   107  
   108  		// Skipping a non-existent test doesn't change anything.
   109  		{"", "TestFoo/skipped", "", "TestFoo", true, false},
   110  		{"TestFoo", "TestFoo/skipped", "", "TestFoo", true, false},
   111  		{"TestFoo/", "TestFoo/skipped", "", "TestFoo", true, true},
   112  		{"TestFoo/bar/baz", "TestFoo/skipped", "", "TestFoo", true, true},
   113  		{"TestFoo", "TestFoo/skipped", "", "TestBar", false, false},
   114  		{"TestFoo/", "TestFoo/skipped", "", "TestBar", false, false},
   115  		{"TestFoo/bar/baz", "TestFoo/skipped", "", "TestBar/bar/baz", false, false},
   116  
   117  		// with subtests
   118  		{"", "", "TestFoo", "x", true, false},
   119  		{"TestFoo", "", "TestFoo", "x", true, false},
   120  		{"TestFoo/", "", "TestFoo", "x", true, false},
   121  		{"TestFoo/bar/baz", "", "TestFoo", "bar", true, true},
   122  
   123  		{"", "TestFoo/skipped", "TestFoo", "x", true, false},
   124  		{"TestFoo", "TestFoo/skipped", "TestFoo", "x", true, false},
   125  		{"TestFoo", "TestFoo/skipped", "TestFoo", "skipped", false, false},
   126  		{"TestFoo/", "TestFoo/skipped", "TestFoo", "x", true, false},
   127  		{"TestFoo/bar/baz", "TestFoo/skipped", "TestFoo", "bar", true, true},
   128  
   129  		// Subtest with a '/' in its name still allows for copy and pasted names
   130  		// to match.
   131  		{"TestFoo/bar/baz", "", "TestFoo", "bar/baz", true, false},
   132  		{"TestFoo/bar/baz", "TestFoo/bar/baz", "TestFoo", "bar/baz", false, false},
   133  		{"TestFoo/bar/baz", "TestFoo/bar/baz/skip", "TestFoo", "bar/baz", true, false},
   134  		{"TestFoo/bar/baz", "", "TestFoo/bar", "baz", true, false},
   135  		{"TestFoo/bar/baz", "", "TestFoo", "x", false, false},
   136  		{"TestFoo", "", "TestBar", "x", false, false},
   137  		{"TestFoo/", "", "TestBar", "x", false, false},
   138  		{"TestFoo/bar/baz", "", "TestBar", "x/bar/baz", false, false},
   139  
   140  		{"A/B|C/D", "", "TestA", "B", true, false},
   141  		{"A/B|C/D", "", "TestC", "D", true, false},
   142  		{"A/B|C/D", "", "TestA", "C", false, false},
   143  
   144  		// subtests only
   145  		{"", "", "TestFoo", "x", true, false},
   146  		{"/", "", "TestFoo", "x", true, false},
   147  		{"./", "", "TestFoo", "x", true, false},
   148  		{"./.", "", "TestFoo", "x", true, false},
   149  		{"/bar/baz", "", "TestFoo", "bar", true, true},
   150  		{"/bar/baz", "", "TestFoo", "bar/baz", true, false},
   151  		{"//baz", "", "TestFoo", "bar/baz", true, false},
   152  		{"//", "", "TestFoo", "bar/baz", true, false},
   153  		{"/bar/baz", "", "TestFoo/bar", "baz", true, false},
   154  		{"//foo", "", "TestFoo", "bar/baz", false, false},
   155  		{"/bar/baz", "", "TestFoo", "x", false, false},
   156  		{"/bar/baz", "", "TestBar", "x/bar/baz", false, false},
   157  	}
   158  
   159  	for _, tc := range testCases {
   160  		m := newMatcher(regexp.MatchString, tc.pattern, "-test.run", tc.skip)
   161  
   162  		parent := &common{name: tc.parent}
   163  		if tc.parent != "" {
   164  			parent.level = 1
   165  		}
   166  		if n, ok, partial := m.fullName(parent, tc.sub); ok != tc.ok || partial != tc.partial {
   167  			t.Errorf("for pattern %q, fullName(parent=%q, sub=%q) = %q, ok %v partial %v; want ok %v partial %v",
   168  				tc.pattern, tc.parent, tc.sub, n, ok, partial, tc.ok, tc.partial)
   169  		}
   170  	}
   171  }
   172  
   173  var namingTestCases = []struct{ name, want string }{
   174  	// Uniqueness
   175  	{"", "x/#00"},
   176  	{"", "x/#01"},
   177  	{"#0", "x/#0"},      // Doesn't conflict with #00 because the number of digits differs.
   178  	{"#00", "x/#00#01"}, // Conflicts with implicit #00 (used above), so add a suffix.
   179  	{"#", "x/#"},
   180  	{"#", "x/##01"},
   181  
   182  	{"t", "x/t"},
   183  	{"t", "x/t#01"},
   184  	{"t", "x/t#02"},
   185  	{"t#00", "x/t#00"}, // Explicit "#00" doesn't conflict with the unsuffixed first subtest.
   186  
   187  	{"a#01", "x/a#01"},    // user has subtest with this name.
   188  	{"a", "x/a"},          // doesn't conflict with this name.
   189  	{"a", "x/a#02"},       // This string is claimed now, so resume
   190  	{"a", "x/a#03"},       // with counting.
   191  	{"a#02", "x/a#02#01"}, // We already used a#02 once, so add a suffix.
   192  
   193  	{"b#00", "x/b#00"},
   194  	{"b", "x/b"}, // Implicit 0 doesn't conflict with explicit "#00".
   195  	{"b", "x/b#01"},
   196  	{"b#9223372036854775807", "x/b#9223372036854775807"}, // MaxInt64
   197  	{"b", "x/b#02"},
   198  	{"b", "x/b#03"},
   199  
   200  	// Sanitizing
   201  	{"A:1 B:2", "x/A:1_B:2"},
   202  	{"s\t\r\u00a0", "x/s___"},
   203  	{"\x01", `x/\x01`},
   204  	{"\U0010ffff", `x/\U0010ffff`},
   205  }
   206  
   207  func TestNaming(t *T) {
   208  	m := newMatcher(regexp.MatchString, "", "", "")
   209  	parent := &common{name: "x", level: 1} // top-level test.
   210  
   211  	for i, tc := range namingTestCases {
   212  		if got, _, _ := m.fullName(parent, tc.name); got != tc.want {
   213  			t.Errorf("%d:%s: got %q; want %q", i, tc.name, got, tc.want)
   214  		}
   215  	}
   216  }
   217  
   218  func FuzzNaming(f *F) {
   219  	for _, tc := range namingTestCases {
   220  		f.Add(tc.name)
   221  	}
   222  	parent := &common{name: "x", level: 1}
   223  	var m *matcher
   224  	var seen map[string]string
   225  	reset := func() {
   226  		m = allMatcher()
   227  		seen = make(map[string]string)
   228  	}
   229  	reset()
   230  
   231  	f.Fuzz(func(t *T, subname string) {
   232  		if len(subname) > 10 {
   233  			// Long names attract the OOM killer.
   234  			t.Skip()
   235  		}
   236  		name := m.unique(parent.name, subname)
   237  		if !strings.Contains(name, "/"+subname) {
   238  			t.Errorf("name %q does not contain subname %q", name, subname)
   239  		}
   240  		if prev, ok := seen[name]; ok {
   241  			t.Errorf("name %q generated by both %q and %q", name, prev, subname)
   242  		}
   243  		if len(seen) > 1e6 {
   244  			// Free up memory.
   245  			reset()
   246  		}
   247  		seen[name] = subname
   248  	})
   249  }
   250  
   251  // GoString returns a string that is more readable than the default, which makes
   252  // it easier to read test errors.
   253  func (m alternationMatch) GoString() string {
   254  	s := make([]string, len(m))
   255  	for i, m := range m {
   256  		s[i] = fmt.Sprintf("%#v", m)
   257  	}
   258  	return fmt.Sprintf("(%s)", strings.Join(s, " | "))
   259  }