| // Copyright 2022 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 pkgpattern | |
| import ( | |
| "strings" | |
| "testing" | |
| ) | |
| var matchPatternTests = ` | |
| pattern ... | |
| match foo | |
| pattern net | |
| match net | |
| not net/http | |
| pattern net/http | |
| match net/http | |
| not net | |
| pattern net... | |
| match net net/http netchan | |
| not not/http not/net/http | |
| # Special cases. Quoting docs: | |
| # First, /... at the end of the pattern can match an empty string, | |
| # so that net/... matches both net and packages in its subdirectories, like net/http. | |
| pattern net/... | |
| match net net/http | |
| not not/http not/net/http netchan | |
| # Second, any slash-separated pattern element containing a wildcard never | |
| # participates in a match of the "vendor" element in the path of a vendored | |
| # package, so that ./... does not match packages in subdirectories of | |
| # ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do. | |
| # Note, however, that a directory named vendor that itself contains code | |
| # is not a vendored package: cmd/vendor would be a command named vendor, | |
| # and the pattern cmd/... matches it. | |
| pattern ./... | |
| match ./vendor ./mycode/vendor | |
| not ./vendor/foo ./mycode/vendor/foo | |
| pattern ./vendor/... | |
| match ./vendor/foo ./vendor/foo/vendor | |
| not ./vendor/foo/vendor/bar | |
| pattern mycode/vendor/... | |
| match mycode/vendor mycode/vendor/foo mycode/vendor/foo/vendor | |
| not mycode/vendor/foo/vendor/bar | |
| pattern x/vendor/y | |
| match x/vendor/y | |
| not x/vendor | |
| pattern x/vendor/y/... | |
| match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor | |
| not x/vendor/y/vendor/z | |
| pattern .../vendor/... | |
| match x/vendor/y x/vendor/y/z x/vendor/y/vendor x/vendor/y/z/vendor | |
| ` | |
| func TestMatchPattern(t *testing.T) { | |
| testPatterns(t, "MatchPattern", matchPatternTests, func(pattern, name string) bool { | |
| return MatchPattern(pattern)(name) | |
| }) | |
| } | |
| var matchSimplePatternTests = ` | |
| pattern ... | |
| match foo | |
| pattern .../bar/.../baz | |
| match foo/bar/abc/baz | |
| pattern net | |
| match net | |
| not net/http | |
| pattern net/http | |
| match net/http | |
| not net | |
| pattern net... | |
| match net net/http netchan | |
| not not/http not/net/http | |
| # Special cases. Quoting docs: | |
| # First, /... at the end of the pattern can match an empty string, | |
| # so that net/... matches both net and packages in its subdirectories, like net/http. | |
| pattern net/... | |
| match net net/http | |
| not not/http not/net/http netchan | |
| ` | |
| func TestSimpleMatchPattern(t *testing.T) { | |
| testPatterns(t, "MatchSimplePattern", matchSimplePatternTests, func(pattern, name string) bool { | |
| return MatchSimplePattern(pattern)(name) | |
| }) | |
| } | |
| var treeCanMatchPatternTests = ` | |
| pattern ... | |
| match foo | |
| pattern net | |
| match net | |
| not net/http | |
| pattern net/http | |
| match net net/http | |
| pattern net... | |
| match net netchan net/http | |
| not not/http not/net/http | |
| pattern net/... | |
| match net net/http | |
| not not/http netchan | |
| pattern abc.../def | |
| match abcxyz | |
| not xyzabc | |
| pattern x/y/z/... | |
| match x x/y x/y/z x/y/z/w | |
| pattern x/y/z | |
| match x x/y x/y/z | |
| not x/y/z/w | |
| pattern x/.../y/z | |
| match x/a/b/c | |
| not y/x/a/b/c | |
| ` | |
| func TestTreeCanMatchPattern(t *testing.T) { | |
| testPatterns(t, "TreeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool { | |
| return TreeCanMatchPattern(pattern)(name) | |
| }) | |
| } | |
| var hasPathPrefixTests = []stringPairTest{ | |
| {"abc", "a", false}, | |
| {"a/bc", "a", true}, | |
| {"a", "a", true}, | |
| {"a/bc", "a/", true}, | |
| } | |
| func TestHasPathPrefix(t *testing.T) { | |
| testStringPairs(t, "hasPathPrefix", hasPathPrefixTests, hasPathPrefix) | |
| } | |
| type stringPairTest struct { | |
| in1 string | |
| in2 string | |
| out bool | |
| } | |
| func testStringPairs(t *testing.T, name string, tests []stringPairTest, f func(string, string) bool) { | |
| for _, tt := range tests { | |
| if out := f(tt.in1, tt.in2); out != tt.out { | |
| t.Errorf("%s(%q, %q) = %v, want %v", name, tt.in1, tt.in2, out, tt.out) | |
| } | |
| } | |
| } | |
| func testPatterns(t *testing.T, name, tests string, fn func(string, string) bool) { | |
| var patterns []string | |
| for _, line := range strings.Split(tests, "\n") { | |
| if i := strings.Index(line, "#"); i >= 0 { | |
| line = line[:i] | |
| } | |
| f := strings.Fields(line) | |
| if len(f) == 0 { | |
| continue | |
| } | |
| switch f[0] { | |
| default: | |
| t.Fatalf("unknown directive %q", f[0]) | |
| case "pattern": | |
| patterns = f[1:] | |
| case "match", "not": | |
| want := f[0] == "match" | |
| for _, pattern := range patterns { | |
| for _, in := range f[1:] { | |
| if fn(pattern, in) != want { | |
| t.Errorf("%s(%q, %q) = %v, want %v", name, pattern, in, !want, want) | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } |