aboutsummaryrefslogtreecommitdiff
path: root/reachability/reachability_integration_test.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-03 22:49:24 +0800
committerGravatar Runxi Yu2026-03-03 22:52:47 +0800
commit6378da9dcf8d991a00ee410bb5408231861d90c0 (patch)
tree5427fbc11b79a683598c02cdcdc81048423c92f2 /reachability/reachability_integration_test.go
parentconfig: Fix lints (diff)
reachability: Refactor v0.1.41
Diffstat (limited to 'reachability/reachability_integration_test.go')
-rw-r--r--reachability/reachability_integration_test.go388
1 files changed, 0 insertions, 388 deletions
diff --git a/reachability/reachability_integration_test.go b/reachability/reachability_integration_test.go
deleted file mode 100644
index 10668006..00000000
--- a/reachability/reachability_integration_test.go
+++ /dev/null
@@ -1,388 +0,0 @@
-package reachability_test
-
-import (
- "errors"
- "fmt"
- "maps"
- "os"
- "path/filepath"
- "slices"
- "strings"
- "testing"
-
- "codeberg.org/lindenii/furgit/internal/testgit"
- "codeberg.org/lindenii/furgit/objectid"
- "codeberg.org/lindenii/furgit/reachability"
- "codeberg.org/lindenii/furgit/repository"
-)
-
-func TestWalkCommitsMatchesGitRevList(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- testRepo := testgit.NewRepo(t, testgit.RepoOptions{
- ObjectFormat: algo,
- Bare: true,
- RefFormat: "files",
- })
-
- _, tree1 := testRepo.MakeSingleFileTree(t, "base.txt", []byte("base\n"))
- base := testRepo.CommitTree(t, tree1, "base")
-
- _, tree2 := testRepo.MakeSingleFileTree(t, "left.txt", []byte("left\n"))
- left := testRepo.CommitTree(t, tree2, "left", base)
-
- _, tree3 := testRepo.MakeSingleFileTree(t, "right.txt", []byte("right\n"))
- right := testRepo.CommitTree(t, tree3, "right", base)
-
- _, tree4 := testRepo.MakeSingleFileTree(t, "merge.txt", []byte("merge\n"))
- merge := testRepo.CommitTree(t, tree4, "merge", left, right)
-
- tag1 := testRepo.TagAnnotated(t, "v1", merge, "v1")
- tag2 := testRepo.TagAnnotated(t, "v2", tag1, "v2")
-
- r := openReachabilityFromTestRepo(t, testRepo)
- walk := r.Walk(
- reachability.DomainCommits,
- nil,
- map[objectid.ObjectID]struct{}{merge: {}},
- )
- got := oidSetFromSeq(walk.Seq())
- if err := walk.Err(); err != nil {
- t.Fatalf("walk.Err(): %v", err)
- }
-
- want := gitRevListSet(t, testRepo, false, []objectid.ObjectID{merge}, nil)
- if !maps.Equal(got, want) {
- t.Fatalf("commit walk mismatch:\n got=%v\nwant=%v", sortedOIDStrings(got), sortedOIDStrings(want))
- }
-
- peelWalk := r.Walk(
- reachability.DomainCommits,
- nil,
- map[objectid.ObjectID]struct{}{tag2: {}},
- )
- peelGot := oidSetFromSeq(peelWalk.Seq())
- if err := peelWalk.Err(); err != nil {
- t.Fatalf("peelWalk.Err(): %v", err)
- }
- wantWithTags := maps.Clone(want)
- wantWithTags[tag1] = struct{}{}
- wantWithTags[tag2] = struct{}{}
- if !maps.Equal(peelGot, wantWithTags) {
- t.Fatalf("tag-root commit walk mismatch:\n got=%v\nwant=%v", sortedOIDStrings(peelGot), sortedOIDStrings(wantWithTags))
- }
- })
-}
-
-func TestWalkObjectsMatchesGitRevListObjects(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- testRepo := testgit.NewRepo(t, testgit.RepoOptions{
- ObjectFormat: algo,
- Bare: true,
- RefFormat: "files",
- })
-
- aBlob := testRepo.HashObject(t, "blob", []byte("a\n"))
- bBlob := testRepo.HashObject(t, "blob", []byte("b\n"))
- nestedTree := testRepo.Mktree(t, fmt.Sprintf("100644 blob %s\tb.txt\n", bBlob))
- rootTree := testRepo.Mktree(t,
- fmt.Sprintf("100644 blob %s\ta.txt\n040000 tree %s\tdir\n", aBlob, nestedTree),
- )
- base := testRepo.CommitTree(t, rootTree, "base")
-
- cBlob := testRepo.HashObject(t, "blob", []byte("c\n"))
- tree2 := testRepo.Mktree(t, fmt.Sprintf("100644 blob %s\tc.txt\n", cBlob))
- head := testRepo.CommitTree(t, tree2, "head", base)
- tag := testRepo.TagAnnotated(t, "objtag", head, "objtag")
-
- r := openReachabilityFromTestRepo(t, testRepo)
- walk := r.Walk(
- reachability.DomainObjects,
- nil,
- map[objectid.ObjectID]struct{}{head: {}},
- )
- got := oidSetFromSeq(walk.Seq())
- if err := walk.Err(); err != nil {
- t.Fatalf("walk.Err(): %v", err)
- }
-
- want := gitRevListSet(t, testRepo, true, []objectid.ObjectID{head}, nil)
- if !maps.Equal(got, want) {
- t.Fatalf("object walk mismatch:\n got=%v\nwant=%v", sortedOIDStrings(got), sortedOIDStrings(want))
- }
-
- peelWalk := r.Walk(
- reachability.DomainObjects,
- nil,
- map[objectid.ObjectID]struct{}{tag: {}},
- )
- peelGot := oidSetFromSeq(peelWalk.Seq())
- if err := peelWalk.Err(); err != nil {
- t.Fatalf("peelWalk.Err(): %v", err)
- }
- wantFromTag := gitRevListSet(t, testRepo, true, []objectid.ObjectID{tag}, nil)
- if !maps.Equal(peelGot, wantFromTag) {
- t.Fatalf("tag-root object walk mismatch:\n got=%v\nwant=%v", sortedOIDStrings(peelGot), sortedOIDStrings(wantFromTag))
- }
-
- walkWithHave := r.Walk(
- reachability.DomainObjects,
- map[objectid.ObjectID]struct{}{base: {}},
- map[objectid.ObjectID]struct{}{head: {}},
- )
- withHave := oidSetFromSeq(walkWithHave.Seq())
- if err := walkWithHave.Err(); err != nil {
- t.Fatalf("walkWithHave.Err(): %v", err)
- }
- if _, ok := withHave[base]; ok {
- t.Fatalf("walk output unexpectedly contains have commit %s", base)
- }
- })
-}
-
-func TestIsAncestorMatchesGitMergeBase(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- testRepo := testgit.NewRepo(t, testgit.RepoOptions{
- ObjectFormat: algo,
- Bare: true,
- RefFormat: "files",
- })
-
- _, tree1 := testRepo.MakeSingleFileTree(t, "one.txt", []byte("one\n"))
- c1 := testRepo.CommitTree(t, tree1, "c1")
-
- _, tree2 := testRepo.MakeSingleFileTree(t, "two.txt", []byte("two\n"))
- c2 := testRepo.CommitTree(t, tree2, "c2", c1)
-
- _, tree3 := testRepo.MakeSingleFileTree(t, "three.txt", []byte("three\n"))
- c3 := testRepo.CommitTree(t, tree3, "c3", c2)
-
- tag := testRepo.TagAnnotated(t, "tip", c2, "tip")
-
- r := openReachabilityFromTestRepo(t, testRepo)
-
- got, err := r.IsAncestor(c1, tag)
- if err != nil {
- t.Fatalf("IsAncestor(c1, tag): %v", err)
- }
- if want := gitMergeBaseIsAncestor(t, testRepo, c1, c2); got != want {
- t.Fatalf("IsAncestor(c1, tag)=%v, want %v", got, want)
- }
-
- got, err = r.IsAncestor(c3, c2)
- if err != nil {
- t.Fatalf("IsAncestor(c3, c2): %v", err)
- }
- if want := gitMergeBaseIsAncestor(t, testRepo, c3, c2); got != want {
- t.Fatalf("IsAncestor(c3, c2)=%v, want %v", got, want)
- }
- })
-}
-
-func TestCheckConnectedMissingObject(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- testRepo := testgit.NewRepo(t, testgit.RepoOptions{
- ObjectFormat: algo,
- Bare: true,
- RefFormat: "files",
- })
-
- _, treeID, commitID := testRepo.MakeCommit(t, "missing")
- if err := os.Remove(looseObjectPath(testRepo.Dir(), treeID)); err != nil {
- t.Fatalf("remove tree object: %v", err)
- }
-
- r := openReachabilityFromTestRepo(t, testRepo)
- err := r.CheckConnected(
- reachability.DomainObjects,
- nil,
- map[objectid.ObjectID]struct{}{commitID: {}},
- )
- if err == nil {
- t.Fatal("expected error")
- }
- var missing *reachability.ErrObjectMissing
- if !errors.As(err, &missing) {
- t.Fatalf("expected ErrObjectMissing, got %T (%v)", err, err)
- }
- if missing.OID != treeID {
- t.Fatalf("missing oid = %s, want %s", missing.OID, treeID)
- }
- })
-}
-
-func TestWalkOnPackedOnlyRepo(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- testRepo := testgit.NewRepo(t, testgit.RepoOptions{
- ObjectFormat: algo,
- Bare: true,
- RefFormat: "files",
- })
-
- _, tree1 := testRepo.MakeSingleFileTree(t, "one.txt", []byte("one\n"))
- c1 := testRepo.CommitTree(t, tree1, "one")
- _, tree2 := testRepo.MakeSingleFileTree(t, "two.txt", []byte("two\n"))
- c2 := testRepo.CommitTree(t, tree2, "two", c1)
- testRepo.UpdateRef(t, "refs/heads/main", c2)
- testRepo.SymbolicRef(t, "HEAD", "refs/heads/main")
-
- testRepo.Repack(t, "-ad")
- testRepo.Run(t, "prune-packed")
-
- assertPackedOnly(t, testRepo.Dir())
-
- r := openReachabilityFromTestRepo(t, testRepo)
- walk := r.Walk(
- reachability.DomainCommits,
- nil,
- map[objectid.ObjectID]struct{}{c2: {}},
- )
- got := oidSetFromSeq(walk.Seq())
- if err := walk.Err(); err != nil {
- t.Fatalf("walk.Err(): %v", err)
- }
- if _, ok := got[c2]; !ok {
- t.Fatalf("walk output missing HEAD commit %s", c2)
- }
- if _, ok := got[c1]; !ok {
- t.Fatalf("walk output missing parent commit %s", c1)
- }
- })
-}
-
-func openReachabilityFromTestRepo(t *testing.T, testRepo *testgit.TestRepo) *reachability.Reachability {
- t.Helper()
- root, err := os.OpenRoot(testRepo.Dir())
- if err != nil {
- t.Fatalf("os.OpenRoot: %v", err)
- }
- t.Cleanup(func() { _ = root.Close() })
-
- repo, err := repository.Open(root)
- if err != nil {
- t.Fatalf("repository.Open: %v", err)
- }
- t.Cleanup(func() { _ = repo.Close() })
-
- return reachability.New(repo.Objects())
-}
-
-func oidSetFromSeq(seq func(func(objectid.ObjectID) bool)) map[objectid.ObjectID]struct{} {
- out := make(map[objectid.ObjectID]struct{})
- seq(func(id objectid.ObjectID) bool {
- out[id] = struct{}{}
- return true
- })
- return out
-}
-
-func gitRevListSet(
- t *testing.T,
- testRepo *testgit.TestRepo,
- includeObjects bool,
- wants []objectid.ObjectID,
- haves []objectid.ObjectID,
-) map[objectid.ObjectID]struct{} {
- t.Helper()
-
- args := []string{"rev-list"}
- if includeObjects {
- args = append(args, "--objects")
- }
- for _, want := range wants {
- args = append(args, want.String())
- }
- if len(haves) > 0 {
- args = append(args, "--not")
- for _, have := range haves {
- args = append(args, have.String())
- }
- }
-
- out := testRepo.Run(t, args...)
- set := make(map[objectid.ObjectID]struct{})
- for line := range strings.SplitSeq(strings.TrimSpace(out), "\n") {
- line = strings.TrimSpace(line)
- if line == "" {
- continue
- }
- tok := line
- if i := strings.IndexByte(tok, ' '); i >= 0 {
- tok = tok[:i]
- }
- id, err := objectid.ParseHex(testRepo.Algorithm(), tok)
- if err != nil {
- t.Fatalf("parse rev-list oid %q: %v", tok, err)
- }
- set[id] = struct{}{}
- }
- return set
-}
-
-func gitMergeBaseIsAncestor(t *testing.T, testRepo *testgit.TestRepo, a, b objectid.ObjectID) bool {
- t.Helper()
- // testgit.Run fatals on non-zero status, so we compare merge-base output.
- mb := testRepo.Run(t, "merge-base", a.String(), b.String())
- return mb == a.String()
-}
-
-func sortedOIDStrings(set map[objectid.ObjectID]struct{}) []string {
- out := make([]string, 0, len(set))
- for id := range set {
- out = append(out, id.String())
- }
- slices.Sort(out)
- return out
-}
-
-func looseObjectPath(repoDir string, id objectid.ObjectID) string {
- hex := id.String()
- return filepath.Join(repoDir, "objects", hex[:2], hex[2:])
-}
-
-func assertPackedOnly(t *testing.T, repoDir string) {
- t.Helper()
- objectsDir := filepath.Join(repoDir, "objects")
-
- entries, err := os.ReadDir(objectsDir)
- if err != nil {
- t.Fatalf("ReadDir(objects): %v", err)
- }
- for _, entry := range entries {
- name := entry.Name()
- if name == "pack" || name == "info" {
- continue
- }
- if len(name) == 2 && isHexDirName(name) {
- subEntries, err := os.ReadDir(filepath.Join(objectsDir, name))
- if err != nil {
- t.Fatalf("ReadDir(objects/%s): %v", name, err)
- }
- if len(subEntries) != 0 {
- t.Fatalf("found loose objects in %s", filepath.Join(objectsDir, name))
- }
- }
- }
-}
-
-func isHexDirName(name string) bool {
- if len(name) != 2 {
- return false
- }
- for i := range 2 {
- c := name[i]
- if (c < '0' || c > '9') && (c < 'a' || c > 'f') {
- return false
- }
- }
- return true
-}