Major cleanup of makefiles, api tests.
[ccan] / ccan / crcsync / test / api.c
1 #include "crcsync/crcsync.h"
2 #include "tap/tap.h"
3 #include <stdlib.h>
4 #include <stdbool.h>
5 #include <string.h>
6
7 /* FIXME: ccanize. */
8 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
9
10 struct result {
11         enum {
12                 LITERAL, BLOCK
13         } type;
14         /* Block number, or length of literal. */
15         size_t val;
16 };
17
18 static inline size_t num_blocks(size_t len, size_t block_size)
19 {
20         return (len + block_size - 1) / block_size;
21 }
22
23 static void check_finalized_result(size_t curr_literal,
24                                    const struct result results[],
25                                    size_t num_results,
26                                    size_t *curr_result)
27 {
28         if (curr_literal == 0)
29                 return;
30         ok1(*curr_result < num_results);
31         ok1(results[*curr_result].type == LITERAL);
32         ok1(results[*curr_result].val == curr_literal);
33         (*curr_result)++;
34 }
35
36 static void check_result(long result,
37                          size_t *curr_literal,
38                          const struct result results[], size_t num_results,
39                          size_t *curr_result)
40 {
41         /* We append multiple literals into one. */
42         if (result >= 0) {
43                 *curr_literal += result;
44                 return;
45         }
46
47         /* Check outstanding literals. */
48         if (*curr_literal) {
49                 check_finalized_result(*curr_literal, results, num_results,
50                                        curr_result);
51                 *curr_literal = 0;
52         }
53
54         ok1(*curr_result < num_results);
55         ok1(results[*curr_result].type == BLOCK);
56         ok1(results[*curr_result].val == -result - 1);
57         (*curr_result)++;
58 }
59
60 /* Start with buffer1 and sync to buffer2. */
61 static void test_sync(const char *buffer1, size_t len1,
62                       const char *buffer2, size_t len2,
63                       size_t block_size,
64                       const struct result results[], size_t num_results)
65 {
66         struct crc_context *ctx;
67         size_t used, ret, i, curr_literal = 0;
68         long result;
69         uint32_t crcs[num_blocks(len1, block_size)];
70
71         crc_of_blocks(buffer1, len1, block_size, 32, crcs);
72         ctx = crc_context_new(block_size, 32, crcs, ARRAY_SIZE(crcs));
73
74         for (used = 0, i = 0; used < len2; used += ret) {
75                 ret = crc_read_block(ctx, &result, buffer2+used, len2-used);
76
77                 check_result(result, &curr_literal, results, num_results, &i);
78         }
79
80         while ((result = crc_read_flush(ctx)) != 0)
81                 check_result(result, &curr_literal, results, num_results, &i);
82
83         check_finalized_result(curr_literal, results, num_results, &i);
84         
85         /* We must have achieved everything we expected. */
86         ok1(i == num_results);
87         crc_context_free(ctx);
88 }
89
90 int main(int argc, char *argv[])
91 {
92         char *buffer1, *buffer2;
93         unsigned int i;
94         uint32_t crcs1[12], crcs2[12];
95
96         plan_tests(733);
97
98         buffer1 = calloc(1024, 1);
99         buffer2 = calloc(1024, 1);
100
101         /* Truncated end block test. */
102         crcs1[11] = 0xdeadbeef;
103         crc_of_blocks(buffer1, 1024, 100, 32, crcs1);
104         ok1(crcs1[11] == 0xdeadbeef);
105         crc_of_blocks(buffer2, 1024, 100, 32, crcs2);
106         ok1(memcmp(crcs1, crcs2, sizeof(crcs1[0])*11) == 0);
107
108         /* Fill with non-zero pattern, retest. */
109         for (i = 0; i < 1024; i++)
110                 buffer1[i] = buffer2[i] = i + i/128;
111
112         crcs1[11] = 0xdeadbeef;
113         crc_of_blocks(buffer1, 1024, 100, 32, crcs1);
114         ok1(crcs1[11] == 0xdeadbeef);
115         crc_of_blocks(buffer2, 1024, 100, 32, crcs2);
116         ok1(memcmp(crcs1, crcs2, sizeof(crcs1[0])*11) == 0);
117
118         /* Check that it correctly masks bits. */
119         crc_of_blocks(buffer1, 1024, 128, 32, crcs1);
120         crc_of_blocks(buffer2, 1024, 128, 8, crcs2);
121         for (i = 0; i < 1024/128; i++)
122                 ok1(crcs2[i] == (crcs1[i] & 0xFF));
123
124         /* Now test the "exact match" "round blocks" case. */
125         {
126                 struct result res[] = {
127                         { BLOCK, 0 },
128                         { BLOCK, 1 },
129                         { BLOCK, 2 },
130                         { BLOCK, 3 },
131                         { BLOCK, 4 },
132                         { BLOCK, 5 },
133                         { BLOCK, 6 },
134                         { BLOCK, 7 } };
135                 test_sync(buffer1, 1024, buffer2, 1024, 128,
136                           res, ARRAY_SIZE(res));
137         }
138
139         /* Now test the "exact match" with end block case. */
140         {
141                 struct result res[] = {
142                         { BLOCK, 0 },
143                         { BLOCK, 1 },
144                         { BLOCK, 2 },
145                         { BLOCK, 3 },
146                         { BLOCK, 4 },
147                         { BLOCK, 5 },
148                         { BLOCK, 6 },
149                         { BLOCK, 7 },
150                         { BLOCK, 8 },
151                         { BLOCK, 9 },
152                         { BLOCK, 10 } };
153                 test_sync(buffer1, 1024, buffer2, 1024, 100,
154                           res, ARRAY_SIZE(res));
155         }
156
157         /* Now test the "one byte append" "round blocks" case. */
158         {
159                 struct result res[] = {
160                         { BLOCK, 0 },
161                         { BLOCK, 1 },
162                         { BLOCK, 2 },
163                         { BLOCK, 3 },
164                         { BLOCK, 4 },
165                         { BLOCK, 5 },
166                         { BLOCK, 6 },
167                         { LITERAL, 1 } };
168                 test_sync(buffer1, 1024-128, buffer2, 1024-127, 128,
169                           res, ARRAY_SIZE(res));
170         }
171
172         /* Now test the "one byte append" with end block case. */
173         {
174                 struct result res[] = {
175                         { BLOCK, 0 },
176                         { BLOCK, 1 },
177                         { BLOCK, 2 },
178                         { BLOCK, 3 },
179                         { BLOCK, 4 },
180                         { BLOCK, 5 },
181                         { BLOCK, 6 },
182                         { BLOCK, 7 },
183                         { BLOCK, 8 },
184                         { BLOCK, 9 },
185                         { BLOCK, 10 },
186                         { LITERAL, 1 } };
187                 test_sync(buffer1, 1023, buffer2, 1024, 100,
188                           res, ARRAY_SIZE(res));
189         }
190
191         /* Now try changing one block at a time, check we get right results. */
192         for (i = 0; i < 1024/128; i++) {
193                 unsigned int j;
194                 struct result res[8];
195
196                 /* Mess with block. */
197                 memcpy(buffer2, buffer1, 1024);
198                 buffer2[i * 128]++;
199
200                 for (j = 0; j < ARRAY_SIZE(res); j++) {
201                         if (j == i) {
202                                 res[j].type = LITERAL;
203                                 res[j].val = 128;
204                         } else {
205                                 res[j].type = BLOCK;
206                                 res[j].val = j;
207                         }
208                 }
209
210                 test_sync(buffer1, 1024, buffer2, 1024, 128,
211                           res, ARRAY_SIZE(res));
212         }
213
214         /* Now try shrinking one block at a time, check we get right results. */
215         for (i = 0; i < 1024/128; i++) {
216                 unsigned int j;
217                 struct result res[8];
218
219                 /* Shrink block. */
220                 memcpy(buffer2, buffer1, i * 128 + 64);
221                 memcpy(buffer2 + i * 128 + 64, buffer1 + i * 128 + 65,
222                        1024 - (i * 128 + 65));
223
224                 for (j = 0; j < ARRAY_SIZE(res); j++) {
225                         if (j == i) {
226                                 res[j].type = LITERAL;
227                                 res[j].val = 127;
228                         } else {
229                                 res[j].type = BLOCK;
230                                 res[j].val = j;
231                         }
232                 }
233
234                 test_sync(buffer1, 1024, buffer2, 1023, 128,
235                           res, ARRAY_SIZE(res));
236         }
237
238         /* Now try shrinking one block at a time, check we get right results. */
239         for (i = 0; i < 1024/128; i++) {
240                 unsigned int j;
241                 struct result res[8];
242
243                 /* Shrink block. */
244                 memcpy(buffer2, buffer1, i * 128 + 64);
245                 memcpy(buffer2 + i * 128 + 64, buffer1 + i * 128 + 65,
246                        1024 - (i * 128 + 65));
247
248                 for (j = 0; j < ARRAY_SIZE(res); j++) {
249                         if (j == i) {
250                                 res[j].type = LITERAL;
251                                 res[j].val = 127;
252                         } else {
253                                 res[j].type = BLOCK;
254                                 res[j].val = j;
255                         }
256                 }
257
258                 test_sync(buffer1, 1024, buffer2, 1023, 128,
259                           res, ARRAY_SIZE(res));
260         }
261
262         return exit_status();
263 }