name: Quality Assurance

on:
  push:
  pull_request:

jobs:
  build-linux:
    name: Linux (${{ matrix.platform.label }}, ${{ matrix.compiler.label }}, ${{ matrix.configure.label }})
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-22.04]
        platform:
          - {label: "x64", arch: "amd64", configure: ""}
          - {label: "x32", arch: "i386", configure: "PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32"}
        compiler:
          - {label: "gcc", cc: "gcc", cxx: "g++"}
          - {label: "clang", cc: "clang", cxx: "clang++"}
        configure:
          - {label: "with parser generation", opt: "--enable-parser-generation" }
          - {label: "wo curl",    opt: "--without-curl" }
          - {label: "wo lua",     opt: "--without-lua" }
          - {label: "wo maxmind", opt: "--without-maxmind" }
          - {label: "wo libxml",  opt: "--without-libxml" }
          - {label: "wo geoip",   opt: "--without-geoip" }
          - {label: "wo ssdeep",  opt: "--without-ssdeep" }
          - {label: "with lmdb",  opt: "--with-lmdb" }
          - {label: "with pcre", opt: "--with-pcre" }
        exclude:
          - platform: {label: "x32"}
            configure: {label: "wo geoip"}
          - platform: {label: "x32"}
            configure: {label: "wo ssdeep"}
    steps:
      - name: Setup Dependencies (common)
        run: |
          sudo dpkg --add-architecture ${{ matrix.platform.arch }}
          sudo apt-get update -y -qq
          sudo apt-get install -y libyajl-dev:${{ matrix.platform.arch }} \
                                  libcurl4-openssl-dev:${{ matrix.platform.arch }} \
                                  liblmdb-dev:${{ matrix.platform.arch }} \
                                  liblua5.2-dev:${{ matrix.platform.arch }} \
                                  libmaxminddb-dev:${{ matrix.platform.arch }} \
                                  libpcre2-dev:${{ matrix.platform.arch }} \
                                  pcre2-utils:${{ matrix.platform.arch }} \
                                  bison flex
      - name: Setup Dependencies (x32)
        if: ${{ matrix.platform.label == 'x32' }}
        run: |
          sudo apt-get install g++-multilib
          sudo apt-get install -y libxml2-dev:${{ matrix.platform.arch }} \
                                  libpcre3-dev:${{ matrix.platform.arch }}
      - name: Setup Dependencies (x64)
        if: ${{ matrix.platform.label == 'x64' }}
        run: |
          sudo apt-get install -y libgeoip-dev:${{ matrix.platform.arch }} \
                                  libfuzzy-dev:${{ matrix.platform.arch }}
      - uses: actions/checkout@v4
        with:
          submodules: true
          fetch-depth: 0
      - name: build.sh
        run: ./build.sh
      - name: configure
        env:
          CC: ${{ matrix.compiler.cc }}
          CXX: ${{ matrix.compiler.cxx }}
        run: ./configure ${{ matrix.platform.configure }} ${{ matrix.configure.opt }} --enable-assertions=yes
      - uses: ammaraskar/gcc-problem-matcher@master
      - name: make
        run: make -j `nproc`
      - name: check
        run: make check

  build-macos:
    name: macOS (${{ matrix.configure.label }})
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [macos-14]
        configure:
          - {label: "with parser generation", opt: "--enable-parser-generation" }
          - {label: "wo curl",    opt: "--without-curl" }
          - {label: "wo lua",     opt: "--without-lua" }
          - {label: "wo maxmind", opt: "--without-maxmind" }
          - {label: "wo libxml",  opt: "--without-libxml" }
          - {label: "wo geoip",   opt: "--without-geoip" }
          - {label: "wo ssdeep",  opt: "--without-ssdeep" }
          - {label: "with lmdb",  opt: "--with-lmdb" }
          - {label: "with pcre", opt: "--with-pcre" }
    steps:
      - name: Setup Dependencies
        # curl, pcre2 not installed because they're already
        # included in the image
        run: |
          brew install autoconf \
                       automake \
                       libtool \
                       yajl \
                       lmdb \
                       lua \
                       libmaxminddb \
                       libxml2 \
                       ssdeep \
                       pcre \
                       bison \
                       flex
      - uses: actions/checkout@v4
        with:
          submodules: true
          fetch-depth: 0
      - name: Build GeoIP
        run: |
          git clone --depth 1 --no-checkout https://github.com/maxmind/geoip-api-c.git
          cd geoip-api-c
          git fetch --tags
          # Check out the last release, v1.6.12
          git checkout 4b526e7331ca1d692b74a0509ddcc725622ed31a
          autoreconf --install
          ./configure --disable-dependency-tracking --disable-silent-rules --prefix=/opt/homebrew
          make install
      - name: build.sh
        run: ./build.sh
      - name: configure
        run: ./configure ${{ matrix.configure.opt }} --enable-assertions=yes
      - uses: ammaraskar/gcc-problem-matcher@master
      - name: make
        run: make -j `sysctl -n hw.logicalcpu`
      - name: check
        run: make check

  build-windows:
    name: Windows (${{ matrix.platform.label }}, ${{ matrix.configure.label }})
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [windows-2022]
        platform:
          - {label: "x64", arch: "x86_64"}
        configuration: [Release]
        configure:
          - {label: "full",       opt: "" }
          - {label: "wo curl",    opt: "-DWITH_CURL=OFF" }
          - {label: "wo lua",     opt: "-DWITH_LUA=OFF" }
          - {label: "wo maxmind", opt: "-DWITH_MAXMIND=OFF" }
          - {label: "wo libxml",  opt: "-DWITH_LIBXML2=OFF" }
          - {label: "with lmdb",  opt: "-DWITH_LMDB=ON" }
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: true
          fetch-depth: 0
      - name: Install Conan
        run: |
          pip3 install conan --upgrade
          conan profile detect
      - uses: ammaraskar/msvc-problem-matcher@master
      - name: Build ${{ matrix.configuration }} ${{ matrix.platform.arch }} ${{ matrix.configure.label }}
        shell: cmd
        run: vcbuild.bat ${{ matrix.configuration }} ${{ matrix.platform.arch }} NO_ASAN "${{ matrix.configure.opt }}"
      - name: Set up test environment
        working-directory: build\win32\build\${{ matrix.configuration }}
        env:
          BASE_DIR: ..\..\..\..
        shell: cmd
        run: |
          copy unit_tests.exe %BASE_DIR%\test
          copy regression_tests.exe %BASE_DIR%\test
          copy libModSecurity.dll %BASE_DIR%\test
          copy %BASE_DIR%\unicode.mapping %BASE_DIR%\test
          md \tmp
          md \bin
          copy "C:\Program Files\Git\usr\bin\echo.exe" \bin
          copy "C:\Program Files\Git\usr\bin\echo.exe" \bin\echo
      - name: Disable tests that don't work on Windows
        working-directory: test\test-cases\regression
        shell: cmd
        run: |
          jq "map(if .title == \"Test match variable (1/n)\" then .enabled = 0 else . end)" issue-2423-msg-in-chain.json > tmp.json && move /Y tmp.json issue-2423-msg-in-chain.json
          jq "map(if .title == \"Test match variable (2/n)\" then .enabled = 0 else . end)" issue-2423-msg-in-chain.json > tmp.json && move /Y tmp.json issue-2423-msg-in-chain.json
          jq "map(if .title == \"Test match variable (3/n)\" then .enabled = 0 else . end)" issue-2423-msg-in-chain.json > tmp.json && move /Y tmp.json issue-2423-msg-in-chain.json
          jq "map(if .title == \"Variable offset - FILES_NAMES\" then .enabled = 0 else . end)" offset-variable.json > tmp.json && move /Y tmp.json offset-variable.json
      - name: Run tests
        working-directory: build\win32\build
        run: |
          ctest -C ${{ matrix.configuration }} --output-on-failure

  cppcheck:
    runs-on: [macos-14]
    steps:
      - name: Setup Dependencies
        run: |
          brew install autoconf \
                       automake \
                       libtool \
                       cppcheck
      - uses: actions/checkout@v4
        with:
          submodules: true
          fetch-depth: 0
      - name: configure
        run: |
          ./build.sh
          ./configure
      - name: cppcheck
        run: make check-static
