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