MeterLogger
test_heatshrink_dynamic.c
Go to the documentation of this file.
1 #include <ctype.h>
2 #include <assert.h>
3 
4 #include "heatshrink_encoder.h"
5 #include "heatshrink_decoder.h"
6 #include "greatest.h"
7 
8 #if !HEATSHRINK_DYNAMIC_ALLOC
9 #error Must set HEATSHRINK_DYNAMIC_ALLOC to 1 for dynamic allocation test suite.
10 #endif
11 
12 SUITE(encoding);
13 SUITE(decoding);
14 SUITE(integration);
15 
16 #ifdef HEATSHRINK_HAS_THEFT
17 SUITE(properties);
18 #endif
19 
20 static void dump_buf(char *name, uint8_t *buf, uint16_t count) {
21  for (int i=0; i<count; i++) {
22  uint8_t c = (uint8_t)buf[i];
23  printf("%s %d: 0x%02x ('%c')\n", name, i, c, isprint(c) ? c : '.');
24  }
25 }
26 
34  PASS();
35 }
36 
39  uint8_t input[] = {'f', 'o', 'o'};
40  size_t input_size = 0;
41  ASSERT(hse);
46  PASS();
47 }
48 
51  uint8_t output[256];
52  size_t output_size = 0;
54  output, 256, &output_size));
56  NULL, 256, &output_size));
58  output, 256, NULL));
59 
61  PASS();
62 }
63 
66  PASS();
67 }
68 
71  ASSERT(hse);
72  uint8_t input[256];
73  size_t bytes_copied = 0;
74  memset(input, '*', 256);
76  input, 256, &bytes_copied));
77  ASSERT_EQ(256, bytes_copied);
78 
80  PASS();
81 }
82 
85  ASSERT(hse);
86  uint8_t input[512];
87  size_t bytes_copied = 0;
88  memset(input, '*', 512);
90  input, 512, &bytes_copied));
91  ASSERT_EQ(256, bytes_copied);
92 
94  PASS();
95 }
96 
99  uint8_t output[512];
100  size_t output_size = 0;
101 
103  output, 512, &output_size);
106  PASS();
107 }
108 
111  ASSERT(hse);
112  uint8_t input[5];
113  uint8_t output[1024];
114  size_t copied = 0;
115  uint8_t expected[] = { 0x80, 0x40, 0x60, 0x50, 0x38, 0x20 };
116 
117  for (int i=0; i<5; i++) { input[i] = i; }
118  memset(output, 0, 1024);
119  ASSERT_EQ(HSER_SINK_OK, heatshrink_encoder_sink(hse, input, 5, &copied));
120  ASSERT_EQ(5, copied);
121 
122  /* Should get no output yet, since encoder doesn't know input is complete. */
123  copied = 0;
124  HSE_poll_res pres = heatshrink_encoder_poll(hse, output, 1024, &copied);
125  ASSERT_EQ(HSER_POLL_EMPTY, pres);
126  ASSERT_EQ(0, copied);
127 
128  /* Mark input stream as done, to force small input to be processed. */
131 
132  pres = heatshrink_encoder_poll(hse, output, 1024, &copied);
133  ASSERT_EQ(HSER_POLL_EMPTY, pres);
134 
135  for (size_t i=0; i<sizeof(expected); i++) {
136  ASSERT_EQ(expected[i], output[i]);
137  }
138 
140 
142  PASS();
143 }
144 
147  ASSERT(hse);
148  uint8_t input[5];
149  uint8_t output[1024];
150  size_t copied = 0;
151  uint8_t expected[] = {0xb0, 0x80, 0x01, 0x80};
152 
153  for (int i=0; i<5; i++) { input[i] = 'a'; } /* "aaaaa" */
154  memset(output, 0, 1024);
155  ASSERT_EQ(HSER_SINK_OK, heatshrink_encoder_sink(hse, input, 5, &copied));
156  ASSERT_EQ(5, copied);
157 
158  /* Should get no output yet, since encoder doesn't know input is complete. */
159  copied = 0;
160  HSE_poll_res pres = heatshrink_encoder_poll(hse, output, 1024, &copied);
161  ASSERT_EQ(HSER_POLL_EMPTY, pres);
162  ASSERT_EQ(0, copied);
163 
164  /* Mark input stream as done, to force small input to be processed. */
167 
168  pres = heatshrink_encoder_poll(hse, output, 1024, &copied);
169  ASSERT_EQ(HSER_POLL_EMPTY, pres);
170  ASSERT_EQ(4, copied);
171  if (0) dump_buf("output", output, copied);
172  for (size_t i=0; i<copied; i++) ASSERT_EQ(expected[i], output[i]);
173 
175 
177  PASS();
178 }
179 
182  uint8_t input[] = {'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd'};
183  uint8_t output[1024];
184  uint8_t expected[] = {0xb0, 0xd8, 0xac, 0x76, 0x40, 0x1b };
185 
186  size_t copied = 0;
187  memset(output, 0, 1024);
189  input, sizeof(input), &copied);
190  ASSERT_EQ(HSER_SINK_OK, sres);
191  ASSERT_EQ(sizeof(input), copied);
192 
195 
196  ASSERT_EQ(HSER_POLL_EMPTY, heatshrink_encoder_poll(hse, output, 1024, &copied));
197  fres = heatshrink_encoder_finish(hse);
199 
200  if (0) dump_buf("output", output, copied);
201  ASSERT_EQ(sizeof(expected), copied);
202  for (size_t i=0; i<sizeof(expected); i++) ASSERT_EQ(expected[i], output[i]);
204  PASS();
205 }
206 
209  uint8_t input[] = {'a', 'b', 'c', 'd', 'a', 'b', 'c', 'd', 'e'};
210  uint8_t output[1024];
211  uint8_t expected[] = {0xb0, 0xd8, 0xac, 0x76, 0x40, 0x1b, 0xb2, 0x80 };
212  size_t copied = 0;
213  memset(output, 0, 1024);
215  input, sizeof(input), &copied);
216  ASSERT_EQ(HSER_SINK_OK, sres);
217  ASSERT_EQ(sizeof(input), copied);
218 
221 
222  ASSERT_EQ(HSER_POLL_EMPTY, heatshrink_encoder_poll(hse, output, 1024, &copied));
223  fres = heatshrink_encoder_finish(hse);
225 
226  if (0) dump_buf("output", output, copied);
227  ASSERT_EQ(sizeof(expected), copied);
228  for (size_t i=0; i<sizeof(expected); i++) ASSERT_EQ(expected[i], output[i]);
230  PASS();
231 }
232 
233 SUITE(encoding) {
235 
239 
242 
244 
249 }
250 
254  PASS();
255 }
256 
260  PASS();
261 }
262 
264  uint8_t input[] = {0,1,2,3,4,5};
265  size_t count = 0;
267  PASS();
268 }
269 
273  size_t count = 0;
276  PASS();
277 }
278 
280  uint8_t input[] = {0,1,2,3,4,5};
285  PASS();
286 }
287 
289  uint8_t input[] = {0,1,2,3,4,5};
292  size_t count = 0;
293  // Sink as much as will fit
294  HSD_sink_res res = heatshrink_decoder_sink(hsd, input, 6, &count);
295  ASSERT_EQ(HSDR_SINK_OK, res);
296  ASSERT_EQ(1, count);
297 
298  // And now, no more should fit.
299  res = heatshrink_decoder_sink(hsd, &input[count], sizeof(input) - count, &count);
301  ASSERT_EQ(0, count);
303  PASS();
304 }
305 
307  uint8_t input[] = {0,1,2,3,4,5};
310  size_t count = 0;
311  HSD_sink_res res = heatshrink_decoder_sink(hsd, input, 6, &count);
312  ASSERT_EQ(HSDR_SINK_OK, res);
313  ASSERT_EQ(hsd->input_size, 6);
314  ASSERT_EQ(hsd->input_index, 0);
316  PASS();
317 }
318 
320  uint8_t output[256];
321  size_t out_sz = 0;
324  HSD_poll_res res = heatshrink_decoder_poll(hsd, output, 256, &out_sz);
327  PASS();
328 }
329 
331  uint8_t output[256];
332  size_t out_sz = 0;
333  HSD_poll_res res = heatshrink_decoder_poll(NULL, output, 256, &out_sz);
335  PASS();
336 }
337 
339  size_t out_sz = 0;
342  HSD_poll_res res = heatshrink_decoder_poll(hsd, NULL, 256, &out_sz);
345  PASS();
346 }
347 
349  uint8_t output[256];
352  HSD_poll_res res = heatshrink_decoder_poll(hsd, output, 256, NULL);
355  PASS();
356 }
357 
359  uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0 }; //"foo"
360  uint8_t output[4];
362  size_t count = 0;
363 
364  HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, sizeof(input), &count);
365  ASSERT_EQ(HSDR_SINK_OK, sres);
366 
367  size_t out_sz = 0;
368  HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, 4, &out_sz);
369  ASSERT_EQ(HSDR_POLL_EMPTY, pres);
370  ASSERT_EQ(3, out_sz);
371  ASSERT_EQ('f', output[0]);
372  ASSERT_EQ('o', output[1]);
373  ASSERT_EQ('o', output[2]);
374 
376  PASS();
377 }
378 
380  uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0, 0x40, 0x80}; //"foofoo"
381  uint8_t output[6];
383  memset(output, 0, sizeof(*output));
384  size_t count = 0;
385 
386  HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, sizeof(input), &count);
387  ASSERT_EQ(HSDR_SINK_OK, sres);
388 
389  size_t out_sz = 0;
390  (void)heatshrink_decoder_poll(hsd, output, 6, &out_sz);
391 
392  if (0) dump_buf("output", output, out_sz);
393  ASSERT_EQ(6, out_sz);
394  ASSERT_EQ('f', output[0]);
395  ASSERT_EQ('o', output[1]);
396  ASSERT_EQ('o', output[2]);
397  ASSERT_EQ('f', output[3]);
398  ASSERT_EQ('o', output[4]);
399  ASSERT_EQ('o', output[5]);
400 
402  PASS();
403 }
404 
406  /* "aaaaa" == (literal, 1), ('a'), (backref, 1 back, 4 bytes) */
407  uint8_t input[] = {0xb0, 0x80, 0x01, 0x80};
408  uint8_t output[6];
409  uint8_t expected[] = {'a', 'a', 'a', 'a', 'a'};
411  size_t count = 0;
412 
413  HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, sizeof(input), &count);
414  ASSERT_EQ(HSDR_SINK_OK, sres);
415 
416  size_t out_sz = 0;
417  (void)heatshrink_decoder_poll(hsd, output, sizeof(output), &out_sz);
418 
419  if (0) dump_buf("output", output, out_sz);
420  ASSERT_EQ(sizeof(expected), out_sz);
421  for (size_t i=0; i<sizeof(expected); i++) ASSERT_EQ(expected[i], output[i]);
422 
424  PASS();
425 }
426 
428  uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0, 0x40, 0x80};
429  uint8_t output[1];
431  size_t count = 0;
432 
433  HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, sizeof(input), &count);
434  ASSERT_EQ(HSDR_SINK_OK, sres);
435 
436  size_t out_sz = 0;
437  HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, 1, &out_sz);
438  ASSERT_EQ(HSDR_POLL_MORE, pres);
439  ASSERT_EQ(1, out_sz);
440  ASSERT_EQ('f', output[0]);
441 
443  PASS();
444 }
445 
447  uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0, 0x40, 0x80}; //"foofoo"
448  uint8_t output[4];
450  memset(output, 0, sizeof(*output));
451  size_t count = 0;
452 
453  HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, 6, &count);
454  ASSERT_EQ(HSDR_SINK_OK, sres);
455 
456  size_t out_sz = 0;
457  HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, 4, &out_sz);
458  ASSERT_EQ(HSDR_POLL_MORE, pres);
459  ASSERT_EQ(4, out_sz);
460  ASSERT_EQ('f', output[0]);
461  ASSERT_EQ('o', output[1]);
462  ASSERT_EQ('o', output[2]);
463  ASSERT_EQ('f', output[3]);
464 
466  PASS();
467 }
468 
470  uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0, 0x40, 0x80}; //"foofoo"
471  uint8_t output[7];
473  memset(output, 0, sizeof(*output));
474  size_t count = 0;
475 
476  HSD_sink_res sres;
477  for (int i=0; i<6; i++) {
478  sres = heatshrink_decoder_sink(hsd, &input[i], 1, &count);
479  ASSERT_EQ(HSDR_SINK_OK, sres);
480  }
482 
483  size_t out_sz = 0;
484  HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, 7, &out_sz);
485  ASSERT_EQ(6, out_sz);
486  ASSERT_EQ(HSDR_POLL_EMPTY, pres);
487  ASSERT_EQ('f', output[0]);
488  ASSERT_EQ('o', output[1]);
489  ASSERT_EQ('o', output[2]);
490  ASSERT_EQ('f', output[3]);
491  ASSERT_EQ('o', output[4]);
492  ASSERT_EQ('o', output[5]);
493 
495  PASS();
496 }
497 
500 
503 
505  PASS();
506 }
507 
509  uint8_t input[] = {0xb3, 0x5b, 0xed, 0xe0, 0x40, 0x80}; //"foofoo"
510 
511  uint8_t output[7];
513  memset(output, 0, sizeof(*output));
514  size_t count = 0;
515 
516  HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, sizeof(input), &count);
517  ASSERT_EQ(HSDR_SINK_OK, sres);
518 
519  size_t out_sz = 0;
520  HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, sizeof(output), &out_sz);
521  ASSERT_EQ(HSDR_POLL_EMPTY, pres);
522  ASSERT_EQ(6, out_sz);
523  ASSERT_EQ('f', output[0]);
524  ASSERT_EQ('o', output[1]);
525  ASSERT_EQ('o', output[2]);
526  ASSERT_EQ('f', output[3]);
527  ASSERT_EQ('o', output[4]);
528  ASSERT_EQ('o', output[5]);
529 
532 
534  PASS();
535 }
536 
537 TEST gen(void) {
539  uint8_t input[] = {'a', 'a', 'a', 'a', 'a'};
540  uint8_t output[1024];
541  size_t copied = 0;
542  memset(output, 0, 1024);
544  input, sizeof(input), &copied);
545  ASSERT_EQ(HSER_SINK_OK, sres);
546  ASSERT_EQ(sizeof(input), copied);
547 
550 
551  ASSERT_EQ(HSER_POLL_EMPTY, heatshrink_encoder_poll(hse, output, 1024, &copied));
552  fres = heatshrink_encoder_finish(hse);
554  if (0) {
555  printf("{");
556  for (size_t i=0; i<copied; i++) printf("0x%02x, ", output[i]);
557  printf("}\n");
558  }
560  PASS();
561 }
562 
564  uint8_t input[512];
565  memset(input, 0xff, 256);
566 
567  uint8_t output[1024];
569  ASSERT(hsd);
570 
571  /* Confirm that no byte of trailing context can lead to
572  * heatshrink_decoder_finish erroneously returning HSDR_FINISH_MORE
573  * when heatshrink_decoder_poll will yield 0 bytes.
574  *
575  * Before 0.3.1, a final byte of 0xFF could potentially cause
576  * this to happen, if at exactly the byte boundary. */
577  for (uint16_t byte = 0; byte < 256; byte++) {
578  for (int i = 1; i < 512; i++) {
579  input[i] = byte;
581  memset(output, 0, sizeof(*output));
582  size_t count = 0;
583 
584  HSD_sink_res sres = heatshrink_decoder_sink(hsd, input, i, &count);
585  ASSERT_EQ(HSDR_SINK_OK, sres);
586 
587  size_t out_sz = 0;
588  HSD_poll_res pres = heatshrink_decoder_poll(hsd, output, sizeof(output), &out_sz);
589  ASSERT_EQ(HSDR_POLL_EMPTY, pres);
590 
593  input[i] = 0xff;
594  }
595  }
596 
598  PASS();
599 }
600 
601 SUITE(decoding) {
604 
610 
611  RUN_TEST(gen);
612 
623 
626 
627  // Regressions
629 }
630 
631 typedef struct {
632  uint8_t log_lvl;
633  uint8_t window_sz2;
634  uint8_t lookahead_sz2;
636 } cfg_info;
637 
638 static int compress_and_expand_and_check(uint8_t *input, uint32_t input_size, cfg_info *cfg) {
640  cfg->lookahead_sz2);
642  cfg->window_sz2, cfg->lookahead_sz2);
643  size_t comp_sz = input_size + (input_size/2) + 4;
644  size_t decomp_sz = input_size + (input_size/2) + 4;
645  uint8_t *comp = malloc(comp_sz);
646  uint8_t *decomp = malloc(decomp_sz);
647  if (comp == NULL) FAILm("malloc fail");
648  if (decomp == NULL) FAILm("malloc fail");
649  memset(comp, 0, comp_sz);
650  memset(decomp, 0, decomp_sz);
651 
652  size_t count = 0;
653 
654  if (cfg->log_lvl > 1) {
655  printf("\n^^ COMPRESSING\n");
656  dump_buf("input", input, input_size);
657  }
658 
659  size_t sunk = 0;
660  size_t polled = 0;
661  while (sunk < input_size) {
662  ASSERT(heatshrink_encoder_sink(hse, &input[sunk], input_size - sunk, &count) >= 0);
663  sunk += count;
664  if (cfg->log_lvl > 1) printf("^^ sunk %zd\n", count);
665  if (sunk == input_size) {
667  }
668 
669  HSE_poll_res pres;
670  do { /* "turn the crank" */
671  pres = heatshrink_encoder_poll(hse, &comp[polled], comp_sz - polled, &count);
672  ASSERT(pres >= 0);
673  polled += count;
674  if (cfg->log_lvl > 1) printf("^^ polled %zd\n", count);
675  } while (pres == HSER_POLL_MORE);
676  ASSERT_EQ(HSER_POLL_EMPTY, pres);
677  if (polled >= comp_sz) FAILm("compression should never expand that much");
678  if (sunk == input_size) {
680  }
681  }
682  if (cfg->log_lvl > 0) printf("in: %u compressed: %zu ", input_size, polled);
683  size_t compressed_size = polled;
684  sunk = 0;
685  polled = 0;
686 
687  if (cfg->log_lvl > 1) {
688  printf("\n^^ DECOMPRESSING\n");
689  dump_buf("comp", comp, compressed_size);
690  }
691  while (sunk < compressed_size) {
692  ASSERT(heatshrink_decoder_sink(hsd, &comp[sunk], compressed_size - sunk, &count) >= 0);
693  sunk += count;
694  if (cfg->log_lvl > 1) printf("^^ sunk %zd\n", count);
695  if (sunk == compressed_size) {
697  }
698 
699  HSD_poll_res pres;
700  do {
701  pres = heatshrink_decoder_poll(hsd, &decomp[polled],
702  decomp_sz - polled, &count);
703  ASSERT(pres >= 0);
704  ASSERT(count > 0);
705  polled += count;
706  if (cfg->log_lvl > 1) printf("^^ polled %zd\n", count);
707  } while (pres == HSDR_POLL_MORE);
708  ASSERT_EQ(HSDR_POLL_EMPTY, pres);
709  if (sunk == compressed_size) {
712  }
713 
714  if (polled > input_size) {
715  printf("\nExpected %zd, got %zu\n", (size_t)input_size, polled);
716  FAILm("Decompressed data is larger than original input");
717  }
718  }
719  if (cfg->log_lvl > 0) printf("decompressed: %zu\n", polled);
720  if (polled != input_size) {
721  FAILm("Decompressed length does not match original input length");
722  }
723 
724  if (cfg->log_lvl > 1) dump_buf("decomp", decomp, polled);
725  for (uint32_t i=0; i<input_size; i++) {
726  if (input[i] != decomp[i]) {
727  printf("*** mismatch at %d\n", i);
728  if (0) {
729  for (uint32_t j=0; j<=/*i*/ input_size; j++) {
730  printf("in[%d] == 0x%02x ('%c') => out[%d] == 0x%02x ('%c') %c\n",
731  j, input[j], isprint(input[j]) ? input[j] : '.',
732  j, decomp[j], isprint(decomp[j]) ? decomp[j] : '.',
733  input[j] == decomp[j] ? ' ' : 'X');
734  }
735  }
736  }
737  ASSERT_EQ(input[i], decomp[i]);
738  }
739  free(comp);
740  free(decomp);
743  PASS();
744 }
745 
747  uint8_t input[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
748  'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
749  's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
750  cfg_info cfg;
751  cfg.log_lvl = 0;
752  cfg.window_sz2 = 8;
753  cfg.lookahead_sz2 = 3;
754  cfg.decoder_input_buffer_size = 256;
755  return compress_and_expand_and_check(input, sizeof(input), &cfg);
756 }
757 
759  uint8_t input[] = {'a', 'b', 'c', 'a', 'b', 'c', 'd', 'a', 'b',
760  'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e', 'f',
761  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b',
762  'c', 'd', 'e', 'f', 'g', 'h'};
763  cfg_info cfg;
764  cfg.log_lvl = 0;
765  cfg.window_sz2 = 8;
766  cfg.lookahead_sz2 = 3;
767  cfg.decoder_input_buffer_size = 256;
768  return compress_and_expand_and_check(input, sizeof(input), &cfg);
769 }
770 
774  uint8_t input[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
775  'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r',
776  's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
777  uint8_t comp[60];
778  uint8_t decomp[60];
779  size_t count = 0;
780  int log = 0;
781 
782  if (log) dump_buf("input", input, sizeof(input));
783  for (uint32_t i=0; i<sizeof(input); i++) {
784  ASSERT(heatshrink_encoder_sink(hse, &input[i], 1, &count) >= 0);
785  }
787 
788  size_t packed_count = 0;
789  do {
790  ASSERT(heatshrink_encoder_poll(hse, &comp[packed_count], 1, &count) >= 0);
791  packed_count += count;
793 
794  if (log) dump_buf("comp", comp, packed_count);
795  for (uint32_t i=0; i<packed_count; i++) {
796  HSD_sink_res sres = heatshrink_decoder_sink(hsd, &comp[i], 1, &count);
797  //printf("sres is %d\n", sres);
798  ASSERT(sres >= 0);
799  }
800 
801  for (uint32_t i=0; i<sizeof(input); i++) {
802  ASSERT(heatshrink_decoder_poll(hsd, &decomp[i], 1, &count) >= 0);
803  }
804 
805  if (log) dump_buf("decomp", decomp, sizeof(input));
806  for (uint32_t i=0; i<sizeof(input); i++) ASSERT_EQ(input[i], decomp[i]);
809  PASS();
810 }
811 
815  uint8_t input[] = {'a', 'b', 'c', 'a', 'b', 'c', 'd', 'a', 'b',
816  'c', 'd', 'e', 'a', 'b', 'c', 'd', 'e', 'f',
817  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'a', 'b',
818  'c', 'd', 'e', 'f', 'g', 'h'};
819  uint8_t comp[60];
820  uint8_t decomp[60];
821  size_t count = 0;
822  int log = 0;
823 
824  if (log) dump_buf("input", input, sizeof(input));
825  for (uint32_t i=0; i<sizeof(input); i++) {
826  ASSERT(heatshrink_encoder_sink(hse, &input[i], 1, &count) >= 0);
827  }
829 
830  size_t packed_count = 0;
831  do {
832  ASSERT(heatshrink_encoder_poll(hse, &comp[packed_count], 1, &count) >= 0);
833  packed_count += count;
835 
836  if (log) dump_buf("comp", comp, packed_count);
837  for (uint32_t i=0; i<packed_count; i++) {
838  HSD_sink_res sres = heatshrink_decoder_sink(hsd, &comp[i], 1, &count);
839  //printf("sres is %d\n", sres);
840  ASSERT(sres >= 0);
841  }
842 
843  for (uint32_t i=0; i<sizeof(input); i++) {
844  ASSERT(heatshrink_decoder_poll(hsd, &decomp[i], 1, &count) >= 0);
845  }
846 
847  if (log) dump_buf("decomp", decomp, sizeof(input));
848  for (uint32_t i=0; i<sizeof(input); i++) ASSERT_EQ(input[i], decomp[i]);
851  PASS();
852 }
853 
854 static void fill_with_pseudorandom_letters(uint8_t *buf, uint32_t size, uint32_t seed) {
855  uint64_t rn = 9223372036854775783; /* prime under 2^64 */
856  for (uint32_t i=0; i<size; i++) {
857  rn = rn*seed + seed;
858  buf[i] = (rn % 26) + 'a';
859  }
860 }
861 
862 TEST pseudorandom_data_should_match(uint32_t size, uint32_t seed, cfg_info *cfg) {
863  uint8_t input[size];
864  if (cfg->log_lvl > 0) {
865  printf("\n-- size %u, seed %u, input buf %zu\n",
866  size, seed, cfg->decoder_input_buffer_size);
867  }
868  fill_with_pseudorandom_letters(input, size, seed);
869  return compress_and_expand_and_check(input, size, cfg);
870 }
871 
873  int size = 5;
874  uint8_t input[size];
875  cfg_info cfg;
876  cfg.log_lvl = 0;
877  cfg.window_sz2 = 8;
878  cfg.lookahead_sz2 = 3;
880  for (uint16_t i=0; i<size; i++) input[i] = 'a' + (i % 26);
881  if (compress_and_expand_and_check(input, size, &cfg) != 0) return -1;
882  PASS();
883 }
884 
886  /* Searching was scanning the entire context buffer, not just
887  * the maximum range addressable by the backref index.*/
888  uint32_t size = 337;
889  uint32_t seed = 3;
890  uint8_t input[size];
891  fill_with_pseudorandom_letters(input, size, seed);
892  cfg_info cfg;
893  cfg.log_lvl = 0;
894  cfg.window_sz2 = 8;
895  cfg.lookahead_sz2 = 3;
896  cfg.decoder_input_buffer_size = 64; // 1
897  return compress_and_expand_and_check(input, size, &cfg);
898 }
899 
901  /* Failured when indexed, cause unknown.
902  *
903  * This has something to do with bad data at the very last
904  * byte being indexed, due to spillover. */
905  uint32_t size = 507;
906  uint32_t seed = 3;
907  uint8_t input[size];
908  fill_with_pseudorandom_letters(input, size, seed);
909  cfg_info cfg;
910  cfg.log_lvl = 0;
911  cfg.window_sz2 = 8;
912  cfg.lookahead_sz2 = 3;
913  cfg.decoder_input_buffer_size = 64;
914  return compress_and_expand_and_check(input, size, &cfg);
915 }
916 
918  /* Regression: An input buffer of 64k should not cause an
919  * overflow that leads to an infinite loop. */
920  uint32_t size = 64 * 1024;
921  uint32_t seed = 1;
922  uint8_t input[size];
923  fill_with_pseudorandom_letters(input, size, seed);
924  cfg_info cfg;
925  cfg.log_lvl = 0;
926  cfg.window_sz2 = 8;
927  cfg.lookahead_sz2 = 3;
928  cfg.decoder_input_buffer_size = 64;
929  return compress_and_expand_and_check(input, size, &cfg);
930 }
931 
932 SUITE(integration) {
937 
938  // Regressions from fuzzing
943 
944 #if __STDC_VERSION__ >= 19901L
945  printf("\n\nFuzzing (single-byte sizes):\n");
946  for (uint8_t lsize=3; lsize < 8; lsize++) {
947  for (uint32_t size=1; size < 128*1024L; size <<= 1) {
948  if (GREATEST_IS_VERBOSE()) printf(" -- size %u\n", size);
949  for (uint16_t ibs=32; ibs<=8192; ibs <<= 1) { /* input buffer size */
950  if (GREATEST_IS_VERBOSE()) printf(" -- input buffer %u\n", ibs);
951  for (uint32_t seed=1; seed<=10; seed++) {
952  if (GREATEST_IS_VERBOSE()) printf(" -- seed %u\n", seed);
953  cfg_info cfg;
954  cfg.log_lvl = 0;
955  cfg.window_sz2 = 8;
956  cfg.lookahead_sz2 = lsize;
957  cfg.decoder_input_buffer_size = ibs;
959  }
960  }
961  }
962  }
963 
964  printf("\nFuzzing (multi-byte sizes):\n");
965  for (uint8_t lsize=6; lsize < 9; lsize++) {
966  for (uint32_t size=1; size < 128*1024L; size <<= 1) {
967  if (GREATEST_IS_VERBOSE()) printf(" -- size %u\n", size);
968  for (uint16_t ibs=32; ibs<=8192; ibs <<= 1) { /* input buffer size */
969  if (GREATEST_IS_VERBOSE()) printf(" -- input buffer %u\n", ibs);
970  for (uint32_t seed=1; seed<=10; seed++) {
971  if (GREATEST_IS_VERBOSE()) printf(" -- seed %u\n", seed);
972  cfg_info cfg;
973  cfg.log_lvl = 0;
974  cfg.window_sz2 = 11;
975  cfg.lookahead_sz2 = lsize;
976  cfg.decoder_input_buffer_size = ibs;
978  }
979  }
980  }
981  }
982 
983 #endif
984 }
985 
986 /* Add all the definitions that need to be in the test runner's main file. */
988 
989 int main(int argc, char **argv) {
990  GREATEST_MAIN_BEGIN(); /* command-line arguments, initialization. */
991  RUN_SUITE(encoding);
992  RUN_SUITE(decoding);
993  RUN_SUITE(integration);
994  #ifdef HEATSHRINK_HAS_THEFT
995  RUN_SUITE(properties);
996  #endif
997  GREATEST_MAIN_END(); /* display results */
998 }
#define free(x)
Definition: platform.h:20
int main(int argc, char **argv)
size_t decoder_input_buffer_size
TEST encoder_poll_should_reject_nulls(void)
static int compress_and_expand_and_check(uint8_t *input, uint32_t input_size, cfg_info *cfg)
HSD_poll_res heatshrink_decoder_poll(heatshrink_decoder *hsd, uint8_t *out_buf, size_t out_buf_size, size_t *output_size)
uint16_t size
TEST small_input_buffer_should_not_impact_decoder_correctness(void)
#define memset(x, a, b)
Definition: platform.h:21
TEST decoder_poll_should_reject_null_output_buffer(void)
#define RUN_SUITE
Definition: greatest.h:568
TEST decoder_should_not_get_stuck_with_finish_yielding_MORE_but_0_bytes_output_from_poll(void)
#define HEATSHRINK_MAX_WINDOW_BITS
TEST decoder_poll_should_expand_short_literal_and_backref_when_fed_input_byte_by_byte(void)
#define RUN_TEST
Definition: greatest.h:566
#define NULL
Definition: def.h:47
#define PASS
Definition: greatest.h:577
#define TEST
Definition: greatest.h:564
#define HEATSHRINK_MIN_WINDOW_BITS
TEST decoder_poll_should_expand_short_literal(void)
heatshrink_decoder * heatshrink_decoder_alloc(uint16_t input_buffer_size, uint8_t window_sz2, uint8_t lookahead_sz2)
TEST decoder_sink_should_reject_excessively_large_input(void)
TEST pseudorandom_data_should_match(uint32_t size, uint32_t seed, cfg_info *cfg)
TEST encoder_poll_should_detect_repeated_substring_and_preserve_trailing_literal(void)
TEST encoder_poll_should_detect_repeated_substring(void)
TEST encoder_sink_should_accept_partial_input_when_some_will_fit(void)
#define malloc(x)
Definition: platform.h:19
TEST decoder_sink_should_sink_data_when_preconditions_hold(void)
HSE_sink_res
#define ASSERT
Definition: greatest.h:569
GREATEST_MAIN_DEFS()
TEST decoder_finish_should_note_when_done(void)
HSD_poll_res
TEST decoder_sink_should_reject_null_count_pointer(void)
#define isprint(c)
Definition: ip_addr.c:115
void heatshrink_decoder_free(heatshrink_decoder *hsd)
heatshrink_encoder * heatshrink_encoder_alloc(uint8_t window_sz2, uint8_t lookahead_sz2)
TEST decoder_poll_should_reject_null_output_size_pointer(void)
HSD_finish_res heatshrink_decoder_finish(heatshrink_decoder *hsd)
TEST decoder_poll_should_suspend_if_out_of_space_in_output_buffer_during_backref_expansion(void)
SUITE(encoding)
TEST decoder_sink_should_reject_null_input_pointer(void)
#define GREATEST_IS_VERBOSE()
Definition: greatest.h:237
HSE_finish_res
static heatshrink_decoder hsd
HSD_sink_res
void heatshrink_encoder_free(heatshrink_encoder *hse)
static void dump_buf(char *name, uint8_t *buf, uint16_t count)
void heatshrink_decoder_reset(heatshrink_decoder *hsd)
TEST encoder_sink_should_accept_input_when_it_will_fit(void)
TEST data_without_duplication_should_match_with_absurdly_tiny_buffers(void)
TEST regression_backreference_counters_should_not_roll_over(void)
HSE_finish_res heatshrink_encoder_finish(heatshrink_encoder *hse)
HSD_sink_res heatshrink_decoder_sink(heatshrink_decoder *hsd, uint8_t *in_buf, size_t size, size_t *input_size)
TEST decoder_alloc_should_reject_zero_byte_input_buffer(void)
TEST encoder_sink_should_reject_nulls(void)
TEST decoder_poll_should_expand_short_literal_and_backref(void)
#define ASSERT_EQ
Definition: greatest.h:572
HSE_poll_res heatshrink_encoder_poll(heatshrink_encoder *hse, uint8_t *out_buf, size_t out_buf_size, size_t *output_size)
HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse, uint8_t *in_buf, size_t size, size_t *input_size)
TEST encoder_alloc_should_reject_invalid_arguments(void)
static void fill_with_pseudorandom_letters(uint8_t *buf, uint32_t size, uint32_t seed)
TEST sixty_four_k(void)
#define RUN_TESTp
Definition: greatest.h:588
TEST decoder_poll_should_suspend_if_out_of_space_in_output_buffer_during_literal_expansion(void)
TEST encoder_should_emit_data_without_repetitions_as_literal_sequence(void)
TEST gen(void)
TEST encoder_finish_should_reject_nulls(void)
TEST decoder_alloc_should_reject_excessively_small_window(void)
TEST data_with_simple_repetition_should_compress_and_decompress_properly(void)
TEST encoder_should_emit_series_of_same_byte_as_literal_then_backref(void)
TEST decoder_poll_should_expand_short_self_overlapping_backref(void)
TEST decoder_sink_should_reject_null_hsd_pointer(void)
HSD_finish_res
TEST encoder_poll_should_indicate_when_no_input_is_provided(void)
TEST regression_index_fail(void)
#define printf(...)
Definition: platform.h:13
TEST decoder_finish_should_reject_null_input(void)
#define GREATEST_MAIN_BEGIN()
Definition: greatest.h:502
TEST decoder_poll_should_reject_null_hsd(void)
#define GREATEST_MAIN_END()
Definition: greatest.h:543
TEST decoder_poll_should_return_empty_if_empty(void)
#define HEATSHRINK_MIN_LOOKAHEAD_BITS
TEST data_without_duplication_should_match(void)
#define FAILm
Definition: greatest.h:581
static heatshrink_encoder hse
TEST data_with_simple_repetition_should_match_with_absurdly_tiny_buffers(void)
HSE_poll_res