]> git.ipfire.org Git - thirdparty/git.git/blob - reftable/record_test.c
926808481566d2df0a05a5c08d05c3f012363b8f
[thirdparty/git.git] / reftable / record_test.c
1 /*
2 Copyright 2020 Google LLC
3
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file or at
6 https://developers.google.com/open-source/licenses/bsd
7 */
8
9 #include "record.h"
10
11 #include "system.h"
12 #include "basics.h"
13 #include "constants.h"
14 #include "test_framework.h"
15 #include "reftable-tests.h"
16
17 static void test_copy(struct reftable_record *rec)
18 {
19 struct reftable_record copy =
20 reftable_new_record(reftable_record_type(rec));
21 reftable_record_copy_from(&copy, rec, GIT_SHA1_RAWSZ);
22 /* do it twice to catch memory leaks */
23 reftable_record_copy_from(&copy, rec, GIT_SHA1_RAWSZ);
24 EXPECT(reftable_record_equal(rec, &copy, GIT_SHA1_RAWSZ));
25 reftable_record_destroy(&copy);
26 }
27
28 static void test_varint_roundtrip(void)
29 {
30 uint64_t inputs[] = { 0,
31 1,
32 27,
33 127,
34 128,
35 257,
36 4096,
37 ((uint64_t)1 << 63),
38 ((uint64_t)1 << 63) + ((uint64_t)1 << 63) - 1 };
39 int i = 0;
40 for (i = 0; i < ARRAY_SIZE(inputs); i++) {
41 uint8_t dest[10];
42
43 struct string_view out = {
44 .buf = dest,
45 .len = sizeof(dest),
46 };
47 uint64_t in = inputs[i];
48 int n = put_var_int(&out, in);
49 uint64_t got = 0;
50
51 EXPECT(n > 0);
52 out.len = n;
53 n = get_var_int(&got, &out);
54 EXPECT(n > 0);
55
56 EXPECT(got == in);
57 }
58 }
59
60 static void test_common_prefix(void)
61 {
62 struct {
63 const char *a, *b;
64 int want;
65 } cases[] = {
66 { "abc", "ab", 2 },
67 { "", "abc", 0 },
68 { "abc", "abd", 2 },
69 { "abc", "pqr", 0 },
70 };
71
72 int i = 0;
73 for (i = 0; i < ARRAY_SIZE(cases); i++) {
74 struct strbuf a = STRBUF_INIT;
75 struct strbuf b = STRBUF_INIT;
76 strbuf_addstr(&a, cases[i].a);
77 strbuf_addstr(&b, cases[i].b);
78 EXPECT(common_prefix_size(&a, &b) == cases[i].want);
79
80 strbuf_release(&a);
81 strbuf_release(&b);
82 }
83 }
84
85 static void set_hash(uint8_t *h, int j)
86 {
87 int i = 0;
88 for (i = 0; i < hash_size(GIT_SHA1_FORMAT_ID); i++) {
89 h[i] = (j >> i) & 0xff;
90 }
91 }
92
93 static void test_reftable_ref_record_roundtrip(void)
94 {
95 int i = 0;
96
97 for (i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) {
98 struct reftable_ref_record in = { NULL };
99 struct reftable_ref_record out = { NULL };
100 struct reftable_record rec_out = { NULL };
101 struct strbuf key = STRBUF_INIT;
102 struct reftable_record rec = { NULL };
103 uint8_t buffer[1024] = { 0 };
104 struct string_view dest = {
105 .buf = buffer,
106 .len = sizeof(buffer),
107 };
108
109 int n, m;
110
111 in.value_type = i;
112 switch (i) {
113 case REFTABLE_REF_DELETION:
114 break;
115 case REFTABLE_REF_VAL1:
116 in.value.val1 = reftable_malloc(GIT_SHA1_RAWSZ);
117 set_hash(in.value.val1, 1);
118 break;
119 case REFTABLE_REF_VAL2:
120 in.value.val2.value = reftable_malloc(GIT_SHA1_RAWSZ);
121 set_hash(in.value.val2.value, 1);
122 in.value.val2.target_value =
123 reftable_malloc(GIT_SHA1_RAWSZ);
124 set_hash(in.value.val2.target_value, 2);
125 break;
126 case REFTABLE_REF_SYMREF:
127 in.value.symref = xstrdup("target");
128 break;
129 }
130 in.refname = xstrdup("refs/heads/master");
131
132 reftable_record_from_ref(&rec, &in);
133 test_copy(&rec);
134
135 EXPECT(reftable_record_val_type(&rec) == i);
136
137 reftable_record_key(&rec, &key);
138 n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
139 EXPECT(n > 0);
140
141 /* decode into a non-zero reftable_record to test for leaks. */
142
143 reftable_record_from_ref(&rec_out, &out);
144 m = reftable_record_decode(&rec_out, key, i, dest,
145 GIT_SHA1_RAWSZ);
146 EXPECT(n == m);
147
148 EXPECT(reftable_ref_record_equal(&in, &out, GIT_SHA1_RAWSZ));
149 reftable_record_release(&rec_out);
150
151 strbuf_release(&key);
152 reftable_ref_record_release(&in);
153 }
154 }
155
156 static void test_reftable_log_record_equal(void)
157 {
158 struct reftable_log_record in[2] = {
159 {
160 .refname = xstrdup("refs/heads/master"),
161 .update_index = 42,
162 },
163 {
164 .refname = xstrdup("refs/heads/master"),
165 .update_index = 22,
166 }
167 };
168
169 EXPECT(!reftable_log_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
170 in[1].update_index = in[0].update_index;
171 EXPECT(reftable_log_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ));
172 reftable_log_record_release(&in[0]);
173 reftable_log_record_release(&in[1]);
174 }
175
176 static void test_reftable_log_record_roundtrip(void)
177 {
178 int i;
179 struct reftable_log_record in[2] = {
180 {
181 .refname = xstrdup("refs/heads/master"),
182 .update_index = 42,
183 .value_type = REFTABLE_LOG_UPDATE,
184 .value = {
185 .update = {
186 .old_hash = reftable_malloc(GIT_SHA1_RAWSZ),
187 .new_hash = reftable_malloc(GIT_SHA1_RAWSZ),
188 .name = xstrdup("han-wen"),
189 .email = xstrdup("hanwen@google.com"),
190 .message = xstrdup("test"),
191 .time = 1577123507,
192 .tz_offset = 100,
193 },
194 }
195 },
196 {
197 .refname = xstrdup("refs/heads/master"),
198 .update_index = 22,
199 .value_type = REFTABLE_LOG_DELETION,
200 }
201 };
202 set_test_hash(in[0].value.update.new_hash, 1);
203 set_test_hash(in[0].value.update.old_hash, 2);
204 for (i = 0; i < ARRAY_SIZE(in); i++) {
205 struct reftable_record rec = { NULL };
206 struct strbuf key = STRBUF_INIT;
207 uint8_t buffer[1024] = { 0 };
208 struct string_view dest = {
209 .buf = buffer,
210 .len = sizeof(buffer),
211 };
212 /* populate out, to check for leaks. */
213 struct reftable_log_record out = {
214 .refname = xstrdup("old name"),
215 .value_type = REFTABLE_LOG_UPDATE,
216 .value = {
217 .update = {
218 .new_hash = reftable_calloc(GIT_SHA1_RAWSZ),
219 .old_hash = reftable_calloc(GIT_SHA1_RAWSZ),
220 .name = xstrdup("old name"),
221 .email = xstrdup("old@email"),
222 .message = xstrdup("old message"),
223 },
224 },
225 };
226 struct reftable_record rec_out = { NULL };
227 int n, m, valtype;
228
229 reftable_record_from_log(&rec, &in[i]);
230
231 test_copy(&rec);
232
233 reftable_record_key(&rec, &key);
234
235 n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
236 EXPECT(n >= 0);
237 reftable_record_from_log(&rec_out, &out);
238 valtype = reftable_record_val_type(&rec);
239 m = reftable_record_decode(&rec_out, key, valtype, dest,
240 GIT_SHA1_RAWSZ);
241 EXPECT(n == m);
242
243 EXPECT(reftable_log_record_equal(&in[i], &out, GIT_SHA1_RAWSZ));
244 reftable_log_record_release(&in[i]);
245 strbuf_release(&key);
246 reftable_record_release(&rec_out);
247 }
248 }
249
250 static void test_u24_roundtrip(void)
251 {
252 uint32_t in = 0x112233;
253 uint8_t dest[3];
254 uint32_t out;
255 put_be24(dest, in);
256 out = get_be24(dest);
257 EXPECT(in == out);
258 }
259
260 static void test_key_roundtrip(void)
261 {
262 uint8_t buffer[1024] = { 0 };
263 struct string_view dest = {
264 .buf = buffer,
265 .len = sizeof(buffer),
266 };
267 struct strbuf last_key = STRBUF_INIT;
268 struct strbuf key = STRBUF_INIT;
269 struct strbuf roundtrip = STRBUF_INIT;
270 int restart;
271 uint8_t extra;
272 int n, m;
273 uint8_t rt_extra;
274
275 strbuf_addstr(&last_key, "refs/heads/master");
276 strbuf_addstr(&key, "refs/tags/bla");
277 extra = 6;
278 n = reftable_encode_key(&restart, dest, last_key, key, extra);
279 EXPECT(!restart);
280 EXPECT(n > 0);
281
282 m = reftable_decode_key(&roundtrip, &rt_extra, last_key, dest);
283 EXPECT(n == m);
284 EXPECT(0 == strbuf_cmp(&key, &roundtrip));
285 EXPECT(rt_extra == extra);
286
287 strbuf_release(&last_key);
288 strbuf_release(&key);
289 strbuf_release(&roundtrip);
290 }
291
292 static void test_reftable_obj_record_roundtrip(void)
293 {
294 uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 };
295 uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 };
296 struct reftable_obj_record recs[3] = { {
297 .hash_prefix = testHash1,
298 .hash_prefix_len = 5,
299 .offsets = till9,
300 .offset_len = 3,
301 },
302 {
303 .hash_prefix = testHash1,
304 .hash_prefix_len = 5,
305 .offsets = till9,
306 .offset_len = 9,
307 },
308 {
309 .hash_prefix = testHash1,
310 .hash_prefix_len = 5,
311 } };
312 int i = 0;
313 for (i = 0; i < ARRAY_SIZE(recs); i++) {
314 struct reftable_obj_record in = recs[i];
315 uint8_t buffer[1024] = { 0 };
316 struct string_view dest = {
317 .buf = buffer,
318 .len = sizeof(buffer),
319 };
320 struct reftable_record rec = { NULL };
321 struct strbuf key = STRBUF_INIT;
322 struct reftable_obj_record out = { NULL };
323 struct reftable_record rec_out = { NULL };
324 int n, m;
325 uint8_t extra;
326
327 reftable_record_from_obj(&rec, &in);
328 test_copy(&rec);
329 reftable_record_key(&rec, &key);
330 n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
331 EXPECT(n > 0);
332 extra = reftable_record_val_type(&rec);
333 reftable_record_from_obj(&rec_out, &out);
334 m = reftable_record_decode(&rec_out, key, extra, dest,
335 GIT_SHA1_RAWSZ);
336 EXPECT(n == m);
337
338 EXPECT(reftable_record_equal(&rec, &rec_out, GIT_SHA1_RAWSZ));
339 strbuf_release(&key);
340 reftable_record_release(&rec_out);
341 }
342 }
343
344 static void test_reftable_index_record_roundtrip(void)
345 {
346 struct reftable_index_record in = {
347 .offset = 42,
348 .last_key = STRBUF_INIT,
349 };
350 uint8_t buffer[1024] = { 0 };
351 struct string_view dest = {
352 .buf = buffer,
353 .len = sizeof(buffer),
354 };
355 struct strbuf key = STRBUF_INIT;
356 struct reftable_record rec = { NULL };
357 struct reftable_index_record out = { .last_key = STRBUF_INIT };
358 struct reftable_record out_rec = { NULL };
359 int n, m;
360 uint8_t extra;
361
362 strbuf_addstr(&in.last_key, "refs/heads/master");
363 reftable_record_from_index(&rec, &in);
364 reftable_record_key(&rec, &key);
365 test_copy(&rec);
366
367 EXPECT(0 == strbuf_cmp(&key, &in.last_key));
368 n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ);
369 EXPECT(n > 0);
370
371 extra = reftable_record_val_type(&rec);
372 reftable_record_from_index(&out_rec, &out);
373 m = reftable_record_decode(&out_rec, key, extra, dest, GIT_SHA1_RAWSZ);
374 EXPECT(m == n);
375
376 EXPECT(reftable_record_equal(&rec, &out_rec, GIT_SHA1_RAWSZ));
377
378 reftable_record_release(&out_rec);
379 strbuf_release(&key);
380 strbuf_release(&in.last_key);
381 }
382
383 int record_test_main(int argc, const char *argv[])
384 {
385 RUN_TEST(test_reftable_log_record_equal);
386 RUN_TEST(test_reftable_log_record_roundtrip);
387 RUN_TEST(test_reftable_ref_record_roundtrip);
388 RUN_TEST(test_varint_roundtrip);
389 RUN_TEST(test_key_roundtrip);
390 RUN_TEST(test_common_prefix);
391 RUN_TEST(test_reftable_obj_record_roundtrip);
392 RUN_TEST(test_reftable_index_record_roundtrip);
393 RUN_TEST(test_u24_roundtrip);
394 return 0;
395 }