]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Replace small/large buffer tests with parameterized test_chunked develop
authorNathan Moinvaziri <nathan@nathanm.com>
Tue, 14 Apr 2026 03:20:26 +0000 (20:20 -0700)
committerHans Kristian Rosbach <hk-github@circlestorm.org>
Sat, 25 Apr 2026 14:25:57 +0000 (16:25 +0200)
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.

test/CMakeLists.txt
test/test_chunked.cc [new file with mode: 0644]
test/test_large_buffers.cc [deleted file]
test/test_small_buffers.cc [deleted file]

index cfaed9312d51b283e76e3eeae211b7b388c438f3..6550a6c2c1cf12e8df3ea2f347469d7ddb48447a 100644 (file)
@@ -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 (file)
index 0000000..ac8716f
--- /dev/null
@@ -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 <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gtest/gtest.h>
+
+#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<chunked_params> {
+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<chunked_params>& 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 (file)
index 3c12081..0000000
+++ /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 <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <gtest/gtest.h>
-
-#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 (file)
index bb3449f..0000000
+++ /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 <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "test_shared.h"
-
-#include <gtest/gtest.h>
-
-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);
-}