name: CI CMake
on: [push, pull_request]
jobs:
  ci-cmake:
    name: ${{ matrix.name }}
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Ubuntu GCC
            os: ubuntu-latest
            compiler: gcc
            cmake-args: -DWITH_SANITIZER=Address
            codecov: ubuntu_gcc

          - name: Ubuntu GCC OSB -O1 No Unaligned64
            os: ubuntu-latest
            compiler: gcc
            cmake-args: -DWITH_UNALIGNED=ON -DUNALIGNED64_OK=OFF -DWITH_SANITIZER=Undefined
            build-dir: ../build
            build-src-dir: ../zlib-ng
            codecov: ubuntu_gcc_osb
            cflags: -O1 -g3

          - name: Ubuntu GCC -O3 No Unaligned
            os: ubuntu-latest
            compiler: gcc
            cmake-args: -DWITH_UNALIGNED=OFF
            codecov: ubuntu_gcc_o3
            cflags: -O3

          - name: Ubuntu GCC Link Zlib
            os: ubuntu-latest
            compiler: gcc
            cmake-args: -DZLIB_DUAL_LINK=ON

          - name: Ubuntu GCC No AVX2
            os: ubuntu-latest
            compiler: gcc
            cmake-args: -DWITH_AVX2=OFF -DWITH_SANITIZER=Undefined
            codecov: ubuntu_gcc_no_avx2

          - name: Ubuntu GCC No SSE2
            os: ubuntu-latest
            compiler: gcc
            cmake-args: -DWITH_SSE2=OFF -DWITH_SANITIZER=Undefined
            codecov: ubuntu_gcc_no_sse2

          - name: Ubuntu GCC No SSE4
            os: ubuntu-latest
            compiler: gcc
            cmake-args: -DWITH_SSE4=OFF -DWITH_SANITIZER=Undefined
            codecov: ubuntu_gcc_no_sse4

          - name: Ubuntu GCC No PCLMULQDQ
            os: ubuntu-latest
            compiler: gcc
            cmake-args: -DWITH_PCLMULQDQ=OFF -DWITH_SANITIZER=Undefined
            codecov: ubuntu_gcc_no_pclmulqdq

          - name: Ubuntu GCC Compat No Opt
            os: ubuntu-latest
            compiler: gcc
            cmake-args: -DZLIB_COMPAT=ON -DWITH_NEW_STRATEGIES=OFF -DWITH_OPTIM=OFF -DWITH_SANITIZER=Address
            codecov: ubuntu_gcc_compat_no_opt
            cflags: -DNOT_TWEAK_COMPILER

          - name: Ubuntu GCC ARM SF
            os: ubuntu-latest
            compiler: arm-linux-gnueabi-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm.cmake -DCMAKE_C_COMPILER_TARGET=arm-linux-gnueabi -DWITH_SANITIZER=Address
            packages: qemu gcc-arm-linux-gnueabi libc-dev-armel-cross
            codecov: ubuntu_gcc_armsf

          - name: Ubuntu GCC ARM SF Compat No Opt
            os: ubuntu-latest
            compiler: arm-linux-gnueabi-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm.cmake -DCMAKE_C_COMPILER_TARGET=arm-linux-gnueabi -DZLIB_COMPAT=ON -DWITH_NEW_STRATEGIES=OFF -DWITH_OPTIM=OFF -DWITH_SANITIZER=Undefined
            packages: qemu gcc-arm-linux-gnueabi libc-dev-armel-cross
            codecov: ubuntu_gcc_armsf_compat_no_opt

          - name: Ubuntu GCC ARM HF
            os: ubuntu-latest
            compiler: arm-linux-gnueabihf-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm.cmake -DCMAKE_C_COMPILER_TARGET=arm-linux-gnueabihf -DWITH_SANITIZER=Address
            packages: qemu gcc-arm-linux-gnueabihf libc-dev-armel-cross
            codecov: ubuntu_gcc_armhf

          - name: Ubuntu GCC ARM HF No ACLE
            os: ubuntu-latest
            compiler: arm-linux-gnueabihf-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm.cmake -DCMAKE_C_COMPILER_TARGET=arm-linux-gnueabihf -DWITH_ACLE=OFF -DWITH_SANITIZER=Address
            packages: qemu gcc-arm-linux-gnueabihf libc-dev-armel-cross
            codecov: ubuntu_gcc_armhf_no_acle

          - name: Ubuntu GCC ARM HF No NEON
            os: ubuntu-latest
            compiler: arm-linux-gnueabihf-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm.cmake -DCMAKE_C_COMPILER_TARGET=arm-linux-gnueabihf -DWITH_NEON=OFF -DWITH_SANITIZER=Address
            packages: qemu gcc-arm-linux-gnueabihf libc-dev-armel-cross
            codecov: ubuntu_gcc_armhf_no_neon

          - name: Ubuntu GCC ARM HF Compat No Opt
            os: ubuntu-latest
            compiler: arm-linux-gnueabihf-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-arm.cmake -DCMAKE_C_COMPILER_TARGET=arm-linux-gnueabihf -DZLIB_COMPAT=ON -DWITH_NEW_STRATEGIES=OFF -DWITH_OPTIM=OFF -DWITH_SANITIZER=Undefined
            packages: qemu gcc-arm-linux-gnueabihf libc-dev-armel-cross
            codecov: ubuntu_gcc_armhf_compat_no_opt

          - name: Ubuntu GCC AARCH64
            os: ubuntu-latest
            compiler: aarch64-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-aarch64.cmake -DWITH_SANITIZER=Address
            asan-options: detect_leaks=0
            packages: qemu gcc-aarch64-linux-gnu libc-dev-arm64-cross
            codecov: ubuntu_gcc_aarch64

          - name: Ubuntu GCC AARCH64 No ACLE
            os: ubuntu-latest
            compiler: aarch64-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-aarch64.cmake -DWITH_ACLE=OFF -DWITH_SANITIZER=Undefined
            asan-options: detect_leaks=0
            packages: qemu gcc-aarch64-linux-gnu libc-dev-arm64-cross
            codecov: ubuntu_gcc_aarch64_no_acle

          - name: Ubuntu GCC AARCH64 No NEON
            os: ubuntu-latest
            compiler: aarch64-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-aarch64.cmake -DWITH_NEON=OFF -DWITH_SANITIZER=Undefined
            asan-options: detect_leaks=0
            packages: qemu gcc-aarch64-linux-gnu libc-dev-arm64-cross
            codecov: ubuntu_gcc_aarch64_no_neon

          - name: Ubuntu GCC AARCH64 Compat No Opt
            os: ubuntu-latest
            compiler: aarch64-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-aarch64.cmake -DZLIB_COMPAT=ON -DWITH_NEW_STRATEGIES=OFF -DWITH_OPTIM=OFF -DWITH_SANITIZER=Undefined
            asan-options: detect_leaks=0
            packages: qemu gcc-aarch64-linux-gnu libc-dev-arm64-cross
            codecov: ubuntu_gcc_aarch64_compat_no_opt

          - name: Ubuntu GCC PPC
            os: ubuntu-latest
            compiler: powerpc-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-powerpc.cmake
            packages: qemu gcc-powerpc-linux-gnu libc-dev-powerpc-cross
            ldflags: -static
            codecov: ubuntu_gcc_ppc

          - name: Ubuntu GCC PPC64
            os: ubuntu-latest
            compiler: powerpc64-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-powerpc64.cmake
            packages: qemu gcc-powerpc64-linux-gnu libc-dev-ppc64-cross
            ldflags: -static
            codecov: ubuntu_gcc_ppc64

          - name: Ubuntu GCC PPC64LE
            os: ubuntu-latest
            compiler: powerpc64le-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-powerpc64le.cmake
            packages: qemu gcc-powerpc64le-linux-gnu libc-dev-ppc64el-cross
            codecov: ubuntu_gcc_ppc64le

          - name: Ubuntu GCC SPARC64
            os: ubuntu-latest
            compiler: sparc64-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-sparc64.cmake
            packages: qemu gcc-sparc64-linux-gnu libc-dev-sparc64-cross
            ldflags: -static
            codecov: ubuntu_gcc_sparc64

          - name: Ubuntu GCC S390X
            os: ubuntu-latest
            compiler: s390x-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-s390x.cmake -DWITH_SANITIZER=Address
            packages: qemu gcc-s390x-linux-gnu libc-dev-s390x-cross
            ldflags: -static
            codecov: ubuntu_gcc_s390x

          - name: Ubuntu GCC S390X DFLTCC
            os: ubuntu-latest
            compiler: s390x-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-s390x.cmake -DWITH_DFLTCC_DEFLATE=ON -DWITH_DFLTCC_INFLATE=ON -DWITH_SANITIZER=Address
            packages: qemu gcc-s390x-linux-gnu libc-dev-s390x-cross
            ldflags: -static
            codecov: ubuntu_gcc_s390x

          - name: Ubuntu GCC S390X DFLTCC Compat
            os: ubuntu-latest
            compiler: s390x-linux-gnu-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-s390x.cmake -DZLIB_COMPAT=ON -DWITH_DFLTCC_DEFLATE=ON -DWITH_DFLTCC_INFLATE=ON -DWITH_SANITIZER=Undefined
            packages: qemu gcc-s390x-linux-gnu libc-dev-s390x-cross
            ldflags: -static
            codecov: ubuntu_gcc_s390x

          - name: Ubuntu MinGW i686
            os: ubuntu-latest
            compiler: i686-w64-mingw32-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-mingw-i686.cmake
            packages: wine32 gcc-mingw-w64
            # Codecov disabled due to gcov locking issue error

          - name: Ubuntu MinGW x86_64
            os: ubuntu-latest
            compiler: x86_64-w64-mingw32-gcc
            cmake-args: -DCMAKE_TOOLCHAIN_FILE=cmake/toolchain-mingw-x86_64.cmake
            packages: wine-stable gcc-mingw-w64
            codecov: ubuntu_gcc_mingw_x86_64

          - name: Ubuntu Clang
            os: ubuntu-latest
            compiler: clang
            packages: llvm-6.0
            gcov-exec: llvm-cov-6.0 gcov
            codecov: ubuntu_clang

          - name: Ubuntu Clang Inflate Strict
            os: ubuntu-latest
            compiler: clang
            cmake-args: -DWITH_INFLATE_STRICT=ON
            packages: llvm-6.0
            gcov-exec: llvm-cov-6.0 gcov
            codecov: ubuntu_clang_inflate_strict

          - name: Ubuntu Clang Inflate Allow Invalid Dist
            os: ubuntu-latest
            compiler: clang
            cmake-args: -DWITH_INFLATE_ALLOW_INVALID_DIST=ON
            packages: llvm-6.0
            gcov-exec: llvm-cov-6.0 gcov
            codecov: ubuntu_clang_inflate_allow_invalid_dist

          - name: Ubuntu Clang Memory Map
            os: ubuntu-latest
            compiler: clang
            cflags: -DUSE_MMAP
            packages: llvm-6.0
            gcov-exec: llvm-cov-6.0 gcov
            codecov: ubuntu_clang_mmap

          - name: Ubuntu Clang Debug
            os: ubuntu-latest
            compiler: clang
            packages: llvm-6.0
            gcov-exec: llvm-cov-6.0 gcov
            codecov: ubuntu_clang_debug
            build-config: Debug

          - name: Ubuntu Clang MSAN
            os: ubuntu-latest
            compiler: clang
            cmake-args: -GNinja -DWITH_SANITIZER=Memory
            packages:  ninja-build llvm-6.0
            gcov-exec: llvm-cov-6.0 gcov
            cflags: -g3 -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize-memory-track-origins
            codecov: ubuntu_clang_msan

          - name: Windows MSVC Win32
            os: windows-latest
            compiler: cl
            cmake-args: -A Win32

          - name: Windows MSVC Win64
            os: windows-latest
            compiler: cl
            cmake-args: -A x64

          - name: Windows MSVC ARM No Test
            os: windows-latest
            compiler: cl
            cmake-args: -A ARM

          - name: Windows MSVC ARM64 No Test
            os: windows-latest
            compiler: cl
            cmake-args: -A ARM64

          - name: Windows GCC
            os: windows-latest
            compiler: gcc
            cmake-args: -G Ninja
            codecov: win64_gcc

          - name: Windows GCC Compat No Opt
            os: windows-latest
            compiler: gcc
            cmake-args: -G Ninja -DZLIB_COMPAT=ON -DWITH_NEW_STRATEGIES=OFF -DWITH_OPTIM=OFF
            codecov: win64_gcc_compat_no_opt

          - name: macOS Clang
            os: macos-latest
            compiler: clang
            cmake-args: -DWITH_SANITIZER=Address
            codecov: macos_clang

          - name: macOS GCC
            os: macos-latest
            compiler: gcc-10
            cmake-args: -DWITH_SANITIZER=Undefined
            packages: gcc@10
            gcov-exec: gcov-10
            codecov: macos_gcc

    steps:
    - name: Checkout repository
      uses: actions/checkout@v2

    - name: Checkout test corpora
      uses: actions/checkout@v2
      with:
        repository: nmoinvaz/corpora
        path: test/data/corpora

    - name: Install packages (Ubuntu)
      if: runner.os == 'Linux' && matrix.packages
      run: |
        sudo dpkg --add-architecture i386 # Required for wine32
        sudo apt-get update
        sudo apt-get install -y ${{ matrix.packages }}

    - name: Install packages (Windows)
      if: runner.os == 'Windows'
      run: |
        choco install ninja ${{ matrix.packages }} --no-progress

    - name: Install packages (macOS)
      if: runner.os == 'macOS'
      run: |
        brew install ninja ${{ matrix.packages }}
      env:
        HOMEBREW_NO_INSTALL_CLEANUP: 1

    - name: Install codecov.io tools
      if: matrix.codecov
      run: |
        python -u -m pip install codecov

    - name: Generate project files
      # Shared libaries turned off for qemu ppc* and sparc & reduce code coverage sources
      run: |
        mkdir ${{ matrix.build-dir || '.not-used' }}
        cd ${{ matrix.build-dir || '.' }}
        cmake ${{ matrix.build-src-dir || '.' }} ${{ matrix.cmake-args }} -DCMAKE_BUILD_TYPE=${{ matrix.build-config || 'Release' }} -DBUILD_SHARED_LIBS=OFF -DWITH_FUZZERS=ON -DWITH_CODE_COVERAGE=ON -DWITH_MAINTAINER_WARNINGS=ON
      env:
        CC: ${{ matrix.compiler }}
        CFLAGS: ${{ matrix.cflags }}
        LDFLAGS: ${{ matrix.ldflags }}
        CI: true

    - name: Compile source code
      run: |
        cd ${{ matrix.build-dir || '.' }}
        cmake --build . --config ${{ matrix.build-config || 'Release' }}

    - name: Run test cases
      # Don't run tests on Windows ARM
      if: runner.os != 'Windows' || contains(matrix.name, 'ARM') == false
      run: |
        cd ${{ matrix.build-dir || '.' }}
        ctest --verbose -C Release --output-on-failure --max-width 120 -j 6
      env:
        ASAN_OPTIONS: ${{ matrix.asan-options || 'verbosity=0' }}:abort_on_error=1
        MSAN_OPTIONS: ${{ matrix.msan-options || 'verbosity=0' }}:abort_on_error=1
        TSAN_OPTIONS: ${{ matrix.tsan-options || 'verbosity=0' }}:abort_on_error=1
        LSAN_OPTIONS: ${{ matrix.lsan-options || 'verbosity=0' }}:abort_on_error=1

    - name: Upload coverage report
      if: matrix.codecov && ( env.CODECOV_TOKEN_SECRET != '' || github.repository == 'zlib-ng/zlib-ng' )
      shell: bash
      run: |
        bash tools/codecov-upload.sh
      env:
        # Codecov does not yet support GitHub Actions
        CODECOV_TOKEN_SECRET: "${{secrets.CODECOV_TOKEN}}"
        CODECOV_TOKEN: "${{ secrets.CODECOV_TOKEN || 'e4fdf847-f541-4ab1-9d50-3d27e5913906' }}"
        CODECOV_FLAGS: "${{ matrix.codecov }}"
        CODECOV_NAME:  "${{ matrix.name }}"
        CODECOV_EXEC:  "${{ matrix.gcov-exec || 'gcov' }}"
        CODECOV_DIR:   "${{ matrix.build-dir || '.' }}"
