Blob


1 /*
2 * Copyright (c) 2021 Stefan Sperling <stsp@openbsd.org>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
17 #include <sys/queue.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <err.h>
23 #include <unistd.h>
24 #include <getopt.h>
26 #include "got_error.h"
27 #include "got_opentemp.h"
29 #include "got_lib_deltify.h"
31 #ifndef nitems
32 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
33 #endif
35 static int
36 deltify_abc_axc(void)
37 {
38 const struct got_error *err = NULL;
39 size_t i;
40 FILE *base_file, *derived_file, *result_file;
41 struct got_delta_table *dt;
42 struct got_delta_instruction *deltas;
43 int ndeltas;
44 int have_nblocks = 0;
45 uint32_t seed;
47 seed = arc4random();
49 base_file = got_opentemp();
50 if (base_file == NULL)
51 return 1;
53 derived_file = got_opentemp();
54 if (derived_file == NULL)
55 return 1;
57 result_file = got_opentemp();
58 if (result_file == NULL)
59 return 1;
61 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
62 fputc('a', base_file);
63 fputc('a', derived_file);
64 }
65 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
66 fputc('b', base_file);
67 fputc('x', derived_file);
68 }
69 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
70 fputc('c', base_file);
71 fputc('c', derived_file);
72 }
74 rewind(base_file);
75 rewind(derived_file);
77 err = got_deltify_init(&dt, base_file, 0, 3 * GOT_DELTIFY_MAXCHUNK,
78 seed);
79 if (err)
80 goto done;
82 for (i = 0; i < dt->nalloc; i++) {
83 if (dt->blocks[i].len > 0)
84 have_nblocks++;
85 }
86 if (have_nblocks != dt->nblocks) {
87 err = got_error(GOT_ERR_BAD_DELTA);
88 goto done;
89 }
91 err = got_deltify(&deltas, &ndeltas, derived_file, 0,
92 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_file, 0,
93 3 * GOT_DELTIFY_MAXCHUNK);
94 if (err)
95 goto done;
97 if (ndeltas != 3) {
98 err = got_error(GOT_ERR_BAD_DELTA);
99 goto done;
101 /* Copy 'aaaa...' from base file. */
102 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
103 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
104 err = got_error(GOT_ERR_BAD_DELTA);
105 goto done;
107 /* Copy 'xxxx...' from derived file. */
108 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
109 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
110 err = got_error(GOT_ERR_BAD_DELTA);
111 goto done;
113 /* Copy 'ccccc...' from base file. */
114 if (!(deltas[2].copy == 1 &&
115 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
116 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
117 err = got_error(GOT_ERR_BAD_DELTA);
118 goto done;
121 done:
122 got_deltify_free(dt);
123 fclose(base_file);
124 fclose(derived_file);
125 fclose(result_file);
126 return (err == NULL);
129 static int
130 deltify_abc_axc_file_mem(void)
132 const struct got_error *err = NULL;
133 size_t i;
134 uint8_t base_data[3 * GOT_DELTIFY_MAXCHUNK];
135 FILE *derived_file, *result_file;
136 struct got_delta_table *dt;
137 struct got_delta_instruction *deltas;
138 int ndeltas;
139 int have_nblocks = 0;
140 uint32_t seed;
142 seed = arc4random();
144 derived_file = got_opentemp();
145 if (derived_file == NULL)
146 return 1;
148 result_file = got_opentemp();
149 if (result_file == NULL)
150 return 1;
152 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
153 base_data[i] = 'a';
154 fputc('a', derived_file);
156 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
157 base_data[GOT_DELTIFY_MAXCHUNK + i] = 'b';
158 fputc('x', derived_file);
160 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
161 base_data[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
162 fputc('c', derived_file);
165 rewind(derived_file);
167 err = got_deltify_init_mem(&dt, base_data, 0, 3 * GOT_DELTIFY_MAXCHUNK,
168 seed);
169 if (err)
170 goto done;
172 for (i = 0; i < dt->nalloc; i++) {
173 if (dt->blocks[i].len > 0)
174 have_nblocks++;
176 if (have_nblocks != dt->nblocks) {
177 err = got_error(GOT_ERR_BAD_DELTA);
178 goto done;
181 err = got_deltify_file_mem(&deltas, &ndeltas, derived_file, 0,
182 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_data, 0,
183 3 * GOT_DELTIFY_MAXCHUNK);
184 if (err)
185 goto done;
187 if (ndeltas != 3) {
188 err = got_error(GOT_ERR_BAD_DELTA);
189 goto done;
191 /* Copy 'aaaa...' from base file. */
192 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
193 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
194 err = got_error(GOT_ERR_BAD_DELTA);
195 goto done;
197 /* Copy 'xxxx...' from derived file. */
198 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
199 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
200 err = got_error(GOT_ERR_BAD_DELTA);
201 goto done;
203 /* Copy 'ccccc...' from base file. */
204 if (!(deltas[2].copy == 1 &&
205 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
206 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
207 err = got_error(GOT_ERR_BAD_DELTA);
208 goto done;
211 done:
212 got_deltify_free(dt);
213 fclose(derived_file);
214 fclose(result_file);
215 return (err == NULL);
218 static int
219 deltify_abc_axc_mem_file(void)
221 const struct got_error *err = NULL;
222 size_t i;
223 FILE *base_file, *result_file;
224 uint8_t derived_file[3 * GOT_DELTIFY_MAXCHUNK];
225 struct got_delta_table *dt;
226 struct got_delta_instruction *deltas;
227 int ndeltas;
228 int have_nblocks = 0;
229 uint32_t seed;
231 seed = arc4random();
233 base_file = got_opentemp();
234 if (base_file == NULL)
235 return 1;
237 result_file = got_opentemp();
238 if (result_file == NULL)
239 return 1;
241 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
242 fputc('a', base_file);
243 derived_file[i] = 'a';
245 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
246 fputc('b', base_file);
247 derived_file[GOT_DELTIFY_MAXCHUNK + i] = 'x';
249 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
250 fputc('c', base_file);
251 derived_file[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
254 rewind(base_file);
256 err = got_deltify_init(&dt, base_file, 0, 3 * GOT_DELTIFY_MAXCHUNK,
257 seed);
258 if (err)
259 goto done;
261 for (i = 0; i < dt->nalloc; i++) {
262 if (dt->blocks[i].len > 0)
263 have_nblocks++;
265 if (have_nblocks != dt->nblocks) {
266 err = got_error(GOT_ERR_BAD_DELTA);
267 goto done;
270 err = got_deltify_mem_file(&deltas, &ndeltas, derived_file, 0,
271 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_file, 0,
272 3 * GOT_DELTIFY_MAXCHUNK);
273 if (err)
274 goto done;
276 if (ndeltas != 3) {
277 err = got_error(GOT_ERR_BAD_DELTA);
278 goto done;
280 /* Copy 'aaaa...' from base file. */
281 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
282 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
283 err = got_error(GOT_ERR_BAD_DELTA);
284 goto done;
286 /* Copy 'xxxx...' from derived file. */
287 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
288 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
289 err = got_error(GOT_ERR_BAD_DELTA);
290 goto done;
292 /* Copy 'ccccc...' from base file. */
293 if (!(deltas[2].copy == 1 &&
294 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
295 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
296 err = got_error(GOT_ERR_BAD_DELTA);
297 goto done;
300 done:
301 got_deltify_free(dt);
302 fclose(base_file);
303 fclose(result_file);
304 return (err == NULL);
307 static int
308 deltify_abc_axc_mem_mem(void)
310 const struct got_error *err = NULL;
311 size_t i;
312 FILE *result_file;
313 uint8_t base_file[3 * GOT_DELTIFY_MAXCHUNK];
314 uint8_t derived_file[3 * GOT_DELTIFY_MAXCHUNK];
315 struct got_delta_table *dt;
316 struct got_delta_instruction *deltas;
317 int ndeltas;
318 int have_nblocks = 0;
319 uint32_t seed;
321 seed = arc4random();
323 result_file = got_opentemp();
324 if (result_file == NULL)
325 return 1;
327 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
328 base_file[i] = 'a';
329 derived_file[i] = 'a';
331 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
332 base_file[GOT_DELTIFY_MAXCHUNK + i] = 'b';
333 derived_file[GOT_DELTIFY_MAXCHUNK + i] = 'x';
335 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
336 base_file[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
337 derived_file[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
340 err = got_deltify_init_mem(&dt, base_file, 0, 3 * GOT_DELTIFY_MAXCHUNK,
341 seed);
342 if (err)
343 goto done;
345 for (i = 0; i < dt->nalloc; i++) {
346 if (dt->blocks[i].len > 0)
347 have_nblocks++;
349 if (have_nblocks != dt->nblocks) {
350 err = got_error(GOT_ERR_BAD_DELTA);
351 goto done;
354 err = got_deltify_mem_mem(&deltas, &ndeltas, derived_file, 0,
355 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_file, 0,
356 3 * GOT_DELTIFY_MAXCHUNK);
357 if (err)
358 goto done;
360 if (ndeltas != 3) {
361 err = got_error(GOT_ERR_BAD_DELTA);
362 goto done;
364 /* Copy 'aaaa...' from base file. */
365 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
366 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
367 err = got_error(GOT_ERR_BAD_DELTA);
368 goto done;
370 /* Copy 'xxxx...' from derived file. */
371 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
372 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
373 err = got_error(GOT_ERR_BAD_DELTA);
374 goto done;
376 /* Copy 'ccccc...' from base file. */
377 if (!(deltas[2].copy == 1 &&
378 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
379 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
380 err = got_error(GOT_ERR_BAD_DELTA);
381 goto done;
384 done:
385 got_deltify_free(dt);
386 fclose(result_file);
387 return (err == NULL);
390 static int quiet;
392 #define RUN_TEST(expr, name) \
393 { test_ok = (expr); \
394 if (!quiet) printf("test_%s %s\n", (name), test_ok ? "ok" : "failed"); \
395 failure = (failure || !test_ok); }
397 static void
398 usage(void)
400 fprintf(stderr, "usage: delta_test [-q]\n");
403 int
404 main(int argc, char *argv[])
406 int test_ok;
407 int failure = 0;
408 int ch;
410 while ((ch = getopt(argc, argv, "q")) != -1) {
411 switch (ch) {
412 case 'q':
413 quiet = 1;
414 break;
415 default:
416 usage();
417 return 1;
421 argc -= optind;
422 argv += optind;
424 if (argc != 0) {
425 usage();
426 return 1;
429 #ifndef PROFILE
430 if (pledge("stdio rpath wpath cpath unveil", NULL) == -1)
431 err(1, "pledge");
432 #endif
433 if (unveil(GOT_TMPDIR_STR, "rwc") != 0)
434 err(1, "unveil");
436 if (unveil(NULL, NULL) != 0)
437 err(1, "unveil");
439 RUN_TEST(deltify_abc_axc(), "deltify_abc_axc");
440 RUN_TEST(deltify_abc_axc_file_mem(), "deltify_abc_axc_file_mem");
441 RUN_TEST(deltify_abc_axc_mem_file(), "deltify_abc_axc_mem_file");
442 RUN_TEST(deltify_abc_axc_mem_mem(), "deltify_abc_axc_mem_mem");
444 return failure ? 1 : 0;