X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fcrcsync%2Ftest%2Fapi.c;fp=ccan%2Fcrcsync%2Ftest%2Fapi.c;h=af7ce558eabc43e1f983b81499115591bfc376f4;hp=0000000000000000000000000000000000000000;hb=94ff9fc87d90173145772a41f79987988f9f0972;hpb=c6a86ac78efbec284b444876a9ea2fbbf7e48033 diff --git a/ccan/crcsync/test/api.c b/ccan/crcsync/test/api.c new file mode 100644 index 00000000..af7ce558 --- /dev/null +++ b/ccan/crcsync/test/api.c @@ -0,0 +1,263 @@ +#include "crcsync/crcsync.h" +#include "crcsync/crcsync.c" +#include "tap/tap.h" +#include +#include + +/* FIXME: ccanize. */ +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct result { + enum { + LITERAL, BLOCK + } type; + /* Block number, or length of literal. */ + size_t val; +}; + +static inline size_t num_blocks(size_t len, size_t block_size) +{ + return (len + block_size - 1) / block_size; +} + +static void check_finalized_result(size_t curr_literal, + const struct result results[], + size_t num_results, + size_t *curr_result) +{ + if (curr_literal == 0) + return; + ok1(*curr_result < num_results); + ok1(results[*curr_result].type == LITERAL); + ok1(results[*curr_result].val == curr_literal); + (*curr_result)++; +} + +static void check_result(long result, + size_t *curr_literal, + const struct result results[], size_t num_results, + size_t *curr_result) +{ + /* We append multiple literals into one. */ + if (result >= 0) { + *curr_literal += result; + return; + } + + /* Check outstanding literals. */ + if (*curr_literal) { + check_finalized_result(*curr_literal, results, num_results, + curr_result); + *curr_literal = 0; + } + + ok1(*curr_result < num_results); + ok1(results[*curr_result].type == BLOCK); + ok1(results[*curr_result].val == -result - 1); + (*curr_result)++; +} + +/* Start with buffer1 and sync to buffer2. */ +static void test_sync(const char *buffer1, size_t len1, + const char *buffer2, size_t len2, + size_t block_size, + const struct result results[], size_t num_results) +{ + struct crc_context *ctx; + size_t used, ret, i, curr_literal = 0; + long result; + uint32_t crcs[num_blocks(len1, block_size)]; + + crc_of_blocks(buffer1, len1, block_size, 32, crcs); + ctx = crc_context_new(block_size, 32, crcs, ARRAY_SIZE(crcs)); + + for (used = 0, i = 0; used < len2; used += ret) { + ret = crc_read_block(ctx, &result, buffer2+used, len2-used); + + check_result(result, &curr_literal, results, num_results, &i); + } + + while ((result = crc_read_flush(ctx)) != 0) + check_result(result, &curr_literal, results, num_results, &i); + + check_finalized_result(curr_literal, results, num_results, &i); + + /* We must have achieved everything we expected. */ + ok1(i == num_results); + crc_context_free(ctx); +} + +int main(int argc, char *argv[]) +{ + char *buffer1, *buffer2; + unsigned int i; + uint32_t crcs1[12], crcs2[12]; + + plan_tests(733); + + buffer1 = calloc(1024, 1); + buffer2 = calloc(1024, 1); + + /* Truncated end block test. */ + crcs1[11] = 0xdeadbeef; + crc_of_blocks(buffer1, 1024, 100, 32, crcs1); + ok1(crcs1[11] == 0xdeadbeef); + crc_of_blocks(buffer2, 1024, 100, 32, crcs2); + ok1(memcmp(crcs1, crcs2, sizeof(crcs1[0])*11) == 0); + + /* Fill with non-zero pattern, retest. */ + for (i = 0; i < 1024; i++) + buffer1[i] = buffer2[i] = i + i/128; + + crcs1[11] = 0xdeadbeef; + crc_of_blocks(buffer1, 1024, 100, 32, crcs1); + ok1(crcs1[11] == 0xdeadbeef); + crc_of_blocks(buffer2, 1024, 100, 32, crcs2); + ok1(memcmp(crcs1, crcs2, sizeof(crcs1[0])*11) == 0); + + /* Check that it correctly masks bits. */ + crc_of_blocks(buffer1, 1024, 128, 32, crcs1); + crc_of_blocks(buffer2, 1024, 128, 8, crcs2); + for (i = 0; i < 1024/128; i++) + ok1(crcs2[i] == (crcs1[i] & 0xFF)); + + /* Now test the "exact match" "round blocks" case. */ + { + struct result res[] = { + { BLOCK, 0 }, + { BLOCK, 1 }, + { BLOCK, 2 }, + { BLOCK, 3 }, + { BLOCK, 4 }, + { BLOCK, 5 }, + { BLOCK, 6 }, + { BLOCK, 7 } }; + test_sync(buffer1, 1024, buffer2, 1024, 128, + res, ARRAY_SIZE(res)); + } + + /* Now test the "exact match" with end block case. */ + { + struct result res[] = { + { BLOCK, 0 }, + { BLOCK, 1 }, + { BLOCK, 2 }, + { BLOCK, 3 }, + { BLOCK, 4 }, + { BLOCK, 5 }, + { BLOCK, 6 }, + { BLOCK, 7 }, + { BLOCK, 8 }, + { BLOCK, 9 }, + { BLOCK, 10 } }; + test_sync(buffer1, 1024, buffer2, 1024, 100, + res, ARRAY_SIZE(res)); + } + + /* Now test the "one byte append" "round blocks" case. */ + { + struct result res[] = { + { BLOCK, 0 }, + { BLOCK, 1 }, + { BLOCK, 2 }, + { BLOCK, 3 }, + { BLOCK, 4 }, + { BLOCK, 5 }, + { BLOCK, 6 }, + { LITERAL, 1 } }; + test_sync(buffer1, 1024-128, buffer2, 1024-127, 128, + res, ARRAY_SIZE(res)); + } + + /* Now test the "one byte append" with end block case. */ + { + struct result res[] = { + { BLOCK, 0 }, + { BLOCK, 1 }, + { BLOCK, 2 }, + { BLOCK, 3 }, + { BLOCK, 4 }, + { BLOCK, 5 }, + { BLOCK, 6 }, + { BLOCK, 7 }, + { BLOCK, 8 }, + { BLOCK, 9 }, + { BLOCK, 10 }, + { LITERAL, 1 } }; + test_sync(buffer1, 1023, buffer2, 1024, 100, + res, ARRAY_SIZE(res)); + } + + /* Now try changing one block at a time, check we get right results. */ + for (i = 0; i < 1024/128; i++) { + unsigned int j; + struct result res[8]; + + /* Mess with block. */ + memcpy(buffer2, buffer1, 1024); + buffer2[i * 128]++; + + for (j = 0; j < ARRAY_SIZE(res); j++) { + if (j == i) { + res[j].type = LITERAL; + res[j].val = 128; + } else { + res[j].type = BLOCK; + res[j].val = j; + } + } + + test_sync(buffer1, 1024, buffer2, 1024, 128, + res, ARRAY_SIZE(res)); + } + + /* Now try shrinking one block at a time, check we get right results. */ + for (i = 0; i < 1024/128; i++) { + unsigned int j; + struct result res[8]; + + /* Shrink block. */ + memcpy(buffer2, buffer1, i * 128 + 64); + memcpy(buffer2 + i * 128 + 64, buffer1 + i * 128 + 65, + 1024 - (i * 128 + 65)); + + for (j = 0; j < ARRAY_SIZE(res); j++) { + if (j == i) { + res[j].type = LITERAL; + res[j].val = 127; + } else { + res[j].type = BLOCK; + res[j].val = j; + } + } + + test_sync(buffer1, 1024, buffer2, 1023, 128, + res, ARRAY_SIZE(res)); + } + + /* Now try shrinking one block at a time, check we get right results. */ + for (i = 0; i < 1024/128; i++) { + unsigned int j; + struct result res[8]; + + /* Shrink block. */ + memcpy(buffer2, buffer1, i * 128 + 64); + memcpy(buffer2 + i * 128 + 64, buffer1 + i * 128 + 65, + 1024 - (i * 128 + 65)); + + for (j = 0; j < ARRAY_SIZE(res); j++) { + if (j == i) { + res[j].type = LITERAL; + res[j].val = 127; + } else { + res[j].type = BLOCK; + res[j].val = j; + } + } + + test_sync(buffer1, 1024, buffer2, 1023, 128, + res, ARRAY_SIZE(res)); + } + + return exit_status(); +}