aboutsummaryrefslogtreecommitdiff
path: root/mergebase
diff options
context:
space:
mode:
Diffstat (limited to 'mergebase')
-rw-r--r--mergebase/base.go30
-rw-r--r--mergebase/compute.go73
-rw-r--r--mergebase/integration_test.go309
-rw-r--r--mergebase/mergebase.go20
-rw-r--r--mergebase/query.go24
-rw-r--r--mergebase/unit_test.go332
6 files changed, 0 insertions, 788 deletions
diff --git a/mergebase/base.go b/mergebase/base.go
deleted file mode 100644
index 278fbed2..00000000
--- a/mergebase/base.go
+++ /dev/null
@@ -1,30 +0,0 @@
-package mergebase
-
-import (
- commitgraphread "codeberg.org/lindenii/furgit/commitgraph/read"
- "codeberg.org/lindenii/furgit/objectid"
- "codeberg.org/lindenii/furgit/objectstore"
-)
-
-// Base reports one merge base between left and right, if any.
-//
-// Both inputs are peeled through annotated tags before commit traversal.
-func Base(
- store objectstore.Store,
- graph *commitgraphread.Reader,
- left objectid.ObjectID,
- right objectid.ObjectID,
-) (objectid.ObjectID, bool, error) {
- query := Query(store, graph, left, right)
-
- bases, err := query.All()
- if err != nil {
- return objectid.ObjectID{}, false, err
- }
-
- if len(bases) == 0 {
- return objectid.ObjectID{}, false, nil
- }
-
- return bases[0], true, nil
-}
diff --git a/mergebase/compute.go b/mergebase/compute.go
deleted file mode 100644
index 76d2294c..00000000
--- a/mergebase/compute.go
+++ /dev/null
@@ -1,73 +0,0 @@
-package mergebase
-
-import (
- "slices"
-
- "codeberg.org/lindenii/furgit/internal/commitquery"
- "codeberg.org/lindenii/furgit/internal/peel"
- "codeberg.org/lindenii/furgit/objectid"
-)
-
-// All returns all merge bases in Git's merge-base --all order.
-func (query *Bases) All() ([]objectid.ObjectID, error) {
- if query.computed {
- return slices.Clone(query.bases), query.err
- }
-
- query.computed = true
-
- leftCommit, err := peel.ToCommit(query.store, query.left)
- if err != nil {
- query.err = err
-
- return nil, err
- }
-
- rightCommit, err := peel.ToCommit(query.store, query.right)
- if err != nil {
- query.err = err
-
- return nil, err
- }
-
- ctx := commitquery.NewContext(query.store, query.graph)
-
- leftIdx, err := ctx.ResolveOID(leftCommit)
- if err != nil {
- query.err = err
-
- return nil, err
- }
-
- rightIdx, err := ctx.ResolveOID(rightCommit)
- if err != nil {
- query.err = err
-
- return nil, err
- }
-
- candidates, err := commitquery.MergeBases(ctx, leftIdx, rightIdx)
- if err != nil {
- query.err = err
-
- return nil, err
- }
-
- slices.SortFunc(candidates, func(left, right commitquery.NodeIndex) int {
- switch {
- case ctx.CommitTime(left) > ctx.CommitTime(right):
- return -1
- case ctx.CommitTime(left) < ctx.CommitTime(right):
- return 1
- default:
- return objectid.Compare(ctx.ID(left), ctx.ID(right))
- }
- })
-
- query.bases = make([]objectid.ObjectID, 0, len(candidates))
- for _, idx := range candidates {
- query.bases = append(query.bases, ctx.ID(idx))
- }
-
- return slices.Clone(query.bases), nil
-}
diff --git a/mergebase/integration_test.go b/mergebase/integration_test.go
deleted file mode 100644
index 3d85409d..00000000
--- a/mergebase/integration_test.go
+++ /dev/null
@@ -1,309 +0,0 @@
-package mergebase_test
-
-import (
- "maps"
- "slices"
- "strings"
- "testing"
-
- "codeberg.org/lindenii/furgit/internal/testgit"
- "codeberg.org/lindenii/furgit/mergebase"
- "codeberg.org/lindenii/furgit/objectid"
-)
-
-func TestQueryMatchesGitMergeBaseAll(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)
-
- tag := testRepo.TagAnnotated(t, "right-tag", right, "right-tag")
-
- store := testRepo.OpenObjectStore(t)
-
- query := mergebase.Query(store, nil, left, tag)
-
- all, err := query.All()
- if err != nil {
- t.Fatalf("query.All(): %v", err)
- }
-
- got := oidSetFromSlice(all)
-
- want := gitMergeBaseAllSet(t, testRepo, left, tag)
- if !maps.Equal(got, want) {
- t.Fatalf("Query(left, tag) mismatch:\n got=%v\nwant=%v", sortedOIDStrings(got), sortedOIDStrings(want))
- }
- })
-}
-
-func TestQueryCrissCrossMatchesGitMergeBaseAll(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, "root.txt", []byte("root\n"))
- root := testRepo.CommitTree(t, tree1, "root")
-
- _, tree2 := testRepo.MakeSingleFileTree(t, "base1.txt", []byte("base1\n"))
- base1 := testRepo.CommitTree(t, tree2, "base1", root)
-
- _, tree3 := testRepo.MakeSingleFileTree(t, "base2.txt", []byte("base2\n"))
- base2 := testRepo.CommitTree(t, tree3, "base2", root)
-
- _, tree4 := testRepo.MakeSingleFileTree(t, "left.txt", []byte("left\n"))
- left := testRepo.CommitTree(t, tree4, "left", base1, base2)
-
- _, tree5 := testRepo.MakeSingleFileTree(t, "right.txt", []byte("right\n"))
- right := testRepo.CommitTree(t, tree5, "right", base2, base1)
-
- store := testRepo.OpenObjectStore(t)
-
- query := mergebase.Query(store, nil, left, right)
-
- all, err := query.All()
- if err != nil {
- t.Fatalf("query.All(): %v", err)
- }
-
- got := oidSetFromSlice(all)
-
- want := gitMergeBaseAllSet(t, testRepo, left, right)
- if !maps.Equal(got, want) {
- t.Fatalf("Query(left, right) mismatch:\n got=%v\nwant=%v", sortedOIDStrings(got), sortedOIDStrings(want))
- }
-
- first, ok, err := mergebase.Base(store, nil, left, right)
- if err != nil {
- t.Fatalf("Base(left, right): %v", err)
- }
-
- if !ok {
- t.Fatal("Base(left, right) unexpectedly reported no base")
- }
-
- if !containsID(want, first) {
- t.Fatalf("Base(left, right)=%s, want one of %v", first, slices.Collect(maps.Keys(want)))
- }
- })
-}
-
-func TestQueryMatchesGitMergeBaseAllWithCommitGraph(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, "root.txt", []byte("root\n"))
- root := testRepo.CommitTree(t, tree1, "root")
-
- _, tree2 := testRepo.MakeSingleFileTree(t, "base1.txt", []byte("base1\n"))
- base1 := testRepo.CommitTree(t, tree2, "base1", root)
-
- _, tree3 := testRepo.MakeSingleFileTree(t, "base2.txt", []byte("base2\n"))
- base2 := testRepo.CommitTree(t, tree3, "base2", root)
-
- _, tree4 := testRepo.MakeSingleFileTree(t, "left.txt", []byte("left\n"))
- left := testRepo.CommitTree(t, tree4, "left", base1, base2)
-
- _, tree5 := testRepo.MakeSingleFileTree(t, "right.txt", []byte("right\n"))
- right := testRepo.CommitTree(t, tree5, "right", base2, base1)
-
- testRepo.UpdateRef(t, "refs/heads/main", right)
- testRepo.SymbolicRef(t, "HEAD", "refs/heads/main")
- testRepo.CommitGraphWrite(t, "--reachable")
-
- store := testRepo.OpenObjectStore(t)
- graph := testRepo.OpenCommitGraph(t)
-
- query := mergebase.Query(store, graph, left, right)
-
- all, err := query.All()
- if err != nil {
- t.Fatalf("query.All(): %v", err)
- }
-
- got := oidSetFromSlice(all)
-
- want := gitMergeBaseAllSet(t, testRepo, left, right)
- if !maps.Equal(got, want) {
- t.Fatalf("Query(left, right) with commit-graph mismatch:\n got=%v\nwant=%v", sortedOIDStrings(got), sortedOIDStrings(want))
- }
-
- first, ok, err := mergebase.Base(store, graph, left, right)
- if err != nil {
- t.Fatalf("Base(left, right): %v", err)
- }
-
- if !ok {
- t.Fatal("Base(left, right) unexpectedly reported no base")
- }
-
- if !containsID(want, first) {
- t.Fatalf("Base(left, right)=%s, want one of %v", first, slices.Collect(maps.Keys(want)))
- }
- })
-}
-
-func TestBaseMatchesGitMergeBaseWithoutAll(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, "root.txt", []byte("root\n"))
- root := testRepo.CommitTree(t, tree1, "root")
-
- _, tree2 := testRepo.MakeSingleFileTree(t, "base1.txt", []byte("base1\n"))
- base1 := testRepo.CommitTreeWithEnv(t, []string{
- "GIT_AUTHOR_DATE=1234567890 +0000",
- "GIT_COMMITTER_DATE=1234567890 +0000",
- }, tree2, "base1", root)
-
- _, tree3 := testRepo.MakeSingleFileTree(t, "base2.txt", []byte("base2\n"))
- base2 := testRepo.CommitTreeWithEnv(t, []string{
- "GIT_AUTHOR_DATE=1234567990 +0000",
- "GIT_COMMITTER_DATE=1234567990 +0000",
- }, tree3, "base2", root)
-
- _, tree4 := testRepo.MakeSingleFileTree(t, "left.txt", []byte("left\n"))
- left := testRepo.CommitTree(t, tree4, "left", base1, base2)
-
- _, tree5 := testRepo.MakeSingleFileTree(t, "right.txt", []byte("right\n"))
- right := testRepo.CommitTree(t, tree5, "right", base2, base1)
-
- store := testRepo.OpenObjectStore(t)
-
- got, ok, err := mergebase.Base(store, nil, left, right)
- if err != nil {
- t.Fatalf("Base(left, right): %v", err)
- }
-
- if !ok {
- t.Fatal("Base(left, right) unexpectedly reported no base")
- }
-
- want := gitMergeBaseOne(t, testRepo, left, right)
- if got != want {
- t.Fatalf("Base(left, right)=%s, want %s", got, want)
- }
-
- testRepo.UpdateRef(t, "refs/heads/main", right)
- testRepo.SymbolicRef(t, "HEAD", "refs/heads/main")
- testRepo.CommitGraphWrite(t, "--reachable")
-
- graph := testRepo.OpenCommitGraph(t)
-
- got, ok, err = mergebase.Base(store, graph, left, right)
- if err != nil {
- t.Fatalf("Base(left, right) with commit-graph: %v", err)
- }
-
- if !ok {
- t.Fatal("Base(left, right) with commit-graph unexpectedly reported no base")
- }
-
- if got != want {
- t.Fatalf("Base(left, right) with commit-graph=%s, want %s", got, want)
- }
- })
-}
-
-// oidSetFromSlice collects one object ID slice into a set.
-func oidSetFromSlice(ids []objectid.ObjectID) map[objectid.ObjectID]struct{} {
- out := make(map[objectid.ObjectID]struct{})
-
- for _, id := range ids {
- out[id] = struct{}{}
- }
-
- return out
-}
-
-// gitMergeBaseAllSet returns Git's merge-base --all output as a set.
-func gitMergeBaseAllSet(
- t *testing.T,
- testRepo *testgit.TestRepo,
- left objectid.ObjectID,
- right objectid.ObjectID,
-) map[objectid.ObjectID]struct{} {
- t.Helper()
-
- out := testRepo.Run(t, "merge-base", "--all", left.String(), right.String())
- set := make(map[objectid.ObjectID]struct{})
-
- for line := range strings.SplitSeq(strings.TrimSpace(out), "\n") {
- line = strings.TrimSpace(line)
- if line == "" {
- continue
- }
-
- id, err := objectid.ParseHex(testRepo.Algorithm(), line)
- if err != nil {
- t.Fatalf("parse merge-base oid %q: %v", line, err)
- }
-
- set[id] = struct{}{}
- }
-
- return set
-}
-
-// gitMergeBaseOne returns Git's merge-base output without --all.
-func gitMergeBaseOne(
- t *testing.T,
- testRepo *testgit.TestRepo,
- left objectid.ObjectID,
- right objectid.ObjectID,
-) objectid.ObjectID {
- t.Helper()
-
- out := strings.TrimSpace(testRepo.Run(t, "merge-base", left.String(), right.String()))
- if out == "" {
- t.Fatal("git merge-base returned no output")
- }
-
- id, err := objectid.ParseHex(testRepo.Algorithm(), out)
- if err != nil {
- t.Fatalf("parse merge-base oid %q: %v", out, err)
- }
-
- return id
-}
-
-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
-}
diff --git a/mergebase/mergebase.go b/mergebase/mergebase.go
deleted file mode 100644
index 772dc355..00000000
--- a/mergebase/mergebase.go
+++ /dev/null
@@ -1,20 +0,0 @@
-// Package mergebase computes best common ancestors between commits.
-package mergebase
-
-import (
- commitgraphread "codeberg.org/lindenii/furgit/commitgraph/read"
- "codeberg.org/lindenii/furgit/objectid"
- "codeberg.org/lindenii/furgit/objectstore"
-)
-
-// Bases is one merge-base query over two commit roots.
-type Bases struct {
- store objectstore.Store
- graph *commitgraphread.Reader
- left objectid.ObjectID
- right objectid.ObjectID
-
- computed bool
- bases []objectid.ObjectID
- err error
-}
diff --git a/mergebase/query.go b/mergebase/query.go
deleted file mode 100644
index 9a934377..00000000
--- a/mergebase/query.go
+++ /dev/null
@@ -1,24 +0,0 @@
-package mergebase
-
-import (
- commitgraphread "codeberg.org/lindenii/furgit/commitgraph/read"
- "codeberg.org/lindenii/furgit/objectid"
- "codeberg.org/lindenii/furgit/objectstore"
-)
-
-// Query builds one merge-base query over two commit roots.
-//
-// Both inputs are peeled through annotated tags before commit traversal.
-func Query(
- store objectstore.Store,
- graph *commitgraphread.Reader,
- left objectid.ObjectID,
- right objectid.ObjectID,
-) *Bases {
- return &Bases{
- store: store,
- graph: graph,
- left: left,
- right: right,
- }
-}
diff --git a/mergebase/unit_test.go b/mergebase/unit_test.go
deleted file mode 100644
index 7ba1ed66..00000000
--- a/mergebase/unit_test.go
+++ /dev/null
@@ -1,332 +0,0 @@
-package mergebase_test
-
-import (
- "errors"
- "fmt"
- "maps"
- "slices"
- "testing"
-
- giterrors "codeberg.org/lindenii/furgit/errors"
- "codeberg.org/lindenii/furgit/internal/testgit"
- "codeberg.org/lindenii/furgit/mergebase"
- "codeberg.org/lindenii/furgit/object"
- "codeberg.org/lindenii/furgit/objectid"
- "codeberg.org/lindenii/furgit/objectstore/memory"
- "codeberg.org/lindenii/furgit/objecttype"
-)
-
-// 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)
-}
-
-// toSet converts one slice of object IDs into a set.
-func toSet(ids []objectid.ObjectID) map[objectid.ObjectID]struct{} {
- set := make(map[objectid.ObjectID]struct{}, len(ids))
- for _, id := range ids {
- set[id] = struct{}{}
- }
-
- return set
-}
-
-// containsID reports whether one set contains one object ID.
-func containsID(set map[objectid.ObjectID]struct{}, id objectid.ObjectID) bool {
- _, ok := set[id]
-
- return ok
-}
-
-// 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
-}
-
-// TestQueryLinearHistory reports one linear-history merge base.
-func TestQueryLinearHistory(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,
- }}}))
- base := store.AddObject(objecttype.TypeCommit, commitBody(tree))
- left := store.AddObject(objecttype.TypeCommit, commitBody(tree, base))
- right := store.AddObject(objecttype.TypeCommit, commitBody(tree, left))
-
- query := mergebase.Query(store, nil, left, right)
-
- got, err := query.All()
- if err != nil {
- t.Fatalf("query.All(): %v", err)
- }
-
- if !slices.Equal(got, []objectid.ObjectID{left}) {
- t.Fatalf("Query(left, right)=%v, want [%s]", got, left)
- }
-
- first, ok, err := mergebase.Base(store, nil, left, right)
- if err != nil {
- t.Fatalf("Base(left, right): %v", err)
- }
-
- if !ok {
- t.Fatal("Base(left, right) unexpectedly reported no base")
- }
-
- if first != left {
- t.Fatalf("Base(left, right)=%s, want %s", first, left)
- }
- })
-}
-
-func TestQueryPeelsAnnotatedTags(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"))
- leftTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("left"),
- ID: blob,
- }}}))
- rightTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("right"),
- ID: blob,
- }}}))
- base := store.AddObject(objecttype.TypeCommit, commitBody(leftTree))
- left := store.AddObject(objecttype.TypeCommit, commitBody(leftTree, base))
- right := store.AddObject(objecttype.TypeCommit, commitBody(rightTree, base))
- tag := store.AddObject(objecttype.TypeTag, tagBody(right, objecttype.TypeCommit))
-
- query := mergebase.Query(store, nil, left, tag)
-
- got, err := query.All()
- if err != nil {
- t.Fatalf("query.All(): %v", err)
- }
-
- if !slices.Equal(got, []objectid.ObjectID{base}) {
- t.Fatalf("Query(left, tag)=%v, want [%s]", got, base)
- }
- })
-}
-
-func TestQueryCrissCrossReturnsAllBestCommonAncestors(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"))
- rootTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("root"),
- ID: blob,
- }}}))
- base1Tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("base1"),
- ID: blob,
- }}}))
- base2Tree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("base2"),
- ID: blob,
- }}}))
- leftTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("left"),
- ID: blob,
- }}}))
- rightTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("right"),
- ID: blob,
- }}}))
- root := store.AddObject(objecttype.TypeCommit, commitBody(rootTree))
- base1 := store.AddObject(objecttype.TypeCommit, commitBody(base1Tree, root))
- base2 := store.AddObject(objecttype.TypeCommit, commitBody(base2Tree, root))
- left := store.AddObject(objecttype.TypeCommit, commitBody(leftTree, base1, base2))
- right := store.AddObject(objecttype.TypeCommit, commitBody(rightTree, base2, base1))
-
- query := mergebase.Query(store, nil, left, right)
-
- all, err := query.All()
- if err != nil {
- t.Fatalf("query.All(): %v", err)
- }
-
- got := toSet(all)
-
- want := map[objectid.ObjectID]struct{}{base1: {}, base2: {}}
- if !maps.Equal(got, want) {
- t.Fatalf("Query(left, right)=%v, want %v", slices.Collect(maps.Keys(got)), slices.Collect(maps.Keys(want)))
- }
-
- first, ok, err := mergebase.Base(store, nil, left, right)
- if err != nil {
- t.Fatalf("Base(left, right): %v", err)
- }
-
- if !ok {
- t.Fatal("Base(left, right) unexpectedly reported no base")
- }
-
- if !containsID(want, first) {
- t.Fatalf("Base(left, right)=%s, want one of %v", first, slices.Collect(maps.Keys(want)))
- }
- })
-}
-
-func TestQueryReturnsNoResultWhenNoCommonAncestorExists(t *testing.T) {
- t.Parallel()
-
- testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
- store := memory.New(algo)
- leftBlob := store.AddObject(objecttype.TypeBlob, []byte("left\n"))
- leftTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("left"),
- ID: leftBlob,
- }}}))
- rightBlob := store.AddObject(objecttype.TypeBlob, []byte("right\n"))
- rightTree := store.AddObject(objecttype.TypeTree, mustSerializeTree(t, &object.Tree{Entries: []object.TreeEntry{{
- Mode: object.FileModeRegular,
- Name: []byte("right"),
- ID: rightBlob,
- }}}))
- left := store.AddObject(objecttype.TypeCommit, commitBody(leftTree))
- right := store.AddObject(objecttype.TypeCommit, commitBody(rightTree))
-
- query := mergebase.Query(store, nil, left, right)
-
- got, err := query.All()
- if err != nil {
- t.Fatalf("query.All(): %v", err)
- }
-
- if len(got) != 0 {
- t.Fatalf("Query(left, right)=%v, want no results", got)
- }
-
- _, ok, err := mergebase.Base(store, nil, left, right)
- if err != nil {
- t.Fatalf("Base(left, right): %v", err)
- }
-
- if ok {
- t.Fatal("Base(left, right) unexpectedly reported a base")
- }
- })
-}
-
-func TestQueryRejectsNonCommitAfterPeel(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))
-
- query := mergebase.Query(store, nil, commit, tagToTree)
-
- _, err := query.All()
- if err == nil {
- t.Fatal("expected error")
- }
-
- typeErr, ok := errors.AsType[*giterrors.ObjectTypeError](err)
- if !ok {
- t.Fatalf("expected ObjectTypeError, got %T (%v)", err, err)
- }
-
- if typeErr.Got != objecttype.TypeTree || typeErr.Want != objecttype.TypeCommit {
- t.Fatalf("unexpected type error: %+v", typeErr)
- }
- })
-}
-
-func TestQueryAllIsRepeatable(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,
- }}}))
- base := store.AddObject(objecttype.TypeCommit, commitBody(tree))
- left := store.AddObject(objecttype.TypeCommit, commitBody(tree, base))
- right := store.AddObject(objecttype.TypeCommit, commitBody(tree, left))
-
- query := mergebase.Query(store, nil, left, right)
-
- first, err := query.All()
- if err != nil {
- t.Fatalf("query.All() first call: %v", err)
- }
-
- again, err := query.All()
- if err != nil {
- t.Fatalf("query.All() second call: %v", err)
- }
-
- if !slices.Equal(again, first) {
- t.Fatalf("second All()=%v, want %v", again, first)
- }
-
- if len(first) == 0 {
- t.Fatal("first All() unexpectedly returned no results")
- }
-
- first[0] = objectid.ObjectID{}
-
- third, err := query.All()
- if err != nil {
- t.Fatalf("query.All() third call: %v", err)
- }
-
- if third[0] == (objectid.ObjectID{}) {
- t.Fatal("query.All() exposed internal slice state")
- }
- })
-}