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>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <err.h>
22 #include <unistd.h>
23 #include <getopt.h>
25 #include "got_error.h"
26 #include "got_opentemp.h"
28 #include "got_lib_deltify.h"
30 #ifndef nitems
31 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
32 #endif
34 static int
35 deltify_abc_axc(void)
36 {
37 const struct got_error *err = NULL;
38 size_t i;
39 FILE *base_file, *derived_file, *result_file;
40 struct got_delta_table *dt;
41 struct got_delta_instruction *deltas;
42 int ndeltas;
43 int have_nblocks = 0;
44 uint32_t seed;
46 seed = arc4random();
48 base_file = got_opentemp();
49 if (base_file == NULL)
50 return 1;
52 derived_file = got_opentemp();
53 if (derived_file == NULL)
54 return 1;
56 result_file = got_opentemp();
57 if (result_file == NULL)
58 return 1;
60 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
61 fputc('a', base_file);
62 fputc('a', derived_file);
63 }
64 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
65 fputc('b', base_file);
66 fputc('x', derived_file);
67 }
68 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
69 fputc('c', base_file);
70 fputc('c', derived_file);
71 }
73 rewind(base_file);
74 rewind(derived_file);
76 err = got_deltify_init(&dt, base_file, 0, 3 * GOT_DELTIFY_MAXCHUNK,
77 seed);
78 if (err)
79 goto done;
81 for (i = 0; i < dt->nalloc; i++) {
82 if (dt->blocks[i].len > 0)
83 have_nblocks++;
84 }
85 if (have_nblocks != dt->nblocks) {
86 err = got_error(GOT_ERR_BAD_DELTA);
87 goto done;
88 }
90 err = got_deltify(&deltas, &ndeltas, derived_file, 0,
91 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_file, 0,
92 3 * GOT_DELTIFY_MAXCHUNK);
93 if (err)
94 goto done;
96 if (ndeltas != 3) {
97 err = got_error(GOT_ERR_BAD_DELTA);
98 goto done;
99 }
100 /* Copy 'aaaa...' from base file. */
101 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
102 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
103 err = got_error(GOT_ERR_BAD_DELTA);
104 goto done;
106 /* Copy 'xxxx...' from derived file. */
107 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
108 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
109 err = got_error(GOT_ERR_BAD_DELTA);
110 goto done;
112 /* Copy 'ccccc...' from base file. */
113 if (!(deltas[2].copy == 1 &&
114 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
115 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
116 err = got_error(GOT_ERR_BAD_DELTA);
117 goto done;
120 done:
121 got_deltify_free(dt);
122 fclose(base_file);
123 fclose(derived_file);
124 fclose(result_file);
125 return (err == NULL);
128 static int
129 deltify_abc_axc_file_mem(void)
131 const struct got_error *err = NULL;
132 size_t i;
133 uint8_t base_data[3 * GOT_DELTIFY_MAXCHUNK];
134 FILE *derived_file, *result_file;
135 struct got_delta_table *dt;
136 struct got_delta_instruction *deltas;
137 int ndeltas;
138 int have_nblocks = 0;
139 uint32_t seed;
141 seed = arc4random();
143 derived_file = got_opentemp();
144 if (derived_file == NULL)
145 return 1;
147 result_file = got_opentemp();
148 if (result_file == NULL)
149 return 1;
151 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
152 base_data[i] = 'a';
153 fputc('a', derived_file);
155 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
156 base_data[GOT_DELTIFY_MAXCHUNK + i] = 'b';
157 fputc('x', derived_file);
159 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
160 base_data[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
161 fputc('c', derived_file);
164 rewind(derived_file);
166 err = got_deltify_init_mem(&dt, base_data, 0, 3 * GOT_DELTIFY_MAXCHUNK,
167 seed);
168 if (err)
169 goto done;
171 for (i = 0; i < dt->nalloc; i++) {
172 if (dt->blocks[i].len > 0)
173 have_nblocks++;
175 if (have_nblocks != dt->nblocks) {
176 err = got_error(GOT_ERR_BAD_DELTA);
177 goto done;
180 err = got_deltify_file_mem(&deltas, &ndeltas, derived_file, 0,
181 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_data, 0,
182 3 * GOT_DELTIFY_MAXCHUNK);
183 if (err)
184 goto done;
186 if (ndeltas != 3) {
187 err = got_error(GOT_ERR_BAD_DELTA);
188 goto done;
190 /* Copy 'aaaa...' from base file. */
191 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
192 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
193 err = got_error(GOT_ERR_BAD_DELTA);
194 goto done;
196 /* Copy 'xxxx...' from derived file. */
197 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
198 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
199 err = got_error(GOT_ERR_BAD_DELTA);
200 goto done;
202 /* Copy 'ccccc...' from base file. */
203 if (!(deltas[2].copy == 1 &&
204 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
205 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
206 err = got_error(GOT_ERR_BAD_DELTA);
207 goto done;
210 done:
211 got_deltify_free(dt);
212 fclose(derived_file);
213 fclose(result_file);
214 return (err == NULL);
217 static int
218 deltify_abc_axc_mem_file(void)
220 const struct got_error *err = NULL;
221 size_t i;
222 FILE *base_file, *result_file;
223 uint8_t derived_file[3 * GOT_DELTIFY_MAXCHUNK];
224 struct got_delta_table *dt;
225 struct got_delta_instruction *deltas;
226 int ndeltas;
227 int have_nblocks = 0;
228 uint32_t seed;
230 seed = arc4random();
232 base_file = got_opentemp();
233 if (base_file == NULL)
234 return 1;
236 result_file = got_opentemp();
237 if (result_file == NULL)
238 return 1;
240 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
241 fputc('a', base_file);
242 derived_file[i] = 'a';
244 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
245 fputc('b', base_file);
246 derived_file[GOT_DELTIFY_MAXCHUNK + i] = 'x';
248 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
249 fputc('c', base_file);
250 derived_file[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
253 rewind(base_file);
255 err = got_deltify_init(&dt, base_file, 0, 3 * GOT_DELTIFY_MAXCHUNK,
256 seed);
257 if (err)
258 goto done;
260 for (i = 0; i < dt->nalloc; i++) {
261 if (dt->blocks[i].len > 0)
262 have_nblocks++;
264 if (have_nblocks != dt->nblocks) {
265 err = got_error(GOT_ERR_BAD_DELTA);
266 goto done;
269 err = got_deltify_mem_file(&deltas, &ndeltas, derived_file, 0,
270 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_file, 0,
271 3 * GOT_DELTIFY_MAXCHUNK);
272 if (err)
273 goto done;
275 if (ndeltas != 3) {
276 err = got_error(GOT_ERR_BAD_DELTA);
277 goto done;
279 /* Copy 'aaaa...' from base file. */
280 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
281 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
282 err = got_error(GOT_ERR_BAD_DELTA);
283 goto done;
285 /* Copy 'xxxx...' from derived file. */
286 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
287 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
288 err = got_error(GOT_ERR_BAD_DELTA);
289 goto done;
291 /* Copy 'ccccc...' from base file. */
292 if (!(deltas[2].copy == 1 &&
293 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
294 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
295 err = got_error(GOT_ERR_BAD_DELTA);
296 goto done;
299 done:
300 got_deltify_free(dt);
301 fclose(base_file);
302 fclose(result_file);
303 return (err == NULL);
306 static int
307 deltify_abc_axc_mem_mem(void)
309 const struct got_error *err = NULL;
310 size_t i;
311 FILE *result_file;
312 uint8_t base_file[3 * GOT_DELTIFY_MAXCHUNK];
313 uint8_t derived_file[3 * GOT_DELTIFY_MAXCHUNK];
314 struct got_delta_table *dt;
315 struct got_delta_instruction *deltas;
316 int ndeltas;
317 int have_nblocks = 0;
318 uint32_t seed;
320 seed = arc4random();
322 result_file = got_opentemp();
323 if (result_file == NULL)
324 return 1;
326 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
327 base_file[i] = 'a';
328 derived_file[i] = 'a';
330 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
331 base_file[GOT_DELTIFY_MAXCHUNK + i] = 'b';
332 derived_file[GOT_DELTIFY_MAXCHUNK + i] = 'x';
334 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
335 base_file[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
336 derived_file[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
339 err = got_deltify_init_mem(&dt, base_file, 0, 3 * GOT_DELTIFY_MAXCHUNK,
340 seed);
341 if (err)
342 goto done;
344 for (i = 0; i < dt->nalloc; i++) {
345 if (dt->blocks[i].len > 0)
346 have_nblocks++;
348 if (have_nblocks != dt->nblocks) {
349 err = got_error(GOT_ERR_BAD_DELTA);
350 goto done;
353 err = got_deltify_mem_mem(&deltas, &ndeltas, derived_file, 0,
354 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_file, 0,
355 3 * GOT_DELTIFY_MAXCHUNK);
356 if (err)
357 goto done;
359 if (ndeltas != 3) {
360 err = got_error(GOT_ERR_BAD_DELTA);
361 goto done;
363 /* Copy 'aaaa...' from base file. */
364 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
365 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
366 err = got_error(GOT_ERR_BAD_DELTA);
367 goto done;
369 /* Copy 'xxxx...' from derived file. */
370 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
371 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
372 err = got_error(GOT_ERR_BAD_DELTA);
373 goto done;
375 /* Copy 'ccccc...' from base file. */
376 if (!(deltas[2].copy == 1 &&
377 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
378 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
379 err = got_error(GOT_ERR_BAD_DELTA);
380 goto done;
383 done:
384 got_deltify_free(dt);
385 fclose(result_file);
386 return (err == NULL);
389 static int quiet;
391 #define RUN_TEST(expr, name) \
392 { test_ok = (expr); \
393 if (!quiet) printf("test_%s %s\n", (name), test_ok ? "ok" : "failed"); \
394 failure = (failure || !test_ok); }
396 static void
397 usage(void)
399 fprintf(stderr, "usage: delta_test [-q]\n");
402 int
403 main(int argc, char *argv[])
405 int test_ok;
406 int failure = 0;
407 int ch;
409 while ((ch = getopt(argc, argv, "q")) != -1) {
410 switch (ch) {
411 case 'q':
412 quiet = 1;
413 break;
414 default:
415 usage();
416 return 1;
420 argc -= optind;
421 argv += optind;
423 if (argc != 0) {
424 usage();
425 return 1;
428 #ifndef PROFILE
429 if (pledge("stdio rpath wpath cpath unveil", NULL) == -1)
430 err(1, "pledge");
431 #endif
432 if (unveil(GOT_TMPDIR_STR, "rwc") != 0)
433 err(1, "unveil");
435 if (unveil(NULL, NULL) != 0)
436 err(1, "unveil");
438 RUN_TEST(deltify_abc_axc(), "deltify_abc_axc");
439 RUN_TEST(deltify_abc_axc_file_mem(), "deltify_abc_axc_file_mem");
440 RUN_TEST(deltify_abc_axc_mem_file(), "deltify_abc_axc_mem_file");
441 RUN_TEST(deltify_abc_axc_mem_mem(), "deltify_abc_axc_mem_mem");
443 return failure ? 1 : 0;