aboutsummaryrefslogtreecommitdiff
path: root/objectstore/loose/write_test.go
blob: cceabe5ae4942b5c5ff49b2f5b64f49bf9ecc56c (about) (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package loose_test

import (
	"bytes"
	"testing"

	"codeberg.org/lindenii/furgit/internal/testgit"
	"codeberg.org/lindenii/furgit/objectheader"
	"codeberg.org/lindenii/furgit/objectid"
	"codeberg.org/lindenii/furgit/objecttype"
)

func TestLooseStoreWriteReaderContentAgainstGit(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})
		store := openLooseStore(t, testRepo.Dir(), algo)

		content := []byte("written-by-content-reader\n")
		expectedHex := testRepo.RunInput(t, content, "hash-object", "-t", "blob", "--stdin")
		expectedID, err := objectid.ParseHex(algo, expectedHex)
		if err != nil {
			t.Fatalf("ParseHex(expected): %v", err)
		}

		writtenID, err := store.WriteReaderContent(objecttype.TypeBlob, int64(len(content)), bytes.NewReader(content))
		if err != nil {
			t.Fatalf("WriteReaderContent: %v", err)
		}
		if writtenID != expectedID {
			t.Fatalf("WriteReaderContent id = %s, want %s", writtenID, expectedID)
		}

		gotBody := testRepo.CatFile(t, "blob", writtenID)
		if !bytes.Equal(gotBody, content) {
			t.Fatalf("git cat-file body mismatch")
		}

		// Writing the same object again should succeed and return the same ID.
		writtenID2, err := store.WriteReaderContent(objecttype.TypeBlob, int64(len(content)), bytes.NewReader(content))
		if err != nil {
			t.Fatalf("WriteReaderContent second: %v", err)
		}
		if writtenID2 != expectedID {
			t.Fatalf("WriteReaderContent second id = %s, want %s", writtenID2, expectedID)
		}
	})
}

func TestLooseStoreWriteReaderFullAgainstGit(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})
		store := openLooseStore(t, testRepo.Dir(), algo)

		body := []byte("full-reader-body\n")
		header, ok := objectheader.Encode(objecttype.TypeBlob, int64(len(body)))
		if !ok {
			t.Fatalf("objectheader.Encode failed")
		}
		raw := make([]byte, len(header)+len(body))
		copy(raw, header)
		copy(raw[len(header):], body)

		wantID := algo.Sum(raw)
		gotID, err := store.WriteReaderFull(bytes.NewReader(raw))
		if err != nil {
			t.Fatalf("WriteReaderFull: %v", err)
		}
		if gotID != wantID {
			t.Fatalf("WriteReaderFull id = %s, want %s", gotID, wantID)
		}

		gotBody := testRepo.CatFile(t, "blob", gotID)
		if !bytes.Equal(gotBody, body) {
			t.Fatalf("git cat-file body mismatch")
		}
	})
}

func TestLooseStoreReaderValidationErrors(t *testing.T) {
	t.Parallel()
	testgit.ForEachAlgorithm(t, func(t *testing.T, algo objectid.Algorithm) { //nolint:thelper
		t.Run("content overflow", func(t *testing.T) {
			t.Parallel()
			testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true})
			store := openLooseStore(t, testRepo.Dir(), algo)

			if _, err := store.WriteReaderContent(objecttype.TypeBlob, 1, bytes.NewReader([]byte("hello"))); err == nil {
				t.Fatalf("expected error after overflow")
			}
		})

		t.Run("content short", func(t *testing.T) {
			t.Parallel()
			testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true})
			store := openLooseStore(t, testRepo.Dir(), algo)

			if _, err := store.WriteReaderContent(objecttype.TypeBlob, 5, bytes.NewReader([]byte("x"))); err == nil {
				t.Fatalf("expected error for short content")
			}
		})

		t.Run("full malformed header", func(t *testing.T) {
			t.Parallel()
			testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true})
			store := openLooseStore(t, testRepo.Dir(), algo)

			if _, err := store.WriteReaderFull(bytes.NewReader([]byte("not-a-header"))); err == nil {
				t.Fatalf("expected error for malformed header")
			}
		})

		t.Run("full size mismatch", func(t *testing.T) {
			t.Parallel()
			testRepo := testgit.NewRepo(t, testgit.RepoOptions{ObjectFormat: algo, Bare: true})
			store := openLooseStore(t, testRepo.Dir(), algo)

			raw := []byte("blob 1\x00hello")
			if _, err := store.WriteReaderFull(bytes.NewReader(raw)); err == nil {
				t.Fatalf("expected error after mismatch")
			}
		})
	})
}