1// Copyright 2022 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 5package pkgpattern 6 7import ( 8 "strings" 9 "testing" 10) 11 12var matchPatternTests = ` 13 pattern ... 14 match foo 15 16 pattern net 17 match net 18 not net/http 19 20 pattern net/http 21 match net/http 22 not net 23 24 pattern net... 25 match net net/http netchan 26 not not/http not/net/http 27 28 # Special cases. Quoting docs: 29 30 # First, /... at the end of the pattern can match an empty string, 31 # so that net/... matches both net and packages in its subdirectories, like net/http. 32 pattern net/... 33 match net net/http 34 not not/http not/net/http netchan 35 36 # Second, any slash-separated pattern element containing a wildcard never 37 # participates in a match of the "vendor" element in the path of a vendored 38 # package, so that ./... does not match packages in subdirectories of 39 # ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do. 40 # Note, however, that a directory named vendor that itself contains code 41 # is not a vendored package: cmd/vendor would be a command named vendor, 42 # and the pattern cmd/... matches it. 43 pattern ./... 44 match ./vendor ./mycode/vendor 45 not ./vendor/foo ./mycode/vendor/foo 46 47 pattern ./vendor/... 48 match ./vendor/foo ./vendor/foo/vendor 49 not ./vendor/foo/vendor/bar 50 51 pattern mycode/vendor/... 52 match mycode/vendor mycode/vendor/foo mycode/vendor/foo/vendor 53 not mycode/vendor/foo/vendor/bar 54 55 pattern x/vendor/y 56 match x/vendor/y 57 not x/vendor 58 59 pattern x/vendor/y/... 60 match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor 61 not x/vendor/y/vendor/z 62 63 pattern .../vendor/... 64 match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor 65` 66 67func TestMatchPattern(t *testing.T) { 68 testPatterns(t, "MatchPattern", matchPatternTests, func(pattern, name string) bool { 69 return MatchPattern(pattern)(name) 70 }) 71} 72 73var matchSimplePatternTests = ` 74 pattern ... 75 match foo 76 77 pattern .../bar/.../baz 78 match foo/bar/abc/baz 79 80 pattern net 81 match net 82 not net/http 83 84 pattern net/http 85 match net/http 86 not net 87 88 pattern net... 89 match net net/http netchan 90 not not/http not/net/http 91 92 # Special cases. Quoting docs: 93 94 # First, /... at the end of the pattern can match an empty string, 95 # so that net/... matches both net and packages in its subdirectories, like net/http. 96 pattern net/... 97 match net net/http 98 not not/http not/net/http netchan 99` 100 101func TestSimpleMatchPattern(t *testing.T) { 102 testPatterns(t, "MatchSimplePattern", matchSimplePatternTests, func(pattern, name string) bool { 103 return MatchSimplePattern(pattern)(name) 104 }) 105} 106 107var treeCanMatchPatternTests = ` 108 pattern ... 109 match foo 110 111 pattern net 112 match net 113 not net/http 114 115 pattern net/http 116 match net net/http 117 118 pattern net... 119 match net netchan net/http 120 not not/http not/net/http 121 122 pattern net/... 123 match net net/http 124 not not/http netchan 125 126 pattern abc.../def 127 match abcxyz 128 not xyzabc 129 130 pattern x/y/z/... 131 match x x/y x/y/z x/y/z/w 132 133 pattern x/y/z 134 match x x/y x/y/z 135 not x/y/z/w 136 137 pattern x/.../y/z 138 match x/a/b/c 139 not y/x/a/b/c 140` 141 142func TestTreeCanMatchPattern(t *testing.T) { 143 testPatterns(t, "TreeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool { 144 return TreeCanMatchPattern(pattern)(name) 145 }) 146} 147 148var hasPathPrefixTests = []stringPairTest{ 149 {"abc", "a", false}, 150 {"a/bc", "a", true}, 151 {"a", "a", true}, 152 {"a/bc", "a/", true}, 153} 154 155func TestHasPathPrefix(t *testing.T) { 156 testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix) 157} 158 159type stringPairTest struct { 160 in1 string 161 in2 string 162 out bool 163} 164 165func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) { 166 for _, tt := range tests { 167 if out := f(tt.in1, tt.in2); out != tt.out { 168 t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out) 169 } 170 } 171} 172 173func testPatterns(t *testing.T, name, tests string, fn func(string, string) bool) { 174 var patterns []string 175 for _, line := range strings.Split(tests, "\n") { 176 if i := strings.Index(line, "#"); i >= 0 { 177 line = line[:i] 178 } 179 f := strings.Fields(line) 180 if len(f) == 0 { 181 continue 182 } 183 switch f[0] { 184 default: 185 t.Fatalf("unknown directive %q", f[0]) 186 case "pattern": 187 patterns = f[1:] 188 case "match", "not": 189 want := f[0] == "match" 190 for _, pattern := range patterns { 191 for _, in := range f[1:] { 192 if fn(pattern, in) != want { 193 t.Errorf("%s(%q, %q) = %v, want %v", name, pattern, in, !want, want) 194 } 195 } 196 } 197 } 198 } 199} 200