From: Nathan Moinvaziri Date: Tue, 14 Apr 2026 03:20:26 +0000 (-0700) Subject: Replace small/large buffer tests with parameterized test_chunked X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=HEAD;p=thirdparty%2Fzlib-ng.git Replace small/large buffer tests with parameterized test_chunked test_large_buffers reset d_stream.next_out on every inflate iteration, so the decompressed output was never compared against the source. test_chunked keeps the input, compressed, and decompressed buffers separate and checks them with memcmp. New avail_out values (3, 64, 128, 256, 259) exercise inflate_fast()'s safe-mode MATCH-state bailout around the 258-byte maximum match length. --- diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index cfaed9312..6550a6c2c 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -149,6 +149,7 @@ if(WITH_GTEST) if(TARGET GTest::GTest) set(TEST_SRCS + test_chunked.cc test_compress.cc test_compress_bound.cc test_cve-2003-0107.cc @@ -167,9 +168,7 @@ if(WITH_GTEST) test_dict.cc test_inflate_adler32.cc test_inflate_copy.cc - test_large_buffers.cc test_raw.cc - test_small_buffers.cc test_small_window.cc ) diff --git a/test/test_chunked.cc b/test/test_chunked.cc new file mode 100644 index 000000000..ac8716ff4 --- /dev/null +++ b/test/test_chunked.cc @@ -0,0 +1,141 @@ +/* test_chunked.cc - Test deflate() and inflate() with various buffer sizes */ + +#include "zbuild.h" +#ifdef ZLIB_COMPAT +# include "zlib.h" +#else +# include "zlib-ng.h" +#endif + +#include +#include +#include +#include + +#include + +#include "compressible_data_p.h" + +struct chunked_params { + size_t compr_size; + size_t uncompr_size; + size_t avail_out; + const char *name; +}; + +class chunked : public ::testing::TestWithParam { +protected: + uint8_t *compr = nullptr; + uint8_t *uncompr = nullptr; + uint8_t *decompressed = nullptr; + + void SetUp() override { + const auto& p = GetParam(); + + compr = (uint8_t *)calloc(1, p.compr_size); + ASSERT_NE(compr, nullptr); + decompressed = (uint8_t *)calloc(1, p.uncompr_size); + ASSERT_NE(decompressed, nullptr); + + uncompr = gen_compressible_data(p.uncompr_size); + ASSERT_NE(uncompr, nullptr); + } + + void TearDown() override { + free(compr); + free(uncompr); + free(decompressed); + } +}; + +TEST_P(chunked, roundtrip) { + const auto& p = GetParam(); + PREFIX3(stream) c_stream, d_stream; + int err; + + memset(&c_stream, 0, sizeof(c_stream)); + memset(&d_stream, 0, sizeof(d_stream)); + + err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); + ASSERT_EQ(err, Z_OK); + + c_stream.next_in = uncompr; + c_stream.avail_in = (uint32_t)p.uncompr_size; + c_stream.next_out = compr; + c_stream.avail_out = (uint32_t)p.avail_out; + + /* Consume all input with Z_NO_FLUSH, refilling avail_out as it drains. */ + while (c_stream.avail_in > 0) { + err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); + ASSERT_EQ(err, Z_OK); + if (c_stream.avail_out == 0) { + size_t remaining = p.compr_size - c_stream.total_out; + ASSERT_NE(remaining, 0u) << "compr buffer too small"; + c_stream.avail_out = (uint32_t)MIN(p.avail_out, remaining); + } + } + + /* Finish the stream, still chunking the output. */ + for (;;) { + err = PREFIX(deflate)(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) + break; + ASSERT_EQ(err, Z_OK); + ASSERT_EQ(c_stream.avail_out, 0u) << "Z_FINISH returned Z_OK with space remaining"; + size_t remaining = p.compr_size - c_stream.total_out; + ASSERT_NE(remaining, 0u) << "compr buffer too small"; + c_stream.avail_out = (uint32_t)MIN(p.avail_out, remaining); + } + + err = PREFIX(deflateEnd)(&c_stream); + ASSERT_EQ(err, Z_OK); + + err = PREFIX(inflateInit)(&d_stream); + ASSERT_EQ(err, Z_OK); + + d_stream.next_in = compr; + d_stream.avail_in = (uint32_t)c_stream.total_out; + d_stream.next_out = decompressed; + d_stream.avail_out = (uint32_t)p.avail_out; + + for (;;) { + err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) + break; + ASSERT_EQ(err, Z_OK); + if (d_stream.avail_out == 0) { + size_t remaining = p.uncompr_size - d_stream.total_out; + ASSERT_NE(remaining, 0u) << "decompressed buffer full before inflate done"; + d_stream.avail_out = (uint32_t)MIN(p.avail_out, remaining); + } + } + + err = PREFIX(inflateEnd)(&d_stream); + ASSERT_EQ(err, Z_OK); + + EXPECT_EQ(d_stream.total_out, p.uncompr_size); + EXPECT_EQ(memcmp(decompressed, uncompr, p.uncompr_size), 0); +} + +/* chunked_params fields: + * compr_size - size of the compressed buffer allocation + * uncompr_size - size of the uncompressed input and the decompressed output buffers + * avail_out - per-chunk output size used for both deflate and inflate; the output is + * drained and refilled in chunks of this size + * name - test case name suffix + */ +INSTANTIATE_TEST_SUITE_P( + chunked, chunked, + ::testing::Values( + chunked_params{128, 128, 1, "small_buffers"}, + chunked_params{48 * 1024, 32 * 1024, 32 * 1024, "large_buffers"}, + /* test inflate_fast() safe mode MATCH state bailout at various avail_out */ + chunked_params{48 * 1024, 32 * 1024, 3, "avail_out_3"}, + chunked_params{48 * 1024, 32 * 1024, 64, "avail_out_64"}, + chunked_params{48 * 1024, 32 * 1024, 128, "avail_out_128"}, + chunked_params{48 * 1024, 32 * 1024, 256, "avail_out_256"}, + chunked_params{48 * 1024, 32 * 1024, 259, "avail_out_259"} + ), + [](const ::testing::TestParamInfo& info) { + return std::string(info.param.name); + }); diff --git a/test/test_large_buffers.cc b/test/test_large_buffers.cc deleted file mode 100644 index 3c1208140..000000000 --- a/test/test_large_buffers.cc +++ /dev/null @@ -1,87 +0,0 @@ -/* test_large_buffers.cc - Test deflate() and inflate() with large buffers */ - -#include "zbuild.h" -#ifdef ZLIB_COMPAT -# include "zlib.h" -#else -# include "zlib-ng.h" -#endif - -#include -#include -#include -#include -#include - -#include - -#include "test_shared.h" - -#define COMPR_BUFFER_SIZE (48 * 1024) -#define UNCOMPR_BUFFER_SIZE (32 * 1024) -#define UNCOMPR_RAND_SIZE (8 * 1024) - -TEST(deflate, large_buffers) { - PREFIX3(stream) c_stream, d_stream; - uint8_t *compr, *uncompr; - uint32_t compr_len, uncompr_len; - int32_t i; - time_t now; - int err; - - memset(&c_stream, 0, sizeof(c_stream)); - memset(&d_stream, 0, sizeof(d_stream)); - - compr = (uint8_t *)calloc(1, COMPR_BUFFER_SIZE); - ASSERT_TRUE(compr != NULL); - uncompr = (uint8_t *)calloc(1, UNCOMPR_BUFFER_SIZE); - ASSERT_TRUE(uncompr != NULL); - - compr_len = COMPR_BUFFER_SIZE; - uncompr_len = UNCOMPR_BUFFER_SIZE; - - srand((unsigned)time(&now)); - for (i = 0; i < UNCOMPR_RAND_SIZE; i++) - uncompr[i] = (uint8_t)(rand() % 256); - - err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); - EXPECT_EQ(err, Z_OK); - - c_stream.next_out = compr; - c_stream.avail_out = compr_len; - c_stream.next_in = uncompr; - c_stream.avail_in = uncompr_len; - - err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); - EXPECT_EQ(err, Z_OK); - EXPECT_EQ(c_stream.avail_in, 0); - - err = PREFIX(deflate)(&c_stream, Z_FINISH); - EXPECT_EQ(err, Z_STREAM_END); - - err = PREFIX(deflateEnd)(&c_stream); - EXPECT_EQ(err, Z_OK); - - d_stream.next_in = compr; - d_stream.avail_in = compr_len; - d_stream.next_out = uncompr; - - err = PREFIX(inflateInit)(&d_stream); - EXPECT_EQ(err, Z_OK); - - for (;;) { - d_stream.next_out = uncompr; /* discard the output */ - d_stream.avail_out = uncompr_len; - err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - EXPECT_EQ(err, Z_OK); - } - - err = PREFIX(inflateEnd)(&d_stream); - EXPECT_EQ(err, Z_OK); - - EXPECT_EQ(d_stream.total_out, uncompr_len); - - free(compr); - free(uncompr); -} diff --git a/test/test_small_buffers.cc b/test/test_small_buffers.cc deleted file mode 100644 index bb3449fd8..000000000 --- a/test/test_small_buffers.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* test_small_buffers.cc - Test deflate() and inflate() with small buffers */ - -#include "zbuild.h" -#ifdef ZLIB_COMPAT -# include "zlib.h" -#else -# include "zlib-ng.h" -#endif - -#include -#include -#include -#include - -#include "test_shared.h" - -#include - -TEST(deflate, small_buffers) { - PREFIX3(stream) c_stream, d_stream; - uint8_t compr[128], uncompr[128]; - z_size_t compr_len = sizeof(compr), uncompr_len = sizeof(uncompr); - int err; - - memset(&c_stream, 0, sizeof(c_stream)); - memset(&d_stream, 0, sizeof(d_stream)); - - err = PREFIX(deflateInit)(&c_stream, Z_DEFAULT_COMPRESSION); - EXPECT_EQ(err, Z_OK); - - c_stream.next_in = (z_const unsigned char *)hello; - c_stream.next_out = compr; - - while (c_stream.total_in != hello_len && c_stream.total_out < compr_len) { - c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ - err = PREFIX(deflate)(&c_stream, Z_NO_FLUSH); - EXPECT_EQ(err, Z_OK); - } - /* Finish the stream, still forcing small buffers */ - for (;;) { - c_stream.avail_out = 1; - err = PREFIX(deflate)(&c_stream, Z_FINISH); - if (err == Z_STREAM_END) break; - EXPECT_EQ(err, Z_OK); - } - - err = PREFIX(deflateEnd)(&c_stream); - EXPECT_EQ(err, Z_OK); - - strcpy((char*)uncompr, "garbage"); - - d_stream.next_in = compr; - d_stream.next_out = uncompr; - - err = PREFIX(inflateInit)(&d_stream); - EXPECT_EQ(err, Z_OK); - - while (d_stream.total_out < uncompr_len && d_stream.total_in < compr_len) { - d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ - err = PREFIX(inflate)(&d_stream, Z_NO_FLUSH); - if (err == Z_STREAM_END) break; - EXPECT_EQ(err, Z_OK); - } - - err = PREFIX(inflateEnd)(&d_stream); - EXPECT_EQ(err, Z_OK); - - EXPECT_STREQ((char*)uncompr, hello); -}