name: test

on:
  push:
  pull_request:

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: full

jobs:
  test:
    name: Build & test
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-latest
          - macos-latest
          - windows-latest
        rust:
          - stable
          - beta
          - nightly
          # 1.45.0 # The weak-into-raw feature stabilized
          # 1.31.0 is tested separately, because it is supposed to only build

    runs-on: ${{ matrix.os }}

    steps:
      - name: checkout
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: ${{ matrix.rust }}
          default: true
          profile: minimal

      - name: Restore cache
        uses: Swatinem/rust-cache@v2

      - name: Build & test
        env:
          RUST_VERSION: ${{ matrix.rust }}
          OS: ${{ matrix.os }}
          RUSTFLAGS: -D warnings
        run: cargo test --features weak,internal-test-strategies,experimental-strategies

  big-tests:
    name: Run the big ignored tests
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          default: true
          profile: minimal

      - name: Restore cache
        uses: Swatinem/rust-cache@v2

      - name: Build & test
        env:
          RUSTFLAGS: -D warnings
        run: cargo test --features weak,internal-test-strategies,experimental-strategies --release -- --ignored

  bits32:
    name: 32bit tests
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          default: true
          profile: minimal
          target: x86_64-unknown-linux-musl

      - name: Restore cache
        uses: Swatinem/rust-cache@v2

      - name: Build & test
        env:
          RUSTFLAGS: -D warnings
        run: cargo test --features weak,internal-test-strategies,experimental-strategies --target x86_64-unknown-linux-musl

  rustfmt:
    name: Check formatting
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          profile: minimal
          toolchain: stable
          default: true
          components: rustfmt

      - run: cargo fmt --all -- --check

  links:
    name: Check documentation links
    runs-on: ubuntu-latest
    steps:
      - name: checkout
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          default: true

      - name: Restore cache
        uses: Swatinem/rust-cache@v2

      - name: Check links
        run: cargo rustdoc --features weak,internal-test-strategies,experimental-strategies -- -D warnings

  clippy:
    name: Clippy lints
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          default: true
          components: clippy

      - name: Restore cache
        uses: Swatinem/rust-cache@v2

      - name: Run clippy linter
        run: cargo clippy --all --features weak,internal-test-strategies,experimental-strategies --tests -- -D clippy::all -D warnings

  bench:
    name: Verify benchmarks compile
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: stable
          profile: minimal
          default: true

      - name: Restore cache
        uses: Swatinem/rust-cache@v2

      - name: Run clippy linter
        run: cargo test --all --release --benches --features weak,internal-test-strategies,experimental-strategies

  semi-ancient:
    name: Check it compiles on old Rust (1.45.0)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: 1.45.0
          profile: minimal
          default: true

      - name: Restore cache
        uses: Swatinem/rust-cache@v2

      - name: Run check
        run: mv Cargo.lock.old Cargo.lock && cargo check --features weak,internal-test-strategies,experimental-strategies

  ancient:
    name: Check it compiles on old Rust (1.31.0)
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: 1.31.0
          profile: minimal
          default: true

      - name: Restore cache
        uses: Swatinem/rust-cache@v2

      - name: Run check
        run: mv Cargo.lock.old Cargo.lock && cargo check

  experimental_thread_local:
    name: Test with experimental-thread-local
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: nightly
          profile: minimal
          default: true

      - name: Restore cache
        uses: Swatinem/rust-cache@v2

      - name: Build & test
        env:
          RUSTFLAGS: -D warnings
        run: cargo test --no-default-features --features weak,experimental-thread-local

  miri:
    name: Miri checks
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v5

      - name: Install Rust
        uses: actions-rs/toolchain@v1
        with:
          toolchain: nightly
          profile: minimal
          default: true
          components: "miri"

      - name: Restore cache
        uses: Swatinem/rust-cache@v2

      - name: Run miri
        env:
          PROPTEST_CASES: "10"
          MIRIFLAGS: "-Zmiri-disable-isolation -Zmiri-permissive-provenance"
        run: cargo miri test --features weak,internal-test-strategies,experimental-strategies

  thread_sanitizer-MacOS:
    name: Thread Sanitizer checks MacOS
    runs-on: macos-latest

    steps:
    - uses: actions/checkout@v5
    - uses: actions/cache@v4
      with:
        path: |
          ~/.cargo/bin/
          ~/.cargo/registry/index/
          ~/.cargo/registry/cache/
          ~/.cargo/git/db/
          target/
        key: ${{ github.event.repository.name }}-${{ runner.os }}-cargo-thread_sanitizer-v2
    - name: Install latest nightly
      uses: actions-rs/toolchain@v1
      with:
          toolchain: nightly
          override: true
          components: rust-src
    - name: Run thread sanitizer
      run: |
        # Thread sanitizer isn't guaranteed to catch all data races, it can only catch it
        # the data race if it happens when running the program.
        #
        # Running the tests multiple times increase the chances that data races are found
        # by the thread sanitizer.
        for _ in $(seq 1 10); do cargo +nightly test -Z build-std --target $(uname -m)-apple-darwin; done
      env:
        RUSTDOCFLAGS: "-Zsanitizer=thread"
        RUSTFLAGS: "-Zsanitizer=thread"
