github.com/zxy12/go_duplicate_112_new@v0.0.0-20200807091221-747231827200/src/cmd/go/internal/modfetch/coderepo_test.go (about) 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. 4 5 package modfetch 6 7 import ( 8 "archive/zip" 9 "internal/testenv" 10 "io" 11 "io/ioutil" 12 "log" 13 "os" 14 "reflect" 15 "strings" 16 "testing" 17 "time" 18 19 "cmd/go/internal/modfetch/codehost" 20 ) 21 22 func TestMain(m *testing.M) { 23 os.Exit(testMain(m)) 24 } 25 26 func testMain(m *testing.M) int { 27 dir, err := ioutil.TempDir("", "gitrepo-test-") 28 if err != nil { 29 log.Fatal(err) 30 } 31 defer os.RemoveAll(dir) 32 33 codehost.WorkRoot = dir 34 return m.Run() 35 } 36 37 const ( 38 vgotest1git = "github.com/rsc/vgotest1" 39 vgotest1hg = "vcs-test.golang.org/hg/vgotest1.hg" 40 ) 41 42 var altVgotests = []string{ 43 vgotest1hg, 44 } 45 46 var codeRepoTests = []struct { 47 path string 48 lookerr string 49 mpath string 50 rev string 51 err string 52 version string 53 name string 54 short string 55 time time.Time 56 gomod string 57 gomoderr string 58 zip []string 59 ziperr string 60 }{ 61 { 62 path: "github.com/rsc/vgotest1", 63 rev: "v0.0.0", 64 version: "v0.0.0", 65 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", 66 short: "80d85c5d4d17", 67 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), 68 zip: []string{ 69 "LICENSE", 70 "README.md", 71 "pkg/p.go", 72 }, 73 }, 74 { 75 path: "github.com/rsc/vgotest1", 76 rev: "v1.0.0", 77 version: "v1.0.0", 78 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", 79 short: "80d85c5d4d17", 80 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), 81 zip: []string{ 82 "LICENSE", 83 "README.md", 84 "pkg/p.go", 85 }, 86 }, 87 { 88 path: "github.com/rsc/vgotest1/v2", 89 rev: "v2.0.0", 90 version: "v2.0.0", 91 name: "45f53230a74ad275c7127e117ac46914c8126160", 92 short: "45f53230a74a", 93 time: time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC), 94 ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0", 95 }, 96 { 97 path: "github.com/rsc/vgotest1", 98 rev: "80d85c5", 99 version: "v1.0.0", 100 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", 101 short: "80d85c5d4d17", 102 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), 103 zip: []string{ 104 "LICENSE", 105 "README.md", 106 "pkg/p.go", 107 }, 108 }, 109 { 110 path: "github.com/rsc/vgotest1", 111 rev: "mytag", 112 version: "v1.0.0", 113 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", 114 short: "80d85c5d4d17", 115 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), 116 zip: []string{ 117 "LICENSE", 118 "README.md", 119 "pkg/p.go", 120 }, 121 }, 122 { 123 path: "github.com/rsc/vgotest1/v2", 124 rev: "45f53230a", 125 version: "v2.0.0", 126 name: "45f53230a74ad275c7127e117ac46914c8126160", 127 short: "45f53230a74a", 128 time: time.Date(2018, 7, 19, 1, 21, 27, 0, time.UTC), 129 gomoderr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0", 130 ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v2/go.mod at revision v2.0.0", 131 }, 132 { 133 path: "github.com/rsc/vgotest1/v54321", 134 rev: "80d85c5", 135 version: "v54321.0.0-20180219231006-80d85c5d4d17", 136 name: "80d85c5d4d17598a0e9055e7c175a32b415d6128", 137 short: "80d85c5d4d17", 138 time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC), 139 ziperr: "missing github.com/rsc/vgotest1/go.mod and .../v54321/go.mod at revision 80d85c5d4d17", 140 }, 141 { 142 path: "github.com/rsc/vgotest1/submod", 143 rev: "v1.0.0", 144 err: "unknown revision submod/v1.0.0", 145 }, 146 { 147 path: "github.com/rsc/vgotest1/submod", 148 rev: "v1.0.3", 149 err: "unknown revision submod/v1.0.3", 150 }, 151 { 152 path: "github.com/rsc/vgotest1/submod", 153 rev: "v1.0.4", 154 version: "v1.0.4", 155 name: "8afe2b2efed96e0880ecd2a69b98a53b8c2738b6", 156 short: "8afe2b2efed9", 157 time: time.Date(2018, 2, 19, 23, 12, 7, 0, time.UTC), 158 gomod: "module \"github.com/vgotest1/submod\" // submod/go.mod\n", 159 zip: []string{ 160 "go.mod", 161 "pkg/p.go", 162 "LICENSE", 163 }, 164 }, 165 { 166 path: "github.com/rsc/vgotest1", 167 rev: "v1.1.0", 168 version: "v1.1.0", 169 name: "b769f2de407a4db81af9c5de0a06016d60d2ea09", 170 short: "b769f2de407a", 171 time: time.Date(2018, 2, 19, 23, 13, 36, 0, time.UTC), 172 gomod: "module \"github.com/rsc/vgotest1\" // root go.mod\nrequire \"github.com/rsc/vgotest1/submod\" v1.0.5\n", 173 zip: []string{ 174 "LICENSE", 175 "README.md", 176 "go.mod", 177 "pkg/p.go", 178 }, 179 }, 180 { 181 path: "github.com/rsc/vgotest1/v2", 182 rev: "v2.0.1", 183 version: "v2.0.1", 184 name: "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9", 185 short: "ea65f87c8f52", 186 time: time.Date(2018, 2, 19, 23, 14, 23, 0, time.UTC), 187 gomod: "module \"github.com/rsc/vgotest1/v2\" // root go.mod\n", 188 }, 189 { 190 path: "github.com/rsc/vgotest1/v2", 191 rev: "v2.0.3", 192 version: "v2.0.3", 193 name: "f18795870fb14388a21ef3ebc1d75911c8694f31", 194 short: "f18795870fb1", 195 time: time.Date(2018, 2, 19, 23, 16, 4, 0, time.UTC), 196 gomoderr: "github.com/rsc/vgotest1/v2/go.mod has non-.../v2 module path \"github.com/rsc/vgotest\" at revision v2.0.3", 197 }, 198 { 199 path: "github.com/rsc/vgotest1/v2", 200 rev: "v2.0.4", 201 version: "v2.0.4", 202 name: "1f863feb76bc7029b78b21c5375644838962f88d", 203 short: "1f863feb76bc", 204 time: time.Date(2018, 2, 20, 0, 3, 38, 0, time.UTC), 205 gomoderr: "github.com/rsc/vgotest1/go.mod and .../v2/go.mod both have .../v2 module paths at revision v2.0.4", 206 }, 207 { 208 path: "github.com/rsc/vgotest1/v2", 209 rev: "v2.0.5", 210 version: "v2.0.5", 211 name: "2f615117ce481c8efef46e0cc0b4b4dccfac8fea", 212 short: "2f615117ce48", 213 time: time.Date(2018, 2, 20, 0, 3, 59, 0, time.UTC), 214 gomod: "module \"github.com/rsc/vgotest1/v2\" // v2/go.mod\n", 215 }, 216 { 217 // redirect to github 218 path: "rsc.io/quote", 219 rev: "v1.0.0", 220 version: "v1.0.0", 221 name: "f488df80bcdbd3e5bafdc24ad7d1e79e83edd7e6", 222 short: "f488df80bcdb", 223 time: time.Date(2018, 2, 14, 0, 45, 20, 0, time.UTC), 224 gomod: "module \"rsc.io/quote\"\n", 225 }, 226 { 227 // redirect to static hosting proxy 228 path: "swtch.com/testmod", 229 rev: "v1.0.0", 230 version: "v1.0.0", 231 // NO name or short - we intentionally ignore those in the proxy protocol 232 time: time.Date(1972, 7, 18, 12, 34, 56, 0, time.UTC), 233 gomod: "module \"swtch.com/testmod\"\n", 234 }, 235 { 236 // redirect to googlesource 237 path: "golang.org/x/text", 238 rev: "4e4a3210bb", 239 version: "v0.3.1-0.20180208041248-4e4a3210bb54", 240 name: "4e4a3210bb54bb31f6ab2cdca2edcc0b50c420c1", 241 short: "4e4a3210bb54", 242 time: time.Date(2018, 2, 8, 4, 12, 48, 0, time.UTC), 243 }, 244 { 245 path: "github.com/pkg/errors", 246 rev: "v0.8.0", 247 version: "v0.8.0", 248 name: "645ef00459ed84a119197bfb8d8205042c6df63d", 249 short: "645ef00459ed", 250 time: time.Date(2016, 9, 29, 1, 48, 1, 0, time.UTC), 251 }, 252 { 253 // package in subdirectory - custom domain 254 // In general we can't reject these definitively in Lookup, 255 // but gopkg.in is special. 256 path: "gopkg.in/yaml.v2/abc", 257 lookerr: "invalid module path \"gopkg.in/yaml.v2/abc\"", 258 }, 259 { 260 // package in subdirectory - github 261 // Because it's a package, Stat should fail entirely. 262 path: "github.com/rsc/quote/buggy", 263 rev: "c4d4236f", 264 err: "missing github.com/rsc/quote/buggy/go.mod at revision c4d4236f9242", 265 }, 266 { 267 path: "gopkg.in/yaml.v2", 268 rev: "d670f940", 269 version: "v2.0.0", 270 name: "d670f9405373e636a5a2765eea47fac0c9bc91a4", 271 short: "d670f9405373", 272 time: time.Date(2018, 1, 9, 11, 43, 31, 0, time.UTC), 273 gomod: "module gopkg.in/yaml.v2\n", 274 }, 275 { 276 path: "gopkg.in/check.v1", 277 rev: "20d25e280405", 278 version: "v1.0.0-20161208181325-20d25e280405", 279 name: "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec", 280 short: "20d25e280405", 281 time: time.Date(2016, 12, 8, 18, 13, 25, 0, time.UTC), 282 gomod: "module gopkg.in/check.v1\n", 283 }, 284 { 285 path: "gopkg.in/yaml.v2", 286 rev: "v2", 287 version: "v2.2.2", 288 name: "51d6538a90f86fe93ac480b35f37b2be17fef232", 289 short: "51d6538a90f8", 290 time: time.Date(2018, 11, 15, 11, 05, 04, 0, time.UTC), 291 gomod: "module \"gopkg.in/yaml.v2\"\n\nrequire (\n\t\"gopkg.in/check.v1\" v0.0.0-20161208181325-20d25e280405\n)\n", 292 }, 293 { 294 path: "vcs-test.golang.org/go/mod/gitrepo1", 295 rev: "master", 296 version: "v1.2.4-annotated", 297 name: "ede458df7cd0fdca520df19a33158086a8a68e81", 298 short: "ede458df7cd0", 299 time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), 300 gomod: "module vcs-test.golang.org/go/mod/gitrepo1\n", 301 }, 302 { 303 path: "gopkg.in/natefinch/lumberjack.v2", 304 rev: "latest", 305 version: "v2.0.0-20170531160350-a96e63847dc3", 306 name: "a96e63847dc3c67d17befa69c303767e2f84e54f", 307 short: "a96e63847dc3", 308 time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC), 309 gomod: "module gopkg.in/natefinch/lumberjack.v2\n", 310 }, 311 { 312 path: "gopkg.in/natefinch/lumberjack.v2", 313 // This repo has a v2.1 tag. 314 // We only allow semver references to tags that are fully qualified, as in v2.1.0. 315 // Because we can't record v2.1.0 (the actual tag is v2.1), we record a pseudo-version 316 // instead, same as if the tag were any other non-version-looking string. 317 // We use a v2 pseudo-version here because of the .v2 in the path, not because 318 // of the v2 in the rev. 319 rev: "v2.1", // non-canonical semantic version turns into pseudo-version 320 version: "v2.0.0-20170531160350-a96e63847dc3", 321 name: "a96e63847dc3c67d17befa69c303767e2f84e54f", 322 short: "a96e63847dc3", 323 time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC), 324 gomod: "module gopkg.in/natefinch/lumberjack.v2\n", 325 }, 326 { 327 path: "nanomsg.org/go/mangos/v2", 328 rev: "v2.0.2", 329 version: "v2.0.2", 330 name: "63f66a65137b9a648ac9f7bf0160b4a4d17d7999", 331 short: "63f66a65137b", 332 time: time.Date(2018, 12, 1, 15, 7, 40, 0, time.UTC), 333 gomod: "module nanomsg.org/go/mangos/v2\n\nrequire (\n\tgithub.com/Microsoft/go-winio v0.4.11\n\tgithub.com/droundy/goopt v0.0.0-20170604162106-0b8effe182da\n\tgithub.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect\n\tgithub.com/gorilla/websocket v1.4.0\n\tgithub.com/jtolds/gls v4.2.1+incompatible // indirect\n\tgithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect\n\tgithub.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c\n\tgolang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 // indirect\n)\n", 334 }, 335 } 336 337 func TestCodeRepo(t *testing.T) { 338 testenv.MustHaveExternalNetwork(t) 339 340 tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-") 341 if err != nil { 342 t.Fatal(err) 343 } 344 defer os.RemoveAll(tmpdir) 345 for _, tt := range codeRepoTests { 346 f := func(t *testing.T) { 347 repo, err := Lookup(tt.path) 348 if tt.lookerr != "" { 349 if err != nil && err.Error() == tt.lookerr { 350 return 351 } 352 t.Errorf("Lookup(%q): %v, want error %q", tt.path, err, tt.lookerr) 353 } 354 if err != nil { 355 t.Fatalf("Lookup(%q): %v", tt.path, err) 356 } 357 if tt.mpath == "" { 358 tt.mpath = tt.path 359 } 360 if mpath := repo.ModulePath(); mpath != tt.mpath { 361 t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath) 362 } 363 info, err := repo.Stat(tt.rev) 364 if err != nil { 365 if tt.err != "" { 366 if !strings.Contains(err.Error(), tt.err) { 367 t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err) 368 } 369 return 370 } 371 t.Fatalf("repo.Stat(%q): %v", tt.rev, err) 372 } 373 if tt.err != "" { 374 t.Errorf("repo.Stat(%q): success, wanted error", tt.rev) 375 } 376 if info.Version != tt.version { 377 t.Errorf("info.Version = %q, want %q", info.Version, tt.version) 378 } 379 if info.Name != tt.name { 380 t.Errorf("info.Name = %q, want %q", info.Name, tt.name) 381 } 382 if info.Short != tt.short { 383 t.Errorf("info.Short = %q, want %q", info.Short, tt.short) 384 } 385 if !info.Time.Equal(tt.time) { 386 t.Errorf("info.Time = %v, want %v", info.Time, tt.time) 387 } 388 if tt.gomod != "" || tt.gomoderr != "" { 389 data, err := repo.GoMod(tt.version) 390 if err != nil && tt.gomoderr == "" { 391 t.Errorf("repo.GoMod(%q): %v", tt.version, err) 392 } else if err != nil && tt.gomoderr != "" { 393 if err.Error() != tt.gomoderr { 394 t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomoderr) 395 } 396 } else if tt.gomoderr != "" { 397 t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomoderr) 398 } else if string(data) != tt.gomod { 399 t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod) 400 } 401 } 402 if tt.zip != nil || tt.ziperr != "" { 403 f, err := ioutil.TempFile(tmpdir, tt.version+".zip.") 404 if err != nil { 405 t.Fatalf("ioutil.TempFile: %v", err) 406 } 407 zipfile := f.Name() 408 err = repo.Zip(f, tt.version) 409 f.Close() 410 if err != nil { 411 if tt.ziperr != "" { 412 if err.Error() == tt.ziperr { 413 return 414 } 415 t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.ziperr) 416 } 417 t.Fatalf("repo.Zip(%q): %v", tt.version, err) 418 } 419 if tt.ziperr != "" { 420 t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.ziperr) 421 } 422 prefix := tt.path + "@" + tt.version + "/" 423 z, err := zip.OpenReader(zipfile) 424 if err != nil { 425 t.Fatalf("open zip %s: %v", zipfile, err) 426 } 427 var names []string 428 for _, file := range z.File { 429 if !strings.HasPrefix(file.Name, prefix) { 430 t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix) 431 continue 432 } 433 names = append(names, file.Name[len(prefix):]) 434 } 435 z.Close() 436 if !reflect.DeepEqual(names, tt.zip) { 437 t.Fatalf("zip = %v\nwant %v\n", names, tt.zip) 438 } 439 } 440 } 441 t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f) 442 if strings.HasPrefix(tt.path, vgotest1git) { 443 for _, alt := range altVgotests { 444 // Note: Communicating with f through tt; should be cleaned up. 445 old := tt 446 tt.path = alt + strings.TrimPrefix(tt.path, vgotest1git) 447 if strings.HasPrefix(tt.mpath, vgotest1git) { 448 tt.mpath = alt + strings.TrimPrefix(tt.mpath, vgotest1git) 449 } 450 var m map[string]string 451 if alt == vgotest1hg { 452 m = hgmap 453 } 454 tt.version = remap(tt.version, m) 455 tt.name = remap(tt.name, m) 456 tt.short = remap(tt.short, m) 457 tt.rev = remap(tt.rev, m) 458 tt.gomoderr = remap(tt.gomoderr, m) 459 tt.ziperr = remap(tt.ziperr, m) 460 t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f) 461 tt = old 462 } 463 } 464 } 465 } 466 467 var hgmap = map[string]string{ 468 "github.com/rsc/vgotest1/": "vcs-test.golang.org/hg/vgotest1.hg/", 469 "f18795870fb14388a21ef3ebc1d75911c8694f31": "a9ad6d1d14eb544f459f446210c7eb3b009807c6", 470 "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9": "f1fc0f22021b638d073d31c752847e7bf385def7", 471 "b769f2de407a4db81af9c5de0a06016d60d2ea09": "92c7eb888b4fac17f1c6bd2e1060a1b881a3b832", 472 "8afe2b2efed96e0880ecd2a69b98a53b8c2738b6": "4e58084d459ae7e79c8c2264d0e8e9a92eb5cd44", 473 "2f615117ce481c8efef46e0cc0b4b4dccfac8fea": "879ea98f7743c8eff54f59a918f3a24123d1cf46", 474 "80d85c5d4d17598a0e9055e7c175a32b415d6128": "e125018e286a4b09061079a81e7b537070b7ff71", 475 "1f863feb76bc7029b78b21c5375644838962f88d": "bf63880162304a9337477f3858f5b7e255c75459", 476 "45f53230a74ad275c7127e117ac46914c8126160": "814fce58e83abd5bf2a13892e0b0e1198abefcd4", 477 } 478 479 func remap(name string, m map[string]string) string { 480 if m[name] != "" { 481 return m[name] 482 } 483 if codehost.AllHex(name) { 484 for k, v := range m { 485 if strings.HasPrefix(k, name) { 486 return v[:len(name)] 487 } 488 } 489 } 490 for k, v := range m { 491 name = strings.ReplaceAll(name, k, v) 492 if codehost.AllHex(k) { 493 name = strings.ReplaceAll(name, k[:12], v[:12]) 494 } 495 } 496 return name 497 } 498 499 var codeRepoVersionsTests = []struct { 500 path string 501 prefix string 502 versions []string 503 }{ 504 { 505 path: "github.com/rsc/vgotest1", 506 versions: []string{"v0.0.0", "v0.0.1", "v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3", "v1.1.0", "v2.0.0+incompatible"}, 507 }, 508 { 509 path: "github.com/rsc/vgotest1", 510 prefix: "v1.0", 511 versions: []string{"v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3"}, 512 }, 513 { 514 path: "github.com/rsc/vgotest1/v2", 515 versions: []string{"v2.0.0", "v2.0.1", "v2.0.2", "v2.0.3", "v2.0.4", "v2.0.5", "v2.0.6"}, 516 }, 517 { 518 path: "swtch.com/testmod", 519 versions: []string{"v1.0.0", "v1.1.1"}, 520 }, 521 { 522 path: "gopkg.in/russross/blackfriday.v2", 523 versions: []string{"v2.0.0", "v2.0.1"}, 524 }, 525 { 526 path: "gopkg.in/natefinch/lumberjack.v2", 527 versions: []string{"v2.0.0"}, 528 }, 529 } 530 531 func TestCodeRepoVersions(t *testing.T) { 532 testenv.MustHaveExternalNetwork(t) 533 534 tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-") 535 if err != nil { 536 t.Fatal(err) 537 } 538 defer os.RemoveAll(tmpdir) 539 for _, tt := range codeRepoVersionsTests { 540 t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) { 541 repo, err := Lookup(tt.path) 542 if err != nil { 543 t.Fatalf("Lookup(%q): %v", tt.path, err) 544 } 545 list, err := repo.Versions(tt.prefix) 546 if err != nil { 547 t.Fatalf("Versions(%q): %v", tt.prefix, err) 548 } 549 if !reflect.DeepEqual(list, tt.versions) { 550 t.Fatalf("Versions(%q):\nhave %v\nwant %v", tt.prefix, list, tt.versions) 551 } 552 }) 553 } 554 } 555 556 var latestTests = []struct { 557 path string 558 version string 559 err string 560 }{ 561 { 562 path: "github.com/rsc/empty", 563 err: "no commits", 564 }, 565 { 566 path: "github.com/rsc/vgotest1", 567 version: "v0.0.0-20180219223237-a08abb797a67", 568 }, 569 { 570 path: "github.com/rsc/vgotest1/subdir", 571 err: "missing github.com/rsc/vgotest1/subdir/go.mod at revision a08abb797a67", 572 }, 573 { 574 path: "swtch.com/testmod", 575 version: "v1.1.1", 576 }, 577 } 578 579 func TestLatest(t *testing.T) { 580 testenv.MustHaveExternalNetwork(t) 581 582 tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-") 583 if err != nil { 584 t.Fatal(err) 585 } 586 defer os.RemoveAll(tmpdir) 587 for _, tt := range latestTests { 588 name := strings.ReplaceAll(tt.path, "/", "_") 589 t.Run(name, func(t *testing.T) { 590 repo, err := Lookup(tt.path) 591 if err != nil { 592 t.Fatalf("Lookup(%q): %v", tt.path, err) 593 } 594 info, err := repo.Latest() 595 if err != nil { 596 if tt.err != "" { 597 if err.Error() == tt.err { 598 return 599 } 600 t.Fatalf("Latest(): %v, want %q", err, tt.err) 601 } 602 t.Fatalf("Latest(): %v", err) 603 } 604 if tt.err != "" { 605 t.Fatalf("Latest() = %v, want error %q", info.Version, tt.err) 606 } 607 if info.Version != tt.version { 608 t.Fatalf("Latest() = %v, want %v", info.Version, tt.version) 609 } 610 }) 611 } 612 } 613 614 // fixedTagsRepo is a fake codehost.Repo that returns a fixed list of tags 615 type fixedTagsRepo struct { 616 tags []string 617 } 618 619 func (ch *fixedTagsRepo) Tags(string) ([]string, error) { return ch.tags, nil } 620 func (ch *fixedTagsRepo) Latest() (*codehost.RevInfo, error) { panic("not impl") } 621 func (ch *fixedTagsRepo) ReadFile(string, string, int64) ([]byte, error) { panic("not impl") } 622 func (ch *fixedTagsRepo) ReadFileRevs([]string, string, int64) (map[string]*codehost.FileRev, error) { 623 panic("not impl") 624 } 625 func (ch *fixedTagsRepo) ReadZip(string, string, int64) (io.ReadCloser, string, error) { 626 panic("not impl") 627 } 628 func (ch *fixedTagsRepo) RecentTag(string, string) (string, error) { 629 panic("not impl") 630 } 631 func (ch *fixedTagsRepo) Stat(string) (*codehost.RevInfo, error) { panic("not impl") } 632 633 func TestNonCanonicalSemver(t *testing.T) { 634 root := "golang.org/x/issue24476" 635 ch := &fixedTagsRepo{ 636 tags: []string{ 637 "", "huh?", "1.0.1", 638 // what about "version 1 dot dogcow"? 639 "v1.🐕.🐄", 640 "v1", "v0.1", 641 // and one normal one that should pass through 642 "v1.0.1", 643 }, 644 } 645 646 cr, err := newCodeRepo(ch, root, root) 647 if err != nil { 648 t.Fatal(err) 649 } 650 651 v, err := cr.Versions("") 652 if err != nil { 653 t.Fatal(err) 654 } 655 if len(v) != 1 || v[0] != "v1.0.1" { 656 t.Fatal("unexpected versions returned:", v) 657 } 658 }