name: Regression testing
on:
  - push
  - pull_request

jobs:
  unix:
    strategy:
      matrix:
        os: [ubuntu-22.04, macos-14]
        cxx: [g++, clang++]
        buildsys: [make, cmake]
        exclude:
          # Don't use `g++` on macOS; it's just an alias to `clang++`.
          - os: macos-14
            cxx: g++
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
      - name: Install deps
        shell: bash
        run: |
          ./.github/scripts/install_deps.sh ${{ matrix.os }}
      - name: Build & install using Make
        if: matrix.buildsys == 'make'
        run: |
          make develop -kj Q= CXX=${{ matrix.cxx }}
          sudo make install -j Q=
      - name: Build & install using CMake
        if: matrix.buildsys == 'cmake'
        run: |
          cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=${{ matrix.cxx }} -DSANITIZERS=ON -DMORE_WARNINGS=ON
          cmake --build build -j --verbose
          sudo cmake --install build --verbose
      - name: Package binaries
        run: |
          mkdir bins
          cp rgb{asm,link,fix,gfx} bins
      - name: Upload binaries
        uses: actions/upload-artifact@v4
        with:
          name: rgbds-canary-${{ matrix.os }}-${{ matrix.cxx }}-${{ matrix.buildsys }}
          path: bins
      - name: Compute test dependency cache params
        id: test-deps-cache-params
        shell: bash
        run: |
          paths=$(test/fetch-test-deps.sh --get-paths)
          hash=$(test/fetch-test-deps.sh --get-hash)
          tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
          tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
      - name: Check test dependency repositories cache
        id: test-deps-cache
        uses: actions/cache@v4
        with:
          path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
          key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
      - name: Fetch test dependency repositories
        if: steps.test-deps-cache.outputs.cache-hit != 'true'
        continue-on-error: true
        run: |
          test/fetch-test-deps.sh
      - name: Install test dependency dependencies
        shell: bash
        run: |
          test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
      - name: Run tests
        shell: bash
        run: |
          CXX=${{ matrix.cxx }} test/run-tests.sh --os ${{ matrix.os }}

  macos-static:
    runs-on: macos-14
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
      - name: Install deps
        shell: bash
        run: |
          ./.github/scripts/install_deps.sh macos
      - name: Build libpng
        run: |
          ./.github/scripts/build_libpng.sh
      - name: Build & install
        run: |
          make -kj CXXFLAGS="-O3 -flto -DNDEBUG -mmacosx-version-min=10.9 -arch x86_64 -arch arm64" PNGCFLAGS="-I libpng-staging/include" PNGLDLIBS="libpng-staging/lib/libpng.a -lz" Q=
      - name: Package binaries
        run: |
          mkdir bins
          cp rgb{asm,link,fix,gfx} bins
      - name: Upload binaries
        uses: actions/upload-artifact@v4
        with:
          name: rgbds-canary-macos-static
          path: bins
      - name: Compute test dependency cache params
        id: test-deps-cache-params
        shell: bash
        run: |
          paths=$(test/fetch-test-deps.sh --get-paths)
          hash=$(test/fetch-test-deps.sh --get-hash)
          tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
          tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
      - name: Check test dependency repositories cache
        id: test-deps-cache
        uses: actions/cache@v4
        with:
          path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
          key: ${{ matrix.os }}-${{ steps.test-deps-cache-params.outputs.hash }}
      - name: Fetch test dependency repositories
        if: steps.test-deps-cache.outputs.cache-hit != 'true'
        continue-on-error: true
        run: |
          test/fetch-test-deps.sh
      - name: Install test dependency dependencies
        shell: bash
        run: |
          test/fetch-test-deps.sh --get-deps macos
      - name: Run tests
        shell: bash
        run: |
          test/run-tests.sh --os macos

  windows:
    strategy:
      matrix:
        bits: [32, 64]
        os: [windows-2022, windows-2025]
        include:
          - bits: 32
            arch: x86
            platform: Win32
          - bits: 64
            arch: x86_x64
            platform: x64
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
      - name: Install deps
        run: .github/scripts/get_win_deps.ps1
      - name: Check libraries cache
        id: cache
        uses: actions/cache@v4
        with:
          path: |
            zbuild
            pngbuild
          key: ${{ matrix.os }}-${{ matrix.arch }}-${{ hashFiles('zlib/**', 'libpng/**') }}
      - name: Build zlib
        if: steps.cache.outputs.cache-hit != 'true'
        shell: bash
        run: | # BUILD_SHARED_LIBS causes the output DLL to be called `z.dll` as of zlib 1.3.2 (formerly `zlib1.dll`)
          cmake -S zlib -B zbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
          cmake --build zbuild --config Release -j
      - name: Install zlib
        run: |
          cmake --install zbuild
      - name: Build libpng
        if: steps.cache.outputs.cache-hit != 'true'
        shell: bash
        run: |
          cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -Wno-dev -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=OFF -DPNG_TESTS=OFF
          cmake --build pngbuild --config Release -j
      - name: Install libpng
        run: |
          cmake --install pngbuild
      - name: Build Windows binaries
        shell: bash
        run: |
          cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
          cmake --build build --config Release -j --verbose
          cmake --install build --verbose --prefix install_dir
      - name: Package binaries
        shell: bash
        run: |
          mkdir bins
          cp install_dir/bin/{rgbasm.exe,rgblink.exe,rgbfix.exe,rgbgfx.exe,z.dll,libpng16.dll} bins
      - name: Upload Windows binaries
        uses: actions/upload-artifact@v4
        with:
          name: rgbds-canary-w${{ matrix.bits }}-${{ matrix.os }}
          path: bins
      - name: Compute test dependency cache params
        id: test-deps-cache-params
        shell: bash
        run: |
          paths=$(test/fetch-test-deps.sh --get-paths)
          hash=$(test/fetch-test-deps.sh --get-hash)
          tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
          tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
      - name: Check test dependency repositories cache
        id: test-deps-cache
        uses: actions/cache@v4
        with:
          path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
          key: ${{ matrix.os }}-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
      - name: Fetch test dependency repositories
        if: steps.test-deps-cache.outputs.cache-hit != 'true'
        shell: bash
        continue-on-error: true
        run: |
          test/fetch-test-deps.sh
      - name: Install test dependency dependencies
        shell: bash
        run: |
          test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
      - name: Run tests
        shell: bash
        run: |
          cp bins/* .
          cp bins/*.dll test/gfx
          test/run-tests.sh --os ${{ matrix.os }}

  windows-mingw-build:
    strategy:
      matrix:
        bits: [32, 64]
        include:
          - bits: 32
            arch: i686
            triplet: i686-w64-mingw32
          - bits: 64
            arch: x86-64
            triplet: x86_64-w64-mingw32
      fail-fast: false
    runs-on: ubuntu-22.04
    env:
      DIST_DIR: win${{ matrix.bits }}
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
      - name: Install deps
        shell: bash
        run: |
          ./.github/scripts/install_deps.sh ubuntu
      - name: Install MinGW
        run: | # dpkg-dev is apparently required for pkg-config for cross-building
          sudo apt-get install g++-mingw-w64-${{ matrix.arch }}-win32 mingw-w64-tools libz-mingw-w64-dev dpkg-dev
      - name: Install libpng dev headers for MinGW
        run: |
          ./.github/scripts/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
      - name: Cross-build Windows binaries
        run: |
          make mingw${{ matrix.bits }} -kj Q=
      - name: Package binaries
        run: | # DLL dependencies can be figured out using e.g. Dependency Walker or objdump -p
          mkdir bins
          mv -v rgb{asm,link,fix,gfx}.exe bins/
          cp -v /usr/${{ matrix.triplet }}/lib/zlib1.dll bins
          cp -v /usr/${{ matrix.triplet }}/bin/libpng16-16.dll bins
          cp -v /usr/lib/gcc/${{ matrix.triplet }}/10-win32/lib{ssp-0,stdc++-6}.dll bins
          [ "${{ matrix.bits }}" -ne 32 ] || cp -v /usr/lib/gcc/${{ matrix.triplet }}/10-win32/libgcc_s_dw2-1.dll bins
      - name: Upload Windows binaries
        uses: actions/upload-artifact@v4
        with:
          name: rgbds-canary-mingw-win${{ matrix.bits }}
          path: bins
      - name: Upload Windows test binaries
        uses: actions/upload-artifact@v4
        with:
          name: testing-programs-mingw-win${{ matrix.bits }}
          path: |
            test/gfx/randtilegen.exe
            test/gfx/rgbgfx_test.exe

  windows-mingw-testing:
    needs: windows-mingw-build
    strategy:
      matrix:
        os: [windows-2022, windows-2025]
        bits: [32, 64]
      fail-fast: false
    runs-on: ${{ matrix.os }}
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
      - name: Retrieve binaries
        uses: actions/download-artifact@v4
        with:
          name: rgbds-canary-mingw-win${{ matrix.bits }}
          path: bins
      - name: Retrieve test binaries
        uses: actions/download-artifact@v4
        with:
          name: testing-programs-mingw-win${{ matrix.bits }}
          path: test/gfx
      - name: Extract binaries
        shell: bash
        run: |
          cp bins/* .
          cp bins/*.dll test/gfx
      - name: Compute test dependency cache params
        id: test-deps-cache-params
        shell: bash
        run: |
          paths=$(test/fetch-test-deps.sh --get-paths)
          hash=$(test/fetch-test-deps.sh --get-hash)
          tee -a <<<"paths=\"${paths//,/\\n}\"" $GITHUB_OUTPUT
          tee -a <<<"hash=${hash%-}" $GITHUB_OUTPUT
      - name: Check test dependency repositories cache
        id: test-deps-cache
        uses: actions/cache@v4
        with:
          path: ${{ fromJSON(steps.test-deps-cache-params.outputs.paths) }}
          key: mingw-${{ matrix.bits }}-${{ steps.test-deps-cache-params.outputs.hash }}
      - name: Fetch test dependency repositories
        if: steps.test-deps-cache.outputs.cache-hit != 'true'
        shell: bash
        continue-on-error: true
        run: |
          test/fetch-test-deps.sh
      - name: Install test dependency dependencies
        shell: bash
        run: |
          test/fetch-test-deps.sh --get-deps ${{ matrix.os }}
      - name: Run tests
        shell: bash
        run: |
          test/run-tests.sh --os ${{ matrix.os }}

  cygwin:
    strategy:
      matrix:
        bits: [32, 64]
        include:
          - bits: 32
            arch: x86
          - bits: 64
            arch: x86_64
      fail-fast: false
    runs-on: windows-2022
    timeout-minutes: 30
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          fetch-tags: true
      - name: Setup Cygwin
        uses: cygwin/cygwin-install-action@v4
        with:
          platform: ${{ matrix.arch }}
          packages: >-
            bison
            gcc-g++
            git
            libpng-devel
            make
            pkg-config
      - name: Build & install using Make
        shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -o igncr '{0}'
        run: | # Cygwin does not support `make develop` sanitizers ASan or UBSan
          make -kj Q=
          make install -j Q=
      - name: Run tests
        shell: C:\cygwin\bin\env.exe CYGWIN_NOWINPATH=1 CHERE_INVOKING=1 C:\cygwin\bin\bash.exe -o igncr '{0}'
        run: |
          test/run-tests.sh --only-internal

  freebsd:
    runs-on: ubuntu-latest
    timeout-minutes: 30
    steps:
      - name: Checkout repo
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          fetch-tags: true
      - name: Build & test using CMake on FreeBSD
        uses: vmactions/freebsd-vm@v1
        with:
          release: "14.3"
          usesh: true
          prepare: |
            pkg install -y \
              bash \
              bison \
              cmake \
              git \
              png
          run: | # FreeBSD `c++` compiler does not support `make develop` sanitizers ASan or UBSan
            cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=c++ -DUSE_EXTERNAL_TESTS=OFF -DOS=bsd
            cmake --build build -j4 --verbose
            cmake --install build --verbose
            cmake --build build --target test
