1
2
3
4
5 package codehost
6
7 import (
8 "archive/zip"
9 "bytes"
10 "cmd/go/internal/cfg"
11 "cmd/go/internal/vcweb/vcstest"
12 "context"
13 "flag"
14 "internal/testenv"
15 "io"
16 "io/fs"
17 "log"
18 "os"
19 "path"
20 "path/filepath"
21 "reflect"
22 "runtime"
23 "strings"
24 "sync"
25 "testing"
26 "time"
27 )
28
29 func TestMain(m *testing.M) {
30 flag.Parse()
31 if err := testMain(m); err != nil {
32 log.Fatal(err)
33 }
34 }
35
36 var gitrepo1, hgrepo1, vgotest1 string
37
38 var altRepos = func() []string {
39 return []string{
40 "localGitRepo",
41 hgrepo1,
42 }
43 }
44
45
46
47
48
49
50
51
52 var localGitRepo string
53
54
55 func localGitURL(t testing.TB) string {
56 testenv.MustHaveExecPath(t, "git")
57 if runtime.GOOS == "android" && strings.HasSuffix(testenv.Builder(), "-corellium") {
58 testenv.SkipFlaky(t, 59940)
59 }
60
61 localGitURLOnce.Do(func() {
62
63
64
65
66 _, localGitURLErr = Run(context.Background(), "", "git", "clone", "--mirror", gitrepo1, localGitRepo)
67 if localGitURLErr != nil {
68 return
69 }
70 repo := gitRepo{dir: localGitRepo}
71 _, localGitURLErr = repo.runGit(context.Background(), "git", "config", "daemon.uploadarch", "true")
72 })
73
74 if localGitURLErr != nil {
75 t.Fatal(localGitURLErr)
76 }
77
78
79
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
122
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
136
137
138
139
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 NewRepo(ctx, "git", localGitURL(t), false)
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, false)
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
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",
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
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",
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",
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",
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",
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",
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",
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",
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 }
797
View as plain text