name: Tests

on: [push, pull_request]

jobs:
  test:
    name: ${{ matrix.os }}-${{ matrix.architecture }} Py${{ matrix.python }} GEOS ${{ matrix.geos }}
    runs-on: ${{ matrix.os }}
    defaults:
      run:
        shell: bash
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-2019]
        architecture: [x64]
        geos: [3.7.5, 3.8.3, 3.9.4, 3.10.5, 3.11.2, main]
        include:
          # 2018
          - python: 3.8  # 3.7 is dropped
            geos: 3.7.5
            numpy: 1.16.2
          # 2019
          - python: 3.8
            geos: 3.8.3
            numpy: 1.16.2
          # 2020
          - python: 3.9
            geos: 3.9.4
            numpy: 1.19.5
          # 2021
          - python: "3.10"
            geos: 3.10.5
            numpy: 1.21.3
          # 2022
          - python: "3.11"
            geos: 3.11.2
            numpy: 1.23.4
            matplotlib: true
            doctest: true
            extra_pytest_args: "-W error"  # error on warnings
          # dev
          - python: "3.11"
            geos: main
            extra_pytest_args: "-W error" # error on warnings
          # enable two 32-bit windows builds:
          - os: windows-2019
            architecture: x86
            python: 3.8
            geos: 3.7.5
            numpy: 1.16.2
          - os: windows-2019
            architecture: x86
            python: 3.9
            geos: 3.10.3
            numpy: 1.19.5
          # pypy (use explicit ubuntu version to not overwrite existing ubuntu-latest + geos 3.11.0 build)
          - os: ubuntu-20.04
            python: "pypy3.8"
            geos: 3.11.2
            numpy: 1.23.4

    env:
      GEOS_VERSION: ${{ matrix.geos }}
      GEOS_VERSION_SPEC: ${{ matrix.geos }}
      GEOS_INSTALL: ${{ github.workspace }}/geosinstall/geos-${{ matrix.geos }}
      GEOS_BUILD: ${{ github.workspace }}/geosbuild

    steps:
      - name: Correct slashes in GEOS_INSTALL (Windows)
        run: |
          echo 'GEOS_INSTALL=${{ github.workspace }}\geosinstall\geos-${{ matrix.geos }}' >> $GITHUB_ENV
          echo 'GEOS_BUILD=${{ github.workspace }}\geosbuild' >> $GITHUB_ENV
        if: ${{ matrix.os == 'windows-2019' }}

      - name: Checkout Shapely
        uses: actions/checkout@v3

      - name: Checkout GEOS (main)
        uses: actions/checkout@v3
        with:
          repository: libgeos/geos
          ref: main
          path: ${{ env.GEOS_BUILD }}
        if: ${{ matrix.geos == 'main' }}

      - name: Put the latest commit hash in the cache token for GEOS main
        run: |
          echo "GEOS_VERSION_SPEC=$(git rev-parse HEAD)" >> $GITHUB_ENV
        working-directory: ${{ env.GEOS_BUILD }}
        if: ${{ matrix.geos == 'main' }}

      - name: Set up Python ${{ matrix.python }}
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python }}
          architecture: ${{ matrix.architecture }}

      - name: Cache GEOS and pip packages
        uses: actions/cache@v3
        with:
          key: ${{ matrix.os }}-${{ matrix.architecture }}-geos-${{ env.GEOS_VERSION_SPEC }}-${{ hashFiles('ci/install_geos.sh') }}
          path: |
            ~/.cache/pip
            ${{ github.workspace }}/geosinstall

      - name: Activate MSVC
        uses: ilammy/msvc-dev-cmd@v1
        with:
          arch: ${{ matrix.architecture }}
        if: ${{ matrix.os == 'windows-2019' }}

      - name: Install GEOS
        run: |
          bash ci/install_geos.sh

      - name: Install python dependencies
        run: |
          python -m pip install --disable-pip-version-check --upgrade pip
          pip install --upgrade wheel setuptools
          if [ -z "${{ matrix.numpy }}" ]; then
            pip install --upgrade --pre Cython numpy pytest pytest-cov coveralls;
          else
            pip install --upgrade Cython numpy==${{ matrix.numpy }} pytest pytest-cov coveralls;
          fi
          if [ -n "${{ matrix.matplotlib }}" ]; then
            pip install matplotlib
          fi
          pip list

      - name: Set environment variables (Linux)
        run: |
          echo "${{ env.GEOS_INSTALL }}/bin" >> $GITHUB_PATH
          echo "LD_LIBRARY_PATH=${{ env.GEOS_INSTALL }}/lib" >> $GITHUB_ENV
        if: ${{ startsWith(matrix.os, 'ubuntu') }}

      - name: Set environment variables (OSX)
        run: |
          echo "${{ env.GEOS_INSTALL }}/bin" >> $GITHUB_PATH
          echo "LDFLAGS=-Wl,-rpath,${{ env.GEOS_INSTALL }}/lib" >> $GITHUB_ENV
        if: ${{ matrix.os == 'macos-latest' }}

      # Windows requires special treatment:
      # - geos-config does not exist, so we specify include and library paths
      # - Python >=3.8 ignores the PATH for finding DLLs, so we copy them into the package
      - name: Set environment variables + copy DLLs (Windows)
        run: |
          cp geosinstall/geos-${{ matrix.geos }}/bin/*.dll shapely
          echo 'GEOS_LIBRARY_PATH=${{ env.GEOS_INSTALL }}\lib' >> $GITHUB_ENV
          echo 'GEOS_INCLUDE_PATH=${{ env.GEOS_INSTALL }}\include' >> $GITHUB_ENV
        if: ${{ matrix.os == 'windows-2019' }}

      - name: Build and install Shapely
        run: |
          pip install -e .

      - name: Overview of the Python environment (pip list)
        run: pip list

      - name: Run tests
        # Enable this if we have failures on GEOS main
        continue-on-error: ${{ matrix.geos == 'main' }}
        run: |
          python -c "import shapely; print(f'GEOS version: {shapely.geos_version_string}')"
          pytest shapely/tests -r a --cov --cov-report term-missing ${{ matrix.extra_pytest_args }}

      # Only run doctests on 1 runner (because of typographic differences in doctest results)
      - name: Run doctests
        if: ${{ matrix.os == 'ubuntu-latest' && matrix.doctest }}
        run: |
          python -m pytest --doctest-modules docs/manual.rst

      - name: Run doctests (part 2)
        if: ${{ matrix.os == 'ubuntu-latest' && matrix.doctest }}
        run: |
          pytest --doctest-modules shapely --ignore=shapely/tests

      - name: Upload coverage
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          COVERALLS_PARALLEL: true
        shell: bash
        run: |
          coveralls --service=github || echo "!! intermittent coveralls failure"

  coveralls:
    name: Indicate completion to coveralls.io
    needs: test
    runs-on: ubuntu-latest
    container: python:3-slim
    steps:
      - name: Finished
        run: |
          pip3 install --upgrade coveralls
          coveralls --finish || echo "!! intermittent coveralls failure"
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
