run.c 7.4 KB

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