aboutsummaryrefslogtreecommitdiff
path: root/ancestor
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-11 20:41:32 +0800
committerGravatar Runxi Yu2026-03-11 20:41:32 +0800
commit040b572d95e4ca27e1ada6113c405b8a1eb4a669 (patch)
tree68d826f4d91144105802c9d1c67175ba9b314e29 /ancestor
parentresearch: Maybe drop mmap in packfile_bloom (diff)
signatureNo signature
commitquery: Merge from ancestor and mergebases
Diffstat (limited to 'ancestor')
-rw-r--r--ancestor/ancestor.go45
-rw-r--r--ancestor/integration_test.go133
-rw-r--r--ancestor/unit_test.go117
3 files changed, 0 insertions, 295 deletions
diff --git a/ancestor/ancestor.go b/ancestor/ancestor.go
deleted file mode 100644
index 51684250..00000000
--- a/ancestor/ancestor.go
+++ /dev/null
@@ -1,45 +0,0 @@
-// Package ancestor answers commit ancestry queries.
-package ancestor
-
-import (
- commitgraphread "codeberg.org/lindenii/furgit/commitgraph/read"
- "codeberg.org/lindenii/furgit/internal/commitquery"
- "codeberg.org/lindenii/furgit/internal/peel"
- "codeberg.org/lindenii/furgit/objectid"
- "codeberg.org/lindenii/furgit/objectstore"
-)
-
-// Is reports whether ancestor is reachable from descendant through commit
-// parent edges.
-//
-// Both inputs are peeled through annotated tags before commit traversal.
-func Is(
- store objectstore.Store,
- graph *commitgraphread.Reader,
- ancestor objectid.ObjectID,
- descendant objectid.ObjectID,
-) (bool, error) {
- ancestorCommit, err := peel.ToCommit(store, ancestor)
- if err != nil {
- return false, err
- }
-
- descendantCommit, err := peel.ToCommit(store, descendant)
- if err != nil {
- return false, err
- }
-
- ctx := commitquery.NewContext(store, graph)
-
- ancestorIdx, err := ctx.ResolveOID(ancestorCommit)
- if err != nil {
- return false, err
- }
-
- descendantIdx, err := ctx.ResolveOID(descendantCommit)
- if err != nil {
- return false, err
- }
-
- return commitquery.IsAncestor(ctx, ancestorIdx, descendantIdx)
-}
diff --git a/ancestor/integration_test.go b/ancestor/integration_test.go
deleted file mode 100644
index fa630f57..00000000
--- a/ancestor/integration_test.go
+++ /dev/null
@@ -1,133 +0,0 @@
-package ancestor_test
-
-import (
- "errors"
- "testing"
-
- giterrors "codeberg.org/lindenii/furgit/errors"
- "codeberg.org/lindenii/furgit/internal/testgit"
- "codeberg.org/lindenii/furgit/objectid"
-
- "codeberg.org/lindenii/furgit/ancestor"
-)
-
-func TestIsMatchesGitMergeBase(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")
-
- store := testRepo.OpenObjectStore(t)
-
- got, err := ancestor.Is(store, nil, c1, tag)
- if err != nil {
- t.Fatalf("Is(c1, tag): %v", err)
- }
-
- want := gitMergeBaseIsAncestor(t, testRepo, c1, c2)
- if got != want {
- t.Fatalf("Is(c1, tag)=%v, want %v", got, want)
- }
-
- got, err = ancestor.Is(store, nil, c3, c2)
- if err != nil {
- t.Fatalf("Is(c3, c2): %v", err)
- }
-
- want = gitMergeBaseIsAncestor(t, testRepo, c3, c2)
- if got != want {
- t.Fatalf("Is(c3, c2)=%v, want %v", got, want)
- }
- })
-}
-
-func TestIsMatchesGitMergeBaseWithCommitGraph(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)
-
- testRepo.UpdateRef(t, "refs/heads/main", c2)
- testRepo.SymbolicRef(t, "HEAD", "refs/heads/main")
- testRepo.CommitGraphWrite(t, "--reachable")
-
- store := testRepo.OpenObjectStore(t)
- graph := testRepo.OpenCommitGraph(t)
-
- got, err := ancestor.Is(store, graph, c1, c2)
- if err != nil {
- t.Fatalf("Is(c1, c2): %v", err)
- }
-
- want := gitMergeBaseIsAncestor(t, testRepo, c1, c2)
- if got != want {
- t.Fatalf("Is(c1, c2)=%v, want %v", got, want)
- }
- })
-}
-
-func TestIsMissingObject(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")
-
- testRepo.RemoveLooseObject(t, treeID)
-
- store := testRepo.OpenObjectStore(t)
-
- _, err := ancestor.Is(store, nil, treeID, commitID)
- if err == nil {
- t.Fatal("expected error")
- }
-
- missing, ok := errors.AsType[*giterrors.ObjectMissingError](err)
- if !ok {
- t.Fatalf("expected ObjectMissingError, got %T (%v)", err, err)
- }
-
- if missing.OID != treeID {
- t.Fatalf("missing oid = %s, want %s", missing.OID, treeID)
- }
- })
-}
-
-// gitMergeBaseIsAncestor reports Git's merge-base ancestry answer.
-func gitMergeBaseIsAncestor(t *testing.T, testRepo *testgit.TestRepo, left, right objectid.ObjectID) bool {
- t.Helper()
-
- out := testRepo.Run(t, "merge-base", left.String(), right.String())
-
- return out == left.String()
-}
diff --git a/ancestor/unit_test.go b/ancestor/unit_test.go
deleted file mode 100644
index b6ca7b58..00000000
--- a/ancestor/unit_test.go
+++ /dev/null
@@ -1,117 +0,0 @@
-package ancestor_test
-
-import (
- "errors"
- "fmt"
- "testing"
-
- giterrors "codeberg.org/lindenii/furgit/errors"
- "codeberg.org/lindenii/furgit/internal/testgit"
- "codeberg.org/lindenii/furgit/object"
- "codeberg.org/lindenii/furgit/objectid"
- "codeberg.org/lindenii/furgit/objectstore/memory"
- "codeberg.org/lindenii/furgit/objecttype"
-
- "codeberg.org/lindenii/furgit/ancestor"
-)
-
-// commitBody serializes one minimal commit body.
-func commitBody(tree objectid.ObjectID, parents ...objectid.ObjectID) []byte {
- buf := fmt.Appendf(nil, "tree %s\n", tree.String())
- for _, parent := range parents {
- buf = append(buf, fmt.Appendf(nil, "parent %s\n", parent.String())...)
- }
-
- buf = append(buf, []byte("\nmsg\n")...)
-
- return buf
-}
-
-// tagBody serializes one minimal annotated tag body.
-func tagBody(target objectid.ObjectID, targetType objecttype.Type) []byte {
- targetName, ok := objecttype.Name(targetType)
- if !ok {
- panic("invalid tag target type")
- }
-
- return fmt.Appendf(nil, "object %s\ntype %s\ntag t\n\nmsg\n", target.String(), targetName)
-}
-
-// mustSerializeTree serializes one tree or fails the test.
-func mustSerializeTree(tb testing.TB, tree *object.Tree) []byte {
- tb.Helper()
-
- body, err := tree.SerializeWithoutHeader()
- if err != nil {
- tb.Fatalf("SerializeWithoutHeader: %v", err)
- }
-
- return body
-}
-
-func TestIs(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- store := memory.New(algo)
- blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n"))
- tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("f"),
- ID: blob,
- }}}))
- c1 := store.AddObject(objecttype.TypeCommit, commitBody(tree))
- c2 := store.AddObject(objecttype.TypeCommit, commitBody(tree, c1))
- otherBlob := store.AddObject(objecttype.TypeBlob, []byte("other-blob\n"))
- otherTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("g"),
- ID: otherBlob,
- }}}))
- c3 := store.AddObject(objecttype.TypeCommit, commitBody(otherTree))
- tag := store.AddObject(objecttype.TypeTag, tagBody(c2, objecttype.TypeCommit))
-
- ok, err := ancestor.Is(store, nil, c1, tag)
- if err != nil {
- t.Fatalf("Is(c1, tag): %v", err)
- }
-
- if !ok {
- t.Fatal("expected c1 to be ancestor of tag->c2")
- }
-
- ok, err = ancestor.Is(store, nil, c3, c2)
- if err != nil {
- t.Fatalf("Is(c3, c2): %v", err)
- }
-
- if ok {
- t.Fatal("did not expect c3 to be ancestor of c2")
- }
- })
-}
-
-func TestIsRejectsNonCommitAfterPeel(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- store := memory.New(algo)
- blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n"))
- tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("f"),
- ID: blob,
- }}}))
- commit := store.AddObject(objecttype.TypeCommit, commitBody(tree))
- tagToTree := store.AddObject(objecttype.TypeTag, tagBody(tree, objecttype.TypeTree))
-
- _, err := ancestor.Is(store, nil, commit, tagToTree)
- if err == nil {
- t.Fatal("expected error")
- }
-
- if _, ok := errors.AsType[*giterrors.ObjectTypeError](err); !ok {
- t.Fatalf("expected ObjectTypeError, got %T (%v)", err, err)
- }
- })
-}