facett-app/tests/devid_release_profile.rs
//! **The DEV-ID chip, proven on a RELEASE build.** The one hole no `#[test]` could cover.
//!
//! # The hole
//!
//! `debug_assertions` is decided at compile time and `cargo test` always compiles with it
//! **on**. Every other devid test — the unit table in `facett-core/src/devid.rs`, the
//! AccessKit assertions in `devid_scene_slots.rs`, facett-demo's deck tests — runs in that
//! one profile. So when the badge was gated on `#[cfg(debug_assertions)]` alone and
//! `badge` compiled to an *empty function body* in every installed `--release` binary,
//! five green tests said nothing was wrong. The tests were not weak; they were structurally
//! incapable of seeing it.
//!
//! The only way out is to leave the profile: build a real release binary and inspect it.
//!
//! # What this asserts
//!
//! `cargo build --release --bin devid_release_probe` (see
//! `facett-app/src/bin/devid_release_probe.rs`), then runs it twice:
//!
//! | run | `enabled()` | dev-id atoms in the AccessKit tree |
//! |---|---|---|
//! | `FACETT_DEVID` unset | `false` | 0 |
//! | `FACETT_DEVID=1` | `true` | ≥ 1, reading `korp/map_canvas` |
//!
//! The probe renders through [`facett_app::scene::render`] — the container korp actually
//! calls — so the assertion is on **applied output**: an atom really in the tree, in a
//! process where `debug_assertions` is really off. Every run also checks the probe's own
//! `debug_assertions` field is `false`; without that, a mis-wired build would inspect a
//! debug binary and pass for the wrong reason.
//!
//! # Cost
//!
//! One release compile of `facett-core` + `facett-app` + `egui` the first time (~1 min on
//! oden, seconds when warm). It reuses the caller's `--target-dir`, so `cargo test
//! -p facett-app --target-dir X` puts the release artifacts in `X/release`. That is the
//! price of the only check in the suite that can see this class of bug, and it is not
//! `#[ignore]`d on purpose — an ignored guard is a green that was never run.
//!
//! ```bash
//! cargo test -p facett-app --test devid_release_profile
//! ```
use std::path::{Path, PathBuf};
use std::process::Command;
/// The target dir the *caller* is using — derived from this test binary's own path
/// (`<target>/debug/deps/devid_release_profile-<hash>`), so `--target-dir` is honoured
/// automatically and the release build shares the caller's dependency artifacts instead
/// of starting a second tree from scratch.
fn target_dir() -> PathBuf {
let exe = std::env::current_exe().expect("test binary has a path");
// deps/ -> debug/ -> <target>
exe.ancestors().nth(3).expect("<target>/debug/deps/<exe>").to_path_buf()
}
fn cargo() -> String {
std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string())
}
fn manifest() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR")).join("Cargo.toml")
}
/// Build the probe with `--release` and hand back the path to the binary.
fn build_release_probe(target: &Path) -> PathBuf {
let out = Command::new(cargo())
.args([
"build",
"--release",
"--bin",
"devid_release_probe",
"--features",
"devid-probe",
"--manifest-path",
])
.arg(manifest())
.arg("--target-dir")
.arg(target)
// The probe must decide its gate from the env WE give it, never from whatever
// the developer's shell (or a running korp-ui) happens to export.
.env_remove("FACETT_DEVID")
.output()
.expect("cargo is runnable");
assert!(
out.status.success(),
"release build of devid_release_probe FAILED:\n{}",
String::from_utf8_lossy(&out.stderr)
);
let bin = target.join("release").join("devid_release_probe");
assert!(bin.is_file(), "cargo reported success but {} does not exist", bin.display());
bin
}
/// Run the probe and parse its one JSON line.
fn run_probe(bin: &Path, devid: Option<&str>) -> serde_json::Value {
let mut cmd = Command::new(bin);
cmd.env_remove("FACETT_DEVID");
if let Some(v) = devid {
cmd.env("FACETT_DEVID", v);
}
let out = cmd.output().expect("the probe runs");
assert!(
out.status.success(),
"probe exited {:?}:\n{}",
out.status.code(),
String::from_utf8_lossy(&out.stderr)
);
let stdout = String::from_utf8_lossy(&out.stdout);
let line = stdout.lines().last().unwrap_or_default();
serde_json::from_str(line).unwrap_or_else(|e| panic!("probe printed no JSON ({e}): {stdout:?}"))
}
#[test]
fn a_release_build_paints_the_chip_when_facett_devid_is_set() {
let target = target_dir();
let bin = build_release_probe(&target);
// ── The control: a release build with nothing set shows nothing. ─────────────
let off = run_probe(&bin, None);
assert_eq!(
off["debug_assertions"], false,
"the probe was NOT a release build — this whole test would then be asserting on \
the same profile as every other test and could not see the bug it exists for. \
Got {off}"
);
assert_eq!(off["enabled"], false, "release + FACETT_DEVID unset must be off: {off}");
assert_eq!(
off["devid_atoms"], 0,
"a release build with the gate closed still painted a chip: {off}"
);
// ── The case that matters: the escape hatch must actually reach the pixels. ──
let on = run_probe(&bin, Some("1"));
assert_eq!(on["debug_assertions"], false, "not a release build: {on}");
assert_eq!(
on["enabled"], true,
"FACETT_DEVID=1 did not switch the chip on in a RELEASE build — the aid is then \
invisible in every binary that ships: {on}"
);
// The APPLIED output, not the gate: an atom really in the AccessKit tree of a real
// `scene::render` pass. This is what `badge` compiling to an empty body would break,
// and what no debug-profile test can observe.
assert!(
on["devid_atoms"].as_u64().unwrap_or(0) >= 1,
"the gate said ON but NO dev-id atom reached the rendered tree — `badge` drew \
nothing in the release build: {on}"
);
let labels = on["labels"].as_array().cloned().unwrap_or_default();
assert!(
labels.iter().any(|l| l.as_str().unwrap_or_default().contains("korp/map_canvas")),
"the chip is there but does not name the pane (expected `korp/map_canvas`): {on}"
);
// A chip identical on every pane is no better than no chip; the registered form is
// `component/slot`, and that is what the release build must produce.
assert_eq!(on["badge_text"], "korp/map_canvas", "wrong chip text in release: {on}");
}