Refine protocol definition and open issues
[httpd-crcsyncproxy.git] / ccan / crcsync / test / api.c
blob2f07cb696e1fe2ea10516ae9b163ca2aa5406c0e
1 #include "crcsync/crcsync.h"
2 #include "tap/tap.h"
3 #include <stdlib.h>
4 #include <stdbool.h>
5 #include <string.h>
7 /* FIXME: ccanize. */
8 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
10 struct result {
11 enum {
12 LITERAL, BLOCK
13 } type;
14 /* Block number, or length of literal. */
15 size_t val;
18 static inline size_t num_blocks(size_t len, size_t block_size)
20 return (len + block_size - 1) / block_size;
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)
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)++;
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)
41 /* We append multiple literals into one. */
42 if (result >= 0) {
43 *curr_literal += result;
44 return;
47 /* Check outstanding literals. */
48 if (*curr_literal) {
49 check_finalized_result(*curr_literal, results, num_results,
50 curr_result);
51 *curr_literal = 0;
54 ok1(*curr_result < num_results);
55 ok1(results[*curr_result].type == BLOCK);
56 ok1(results[*curr_result].val == -result - 1);
57 (*curr_result)++;
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)
66 struct crc_context *ctx;
67 size_t used, ret, i, curr_literal;
68 long result;
69 uint32_t crcs[num_blocks(len1, block_size)];
71 crc_of_blocks(buffer1, len1, block_size, 32, crcs);
73 /* Normal method. */
74 ctx = crc_context_new(block_size, 32, crcs, ARRAY_SIZE(crcs));
76 curr_literal = 0;
77 for (used = 0, i = 0; used < len2; used += ret) {
78 ret = crc_read_block(ctx, &result, buffer2+used, len2-used);
79 check_result(result, &curr_literal, results, num_results, &i);
82 while ((result = crc_read_flush(ctx)) != 0)
83 check_result(result, &curr_literal, results, num_results, &i);
85 check_finalized_result(curr_literal, results, num_results, &i);
87 /* We must have achieved everything we expected. */
88 ok1(i == num_results);
89 crc_context_free(ctx);
91 /* Byte-at-a-time method. */
92 ctx = crc_context_new(block_size, 32, crcs, ARRAY_SIZE(crcs));
94 curr_literal = 0;
95 for (used = 0, i = 0; used < len2; used += ret) {
96 ret = crc_read_block(ctx, &result, buffer2+used, 1);
98 check_result(result, &curr_literal, results, num_results, &i);
101 while ((result = crc_read_flush(ctx)) != 0)
102 check_result(result, &curr_literal, results, num_results, &i);
104 check_finalized_result(curr_literal, results, num_results, &i);
106 /* We must have achieved everything we expected. */
107 ok1(i == num_results);
108 crc_context_free(ctx);
111 int main(int argc, char *argv[])
113 char *buffer1, *buffer2;
114 unsigned int i;
115 uint32_t crcs1[12], crcs2[12];
117 plan_tests(1454);
119 buffer1 = calloc(1024, 1);
120 buffer2 = calloc(1024, 1);
122 /* Truncated end block test. */
123 crcs1[11] = 0xdeadbeef;
124 crc_of_blocks(buffer1, 1024, 100, 32, crcs1);
125 ok1(crcs1[11] == 0xdeadbeef);
126 crc_of_blocks(buffer2, 1024, 100, 32, crcs2);
127 ok1(memcmp(crcs1, crcs2, sizeof(crcs1[0])*11) == 0);
129 /* Fill with non-zero pattern, retest. */
130 for (i = 0; i < 1024; i++)
131 buffer1[i] = buffer2[i] = i + i/128;
133 crcs1[11] = 0xdeadbeef;
134 crc_of_blocks(buffer1, 1024, 100, 32, crcs1);
135 ok1(crcs1[11] == 0xdeadbeef);
136 crc_of_blocks(buffer2, 1024, 100, 32, crcs2);
137 ok1(memcmp(crcs1, crcs2, sizeof(crcs1[0])*11) == 0);
139 /* Check that it correctly masks bits. */
140 crc_of_blocks(buffer1, 1024, 128, 32, crcs1);
141 crc_of_blocks(buffer2, 1024, 128, 8, crcs2);
142 for (i = 0; i < 1024/128; i++)
143 ok1(crcs2[i] == (crcs1[i] & 0xFF));
145 /* Now test the "exact match" "round blocks" case. */
147 struct result res[] = {
148 { BLOCK, 0 },
149 { BLOCK, 1 },
150 { BLOCK, 2 },
151 { BLOCK, 3 },
152 { BLOCK, 4 },
153 { BLOCK, 5 },
154 { BLOCK, 6 },
155 { BLOCK, 7 } };
156 test_sync(buffer1, 1024, buffer2, 1024, 128,
157 res, ARRAY_SIZE(res));
160 /* Now test the "exact match" with end block case. */
162 struct result res[] = {
163 { BLOCK, 0 },
164 { BLOCK, 1 },
165 { BLOCK, 2 },
166 { BLOCK, 3 },
167 { BLOCK, 4 },
168 { BLOCK, 5 },
169 { BLOCK, 6 },
170 { BLOCK, 7 },
171 { BLOCK, 8 },
172 { BLOCK, 9 },
173 { BLOCK, 10 } };
174 test_sync(buffer1, 1024, buffer2, 1024, 100,
175 res, ARRAY_SIZE(res));
178 /* Now test the "one byte append" "round blocks" case. */
180 struct result res[] = {
181 { BLOCK, 0 },
182 { BLOCK, 1 },
183 { BLOCK, 2 },
184 { BLOCK, 3 },
185 { BLOCK, 4 },
186 { BLOCK, 5 },
187 { BLOCK, 6 },
188 { LITERAL, 1 } };
189 test_sync(buffer1, 1024-128, buffer2, 1024-127, 128,
190 res, ARRAY_SIZE(res));
193 /* Now test the "one byte append" with end block case. */
195 struct result res[] = {
196 { BLOCK, 0 },
197 { BLOCK, 1 },
198 { BLOCK, 2 },
199 { BLOCK, 3 },
200 { BLOCK, 4 },
201 { BLOCK, 5 },
202 { BLOCK, 6 },
203 { BLOCK, 7 },
204 { BLOCK, 8 },
205 { BLOCK, 9 },
206 { BLOCK, 10 },
207 { LITERAL, 1 } };
208 test_sync(buffer1, 1023, buffer2, 1024, 100,
209 res, ARRAY_SIZE(res));
212 /* Now try changing one block at a time, check we get right results. */
213 for (i = 0; i < 1024/128; i++) {
214 unsigned int j;
215 struct result res[8];
217 /* Mess with block. */
218 memcpy(buffer2, buffer1, 1024);
219 buffer2[i * 128]++;
221 for (j = 0; j < ARRAY_SIZE(res); j++) {
222 if (j == i) {
223 res[j].type = LITERAL;
224 res[j].val = 128;
225 } else {
226 res[j].type = BLOCK;
227 res[j].val = j;
231 test_sync(buffer1, 1024, buffer2, 1024, 128,
232 res, ARRAY_SIZE(res));
235 /* Now try shrinking one block at a time, check we get right results. */
236 for (i = 0; i < 1024/128; i++) {
237 unsigned int j;
238 struct result res[8];
240 /* Shrink block. */
241 memcpy(buffer2, buffer1, i * 128 + 64);
242 memcpy(buffer2 + i * 128 + 64, buffer1 + i * 128 + 65,
243 1024 - (i * 128 + 65));
245 for (j = 0; j < ARRAY_SIZE(res); j++) {
246 if (j == i) {
247 res[j].type = LITERAL;
248 res[j].val = 127;
249 } else {
250 res[j].type = BLOCK;
251 res[j].val = j;
255 test_sync(buffer1, 1024, buffer2, 1023, 128,
256 res, ARRAY_SIZE(res));
259 /* Now try shrinking one block at a time, check we get right results. */
260 for (i = 0; i < 1024/128; i++) {
261 unsigned int j;
262 struct result res[8];
264 /* Shrink block. */
265 memcpy(buffer2, buffer1, i * 128 + 64);
266 memcpy(buffer2 + i * 128 + 64, buffer1 + i * 128 + 65,
267 1024 - (i * 128 + 65));
269 for (j = 0; j < ARRAY_SIZE(res); j++) {
270 if (j == i) {
271 res[j].type = LITERAL;
272 res[j].val = 127;
273 } else {
274 res[j].type = BLOCK;
275 res[j].val = j;
279 test_sync(buffer1, 1024, buffer2, 1023, 128,
280 res, ARRAY_SIZE(res));
283 return exit_status();