]> git.ipfire.org Git - thirdparty/zlib-ng.git/commitdiff
Add parameterized testing, based on #1448 by Ruben Vorderman
authorHans Kristian Rosbach <hk-git@circlestorm.org>
Mon, 17 Mar 2025 14:00:52 +0000 (15:00 +0100)
committerHans Kristian Rosbach <hk-git@circlestorm.org>
Wed, 19 Mar 2025 18:43:37 +0000 (19:43 +0100)
Co-authored-by: Ruben Vorderman <r.h.p.vorderman@lumc.nl>
configure
test/CMakeLists.txt
test/Makefile.in
test/cmake/test-data.cmake
test/cmake/test-detect.cmake [new file with mode: 0644]
test/cmake/test-tools.cmake
test/parameterized_tester.c [new file with mode: 0644]

index fe19641bb6724cb1817aba58cc283556e9956196..5d354380491d05e2704810e5998967d5a31aeb23 100755 (executable)
--- a/configure
+++ b/configure
@@ -2274,7 +2274,7 @@ sed < $SRCDIR/arch/generic/Makefile.in "
 # Emscripten does not support large amounts of data via stdin/out
 # https://github.com/emscripten-core/emscripten/issues/16755#issuecomment-1102732849
 if test "$CHOST" != "wasm32"; then
-    TEST="${TEST} ghtests"
+    TEST="${TEST} ghtests parameterized"
 fi
 
 # Determine emulator to use when running tests
index 0150c7037b2c19beb7ba94b19ab345af5f8173e4..86ec3a873f8cd96c683f3a6450d713f7ee5846ef 100644 (file)
@@ -47,6 +47,11 @@ configure_test_executable(switchlevels)
 target_link_libraries(switchlevels zlib)
 set(SWITCHLEVELS_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:switchlevels>)
 
+add_executable(parameterized_tester parameterized_tester.c)
+configure_test_executable(parameterized_tester)
+target_link_libraries(parameterized_tester zlib)
+set(PARAMETERIZED_TESTER_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $<TARGET_FILE:parameterized_tester>)
+
 add_executable(infcover infcover.c)
 configure_test_executable(infcover)
 target_link_libraries(infcover zlib)
@@ -79,6 +84,9 @@ if(NOT BASEARCH_WASM32_FOUND)
     # Run tests with data files
     include(cmake/test-data.cmake)
 
+    # Run tests with data files
+    include(cmake/test-detect.cmake)
+
     # Run tests targeting GitHub issues
     include(cmake/test-issues.cmake)
 
index 5b45965926c71bd80483d8c2cb855c29927ffe70..fae87d63818dca520a8af2fcaf17cf07fe7fbc02 100644 (file)
@@ -74,6 +74,22 @@ gh1235$(EXE): $(SRCDIR)/gh1235.c
 testGH-1235: gh1235$(EXE)
        $(EMU_RUN) ./gh1235$(EXE)
 
+parameterized_tester$(EXE): $(SRCDIR)/parameterized_tester.c
+       $(CC) $(CFLAGS) -I.. -I$(SRCTOP) -o $@ $< $(TEST_LDFLAGS)
+
+.PHONY: parameterized
+parameterized: test-fireworks test-lcet10 test-paper-100k
+
+.PHONY: test-fireworks test-lcet10 test-paper-100k
+test-fireworks: parameterized_tester$(EXE)
+       $(EMU_RUN) ./parameterized_tester$(EXE) $(SRCDIR)/data/fireworks.jpg
+
+test-lcet10: parameterized_tester$(EXE)
+       $(EMU_RUN) ./parameterized_tester$(EXE) $(SRCDIR)/data/lcet10.txt
+
+test-paper-100k: parameterized_tester$(EXE)
+       $(EMU_RUN) ./parameterized_tester$(EXE) $(SRCDIR)/data/paper-100k.pdf
+
 clean:
        rm -f *.o *.gcda *.gcno *.gcov
        rm -f switchlevels$(EXE) gh1235$(EXE)
index e60c356e462bf74a6073fe47662122a9b340ca20..ca7a6d69d3a97a56a9060f286011967836dba2b9 100644 (file)
@@ -1,47 +1,16 @@
 # test-data.cmake - Tests targeting data files in the data directory
 
 # Test compress and verify test against data file using extra args
-macro(test_minigzip name path)
-    # Construct compression arguments for minigzip
-    set(compress_args -k -c)
-    foreach(extra_arg IN ITEMS "${ARGN}")
-        list(APPEND compress_args ${extra_arg})
-    endforeach()
-
-    # Create unique friendly string for test
-    string(REPLACE ";" "" arg_list "${ARGN}")
-    string(REPLACE " " "" arg_list "${arg_list}")
-    string(REPLACE "-" "" arg_list "${arg_list}")
-
-    set(test_id minigzip-${name}-${arg_list})
+macro(parameterized_tester name path)
+    set(test_id parameterized-${name})
 
     if(NOT TEST ${test_id})
         add_test(NAME ${test_id}
-            COMMAND ${CMAKE_COMMAND}
-            "-DTARGET=${MINIGZIP_COMMAND}"
-            "-DCOMPRESS_ARGS=${compress_args}"
-            "-DDECOMPRESS_ARGS=-d;-c"
-            -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${path}
-            -DTEST_NAME=${test_id}
-            -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake)
+            COMMAND ${PARAMETERIZED_TESTER_COMMAND}
+            "${CMAKE_CURRENT_SOURCE_DIR}/${path}")
     endif()
 endmacro()
 
-# List of arg combinations to use during compression
-set(TEST_CONFIGS
-    -R      # Z_RLE
-    -h      # Z_HUFFMAN_ONLY
-    -T      # Direct store
-    -0      # No compression
-    -1      # Deflate quick
-    -2      # Deflate fast
-    -4      # Deflate medium (lazy matches)
-    "-5;-F" # Deflate medium (Z_FIXED)
-    -6      # Deflate medium
-    -9      # Deflate slow
-    "-9;-f" # Deflate slow (Z_FILTERED)
-)
-
 # Enumerate all files in data directory to run tests against
 file(GLOB_RECURSE TEST_FILE_PATHS
     LIST_DIRECTORIES false
@@ -54,15 +23,9 @@ foreach(test_file_path ${TEST_FILE_PATHS})
         "${test_file_path}" MATCHES "/.git/" OR "${test_file_path}" MATCHES ".md$")
         continue()
     endif()
-    foreach(test_config ${TEST_CONFIGS})
-        get_filename_component(test_name ${test_file_path} NAME)
-        if (test_name STREQUAL "")
-            continue()
-        endif()
-        test_minigzip(${test_name} ${test_file_path} ${test_config})
-    endforeach()
+    get_filename_component(test_name ${test_file_path} NAME)
+    if (test_name STREQUAL "")
+        continue()
+    endif()
+    parameterized_tester(${test_name} ${test_file_path})
 endforeach()
-
-# Additional tests to verify with automatic data type detection arg
-test_minigzip("detect-text" "data/lcet10.txt" -A)
-test_minigzip("detect-binary" "data/paper-100k.pdf" -A)
diff --git a/test/cmake/test-detect.cmake b/test/cmake/test-detect.cmake
new file mode 100644 (file)
index 0000000..ba8c8ba
--- /dev/null
@@ -0,0 +1,32 @@
+# test-detect.cmake - Tests automatic data type detection
+
+# Test compress and verify test against data file using extra args
+macro(test_minigzip name path)
+    # Construct compression arguments for minigzip
+    set(compress_args -k -c)
+    foreach(extra_arg IN ITEMS "${ARGN}")
+        list(APPEND compress_args ${extra_arg})
+    endforeach()
+
+    # Create unique friendly string for test
+    string(REPLACE ";" "" arg_list "${ARGN}")
+    string(REPLACE " " "" arg_list "${arg_list}")
+    string(REPLACE "-" "" arg_list "${arg_list}")
+
+    set(test_id minigzip-${name}-${arg_list})
+
+    if(NOT TEST ${test_id})
+        add_test(NAME ${test_id}
+            COMMAND ${CMAKE_COMMAND}
+            "-DTARGET=${MINIGZIP_COMMAND}"
+            "-DCOMPRESS_ARGS=${compress_args}"
+            "-DDECOMPRESS_ARGS=-d;-c"
+            -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${path}
+            -DTEST_NAME=${test_id}
+            -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/compress-and-verify.cmake)
+    endif()
+endmacro()
+
+# Tests to verify with automatic data type detection arg
+test_minigzip("detect-text" "data/lcet10.txt" -A)
+test_minigzip("detect-binary" "data/paper-100k.pdf" -A)
index c2a683fbd94e1147cf6f78987cac94bf24bb1ffc..d78d8e006b6b5af60414fc5597558e9b948e2b22 100644 (file)
@@ -52,6 +52,12 @@ add_test(NAME switchlevels-help
      "-DCOMMAND=${TEST_COMMAND}"
      -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake)
 
+set(TEST_COMMAND ${PARAMETERIZED_TESTER_COMMAND} "--help")
+add_test(NAME parameterized_tester-help
+    COMMAND ${CMAKE_COMMAND}
+     "-DCOMMAND=${TEST_COMMAND}"
+     -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-and-redirect.cmake)
+
 # Test generated crc32 tables match tables in source directory
 add_test(NAME makecrct
     COMMAND ${CMAKE_COMMAND}
diff --git a/test/parameterized_tester.c b/test/parameterized_tester.c
new file mode 100644 (file)
index 0000000..eb9d1ae
--- /dev/null
@@ -0,0 +1,194 @@
+/* parameterized_tester.c - Test deflate() and inflate() on a chunk of the
+ * input data file, combining many deflate() settings to improve testing coverage.
+ */
+#include "zbuild.h"
+#ifdef ZLIB_COMPAT
+#  include "zlib.h"
+#else
+#  include "zlib-ng.h"
+#endif
+
+#include <stdio.h>
+
+/*
+ * WITH_EXTRA_TESTS results in 9450 permutations per input file.
+ * Normal mode results in 540.
+ *
+ * WITH_EXTRA_TESTS also tests a bigger chunk of the files.
+ */
+
+#ifdef WITH_EXTRA_TESTS
+const int valid_wbits[] = {
+    -9, -10, -11, -12, -13, -14, -15,
+     9,  10,  11,  12,  13,  14,  15,
+#  ifdef WITH_GZFILEOP
+    25,  26,  27,  28,  29,  30,  31,
+#  endif
+};
+
+const int valid_compression_levels[] = {
+    0, 1, 2, 3, 4, 5, 6, 7, 8, 9
+};
+
+const int valid_mem_levels[] = {
+    1, 2, 3, 4, 5, 6, 7, 8, 9,
+};
+
+#define MAX_FILESIZE_KB 4096
+
+#  ifdef WITH_GZFILEOP
+#    define NUM_W 21
+#  else
+#    define NUM_W 14
+#  endif
+#  define NUM_C 10
+#  define NUM_M 9
+
+#else // !WITH_EXTRA_TESTS
+
+const int valid_wbits[] = {
+    -9, -15,
+     9,  15,
+#  ifdef WITH_GZFILEOP
+    25,  31,
+#  endif
+};
+
+const int valid_compression_levels[] = {
+    0, 1, 2, 4, 6, 9
+};
+
+const int valid_mem_levels[] = {
+    1, 8, 9,
+};
+
+#define MAX_FILESIZE_KB 128
+
+#  ifdef WITH_GZFILEOP
+#    define NUM_W 6
+#  else
+#    define NUM_W 4
+#  endif
+#  define NUM_C 6
+#  define NUM_M 3
+#endif
+
+#define MAX_FILESIZE MAX_FILESIZE_KB * 1024
+#define MAX_OUTSIZE MAX_FILESIZE_KB * (1024 + 128)
+
+const int valid_strategies[] = {
+    Z_FILTERED,
+    Z_HUFFMAN_ONLY,
+    Z_RLE,
+    Z_FIXED,
+    Z_DEFAULT_STRATEGY,
+};
+
+int main (int argc, char *argv[])  {
+    PREFIX3(stream) c_stream;
+    PREFIX3(stream) d_stream;
+    uint8_t data_in[MAX_FILESIZE];
+    uint8_t compressed_out[MAX_OUTSIZE];
+    uint8_t decompressed_out[MAX_OUTSIZE];
+    const char *error_format = "Error at %s\n"
+                               "level: %d\n"
+                               "wbits: %d\n"
+                               "memLevel: %d\n"
+                               "strategy: %d\n"
+                               "exit: %d\n"
+                               "message: %s\n";
+
+    if (argc != 2) {
+        fputs("A data input must be given as argument", stderr);
+        return EXIT_FAILURE;
+    }
+
+    if ((argc == 2 && strcmp(argv[1], "--help") == 0)) {
+        printf("Usage: test_parameterized <FILENAME>\n\n");
+        return 0;
+    }
+
+    FILE *in_file = fopen(argv[1], "r");
+    uint32_t read_size = (uint32_t)fread(data_in, 1, MAX_FILESIZE, in_file);
+    fclose(in_file);
+
+    if (!read_size) {
+        fprintf(stderr, "File is empty or error: %s", argv[1]);
+        return EXIT_FAILURE;
+    }
+
+    for (int wbits_index = 0; wbits_index < NUM_W; wbits_index += 1) {
+        for (int complevel_index = 0; complevel_index < NUM_C; complevel_index += 1) {
+            for (int memlevel_index = 0; memlevel_index < NUM_M; memlevel_index += 1) {
+                for (int strat_index = 0; strat_index < 5; strat_index += 1) {
+
+                    int level = valid_compression_levels[complevel_index];
+                    int wbits = valid_wbits[wbits_index];
+                    int memlevel  = valid_mem_levels[memlevel_index];
+                    int strategy = valid_strategies[strat_index];
+                    memset(&c_stream, 0, sizeof(PREFIX3(stream)));
+                    memset(&d_stream, 0, sizeof(PREFIX3(stream)));
+
+                    int err = PREFIX(deflateInit2)(&c_stream, level, Z_DEFLATED, wbits, memlevel, strategy);
+                    if (err != Z_OK) {
+                        fprintf(stderr, error_format, "deflateInit2", level, wbits, memlevel, strategy, c_stream.msg);
+                        return EXIT_FAILURE;
+                    }
+
+                    c_stream.next_in = data_in;
+                    c_stream.avail_in = read_size;
+                    c_stream.next_out = compressed_out;
+                    c_stream.avail_out = MAX_OUTSIZE;
+
+                    err = PREFIX(deflate)(&c_stream, Z_FINISH);
+                    if (err != Z_STREAM_END) {
+                        fprintf(stderr, error_format, "deflate", level, wbits, memlevel, strategy, c_stream.msg);
+                        return EXIT_FAILURE;
+                    }
+
+                    err = PREFIX(inflateInit2)(&d_stream, wbits);
+                    if (err != Z_OK) {
+                        fprintf(stderr, error_format, "inflateInit2", level, wbits, memlevel, strategy, err, d_stream.msg);
+                        return EXIT_FAILURE;
+                    }
+
+                    d_stream.next_in = compressed_out;
+                    d_stream.avail_in = MAX_OUTSIZE - c_stream.avail_out;
+                    d_stream.next_out = decompressed_out;
+                    d_stream.avail_out = MAX_OUTSIZE;
+
+                    err = PREFIX(inflate)(&d_stream, Z_FINISH);
+                    if (err != Z_STREAM_END) {
+                        fprintf(stderr, error_format, "inflate", level, wbits, memlevel, strategy, err, d_stream.msg);
+                        return EXIT_FAILURE;
+                    }
+
+                    if (((MAX_OUTSIZE - d_stream.avail_out) != read_size) || memcmp(data_in, decompressed_out, read_size) !=0) {
+                        fprintf(stderr, error_format, "Input and output is not the same", level, wbits, memlevel, strategy, 0, "");
+                        fprintf(stderr,
+                                "in bytes: %u\n"
+                                "out_bytes:%u\n"
+                                "compare_result:%d\n",
+                                read_size, MAX_OUTSIZE - d_stream.avail_out,
+                                memcmp(data_in, decompressed_out, read_size));
+                        return EXIT_FAILURE;
+                    }
+
+                    err = PREFIX(deflateEnd)(&c_stream);
+                    if (err != Z_OK) {
+                        printf("%d", c_stream.avail_out);
+                        fprintf(stderr, error_format, "deflateEnd", level, wbits, memlevel, strategy, err, c_stream.msg);
+                        return EXIT_FAILURE;
+                    }
+
+                    err = PREFIX(inflateEnd)(&d_stream);
+                    if (err != Z_OK) {
+                        fprintf(stderr, error_format, "inflateEnd", level, wbits, memlevel, strategy, err, d_stream.msg);
+                        return EXIT_FAILURE;
+                    }
+                }
+            }
+        }
+    }
+    return EXIT_SUCCESS;
+}