github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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 328 func TestCodeRepo(t *testing.T) { 329 testenv.MustHaveExternalNetwork(t) 330 331 tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-") 332 if err != nil { 333 t.Fatal(err) 334 } 335 defer os.RemoveAll(tmpdir) 336 for _, tt := range codeRepoTests { 337 f := func(t *testing.T) { 338 repo, err := Lookup(tt.path) 339 if tt.lookerr != "" { 340 if err != nil && err.Error() == tt.lookerr { 341 return 342 } 343 t.Errorf("Lookup(%q): %v, want error %q", tt.path, err, tt.lookerr) 344 } 345 if err != nil { 346 t.Fatalf("Lookup(%q): %v", tt.path, err) 347 } 348 if tt.mpath == "" { 349 tt.mpath = tt.path 350 } 351 if mpath := repo.ModulePath(); mpath != tt.mpath { 352 t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath) 353 } 354 info, err := repo.Stat(tt.rev) 355 if err != nil { 356 if tt.err != "" { 357 if !strings.Contains(err.Error(), tt.err) { 358 t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err) 359 } 360 return 361 } 362 t.Fatalf("repo.Stat(%q): %v", tt.rev, err) 363 } 364 if tt.err != "" { 365 t.Errorf("repo.Stat(%q): success, wanted error", tt.rev) 366 } 367 if info.Version != tt.version { 368 t.Errorf("info.Version = %q, want %q", info.Version, tt.version) 369 } 370 if info.Name != tt.name { 371 t.Errorf("info.Name = %q, want %q", info.Name, tt.name) 372 } 373 if info.Short != tt.short { 374 t.Errorf("info.Short = %q, want %q", info.Short, tt.short) 375 } 376 if !info.Time.Equal(tt.time) { 377 t.Errorf("info.Time = %v, want %v", info.Time, tt.time) 378 } 379 if tt.gomod != "" || tt.gomoderr != "" { 380 data, err := repo.GoMod(tt.version) 381 if err != nil && tt.gomoderr == "" { 382 t.Errorf("repo.GoMod(%q): %v", tt.version, err) 383 } else if err != nil && tt.gomoderr != "" { 384 if err.Error() != tt.gomoderr { 385 t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomoderr) 386 } 387 } else if tt.gomoderr != "" { 388 t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomoderr) 389 } else if string(data) != tt.gomod { 390 t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod) 391 } 392 } 393 if tt.zip != nil || tt.ziperr != "" { 394 f, err := ioutil.TempFile(tmpdir, tt.version+".zip.") 395 if err != nil { 396 t.Fatalf("ioutil.TempFile: %v", err) 397 } 398 zipfile := f.Name() 399 err = repo.Zip(f, tt.version) 400 f.Close() 401 if err != nil { 402 if tt.ziperr != "" { 403 if err.Error() == tt.ziperr { 404 return 405 } 406 t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.ziperr) 407 } 408 t.Fatalf("repo.Zip(%q): %v", tt.version, err) 409 } 410 if tt.ziperr != "" { 411 t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.ziperr) 412 } 413 prefix := tt.path + "@" + tt.version + "/" 414 z, err := zip.OpenReader(zipfile) 415 if err != nil { 416 t.Fatalf("open zip %s: %v", zipfile, err) 417 } 418 var names []string 419 for _, file := range z.File { 420 if !strings.HasPrefix(file.Name, prefix) { 421 t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix) 422 continue 423 } 424 names = append(names, file.Name[len(prefix):]) 425 } 426 z.Close() 427 if !reflect.DeepEqual(names, tt.zip) { 428 t.Fatalf("zip = %v\nwant %v\n", names, tt.zip) 429 } 430 } 431 } 432 t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f) 433 if strings.HasPrefix(tt.path, vgotest1git) { 434 for _, alt := range altVgotests { 435 // Note: Communicating with f through tt; should be cleaned up. 436 old := tt 437 tt.path = alt + strings.TrimPrefix(tt.path, vgotest1git) 438 if strings.HasPrefix(tt.mpath, vgotest1git) { 439 tt.mpath = alt + strings.TrimPrefix(tt.mpath, vgotest1git) 440 } 441 var m map[string]string 442 if alt == vgotest1hg { 443 m = hgmap 444 } 445 tt.version = remap(tt.version, m) 446 tt.name = remap(tt.name, m) 447 tt.short = remap(tt.short, m) 448 tt.rev = remap(tt.rev, m) 449 tt.gomoderr = remap(tt.gomoderr, m) 450 tt.ziperr = remap(tt.ziperr, m) 451 t.Run(strings.ReplaceAll(tt.path, "/", "_")+"/"+tt.rev, f) 452 tt = old 453 } 454 } 455 } 456 } 457 458 var hgmap = map[string]string{ 459 "github.com/rsc/vgotest1/": "vcs-test.golang.org/hg/vgotest1.hg/", 460 "f18795870fb14388a21ef3ebc1d75911c8694f31": "a9ad6d1d14eb544f459f446210c7eb3b009807c6", 461 "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9": "f1fc0f22021b638d073d31c752847e7bf385def7", 462 "b769f2de407a4db81af9c5de0a06016d60d2ea09": "92c7eb888b4fac17f1c6bd2e1060a1b881a3b832", 463 "8afe2b2efed96e0880ecd2a69b98a53b8c2738b6": "4e58084d459ae7e79c8c2264d0e8e9a92eb5cd44", 464 "2f615117ce481c8efef46e0cc0b4b4dccfac8fea": "879ea98f7743c8eff54f59a918f3a24123d1cf46", 465 "80d85c5d4d17598a0e9055e7c175a32b415d6128": "e125018e286a4b09061079a81e7b537070b7ff71", 466 "1f863feb76bc7029b78b21c5375644838962f88d": "bf63880162304a9337477f3858f5b7e255c75459", 467 "45f53230a74ad275c7127e117ac46914c8126160": "814fce58e83abd5bf2a13892e0b0e1198abefcd4", 468 } 469 470 func remap(name string, m map[string]string) string { 471 if m[name] != "" { 472 return m[name] 473 } 474 if codehost.AllHex(name) { 475 for k, v := range m { 476 if strings.HasPrefix(k, name) { 477 return v[:len(name)] 478 } 479 } 480 } 481 for k, v := range m { 482 name = strings.ReplaceAll(name, k, v) 483 if codehost.AllHex(k) { 484 name = strings.ReplaceAll(name, k[:12], v[:12]) 485 } 486 } 487 return name 488 } 489 490 var codeRepoVersionsTests = []struct { 491 path string 492 prefix string 493 versions []string 494 }{ 495 { 496 path: "github.com/rsc/vgotest1", 497 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"}, 498 }, 499 { 500 path: "github.com/rsc/vgotest1", 501 prefix: "v1.0", 502 versions: []string{"v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3"}, 503 }, 504 { 505 path: "github.com/rsc/vgotest1/v2", 506 versions: []string{"v2.0.0", "v2.0.1", "v2.0.2", "v2.0.3", "v2.0.4", "v2.0.5", "v2.0.6"}, 507 }, 508 { 509 path: "swtch.com/testmod", 510 versions: []string{"v1.0.0", "v1.1.1"}, 511 }, 512 { 513 path: "gopkg.in/russross/blackfriday.v2", 514 versions: []string{"v2.0.0", "v2.0.1"}, 515 }, 516 { 517 path: "gopkg.in/natefinch/lumberjack.v2", 518 versions: []string{"v2.0.0"}, 519 }, 520 } 521 522 func TestCodeRepoVersions(t *testing.T) { 523 testenv.MustHaveExternalNetwork(t) 524 525 tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-") 526 if err != nil { 527 t.Fatal(err) 528 } 529 defer os.RemoveAll(tmpdir) 530 for _, tt := range codeRepoVersionsTests { 531 t.Run(strings.ReplaceAll(tt.path, "/", "_"), func(t *testing.T) { 532 repo, err := Lookup(tt.path) 533 if err != nil { 534 t.Fatalf("Lookup(%q): %v", tt.path, err) 535 } 536 list, err := repo.Versions(tt.prefix) 537 if err != nil { 538 t.Fatalf("Versions(%q): %v", tt.prefix, err) 539 } 540 if !reflect.DeepEqual(list, tt.versions) { 541 t.Fatalf("Versions(%q):\nhave %v\nwant %v", tt.prefix, list, tt.versions) 542 } 543 }) 544 } 545 } 546 547 var latestTests = []struct { 548 path string 549 version string 550 err string 551 }{ 552 { 553 path: "github.com/rsc/empty", 554 err: "no commits", 555 }, 556 { 557 path: "github.com/rsc/vgotest1", 558 version: "v0.0.0-20180219223237-a08abb797a67", 559 }, 560 { 561 path: "github.com/rsc/vgotest1/subdir", 562 err: "missing github.com/rsc/vgotest1/subdir/go.mod at revision a08abb797a67", 563 }, 564 { 565 path: "swtch.com/testmod", 566 version: "v1.1.1", 567 }, 568 } 569 570 func TestLatest(t *testing.T) { 571 testenv.MustHaveExternalNetwork(t) 572 573 tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-") 574 if err != nil { 575 t.Fatal(err) 576 } 577 defer os.RemoveAll(tmpdir) 578 for _, tt := range latestTests { 579 name := strings.ReplaceAll(tt.path, "/", "_") 580 t.Run(name, func(t *testing.T) { 581 repo, err := Lookup(tt.path) 582 if err != nil { 583 t.Fatalf("Lookup(%q): %v", tt.path, err) 584 } 585 info, err := repo.Latest() 586 if err != nil { 587 if tt.err != "" { 588 if err.Error() == tt.err { 589 return 590 } 591 t.Fatalf("Latest(): %v, want %q", err, tt.err) 592 } 593 t.Fatalf("Latest(): %v", err) 594 } 595 if tt.err != "" { 596 t.Fatalf("Latest() = %v, want error %q", info.Version, tt.err) 597 } 598 if info.Version != tt.version { 599 t.Fatalf("Latest() = %v, want %v", info.Version, tt.version) 600 } 601 }) 602 } 603 } 604 605 // fixedTagsRepo is a fake codehost.Repo that returns a fixed list of tags 606 type fixedTagsRepo struct { 607 tags []string 608 } 609 610 func (ch *fixedTagsRepo) Tags(string) ([]string, error) { return ch.tags, nil } 611 func (ch *fixedTagsRepo) Latest() (*codehost.RevInfo, error) { panic("not impl") } 612 func (ch *fixedTagsRepo) ReadFile(string, string, int64) ([]byte, error) { panic("not impl") } 613 func (ch *fixedTagsRepo) ReadFileRevs([]string, string, int64) (map[string]*codehost.FileRev, error) { 614 panic("not impl") 615 } 616 func (ch *fixedTagsRepo) ReadZip(string, string, int64) (io.ReadCloser, string, error) { 617 panic("not impl") 618 } 619 func (ch *fixedTagsRepo) RecentTag(string, string) (string, error) { 620 panic("not impl") 621 } 622 func (ch *fixedTagsRepo) Stat(string) (*codehost.RevInfo, error) { panic("not impl") } 623 624 func TestNonCanonicalSemver(t *testing.T) { 625 root := "golang.org/x/issue24476" 626 ch := &fixedTagsRepo{ 627 tags: []string{ 628 "", "huh?", "1.0.1", 629 // what about "version 1 dot dogcow"? 630 "v1.🐕.🐄", 631 "v1", "v0.1", 632 // and one normal one that should pass through 633 "v1.0.1", 634 }, 635 } 636 637 cr, err := newCodeRepo(ch, root, root) 638 if err != nil { 639 t.Fatal(err) 640 } 641 642 v, err := cr.Versions("") 643 if err != nil { 644 t.Fatal(err) 645 } 646 if len(v) != 1 || v[0] != "v1.0.1" { 647 t.Fatal("unexpected versions returned:", v) 648 } 649 }