# kache-e2e fixture: the configured fallback wrapper.
#
# kache can delegate to another compiler-wrapper (e.g. sccache) on the
# passthrough path — set `KACHE_FALLBACK` and a declined compile runs
# `<fallback> <compiler> <args>` instead of the compiler directly
# (#109). This fixture is the cell for that wiring.
#
# The project is a dependency-free `bin`. kache never caches a
# user-facing executable, so building it ALWAYS takes the passthrough
# path — which, with `KACHE_FALLBACK` set, hands the compile to the
# `e2e-fallback` wrapper. Driven by `E2E_FALLBACK_CFG`, it appends
# `--cfg fallback_was_used` to the compile, which `src/main.rs` reads
# via `cfg!`, so the binary's own output proves the fallback ran.
#
# NOT `negative_control_exempt`: unlike `c-passthrough`, disabling
# kache IS distinguishable here. `KACHE_DISABLED=1` routes straight to
# the real compiler — the fallback is skipped, the marker is unset,
# and `[verify]` flips to fail. That is what makes the fixture
# falsifiable.

name = "e2e-rust-fallback"
tags = ["suite:e2e", "lang:rust", "mode:fallback"]

[source]
kind = "fixture"
path = "source"

[env]
RUSTC_WRAPPER = "$KACHE"
# Cross-platform fallback wrapper (`e2e-fallback`), built next to the
# harness; `$FALLBACK` expands to its absolute path, so the relocated
# build finds it too — no per-fixture script to `cp -R`, and it runs on
# Windows (a `.sh` can't be exec'd there).
KACHE_FALLBACK = "$FALLBACK"
# Drive the wrapper: append `--cfg fallback_was_used` to the fixture
# crate's own compile (matched by `--crate-name rust_fallback`).
E2E_FALLBACK_CRATE = "rust_fallback"
E2E_FALLBACK_CFG = "fallback_was_used"

[commands]
build = "cargo build"
clean = "rm -rf target"

[verify]
run = "./target/debug/rust-fallback"
# Printed only when the `e2e-fallback` wrapper ran — i.e. the fallback
# was actually invoked. With the fallback broken the binary prints
# `rust-fallback: no fallback` and this assertion fails.
expected_stdout_contains = ["rust-fallback: via fallback"]

# kache declines to cache the executable on every phase, so nothing
# is ever stored — the contract is "the fallback ran", asserted by
# `[verify]`, not by cache entries.
[assertions.cold]
max_entries_after = 0

[assertions.warm]
max_entries_after = 0

# A no-op rebuild: cargo's own freshness check sees nothing changed
# and does not recompile. (kache caches nothing here, but cargo still
# short-circuits before reaching the wrapper.)
[assertions.noop]
should_not_recompile = true
recompile_marker = "Compiling"

# Built from a different absolute path: still passthrough, still
# fallback, still nothing cached.
[assertions.relocate]
max_entries_after = 0
