|
| 1 | +//go:build ignore |
| 2 | + |
| 3 | +// Copyright 2018 The Go Authors. All rights reserved. |
| 4 | +// Use of this source code is governed by a BSD-style |
| 5 | +// license that can be found in the LICENSE file. |
| 6 | + |
| 7 | +package module |
| 8 | + |
| 9 | +import "testing" |
| 10 | + |
| 11 | +var checkTests = []struct { |
| 12 | + path string |
| 13 | + version string |
| 14 | + ok bool |
| 15 | +}{ |
| 16 | + {"rsc.io/quote", "0.1.0", false}, |
| 17 | + {"rsc io/quote", "v1.0.0", false}, |
| 18 | + |
| 19 | + {"github.com/go-yaml/yaml", "v0.8.0", true}, |
| 20 | + {"github.com/go-yaml/yaml", "v1.0.0", true}, |
| 21 | + {"github.com/go-yaml/yaml", "v2.0.0", false}, |
| 22 | + {"github.com/go-yaml/yaml", "v2.1.5", false}, |
| 23 | + {"github.com/go-yaml/yaml", "v3.0.0", false}, |
| 24 | + |
| 25 | + {"github.com/go-yaml/yaml/v2", "v1.0.0", false}, |
| 26 | + {"github.com/go-yaml/yaml/v2", "v2.0.0", true}, |
| 27 | + {"github.com/go-yaml/yaml/v2", "v2.1.5", true}, |
| 28 | + {"github.com/go-yaml/yaml/v2", "v3.0.0", false}, |
| 29 | + |
| 30 | + {"gopkg.in/yaml.v0", "v0.8.0", true}, |
| 31 | + {"gopkg.in/yaml.v0", "v1.0.0", false}, |
| 32 | + {"gopkg.in/yaml.v0", "v2.0.0", false}, |
| 33 | + {"gopkg.in/yaml.v0", "v2.1.5", false}, |
| 34 | + {"gopkg.in/yaml.v0", "v3.0.0", false}, |
| 35 | + |
| 36 | + {"gopkg.in/yaml.v1", "v0.8.0", false}, |
| 37 | + {"gopkg.in/yaml.v1", "v1.0.0", true}, |
| 38 | + {"gopkg.in/yaml.v1", "v2.0.0", false}, |
| 39 | + {"gopkg.in/yaml.v1", "v2.1.5", false}, |
| 40 | + {"gopkg.in/yaml.v1", "v3.0.0", false}, |
| 41 | + |
| 42 | + // For gopkg.in, .v1 means v1 only (not v0). |
| 43 | + // But early versions of vgo still generated v0 pseudo-versions for it. |
| 44 | + // Even though now we'd generate those as v1 pseudo-versions, |
| 45 | + // we accept the old pseudo-versions to avoid breaking existing go.mod files. |
| 46 | + // For example gopkg.in/[email protected]'s go.mod requires check.v1 at a v0 pseudo-version. |
| 47 | + {"gopkg.in/check.v1", "v0.0.0", false}, |
| 48 | + {"gopkg.in/check.v1", "v0.0.0-20160102150405-abcdef123456", true}, |
| 49 | + |
| 50 | + {"gopkg.in/yaml.v2", "v1.0.0", false}, |
| 51 | + {"gopkg.in/yaml.v2", "v2.0.0", true}, |
| 52 | + {"gopkg.in/yaml.v2", "v2.1.5", true}, |
| 53 | + {"gopkg.in/yaml.v2", "v3.0.0", false}, |
| 54 | + |
| 55 | + {"rsc.io/quote", "v17.0.0", false}, |
| 56 | + {"rsc.io/quote", "v17.0.0+incompatible", true}, |
| 57 | +} |
| 58 | + |
| 59 | +func TestCheck(t *testing.T) { |
| 60 | + for _, tt := range checkTests { |
| 61 | + err := Check(tt.path, tt.version) |
| 62 | + if tt.ok && err != nil { |
| 63 | + t.Errorf("Check(%q, %q) = %v, wanted nil error", tt.path, tt.version, err) |
| 64 | + } else if !tt.ok && err == nil { |
| 65 | + t.Errorf("Check(%q, %q) succeeded, wanted error", tt.path, tt.version) |
| 66 | + } |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | +var checkPathTests = []struct { |
| 71 | + path string |
| 72 | + ok bool |
| 73 | + importOK bool |
| 74 | + fileOK bool |
| 75 | +}{ |
| 76 | + {"x.y/z", true, true, true}, |
| 77 | + {"x.y", true, true, true}, |
| 78 | + |
| 79 | + {"", false, false, false}, |
| 80 | + {"x.y/\xFFz", false, false, false}, |
| 81 | + {"/x.y/z", false, false, false}, |
| 82 | + {"x./z", false, false, false}, |
| 83 | + {".x/z", false, true, true}, |
| 84 | + {"-x/z", false, false, true}, |
| 85 | + {"x..y/z", true, true, true}, |
| 86 | + {"x.y/z/../../w", false, false, false}, |
| 87 | + {"x.y//z", false, false, false}, |
| 88 | + {"x.y/z//w", false, false, false}, |
| 89 | + {"x.y/z/", false, false, false}, |
| 90 | + |
| 91 | + {"x.y/z/v0", false, true, true}, |
| 92 | + {"x.y/z/v1", false, true, true}, |
| 93 | + {"x.y/z/v2", true, true, true}, |
| 94 | + {"x.y/z/v2.0", false, true, true}, |
| 95 | + {"X.y/z", false, true, true}, |
| 96 | + |
| 97 | + {"!x.y/z", false, false, true}, |
| 98 | + {"_x.y/z", false, true, true}, |
| 99 | + {"x.y!/z", false, false, true}, |
| 100 | + {"x.y\"/z", false, false, false}, |
| 101 | + {"x.y#/z", false, false, true}, |
| 102 | + {"x.y$/z", false, false, true}, |
| 103 | + {"x.y%/z", false, false, true}, |
| 104 | + {"x.y&/z", false, false, true}, |
| 105 | + {"x.y'/z", false, false, false}, |
| 106 | + {"x.y(/z", false, false, true}, |
| 107 | + {"x.y)/z", false, false, true}, |
| 108 | + {"x.y*/z", false, false, false}, |
| 109 | + {"x.y+/z", false, true, true}, |
| 110 | + {"x.y,/z", false, false, true}, |
| 111 | + {"x.y-/z", true, true, true}, |
| 112 | + {"x.y./zt", false, false, false}, |
| 113 | + {"x.y:/z", false, false, false}, |
| 114 | + {"x.y;/z", false, false, false}, |
| 115 | + {"x.y</z", false, false, false}, |
| 116 | + {"x.y=/z", false, false, true}, |
| 117 | + {"x.y>/z", false, false, false}, |
| 118 | + {"x.y?/z", false, false, false}, |
| 119 | + {"x.y@/z", false, false, true}, |
| 120 | + {"x.y[/z", false, false, true}, |
| 121 | + {"x.y\\/z", false, false, false}, |
| 122 | + {"x.y]/z", false, false, true}, |
| 123 | + {"x.y^/z", false, false, true}, |
| 124 | + {"x.y_/z", false, true, true}, |
| 125 | + {"x.y`/z", false, false, false}, |
| 126 | + {"x.y{/z", false, false, true}, |
| 127 | + {"x.y}/z", false, false, true}, |
| 128 | + {"x.y~/z", false, true, true}, |
| 129 | + {"x.y/z!", false, false, true}, |
| 130 | + {"x.y/z\"", false, false, false}, |
| 131 | + {"x.y/z#", false, false, true}, |
| 132 | + {"x.y/z$", false, false, true}, |
| 133 | + {"x.y/z%", false, false, true}, |
| 134 | + {"x.y/z&", false, false, true}, |
| 135 | + {"x.y/z'", false, false, false}, |
| 136 | + {"x.y/z(", false, false, true}, |
| 137 | + {"x.y/z)", false, false, true}, |
| 138 | + {"x.y/z*", false, false, false}, |
| 139 | + {"x.y/z++", false, true, true}, |
| 140 | + {"x.y/z,", false, false, true}, |
| 141 | + {"x.y/z-", true, true, true}, |
| 142 | + {"x.y/z.t", true, true, true}, |
| 143 | + {"x.y/z/t", true, true, true}, |
| 144 | + {"x.y/z:", false, false, false}, |
| 145 | + {"x.y/z;", false, false, false}, |
| 146 | + {"x.y/z<", false, false, false}, |
| 147 | + {"x.y/z=", false, false, true}, |
| 148 | + {"x.y/z>", false, false, false}, |
| 149 | + {"x.y/z?", false, false, false}, |
| 150 | + {"x.y/z@", false, false, true}, |
| 151 | + {"x.y/z[", false, false, true}, |
| 152 | + {"x.y/z\\", false, false, false}, |
| 153 | + {"x.y/z]", false, false, true}, |
| 154 | + {"x.y/z^", false, false, true}, |
| 155 | + {"x.y/z_", true, true, true}, |
| 156 | + {"x.y/z`", false, false, false}, |
| 157 | + {"x.y/z{", false, false, true}, |
| 158 | + {"x.y/z}", false, false, true}, |
| 159 | + {"x.y/z~", true, true, true}, |
| 160 | + {"x.y/x.foo", true, true, true}, |
| 161 | + {"x.y/aux.foo", false, false, false}, |
| 162 | + {"x.y/prn", false, false, false}, |
| 163 | + {"x.y/prn2", true, true, true}, |
| 164 | + {"x.y/com", true, true, true}, |
| 165 | + {"x.y/com1", false, false, false}, |
| 166 | + {"x.y/com1.txt", false, false, false}, |
| 167 | + {"x.y/calm1", true, true, true}, |
| 168 | + {"x.y/z~", true, true, true}, |
| 169 | + {"x.y/z~0", false, false, true}, |
| 170 | + {"x.y/z~09", false, false, true}, |
| 171 | + {"x.y/z09", true, true, true}, |
| 172 | + {"x.y/z09~", true, true, true}, |
| 173 | + {"x.y/z09~09z", true, true, true}, |
| 174 | + {"x.y/z09~09z~09", false, false, true}, |
| 175 | + {"github.com/!123/logrus", false, false, true}, |
| 176 | + |
| 177 | + // TODO: CL 41822 allowed Unicode letters in old "go get" |
| 178 | + // without due consideration of the implications, and only on github.com (!). |
| 179 | + // For now, we disallow non-ASCII characters in module mode, |
| 180 | + // in both module paths and general import paths, |
| 181 | + // until we can get the implications right. |
| 182 | + // When we do, we'll enable them everywhere, not just for GitHub. |
| 183 | + {"github.com/user/unicode/испытание", false, false, true}, |
| 184 | + |
| 185 | + {"../x", false, false, false}, |
| 186 | + {"./y", false, false, false}, |
| 187 | + {"x:y", false, false, false}, |
| 188 | + {`\temp\foo`, false, false, false}, |
| 189 | + {".gitignore", false, true, true}, |
| 190 | + {".github/ISSUE_TEMPLATE", false, true, true}, |
| 191 | + {"x☺y", false, false, false}, |
| 192 | +} |
| 193 | + |
| 194 | +func TestCheckPath(t *testing.T) { |
| 195 | + for _, tt := range checkPathTests { |
| 196 | + err := CheckPath(tt.path) |
| 197 | + if tt.ok && err != nil { |
| 198 | + t.Errorf("CheckPath(%q) = %v, wanted nil error", tt.path, err) |
| 199 | + } else if !tt.ok && err == nil { |
| 200 | + t.Errorf("CheckPath(%q) succeeded, wanted error", tt.path) |
| 201 | + } |
| 202 | + |
| 203 | + err = CheckImportPath(tt.path) |
| 204 | + if tt.importOK && err != nil { |
| 205 | + t.Errorf("CheckImportPath(%q) = %v, wanted nil error", tt.path, err) |
| 206 | + } else if !tt.importOK && err == nil { |
| 207 | + t.Errorf("CheckImportPath(%q) succeeded, wanted error", tt.path) |
| 208 | + } |
| 209 | + |
| 210 | + err = CheckFilePath(tt.path) |
| 211 | + if tt.fileOK && err != nil { |
| 212 | + t.Errorf("CheckFilePath(%q) = %v, wanted nil error", tt.path, err) |
| 213 | + } else if !tt.fileOK && err == nil { |
| 214 | + t.Errorf("CheckFilePath(%q) succeeded, wanted error", tt.path) |
| 215 | + } |
| 216 | + } |
| 217 | +} |
| 218 | + |
| 219 | +var splitPathVersionTests = []struct { |
| 220 | + pathPrefix string |
| 221 | + version string |
| 222 | +}{ |
| 223 | + {"x.y/z", ""}, |
| 224 | + {"x.y/z", "/v2"}, |
| 225 | + {"x.y/z", "/v3"}, |
| 226 | + {"x.y/v", ""}, |
| 227 | + {"gopkg.in/yaml", ".v0"}, |
| 228 | + {"gopkg.in/yaml", ".v1"}, |
| 229 | + {"gopkg.in/yaml", ".v2"}, |
| 230 | + {"gopkg.in/yaml", ".v3"}, |
| 231 | +} |
| 232 | + |
| 233 | +func TestSplitPathVersion(t *testing.T) { |
| 234 | + for _, tt := range splitPathVersionTests { |
| 235 | + pathPrefix, version, ok := SplitPathVersion(tt.pathPrefix + tt.version) |
| 236 | + if pathPrefix != tt.pathPrefix || version != tt.version || !ok { |
| 237 | + t.Errorf("SplitPathVersion(%q) = %q, %q, %v, want %q, %q, true", tt.pathPrefix+tt.version, pathPrefix, version, ok, tt.pathPrefix, tt.version) |
| 238 | + } |
| 239 | + } |
| 240 | + |
| 241 | + for _, tt := range checkPathTests { |
| 242 | + pathPrefix, version, ok := SplitPathVersion(tt.path) |
| 243 | + if pathPrefix+version != tt.path { |
| 244 | + t.Errorf("SplitPathVersion(%q) = %q, %q, %v, doesn't add to input", tt.path, pathPrefix, version, ok) |
| 245 | + } |
| 246 | + } |
| 247 | +} |
| 248 | + |
| 249 | +var escapeTests = []struct { |
| 250 | + path string |
| 251 | + esc string // empty means same as path |
| 252 | +}{ |
| 253 | + {path: "ascii.com/abcdefghijklmnopqrstuvwxyz.-/~_0123456789"}, |
| 254 | + {path: "github.com/GoogleCloudPlatform/omega", esc: "github.com/!google!cloud!platform/omega"}, |
| 255 | +} |
| 256 | + |
| 257 | +func TestEscapePath(t *testing.T) { |
| 258 | + // Check invalid paths. |
| 259 | + for _, tt := range checkPathTests { |
| 260 | + if !tt.ok { |
| 261 | + _, err := EscapePath(tt.path) |
| 262 | + if err == nil { |
| 263 | + t.Errorf("EscapePath(%q): succeeded, want error (invalid path)", tt.path) |
| 264 | + } |
| 265 | + } |
| 266 | + } |
| 267 | + |
| 268 | + // Check encodings. |
| 269 | + for _, tt := range escapeTests { |
| 270 | + esc, err := EscapePath(tt.path) |
| 271 | + if err != nil { |
| 272 | + t.Errorf("EscapePath(%q): unexpected error: %v", tt.path, err) |
| 273 | + continue |
| 274 | + } |
| 275 | + want := tt.esc |
| 276 | + if want == "" { |
| 277 | + want = tt.path |
| 278 | + } |
| 279 | + if esc != want { |
| 280 | + t.Errorf("EscapePath(%q) = %q, want %q", tt.path, esc, want) |
| 281 | + } |
| 282 | + } |
| 283 | +} |
| 284 | + |
| 285 | +var badUnescape = []string{ |
| 286 | + "github.com/GoogleCloudPlatform/omega", |
| 287 | + "github.com/!google!cloud!platform!/omega", |
| 288 | + "github.com/!0google!cloud!platform/omega", |
| 289 | + "github.com/!_google!cloud!platform/omega", |
| 290 | + "github.com/!!google!cloud!platform/omega", |
| 291 | + "", |
| 292 | +} |
| 293 | + |
| 294 | +func TestUnescapePath(t *testing.T) { |
| 295 | + // Check invalid decodings. |
| 296 | + for _, bad := range badUnescape { |
| 297 | + _, err := UnescapePath(bad) |
| 298 | + if err == nil { |
| 299 | + t.Errorf("UnescapePath(%q): succeeded, want error (invalid decoding)", bad) |
| 300 | + } |
| 301 | + } |
| 302 | + |
| 303 | + // Check invalid paths (or maybe decodings). |
| 304 | + for _, tt := range checkPathTests { |
| 305 | + if !tt.ok { |
| 306 | + path, err := UnescapePath(tt.path) |
| 307 | + if err == nil { |
| 308 | + t.Errorf("UnescapePath(%q) = %q, want error (invalid path)", tt.path, path) |
| 309 | + } |
| 310 | + } |
| 311 | + } |
| 312 | + |
| 313 | + // Check encodings. |
| 314 | + for _, tt := range escapeTests { |
| 315 | + esc := tt.esc |
| 316 | + if esc == "" { |
| 317 | + esc = tt.path |
| 318 | + } |
| 319 | + path, err := UnescapePath(esc) |
| 320 | + if err != nil { |
| 321 | + t.Errorf("UnescapePath(%q): unexpected error: %v", esc, err) |
| 322 | + continue |
| 323 | + } |
| 324 | + if path != tt.path { |
| 325 | + t.Errorf("UnescapePath(%q) = %q, want %q", esc, path, tt.path) |
| 326 | + } |
| 327 | + } |
| 328 | +} |
| 329 | + |
| 330 | +func TestMatchPathMajor(t *testing.T) { |
| 331 | + for _, test := range []struct { |
| 332 | + v, pathMajor string |
| 333 | + want bool |
| 334 | + }{ |
| 335 | + {"v0.0.0", "", true}, |
| 336 | + {"v0.0.0", "/v2", false}, |
| 337 | + {"v0.0.0", ".v0", true}, |
| 338 | + {"v0.0.0-20190510104115-cbcb75029529", ".v1", true}, |
| 339 | + {"v1.0.0", "/v2", false}, |
| 340 | + {"v1.0.0", ".v1", true}, |
| 341 | + {"v1.0.0", ".v1-unstable", true}, |
| 342 | + {"v2.0.0+incompatible", "", true}, |
| 343 | + {"v2.0.0", "", false}, |
| 344 | + {"v2.0.0", "/v2", true}, |
| 345 | + {"v2.0.0", ".v2", true}, |
| 346 | + } { |
| 347 | + if got := MatchPathMajor(test.v, test.pathMajor); got != test.want { |
| 348 | + t.Errorf("MatchPathMajor(%q, %q) = %v, want %v", test.v, test.pathMajor, got, test.want) |
| 349 | + } |
| 350 | + } |
| 351 | +} |
| 352 | + |
| 353 | +func TestMatchPrefixPatterns(t *testing.T) { |
| 354 | + for _, test := range []struct { |
| 355 | + globs, target string |
| 356 | + want bool |
| 357 | + }{ |
| 358 | + {"", "rsc.io/quote", false}, |
| 359 | + {"/", "rsc.io/quote", false}, |
| 360 | + {"*/quote", "rsc.io/quote", true}, |
| 361 | + {"*/quo", "rsc.io/quote", false}, |
| 362 | + {"*/quo??", "rsc.io/quote", true}, |
| 363 | + {"*/quo*", "rsc.io/quote", true}, |
| 364 | + {"*quo*", "rsc.io/quote", false}, |
| 365 | + {"rsc.io", "rsc.io/quote", true}, |
| 366 | + {"*.io", "rsc.io/quote", true}, |
| 367 | + {"rsc.io/", "rsc.io/quote", true}, |
| 368 | + {"rsc", "rsc.io/quote", false}, |
| 369 | + {"rsc*", "rsc.io/quote", true}, |
| 370 | + |
| 371 | + {"rsc.io", "rsc.io/quote/v3", true}, |
| 372 | + {"*/quote", "rsc.io/quote/v3", true}, |
| 373 | + {"*/quote/", "rsc.io/quote/v3", true}, |
| 374 | + {"*/quote/*", "rsc.io/quote/v3", true}, |
| 375 | + {"*/quote/*/", "rsc.io/quote/v3", true}, |
| 376 | + {"*/v3", "rsc.io/quote/v3", false}, |
| 377 | + {"*/*/v3", "rsc.io/quote/v3", true}, |
| 378 | + {"*/*/*", "rsc.io/quote/v3", true}, |
| 379 | + {"*/*/*/", "rsc.io/quote/v3", true}, |
| 380 | + {"*/*/*", "rsc.io/quote", false}, |
| 381 | + {"*/*/*/", "rsc.io/quote", false}, |
| 382 | + |
| 383 | + {"*/*/*,,", "rsc.io/quote", false}, |
| 384 | + {"*/*/*,,*/quote", "rsc.io/quote", true}, |
| 385 | + {",,*/quote", "rsc.io/quote", true}, |
| 386 | + } { |
| 387 | + if got := MatchPrefixPatterns(test.globs, test.target); got != test.want { |
| 388 | + t.Errorf("MatchPrefixPatterns(%q, %q) = %t, want %t", test.globs, test.target, got, test.want) |
| 389 | + } |
| 390 | + } |
| 391 | +} |
0 commit comments