github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/modfetch/codehost/git_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 codehost 6 7 import ( 8 "archive/zip" 9 "bytes" 10 "context" 11 "flag" 12 "io" 13 "io/fs" 14 "log" 15 "os" 16 "path" 17 "path/filepath" 18 "reflect" 19 "runtime" 20 "strings" 21 "sync" 22 "testing" 23 "time" 24 25 "github.com/go-asm/go/cmd/go/cfg" 26 "github.com/go-asm/go/cmd/go/vcweb/vcstest" 27 "github.com/go-asm/go/testenv" 28 ) 29 30 func TestMain(m *testing.M) { 31 flag.Parse() 32 if err := testMain(m); err != nil { 33 log.Fatal(err) 34 } 35 } 36 37 var gitrepo1, hgrepo1, vgotest1 string 38 39 var altRepos = func() []string { 40 return []string{ 41 "localGitRepo", 42 hgrepo1, 43 } 44 } 45 46 // TODO: Convert gitrepo1 to svn, bzr, fossil and add tests. 47 // For now, at least the hgrepo1 tests check the general vcs.go logic. 48 49 // localGitRepo is like gitrepo1 but allows archive access 50 // (although that doesn't really matter after CL 120041), 51 // and has a file:// URL instead of http:// or https:// 52 // (which might still matter). 53 var localGitRepo string 54 55 // localGitURL initializes the repo in localGitRepo and returns its URL. 56 func localGitURL(t testing.TB) string { 57 testenv.MustHaveExecPath(t, "git") 58 if runtime.GOOS == "android" && strings.HasSuffix(testenv.Builder(), "-corellium") { 59 testenv.SkipFlaky(t, 59940) 60 } 61 62 localGitURLOnce.Do(func() { 63 // Clone gitrepo1 into a local directory. 64 // If we use a file:// URL to access the local directory, 65 // then git starts up all the usual protocol machinery, 66 // which will let us test remote git archive invocations. 67 _, localGitURLErr = Run(context.Background(), "", "git", "clone", "--mirror", gitrepo1, localGitRepo) 68 if localGitURLErr != nil { 69 return 70 } 71 _, localGitURLErr = Run(context.Background(), localGitRepo, "git", "config", "daemon.uploadarch", "true") 72 }) 73 74 if localGitURLErr != nil { 75 t.Fatal(localGitURLErr) 76 } 77 // Convert absolute path to file URL. LocalGitRepo will not accept 78 // Windows absolute paths because they look like a host:path remote. 79 // TODO(golang.org/issue/32456): use url.FromFilePath when implemented. 80 if strings.HasPrefix(localGitRepo, "/") { 81 return "file://" + localGitRepo 82 } else { 83 return "file:///" + filepath.ToSlash(localGitRepo) 84 } 85 } 86 87 var ( 88 localGitURLOnce sync.Once 89 localGitURLErr error 90 ) 91 92 func testMain(m *testing.M) (err error) { 93 cfg.BuildX = testing.Verbose() 94 95 srv, err := vcstest.NewServer() 96 if err != nil { 97 return err 98 } 99 defer func() { 100 if closeErr := srv.Close(); err == nil { 101 err = closeErr 102 } 103 }() 104 105 gitrepo1 = srv.HTTP.URL + "/git/gitrepo1" 106 hgrepo1 = srv.HTTP.URL + "/hg/hgrepo1" 107 vgotest1 = srv.HTTP.URL + "/git/vgotest1" 108 109 dir, err := os.MkdirTemp("", "gitrepo-test-") 110 if err != nil { 111 return err 112 } 113 defer func() { 114 if rmErr := os.RemoveAll(dir); err == nil { 115 err = rmErr 116 } 117 }() 118 119 localGitRepo = filepath.Join(dir, "gitrepo2") 120 121 // Redirect the module cache to a fresh directory to avoid crosstalk, and make 122 // it read/write so that the test can still clean it up easily when done. 123 cfg.GOMODCACHE = filepath.Join(dir, "modcache") 124 cfg.ModCacheRW = true 125 126 m.Run() 127 return nil 128 } 129 130 func testContext(t testing.TB) context.Context { 131 w := newTestWriter(t) 132 return cfg.WithBuildXWriter(context.Background(), w) 133 } 134 135 // A testWriter is an io.Writer that writes to a test's log. 136 // 137 // The writer batches written data until the last byte of a write is a newline 138 // character, then flushes the batched data as a single call to Logf. 139 // Any remaining unflushed data is logged during Cleanup. 140 type testWriter struct { 141 t testing.TB 142 143 mu sync.Mutex 144 buf bytes.Buffer 145 } 146 147 func newTestWriter(t testing.TB) *testWriter { 148 w := &testWriter{t: t} 149 150 t.Cleanup(func() { 151 w.mu.Lock() 152 defer w.mu.Unlock() 153 if b := w.buf.Bytes(); len(b) > 0 { 154 w.t.Logf("%s", b) 155 w.buf.Reset() 156 } 157 }) 158 159 return w 160 } 161 162 func (w *testWriter) Write(p []byte) (int, error) { 163 w.mu.Lock() 164 defer w.mu.Unlock() 165 n, err := w.buf.Write(p) 166 if b := w.buf.Bytes(); len(b) > 0 && b[len(b)-1] == '\n' { 167 w.t.Logf("%s", b) 168 w.buf.Reset() 169 } 170 return n, err 171 } 172 173 func testRepo(ctx context.Context, t *testing.T, remote string) (Repo, error) { 174 if remote == "localGitRepo" { 175 return LocalGitRepo(ctx, localGitURL(t)) 176 } 177 vcsName := "git" 178 for _, k := range []string{"hg"} { 179 if strings.Contains(remote, "/"+k+"/") { 180 vcsName = k 181 } 182 } 183 if testing.Short() && vcsName == "hg" { 184 t.Skipf("skipping hg test in short mode: hg is slow") 185 } 186 testenv.MustHaveExecPath(t, vcsName) 187 if runtime.GOOS == "android" && strings.HasSuffix(testenv.Builder(), "-corellium") { 188 testenv.SkipFlaky(t, 59940) 189 } 190 return NewRepo(ctx, vcsName, remote) 191 } 192 193 func TestTags(t *testing.T) { 194 t.Parallel() 195 196 type tagsTest struct { 197 repo string 198 prefix string 199 tags []Tag 200 } 201 202 runTest := func(tt tagsTest) func(*testing.T) { 203 return func(t *testing.T) { 204 t.Parallel() 205 ctx := testContext(t) 206 207 r, err := testRepo(ctx, t, tt.repo) 208 if err != nil { 209 t.Fatal(err) 210 } 211 tags, err := r.Tags(ctx, tt.prefix) 212 if err != nil { 213 t.Fatal(err) 214 } 215 if tags == nil || !reflect.DeepEqual(tags.List, tt.tags) { 216 t.Errorf("Tags(%q): incorrect tags\nhave %v\nwant %v", tt.prefix, tags, tt.tags) 217 } 218 } 219 } 220 221 for _, tt := range []tagsTest{ 222 {gitrepo1, "xxx", []Tag{}}, 223 {gitrepo1, "", []Tag{ 224 {"v1.2.3", "ede458df7cd0fdca520df19a33158086a8a68e81"}, 225 {"v1.2.4-annotated", "ede458df7cd0fdca520df19a33158086a8a68e81"}, 226 {"v2.0.1", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"}, 227 {"v2.0.2", "9d02800338b8a55be062c838d1f02e0c5780b9eb"}, 228 {"v2.3", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"}, 229 }}, 230 {gitrepo1, "v", []Tag{ 231 {"v1.2.3", "ede458df7cd0fdca520df19a33158086a8a68e81"}, 232 {"v1.2.4-annotated", "ede458df7cd0fdca520df19a33158086a8a68e81"}, 233 {"v2.0.1", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"}, 234 {"v2.0.2", "9d02800338b8a55be062c838d1f02e0c5780b9eb"}, 235 {"v2.3", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"}, 236 }}, 237 {gitrepo1, "v1", []Tag{ 238 {"v1.2.3", "ede458df7cd0fdca520df19a33158086a8a68e81"}, 239 {"v1.2.4-annotated", "ede458df7cd0fdca520df19a33158086a8a68e81"}, 240 }}, 241 {gitrepo1, "2", []Tag{}}, 242 } { 243 t.Run(path.Base(tt.repo)+"/"+tt.prefix, runTest(tt)) 244 if tt.repo == gitrepo1 { 245 // Clear hashes. 246 clearTags := []Tag{} 247 for _, tag := range tt.tags { 248 clearTags = append(clearTags, Tag{tag.Name, ""}) 249 } 250 tags := tt.tags 251 for _, tt.repo = range altRepos() { 252 if strings.Contains(tt.repo, "Git") { 253 tt.tags = tags 254 } else { 255 tt.tags = clearTags 256 } 257 t.Run(path.Base(tt.repo)+"/"+tt.prefix, runTest(tt)) 258 } 259 } 260 } 261 } 262 263 func TestLatest(t *testing.T) { 264 t.Parallel() 265 266 type latestTest struct { 267 repo string 268 info *RevInfo 269 } 270 runTest := func(tt latestTest) func(*testing.T) { 271 return func(t *testing.T) { 272 t.Parallel() 273 ctx := testContext(t) 274 275 r, err := testRepo(ctx, t, tt.repo) 276 if err != nil { 277 t.Fatal(err) 278 } 279 info, err := r.Latest(ctx) 280 if err != nil { 281 t.Fatal(err) 282 } 283 if !reflect.DeepEqual(info, tt.info) { 284 t.Errorf("Latest: incorrect info\nhave %+v (origin %+v)\nwant %+v (origin %+v)", info, info.Origin, tt.info, tt.info.Origin) 285 } 286 } 287 } 288 289 for _, tt := range []latestTest{ 290 { 291 gitrepo1, 292 &RevInfo{ 293 Origin: &Origin{ 294 VCS: "git", 295 URL: gitrepo1, 296 Ref: "HEAD", 297 Hash: "ede458df7cd0fdca520df19a33158086a8a68e81", 298 }, 299 Name: "ede458df7cd0fdca520df19a33158086a8a68e81", 300 Short: "ede458df7cd0", 301 Version: "ede458df7cd0fdca520df19a33158086a8a68e81", 302 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), 303 Tags: []string{"v1.2.3", "v1.2.4-annotated"}, 304 }, 305 }, 306 { 307 hgrepo1, 308 &RevInfo{ 309 Origin: &Origin{ 310 VCS: "hg", 311 URL: hgrepo1, 312 Hash: "18518c07eb8ed5c80221e997e518cccaa8c0c287", 313 }, 314 Name: "18518c07eb8ed5c80221e997e518cccaa8c0c287", 315 Short: "18518c07eb8e", 316 Version: "18518c07eb8ed5c80221e997e518cccaa8c0c287", 317 Time: time.Date(2018, 6, 27, 16, 16, 30, 0, time.UTC), 318 }, 319 }, 320 } { 321 t.Run(path.Base(tt.repo), runTest(tt)) 322 if tt.repo == gitrepo1 { 323 tt.repo = "localGitRepo" 324 info := *tt.info 325 tt.info = &info 326 o := *info.Origin 327 info.Origin = &o 328 o.URL = localGitURL(t) 329 t.Run(path.Base(tt.repo), runTest(tt)) 330 } 331 } 332 } 333 334 func TestReadFile(t *testing.T) { 335 t.Parallel() 336 337 type readFileTest struct { 338 repo string 339 rev string 340 file string 341 err string 342 data string 343 } 344 runTest := func(tt readFileTest) func(*testing.T) { 345 return func(t *testing.T) { 346 t.Parallel() 347 ctx := testContext(t) 348 349 r, err := testRepo(ctx, t, tt.repo) 350 if err != nil { 351 t.Fatal(err) 352 } 353 data, err := r.ReadFile(ctx, tt.rev, tt.file, 100) 354 if err != nil { 355 if tt.err == "" { 356 t.Fatalf("ReadFile: unexpected error %v", err) 357 } 358 if !strings.Contains(err.Error(), tt.err) { 359 t.Fatalf("ReadFile: wrong error %q, want %q", err, tt.err) 360 } 361 if len(data) != 0 { 362 t.Errorf("ReadFile: non-empty data %q with error %v", data, err) 363 } 364 return 365 } 366 if tt.err != "" { 367 t.Fatalf("ReadFile: no error, wanted %v", tt.err) 368 } 369 if string(data) != tt.data { 370 t.Errorf("ReadFile: incorrect data\nhave %q\nwant %q", data, tt.data) 371 } 372 } 373 } 374 375 for _, tt := range []readFileTest{ 376 { 377 repo: gitrepo1, 378 rev: "latest", 379 file: "README", 380 data: "", 381 }, 382 { 383 repo: gitrepo1, 384 rev: "v2", 385 file: "another.txt", 386 data: "another\n", 387 }, 388 { 389 repo: gitrepo1, 390 rev: "v2.3.4", 391 file: "another.txt", 392 err: fs.ErrNotExist.Error(), 393 }, 394 } { 395 t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.file, runTest(tt)) 396 if tt.repo == gitrepo1 { 397 for _, tt.repo = range altRepos() { 398 t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.file, runTest(tt)) 399 } 400 } 401 } 402 } 403 404 type zipFile struct { 405 name string 406 size int64 407 } 408 409 func TestReadZip(t *testing.T) { 410 t.Parallel() 411 412 type readZipTest struct { 413 repo string 414 rev string 415 subdir string 416 err string 417 files map[string]uint64 418 } 419 runTest := func(tt readZipTest) func(*testing.T) { 420 return func(t *testing.T) { 421 t.Parallel() 422 ctx := testContext(t) 423 424 r, err := testRepo(ctx, t, tt.repo) 425 if err != nil { 426 t.Fatal(err) 427 } 428 rc, err := r.ReadZip(ctx, tt.rev, tt.subdir, 100000) 429 if err != nil { 430 if tt.err == "" { 431 t.Fatalf("ReadZip: unexpected error %v", err) 432 } 433 if !strings.Contains(err.Error(), tt.err) { 434 t.Fatalf("ReadZip: wrong error %q, want %q", err, tt.err) 435 } 436 if rc != nil { 437 t.Errorf("ReadZip: non-nil io.ReadCloser with error %v", err) 438 } 439 return 440 } 441 defer rc.Close() 442 if tt.err != "" { 443 t.Fatalf("ReadZip: no error, wanted %v", tt.err) 444 } 445 zipdata, err := io.ReadAll(rc) 446 if err != nil { 447 t.Fatal(err) 448 } 449 z, err := zip.NewReader(bytes.NewReader(zipdata), int64(len(zipdata))) 450 if err != nil { 451 t.Fatalf("ReadZip: cannot read zip file: %v", err) 452 } 453 have := make(map[string]bool) 454 for _, f := range z.File { 455 size, ok := tt.files[f.Name] 456 if !ok { 457 t.Errorf("ReadZip: unexpected file %s", f.Name) 458 continue 459 } 460 have[f.Name] = true 461 if size != ^uint64(0) && f.UncompressedSize64 != size { 462 t.Errorf("ReadZip: file %s has unexpected size %d != %d", f.Name, f.UncompressedSize64, size) 463 } 464 } 465 for name := range tt.files { 466 if !have[name] { 467 t.Errorf("ReadZip: missing file %s", name) 468 } 469 } 470 } 471 } 472 473 for _, tt := range []readZipTest{ 474 { 475 repo: gitrepo1, 476 rev: "v2.3.4", 477 subdir: "", 478 files: map[string]uint64{ 479 "prefix/": 0, 480 "prefix/README": 0, 481 "prefix/v2": 3, 482 }, 483 }, 484 { 485 repo: hgrepo1, 486 rev: "v2.3.4", 487 subdir: "", 488 files: map[string]uint64{ 489 "prefix/.hg_archival.txt": ^uint64(0), 490 "prefix/README": 0, 491 "prefix/v2": 3, 492 }, 493 }, 494 495 { 496 repo: gitrepo1, 497 rev: "v2", 498 subdir: "", 499 files: map[string]uint64{ 500 "prefix/": 0, 501 "prefix/README": 0, 502 "prefix/v2": 3, 503 "prefix/another.txt": 8, 504 "prefix/foo.txt": 13, 505 }, 506 }, 507 { 508 repo: hgrepo1, 509 rev: "v2", 510 subdir: "", 511 files: map[string]uint64{ 512 "prefix/.hg_archival.txt": ^uint64(0), 513 "prefix/README": 0, 514 "prefix/v2": 3, 515 "prefix/another.txt": 8, 516 "prefix/foo.txt": 13, 517 }, 518 }, 519 520 { 521 repo: gitrepo1, 522 rev: "v3", 523 subdir: "", 524 files: map[string]uint64{ 525 "prefix/": 0, 526 "prefix/v3/": 0, 527 "prefix/v3/sub/": 0, 528 "prefix/v3/sub/dir/": 0, 529 "prefix/v3/sub/dir/file.txt": 16, 530 "prefix/README": 0, 531 }, 532 }, 533 { 534 repo: hgrepo1, 535 rev: "v3", 536 subdir: "", 537 files: map[string]uint64{ 538 "prefix/.hg_archival.txt": ^uint64(0), 539 "prefix/.hgtags": 405, 540 "prefix/v3/sub/dir/file.txt": 16, 541 "prefix/README": 0, 542 }, 543 }, 544 545 { 546 repo: gitrepo1, 547 rev: "v3", 548 subdir: "v3/sub/dir", 549 files: map[string]uint64{ 550 "prefix/": 0, 551 "prefix/v3/": 0, 552 "prefix/v3/sub/": 0, 553 "prefix/v3/sub/dir/": 0, 554 "prefix/v3/sub/dir/file.txt": 16, 555 }, 556 }, 557 { 558 repo: hgrepo1, 559 rev: "v3", 560 subdir: "v3/sub/dir", 561 files: map[string]uint64{ 562 "prefix/v3/sub/dir/file.txt": 16, 563 }, 564 }, 565 566 { 567 repo: gitrepo1, 568 rev: "v3", 569 subdir: "v3/sub", 570 files: map[string]uint64{ 571 "prefix/": 0, 572 "prefix/v3/": 0, 573 "prefix/v3/sub/": 0, 574 "prefix/v3/sub/dir/": 0, 575 "prefix/v3/sub/dir/file.txt": 16, 576 }, 577 }, 578 { 579 repo: hgrepo1, 580 rev: "v3", 581 subdir: "v3/sub", 582 files: map[string]uint64{ 583 "prefix/v3/sub/dir/file.txt": 16, 584 }, 585 }, 586 587 { 588 repo: gitrepo1, 589 rev: "aaaaaaaaab", 590 subdir: "", 591 err: "unknown revision", 592 }, 593 { 594 repo: hgrepo1, 595 rev: "aaaaaaaaab", 596 subdir: "", 597 err: "unknown revision", 598 }, 599 600 { 601 repo: vgotest1, 602 rev: "submod/v1.0.4", 603 subdir: "submod", 604 files: map[string]uint64{ 605 "prefix/": 0, 606 "prefix/submod/": 0, 607 "prefix/submod/go.mod": 53, 608 "prefix/submod/pkg/": 0, 609 "prefix/submod/pkg/p.go": 31, 610 }, 611 }, 612 } { 613 t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.subdir, runTest(tt)) 614 if tt.repo == gitrepo1 { 615 tt.repo = "localGitRepo" 616 t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.subdir, runTest(tt)) 617 } 618 } 619 } 620 621 var hgmap = map[string]string{ 622 "HEAD": "41964ddce1180313bdc01d0a39a2813344d6261d", // not tip due to bad hgrepo1 conversion 623 "9d02800338b8a55be062c838d1f02e0c5780b9eb": "8f49ee7a6ddcdec6f0112d9dca48d4a2e4c3c09e", 624 "76a00fb249b7f93091bc2c89a789dab1fc1bc26f": "88fde824ec8b41a76baa16b7e84212cee9f3edd0", 625 "ede458df7cd0fdca520df19a33158086a8a68e81": "41964ddce1180313bdc01d0a39a2813344d6261d", 626 "97f6aa59c81c623494825b43d39e445566e429a4": "c0cbbfb24c7c3c50c35c7b88e7db777da4ff625d", 627 } 628 629 func TestStat(t *testing.T) { 630 t.Parallel() 631 632 type statTest struct { 633 repo string 634 rev string 635 err string 636 info *RevInfo 637 } 638 runTest := func(tt statTest) func(*testing.T) { 639 return func(t *testing.T) { 640 t.Parallel() 641 ctx := testContext(t) 642 643 r, err := testRepo(ctx, t, tt.repo) 644 if err != nil { 645 t.Fatal(err) 646 } 647 info, err := r.Stat(ctx, tt.rev) 648 if err != nil { 649 if tt.err == "" { 650 t.Fatalf("Stat: unexpected error %v", err) 651 } 652 if !strings.Contains(err.Error(), tt.err) { 653 t.Fatalf("Stat: wrong error %q, want %q", err, tt.err) 654 } 655 if info != nil && info.Origin == nil { 656 t.Errorf("Stat: non-nil info with nil Origin with error %q", err) 657 } 658 return 659 } 660 info.Origin = nil // TestLatest and ../../../testdata/script/reuse_git.txt test Origin well enough 661 if !reflect.DeepEqual(info, tt.info) { 662 t.Errorf("Stat: incorrect info\nhave %+v\nwant %+v", *info, *tt.info) 663 } 664 } 665 } 666 667 for _, tt := range []statTest{ 668 { 669 repo: gitrepo1, 670 rev: "HEAD", 671 info: &RevInfo{ 672 Name: "ede458df7cd0fdca520df19a33158086a8a68e81", 673 Short: "ede458df7cd0", 674 Version: "ede458df7cd0fdca520df19a33158086a8a68e81", 675 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), 676 Tags: []string{"v1.2.3", "v1.2.4-annotated"}, 677 }, 678 }, 679 { 680 repo: gitrepo1, 681 rev: "v2", // branch 682 info: &RevInfo{ 683 Name: "9d02800338b8a55be062c838d1f02e0c5780b9eb", 684 Short: "9d02800338b8", 685 Version: "9d02800338b8a55be062c838d1f02e0c5780b9eb", 686 Time: time.Date(2018, 4, 17, 20, 00, 32, 0, time.UTC), 687 Tags: []string{"v2.0.2"}, 688 }, 689 }, 690 { 691 repo: gitrepo1, 692 rev: "v2.3.4", // badly-named branch (semver should be a tag) 693 info: &RevInfo{ 694 Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f", 695 Short: "76a00fb249b7", 696 Version: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f", 697 Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC), 698 Tags: []string{"v2.0.1", "v2.3"}, 699 }, 700 }, 701 { 702 repo: gitrepo1, 703 rev: "v2.3", // badly-named tag (we only respect full semver v2.3.0) 704 info: &RevInfo{ 705 Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f", 706 Short: "76a00fb249b7", 707 Version: "v2.3", 708 Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC), 709 Tags: []string{"v2.0.1", "v2.3"}, 710 }, 711 }, 712 { 713 repo: gitrepo1, 714 rev: "v1.2.3", // tag 715 info: &RevInfo{ 716 Name: "ede458df7cd0fdca520df19a33158086a8a68e81", 717 Short: "ede458df7cd0", 718 Version: "v1.2.3", 719 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), 720 Tags: []string{"v1.2.3", "v1.2.4-annotated"}, 721 }, 722 }, 723 { 724 repo: gitrepo1, 725 rev: "ede458df", // hash prefix in refs 726 info: &RevInfo{ 727 Name: "ede458df7cd0fdca520df19a33158086a8a68e81", 728 Short: "ede458df7cd0", 729 Version: "ede458df7cd0fdca520df19a33158086a8a68e81", 730 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), 731 Tags: []string{"v1.2.3", "v1.2.4-annotated"}, 732 }, 733 }, 734 { 735 repo: gitrepo1, 736 rev: "97f6aa59", // hash prefix not in refs 737 info: &RevInfo{ 738 Name: "97f6aa59c81c623494825b43d39e445566e429a4", 739 Short: "97f6aa59c81c", 740 Version: "97f6aa59c81c623494825b43d39e445566e429a4", 741 Time: time.Date(2018, 4, 17, 20, 0, 19, 0, time.UTC), 742 }, 743 }, 744 { 745 repo: gitrepo1, 746 rev: "v1.2.4-annotated", // annotated tag uses unwrapped commit hash 747 info: &RevInfo{ 748 Name: "ede458df7cd0fdca520df19a33158086a8a68e81", 749 Short: "ede458df7cd0", 750 Version: "v1.2.4-annotated", 751 Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), 752 Tags: []string{"v1.2.3", "v1.2.4-annotated"}, 753 }, 754 }, 755 { 756 repo: gitrepo1, 757 rev: "aaaaaaaaab", 758 err: "unknown revision", 759 }, 760 } { 761 t.Run(path.Base(tt.repo)+"/"+tt.rev, runTest(tt)) 762 if tt.repo == gitrepo1 { 763 for _, tt.repo = range altRepos() { 764 old := tt 765 var m map[string]string 766 if tt.repo == hgrepo1 { 767 m = hgmap 768 } 769 if tt.info != nil { 770 info := *tt.info 771 tt.info = &info 772 tt.info.Name = remap(tt.info.Name, m) 773 tt.info.Version = remap(tt.info.Version, m) 774 tt.info.Short = remap(tt.info.Short, m) 775 } 776 tt.rev = remap(tt.rev, m) 777 t.Run(path.Base(tt.repo)+"/"+tt.rev, runTest(tt)) 778 tt = old 779 } 780 } 781 } 782 } 783 784 func remap(name string, m map[string]string) string { 785 if m[name] != "" { 786 return m[name] 787 } 788 if AllHex(name) { 789 for k, v := range m { 790 if strings.HasPrefix(k, name) { 791 return v[:len(name)] 792 } 793 } 794 } 795 return name 796 }