1 // Copyright 2018 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.
9 var checkTests = []struct {
14 {"rsc.io/quote", "0.1.0", false},
15 {"rsc io/quote", "v1.0.0", false},
17 {"github.com/go-yaml/yaml", "v0.8.0", true},
18 {"github.com/go-yaml/yaml", "v1.0.0", true},
19 {"github.com/go-yaml/yaml", "v2.0.0", false},
20 {"github.com/go-yaml/yaml", "v2.1.5", false},
21 {"github.com/go-yaml/yaml", "v3.0.0", false},
23 {"github.com/go-yaml/yaml/v2", "v1.0.0", false},
24 {"github.com/go-yaml/yaml/v2", "v2.0.0", true},
25 {"github.com/go-yaml/yaml/v2", "v2.1.5", true},
26 {"github.com/go-yaml/yaml/v2", "v3.0.0", false},
28 {"gopkg.in/yaml.v0", "v0.8.0", true},
29 {"gopkg.in/yaml.v0", "v1.0.0", false},
30 {"gopkg.in/yaml.v0", "v2.0.0", false},
31 {"gopkg.in/yaml.v0", "v2.1.5", false},
32 {"gopkg.in/yaml.v0", "v3.0.0", false},
34 {"gopkg.in/yaml.v1", "v0.8.0", false},
35 {"gopkg.in/yaml.v1", "v1.0.0", true},
36 {"gopkg.in/yaml.v1", "v2.0.0", false},
37 {"gopkg.in/yaml.v1", "v2.1.5", false},
38 {"gopkg.in/yaml.v1", "v3.0.0", false},
40 // For gopkg.in, .v1 means v1 only (not v0).
41 // But early versions of vgo still generated v0 pseudo-versions for it.
42 // Even though now we'd generate those as v1 pseudo-versions,
43 // we accept the old pseudo-versions to avoid breaking existing go.mod files.
44 // For example gopkg.in/yaml.v2@v2.2.1's go.mod requires check.v1 at a v0 pseudo-version.
45 {"gopkg.in/check.v1", "v0.0.0", false},
46 {"gopkg.in/check.v1", "v0.0.0-20160102150405-abcdef123456", true},
48 {"gopkg.in/yaml.v2", "v1.0.0", false},
49 {"gopkg.in/yaml.v2", "v2.0.0", true},
50 {"gopkg.in/yaml.v2", "v2.1.5", true},
51 {"gopkg.in/yaml.v2", "v3.0.0", false},
53 {"rsc.io/quote", "v17.0.0", false},
54 {"rsc.io/quote", "v17.0.0+incompatible", true},
57 func TestCheck(t *testing.T) {
58 for _, tt := range checkTests {
59 err := Check(tt.path, tt.version)
60 if tt.ok && err != nil {
61 t.Errorf("Check(%q, %q) = %v, wanted nil error", tt.path, tt.version, err)
62 } else if !tt.ok && err == nil {
63 t.Errorf("Check(%q, %q) succeeded, wanted error", tt.path, tt.version)
68 var checkPathTests = []struct {
74 {"x.y/z", true, true, true},
75 {"x.y", true, true, true},
77 {"", false, false, false},
78 {"x.y/\xFFz", false, false, false},
79 {"/x.y/z", false, false, false},
80 {"x./z", false, false, false},
81 {".x/z", false, false, true},
82 {"-x/z", false, false, false},
83 {"x..y/z", true, true, true},
84 {"x.y/z/../../w", false, false, false},
85 {"x.y//z", false, false, false},
86 {"x.y/z//w", false, false, false},
87 {"x.y/z/", false, false, false},
89 {"x.y/z/v0", false, true, true},
90 {"x.y/z/v1", false, true, true},
91 {"x.y/z/v2", true, true, true},
92 {"x.y/z/v2.0", false, true, true},
93 {"X.y/z", false, true, true},
95 {"!x.y/z", false, false, true},
96 {"_x.y/z", false, true, true},
97 {"x.y!/z", false, false, true},
98 {"x.y\"/z", false, false, false},
99 {"x.y#/z", false, false, true},
100 {"x.y$/z", false, false, true},
101 {"x.y%/z", false, false, true},
102 {"x.y&/z", false, false, true},
103 {"x.y'/z", false, false, false},
104 {"x.y(/z", false, false, true},
105 {"x.y)/z", false, false, true},
106 {"x.y*/z", false, false, false},
107 {"x.y+/z", false, true, true},
108 {"x.y,/z", false, false, true},
109 {"x.y-/z", true, true, true},
110 {"x.y./zt", false, false, false},
111 {"x.y:/z", false, false, false},
112 {"x.y;/z", false, false, false},
113 {"x.y</z", false, false, false},
114 {"x.y=/z", false, false, true},
115 {"x.y>/z", false, false, false},
116 {"x.y?/z", false, false, false},
117 {"x.y@/z", false, false, true},
118 {"x.y[/z", false, false, true},
119 {"x.y\\/z", false, false, false},
120 {"x.y]/z", false, false, true},
121 {"x.y^/z", false, false, true},
122 {"x.y_/z", false, true, true},
123 {"x.y`/z", false, false, false},
124 {"x.y{/z", false, false, true},
125 {"x.y}/z", false, false, true},
126 {"x.y~/z", false, true, true},
127 {"x.y/z!", false, false, true},
128 {"x.y/z\"", false, false, false},
129 {"x.y/z#", false, false, true},
130 {"x.y/z$", false, false, true},
131 {"x.y/z%", false, false, true},
132 {"x.y/z&", false, false, true},
133 {"x.y/z'", false, false, false},
134 {"x.y/z(", false, false, true},
135 {"x.y/z)", false, false, true},
136 {"x.y/z*", false, false, false},
137 {"x.y/z+", true, true, true},
138 {"x.y/z,", false, false, true},
139 {"x.y/z-", true, true, true},
140 {"x.y/z.t", true, true, true},
141 {"x.y/z/t", true, true, true},
142 {"x.y/z:", false, false, false},
143 {"x.y/z;", false, false, false},
144 {"x.y/z<", false, false, false},
145 {"x.y/z=", false, false, true},
146 {"x.y/z>", false, false, false},
147 {"x.y/z?", false, false, false},
148 {"x.y/z@", false, false, true},
149 {"x.y/z[", false, false, true},
150 {"x.y/z\\", false, false, false},
151 {"x.y/z]", false, false, true},
152 {"x.y/z^", false, false, true},
153 {"x.y/z_", true, true, true},
154 {"x.y/z`", false, false, false},
155 {"x.y/z{", false, false, true},
156 {"x.y/z}", false, false, true},
157 {"x.y/z~", true, true, true},
158 {"x.y/x.foo", true, true, true},
159 {"x.y/aux.foo", false, false, false},
160 {"x.y/prn", false, false, false},
161 {"x.y/prn2", true, true, true},
162 {"x.y/com", true, true, true},
163 {"x.y/com1", false, false, false},
164 {"x.y/com1.txt", false, false, false},
165 {"x.y/calm1", true, true, true},
166 {"github.com/!123/logrus", false, false, true},
168 // TODO: CL 41822 allowed Unicode letters in old "go get"
169 // without due consideration of the implications, and only on github.com (!).
170 // For now, we disallow non-ASCII characters in module mode,
171 // in both module paths and general import paths,
172 // until we can get the implications right.
173 // When we do, we'll enable them everywhere, not just for GitHub.
174 {"github.com/user/unicode/испытание", false, false, true},
176 {"../x", false, false, false},
177 {"./y", false, false, false},
178 {"x:y", false, false, false},
179 {`\temp\foo`, false, false, false},
180 {".gitignore", false, false, true},
181 {".github/ISSUE_TEMPLATE", false, false, true},
182 {"x☺y", false, false, false},
185 func TestCheckPath(t *testing.T) {
186 for _, tt := range checkPathTests {
187 err := CheckPath(tt.path)
188 if tt.ok && err != nil {
189 t.Errorf("CheckPath(%q) = %v, wanted nil error", tt.path, err)
190 } else if !tt.ok && err == nil {
191 t.Errorf("CheckPath(%q) succeeded, wanted error", tt.path)
194 err = CheckImportPath(tt.path)
195 if tt.importOK && err != nil {
196 t.Errorf("CheckImportPath(%q) = %v, wanted nil error", tt.path, err)
197 } else if !tt.importOK && err == nil {
198 t.Errorf("CheckImportPath(%q) succeeded, wanted error", tt.path)
201 err = CheckFilePath(tt.path)
202 if tt.fileOK && err != nil {
203 t.Errorf("CheckFilePath(%q) = %v, wanted nil error", tt.path, err)
204 } else if !tt.fileOK && err == nil {
205 t.Errorf("CheckFilePath(%q) succeeded, wanted error", tt.path)
210 var splitPathVersionTests = []struct {
218 {"gopkg.in/yaml", ".v0"},
219 {"gopkg.in/yaml", ".v1"},
220 {"gopkg.in/yaml", ".v2"},
221 {"gopkg.in/yaml", ".v3"},
224 func TestSplitPathVersion(t *testing.T) {
225 for _, tt := range splitPathVersionTests {
226 pathPrefix, version, ok := SplitPathVersion(tt.pathPrefix + tt.version)
227 if pathPrefix != tt.pathPrefix || version != tt.version || !ok {
228 t.Errorf("SplitPathVersion(%q) = %q, %q, %v, want %q, %q, true", tt.pathPrefix+tt.version, pathPrefix, version, ok, tt.pathPrefix, tt.version)
232 for _, tt := range checkPathTests {
233 pathPrefix, version, ok := SplitPathVersion(tt.path)
234 if pathPrefix+version != tt.path {
235 t.Errorf("SplitPathVersion(%q) = %q, %q, %v, doesn't add to input", tt.path, pathPrefix, version, ok)
240 var escapeTests = []struct {
242 esc string // empty means same as path
244 {path: "ascii.com/abcdefghijklmnopqrstuvwxyz.-+/~_0123456789"},
245 {path: "github.com/GoogleCloudPlatform/omega", esc: "github.com/!google!cloud!platform/omega"},
248 func TestEscapePath(t *testing.T) {
249 // Check invalid paths.
250 for _, tt := range checkPathTests {
252 _, err := EscapePath(tt.path)
254 t.Errorf("EscapePath(%q): succeeded, want error (invalid path)", tt.path)
260 for _, tt := range escapeTests {
261 esc, err := EscapePath(tt.path)
263 t.Errorf("EscapePath(%q): unexpected error: %v", tt.path, err)
271 t.Errorf("EscapePath(%q) = %q, want %q", tt.path, esc, want)
276 var badUnescape = []string{
277 "github.com/GoogleCloudPlatform/omega",
278 "github.com/!google!cloud!platform!/omega",
279 "github.com/!0google!cloud!platform/omega",
280 "github.com/!_google!cloud!platform/omega",
281 "github.com/!!google!cloud!platform/omega",
285 func TestUnescapePath(t *testing.T) {
286 // Check invalid decodings.
287 for _, bad := range badUnescape {
288 _, err := UnescapePath(bad)
290 t.Errorf("UnescapePath(%q): succeeded, want error (invalid decoding)", bad)
294 // Check invalid paths (or maybe decodings).
295 for _, tt := range checkPathTests {
297 path, err := UnescapePath(tt.path)
299 t.Errorf("UnescapePath(%q) = %q, want error (invalid path)", tt.path, path)
305 for _, tt := range escapeTests {
310 path, err := UnescapePath(esc)
312 t.Errorf("UnescapePath(%q): unexpected error: %v", esc, err)
316 t.Errorf("UnescapePath(%q) = %q, want %q", esc, path, tt.path)
321 func TestMatchPathMajor(t *testing.T) {
322 for _, test := range []struct {
326 {"v0.0.0", "", true},
327 {"v0.0.0", "/v2", false},
328 {"v0.0.0", ".v0", true},
329 {"v0.0.0-20190510104115-cbcb75029529", ".v1", true},
330 {"v1.0.0", "/v2", false},
331 {"v1.0.0", ".v1", true},
332 {"v1.0.0", ".v1-unstable", true},
333 {"v2.0.0+incompatible", "", true},
334 {"v2.0.0", "", false},
335 {"v2.0.0", "/v2", true},
336 {"v2.0.0", ".v2", true},
338 if got := MatchPathMajor(test.v, test.pathMajor); got != test.want {
339 t.Errorf("MatchPathMajor(%q, %q) = %v, want %v", test.v, test.pathMajor, got, test.want)