]>
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 | { | |
102 | int i = 0; | |
103 | ||
104 | for (i = REFTABLE_REF_DELETION; i < REFTABLE_NR_REF_VALUETYPES; i++) { | |
66c0daba HWN |
105 | struct reftable_record in = { |
106 | .type = BLOCK_TYPE_REF, | |
107 | }; | |
108 | struct reftable_record out = { .type = BLOCK_TYPE_REF }; | |
e303bf22 | 109 | struct strbuf key = STRBUF_INIT; |
e303bf22 HWN |
110 | uint8_t buffer[1024] = { 0 }; |
111 | struct string_view dest = { | |
112 | .buf = buffer, | |
113 | .len = sizeof(buffer), | |
114 | }; | |
e303bf22 HWN |
115 | int n, m; |
116 | ||
66c0daba | 117 | in.u.ref.value_type = i; |
e303bf22 HWN |
118 | switch (i) { |
119 | case REFTABLE_REF_DELETION: | |
120 | break; | |
121 | case REFTABLE_REF_VAL1: | |
66c0daba | 122 | set_hash(in.u.ref.value.val1, 1); |
e303bf22 HWN |
123 | break; |
124 | case REFTABLE_REF_VAL2: | |
66c0daba | 125 | set_hash(in.u.ref.value.val2.value, 1); |
66c0daba | 126 | set_hash(in.u.ref.value.val2.target_value, 2); |
e303bf22 HWN |
127 | break; |
128 | case REFTABLE_REF_SYMREF: | |
66c0daba | 129 | in.u.ref.value.symref = xstrdup("target"); |
e303bf22 HWN |
130 | break; |
131 | } | |
66c0daba | 132 | in.u.ref.refname = xstrdup("refs/heads/master"); |
e303bf22 | 133 | |
66c0daba | 134 | test_copy(&in); |
e303bf22 | 135 | |
66c0daba | 136 | EXPECT(reftable_record_val_type(&in) == i); |
e303bf22 | 137 | |
66c0daba HWN |
138 | reftable_record_key(&in, &key); |
139 | n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); | |
e303bf22 HWN |
140 | EXPECT(n > 0); |
141 | ||
142 | /* decode into a non-zero reftable_record to test for leaks. */ | |
66c0daba | 143 | m = reftable_record_decode(&out, key, i, dest, GIT_SHA1_RAWSZ); |
e303bf22 HWN |
144 | EXPECT(n == m); |
145 | ||
66c0daba HWN |
146 | EXPECT(reftable_ref_record_equal(&in.u.ref, &out.u.ref, |
147 | GIT_SHA1_RAWSZ)); | |
148 | reftable_record_release(&in); | |
e303bf22 HWN |
149 | |
150 | strbuf_release(&key); | |
66c0daba | 151 | reftable_record_release(&out); |
e303bf22 HWN |
152 | } |
153 | } | |
154 | ||
155 | static void test_reftable_log_record_equal(void) | |
156 | { | |
157 | struct reftable_log_record in[2] = { | |
158 | { | |
159 | .refname = xstrdup("refs/heads/master"), | |
160 | .update_index = 42, | |
161 | }, | |
162 | { | |
163 | .refname = xstrdup("refs/heads/master"), | |
164 | .update_index = 22, | |
165 | } | |
166 | }; | |
167 | ||
168 | EXPECT(!reftable_log_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); | |
169 | in[1].update_index = in[0].update_index; | |
170 | EXPECT(reftable_log_record_equal(&in[0], &in[1], GIT_SHA1_RAWSZ)); | |
171 | reftable_log_record_release(&in[0]); | |
172 | reftable_log_record_release(&in[1]); | |
173 | } | |
174 | ||
175 | static void test_reftable_log_record_roundtrip(void) | |
176 | { | |
177 | int i; | |
01033de4 HWN |
178 | |
179 | struct reftable_log_record in[] = { | |
e303bf22 HWN |
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, | |
01033de4 HWN |
200 | }, |
201 | { | |
202 | .refname = xstrdup("branch"), | |
203 | .update_index = 33, | |
204 | .value_type = REFTABLE_LOG_UPDATE, | |
205 | .value = { | |
206 | .update = { | |
207 | .old_hash = reftable_malloc(GIT_SHA1_RAWSZ), | |
208 | .new_hash = reftable_malloc(GIT_SHA1_RAWSZ), | |
209 | /* rest of fields left empty. */ | |
210 | }, | |
211 | }, | |
e303bf22 HWN |
212 | } |
213 | }; | |
214 | set_test_hash(in[0].value.update.new_hash, 1); | |
215 | set_test_hash(in[0].value.update.old_hash, 2); | |
01033de4 HWN |
216 | set_test_hash(in[2].value.update.new_hash, 3); |
217 | set_test_hash(in[2].value.update.old_hash, 4); | |
e303bf22 | 218 | for (i = 0; i < ARRAY_SIZE(in); i++) { |
66c0daba | 219 | struct reftable_record rec = { .type = BLOCK_TYPE_LOG }; |
e303bf22 HWN |
220 | struct strbuf key = STRBUF_INIT; |
221 | uint8_t buffer[1024] = { 0 }; | |
222 | struct string_view dest = { | |
223 | .buf = buffer, | |
224 | .len = sizeof(buffer), | |
225 | }; | |
226 | /* populate out, to check for leaks. */ | |
66c0daba HWN |
227 | struct reftable_record out = { |
228 | .type = BLOCK_TYPE_LOG, | |
229 | .u.log = { | |
230 | .refname = xstrdup("old name"), | |
231 | .value_type = REFTABLE_LOG_UPDATE, | |
232 | .value = { | |
233 | .update = { | |
b4ff12c8 PS |
234 | .new_hash = reftable_calloc(GIT_SHA1_RAWSZ, 1), |
235 | .old_hash = reftable_calloc(GIT_SHA1_RAWSZ, 1), | |
66c0daba HWN |
236 | .name = xstrdup("old name"), |
237 | .email = xstrdup("old@email"), | |
238 | .message = xstrdup("old message"), | |
239 | }, | |
e303bf22 HWN |
240 | }, |
241 | }, | |
242 | }; | |
e303bf22 HWN |
243 | int n, m, valtype; |
244 | ||
66c0daba | 245 | rec.u.log = in[i]; |
e303bf22 HWN |
246 | |
247 | test_copy(&rec); | |
248 | ||
249 | reftable_record_key(&rec, &key); | |
250 | ||
251 | n = reftable_record_encode(&rec, dest, GIT_SHA1_RAWSZ); | |
252 | EXPECT(n >= 0); | |
e303bf22 | 253 | valtype = reftable_record_val_type(&rec); |
66c0daba | 254 | m = reftable_record_decode(&out, key, valtype, dest, |
e303bf22 HWN |
255 | GIT_SHA1_RAWSZ); |
256 | EXPECT(n == m); | |
257 | ||
66c0daba HWN |
258 | EXPECT(reftable_log_record_equal(&in[i], &out.u.log, |
259 | GIT_SHA1_RAWSZ)); | |
e303bf22 HWN |
260 | reftable_log_record_release(&in[i]); |
261 | strbuf_release(&key); | |
66c0daba | 262 | reftable_record_release(&out); |
e303bf22 HWN |
263 | } |
264 | } | |
265 | ||
266 | static void test_u24_roundtrip(void) | |
267 | { | |
268 | uint32_t in = 0x112233; | |
269 | uint8_t dest[3]; | |
270 | uint32_t out; | |
271 | put_be24(dest, in); | |
272 | out = get_be24(dest); | |
273 | EXPECT(in == out); | |
274 | } | |
275 | ||
276 | static void test_key_roundtrip(void) | |
277 | { | |
278 | uint8_t buffer[1024] = { 0 }; | |
279 | struct string_view dest = { | |
280 | .buf = buffer, | |
281 | .len = sizeof(buffer), | |
282 | }; | |
283 | struct strbuf last_key = STRBUF_INIT; | |
284 | struct strbuf key = STRBUF_INIT; | |
285 | struct strbuf roundtrip = STRBUF_INIT; | |
286 | int restart; | |
287 | uint8_t extra; | |
288 | int n, m; | |
289 | uint8_t rt_extra; | |
290 | ||
291 | strbuf_addstr(&last_key, "refs/heads/master"); | |
292 | strbuf_addstr(&key, "refs/tags/bla"); | |
293 | extra = 6; | |
294 | n = reftable_encode_key(&restart, dest, last_key, key, extra); | |
295 | EXPECT(!restart); | |
296 | EXPECT(n > 0); | |
297 | ||
298 | m = reftable_decode_key(&roundtrip, &rt_extra, last_key, dest); | |
299 | EXPECT(n == m); | |
300 | EXPECT(0 == strbuf_cmp(&key, &roundtrip)); | |
301 | EXPECT(rt_extra == extra); | |
302 | ||
303 | strbuf_release(&last_key); | |
304 | strbuf_release(&key); | |
305 | strbuf_release(&roundtrip); | |
306 | } | |
307 | ||
308 | static void test_reftable_obj_record_roundtrip(void) | |
309 | { | |
310 | uint8_t testHash1[GIT_SHA1_RAWSZ] = { 1, 2, 3, 4, 0 }; | |
311 | uint64_t till9[] = { 1, 2, 3, 4, 500, 600, 700, 800, 9000 }; | |
312 | struct reftable_obj_record recs[3] = { { | |
313 | .hash_prefix = testHash1, | |
314 | .hash_prefix_len = 5, | |
315 | .offsets = till9, | |
316 | .offset_len = 3, | |
317 | }, | |
318 | { | |
319 | .hash_prefix = testHash1, | |
320 | .hash_prefix_len = 5, | |
321 | .offsets = till9, | |
322 | .offset_len = 9, | |
323 | }, | |
324 | { | |
325 | .hash_prefix = testHash1, | |
326 | .hash_prefix_len = 5, | |
327 | } }; | |
328 | int i = 0; | |
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, | |
e303bf22 HWN |
352 | GIT_SHA1_RAWSZ); |
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 HWN |
358 | } |
359 | } | |
360 | ||
361 | static void test_reftable_index_record_roundtrip(void) | |
362 | { | |
66c0daba HWN |
363 | struct reftable_record in = { |
364 | .type = BLOCK_TYPE_INDEX, | |
365 | .u.idx = { | |
366 | .offset = 42, | |
367 | .last_key = STRBUF_INIT, | |
368 | }, | |
e303bf22 HWN |
369 | }; |
370 | uint8_t buffer[1024] = { 0 }; | |
371 | struct string_view dest = { | |
372 | .buf = buffer, | |
373 | .len = sizeof(buffer), | |
374 | }; | |
375 | struct strbuf key = STRBUF_INIT; | |
66c0daba HWN |
376 | struct reftable_record out = { |
377 | .type = BLOCK_TYPE_INDEX, | |
378 | .u.idx = { .last_key = STRBUF_INIT }, | |
379 | }; | |
e303bf22 HWN |
380 | int n, m; |
381 | uint8_t extra; | |
382 | ||
66c0daba HWN |
383 | strbuf_addstr(&in.u.idx.last_key, "refs/heads/master"); |
384 | reftable_record_key(&in, &key); | |
385 | test_copy(&in); | |
e303bf22 | 386 | |
66c0daba HWN |
387 | EXPECT(0 == strbuf_cmp(&key, &in.u.idx.last_key)); |
388 | n = reftable_record_encode(&in, dest, GIT_SHA1_RAWSZ); | |
e303bf22 HWN |
389 | EXPECT(n > 0); |
390 | ||
66c0daba HWN |
391 | extra = reftable_record_val_type(&in); |
392 | m = reftable_record_decode(&out, key, extra, dest, GIT_SHA1_RAWSZ); | |
e303bf22 HWN |
393 | EXPECT(m == n); |
394 | ||
66c0daba | 395 | EXPECT(reftable_record_equal(&in, &out, GIT_SHA1_RAWSZ)); |
e303bf22 | 396 | |
66c0daba | 397 | reftable_record_release(&out); |
e303bf22 | 398 | strbuf_release(&key); |
66c0daba | 399 | strbuf_release(&in.u.idx.last_key); |
e303bf22 HWN |
400 | } |
401 | ||
402 | int record_test_main(int argc, const char *argv[]) | |
403 | { | |
404 | RUN_TEST(test_reftable_log_record_equal); | |
405 | RUN_TEST(test_reftable_log_record_roundtrip); | |
406 | RUN_TEST(test_reftable_ref_record_roundtrip); | |
407 | RUN_TEST(test_varint_roundtrip); | |
408 | RUN_TEST(test_key_roundtrip); | |
409 | RUN_TEST(test_common_prefix); | |
410 | RUN_TEST(test_reftable_obj_record_roundtrip); | |
411 | RUN_TEST(test_reftable_index_record_roundtrip); | |
412 | RUN_TEST(test_u24_roundtrip); | |
413 | return 0; | |
414 | } |