diff --git a/.cirrus.yml b/.cirrus.yml new file mode 100644 index 000000000..750f84baf --- /dev/null +++ b/.cirrus.yml @@ -0,0 +1,72 @@ +upload_junit_template: &UPLOAD_JUNIT + always: + junit_artifacts: + path: "btmp/*-junit.xml" + type: text/xml + format: junit + +check_docker_task: + matrix: + - name: "ubu1404" + container: + dockerfile: ci/cirrus/ubu1404/Dockerfile # remove 2022/4 + - name: "ubu1604" + container: + dockerfile: ci/cirrus/ubu1604/Dockerfile # remove 2024/4 + - name: "ubu1804" + container: + dockerfile: ci/cirrus/ubu1804/Dockerfile # remove 2028/4 + - name: "ubu2004" + container: + dockerfile: ci/cirrus/ubu2004/Dockerfile + - name: "ubu2010" + container: + dockerfile: ci/cirrus/ubu2010/Dockerfile # remove 2021/7 + - name: "debian8" + container: + dockerfile: ci/cirrus/debian8/Dockerfile # remove 2020/7 + - name: "debian9" + container: + dockerfile: ci/cirrus/debian9/Dockerfile # remove 2022/7 + - name: "debian10" + container: + dockerfile: ci/cirrus/debian10/Dockerfile + - name: "fedora31" + container: + dockerfile: ci/cirrus/fedora31/Dockerfile # remove 2020/11 + - name: "fedora32" + container: + dockerfile: ci/cirrus/fedora32/Dockerfile # remove 2021/5 + test_script: + - sh ci/test-cmake.sh && sh ci/pkgcheck.sh + << : *UPLOAD_JUNIT + +check_mac_task: + osx_instance: + image: catalina-xcode + install_script: + - brew install ninja + test_script: + - sh ci/test-cmake.sh && sh ci/pkgcheck.sh + << : *UPLOAD_JUNIT + +check_bsd_task: + freebsd_instance: + image_family: freebsd-12-1 + install_script: + - pkg install -y gcc cmake ninja + test_script: + - sh ci/test-cmake.sh && sh ci/pkgcheck.sh + << : *UPLOAD_JUNIT + +check_win_task: + windows_container: + image: cirrusci/windowsservercore:cmake + install_script: + - choco install -y --no-progress ninja + test_script: + - cmake --version + - ninja --version + - echo "Setting compiler to MSVC rather than the default (GCC from chocolatey)" + - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\Auxiliary\Build\vcvars64.bat" && where cl && set CC=cl && mkdir btmp && cd btmp && cmake -G Ninja .. && ninja && ctest -V + << : *UPLOAD_JUNIT diff --git a/CMakeLists.txt b/CMakeLists.txt index e108c16f8..85c414884 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,16 +3,31 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON) project(zlib C) +# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) +string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" + "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) +# FIXME: parse VERSION from ZLIB_FULL_VERSION set(VERSION "1.2.11.1") option(ASM686 "Enable building i686 assembly implementation") option(AMD64 "Enable building amd64 assembly implementation") +option(JUNIT "Enable junit output when testing") set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables") set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries") set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers") set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages") -set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") +set(INSTALL_PKGCONFIG_DIR "${INSTALL_LIB_DIR}/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files") + +# Set a default build type if none was specified +set(default_build_type "Release") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() include(CheckTypeSize) include(CheckFunctionExists) @@ -21,8 +36,35 @@ include(CheckCSourceCompiles) enable_testing() check_include_file(sys/types.h HAVE_SYS_TYPES_H) +check_include_file(stdarg.h HAVE_STDARG_H) check_include_file(stdint.h HAVE_STDINT_H) check_include_file(stddef.h HAVE_STDDEF_H) +check_include_file(unistd.h HAVE_UNISTD_H) + +# +# Match configure's zconf.h exactly +# +if (HAVE_STDARG_H) + SET(ZCONF_STDARG_LINE "#if 1 /* was set to #if 1 by ./configure */") +else() + SET(ZCONF_STDARG_LINE "#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */") +endif() +if (HAVE_UNISTD_H) + SET(ZCONF_UNISTD_LINE "#if 1 /* was set to #if 1 by ./configure */") +else() + SET(ZCONF_UNISTD_LINE "#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */") +endif() + +# +# Check to see if compiler supports __attribute__((visibility ("hidden"))) +# +check_c_source_compiles( + "int __attribute__((visibility (\"hidden\"))) foo; int main() { return foo; }" + HAVE_HIDDEN +) +if(HAVE_HIDDEN) + add_definitions(-DHAVE_HIDDEN) +endif() # # Check to see if we have large file support @@ -57,7 +99,7 @@ endif() # # Check for unistd.h # -check_include_file(unistd.h Z_HAVE_UNISTD_H) +check_include_file(unistd.h HAVE_UNISTD_H) if(MSVC) set(CMAKE_DEBUG_POSTFIX "d") @@ -78,6 +120,19 @@ if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR) endif() endif() +# Refer to prefix symbolically to ease relocation by end user, +# and match Makefile-generate .pc file exactly. +if(INSTALL_INC_DIR STREQUAL "${CMAKE_INSTALL_PREFIX}/include") + set(PC_INSTALL_INC_DIR "\${prefix}/include") +else() + set(PC_INSTALL_INC_DIR "${INSTALL_INC_DIR}") +endif() +if(INSTALL_LIB_DIR STREQUAL "${CMAKE_INSTALL_PREFIX}/lib") + set(PC_INSTALL_LIB_DIR "\${exec_prefix}/lib") +else() + set(PC_INSTALL_LIB_DIR "${INSTALL_LIB_DIR}") +endif() + set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein ${ZLIB_PC} @ONLY) @@ -105,22 +160,27 @@ set(ZLIB_PRIVATE_HDRS trees.h zutil.h ) + +# Note: keep these in the same order as in Makefile.in +# This allows libz.so to be identical between the two build systems. set(ZLIB_SRCS + # Makefile.in: PIC_OBJZ adler32.c - compress.c crc32.c deflate.c - gzclose.c - gzlib.c - gzread.c - gzwrite.c - inflate.c infback.c - inftrees.c inffast.c + inflate.c + inftrees.c trees.c - uncompr.c zutil.c + # Makefile.in: PIC_OBJG + compress.c + uncompr.c + gzclose.c + gzlib.c + gzread.c + gzwrite.c ) if(NOT MINGW) @@ -162,11 +222,6 @@ if(MSVC) endif() endif() -# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION -file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents) -string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*" - "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents}) - if(MINGW) # This gets us DLL resource information when compiling on MinGW. if(NOT CMAKE_RC_COMPILER) @@ -204,6 +259,9 @@ if(UNIX) set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z) if(NOT APPLE) set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"") + # Makefile.in uses -lc... + set(LDSHAREDLIBC -lc) + target_link_libraries(zlib ${LDSHAREDLIBC}) endif() elseif(BUILD_SHARED_LIBS AND WIN32) # Creates zlib1.dll when building shared library version @@ -232,7 +290,12 @@ endif() add_executable(example test/example.c) target_link_libraries(example zlib) -add_test(example example) +if(JUNIT) + add_test(example example --junit ${CMAKE_CURRENT_BINARY_DIR}/example-junit.xml) +else() + add_test(example example) +endif() + add_executable(minigzip test/minigzip.c) target_link_libraries(minigzip zlib) @@ -241,7 +304,11 @@ if(HAVE_OFF64_T) add_executable(example64 test/example.c) target_link_libraries(example64 zlib) set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64") - add_test(example64 example64) + if(JUNIT) + add_test(example64 example64 --junit ${CMAKE_CURRENT_BINARY_DIR}/example64-junit.xml) + else() + add_test(example64 example64) + endif() add_executable(minigzip64 test/minigzip.c) target_link_libraries(minigzip64 zlib) diff --git a/README b/README.md similarity index 90% rename from README rename to README.md index 5b74a3cdf..c44761bf8 100644 --- a/README +++ b/README.md @@ -1,5 +1,7 @@ ZLIB DATA COMPRESSION LIBRARY +[![AppVeyor CI status][appveyor-shield]][appveyor-link][![Cirrus CI status][cirrus-shield]][cirrus-link] + zlib 1.2.11.1 is a general purpose data compression library. All the code is thread safe. The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files @@ -102,8 +104,7 @@ Copyright notice: misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu + Jean-loup Gailly (jloup@gzip.org) & Mark Adler (madler@alumni.caltech.edu) If you use the zlib library in a product, we would appreciate *not* receiving lengthy legal documents to sign. The sources are provided for free but without @@ -116,3 +117,9 @@ any third parties. If you redistribute modified sources, we would appreciate that you include in the file ChangeLog history information documenting your changes. Please read the FAQ for more information on the distribution of modified source versions. + + +[appveyor-shield]: https://ci.appveyor.com/api/projects/status/h80iqyhbe09p29n0/branch/develop?svg=true +[appveyor-link]: https://ci.appveyor.com/project/dankegel/zlib/branch/develop +[cirrus-shield]: https://api.cirrus-ci.com/github/dankegel/zlib.svg?branch=develop +[cirrus-link]: https://cirrus-ci.com/github/dankegel/zlib/develop diff --git a/ci/appveyor.yml b/ci/appveyor.yml new file mode 100644 index 000000000..c0e2d7d9b --- /dev/null +++ b/ci/appveyor.yml @@ -0,0 +1,33 @@ +version: 1.2.11.1.{build} + +pull_requests: + do_not_increment_build_number: true + +shallow_clone: true + +image: + - Visual Studio 2019 + +before_build: + - cmd: cmake -DJUNIT=ON . + +build: + project: "zlib.sln" + +platform: + - x64 +configuration: + - Debug + - Release + +test_script: + - ps: | + &"ctest" -V + $testError = $LastExitCode + $wc = New-Object 'System.Net.WebClient' + $jurl = "https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)" + $wc.UploadFile($jurl, (Resolve-Path "$($env:APPVEYOR_BUILD_FOLDER)\example-junit.xml")) + if ($testError -ne 0) + { + throw $testError + } diff --git a/ci/cirrus/debian10/Dockerfile b/ci/cirrus/debian10/Dockerfile new file mode 100644 index 000000000..fad0f0f6a --- /dev/null +++ b/ci/cirrus/debian10/Dockerfile @@ -0,0 +1,5 @@ +FROM debian:10 + +RUN apt-get update && \ + apt-get install --no-install-recommends -y cmake gcc libc6-dev ninja-build make && \ + apt-get clean diff --git a/ci/cirrus/debian8/Dockerfile b/ci/cirrus/debian8/Dockerfile new file mode 100644 index 000000000..25e24929f --- /dev/null +++ b/ci/cirrus/debian8/Dockerfile @@ -0,0 +1,5 @@ +FROM debian:8 + +RUN apt-get update && \ + apt-get install --no-install-recommends -y cmake gcc libc6-dev ninja-build make && \ + apt-get clean diff --git a/ci/cirrus/debian9/Dockerfile b/ci/cirrus/debian9/Dockerfile new file mode 100644 index 000000000..1e19b248c --- /dev/null +++ b/ci/cirrus/debian9/Dockerfile @@ -0,0 +1,5 @@ +FROM debian:9 + +RUN apt-get update && \ + apt-get install --no-install-recommends -y cmake gcc libc6-dev ninja-build make && \ + apt-get clean diff --git a/ci/cirrus/fedora31/Dockerfile b/ci/cirrus/fedora31/Dockerfile new file mode 100644 index 000000000..a4ccdf216 --- /dev/null +++ b/ci/cirrus/fedora31/Dockerfile @@ -0,0 +1,12 @@ +FROM fedora:31 + +RUN dnf -y update && dnf clean all + +RUN dnf makecache \ + && dnf -y install \ + gcc \ + cmake \ + diffutils \ + make \ + ninja-build \ + && dnf clean all diff --git a/ci/cirrus/fedora32/Dockerfile b/ci/cirrus/fedora32/Dockerfile new file mode 100644 index 000000000..ab316e903 --- /dev/null +++ b/ci/cirrus/fedora32/Dockerfile @@ -0,0 +1,12 @@ +FROM fedora:32 + +RUN dnf -y update && dnf clean all + +RUN dnf makecache \ + && dnf -y install \ + gcc \ + cmake \ + diffutils \ + make \ + ninja-build \ + && dnf clean all diff --git a/ci/cirrus/ubu1404/Dockerfile b/ci/cirrus/ubu1404/Dockerfile new file mode 100644 index 000000000..6367509c0 --- /dev/null +++ b/ci/cirrus/ubu1404/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:14.04 + +RUN apt-get update && \ + apt-get install --no-install-recommends -y cmake gcc libc6-dev ninja-build make && \ + apt-get clean diff --git a/ci/cirrus/ubu1604/Dockerfile b/ci/cirrus/ubu1604/Dockerfile new file mode 100644 index 000000000..fc3234014 --- /dev/null +++ b/ci/cirrus/ubu1604/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:16.04 + +RUN apt-get update && \ + apt-get install --no-install-recommends -y cmake gcc libc6-dev ninja-build make && \ + apt-get clean diff --git a/ci/cirrus/ubu1804/Dockerfile b/ci/cirrus/ubu1804/Dockerfile new file mode 100644 index 000000000..ebfd25e1a --- /dev/null +++ b/ci/cirrus/ubu1804/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:18.04 + +RUN apt-get update && \ + apt-get install --no-install-recommends -y cmake gcc libc6-dev ninja-build make && \ + apt-get clean diff --git a/ci/cirrus/ubu2004/Dockerfile b/ci/cirrus/ubu2004/Dockerfile new file mode 100644 index 000000000..99f06be80 --- /dev/null +++ b/ci/cirrus/ubu2004/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:20.04 + +RUN apt-get update && \ + apt-get install --no-install-recommends -y cmake gcc libc6-dev ninja-build make && \ + apt-get clean diff --git a/ci/cirrus/ubu2010/Dockerfile b/ci/cirrus/ubu2010/Dockerfile new file mode 100644 index 000000000..42cf02000 --- /dev/null +++ b/ci/cirrus/ubu2010/Dockerfile @@ -0,0 +1,5 @@ +FROM ubuntu:20.10 + +RUN apt-get update && \ + apt-get install --no-install-recommends -y cmake gcc libc6-dev ninja-build make && \ + apt-get clean diff --git a/ci/pkgcheck.sh b/ci/pkgcheck.sh new file mode 100644 index 000000000..f96a103ac --- /dev/null +++ b/ci/pkgcheck.sh @@ -0,0 +1,90 @@ +#!/bin/sh +# Verify that the various build systems produce identical results on a Unixlike system +set -ex + +# Tell GNU's ld etc. to use Jan 1 1970 when embedding timestamps +export SOURCE_DATE_EPOCH=0 +# Tell Apple's ar etc. to use zero timestamps +export ZERO_AR_DATE=1 + +# Use same compiler for make and cmake builds +if clang --version +then + export CC=clang +elif gcc --version +then + export CC=gcc +fi + +# New build system +# Happens to delete top-level zconf.h +# (which itself is a bug, https://github.com/madler/zlib/issues/162 ) +# which triggers another bug later in configure, +# https://github.com/madler/zlib/issues/499 +rm -rf btmp2 pkgtmp2 +mkdir btmp2 pkgtmp2 +export DESTDIR=$(pwd)/pkgtmp2 +cd btmp2 + cmake -G Ninja .. + ninja -v + ninja install +cd .. + +# Original build system +rm -rf btmp1 pkgtmp1 +mkdir btmp1 pkgtmp1 +export DESTDIR=$(pwd)/pkgtmp1 +cd btmp1 + case $(uname) in + Darwin) + export LDFLAGS="-Wl,-headerpad_max_install_names" + ;; + Linux) + if grep -i fedora /etc/os-release > /dev/null + then + # Note: Fedora patches cmake to use -O2 in release, which + # does not match the -O3 configure sets :-( + export CFLAGS="-O2 -DNDEBUG" + fi + ;; + esac + ../configure + make + make install +cd .. + +repack_ar() { + if ! cmp --silent pkgtmp1/usr/local/lib/libz.a pkgtmp2/usr/local/lib/libz.a + then + echo "Warning: libz.a does not match. Assuming ar needs -D option. Unpacking..." + cd pkgtmp1; ar x usr/local/lib/libz.a; rm usr/local/lib/libz.a; cd .. + cd pkgtmp2; ar x usr/local/lib/libz.a; rm usr/local/lib/libz.a; cd .. + fi +} + +case $(uname) in +Darwin) + # Alas, dylibs still have an embedded hash or something, + # so nuke it. + # FIXME: find a less fragile way to deal with this. + dylib1=$(find pkgtmp1 -name '*.dylib*' -type f) + dylib2=$(find pkgtmp2 -name '*.dylib*' -type f) + dd conv=notrunc if=/dev/zero of=$dylib1 skip=1337 count=16 + dd conv=notrunc if=/dev/zero of=$dylib2 skip=1337 count=16 + ;; +FreeBSD|Linux) + # The ar on newer systems defaults to -D (i.e. deterministic), + # but FreeBSD 12.1, Debian 8, and Ubuntu 14.04 seem to not do that. + # I had trouble passing -D safely to the ar inside CMakeLists.txt, + # so punt and unpack the archive if needed before comparing. + repack_ar + ;; +esac + +if diff -Nur pkgtmp1 pkgtmp2 +then + echo pkgcheck-cmake-bits-identical PASS +else + echo pkgcheck-cmake-bits-identical FAIL + exit 1 +fi diff --git a/ci/test-cmake.sh b/ci/test-cmake.sh new file mode 100644 index 000000000..a00693bfe --- /dev/null +++ b/ci/test-cmake.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# Build and test with CMake; output junit xml files. +set -ex + +rm -rf btmp +mkdir btmp +cd btmp + cmake -G Ninja -DJUNIT=ON .. + ninja + ctest -V +cd .. diff --git a/ci/test-make.sh b/ci/test-make.sh new file mode 100644 index 000000000..41a5f733b --- /dev/null +++ b/ci/test-make.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# Build and test with Make +set -ex + +rm -rf btmp +mkdir btmp +cd btmp1 + ../configure + make + make test +cd .. diff --git a/configure b/configure index 1cd4fe57a..fd0c33a90 100755 --- a/configure +++ b/configure @@ -25,7 +25,7 @@ if test $SRCDIR = "."; then ZINCOUT="-I." SRCDIR="" else - ZINC='-include zconf.h' + ZINC='-I. -include zconf.h' ZINCOUT='-I. -I$(SRCDIR)' SRCDIR="$SRCDIR/" fi diff --git a/test/example.c b/test/example.c index 949f4f625..c5d6333b0 100644 --- a/test/example.c +++ b/test/example.c @@ -19,13 +19,129 @@ # define TESTFILE "foo.gz" #endif -#define CHECK_ERR(err, msg) { \ - if (err != Z_OK) { \ - fprintf(stderr, "%s error: %d\n", msg, err); \ - exit(1); \ +#define SUCCESSFUL 1 +#define FAILED_WITH_ERROR_CODE 0 +#define FAILED_WITHOUT_ERROR_CODE -1 + +typedef struct test_result_s { + int result; /* One of: SUCCESSFUL, + FAILED_WITH_ERROR_CODE, or + FAILED_WITHOUT_ERROR_CODE*/ + int error_code; /* error code if success is FAILED_WITH_ERROR_CODE */ + int line_number; + const char* message; + const char* extended_message; +} test_result; + +#define STRING_BUFFER_SIZE 100 +char string_buffer[STRING_BUFFER_SIZE]; +int g_fail_fast; +char g_test_class[STRING_BUFFER_SIZE] = "default"; + +#define CHECK_ERR(_error_code, _message) { \ + if (_error_code != Z_OK) { \ + test_result result; \ + result.result = FAILED_WITH_ERROR_CODE; \ + result.error_code = _error_code; \ + result.line_number = __LINE__; \ + result.message = _message; \ + result.extended_message = NULL; \ + return result; \ } \ } +#define RETURN_FAILURE(_message, _extended_message) { \ + test_result result; \ + result.result = FAILED_WITHOUT_ERROR_CODE; \ + result.error_code = Z_OK; \ + result.line_number = __LINE__; \ + result.message = _message; \ + result.extended_message = _extended_message; \ + return result; \ +} + +#define RETURN_SUCCESS(_message, _extended_message) { \ + test_result result; \ + result.result = SUCCESSFUL; \ + result.error_code = Z_OK; \ + result.message = _message; \ + result.extended_message = _extended_message; \ + return result; \ +} + +void handle_stdout_test_results OF((test_result result, const char* testcase_name)); +void handle_junit_test_results OF((FILE* output, test_result result, const char* testcase_name)); +void handle_test_results OF((FILE* output, test_result result, const char* testcase_name, int is_junit_output, int* failed_test_count)); + +void handle_stdout_test_results(result, testcase_name) + test_result result; + const char* testcase_name; +{ + if (result.result == FAILED_WITH_ERROR_CODE) { + fprintf(stderr, "%s error: %d\n", result.message, result.error_code); + } else if (result.result == FAILED_WITHOUT_ERROR_CODE) { + fprintf(stderr, "%s", result.message); + if (result.extended_message != NULL) { + fprintf(stderr, "%s", result.extended_message); + } + fprintf(stderr, "\n"); + } else { + if (result.message != NULL) { + if (result.extended_message != NULL) { + fprintf(stderr, "%s%s\n", result.message, result.extended_message); + } else { + fprintf(stderr, "%s", result.message); + } + } + } +} + +void handle_junit_test_results(output, result, testcase_name) + FILE* output; + test_result result; + const char* testcase_name; +{ + /* github.com/cirruslabs/cirrus-ci-annotations/blob/master/testdata/junit/PythonXMLRunner.xml + * suggests how to encode classname, file, and line to get + * annotations to appear properly on github. + */ + if (result.result == FAILED_WITH_ERROR_CODE) { + fprintf(output, + "\t\t\n" + "\t\t\t%s: error %d\n" + "\t\t\n", + g_test_class, testcase_name, __FILE__, result.line_number, result.message, + result.error_code); + } else if (result.result == FAILED_WITHOUT_ERROR_CODE) { + fprintf(output, + "\t\t\n" + "\t\t\t%s%s\n" + "\t\t\n", + g_test_class, testcase_name, __FILE__, result.line_number, result.message, + (result.extended_message ? result.extended_message : "")); + } else { + fprintf(output, "\t\t\n", testcase_name); + } +} + +void handle_test_results(output, result, testcase_name, is_junit_output, failed_test_count) + FILE* output; + test_result result; + const char* testcase_name; + int is_junit_output; + int* failed_test_count; +{ + if (is_junit_output) { + handle_junit_test_results(output, result, testcase_name); + } + handle_stdout_test_results(result, testcase_name); + if (result.result == FAILED_WITH_ERROR_CODE || result.result == FAILED_WITHOUT_ERROR_CODE) { + (*failed_test_count)++; + if (g_fail_fast) + exit(1); + } +} + static z_const char hello[] = "hello, hello!"; /* "hello world" would be more standard, but the repeated "hello" * stresses the compression code better, sorry... @@ -34,20 +150,20 @@ static z_const char hello[] = "hello, hello!"; static const char dictionary[] = "hello"; static uLong dictId; /* Adler32 value of the dictionary */ -void test_deflate OF((Byte *compr, uLong comprLen)); -void test_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_large_deflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_large_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_flush OF((Byte *compr, uLong *comprLen)); -void test_sync OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_dict_deflate OF((Byte *compr, uLong comprLen)); -void test_dict_inflate OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -int main OF((int argc, char *argv[])); +test_result test_deflate OF((Byte *compr, uLong comprLen)); +test_result test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +test_result test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +test_result test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +test_result test_flush OF((Byte *compr, uLong *comprLen)); +test_result test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +test_result test_dict_deflate OF((Byte *compr, uLong comprLen)); +test_result test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); #ifdef Z_SOLO @@ -77,15 +193,16 @@ static free_func zfree = myfree; static alloc_func zalloc = (alloc_func)0; static free_func zfree = (free_func)0; -void test_compress OF((Byte *compr, uLong comprLen, - Byte *uncompr, uLong uncomprLen)); -void test_gzio OF((const char *fname, - Byte *uncompr, uLong uncomprLen)); +test_result test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +test_result test_gzio OF((const char *fname, + Byte *uncompr, uLong uncomprLen)); +test_result test_force_fail OF((int force_fail)); /* =========================================================================== * Test compress() and uncompress() */ -void test_compress(compr, comprLen, uncompr, uncomprLen) +test_result test_compress(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { @@ -101,23 +218,22 @@ void test_compress(compr, comprLen, uncompr, uncomprLen) CHECK_ERR(err, "uncompress"); if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad uncompress\n"); - exit(1); + RETURN_FAILURE("bad uncompress\n", NULL); } else { - printf("uncompress(): %s\n", (char *)uncompr); + RETURN_SUCCESS("uncompress(): ", (char*)uncompr); } } /* =========================================================================== * Test read/write of .gz files */ -void test_gzio(fname, uncompr, uncomprLen) +test_result test_gzio(fname, uncompr, uncomprLen) const char *fname; /* compressed file name */ Byte *uncompr; uLong uncomprLen; { #ifdef NO_GZCOMPRESS - fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n"); + RETURN_FAILURE("NO_GZCOMPRESS -- gz* functions cannot compress", NULL); #else int err; int len = (int)strlen(hello)+1; @@ -126,78 +242,90 @@ void test_gzio(fname, uncompr, uncomprLen) file = gzopen(fname, "wb"); if (file == NULL) { - fprintf(stderr, "gzopen error\n"); - exit(1); + RETURN_FAILURE("gzopen error", NULL); } gzputc(file, 'h'); if (gzputs(file, "ello") != 4) { - fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err)); - exit(1); + RETURN_FAILURE("gzputs err: ", gzerror(file, &err)); } if (gzprintf(file, ", %s!", "hello") != 8) { - fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err)); - exit(1); + RETURN_FAILURE("gzprintf err: ", gzerror(file, &err)); } gzseek(file, 1L, SEEK_CUR); /* add one zero byte */ gzclose(file); file = gzopen(fname, "rb"); if (file == NULL) { - fprintf(stderr, "gzopen error\n"); - exit(1); + RETURN_FAILURE("gzopen error", NULL); } strcpy((char*)uncompr, "garbage"); if (gzread(file, uncompr, (unsigned)uncomprLen) != len) { - fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); - exit(1); + RETURN_FAILURE("gzread err: ", gzerror(file, &err)); } if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad gzread: %s\n", (char*)uncompr); - exit(1); + RETURN_FAILURE("bad gzread: ", (char*)uncompr); } else { printf("gzread(): %s\n", (char*)uncompr); } pos = gzseek(file, -8L, SEEK_CUR); if (pos != 6 || gztell(file) != pos) { - fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n", + test_result result; + sprintf(string_buffer, "gzseek error, pos=%ld, gztell=%ld\n", (long)pos, (long)gztell(file)); - exit(1); + result.result = FAILED_WITHOUT_ERROR_CODE; + result.error_code = Z_OK; + result.line_number = __LINE__; + result.message = string_buffer; + result.extended_message = NULL; + return result; } if (gzgetc(file) != ' ') { - fprintf(stderr, "gzgetc error\n"); - exit(1); + RETURN_FAILURE("gzgetc error", NULL); } if (gzungetc(' ', file) != ' ') { - fprintf(stderr, "gzungetc error\n"); - exit(1); + RETURN_FAILURE("gzungetc error", NULL); } gzgets(file, (char*)uncompr, (int)uncomprLen); if (strlen((char*)uncompr) != 7) { /* " hello!" */ - fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err)); - exit(1); + RETURN_FAILURE("gzgets err after gzseek: ", gzerror(file, &err)); } if (strcmp((char*)uncompr, hello + 6)) { - fprintf(stderr, "bad gzgets after gzseek\n"); - exit(1); + RETURN_FAILURE("bad gzgets after gzseek", NULL); } else { printf("gzgets() after gzseek: %s\n", (char*)uncompr); } gzclose(file); + + RETURN_SUCCESS(NULL, NULL); #endif } +/* =========================================================================== + * Optionally test fault injection. + */ +test_result test_force_fail(force_fail) + int force_fail; +{ + int err = Z_OK; + if (force_fail) + err = 54321; + CHECK_ERR(err, "forced"); + + RETURN_SUCCESS(NULL, NULL); +} + #endif /* Z_SOLO */ /* =========================================================================== * Test deflate() with small buffers */ -void test_deflate(compr, comprLen) +test_result test_deflate(compr, comprLen) Byte *compr; uLong comprLen; { @@ -230,12 +358,14 @@ void test_deflate(compr, comprLen) err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); + + RETURN_SUCCESS(NULL, NULL); } /* =========================================================================== * Test inflate() with small buffers */ -void test_inflate(compr, comprLen, uncompr, uncomprLen) +test_result test_inflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { @@ -266,17 +396,16 @@ void test_inflate(compr, comprLen, uncompr, uncomprLen) CHECK_ERR(err, "inflateEnd"); if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad inflate\n"); - exit(1); + RETURN_FAILURE("bad inflate\n", NULL); } else { - printf("inflate(): %s\n", (char *)uncompr); + RETURN_SUCCESS("inflate(): ", (char*)uncompr); } } /* =========================================================================== * Test deflate() with large buffers and dynamic change of compression level */ -void test_large_deflate(compr, comprLen, uncompr, uncomprLen) +test_result test_large_deflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { @@ -301,8 +430,7 @@ void test_large_deflate(compr, comprLen, uncompr, uncomprLen) err = deflate(&c_stream, Z_NO_FLUSH); CHECK_ERR(err, "deflate"); if (c_stream.avail_in != 0) { - fprintf(stderr, "deflate not greedy\n"); - exit(1); + RETURN_FAILURE("deflate not greedy\n", NULL); } /* Feed in already compressed data and switch to no compression: */ @@ -321,17 +449,18 @@ void test_large_deflate(compr, comprLen, uncompr, uncomprLen) err = deflate(&c_stream, Z_FINISH); if (err != Z_STREAM_END) { - fprintf(stderr, "deflate should report Z_STREAM_END\n"); - exit(1); + RETURN_FAILURE("deflate should report Z_STREAM_END\n", NULL); } err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); + + RETURN_SUCCESS(NULL, NULL); } /* =========================================================================== * Test inflate() with large buffers */ -void test_large_inflate(compr, comprLen, uncompr, uncomprLen) +test_result test_large_inflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { @@ -362,17 +491,23 @@ void test_large_inflate(compr, comprLen, uncompr, uncomprLen) CHECK_ERR(err, "inflateEnd"); if (d_stream.total_out != 2*uncomprLen + comprLen/2) { - fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); - exit(1); + test_result result; + sprintf(string_buffer, "bad large inflate: %ld\n", d_stream.total_out); + result.result = FAILED_WITHOUT_ERROR_CODE; + result.error_code = Z_OK; + result.line_number = __LINE__; + result.message = string_buffer; + result.extended_message = NULL; + return result; } else { - printf("large_inflate(): OK\n"); + RETURN_SUCCESS("large_inflate(): OK\n", NULL); } } /* =========================================================================== * Test deflate() with full flush */ -void test_flush(compr, comprLen) +test_result test_flush(compr, comprLen) Byte *compr; uLong *comprLen; { @@ -405,12 +540,14 @@ void test_flush(compr, comprLen) CHECK_ERR(err, "deflateEnd"); *comprLen = c_stream.total_out; + + RETURN_SUCCESS(NULL, NULL); } /* =========================================================================== * Test inflateSync() */ -void test_sync(compr, comprLen, uncompr, uncomprLen) +test_result test_sync(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { @@ -441,19 +578,18 @@ void test_sync(compr, comprLen, uncompr, uncomprLen) err = inflate(&d_stream, Z_FINISH); if (err != Z_STREAM_END) { - fprintf(stderr, "inflate should report Z_STREAM_END\n"); - exit(1); + RETURN_FAILURE("inflate should report Z_STREAM_END\n", NULL); } err = inflateEnd(&d_stream); CHECK_ERR(err, "inflateEnd"); - printf("after inflateSync(): hel%s\n", (char *)uncompr); + RETURN_SUCCESS("after inflateSync(): hel", (char*)uncompr); } /* =========================================================================== * Test deflate() with preset dictionary */ -void test_dict_deflate(compr, comprLen) +test_result test_dict_deflate(compr, comprLen) Byte *compr; uLong comprLen; { @@ -480,17 +616,18 @@ void test_dict_deflate(compr, comprLen) err = deflate(&c_stream, Z_FINISH); if (err != Z_STREAM_END) { - fprintf(stderr, "deflate should report Z_STREAM_END\n"); - exit(1); + RETURN_FAILURE("deflate should report Z_STREAM_END\n", NULL); } err = deflateEnd(&c_stream); CHECK_ERR(err, "deflateEnd"); + + RETURN_SUCCESS(NULL, NULL); } /* =========================================================================== * Test inflate() with a preset dictionary */ -void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) +test_result test_dict_inflate(compr, comprLen, uncompr, uncomprLen) Byte *compr, *uncompr; uLong comprLen, uncomprLen; { @@ -530,15 +667,14 @@ void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) CHECK_ERR(err, "inflateEnd"); if (strcmp((char*)uncompr, hello)) { - fprintf(stderr, "bad inflate with dict\n"); - exit(1); + RETURN_FAILURE("bad inflate with dict\n", NULL); } else { - printf("inflate with dictionary: %s\n", (char *)uncompr); + RETURN_SUCCESS("inflate with dictionary: ", (char*)uncompr); } } /* =========================================================================== - * Usage: example [output.gz [input.gz]] + * Usage: example [--fail_fast][--force_fail][--junit results.xml] [output.gz [input.gz]] */ int main(argc, argv) @@ -549,11 +685,17 @@ int main(argc, argv) uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ uLong uncomprLen = comprLen; static const char* myVersion = ZLIB_VERSION; + test_result result; + int is_junit_output = 0; + const char* output_file_path = NULL; + FILE* output = stdout; + int next_argv_index = 1; + int failed_test_count = 0; + int force_fail = 0; if (zlibVersion()[0] != myVersion[0]) { fprintf(stderr, "incompatible zlib version\n"); exit(1); - } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { fprintf(stderr, "warning: different zlib version\n"); } @@ -575,27 +717,99 @@ int main(argc, argv) (void)argc; (void)argv; #else - test_compress(compr, comprLen, uncompr, uncomprLen); + output_file_path = getenv("ZLIB_JUNIT_OUTPUT_FILE"); + force_fail = getenv("ZLIB_FORCE_FAIL") && atoi(getenv("ZLIB_FORCE_FAIL")); + g_fail_fast = getenv("ZLIB_FAIL_FAST") && atoi(getenv("ZLIB_FAIL_FAST")); + while (next_argv_index < argc && !strncmp(argv[next_argv_index], "--", 2)) { + if (strcmp(argv[next_argv_index], "--junit") == 0) { + next_argv_index++; + if (argc <= next_argv_index) { + fprintf(stderr, "--junit flag requires an output file parameter, like --junit output.xml"); + exit(1); + } + output_file_path = argv[next_argv_index]; + next_argv_index++; + } else if (strcmp(argv[next_argv_index], "--fail_fast") == 0) { + g_fail_fast = 1; + next_argv_index++; + } else if (strcmp(argv[next_argv_index], "--force_fail") == 0) { + force_fail = 1; + next_argv_index++; + } else { + fprintf(stderr, "Unrecognized option %s\n", argv[next_argv_index]); + exit(1); + } + } + if (output_file_path) { + fprintf(stdout, "output path is %s", output_file_path); + is_junit_output = 1; + output = fopen(output_file_path, "w+"); + if (!output) { + fprintf(stderr, "Could not open junit file %s\n", output_file_path); + exit(1); + } else { + /* If run by CMakeLists.txt's JUNIT option, path is FOO/$exe-junit.xml. + * Extract $exe and pass to handle_junit_test_results so github error + * annotations show the name of the executable causing each error. + */ + const char *p = strrchr(output_file_path, '/'); + if (p) { + p++; /* skip past slash */ + const char *q = strrchr(p, '-'); + int len = q - p; + if (!strcmp(q, "-junit.xml") && (len < sizeof(g_test_class))) { + strncpy(g_test_class, p, len); + g_test_class[len] = 0; + } + } + } + fprintf(output, "\n"); + fprintf(output, "\n"); + fprintf(output, "\t\n"); + } + + result = test_compress(compr, comprLen, uncompr, uncomprLen); + handle_test_results(output, result, "compress", is_junit_output, &failed_test_count); + + result = test_gzio((argc > next_argv_index ? argv[next_argv_index++] : TESTFILE), + uncompr, uncomprLen); + handle_test_results(output, result, "gzio", is_junit_output, &failed_test_count); - test_gzio((argc > 1 ? argv[1] : TESTFILE), - uncompr, uncomprLen); + result = test_force_fail(force_fail); + handle_test_results(output, result, "force fail", is_junit_output, &failed_test_count); #endif - test_deflate(compr, comprLen); - test_inflate(compr, comprLen, uncompr, uncomprLen); + result = test_deflate(compr, comprLen); + handle_test_results(output, result, "deflate", is_junit_output, &failed_test_count); + result = test_inflate(compr, comprLen, uncompr, uncomprLen); + handle_test_results(output, result, "inflate", is_junit_output, &failed_test_count); - test_large_deflate(compr, comprLen, uncompr, uncomprLen); - test_large_inflate(compr, comprLen, uncompr, uncomprLen); + result = test_large_deflate(compr, comprLen, uncompr, uncomprLen); + handle_test_results(output, result, "large deflate", is_junit_output, &failed_test_count); + result = test_large_inflate(compr, comprLen, uncompr, uncomprLen); + handle_test_results(output, result, "large inflate", is_junit_output, &failed_test_count); - test_flush(compr, &comprLen); - test_sync(compr, comprLen, uncompr, uncomprLen); + result = test_flush(compr, &comprLen); + handle_test_results(output, result, "flush", is_junit_output, &failed_test_count); + result = test_sync(compr, comprLen, uncompr, uncomprLen); + handle_test_results(output, result, "sync", is_junit_output, &failed_test_count); comprLen = uncomprLen; - test_dict_deflate(compr, comprLen); - test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + result = test_dict_deflate(compr, comprLen); + handle_test_results(output, result, "dict deflate", is_junit_output, &failed_test_count); + result = test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + handle_test_results(output, result, "dict inflate", is_junit_output, &failed_test_count); + if (is_junit_output) { + fprintf(output, "\t\n"); + fprintf(output, ""); + fclose(output); + } free(compr); free(uncompr); + if (failed_test_count) { + return 1; + } return 0; } diff --git a/zconf.h.cmakein b/zconf.h.cmakein index a7f24cce6..83072aad7 100644 --- a/zconf.h.cmakein +++ b/zconf.h.cmakein @@ -7,8 +7,6 @@ #ifndef ZCONF_H #define ZCONF_H -#cmakedefine Z_PREFIX -#cmakedefine Z_HAVE_UNISTD_H /* * If you *really* need a unique prefix for all types and library functions, @@ -433,11 +431,11 @@ typedef uLong FAR uLongf; typedef unsigned long z_crc_t; #endif -#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ +@ZCONF_UNISTD_LINE@ # define Z_HAVE_UNISTD_H #endif -#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ +@ZCONF_STDARG_LINE@ # define Z_HAVE_STDARG_H #endif diff --git a/zlib.pc.cmakein b/zlib.pc.cmakein index a5e642938..a46594afb 100644 --- a/zlib.pc.cmakein +++ b/zlib.pc.cmakein @@ -1,12 +1,12 @@ prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=@CMAKE_INSTALL_PREFIX@ -libdir=@INSTALL_LIB_DIR@ -sharedlibdir=@INSTALL_LIB_DIR@ -includedir=@INSTALL_INC_DIR@ +exec_prefix=${prefix} +libdir=@PC_INSTALL_LIB_DIR@ +sharedlibdir=${libdir} +includedir=@PC_INSTALL_INC_DIR@ Name: zlib Description: zlib compression library -Version: @VERSION@ +Version: @ZLIB_FULL_VERSION@ Requires: Libs: -L${libdir} -L${sharedlibdir} -lz