name: Run tests
on: [push, pull_request]

permissions:
  contents: read

jobs:
  run-tests:
    name: Run tests
    permissions:
      contents: read
      actions: write
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest, windows-latest]
        python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]

    runs-on: ${{ matrix.os }}
    env:
      liboqs_version: '0.10.1'
      nettle_version: nettle_3.8.1_release_20220727

    steps:
      - name: Checkout asyncssh
        uses: actions/checkout@v4
        with:
          path: asyncssh

      - name: Checkout liboqs
        if: ${{ runner.os != 'macOS' }}
        uses: actions/checkout@v4
        with:
          repository: open-quantum-safe/liboqs
          ref: ${{ env.liboqs_version }}
          path: liboqs

      - uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          cache: pip
          cache-dependency-path: |
            asyncssh/setup.py
            asyncssh/tox.ini

      - name: Fix modules path for OpenSSL on Windows
        if: ${{ runner.os == 'Windows' }}
        shell: pwsh
        run: |
          $openssl_path = ((Get-Command openssl).Path | Split-Path -Parent)
          echo "OPENSSL_MODULES=$openssl_path" >> $env:GITHUB_ENV

      - name: Verify legacy provider can be enabled in OpenSSL on Windows
        if: ${{ runner.os == 'Windows' }}
        shell: pwsh
        run: |
          openssl list -provider default -provider legacy -providers

      - name: Set up ccache for liboqs (Linux)
        uses: hendrikmuhs/ccache-action@v1.2
        if: ${{ runner.os == 'Linux' }}
        with:
          key: liboqs-cache-${{ matrix.os }}

      - name: Install Linux dependencies
        if: ${{ runner.os == 'Linux' }}
        run: |
          sudo apt update
          sudo apt install -y --no-install-recommends libnettle8 libssl-dev libkrb5-dev ssh cmake ninja-build

      - name: Install macOS dependencies
        if: ${{ runner.os == 'macOS' }}
        run: brew install nettle liboqs

      - name: Install nettle (Windows)
        if: ${{ runner.os == 'Windows' }}
        shell: pwsh
        run: |
          curl -fLO https://github.com/ShiftMediaProject/nettle/releases/download/${{ env.nettle_version }}/libnettle_${{ env.nettle_version }}_msvc17.zip
          Expand-Archive libnettle_${{ env.nettle_version }}_msvc17.zip nettle
          cp nettle\bin\x64\*.dll "$env:Python_ROOT_DIR"

      - name: Install liboqs (Linux)
        if: ${{ runner.os == 'Linux' }}
        working-directory: liboqs
        run: |
          cmake -GNinja -Bbuild . -DCMAKE_INSTALL_PREFIX=/usr -DBUILD_SHARED_LIBS=ON -DOQS_BUILD_ONLY_LIB=ON -DOQS_DIST_BUILD=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache
          cmake --build build
          sudo cmake --install build

      - name: Initialize MSVC environment
        uses: ilammy/msvc-dev-cmd@v1

      - name: Install liboqs (Windows)
        if: ${{ runner.os == 'Windows' }}
        shell: pwsh
        working-directory: liboqs
        run: |
          cmake -GNinja -Bbuild . -DBUILD_SHARED_LIBS=ON -DOQS_BUILD_ONLY_LIB=ON -DOQS_DIST_BUILD=ON
          cmake --build build
          cp build\bin\oqs.dll "$env:Python_ROOT_DIR"

      - name: Install Python dependencies
        run: pip install tox

      - name: Run tests
        shell: python
        working-directory: asyncssh
        run: |
          import os, sys, platform, subprocess
          V = sys.version_info
          p = platform.system().lower()
          subprocess.run(
              ['tox', 'run', '-e', f'py{V.major}{V.minor}-{p}', '--', '-ra'],
              check=True)

      - name: Upload coverage data
        uses: actions/upload-artifact@v4
        with:
          name: coverage-${{ matrix.os }}-${{ matrix.python-version }}
          path: asyncssh/.coverage.*
          include-hidden-files: true
          retention-days: 1

  merge-coverage:
    runs-on: ubuntu-latest
    needs: run-tests
    if: ${{ always() }}
    permissions:
      actions: write
    steps:
      - name: Merge coverage
        uses: actions/upload-artifact/merge@v4
        with:
          name: coverage
          pattern: coverage-*
          include-hidden-files: true

  report-coverage:
    name: Report coverage
    runs-on: ubuntu-latest
    needs: merge-coverage
    if: ${{ always() }}
    permissions:
      contents: read
      actions: read
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
      - uses: actions/download-artifact@v4
        with:
          name: coverage
      - name: Install dependencies
        run: |
          sudo apt install -y sqlite3
          pip install tox
      - name: Report coverage
        run: |
          shopt -s nullglob
          for f in .coverage.*-windows; do
            sqlite3 "$f" "update file set path = replace(path, '\\', '/');"
          done
          tox -e report
      - uses: codecov/codecov-action@v4
        with:
          files: coverage.xml
          token: ${{ secrets.CODECOV_TOKEN }}
