lihaaf 0.1.0

Fast compile-fail and compile-pass test harness for Rust proc macros; a faster trybuild-style workflow
Documentation
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  CARGO_TERM_COLOR: always

permissions:
  contents: read
  pull-requests: read

jobs:
  check:
    name: Build, Test, Lint
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy, rustfmt

      - name: Cache cargo registry and build
        uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-cargo-

      - name: Check formatting
        run: cargo fmt --all -- --check

      - name: Clippy
        run: cargo clippy --all-targets -- -D warnings

      - name: Build (release)
        run: cargo build --release

      - name: Test
        env:
          # Opt into the gated `cargo rustc` integration test that
          # codifies the PR #34 overlay-staging-path fix
          # (`cargo_accepts_staged_overlay_for_dylib_build` in
          # `tests/compat/overlay_determinism.rs`). The gate exists so
          # RAM-limited local boxes can skip the test by default; CI
          # explicitly opts in to make the test authoritative.
          LIHAAF_RUN_CARGO_BUILD_TESTS: "1"
        run: cargo test

      - name: Self-test corpus end-to-end
        # Build cargo-lihaaf and run it against the in-tree
        # `tests/lihaaf/{compile_pass,compile_fail,compile_pass_suite_demo}/`
        # corpus. The corpus is `[package.metadata.lihaaf]` self-
        # references — lihaaf builds itself as the dylib_crate and links
        # each fixture against it.
        #
        # `cargo lihaaf` (no `--suite`) runs every defined suite in
        # declared metadata order: the implicit `default` suite over
        # `compile_fail/` + `compile_pass/`, then the named
        # `suite_demo` suite over `compile_pass_suite_demo/` with
        # `--features suite_demo` activated. The named suite proves
        # the v0.1.0-alpha.3 multi-suite capability propagates the
        # feature set to BOTH the dylib build AND the per-fixture rustc
        # invocation: the demo fixture references
        # `lihaaf::SUITE_DEMO_MARKER` (only exposed under the feature),
        # so any regression that drops feature propagation fails to
        # link and CI flips red.
        #
        # A non-zero exit fails CI; the success path proves the full
        # session pipeline (config load → toolchain capture → per-suite
        # dylib build → per-suite manifest refresh → discovery → worker
        # pool dispatch with §4.5 freshness checks → §3.3 aggregate
        # report) works end-to-end on the current toolchain across two
        # independent suites.
        run: cargo run --release --bin cargo-lihaaf -- lihaaf

      - name: Self-test corpus (integration_corpus)
        # FIX_BEFORE_BETA Spec D: a real-adopter-shaped integration
        # corpus that exercises lihaaf's negative-path verdict classes
        # in CI. The corpus lives under `tests/integration_corpus/`
        # (excluded from lihaaf's own package via `[package].exclude`
        # in the root Cargo.toml) and uses a two-crate layout — a
        # regular library `integration_corpus` (which lihaaf builds as
        # the dylib_crate) plus a sibling `integration_corpus_macros`
        # proc-macro crate (which lihaaf cannot build as a dylib;
        # cargo rejects `[lib] proc-macro = true` with
        # `--crate-type=dylib`). The macros are re-exported through
        # the parent crate so fixtures use a single
        # `use integration_corpus::*;` shape (the serde/serde_derive
        # layout).
        #
        # The six fixtures cover one verdict class each:
        # - uses_corpus_noop.rs       → OK (no-op macro + const)
        # - corpus_error_basic.rs     → OK (snapshot match)
        # - large_snapshot.rs         → SNAPSHOT_DIFF + LARGE_SNAPSHOT
        #                                warning (>10K-line diagnostic
        #                                with one mutated snapshot line)
        # - missing_snapshot.rs       → SNAPSHOT_MISSING (no .stderr)
        # - intentional_timeout.rs    → TIMEOUT (macro sleeps forever)
        # - intentional_oom.rs        → MEMORY_EXHAUSTED (paced 16 MiB
        #                                writes against a 128 MiB cap)
        #
        # The grep gates anchor on the verdict labels in
        # `src/verdict.rs::Verdict::label` and on the warning line
        # emitted in `src/session.rs::emit_fixture_warnings`. Any
        # regression that drops one of those labels — e.g. renaming
        # `MEMORY_EXHAUSTED` to `OOM`, dropping the LARGE_SNAPSHOT
        # warning emit, or short-circuiting the snapshot-missing path
        # — flips CI red here, even if the rest of lihaaf still builds
        # and the self-test suite still passes.
        #
        # `|| true` after `tee` ensures the verdict-bearing lihaaf
        # invocation does not fail the step (lihaaf exits non-zero
        # whenever fixtures don't all pass — by design, this corpus
        # has four deliberate failures); the six `grep -q` calls are
        # the real assertion: four negative-verdict labels, the
        # LARGE_SNAPSHOT warning, and the aggregate summary line.
        run: |
          cargo run --release --bin cargo-lihaaf -- lihaaf \
            --manifest-path tests/integration_corpus/Cargo.toml \
            --quiet 2>&1 | tee /tmp/corpus.log || true
          grep -q SNAPSHOT_MISSING /tmp/corpus.log
          grep -q TIMEOUT /tmp/corpus.log
          grep -q MEMORY_EXHAUSTED /tmp/corpus.log
          grep -q LARGE_SNAPSHOT /tmp/corpus.log
          grep -q SNAPSHOT_DIFF /tmp/corpus.log
          grep -qE 'lihaaf: 2 ok, 2 failed, 1 timeout, 1 memory_exhausted' /tmp/corpus.log
        env:
          CARGO_TERM_COLOR: always

      - name: Secrets-scan self-tests
        run: bash scripts/run-scan-tests.sh

  docs:
    name: cargo doc
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo registry and build
        uses: actions/cache@v5
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-docs-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-cargo-docs-

      - name: cargo doc (warnings as errors)
        env:
          RUSTDOCFLAGS: "-D warnings"
        run: cargo doc --no-deps

  audit:
    name: cargo audit
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v6

      - name: Install cargo-audit
        run: cargo install --locked cargo-audit

      - name: Run cargo audit
        run: cargo audit