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