aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-08-12 16:43:20 +0800
committer魏曹先生 <1992414357@qq.com>2026-08-12 16:43:20 +0800
commit6f1b5233b9aff8f9b75682699ac6c1d6e3d98efa (patch)
tree5b02dce537fbd680e56af554b11046e2de750d2f
parent3a2341b0b618eacd902d611b49d4c481b671e286 (diff)
feat(cov-test): build examples with RUSTFLAGS for complete coverage
Replace `cargo llvm-cov run` with explicit RUSTFLAGS-compiled examples to ensure dependency crates are instrumented, fixing silent coverage loss (e.g., once_exec.rs at 0%).
-rw-r--r--.run/src/bin/cov-test.rs71
1 files changed, 60 insertions, 11 deletions
diff --git a/.run/src/bin/cov-test.rs b/.run/src/bin/cov-test.rs
index 93318ee..dd431ba 100644
--- a/.run/src/bin/cov-test.rs
+++ b/.run/src/bin/cov-test.rs
@@ -103,20 +103,56 @@ fn main() {
});
}
- // 3. Examples: execute every command from test-examples.toml so their
- // code paths are recorded. Non-zero exit codes are expected for some
- // examples (e.g. `--help` exits with 2); profraw is still written.
+ // 3. Examples: build each example with explicit RUSTFLAGS, then execute
+ // every command from test-examples.toml directly.
+ //
+ // NOTE: `cargo llvm-cov run` cannot be used here. Its rustc wrapper
+ // only instruments the crates of the *current* cargo project (with
+ // `--manifest-path` that is the example itself), so the mingling
+ // libraries — being dependencies — would not be instrumented and their
+ // coverage would silently be lost (once_exec.rs showed 0%). Building
+ // with plain RUSTFLAGS instruments the whole dependency graph.
+ //
+ // RUSTFLAGS/CARGO_TARGET_DIR are set process-wide here because only the
+ // `report` step (which does not compile) follows. Non-zero exit codes
+ // are expected for some examples (e.g. `--help` exits with 2); profraw
+ // is still written.
+ unsafe {
+ std::env::set_var("RUSTFLAGS", "-Cinstrument-coverage");
+ std::env::set_var("CARGO_TARGET_DIR", &cov_target);
+ }
let examples = load_example_commands(&repo_root);
+ let mut built = std::collections::HashSet::new();
for (example, command) in &examples {
- if let Err(code) = run_cmd!(format!(
- "cargo llvm-cov run --no-report --manifest-path examples/{}/Cargo.toml --color always -- {}",
- example, command
- )) {
- println_cargo_style!(
- "Warning: example {} exited with {}, profraw still recorded",
+ if built.insert(example.clone()) {
+ println_cargo_style!("Building: {}", example);
+ run_cmd!(format!(
+ "cargo build --manifest-path examples/{}/Cargo.toml --color always",
+ example
+ ))
+ .unwrap_or_else(|code| {
+ eprintln_cargo_style!("build of example {} failed with exit code {}", example, code);
+ std::process::exit(code);
+ });
+ }
+ let binary = cov_target.join("debug").join(get_binary_name(example));
+ let profraw = format!(
+ "{}/example-{}.%p.profraw",
+ cov_target.to_string_lossy(),
+ example
+ );
+ match std::process::Command::new(&binary)
+ .args(command.split_whitespace())
+ .env("LLVM_PROFILE_FILE", &profraw)
+ .status()
+ {
+ Ok(status) if status.success() => {}
+ Ok(status) => println_cargo_style!(
+ "Warning: example {} exited with {:?}, profraw still recorded",
example,
- code
- );
+ status.code()
+ ),
+ Err(e) => eprintln_cargo_style!("Failed to run example {}: {}", example, e),
}
}
@@ -356,6 +392,19 @@ fn file_id(path: &Path) -> String {
.into_owned()
}
+/// Resolve binary filename for the given example.
+///
+/// The binary name matches the package name. On Windows, the `.exe` suffix is
+/// required.
+fn get_binary_name(example_name: &str) -> String {
+ let base = example_name;
+ if cfg!(target_os = "windows") {
+ format!("{base}.exe")
+ } else {
+ base.to_string()
+ }
+}
+
/// True if the file is executable: mode bits on Unix, `.exe` on Windows.
fn is_executable(path: &Path) -> bool {
#[cfg(unix)]