]>
Commit | Line | Data |
---|---|---|
e303bf22 HWN |
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 | { | |
3ddef475 | 19 | struct reftable_record copy; |
66c0daba HWN |
20 | uint8_t typ; |
21 | ||
22 | typ = reftable_record_type(rec); | |
3ddef475 | 23 | reftable_record_init(©, typ); |
e303bf22 HWN |
24 | reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ); |
25 | /* do it twice to catch memory leaks */ | |
26 | reftable_record_copy_from(©, rec, GIT_SHA1_RAWSZ); | |
c9833740 | 27 | EXPECT(reftable_record_equal(rec, ©, GIT_SHA1_RAWSZ)); |
01033de4 HWN |
28 | |
29 | puts("testing print coverage:\n"); | |
30 | reftable_record_print(©, GIT_SHA1_RAWSZ); | |
31 | ||
66c0daba | 32 | reftable_record_release(©); |
e303bf22 HWN |
33 | } |
34 | ||
35 | static void test_varint_roundtrip(void) | |
36 | { | |
37 | uint64_t inputs[] = { 0, | |
38 | 1, | |
39 | 27, | |
40 | 127, | |
41 | 128, | |
42 | 257, | |
43 | 4096, | |
44 | ((uint64_t)1 << 63), | |
45 | ((uint64_t)1 << 63) + ((uint64_t)1 << 63) - 1 }; | |
46 | int i = 0; | |
47 | for (i = 0; i < ARRAY_SIZE(inputs); i++) { | |
48 | uint8_t dest[10]; | |
49 | ||
50 | struct string_view out = { | |
51 | .buf = dest, | |
52 | .len = sizeof(dest), | |
53 | }; | |
54 | uint64_t in = inputs[i]; | |
55 | int n = put_var_int(&out, in); | |
56 | uint64_t got = 0; | |
57 | ||
58 | EXPECT(n > 0); | |
59 | out.len = n; | |
60 | n = get_var_int(&got, &out); | |
61 | EXPECT(n > 0); | |
62 | ||
63 | EXPECT(got == in); | |
64 | } | |
65 | } | |
66 | ||
67 | static void test_common_prefix(void) | |
68 | { | |
69 | struct { | |
70 | const char *a, *b; | |
71 | int want; | |
72 | } cases[] = { | |
73 | { "abc", "ab", 2 }, | |
74 | { "", "abc", 0 }, | |
75 | { "abc", "abd", 2 }, | |
76 | { "abc", "pqr", 0 }, | |
77 | }; | |
78 | ||
79 | int i = 0; | |
80 | for (i = 0; i < ARRAY_SIZE(cases); i++) { | |
81 | struct strbuf a = STRBUF_INIT; | |
82 | struct strbuf b = STRBUF_INIT; | |
83 | strbuf_addstr(&a, cases[i].a); | |
84 | strbuf_addstr(&b, cases[i].b); | |
85 | EXPECT(common_prefix_size(&a, &b) == cases[i].want); | |
86 | ||
87 | strbuf_release(&a); | |
88 | strbuf_release(&b); | |
89 | } | |
90 | } | |
91 | ||
92 | static void set_hash(uint8_t *h, int j) | |
93 | { | |
94 | int i = 0; | |
95 | for (i = 0; i < hash_size(GIT_SHA1_FORMAT_ID); i++) { | |
96 | h[i] = (j >> i) & 0xff; | |
97 | } | |
98 | } | |
99 | ||
100 | static void test_reftable_ref_record_roundtrip(void) | |
101 | { | |
7b8abc4d | 102 | struct strbuf scratch = STRBUF_INIT; |
e303bf22 HWN |
103 | int i = 0; |
104 | ||
105 | for (i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) { | |
66c0daba HWN |
106 | struct reftable_record in = { |
107 | .type = BLOCK_TYPE_REF, | |
108 | }; | |
109 | struct reftable_record out = { .type = BLOCK_TYPE_REF }; | |
e303bf22 | 110 | struct strbuf key = STRBUF_INIT; |
e303bf22 HWN |
111 | uint8_t buffer[1024] = { 0 }; |
112 | struct string_view dest = { | |
113 | .buf = buffer, | |
114 | .len = sizeof(buffer), | |
115 | }; | |
e303bf22 HWN |
116 | int n, m; |
117 | ||
66c0daba | 118 | in.u.ref.value_type = i; |
e303bf22 HWN |
119 | switch (i) { |
120 | case REFTABLE_REF_DELETION: | |
121 | break; | |
122 | case REFTABLE_REF_VAL1: | |
66c0daba | 123 | set_hash(in.u.ref.value.val1, 1); |
e303bf22 HWN |
124 | break; |
125 | case REFTABLE_REF_VAL2: | |
66c0daba | 126 | set_hash(in.u.ref.value.val2.value, 1); |
66c0daba | 127 | set_hash(in.u.ref.value.val2.target_value, 2); |
e303bf22 HWN |
128 | break; |
129 | case REFTABLE_REF_SYMREF: | |
66c0daba | 130 | in.u.ref.value.symref = xstrdup("target"); |
e303bf22 HWN |
131 | break; |
132 | } | |
66c0daba | 133 | in.u.ref.refname = xstrdup("refs/heads/master"); |
e303bf22 | 134 | |
66c0daba | 135 | test_copy(&in); |
e303bf22 | 136 | |
66c0daba | 137 | EXPECT(reftable_record_val_type(&in) == i); |
e303bf22 | 138 | |
66c0daba HWN |
139 | reftable_record_key(&in, &key); |
140 | n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); | |
e303bf22 HWN |
141 | EXPECT(n > 0); |
142 | ||
143 | /* decode into a non-zero reftable_record to test for leaks. */ | |
7b8abc4d | 144 | m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ, &scratch); |
e303bf22 HWN |
145 | EXPECT(n == m); |
146 | ||
66c0daba HWN |
147 | EXPECT(reftable_ref_record_equal(&in.u.ref, &out.u.ref, |
148 | GIT_SHA1_RAWSZ)); | |
149 | reftable_record_release(&in); | |
e303bf22 HWN |
150 | |
151 | strbuf_release(&key); | |
66c0daba | 152 | reftable_record_release(&out); |
e303bf22 | 153 | } |
7b8abc4d PS |
154 | |
155 | strbuf_release(&scratch); | |
e303bf22 HWN |
156 | } |
157 | ||
158 | static void test_reftable_log_record_equal(void) | |
159 | { | |
160 | struct reftable_log_record in[2] = { | |
161 | { | |
162 | .refname = xstrdup("refs/heads/master"), | |
163 | .update_index = 42, | |
164 | }, | |
165 | { | |
166 | .refname = xstrdup("refs/heads/master"), | |
167 | .update_index = 22, | |
168 | } | |
169 | }; | |
170 | ||
171 | EXPECT(!reftable_log_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); | |
172 | in[1].update_index = in[0].update_index; | |
173 | EXPECT(reftable_log_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); | |
174 | reftable_log_record_release(&in[0]); | |
175 | reftable_log_record_release(&in[1]); | |
176 | } | |
177 | ||
178 | static void test_reftable_log_record_roundtrip(void) | |
179 | { | |
180 | int i; | |
01033de4 | 181 | struct reftable_log_record in[] = { |
e303bf22 HWN |
182 | { |
183 | .refname = xstrdup("refs/heads/master"), | |
184 | .update_index = 42, | |
185 | .value_type = REFTABLE_LOG_UPDATE, | |
186 | .value = { | |
187 | .update = { | |
e303bf22 HWN |
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, | |
01033de4 HWN |
200 | }, |
201 | { | |
202 | .refname = xstrdup("branch"), | |
203 | .update_index = 33, | |
204 | .value_type = REFTABLE_LOG_UPDATE, | |
e303bf22 HWN |
205 | } |
206 | }; | |
7b8abc4d PS |
207 | struct strbuf scratch = STRBUF_INIT; |
208 | ||
e303bf22 HWN |
209 | set_test_hash(in[0].value.update.new_hash, 1); |
210 | set_test_hash(in[0].value.update.old_hash, 2); | |
01033de4 HWN |
211 | set_test_hash(in[2].value.update.new_hash, 3); |
212 | set_test_hash(in[2].value.update.old_hash, 4); | |
e303bf22 | 213 | for (i = 0; i < ARRAY_SIZE(in); i++) { |
66c0daba | 214 | struct reftable_record rec = { .type = BLOCK_TYPE_LOG }; |
e303bf22 HWN |
215 | struct strbuf key = STRBUF_INIT; |
216 | uint8_t buffer[1024] = { 0 }; | |
217 | struct string_view dest = { | |
218 | .buf = buffer, | |
219 | .len = sizeof(buffer), | |
220 | }; | |
221 | /* populate out, to check for leaks. */ | |
66c0daba HWN |
222 | struct reftable_record out = { |
223 | .type = BLOCK_TYPE_LOG, | |
224 | .u.log = { | |
225 | .refname = xstrdup("old name"), | |
226 | .value_type = REFTABLE_LOG_UPDATE, | |
227 | .value = { | |
228 | .update = { | |
66c0daba HWN |
229 | .name = xstrdup("old name"), |
230 | .email = xstrdup("old@email"), | |
231 | .message = xstrdup("old message"), | |
232 | }, | |
e303bf22 HWN |
233 | }, |
234 | }, | |
235 | }; | |
e303bf22 HWN |
236 | int n, m, valtype; |
237 | ||
66c0daba | 238 | rec.u.log = in[i]; |
e303bf22 HWN |
239 | |
240 | test_copy(&rec); | |
241 | ||
242 | reftable_record_key(&rec, &key); | |
243 | ||
244 | n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ); | |
245 | EXPECT(n >= 0); | |
e303bf22 | 246 | valtype = reftable_record_val_type(&rec); |
66c0daba | 247 | m = reftable_record_decode(&out, key, valtype, dest, |
7b8abc4d | 248 | GIT_SHA1_RAWSZ, &scratch); |
e303bf22 HWN |
249 | EXPECT(n == m); |
250 | ||
66c0daba HWN |
251 | EXPECT(reftable_log_record_equal(&in[i], &out.u.log, |
252 | GIT_SHA1_RAWSZ)); | |
e303bf22 HWN |
253 | reftable_log_record_release(&in[i]); |
254 | strbuf_release(&key); | |
66c0daba | 255 | reftable_record_release(&out); |
e303bf22 | 256 | } |
7b8abc4d PS |
257 | |
258 | strbuf_release(&scratch); | |
e303bf22 HWN |
259 | } |
260 | ||
261 | static void test_u24_roundtrip(void) | |
262 | { | |
263 | uint32_t in = 0x112233; | |
264 | uint8_t dest[3]; | |
265 | uint32_t out; | |
266 | put_be24(dest, in); | |
267 | out = get_be24(dest); | |
268 | EXPECT(in == out); | |
269 | } | |
270 | ||
271 | static void test_key_roundtrip(void) | |
272 | { | |
273 | uint8_t buffer[1024] = { 0 }; | |
274 | struct string_view dest = { | |
275 | .buf = buffer, | |
276 | .len = sizeof(buffer), | |
277 | }; | |
278 | struct strbuf last_key = STRBUF_INIT; | |
279 | struct strbuf key = STRBUF_INIT; | |
280 | struct strbuf roundtrip = STRBUF_INIT; | |
281 | int restart; | |
282 | uint8_t extra; | |
283 | int n, m; | |
284 | uint8_t rt_extra; | |
285 | ||
286 | strbuf_addstr(&last_key, "refs/heads/master"); | |
287 | strbuf_addstr(&key, "refs/tags/bla"); | |
288 | extra = 6; | |
289 | n = reftable_encode_key(&restart, dest, last_key, key, extra); | |
290 | EXPECT(!restart); | |
291 | EXPECT(n > 0); | |
292 | ||
daf4f43d PS |
293 | strbuf_addstr(&roundtrip, "refs/heads/master"); |
294 | m = reftable_decode_key(&roundtrip, &rt_extra, dest); | |
e303bf22 HWN |
295 | EXPECT(n == m); |
296 | EXPECT(0 == strbuf_cmp(&key, &roundtrip)); | |
297 | EXPECT(rt_extra == extra); | |
298 | ||
299 | strbuf_release(&last_key); | |
300 | strbuf_release(&key); | |
301 | strbuf_release(&roundtrip); | |
302 | } | |
303 | ||
304 | static void test_reftable_obj_record_roundtrip(void) | |
305 | { | |
306 | uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 }; | |
307 | uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 }; | |
7b8abc4d PS |
308 | struct reftable_obj_record recs[3] = { |
309 | { | |
310 | .hash_prefix = testHash1, | |
311 | .hash_prefix_len = 5, | |
312 | .offsets = till9, | |
313 | .offset_len = 3, | |
314 | }, | |
315 | { | |
316 | .hash_prefix = testHash1, | |
317 | .hash_prefix_len = 5, | |
318 | .offsets = till9, | |
319 | .offset_len = 9, | |
320 | }, | |
321 | { | |
322 | .hash_prefix = testHash1, | |
323 | .hash_prefix_len = 5, | |
324 | }, | |
325 | }; | |
326 | struct strbuf scratch = STRBUF_INIT; | |
e303bf22 | 327 | int i = 0; |
7b8abc4d | 328 | |
e303bf22 | 329 | for (i = 0; i < ARRAY_SIZE(recs); i++) { |
e303bf22 HWN |
330 | uint8_t buffer[1024] = { 0 }; |
331 | struct string_view dest = { | |
332 | .buf = buffer, | |
333 | .len = sizeof(buffer), | |
334 | }; | |
66c0daba HWN |
335 | struct reftable_record in = { |
336 | .type = BLOCK_TYPE_OBJ, | |
33665d98 ÆAB |
337 | .u = { |
338 | .obj = recs[i], | |
339 | }, | |
66c0daba | 340 | }; |
e303bf22 | 341 | struct strbuf key = STRBUF_INIT; |
66c0daba | 342 | struct reftable_record out = { .type = BLOCK_TYPE_OBJ }; |
e303bf22 HWN |
343 | int n, m; |
344 | uint8_t extra; | |
345 | ||
66c0daba HWN |
346 | test_copy(&in); |
347 | reftable_record_key(&in, &key); | |
348 | n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); | |
e303bf22 | 349 | EXPECT(n > 0); |
66c0daba HWN |
350 | extra = reftable_record_val_type(&in); |
351 | m = reftable_record_decode(&out, key, extra, dest, | |
7b8abc4d | 352 | GIT_SHA1_RAWSZ, &scratch); |
e303bf22 HWN |
353 | EXPECT(n == m); |
354 | ||
66c0daba | 355 | EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); |
e303bf22 | 356 | strbuf_release(&key); |
66c0daba | 357 | reftable_record_release(&out); |
e303bf22 | 358 | } |
7b8abc4d PS |
359 | |
360 | strbuf_release(&scratch); | |
e303bf22 HWN |
361 | } |
362 | ||
363 | static void test_reftable_index_record_roundtrip(void) | |
364 | { | |
66c0daba HWN |
365 | struct reftable_record in = { |
366 | .type = BLOCK_TYPE_INDEX, | |
367 | .u.idx = { | |
368 | .offset = 42, | |
369 | .last_key = STRBUF_INIT, | |
370 | }, | |
e303bf22 HWN |
371 | }; |
372 | uint8_t buffer[1024] = { 0 }; | |
373 | struct string_view dest = { | |
374 | .buf = buffer, | |
375 | .len = sizeof(buffer), | |
376 | }; | |
7b8abc4d | 377 | struct strbuf scratch = STRBUF_INIT; |
e303bf22 | 378 | struct strbuf key = STRBUF_INIT; |
66c0daba HWN |
379 | struct reftable_record out = { |
380 | .type = BLOCK_TYPE_INDEX, | |
381 | .u.idx = { .last_key = STRBUF_INIT }, | |
382 | }; | |
e303bf22 HWN |
383 | int n, m; |
384 | uint8_t extra; | |
385 | ||
66c0daba HWN |
386 | strbuf_addstr(&in.u.idx.last_key, "refs/heads/master"); |
387 | reftable_record_key(&in, &key); | |
388 | test_copy(&in); | |
e303bf22 | 389 | |
66c0daba HWN |
390 | EXPECT(0 == strbuf_cmp(&key, &in.u.idx.last_key)); |
391 | n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); | |
e303bf22 HWN |
392 | EXPECT(n > 0); |
393 | ||
66c0daba | 394 | extra = reftable_record_val_type(&in); |
7b8abc4d PS |
395 | m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ, |
396 | &scratch); | |
e303bf22 HWN |
397 | EXPECT(m == n); |
398 | ||
66c0daba | 399 | EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); |
e303bf22 | 400 | |
66c0daba | 401 | reftable_record_release(&out); |
e303bf22 | 402 | strbuf_release(&key); |
7b8abc4d | 403 | strbuf_release(&scratch); |
66c0daba | 404 | strbuf_release(&in.u.idx.last_key); |
e303bf22 HWN |
405 | } |
406 | ||
407 | int record_test_main(int argc, const char *argv[]) | |
408 | { | |
409 | RUN_TEST(test_reftable_log_record_equal); | |
410 | RUN_TEST(test_reftable_log_record_roundtrip); | |
411 | RUN_TEST(test_reftable_ref_record_roundtrip); | |
412 | RUN_TEST(test_varint_roundtrip); | |
413 | RUN_TEST(test_key_roundtrip); | |
414 | RUN_TEST(test_common_prefix); | |
415 | RUN_TEST(test_reftable_obj_record_roundtrip); | |
416 | RUN_TEST(test_reftable_index_record_roundtrip); | |
417 | RUN_TEST(test_u24_roundtrip); | |
418 | return 0; | |
419 | } |