1package syncpkg_test
2
3import (
4 "bytes"
5 "crypto/sha256"
6 "testing"
7
8 "arche/internal/syncpkg"
9)
10
11func makeID(seed byte) [32]byte {
12 var b [32]byte
13 b[0] = seed
14 return sha256.Sum256(b[:])
15}
16
17func TestBloom_AddTest_HitAfterAdd(t *testing.T) {
18 f := syncpkg.NewBloom(100)
19 id := makeID(1)
20 if f.Test(id) {
21 t.Error("should not be present before Add")
22 }
23 f.Add(id)
24 if !f.Test(id) {
25 t.Error("should be present after Add")
26 }
27}
28
29func TestBloom_NoFalseNegatives(t *testing.T) {
30 const n = 200
31 f := syncpkg.NewBloom(n)
32 ids := make([][32]byte, n)
33 for i := range ids {
34 ids[i] = makeID(byte(i))
35 f.Add(ids[i])
36 }
37 for i, id := range ids {
38 if !f.Test(id) {
39 t.Errorf("false negative at index %d", i)
40 }
41 }
42}
43
44func TestBloom_Serialize(t *testing.T) {
45 f := syncpkg.NewBloom(50)
46 for i := range 10 {
47 f.Add(makeID(byte(i)))
48 }
49
50 data := f.Bytes()
51
52 f2, err := syncpkg.BloomFilterFrom(data)
53 if err != nil {
54 t.Fatalf("BloomFilterFrom: %v", err)
55 }
56
57 for i := range 10 {
58 id := makeID(byte(i))
59 if !f2.Test(id) {
60 t.Errorf("id %d not found after deserialization", i)
61 }
62 }
63}
64
65func TestBloom_EmptyBytes(t *testing.T) {
66 _, err := syncpkg.BloomFilterFrom([]byte{})
67 if err == nil {
68 t.Error("expected error for empty data")
69 }
70}
71
72func TestPack_Empty(t *testing.T) {
73 var buf bytes.Buffer
74 if err := syncpkg.WritePack(&buf, nil); err != nil {
75 t.Fatalf("WritePack (empty): %v", err)
76 }
77 entries, err := syncpkg.ReadPack(&buf)
78 if err != nil {
79 t.Fatalf("ReadPack (empty): %v", err)
80 }
81 if len(entries) != 0 {
82 t.Errorf("expected 0 entries, got %d", len(entries))
83 }
84}
85
86func TestPack_SingleEntry(t *testing.T) {
87 id := makeID(7)
88 e := syncpkg.PackEntry{
89 ID: id,
90 Kind: "blob",
91 Data: []byte("hello pack"),
92 }
93
94 var buf bytes.Buffer
95 if err := syncpkg.WritePack(&buf, []syncpkg.PackEntry{e}); err != nil {
96 t.Fatalf("WritePack: %v", err)
97 }
98
99 entries, err := syncpkg.ReadPack(&buf)
100 if err != nil {
101 t.Fatalf("ReadPack: %v", err)
102 }
103 if len(entries) != 1 {
104 t.Fatalf("len: want 1, got %d", len(entries))
105 }
106 if entries[0].ID != id {
107 t.Errorf("ID mismatch")
108 }
109 if entries[0].Kind != "blob" {
110 t.Errorf("Kind: want blob, got %q", entries[0].Kind)
111 }
112 if !bytes.Equal(entries[0].Data, []byte("hello pack")) {
113 t.Errorf("Data mismatch")
114 }
115}
116
117func TestPack_MultipleEntries(t *testing.T) {
118 kinds := []string{"blob", "tree", "commit"}
119 in := make([]syncpkg.PackEntry, len(kinds))
120 for i, k := range kinds {
121 in[i] = syncpkg.PackEntry{
122 ID: makeID(byte(i + 10)),
123 Kind: k,
124 Data: []byte("data-" + k),
125 }
126 }
127
128 var buf bytes.Buffer
129 if err := syncpkg.WritePack(&buf, in); err != nil {
130 t.Fatalf("WritePack: %v", err)
131 }
132 out, err := syncpkg.ReadPack(&buf)
133 if err != nil {
134 t.Fatalf("ReadPack: %v", err)
135 }
136 if len(out) != len(in) {
137 t.Fatalf("len: want %d, got %d", len(in), len(out))
138 }
139 for i := range in {
140 if out[i].ID != in[i].ID {
141 t.Errorf("[%d] ID mismatch", i)
142 }
143 if out[i].Kind != in[i].Kind {
144 t.Errorf("[%d] Kind: want %q got %q", i, in[i].Kind, out[i].Kind)
145 }
146 if !bytes.Equal(out[i].Data, in[i].Data) {
147 t.Errorf("[%d] Data mismatch", i)
148 }
149 }
150}
151
152func TestPack_LargeData(t *testing.T) {
153 large := make([]byte, 64*1024)
154 for i := range large {
155 large[i] = byte(i % 251)
156 }
157 e := syncpkg.PackEntry{ID: makeID(99), Kind: "blob", Data: large}
158
159 var buf bytes.Buffer
160 syncpkg.WritePack(&buf, []syncpkg.PackEntry{e}) //nolint:errcheck
161 out, err := syncpkg.ReadPack(&buf)
162 if err != nil {
163 t.Fatalf("ReadPack large: %v", err)
164 }
165 if !bytes.Equal(out[0].Data, large) {
166 t.Error("large data round-trip failed")
167 }
168}