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 <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <err.h>
21 #include <unistd.h>
22 #include <getopt.h>
24 #include "got_error.h"
25 #include "got_opentemp.h"
27 #include "got_lib_deltify.h"
29 #ifndef nitems
30 #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
31 #endif
33 static int
34 deltify_abc_axc(void)
35 {
36 const struct got_error *err = NULL;
37 size_t i;
38 FILE *base_file, *derived_file, *result_file;
39 struct got_delta_table *dt;
40 struct got_delta_instruction *deltas;
41 int ndeltas;
42 int have_nblocks = 0;
43 uint32_t seed;
45 seed = arc4random();
47 base_file = got_opentemp();
48 if (base_file == NULL)
49 return 1;
51 derived_file = got_opentemp();
52 if (derived_file == NULL)
53 return 1;
55 result_file = got_opentemp();
56 if (result_file == NULL)
57 return 1;
59 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
60 fputc('a', base_file);
61 fputc('a', derived_file);
62 }
63 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
64 fputc('b', base_file);
65 fputc('x', derived_file);
66 }
67 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
68 fputc('c', base_file);
69 fputc('c', derived_file);
70 }
72 rewind(base_file);
73 rewind(derived_file);
75 err = got_deltify_init(&dt, base_file, 0, 3 * GOT_DELTIFY_MAXCHUNK,
76 seed);
77 if (err)
78 goto done;
80 for (i = 0; i < dt->nalloc; i++) {
81 if (dt->blocks[i].len > 0)
82 have_nblocks++;
83 }
84 if (have_nblocks != dt->nblocks) {
85 err = got_error(GOT_ERR_BAD_DELTA);
86 goto done;
87 }
89 err = got_deltify(&deltas, &ndeltas, derived_file, 0,
90 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_file, 0,
91 3 * GOT_DELTIFY_MAXCHUNK);
92 if (err)
93 goto done;
95 if (ndeltas != 3) {
96 err = got_error(GOT_ERR_BAD_DELTA);
97 goto done;
98 }
99 /* Copy 'aaaa...' from base file. */
100 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
101 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
102 err = got_error(GOT_ERR_BAD_DELTA);
103 goto done;
105 /* Copy 'xxxx...' from derived file. */
106 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
107 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
108 err = got_error(GOT_ERR_BAD_DELTA);
109 goto done;
111 /* Copy 'ccccc...' from base file. */
112 if (!(deltas[2].copy == 1 &&
113 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
114 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
115 err = got_error(GOT_ERR_BAD_DELTA);
116 goto done;
119 done:
120 got_deltify_free(dt);
121 fclose(base_file);
122 fclose(derived_file);
123 fclose(result_file);
124 return (err == NULL);
127 static int
128 deltify_abc_axc_file_mem(void)
130 const struct got_error *err = NULL;
131 size_t i;
132 uint8_t base_data[3 * GOT_DELTIFY_MAXCHUNK];
133 FILE *derived_file, *result_file;
134 struct got_delta_table *dt;
135 struct got_delta_instruction *deltas;
136 int ndeltas;
137 int have_nblocks = 0;
138 uint32_t seed;
140 seed = arc4random();
142 derived_file = got_opentemp();
143 if (derived_file == NULL)
144 return 1;
146 result_file = got_opentemp();
147 if (result_file == NULL)
148 return 1;
150 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
151 base_data[i] = 'a';
152 fputc('a', derived_file);
154 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
155 base_data[GOT_DELTIFY_MAXCHUNK + i] = 'b';
156 fputc('x', derived_file);
158 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
159 base_data[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
160 fputc('c', derived_file);
163 rewind(derived_file);
165 err = got_deltify_init_mem(&dt, base_data, 0, 3 * GOT_DELTIFY_MAXCHUNK,
166 seed);
167 if (err)
168 goto done;
170 for (i = 0; i < dt->nalloc; i++) {
171 if (dt->blocks[i].len > 0)
172 have_nblocks++;
174 if (have_nblocks != dt->nblocks) {
175 err = got_error(GOT_ERR_BAD_DELTA);
176 goto done;
179 err = got_deltify_file_mem(&deltas, &ndeltas, derived_file, 0,
180 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_data, 0,
181 3 * GOT_DELTIFY_MAXCHUNK);
182 if (err)
183 goto done;
185 if (ndeltas != 3) {
186 err = got_error(GOT_ERR_BAD_DELTA);
187 goto done;
189 /* Copy 'aaaa...' from base file. */
190 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
191 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
192 err = got_error(GOT_ERR_BAD_DELTA);
193 goto done;
195 /* Copy 'xxxx...' from derived file. */
196 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
197 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
198 err = got_error(GOT_ERR_BAD_DELTA);
199 goto done;
201 /* Copy 'ccccc...' from base file. */
202 if (!(deltas[2].copy == 1 &&
203 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
204 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
205 err = got_error(GOT_ERR_BAD_DELTA);
206 goto done;
209 done:
210 got_deltify_free(dt);
211 fclose(derived_file);
212 fclose(result_file);
213 return (err == NULL);
216 static int
217 deltify_abc_axc_mem_file(void)
219 const struct got_error *err = NULL;
220 size_t i;
221 FILE *base_file, *result_file;
222 uint8_t derived_file[3 * GOT_DELTIFY_MAXCHUNK];
223 struct got_delta_table *dt;
224 struct got_delta_instruction *deltas;
225 int ndeltas;
226 int have_nblocks = 0;
227 uint32_t seed;
229 seed = arc4random();
231 base_file = got_opentemp();
232 if (base_file == NULL)
233 return 1;
235 result_file = got_opentemp();
236 if (result_file == NULL)
237 return 1;
239 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
240 fputc('a', base_file);
241 derived_file[i] = 'a';
243 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
244 fputc('b', base_file);
245 derived_file[GOT_DELTIFY_MAXCHUNK + i] = 'x';
247 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
248 fputc('c', base_file);
249 derived_file[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
252 rewind(base_file);
254 err = got_deltify_init(&dt, base_file, 0, 3 * GOT_DELTIFY_MAXCHUNK,
255 seed);
256 if (err)
257 goto done;
259 for (i = 0; i < dt->nalloc; i++) {
260 if (dt->blocks[i].len > 0)
261 have_nblocks++;
263 if (have_nblocks != dt->nblocks) {
264 err = got_error(GOT_ERR_BAD_DELTA);
265 goto done;
268 err = got_deltify_mem_file(&deltas, &ndeltas, derived_file, 0,
269 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_file, 0,
270 3 * GOT_DELTIFY_MAXCHUNK);
271 if (err)
272 goto done;
274 if (ndeltas != 3) {
275 err = got_error(GOT_ERR_BAD_DELTA);
276 goto done;
278 /* Copy 'aaaa...' from base file. */
279 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
280 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
281 err = got_error(GOT_ERR_BAD_DELTA);
282 goto done;
284 /* Copy 'xxxx...' from derived file. */
285 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
286 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
287 err = got_error(GOT_ERR_BAD_DELTA);
288 goto done;
290 /* Copy 'ccccc...' from base file. */
291 if (!(deltas[2].copy == 1 &&
292 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
293 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
294 err = got_error(GOT_ERR_BAD_DELTA);
295 goto done;
298 done:
299 got_deltify_free(dt);
300 fclose(base_file);
301 fclose(result_file);
302 return (err == NULL);
305 static int
306 deltify_abc_axc_mem_mem(void)
308 const struct got_error *err = NULL;
309 size_t i;
310 FILE *result_file;
311 uint8_t base_file[3 * GOT_DELTIFY_MAXCHUNK];
312 uint8_t derived_file[3 * GOT_DELTIFY_MAXCHUNK];
313 struct got_delta_table *dt;
314 struct got_delta_instruction *deltas;
315 int ndeltas;
316 int have_nblocks = 0;
317 uint32_t seed;
319 seed = arc4random();
321 result_file = got_opentemp();
322 if (result_file == NULL)
323 return 1;
325 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
326 base_file[i] = 'a';
327 derived_file[i] = 'a';
329 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
330 base_file[GOT_DELTIFY_MAXCHUNK + i] = 'b';
331 derived_file[GOT_DELTIFY_MAXCHUNK + i] = 'x';
333 for (i = 0; i < GOT_DELTIFY_MAXCHUNK; i++) {
334 base_file[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
335 derived_file[2 * GOT_DELTIFY_MAXCHUNK + i] = 'c';
338 err = got_deltify_init_mem(&dt, base_file, 0, 3 * GOT_DELTIFY_MAXCHUNK,
339 seed);
340 if (err)
341 goto done;
343 for (i = 0; i < dt->nalloc; i++) {
344 if (dt->blocks[i].len > 0)
345 have_nblocks++;
347 if (have_nblocks != dt->nblocks) {
348 err = got_error(GOT_ERR_BAD_DELTA);
349 goto done;
352 err = got_deltify_mem_mem(&deltas, &ndeltas, derived_file, 0,
353 3 * GOT_DELTIFY_MAXCHUNK, seed, dt, base_file, 0,
354 3 * GOT_DELTIFY_MAXCHUNK);
355 if (err)
356 goto done;
358 if (ndeltas != 3) {
359 err = got_error(GOT_ERR_BAD_DELTA);
360 goto done;
362 /* Copy 'aaaa...' from base file. */
363 if (!(deltas[0].copy == 1 && deltas[0].offset == 0 &&
364 deltas[0].len == GOT_DELTIFY_MAXCHUNK)) {
365 err = got_error(GOT_ERR_BAD_DELTA);
366 goto done;
368 /* Copy 'xxxx...' from derived file. */
369 if (!(deltas[1].copy == 0 && deltas[1].offset == GOT_DELTIFY_MAXCHUNK &&
370 deltas[1].len == GOT_DELTIFY_MAXCHUNK)) {
371 err = got_error(GOT_ERR_BAD_DELTA);
372 goto done;
374 /* Copy 'ccccc...' from base file. */
375 if (!(deltas[2].copy == 1 &&
376 deltas[2].offset == 2 * GOT_DELTIFY_MAXCHUNK &&
377 deltas[2].len == GOT_DELTIFY_MAXCHUNK)) {
378 err = got_error(GOT_ERR_BAD_DELTA);
379 goto done;
382 done:
383 got_deltify_free(dt);
384 fclose(result_file);
385 return (err == NULL);
388 static int quiet;
390 #define RUN_TEST(expr, name) \
391 { test_ok = (expr); \
392 if (!quiet) printf("test_%s %s\n", (name), test_ok ? "ok" : "failed"); \
393 failure = (failure || !test_ok); }
395 static void
396 usage(void)
398 fprintf(stderr, "usage: delta_test [-q]\n");
401 int
402 main(int argc, char *argv[])
404 int test_ok;
405 int failure = 0;
406 int ch;
408 while ((ch = getopt(argc, argv, "q")) != -1) {
409 switch (ch) {
410 case 'q':
411 quiet = 1;
412 break;
413 default:
414 usage();
415 return 1;
419 argc -= optind;
420 argv += optind;
422 if (argc != 0) {
423 usage();
424 return 1;
427 #ifndef PROFILE
428 if (pledge("stdio rpath wpath cpath unveil", NULL) == -1)
429 err(1, "pledge");
430 #endif
431 if (unveil(GOT_TMPDIR_STR, "rwc") != 0)
432 err(1, "unveil");
434 if (unveil(NULL, NULL) != 0)
435 err(1, "unveil");
437 RUN_TEST(deltify_abc_axc(), "deltify_abc_axc");
438 RUN_TEST(deltify_abc_axc_file_mem(), "deltify_abc_axc_file_mem");
439 RUN_TEST(deltify_abc_axc_mem_file(), "deltify_abc_axc_mem_file");
440 RUN_TEST(deltify_abc_axc_mem_mem(), "deltify_abc_axc_mem_mem");
442 return failure ? 1 : 0;