| // Copyright 2018 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package codehost |
| |
| import ( |
| "archive/zip" |
| "bytes" |
| "cmd/go/internal/cfg" |
| "cmd/go/internal/vcweb/vcstest" |
| "context" |
| "flag" |
| "internal/testenv" |
| "io" |
| "io/fs" |
| "log" |
| "os" |
| "path" |
| "path/filepath" |
| "reflect" |
| "runtime" |
| "strings" |
| "sync" |
| "testing" |
| "time" |
| ) |
| |
| func TestMain(m *testing.M) { |
| flag.Parse() |
| if err := testMain(m); err != nil { |
| log.Fatal(err) |
| } |
| } |
| |
| var gitrepo1, hgrepo1, vgotest1 string |
| |
| var altRepos = func() []string { |
| return []string{ |
| "localGitRepo", |
| hgrepo1, |
| } |
| } |
| |
| // TODO: Convert gitrepo1 to svn, bzr, fossil and add tests. |
| // For now, at least the hgrepo1 tests check the general vcs.go logic. |
| |
| // localGitRepo is like gitrepo1 but allows archive access |
| // (although that doesn't really matter after CL 120041), |
| // and has a file:// URL instead of http:// or https:// |
| // (which might still matter). |
| var localGitRepo string |
| |
| // localGitURL initializes the repo in localGitRepo and returns its URL. |
| func localGitURL(t testing.TB) string { |
| testenv.MustHaveExecPath(t, "git") |
| if runtime.GOOS == "android" && strings.HasSuffix(testenv.Builder(), "-corellium") { |
| testenv.SkipFlaky(t, 59940) |
| } |
| |
| localGitURLOnce.Do(func() { |
| // Clone gitrepo1 into a local directory. |
| // If we use a file:// URL to access the local directory, |
| // then git starts up all the usual protocol machinery, |
| // which will let us test remote git archive invocations. |
| _, localGitURLErr = Run(context.Background(), "", "git", "clone", "--mirror", gitrepo1, localGitRepo) |
| if localGitURLErr != nil { |
| return |
| } |
| _, localGitURLErr = Run(context.Background(), localGitRepo, "git", "config", "daemon.uploadarch", "true") |
| }) |
| |
| if localGitURLErr != nil { |
| t.Fatal(localGitURLErr) |
| } |
| // Convert absolute path to file URL. LocalGitRepo will not accept |
| // Windows absolute paths because they look like a host:path remote. |
| // TODO(golang.org/issue/32456): use url.FromFilePath when implemented. |
| if strings.HasPrefix(localGitRepo, "/") { |
| return "file://" + localGitRepo |
| } else { |
| return "file:///" + filepath.ToSlash(localGitRepo) |
| } |
| } |
| |
| var ( |
| localGitURLOnce sync.Once |
| localGitURLErr error |
| ) |
| |
| func testMain(m *testing.M) (err error) { |
| cfg.BuildX = testing.Verbose() |
| |
| srv, err := vcstest.NewServer() |
| if err != nil { |
| return err |
| } |
| defer func() { |
| if closeErr := srv.Close(); err == nil { |
| err = closeErr |
| } |
| }() |
| |
| gitrepo1 = srv.HTTP.URL + "/git/gitrepo1" |
| hgrepo1 = srv.HTTP.URL + "/hg/hgrepo1" |
| vgotest1 = srv.HTTP.URL + "/git/vgotest1" |
| |
| dir, err := os.MkdirTemp("", "gitrepo-test-") |
| if err != nil { |
| return err |
| } |
| defer func() { |
| if rmErr := os.RemoveAll(dir); err == nil { |
| err = rmErr |
| } |
| }() |
| |
| localGitRepo = filepath.Join(dir, "gitrepo2") |
| |
| // Redirect the module cache to a fresh directory to avoid crosstalk, and make |
| // it read/write so that the test can still clean it up easily when done. |
| cfg.GOMODCACHE = filepath.Join(dir, "modcache") |
| cfg.ModCacheRW = true |
| |
| m.Run() |
| return nil |
| } |
| |
| func testContext(t testing.TB) context.Context { |
| w := newTestWriter(t) |
| return cfg.WithBuildXWriter(context.Background(), w) |
| } |
| |
| // A testWriter is an io.Writer that writes to a test's log. |
| // |
| // The writer batches written data until the last byte of a write is a newline |
| // character, then flushes the batched data as a single call to Logf. |
| // Any remaining unflushed data is logged during Cleanup. |
| type testWriter struct { |
| t testing.TB |
| |
| mu sync.Mutex |
| buf bytes.Buffer |
| } |
| |
| func newTestWriter(t testing.TB) *testWriter { |
| w := &testWriter{t: t} |
| |
| t.Cleanup(func() { |
| w.mu.Lock() |
| defer w.mu.Unlock() |
| if b := w.buf.Bytes(); len(b) > 0 { |
| w.t.Logf("%s", b) |
| w.buf.Reset() |
| } |
| }) |
| |
| return w |
| } |
| |
| func (w *testWriter) Write(p []byte) (int, error) { |
| w.mu.Lock() |
| defer w.mu.Unlock() |
| n, err := w.buf.Write(p) |
| if b := w.buf.Bytes(); len(b) > 0 && b[len(b)-1] == '\n' { |
| w.t.Logf("%s", b) |
| w.buf.Reset() |
| } |
| return n, err |
| } |
| |
| func testRepo(ctx context.Context, t *testing.T, remote string) (Repo, error) { |
| if remote == "localGitRepo" { |
| return LocalGitRepo(ctx, localGitURL(t)) |
| } |
| vcsName := "git" |
| for _, k := range []string{"hg"} { |
| if strings.Contains(remote, "/"+k+"/") { |
| vcsName = k |
| } |
| } |
| if testing.Short() && vcsName == "hg" { |
| t.Skipf("skipping hg test in short mode: hg is slow") |
| } |
| testenv.MustHaveExecPath(t, vcsName) |
| if runtime.GOOS == "android" && strings.HasSuffix(testenv.Builder(), "-corellium") { |
| testenv.SkipFlaky(t, 59940) |
| } |
| return NewRepo(ctx, vcsName, remote) |
| } |
| |
| func TestTags(t *testing.T) { |
| t.Parallel() |
| |
| type tagsTest struct { |
| repo string |
| prefix string |
| tags []Tag |
| } |
| |
| runTest := func(tt tagsTest) func(*testing.T) { |
| return func(t *testing.T) { |
| t.Parallel() |
| ctx := testContext(t) |
| |
| r, err := testRepo(ctx, t, tt.repo) |
| if err != nil { |
| t.Fatal(err) |
| } |
| tags, err := r.Tags(ctx, tt.prefix) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if tags == nil || !reflect.DeepEqual(tags.List, tt.tags) { |
| t.Errorf("Tags(%q): incorrect tags\nhave %v\nwant %v", tt.prefix, tags, tt.tags) |
| } |
| } |
| } |
| |
| for _, tt := range []tagsTest{ |
| {gitrepo1, "xxx", []Tag{}}, |
| {gitrepo1, "", []Tag{ |
| {"v1.2.3", "ede458df7cd0fdca520df19a33158086a8a68e81"}, |
| {"v1.2.4-annotated", "ede458df7cd0fdca520df19a33158086a8a68e81"}, |
| {"v2.0.1", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"}, |
| {"v2.0.2", "9d02800338b8a55be062c838d1f02e0c5780b9eb"}, |
| {"v2.3", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"}, |
| }}, |
| {gitrepo1, "v", []Tag{ |
| {"v1.2.3", "ede458df7cd0fdca520df19a33158086a8a68e81"}, |
| {"v1.2.4-annotated", "ede458df7cd0fdca520df19a33158086a8a68e81"}, |
| {"v2.0.1", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"}, |
| {"v2.0.2", "9d02800338b8a55be062c838d1f02e0c5780b9eb"}, |
| {"v2.3", "76a00fb249b7f93091bc2c89a789dab1fc1bc26f"}, |
| }}, |
| {gitrepo1, "v1", []Tag{ |
| {"v1.2.3", "ede458df7cd0fdca520df19a33158086a8a68e81"}, |
| {"v1.2.4-annotated", "ede458df7cd0fdca520df19a33158086a8a68e81"}, |
| }}, |
| {gitrepo1, "2", []Tag{}}, |
| } { |
| t.Run(path.Base(tt.repo)+"/"+tt.prefix, runTest(tt)) |
| if tt.repo == gitrepo1 { |
| // Clear hashes. |
| clearTags := []Tag{} |
| for _, tag := range tt.tags { |
| clearTags = append(clearTags, Tag{tag.Name, ""}) |
| } |
| tags := tt.tags |
| for _, tt.repo = range altRepos() { |
| if strings.Contains(tt.repo, "Git") { |
| tt.tags = tags |
| } else { |
| tt.tags = clearTags |
| } |
| t.Run(path.Base(tt.repo)+"/"+tt.prefix, runTest(tt)) |
| } |
| } |
| } |
| } |
| |
| func TestLatest(t *testing.T) { |
| t.Parallel() |
| |
| type latestTest struct { |
| repo string |
| info *RevInfo |
| } |
| runTest := func(tt latestTest) func(*testing.T) { |
| return func(t *testing.T) { |
| t.Parallel() |
| ctx := testContext(t) |
| |
| r, err := testRepo(ctx, t, tt.repo) |
| if err != nil { |
| t.Fatal(err) |
| } |
| info, err := r.Latest(ctx) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if !reflect.DeepEqual(info, tt.info) { |
| t.Errorf("Latest: incorrect info\nhave %+v (origin %+v)\nwant %+v (origin %+v)", info, info.Origin, tt.info, tt.info.Origin) |
| } |
| } |
| } |
| |
| for _, tt := range []latestTest{ |
| { |
| gitrepo1, |
| &RevInfo{ |
| Origin: &Origin{ |
| VCS: "git", |
| URL: gitrepo1, |
| Ref: "HEAD", |
| Hash: "ede458df7cd0fdca520df19a33158086a8a68e81", |
| }, |
| Name: "ede458df7cd0fdca520df19a33158086a8a68e81", |
| Short: "ede458df7cd0", |
| Version: "ede458df7cd0fdca520df19a33158086a8a68e81", |
| Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), |
| Tags: []string{"v1.2.3", "v1.2.4-annotated"}, |
| }, |
| }, |
| { |
| hgrepo1, |
| &RevInfo{ |
| Origin: &Origin{ |
| VCS: "hg", |
| URL: hgrepo1, |
| Hash: "18518c07eb8ed5c80221e997e518cccaa8c0c287", |
| }, |
| Name: "18518c07eb8ed5c80221e997e518cccaa8c0c287", |
| Short: "18518c07eb8e", |
| Version: "18518c07eb8ed5c80221e997e518cccaa8c0c287", |
| Time: time.Date(2018, 6, 27, 16, 16, 30, 0, time.UTC), |
| }, |
| }, |
| } { |
| t.Run(path.Base(tt.repo), runTest(tt)) |
| if tt.repo == gitrepo1 { |
| tt.repo = "localGitRepo" |
| info := *tt.info |
| tt.info = &info |
| o := *info.Origin |
| info.Origin = &o |
| o.URL = localGitURL(t) |
| t.Run(path.Base(tt.repo), runTest(tt)) |
| } |
| } |
| } |
| |
| func TestReadFile(t *testing.T) { |
| t.Parallel() |
| |
| type readFileTest struct { |
| repo string |
| rev string |
| file string |
| err string |
| data string |
| } |
| runTest := func(tt readFileTest) func(*testing.T) { |
| return func(t *testing.T) { |
| t.Parallel() |
| ctx := testContext(t) |
| |
| r, err := testRepo(ctx, t, tt.repo) |
| if err != nil { |
| t.Fatal(err) |
| } |
| data, err := r.ReadFile(ctx, tt.rev, tt.file, 100) |
| if err != nil { |
| if tt.err == "" { |
| t.Fatalf("ReadFile: unexpected error %v", err) |
| } |
| if !strings.Contains(err.Error(), tt.err) { |
| t.Fatalf("ReadFile: wrong error %q, want %q", err, tt.err) |
| } |
| if len(data) != 0 { |
| t.Errorf("ReadFile: non-empty data %q with error %v", data, err) |
| } |
| return |
| } |
| if tt.err != "" { |
| t.Fatalf("ReadFile: no error, wanted %v", tt.err) |
| } |
| if string(data) != tt.data { |
| t.Errorf("ReadFile: incorrect data\nhave %q\nwant %q", data, tt.data) |
| } |
| } |
| } |
| |
| for _, tt := range []readFileTest{ |
| { |
| repo: gitrepo1, |
| rev: "latest", |
| file: "README", |
| data: "", |
| }, |
| { |
| repo: gitrepo1, |
| rev: "v2", |
| file: "another.txt", |
| data: "another\n", |
| }, |
| { |
| repo: gitrepo1, |
| rev: "v2.3.4", |
| file: "another.txt", |
| err: fs.ErrNotExist.Error(), |
| }, |
| } { |
| t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.file, runTest(tt)) |
| if tt.repo == gitrepo1 { |
| for _, tt.repo = range altRepos() { |
| t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.file, runTest(tt)) |
| } |
| } |
| } |
| } |
| |
| type zipFile struct { |
| name string |
| size int64 |
| } |
| |
| func TestReadZip(t *testing.T) { |
| t.Parallel() |
| |
| type readZipTest struct { |
| repo string |
| rev string |
| subdir string |
| err string |
| files map[string]uint64 |
| } |
| runTest := func(tt readZipTest) func(*testing.T) { |
| return func(t *testing.T) { |
| t.Parallel() |
| ctx := testContext(t) |
| |
| r, err := testRepo(ctx, t, tt.repo) |
| if err != nil { |
| t.Fatal(err) |
| } |
| rc, err := r.ReadZip(ctx, tt.rev, tt.subdir, 100000) |
| if err != nil { |
| if tt.err == "" { |
| t.Fatalf("ReadZip: unexpected error %v", err) |
| } |
| if !strings.Contains(err.Error(), tt.err) { |
| t.Fatalf("ReadZip: wrong error %q, want %q", err, tt.err) |
| } |
| if rc != nil { |
| t.Errorf("ReadZip: non-nil io.ReadCloser with error %v", err) |
| } |
| return |
| } |
| defer rc.Close() |
| if tt.err != "" { |
| t.Fatalf("ReadZip: no error, wanted %v", tt.err) |
| } |
| zipdata, err := io.ReadAll(rc) |
| if err != nil { |
| t.Fatal(err) |
| } |
| z, err := zip.NewReader(bytes.NewReader(zipdata), int64(len(zipdata))) |
| if err != nil { |
| t.Fatalf("ReadZip: cannot read zip file: %v", err) |
| } |
| have := make(map[string]bool) |
| for _, f := range z.File { |
| size, ok := tt.files[f.Name] |
| if !ok { |
| t.Errorf("ReadZip: unexpected file %s", f.Name) |
| continue |
| } |
| have[f.Name] = true |
| if size != ^uint64(0) && f.UncompressedSize64 != size { |
| t.Errorf("ReadZip: file %s has unexpected size %d != %d", f.Name, f.UncompressedSize64, size) |
| } |
| } |
| for name := range tt.files { |
| if !have[name] { |
| t.Errorf("ReadZip: missing file %s", name) |
| } |
| } |
| } |
| } |
| |
| for _, tt := range []readZipTest{ |
| { |
| repo: gitrepo1, |
| rev: "v2.3.4", |
| subdir: "", |
| files: map[string]uint64{ |
| "prefix/": 0, |
| "prefix/README": 0, |
| "prefix/v2": 3, |
| }, |
| }, |
| { |
| repo: hgrepo1, |
| rev: "v2.3.4", |
| subdir: "", |
| files: map[string]uint64{ |
| "prefix/.hg_archival.txt": ^uint64(0), |
| "prefix/README": 0, |
| "prefix/v2": 3, |
| }, |
| }, |
| |
| { |
| repo: gitrepo1, |
| rev: "v2", |
| subdir: "", |
| files: map[string]uint64{ |
| "prefix/": 0, |
| "prefix/README": 0, |
| "prefix/v2": 3, |
| "prefix/another.txt": 8, |
| "prefix/foo.txt": 13, |
| }, |
| }, |
| { |
| repo: hgrepo1, |
| rev: "v2", |
| subdir: "", |
| files: map[string]uint64{ |
| "prefix/.hg_archival.txt": ^uint64(0), |
| "prefix/README": 0, |
| "prefix/v2": 3, |
| "prefix/another.txt": 8, |
| "prefix/foo.txt": 13, |
| }, |
| }, |
| |
| { |
| repo: gitrepo1, |
| rev: "v3", |
| subdir: "", |
| files: map[string]uint64{ |
| "prefix/": 0, |
| "prefix/v3/": 0, |
| "prefix/v3/sub/": 0, |
| "prefix/v3/sub/dir/": 0, |
| "prefix/v3/sub/dir/file.txt": 16, |
| "prefix/README": 0, |
| }, |
| }, |
| { |
| repo: hgrepo1, |
| rev: "v3", |
| subdir: "", |
| files: map[string]uint64{ |
| "prefix/.hg_archival.txt": ^uint64(0), |
| "prefix/.hgtags": 405, |
| "prefix/v3/sub/dir/file.txt": 16, |
| "prefix/README": 0, |
| }, |
| }, |
| |
| { |
| repo: gitrepo1, |
| rev: "v3", |
| subdir: "v3/sub/dir", |
| files: map[string]uint64{ |
| "prefix/": 0, |
| "prefix/v3/": 0, |
| "prefix/v3/sub/": 0, |
| "prefix/v3/sub/dir/": 0, |
| "prefix/v3/sub/dir/file.txt": 16, |
| }, |
| }, |
| { |
| repo: hgrepo1, |
| rev: "v3", |
| subdir: "v3/sub/dir", |
| files: map[string]uint64{ |
| "prefix/v3/sub/dir/file.txt": 16, |
| }, |
| }, |
| |
| { |
| repo: gitrepo1, |
| rev: "v3", |
| subdir: "v3/sub", |
| files: map[string]uint64{ |
| "prefix/": 0, |
| "prefix/v3/": 0, |
| "prefix/v3/sub/": 0, |
| "prefix/v3/sub/dir/": 0, |
| "prefix/v3/sub/dir/file.txt": 16, |
| }, |
| }, |
| { |
| repo: hgrepo1, |
| rev: "v3", |
| subdir: "v3/sub", |
| files: map[string]uint64{ |
| "prefix/v3/sub/dir/file.txt": 16, |
| }, |
| }, |
| |
| { |
| repo: gitrepo1, |
| rev: "aaaaaaaaab", |
| subdir: "", |
| err: "unknown revision", |
| }, |
| { |
| repo: hgrepo1, |
| rev: "aaaaaaaaab", |
| subdir: "", |
| err: "unknown revision", |
| }, |
| |
| { |
| repo: vgotest1, |
| rev: "submod/v1.0.4", |
| subdir: "submod", |
| files: map[string]uint64{ |
| "prefix/": 0, |
| "prefix/submod/": 0, |
| "prefix/submod/go.mod": 53, |
| "prefix/submod/pkg/": 0, |
| "prefix/submod/pkg/p.go": 31, |
| }, |
| }, |
| } { |
| t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.subdir, runTest(tt)) |
| if tt.repo == gitrepo1 { |
| tt.repo = "localGitRepo" |
| t.Run(path.Base(tt.repo)+"/"+tt.rev+"/"+tt.subdir, runTest(tt)) |
| } |
| } |
| } |
| |
| var hgmap = map[string]string{ |
| "HEAD": "41964ddce1180313bdc01d0a39a2813344d6261d", // not tip due to bad hgrepo1 conversion |
| "9d02800338b8a55be062c838d1f02e0c5780b9eb": "8f49ee7a6ddcdec6f0112d9dca48d4a2e4c3c09e", |
| "76a00fb249b7f93091bc2c89a789dab1fc1bc26f": "88fde824ec8b41a76baa16b7e84212cee9f3edd0", |
| "ede458df7cd0fdca520df19a33158086a8a68e81": "41964ddce1180313bdc01d0a39a2813344d6261d", |
| "97f6aa59c81c623494825b43d39e445566e429a4": "c0cbbfb24c7c3c50c35c7b88e7db777da4ff625d", |
| } |
| |
| func TestStat(t *testing.T) { |
| t.Parallel() |
| |
| type statTest struct { |
| repo string |
| rev string |
| err string |
| info *RevInfo |
| } |
| runTest := func(tt statTest) func(*testing.T) { |
| return func(t *testing.T) { |
| t.Parallel() |
| ctx := testContext(t) |
| |
| r, err := testRepo(ctx, t, tt.repo) |
| if err != nil { |
| t.Fatal(err) |
| } |
| info, err := r.Stat(ctx, tt.rev) |
| if err != nil { |
| if tt.err == "" { |
| t.Fatalf("Stat: unexpected error %v", err) |
| } |
| if !strings.Contains(err.Error(), tt.err) { |
| t.Fatalf("Stat: wrong error %q, want %q", err, tt.err) |
| } |
| if info != nil && info.Origin == nil { |
| t.Errorf("Stat: non-nil info with nil Origin with error %q", err) |
| } |
| return |
| } |
| info.Origin = nil // TestLatest and ../../../testdata/script/reuse_git.txt test Origin well enough |
| if !reflect.DeepEqual(info, tt.info) { |
| t.Errorf("Stat: incorrect info\nhave %+v\nwant %+v", *info, *tt.info) |
| } |
| } |
| } |
| |
| for _, tt := range []statTest{ |
| { |
| repo: gitrepo1, |
| rev: "HEAD", |
| info: &RevInfo{ |
| Name: "ede458df7cd0fdca520df19a33158086a8a68e81", |
| Short: "ede458df7cd0", |
| Version: "ede458df7cd0fdca520df19a33158086a8a68e81", |
| Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), |
| Tags: []string{"v1.2.3", "v1.2.4-annotated"}, |
| }, |
| }, |
| { |
| repo: gitrepo1, |
| rev: "v2", // branch |
| info: &RevInfo{ |
| Name: "9d02800338b8a55be062c838d1f02e0c5780b9eb", |
| Short: "9d02800338b8", |
| Version: "9d02800338b8a55be062c838d1f02e0c5780b9eb", |
| Time: time.Date(2018, 4, 17, 20, 00, 32, 0, time.UTC), |
| Tags: []string{"v2.0.2"}, |
| }, |
| }, |
| { |
| repo: gitrepo1, |
| rev: "v2.3.4", // badly-named branch (semver should be a tag) |
| info: &RevInfo{ |
| Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f", |
| Short: "76a00fb249b7", |
| Version: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f", |
| Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC), |
| Tags: []string{"v2.0.1", "v2.3"}, |
| }, |
| }, |
| { |
| repo: gitrepo1, |
| rev: "v2.3", // badly-named tag (we only respect full semver v2.3.0) |
| info: &RevInfo{ |
| Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f", |
| Short: "76a00fb249b7", |
| Version: "v2.3", |
| Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC), |
| Tags: []string{"v2.0.1", "v2.3"}, |
| }, |
| }, |
| { |
| repo: gitrepo1, |
| rev: "v1.2.3", // tag |
| info: &RevInfo{ |
| Name: "ede458df7cd0fdca520df19a33158086a8a68e81", |
| Short: "ede458df7cd0", |
| Version: "v1.2.3", |
| Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), |
| Tags: []string{"v1.2.3", "v1.2.4-annotated"}, |
| }, |
| }, |
| { |
| repo: gitrepo1, |
| rev: "ede458df", // hash prefix in refs |
| info: &RevInfo{ |
| Name: "ede458df7cd0fdca520df19a33158086a8a68e81", |
| Short: "ede458df7cd0", |
| Version: "ede458df7cd0fdca520df19a33158086a8a68e81", |
| Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), |
| Tags: []string{"v1.2.3", "v1.2.4-annotated"}, |
| }, |
| }, |
| { |
| repo: gitrepo1, |
| rev: "97f6aa59", // hash prefix not in refs |
| info: &RevInfo{ |
| Name: "97f6aa59c81c623494825b43d39e445566e429a4", |
| Short: "97f6aa59c81c", |
| Version: "97f6aa59c81c623494825b43d39e445566e429a4", |
| Time: time.Date(2018, 4, 17, 20, 0, 19, 0, time.UTC), |
| }, |
| }, |
| { |
| repo: gitrepo1, |
| rev: "v1.2.4-annotated", // annotated tag uses unwrapped commit hash |
| info: &RevInfo{ |
| Name: "ede458df7cd0fdca520df19a33158086a8a68e81", |
| Short: "ede458df7cd0", |
| Version: "v1.2.4-annotated", |
| Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC), |
| Tags: []string{"v1.2.3", "v1.2.4-annotated"}, |
| }, |
| }, |
| { |
| repo: gitrepo1, |
| rev: "aaaaaaaaab", |
| err: "unknown revision", |
| }, |
| } { |
| t.Run(path.Base(tt.repo)+"/"+tt.rev, runTest(tt)) |
| if tt.repo == gitrepo1 { |
| for _, tt.repo = range altRepos() { |
| old := tt |
| var m map[string]string |
| if tt.repo == hgrepo1 { |
| m = hgmap |
| } |
| if tt.info != nil { |
| info := *tt.info |
| tt.info = &info |
| tt.info.Name = remap(tt.info.Name, m) |
| tt.info.Version = remap(tt.info.Version, m) |
| tt.info.Short = remap(tt.info.Short, m) |
| } |
| tt.rev = remap(tt.rev, m) |
| t.Run(path.Base(tt.repo)+"/"+tt.rev, runTest(tt)) |
| tt = old |
| } |
| } |
| } |
| } |
| |
| func remap(name string, m map[string]string) string { |
| if m[name] != "" { |
| return m[name] |
| } |
| if AllHex(name) { |
| for k, v := range m { |
| if strings.HasPrefix(k, name) { |
| return v[:len(name)] |
| } |
| } |
| } |
| return name |
| } |