From: Hans Kristian Rosbach Date: Mon, 17 Mar 2025 14:00:52 +0000 (+0100) Subject: Add parameterized testing, based on #1448 by Ruben Vorderman X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=33be7a3357d26567ec1d8c7727f08b13709cf9bf;p=thirdparty%2Fzlib-ng.git Add parameterized testing, based on #1448 by Ruben Vorderman Co-authored-by: Ruben Vorderman --- diff --git a/configure b/configure index fe19641b..5d354380 100755 --- 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 diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0150c703..86ec3a87 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -47,6 +47,11 @@ configure_test_executable(switchlevels) target_link_libraries(switchlevels zlib) set(SWITCHLEVELS_COMMAND ${CMAKE_CROSSCOMPILING_EMULATOR} $) +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} $) + 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) diff --git a/test/Makefile.in b/test/Makefile.in index 5b459659..fae87d63 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -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) diff --git a/test/cmake/test-data.cmake b/test/cmake/test-data.cmake index e60c356e..ca7a6d69 100644 --- a/test/cmake/test-data.cmake +++ b/test/cmake/test-data.cmake @@ -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 index 00000000..ba8c8bad --- /dev/null +++ b/test/cmake/test-detect.cmake @@ -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) diff --git a/test/cmake/test-tools.cmake b/test/cmake/test-tools.cmake index c2a683fb..d78d8e00 100644 --- a/test/cmake/test-tools.cmake +++ b/test/cmake/test-tools.cmake @@ -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 index 00000000..eb9d1ae8 --- /dev/null +++ b/test/parameterized_tester.c @@ -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 + +/* + * 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 \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; +}