| // Copyright 2017 The Puffs Authors. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| /* |
| This test program is typically run indirectly, by the "puffs test" or "puffs |
| bench" commands. These commands take an optional "-mimic" flag to check that |
| Puffs' output mimics (i.e. exactly matches) other libraries' output, such as |
| giflib for GIF, libpng for PNG, etc. |
| |
| To manually run this test: |
| |
| for cc in clang gcc; do |
| $cc -std=c99 -Wall -Werror flate.c && ./a.out |
| rm -f a.out |
| done |
| |
| Each edition should print "PASS", amongst other information, and exit(0). |
| |
| Add the "puffs mimic cflags" (everything after the colon below) to the C |
| compiler flags (after the .c file) to run the mimic tests. |
| |
| To manually run the benchmarks, replace "-Wall -Werror" with "-O3" and replace |
| the first "./a.out" with "./a.out -bench". Combine these changes with the |
| "puffs mimic cflags" to run the mimic benchmarks. |
| */ |
| |
| // !! puffs mimic cflags: -DPUFFS_MIMIC -lz |
| |
| #include "../../../gen/c/std/flate.c" |
| #include "../testlib/testlib.c" |
| |
| const char* proc_filename = "std/flate.c"; |
| |
| // ---------------- Golden Tests |
| |
| // The src_offset0 and src_offset1 magic numbers come from: |
| // |
| // go run script/extract-flate-offsets.go test/testdata/*.gz |
| // |
| // The empty comments forces clang-format to place one element per line. |
| |
| golden_test checksum_midsummer_gt = { |
| .src_filename = "../../testdata/midsummer.txt", // |
| }; |
| |
| golden_test checksum_pi_gt = { |
| .src_filename = "../../testdata/pi.txt", // |
| }; |
| |
| golden_test flate_256_bytes_gt = { |
| .want_filename = "../../testdata/artificial/256.bytes", // |
| .src_filename = "../../testdata/artificial/256.bytes.gz", // |
| .src_offset0 = 20, // |
| .src_offset1 = 281, // |
| }; |
| |
| golden_test flate_midsummer_gt = { |
| .want_filename = "../../testdata/midsummer.txt", // |
| .src_filename = "../../testdata/midsummer.txt.gz", // |
| .src_offset0 = 24, // |
| .src_offset1 = 5166, // |
| }; |
| |
| golden_test flate_pi_gt = { |
| .want_filename = "../../testdata/pi.txt", // |
| .src_filename = "../../testdata/pi.txt.gz", // |
| .src_offset0 = 17, // |
| .src_offset1 = 48335, // |
| }; |
| |
| golden_test flate_romeo_gt = { |
| .want_filename = "../../testdata/romeo.txt", // |
| .src_filename = "../../testdata/romeo.txt.gz", // |
| .src_offset0 = 20, // |
| .src_offset1 = 550, // |
| }; |
| |
| golden_test flate_romeo_fixed_gt = { |
| .want_filename = "../../testdata/romeo.txt", // |
| .src_filename = "../../testdata/romeo.txt.fixed-huff.flate", // |
| }; |
| |
| golden_test gzip_midsummer_gt = { |
| .want_filename = "../../testdata/midsummer.txt", // |
| .src_filename = "../../testdata/midsummer.txt.gz", // |
| }; |
| |
| golden_test gzip_pi_gt = { |
| .want_filename = "../../testdata/pi.txt", // |
| .src_filename = "../../testdata/pi.txt.gz", // |
| }; |
| |
| golden_test zlib_midsummer_gt = { |
| .want_filename = "../../testdata/midsummer.txt", // |
| .src_filename = "../../testdata/midsummer.txt.zlib", // |
| }; |
| |
| golden_test zlib_pi_gt = { |
| .want_filename = "../../testdata/pi.txt", // |
| .src_filename = "../../testdata/pi.txt.zlib", // |
| }; |
| |
| // ---------------- Checksum Tests |
| |
| void test_puffs_adler32() { |
| proc_funcname = __func__; |
| |
| struct { |
| const char* filename; |
| // The want values are determined by script/adler32sum.go. |
| uint32_t want; |
| } test_cases[] = { |
| { |
| .filename = "../../testdata/hat.bmp", |
| .want = 0x3D26D034, |
| }, |
| { |
| .filename = "../../testdata/hat.gif", |
| .want = 0x2A5EB144, |
| }, |
| { |
| .filename = "../../testdata/hat.jpeg", |
| .want = 0x3A503B1A, |
| }, |
| { |
| .filename = "../../testdata/hat.lossless.webp", |
| .want = 0xD059D427, |
| }, |
| { |
| .filename = "../../testdata/hat.lossy.webp", |
| .want = 0xF1BB258D, |
| }, |
| { |
| .filename = "../../testdata/hat.png", |
| .want = 0xDFC6C9C6, |
| }, |
| { |
| .filename = "../../testdata/hat.tiff", |
| .want = 0xBDC011E9, |
| }, |
| }; |
| |
| int i; |
| for (i = 0; i < PUFFS_TESTLIB_ARRAY_SIZE(test_cases); i++) { |
| puffs_base__buf1 src = {.ptr = global_src_buffer, .len = BUFFER_SIZE}; |
| if (!read_file(&src, test_cases[i].filename)) { |
| return; |
| } |
| puffs_flate__adler32 checksum; |
| puffs_flate__adler32__initialize(&checksum, PUFFS_VERSION, 0); |
| uint32_t got = |
| puffs_flate__adler32__update(&checksum, ((puffs_base__slice_u8){ |
| .ptr = src.ptr + src.ri, |
| .len = src.wi - src.ri, |
| })); |
| if (got != test_cases[i].want) { |
| FAIL("i=%d, filename=\"%s\": got 0x%08" PRIX32 ", want 0x%08" PRIX32 "\n", |
| i, test_cases[i].filename, got, test_cases[i].want); |
| return; |
| } |
| } |
| } |
| |
| // ---------------- Flate Tests |
| |
| const char* puffs_flate_decode(puffs_base__buf1* dst, |
| puffs_base__buf1* src, |
| uint64_t wlimit, |
| uint64_t rlimit) { |
| puffs_flate__flate_decoder dec; |
| puffs_flate__flate_decoder__initialize(&dec, PUFFS_VERSION, 0); |
| puffs_base__writer1 dst_writer = {.buf = dst}; |
| puffs_base__reader1 src_reader = {.buf = src}; |
| while (true) { |
| uint64_t wlim = wlimit; |
| if (wlimit) { |
| dst_writer.limit.ptr_to_len = &wlim; |
| } |
| uint64_t rlim = rlimit; |
| if (rlimit) { |
| src_reader.limit.ptr_to_len = &rlim; |
| } |
| |
| puffs_flate__status s = |
| puffs_flate__flate_decoder__decode(&dec, dst_writer, src_reader); |
| |
| if (s == PUFFS_FLATE__STATUS_OK) { |
| return NULL; |
| } |
| if ((wlimit && (s == PUFFS_FLATE__SUSPENSION_SHORT_WRITE)) || |
| (rlimit && (s == PUFFS_FLATE__SUSPENSION_SHORT_READ))) { |
| continue; |
| } |
| return puffs_flate__status__string(s); |
| } |
| } |
| |
| const char* puffs_zlib_decode(puffs_base__buf1* dst, |
| puffs_base__buf1* src, |
| uint64_t wlimit, |
| uint64_t rlimit) { |
| puffs_flate__zlib_decoder dec; |
| puffs_flate__zlib_decoder__initialize(&dec, PUFFS_VERSION, 0); |
| puffs_base__writer1 dst_writer = {.buf = dst}; |
| puffs_base__reader1 src_reader = {.buf = src}; |
| |
| while (true) { |
| uint64_t wlim = wlimit; |
| if (wlimit) { |
| dst_writer.limit.ptr_to_len = &wlim; |
| } |
| uint64_t rlim = rlimit; |
| if (rlimit) { |
| src_reader.limit.ptr_to_len = &rlim; |
| } |
| |
| puffs_flate__status s = |
| puffs_flate__zlib_decoder__decode(&dec, dst_writer, src_reader); |
| |
| if (s == PUFFS_FLATE__STATUS_OK) { |
| return NULL; |
| } |
| if ((wlimit && (s == PUFFS_FLATE__SUSPENSION_SHORT_WRITE)) || |
| (rlimit && (s == PUFFS_FLATE__SUSPENSION_SHORT_READ))) { |
| continue; |
| } |
| return puffs_flate__status__string(s); |
| } |
| } |
| |
| void test_puffs_flate_decode_256_bytes() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(puffs_flate_decode, &flate_256_bytes_gt, 0, 0); |
| } |
| |
| void test_puffs_flate_decode_midsummer() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(puffs_flate_decode, &flate_midsummer_gt, 0, 0); |
| } |
| |
| void test_puffs_flate_decode_pi() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(puffs_flate_decode, &flate_pi_gt, 0, 0); |
| } |
| |
| void test_puffs_flate_decode_pi_many_big_reads() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(puffs_flate_decode, &flate_pi_gt, 0, 4096); |
| } |
| |
| void test_puffs_flate_decode_pi_many_medium_reads() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(puffs_flate_decode, &flate_pi_gt, 0, 599); |
| } |
| |
| void test_puffs_flate_decode_pi_many_small_writes_reads() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(puffs_flate_decode, &flate_pi_gt, 59, 61); |
| } |
| |
| void test_puffs_flate_decode_romeo() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(puffs_flate_decode, &flate_romeo_gt, 0, 0); |
| } |
| |
| void test_puffs_flate_decode_romeo_fixed() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(puffs_flate_decode, &flate_romeo_fixed_gt, 0, 0); |
| } |
| |
| void test_puffs_flate_decode_split_src() { |
| proc_funcname = __func__; |
| |
| puffs_base__buf1 src = {.ptr = global_src_buffer, .len = BUFFER_SIZE}; |
| puffs_base__buf1 got = {.ptr = global_got_buffer, .len = BUFFER_SIZE}; |
| puffs_base__buf1 want = {.ptr = global_want_buffer, .len = BUFFER_SIZE}; |
| |
| golden_test* gt = &flate_256_bytes_gt; |
| if (!read_file(&src, gt->src_filename)) { |
| return; |
| } |
| if (!read_file(&want, gt->want_filename)) { |
| return; |
| } |
| |
| puffs_flate__flate_decoder dec; |
| puffs_base__writer1 dst_writer = {.buf = &got}; |
| puffs_base__reader1 src_reader = {.buf = &src}; |
| |
| int i; |
| for (i = 1; i < 32; i++) { |
| size_t split = gt->src_offset0 + i; |
| if (split >= gt->src_offset1) { |
| FAIL("i=%d: split was not an interior split", i); |
| return; |
| } |
| got.wi = 0; |
| |
| puffs_flate__flate_decoder__initialize(&dec, PUFFS_VERSION, 0); |
| |
| src.closed = false; |
| src.ri = gt->src_offset0; |
| src.wi = split; |
| puffs_flate__status s0 = |
| puffs_flate__flate_decoder__decode(&dec, dst_writer, src_reader); |
| |
| src.closed = true; |
| src.ri = split; |
| src.wi = gt->src_offset1; |
| puffs_flate__status s1 = |
| puffs_flate__flate_decoder__decode(&dec, dst_writer, src_reader); |
| |
| if (s0 != PUFFS_FLATE__SUSPENSION_SHORT_READ) { |
| FAIL("i=%d: s0: got %" PRIi32 " (%s), want %" PRIi32 " (%s)", i, s0, |
| puffs_flate__status__string(s0), PUFFS_FLATE__SUSPENSION_SHORT_READ, |
| puffs_flate__status__string(PUFFS_FLATE__SUSPENSION_SHORT_READ)); |
| return; |
| } |
| |
| if (s1 != PUFFS_FLATE__STATUS_OK) { |
| FAIL("i=%d: s1: got %" PRIi32 " (%s), want %" PRIi32 " (%s)", i, s1, |
| puffs_flate__status__string(s1), PUFFS_FLATE__STATUS_OK, |
| puffs_flate__status__string(PUFFS_FLATE__STATUS_OK)); |
| return; |
| } |
| |
| char prefix[64]; |
| snprintf(prefix, 64, "i=%d: ", i); |
| if (!buf1s_equal(prefix, &got, &want)) { |
| return; |
| } |
| } |
| } |
| |
| bool do_test_puffs_flate_history(int i, |
| golden_test* gt, |
| puffs_base__buf1* src, |
| puffs_base__buf1* got, |
| puffs_flate__flate_decoder* dec, |
| uint32_t starting_history_index, |
| uint64_t limit, |
| puffs_flate__status want_s) { |
| src->ri = gt->src_offset0; |
| src->wi = gt->src_offset1; |
| got->ri = 0; |
| got->wi = 0; |
| |
| puffs_flate__flate_decoder__initialize(dec, PUFFS_VERSION, 0); |
| puffs_base__writer1 dst_writer = {.buf = got}; |
| puffs_base__reader1 src_reader = {.buf = src}; |
| |
| dec->private_impl.f_history_index = starting_history_index; |
| |
| dst_writer.limit.ptr_to_len = &limit; |
| |
| puffs_flate__status got_s = |
| puffs_flate__flate_decoder__decode(dec, dst_writer, src_reader); |
| if (got_s != want_s) { |
| FAIL("i=%d: starting_history_index=0x%04" PRIX32 |
| ": decode status: got %" PRIi32 " (%s), want %" PRIi32 " (%s)", |
| i, starting_history_index, got_s, puffs_flate__status__string(got_s), |
| want_s, puffs_flate__status__string(want_s)); |
| return false; |
| } |
| return true; |
| } |
| |
| void test_puffs_flate_history_full() { |
| proc_funcname = __func__; |
| |
| puffs_base__buf1 src = {.ptr = global_src_buffer, .len = BUFFER_SIZE}; |
| puffs_base__buf1 got = {.ptr = global_got_buffer, .len = BUFFER_SIZE}; |
| puffs_base__buf1 want = {.ptr = global_want_buffer, .len = BUFFER_SIZE}; |
| |
| golden_test* gt = &flate_pi_gt; |
| if (!read_file(&src, gt->src_filename)) { |
| return; |
| } |
| if (!read_file(&want, gt->want_filename)) { |
| return; |
| } |
| |
| const int full_history_size = 0x8000; |
| int i; |
| for (i = -2; i <= +2; i++) { |
| puffs_flate__flate_decoder dec; |
| if (!do_test_puffs_flate_history( |
| i, gt, &src, &got, &dec, 0, want.wi + i, |
| i >= 0 ? PUFFS_FLATE__STATUS_OK |
| : PUFFS_FLATE__SUSPENSION_SHORT_WRITE)) { |
| return; |
| } |
| |
| uint32_t want_history_index = i >= 0 ? 0 : full_history_size; |
| if (dec.private_impl.f_history_index != want_history_index) { |
| FAIL("i=%d: history_index: got %" PRIu32 ", want %" PRIu32, i, |
| dec.private_impl.f_history_index, want_history_index); |
| return; |
| } |
| if (i >= 0) { |
| continue; |
| } |
| |
| puffs_base__buf1 history_got = { |
| .ptr = dec.private_impl.f_history, |
| .len = full_history_size, |
| .wi = full_history_size, |
| }; |
| if (want.wi < full_history_size - i) { |
| FAIL("i=%d: want file is too short", i); |
| return; |
| } |
| puffs_base__buf1 history_want = { |
| .ptr = global_want_buffer + want.wi - (full_history_size - i), |
| .len = full_history_size, |
| .wi = full_history_size, |
| }; |
| if (!buf1s_equal("", &history_got, &history_want)) { |
| return; |
| } |
| } |
| } |
| |
| void test_puffs_flate_history_partial() { |
| proc_funcname = __func__; |
| |
| puffs_base__buf1 src = {.ptr = global_src_buffer, .len = BUFFER_SIZE}; |
| puffs_base__buf1 got = {.ptr = global_got_buffer, .len = BUFFER_SIZE}; |
| |
| golden_test* gt = &flate_pi_gt; |
| if (!read_file(&src, gt->src_filename)) { |
| return; |
| } |
| |
| uint32_t starting_history_indexes[] = { |
| 0x0000, 0x0001, 0x1234, 0x7FFB, 0x7FFC, 0x7FFD, 0x7FFE, 0x7FFF, |
| 0x8000, 0x8001, 0x9234, 0xFFFB, 0xFFFC, 0xFFFD, 0xFFFE, 0xFFFF, |
| }; |
| |
| int i; |
| for (i = 0; i < PUFFS_TESTLIB_ARRAY_SIZE(starting_history_indexes); i++) { |
| uint32_t starting_history_index = starting_history_indexes[i]; |
| |
| // The flate_pi_gt golden test file decodes to the digits of pi. |
| const char* fragment = "3.14"; |
| const uint32_t fragment_length = 4; |
| |
| puffs_flate__flate_decoder dec; |
| if (!do_test_puffs_flate_history(i, gt, &src, &got, &dec, |
| starting_history_index, fragment_length, |
| PUFFS_FLATE__SUSPENSION_SHORT_WRITE)) { |
| return; |
| } |
| |
| bool got_full = dec.private_impl.f_history_index >= 0x8000; |
| uint32_t got_history_index = dec.private_impl.f_history_index & 0x7FFF; |
| bool want_full = (starting_history_index + fragment_length) >= 0x8000; |
| uint32_t want_history_index = |
| (starting_history_index + fragment_length) & 0x7FFF; |
| if ((got_full != want_full) || (got_history_index != want_history_index)) { |
| FAIL("i=%d: starting_history_index=0x%04" PRIX32 |
| ": history_index: got %d;%04" PRIX32 ", want %d;%04" PRIX32, |
| i, starting_history_index, (int)(got_full), got_history_index, |
| (int)(want_full), want_history_index); |
| return; |
| } |
| |
| int j; |
| for (j = -2; j < (int)(fragment_length) + 2; j++) { |
| uint32_t index = (starting_history_index + j) & 0x7FFF; |
| uint8_t got = dec.private_impl.f_history[index]; |
| uint8_t want = (0 <= j && j < fragment_length) ? fragment[j] : 0; |
| if (got != want) { |
| FAIL("i=%d: starting_history_index=0x%04" PRIX32 |
| ": j=%d: got 0x%02" PRIX8 ", want 0x%02" PRIX8, |
| i, starting_history_index, j, got, want); |
| return; |
| } |
| } |
| } |
| } |
| |
| void test_puffs_flate_table_redirect() { |
| proc_funcname = __func__; |
| |
| // Call init_huff with a Huffman code that looks like: |
| // |
| // code_bits cl c r s 1st 2nd |
| // 0b_______________0 1 1 1 0 0b........0 |
| // 0b______________10 2 1 1 1 0b.......01 |
| // 0b_____________110 3 1 1 2 0b......011 |
| // 0b____________1110 4 1 1 3 0b.....0111 |
| // 0b__________1_1110 5 1 1 4 0b....01111 |
| // 0b_________11_1110 6 1 1 5 0b...011111 |
| // 0b________111_1110 7 1 1 6 0b..0111111 |
| // 8 0 2 |
| // 0b_____1_1111_1100 9 1 3 7 0b001111111 |
| // 0b____11_1111_1010 10 1 5 8 0b101111111 0b..0 (3 bits) |
| // 11 0 10 |
| // 0b__1111_1110_1100 12 19 19 9 0b101111111 0b001 |
| // 0b__1111_1110_1101 12 18 10 0b101111111 0b101 |
| // 0b__1111_1110_1110 12 17 11 0b101111111 0b011 |
| // 0b__1111_1110_1111 12 16 12 0b101111111 0b111 |
| // 0b__1111_1111_0000 12 15 13 0b011111111 0b000 (3 bits) |
| // 0b__1111_1111_0001 12 14 14 0b011111111 0b100 |
| // 0b__1111_1111_0010 12 13 15 0b011111111 0b010 |
| // 0b__1111_1111_0011 12 12 16 0b011111111 0b110 |
| // 0b__1111_1111_0100 12 11 17 0b011111111 0b001 |
| // 0b__1111_1111_0101 12 10 18 0b011111111 0b101 |
| // 0b__1111_1111_0110 12 9 19 0b011111111 0b011 |
| // 0b__1111_1111_0111 12 8 20 0b011111111 0b111 |
| // 0b__1111_1111_1000 12 7 21 0b111111111 0b.000 (4 bits) |
| // 0b__1111_1111_1001 12 6 22 0b111111111 0b.100 |
| // 0b__1111_1111_1010 12 5 23 0b111111111 0b.010 |
| // 0b__1111_1111_1011 12 4 24 0b111111111 0b.110 |
| // 0b__1111_1111_1100 12 3 25 0b111111111 0b.001 |
| // 0b__1111_1111_1101 12 2 26 0b111111111 0b.101 |
| // 0b__1111_1111_1110 12 1 27 0b111111111 0b.011 |
| // 0b1_1111_1111_1110 13 2 1 28 0b111111111 0b0111 |
| // 0b1_1111_1111_1111 13 0 29 0b111111111 0b1111 |
| // |
| // cl is the code_length. |
| // c is counts[code_length] |
| // r is the number of codes (of that code_length) remaining. |
| // s is the symbol |
| // 1st is the key in the first level table (9 bits). |
| // 2nd is the key in the second level table (variable bits). |
| |
| puffs_flate__flate_decoder dec; |
| puffs_flate__flate_decoder__initialize(&dec, PUFFS_VERSION, 0); |
| |
| // The initializer should zero out dec's fields, but to be paranoid, we zero |
| // it out explicitly. |
| memset(&dec.private_impl.f_huffs[0], 0, sizeof(dec.private_impl.f_huffs[0])); |
| |
| int i; |
| int n = 0; |
| dec.private_impl.f_code_lengths[n++] = 1; |
| dec.private_impl.f_code_lengths[n++] = 2; |
| dec.private_impl.f_code_lengths[n++] = 3; |
| dec.private_impl.f_code_lengths[n++] = 4; |
| dec.private_impl.f_code_lengths[n++] = 5; |
| dec.private_impl.f_code_lengths[n++] = 6; |
| dec.private_impl.f_code_lengths[n++] = 7; |
| dec.private_impl.f_code_lengths[n++] = 9; |
| dec.private_impl.f_code_lengths[n++] = 10; |
| for (i = 0; i < 19; i++) { |
| dec.private_impl.f_code_lengths[n++] = 12; |
| } |
| dec.private_impl.f_code_lengths[n++] = 13; |
| dec.private_impl.f_code_lengths[n++] = 13; |
| |
| puffs_flate__status s = |
| puffs_flate__flate_decoder__init_huff(&dec, 0, 0, n, 257); |
| if (s) { |
| FAIL("%s", puffs_flate__status__string(s)); |
| return; |
| } |
| |
| // There is one 1st-level table (9 bits), and three 2nd-level tables (3, 3 |
| // and 4 bits). f_huffs[0]'s elements should be non-zero for those tables and |
| // should be zero outside of those tables. |
| const int n_f_huffs = sizeof(dec.private_impl.f_huffs[0]) / |
| sizeof(dec.private_impl.f_huffs[0][0]); |
| for (i = 0; i < n_f_huffs; i++) { |
| bool got = dec.private_impl.f_huffs[0][i] == 0; |
| bool want = i >= (1 << 9) + (1 << 3) + (1 << 3) + (1 << 4); |
| if (got != want) { |
| FAIL("huffs[0][%d] == 0: got %d, want %d", i, got, want); |
| return; |
| } |
| } |
| |
| // The redirects in the 1st-level table should be at: |
| // - 0b101111111 (0x017F) to the table offset 512 (0x0200), a 3-bit table. |
| // - 0b011111111 (0x00FF) to the table offset 520 (0x0208), a 3-bit table. |
| // - 0b111111111 (0x01FF) to the table offset 528 (0x0210), a 4-bit table. |
| uint32_t got; |
| uint32_t want; |
| got = dec.private_impl.f_huffs[0][0x017F]; |
| want = 0x10020039; |
| if (got != want) { |
| FAIL("huffs[0][0x017F]: got 0x%08" PRIX32 ", want 0x%08" PRIX32, got, want); |
| return; |
| } |
| got = dec.private_impl.f_huffs[0][0x00FF]; |
| want = 0x10020839; |
| if (got != want) { |
| FAIL("huffs[0][0x00FF]: got 0x%08" PRIX32 ", want 0x%08" PRIX32, got, want); |
| return; |
| } |
| got = dec.private_impl.f_huffs[0][0x01FF]; |
| want = 0x10021049; |
| if (got != want) { |
| FAIL("huffs[0][0x01FF]: got 0x%08" PRIX32 ", want 0x%08" PRIX32, got, want); |
| return; |
| } |
| |
| // The first 2nd-level table should look like wants. |
| const uint32_t wants[8] = { |
| 0x80000801, 0x80000903, 0x80000801, 0x80000B03, |
| 0x80000801, 0x80000A03, 0x80000801, 0x80000C03, |
| }; |
| for (i = 0; i < 8; i++) { |
| got = dec.private_impl.f_huffs[0][0x0200 + i]; |
| want = wants[i]; |
| if (got != want) { |
| FAIL("huffs[0][0x%04" PRIX32 "]: got 0x%08" PRIX32 ", want 0x%08" PRIX32, |
| (uint32_t)(0x0200 + i), got, want); |
| return; |
| } |
| } |
| } |
| |
| void test_puffs_zlib_checksum_mismatch() { |
| proc_funcname = __func__; |
| |
| puffs_base__buf1 got = {.ptr = global_got_buffer, .len = BUFFER_SIZE}; |
| puffs_base__buf1 src = {.ptr = global_src_buffer, .len = BUFFER_SIZE}; |
| |
| if (!read_file(&src, zlib_midsummer_gt.src_filename)) { |
| return; |
| } |
| if (src.wi == 0) { |
| FAIL("source file was empty"); |
| return; |
| } |
| // Flip a bit in the zlib checksum, which comes at the end of the file. |
| src.ptr[src.wi - 1] ^= 1; |
| |
| puffs_flate__zlib_decoder dec; |
| puffs_flate__zlib_decoder__initialize(&dec, PUFFS_VERSION, 0); |
| puffs_base__writer1 got_writer = {.buf = &got}; |
| puffs_base__reader1 src_reader = {.buf = &src}; |
| |
| puffs_flate__status status = |
| puffs_flate__zlib_decoder__decode(&dec, got_writer, src_reader); |
| if (status != PUFFS_FLATE__ERROR_CHECKSUM_MISMATCH) { |
| FAIL("status: got %" PRIi32 " (%s), want %" PRIi32 " (%s)", status, |
| puffs_flate__status__string(status), |
| PUFFS_FLATE__ERROR_CHECKSUM_MISMATCH, |
| puffs_flate__status__string(PUFFS_FLATE__ERROR_CHECKSUM_MISMATCH)); |
| return; |
| } |
| } |
| |
| void test_puffs_zlib_decode_midsummer() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(puffs_zlib_decode, &zlib_midsummer_gt, 0, 0); |
| } |
| |
| void test_puffs_zlib_decode_pi() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(puffs_zlib_decode, &zlib_pi_gt, 0, 0); |
| } |
| |
| // ---------------- Mimic Tests |
| |
| #ifdef PUFFS_MIMIC |
| |
| #include "../mimiclib/flate.c" |
| |
| void test_mimic_flate_decode_256_bytes() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(mimic_flate_decode, &flate_256_bytes_gt, 0, 0); |
| } |
| |
| void test_mimic_flate_decode_midsummer() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(mimic_flate_decode, &flate_midsummer_gt, 0, 0); |
| } |
| |
| void test_mimic_flate_decode_pi() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(mimic_flate_decode, &flate_pi_gt, 0, 0); |
| } |
| |
| void test_mimic_flate_decode_romeo() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(mimic_flate_decode, &flate_romeo_gt, 0, 0); |
| } |
| |
| void test_mimic_flate_decode_romeo_fixed() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(mimic_flate_decode, &flate_romeo_fixed_gt, 0, 0); |
| } |
| |
| void test_mimic_gzip_decode_midsummer() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(mimic_gzip_decode, &gzip_midsummer_gt, 0, 0); |
| } |
| |
| void test_mimic_gzip_decode_pi() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(mimic_gzip_decode, &gzip_pi_gt, 0, 0); |
| } |
| |
| void test_mimic_zlib_decode_midsummer() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(mimic_zlib_decode, &zlib_midsummer_gt, 0, 0); |
| } |
| |
| void test_mimic_zlib_decode_pi() { |
| proc_funcname = __func__; |
| do_test_buf1_buf1(mimic_zlib_decode, &zlib_pi_gt, 0, 0); |
| } |
| |
| #endif // PUFFS_MIMIC |
| |
| // ---------------- Checksum Benches |
| |
| uint32_t global_puffs_flate_unused_u32; |
| |
| const char* puffs_bench_adler32(puffs_base__buf1* dst, |
| puffs_base__buf1* src, |
| uint64_t wlimit, |
| uint64_t rlimit) { |
| // TODO: don't ignore wlimit and rlimit. |
| puffs_flate__adler32 checksum; |
| puffs_flate__adler32__initialize(&checksum, PUFFS_VERSION, 0); |
| global_puffs_flate_unused_u32 = |
| puffs_flate__adler32__update(&checksum, ((puffs_base__slice_u8){ |
| .ptr = src->ptr + src->ri, |
| .len = src->wi - src->ri, |
| })); |
| src->ri = src->wi; |
| return NULL; |
| } |
| |
| void bench_puffs_adler32_10k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(puffs_bench_adler32, tc_src, &checksum_midsummer_gt, 0, 0, |
| 30000); |
| } |
| |
| void bench_puffs_adler32_100k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(puffs_bench_adler32, tc_src, &checksum_pi_gt, 0, 0, 3000); |
| } |
| |
| // ---------------- Flate Benches |
| |
| void bench_puffs_flate_decode_1k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(puffs_flate_decode, tc_dst, &flate_romeo_gt, 0, 0, 200000); |
| } |
| |
| void bench_puffs_flate_decode_10k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(puffs_flate_decode, tc_dst, &flate_midsummer_gt, 0, 0, |
| 30000); |
| } |
| |
| void bench_puffs_flate_decode_100k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(puffs_flate_decode, tc_dst, &flate_pi_gt, 0, 0, 3000); |
| } |
| |
| void bench_puffs_zlib_decode_10k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(puffs_zlib_decode, tc_dst, &zlib_midsummer_gt, 0, 0, |
| 30000); |
| } |
| |
| void bench_puffs_zlib_decode_100k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(puffs_zlib_decode, tc_dst, &zlib_pi_gt, 0, 0, 3000); |
| } |
| |
| // ---------------- Mimic Benches |
| |
| #ifdef PUFFS_MIMIC |
| |
| void bench_mimic_adler32_10k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_bench_adler32, tc_src, &checksum_midsummer_gt, 0, 0, |
| 30000); |
| } |
| |
| void bench_mimic_adler32_100k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_bench_adler32, tc_src, &checksum_pi_gt, 0, 0, 3000); |
| } |
| |
| void bench_mimic_crc32_10k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_bench_crc32, tc_src, &checksum_midsummer_gt, 0, 0, |
| 30000); |
| } |
| |
| void bench_mimic_crc32_100k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_bench_crc32, tc_src, &checksum_pi_gt, 0, 0, 3000); |
| } |
| |
| void bench_mimic_flate_decode_1k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_flate_decode, tc_dst, &flate_romeo_gt, 0, 0, 200000); |
| } |
| |
| void bench_mimic_flate_decode_10k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_flate_decode, tc_dst, &flate_midsummer_gt, 0, 0, |
| 30000); |
| } |
| |
| void bench_mimic_flate_decode_100k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_flate_decode, tc_dst, &flate_pi_gt, 0, 0, 3000); |
| } |
| |
| void bench_mimic_gzip_decode_10k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_gzip_decode, tc_dst, &gzip_midsummer_gt, 0, 0, |
| 30000); |
| } |
| |
| void bench_mimic_gzip_decode_100k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_gzip_decode, tc_dst, &gzip_pi_gt, 0, 0, 3000); |
| } |
| |
| void bench_mimic_zlib_decode_10k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_zlib_decode, tc_dst, &zlib_midsummer_gt, 0, 0, |
| 30000); |
| } |
| |
| void bench_mimic_zlib_decode_100k() { |
| proc_funcname = __func__; |
| do_bench_buf1_buf1(mimic_zlib_decode, tc_dst, &zlib_pi_gt, 0, 0, 3000); |
| } |
| |
| #endif // PUFFS_MIMIC |
| |
| // ---------------- Manifest |
| |
| // The empty comments forces clang-format to place one element per line. |
| proc tests[] = { |
| // Flate Tests |
| test_puffs_adler32, // |
| test_puffs_flate_decode_256_bytes, // |
| test_puffs_flate_decode_midsummer, // |
| test_puffs_flate_decode_pi, // |
| test_puffs_flate_decode_pi_many_big_reads, // |
| test_puffs_flate_decode_pi_many_medium_reads, // |
| test_puffs_flate_decode_pi_many_small_writes_reads, // |
| test_puffs_flate_decode_romeo, // |
| test_puffs_flate_decode_romeo_fixed, // |
| test_puffs_flate_decode_split_src, // |
| test_puffs_flate_history_full, // |
| test_puffs_flate_history_partial, // |
| test_puffs_flate_table_redirect, // |
| test_puffs_zlib_checksum_mismatch, // |
| test_puffs_zlib_decode_midsummer, // |
| test_puffs_zlib_decode_pi, // |
| |
| #ifdef PUFFS_MIMIC |
| |
| // Mimic Tests |
| test_mimic_flate_decode_256_bytes, // |
| test_mimic_flate_decode_midsummer, // |
| test_mimic_flate_decode_pi, // |
| test_mimic_flate_decode_romeo, // |
| test_mimic_flate_decode_romeo_fixed, // |
| test_mimic_gzip_decode_midsummer, // |
| test_mimic_gzip_decode_pi, // |
| test_mimic_zlib_decode_midsummer, // |
| test_mimic_zlib_decode_pi, // |
| |
| #endif // PUFFS_MIMIC |
| |
| NULL, |
| }; |
| |
| // The empty comments forces clang-format to place one element per line. |
| proc benches[] = { |
| // Flate Benches |
| bench_puffs_adler32_10k, // |
| bench_puffs_adler32_100k, // |
| bench_puffs_flate_decode_1k, // |
| bench_puffs_flate_decode_10k, // |
| bench_puffs_flate_decode_100k, // |
| bench_puffs_zlib_decode_10k, // |
| bench_puffs_zlib_decode_100k, // |
| |
| #ifdef PUFFS_MIMIC |
| |
| // Mimic Benches |
| bench_mimic_adler32_10k, // |
| bench_mimic_adler32_100k, // |
| bench_mimic_crc32_10k, // |
| bench_mimic_crc32_100k, // |
| bench_mimic_flate_decode_1k, // |
| bench_mimic_flate_decode_10k, // |
| bench_mimic_flate_decode_100k, // |
| bench_mimic_gzip_decode_10k, // |
| bench_mimic_gzip_decode_100k, // |
| bench_mimic_zlib_decode_10k, // |
| bench_mimic_zlib_decode_100k, // |
| |
| #endif // PUFFS_MIMIC |
| |
| NULL, |
| }; |