package commitquery_test import ( "errors" "fmt" "testing" giterrors "codeberg.org/lindenii/furgit/errors" "codeberg.org/lindenii/furgit/internal/testgit" "codeberg.org/lindenii/furgit/object/fetch" objectid "codeberg.org/lindenii/furgit/object/id" "codeberg.org/lindenii/furgit/object/store/memory" objecttree "codeberg.org/lindenii/furgit/object/tree" objecttype "codeberg.org/lindenii/furgit/object/type" "codeberg.org/lindenii/furgit/commitquery" ) // ancestorCommitBody serializes one minimal commit body. func ancestorCommitBody(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 } // ancestorTagBody serializes one minimal annotated tag body. func ancestorTagBody(target objectid.ObjectID, targetType objecttype.Type) []byte { targetName, ok := targetType.Name() if !ok { panic("invalid tag target type") } return fmt.Appendf(nil, "object %s\ntype %s\ntag t\n\nmsg\n", target.String(), targetName) } // mustSerializeAncestorTree serializes one tree or fails the test. func mustSerializeAncestorTree(tb testing.TB, tree *objecttree.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, err := store.WriteBytesContent(objecttype.TypeBlob, []byte("blob\n")) if err != nil { t.Fatal(err) } tree, err := store.WriteBytesContent(objecttype.TypeTree, mustSerializeAncestorTree(t, &objecttree.Tree{Entries: []objecttree.TreeEntry{{ Mode: objecttree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) if err != nil { t.Fatal(err) } c1, err := store.WriteBytesContent(objecttype.TypeCommit, ancestorCommitBody(tree)) if err != nil { t.Fatal(err) } c2, err := store.WriteBytesContent(objecttype.TypeCommit, ancestorCommitBody(tree, c1)) if err != nil { t.Fatal(err) } otherBlob, err := store.WriteBytesContent(objecttype.TypeBlob, []byte("other-blob\n")) if err != nil { t.Fatal(err) } otherTree, err := store.WriteBytesContent(objecttype.TypeTree, mustSerializeAncestorTree(t, &objecttree.Tree{Entries: []objecttree.TreeEntry{{ Mode: objecttree.FileModeRegular, Name: []byte("g"), ID: otherBlob, }}})) if err != nil { t.Fatal(err) } c3, err := store.WriteBytesContent(objecttype.TypeCommit, ancestorCommitBody(otherTree)) if err != nil { t.Fatal(err) } tag, err := store.WriteBytesContent(objecttype.TypeTag, ancestorTagBody(c2, objecttype.TypeCommit)) if err != nil { t.Fatal(err) } ok, err := commitquery.New(fetch.New(store), nil).IsAncestor(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 = commitquery.New(fetch.New(store), nil).IsAncestor(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, err := store.WriteBytesContent(objecttype.TypeBlob, []byte("blob\n")) if err != nil { t.Fatal(err) } tree, err := store.WriteBytesContent(objecttype.TypeTree, mustSerializeAncestorTree(t, &objecttree.Tree{Entries: []objecttree.TreeEntry{{ Mode: objecttree.FileModeRegular, Name: []byte("f"), ID: blob, }}})) if err != nil { t.Fatal(err) } commit, err := store.WriteBytesContent(objecttype.TypeCommit, ancestorCommitBody(tree)) if err != nil { t.Fatal(err) } tagToTree, err := store.WriteBytesContent(objecttype.TypeTag, ancestorTagBody(tree, objecttype.TypeTree)) if err != nil { t.Fatal(err) } _, err = commitquery.New(fetch.New(store), nil).IsAncestor(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) } }) }