Fast implementation of Git in pure Go
at master 117 lines 3.7 kB view raw
1package commitquery_test 2 3import ( 4 "errors" 5 "fmt" 6 "testing" 7 8 giterrors "codeberg.org/lindenii/furgit/errors" 9 "codeberg.org/lindenii/furgit/internal/testgit" 10 "codeberg.org/lindenii/furgit/object" 11 "codeberg.org/lindenii/furgit/objectid" 12 "codeberg.org/lindenii/furgit/objectstore/memory" 13 "codeberg.org/lindenii/furgit/objecttype" 14 15 "codeberg.org/lindenii/furgit/commitquery" 16) 17 18// ancestorCommitBody serializes one minimal commit body. 19func ancestorCommitBody(tree objectid.ObjectID, parents ...objectid.ObjectID) []byte { 20 buf := fmt.Appendf(nil, "tree %s\n", tree.String()) 21 for _, parent := range parents { 22 buf = append(buf, fmt.Appendf(nil, "parent %s\n", parent.String())...) 23 } 24 25 buf = append(buf, []byte("\nmsg\n")...) 26 27 return buf 28} 29 30// ancestorTagBody serializes one minimal annotated tag body. 31func ancestorTagBody(target objectid.ObjectID, targetType objecttype.Type) []byte { 32 targetName, ok := objecttype.Name(targetType) 33 if !ok { 34 panic("invalid tag target type") 35 } 36 37 return fmt.Appendf(nil, "object %s\ntype %s\ntag t\n\nmsg\n", target.String(), targetName) 38} 39 40// mustSerializeAncestorTree serializes one tree or fails the test. 41func mustSerializeAncestorTree(tb testing.TB, tree *object.Tree) []byte { 42 tb.Helper() 43 44 body, err := tree.SerializeWithoutHeader() 45 if err != nil { 46 tb.Fatalf("SerializeWithoutHeader: %v", err) 47 } 48 49 return body 50} 51 52func TestIs(t *testing.T) { 53 t.Parallel() 54 55 testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper 56 store := memory.New(algo) 57 blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) 58 tree := store.AddObject(objecttype.TypeTree, mustSerializeAncestorTree(t, &object.Tree{Entries: []object.TreeEntry{{ 59 Mode: object.FileModeRegular, 60 Name: []byte("f"), 61 ID: blob, 62 }}})) 63 c1 := store.AddObject(objecttype.TypeCommit, ancestorCommitBody(tree)) 64 c2 := store.AddObject(objecttype.TypeCommit, ancestorCommitBody(tree, c1)) 65 otherBlob := store.AddObject(objecttype.TypeBlob, []byte("other-blob\n")) 66 otherTree := store.AddObject(objecttype.TypeTree, mustSerializeAncestorTree(t, &object.Tree{Entries: []object.TreeEntry{{ 67 Mode: object.FileModeRegular, 68 Name: []byte("g"), 69 ID: otherBlob, 70 }}})) 71 c3 := store.AddObject(objecttype.TypeCommit, ancestorCommitBody(otherTree)) 72 tag := store.AddObject(objecttype.TypeTag, ancestorTagBody(c2, objecttype.TypeCommit)) 73 74 ok, err := commitquery.New(store, nil).IsAncestor(c1, tag) 75 if err != nil { 76 t.Fatalf("Is(c1, tag): %v", err) 77 } 78 79 if !ok { 80 t.Fatal("expected c1 to be ancestor of tag->c2") 81 } 82 83 ok, err = commitquery.New(store, nil).IsAncestor(c3, c2) 84 if err != nil { 85 t.Fatalf("Is(c3, c2): %v", err) 86 } 87 88 if ok { 89 t.Fatal("did not expect c3 to be ancestor of c2") 90 } 91 }) 92} 93 94func TestIsRejectsNonCommitAfterPeel(t *testing.T) { 95 t.Parallel() 96 97 testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper 98 store := memory.New(algo) 99 blob := store.AddObject(objecttype.TypeBlob, []byte("blob\n")) 100 tree := store.AddObject(objecttype.TypeTree, mustSerializeAncestorTree(t, &object.Tree{Entries: []object.TreeEntry{{ 101 Mode: object.FileModeRegular, 102 Name: []byte("f"), 103 ID: blob, 104 }}})) 105 commit := store.AddObject(objecttype.TypeCommit, ancestorCommitBody(tree)) 106 tagToTree := store.AddObject(objecttype.TypeTag, ancestorTagBody(tree, objecttype.TypeTree)) 107 108 _, err := commitquery.New(store, nil).IsAncestor(commit, tagToTree) 109 if err == nil { 110 t.Fatal("expected error") 111 } 112 113 if _, ok := errors.AsType[*giterrors.ObjectTypeError](err); !ok { 114 t.Fatalf("expected ObjectTypeError, got %T (%v)", err, err) 115 } 116 }) 117}