package loose_test
import (
"bytes"
"errors"
"testing"
"lindenii.org/go/furgit/internal/testgit"
"lindenii.org/go/furgit/object/header"
"lindenii.org/go/furgit/object/id"
"lindenii.org/go/furgit/object/store"
"lindenii.org/go/furgit/object/store/loose"
"lindenii.org/go/furgit/object/typ"
)
func TestWrite(t *testing.T) {
t.Parallel()
writes := []struct {
name string
write func(looseStore *loose.Loose, content []byte) (id.ObjectID, error)
}{
{
name: "BytesContent",
write: func(looseStore *loose.Loose, content []byte) (id.ObjectID, error) {
return looseStore.WriteBytesContent(typ.TypeBlob, content)
},
},
{
name: "ReaderContent",
write: func(looseStore *loose.Loose, content []byte) (id.ObjectID, error) {
return looseStore.WriteReaderContent(typ.TypeBlob, uint64(len(content)), bytes.NewReader(content))
},
},
{
name: "BytesFull",
write: func(looseStore *loose.Loose, content []byte) (id.ObjectID, error) {
raw := header.Append(nil, typ.TypeBlob, uint64(len(content)))
raw = append(raw, content...)
return looseStore.WriteBytesFull(raw)
},
},
{
name: "ReaderFull",
write: func(looseStore *loose.Loose, content []byte) (id.ObjectID, error) {
raw := header.Append(nil, typ.TypeBlob, uint64(len(content)))
raw = append(raw, content...)
return looseStore.WriteReaderFull(bytes.NewReader(raw))
},
},
}
for _, objectFormat := range id.SupportedObjectFormats() {
t.Run(objectFormat.String(), func(t *testing.T) {
t.Parallel()
repo, err := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: objectFormat})
if err != nil {
t.Fatalf("NewRepo: %v", err)
}
looseStore := openLooseStore(t, repo)
for _, w := range writes {
t.Run(w.name, func(t *testing.T) {
content := []byte("written via " + w.name + "\n")
want, err := repo.HashObject(t, typ.TypeBlob, bytes.NewReader(content))
if err != nil {
t.Fatalf("HashObject: %v", err)
}
got, err := w.write(looseStore, content)
if err != nil {
t.Fatalf("write: %v", err)
}
if got != want {
t.Fatalf("id = %s, want %s", got, want)
}
gotBody, err := repo.CatFile(t, typ.TypeBlob, got)
if err != nil {
t.Fatalf("CatFile: %v", err)
}
if !bytes.Equal(gotBody, content) {
t.Fatalf("git cat-file body mismatch")
}
regot, err := w.write(looseStore, content)
if err != nil {
t.Fatalf("rewrite: %v", err)
}
if regot != want {
t.Fatalf("rewrite id = %s, want %s", regot, want)
}
})
}
})
}
}
func TestWriteRejects(t *testing.T) {
t.Parallel()
for _, objectFormat := range id.SupportedObjectFormats() {
t.Run(objectFormat.String(), func(t *testing.T) {
t.Parallel()
repo, err := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: objectFormat})
if err != nil {
t.Fatalf("NewRepo: %v", err)
}
looseStore := openLooseStore(t, repo)
t.Run("ContentOverflow", func(t *testing.T) {
t.Parallel()
_, err := looseStore.WriteReaderContent(typ.TypeBlob, 1, bytes.NewReader([]byte("hello")))
if !errors.Is(err, store.ErrInvalidObject) {
t.Fatalf("err = %v, want ErrInvalidObject", err)
}
})
t.Run("ContentShort", func(t *testing.T) {
t.Parallel()
_, err := looseStore.WriteReaderContent(typ.TypeBlob, 5, bytes.NewReader([]byte("x")))
if !errors.Is(err, store.ErrInvalidObject) {
t.Fatalf("err = %v, want ErrInvalidObject", err)
}
})
t.Run("FullMalformedHeader", func(t *testing.T) {
t.Parallel()
_, err := looseStore.WriteReaderFull(bytes.NewReader([]byte("not-a-header")))
if !errors.Is(err, store.ErrInvalidObject) {
t.Fatalf("err = %v, want ErrInvalidObject", err)
}
})
t.Run("FullSizeMismatch", func(t *testing.T) {
t.Parallel()
_, err := looseStore.WriteReaderFull(bytes.NewReader([]byte("blob 1\x00hello")))
if !errors.Is(err, store.ErrInvalidObject) {
t.Fatalf("err = %v, want ErrInvalidObject", err)
}
})
})
}
}