lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README | LICENSE

commit b1f45c374f4914aa691ba15e4e34c475ebf559fc
parent 816edb4767c58db6e75c636c1ff365bd7ac3ecf1
Author: triesap <tyson@radroots.org>
Date:   Sat, 21 Feb 2026 17:32:36 +0000

tests: add `xtask` coverage parser and gate unit tests



- add summary parser unit test for llvm-cov totals extraction
- add lcov parser unit test for da and branch metrics
- add gate evaluator unit test for required branch data failure behavior
- run cargo check -q -p xtask and cargo test -q -p xtask

Diffstat:
Mcrates/xtask/src/coverage.rs | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 94 insertions(+), 0 deletions(-)

diff --git a/crates/xtask/src/coverage.rs b/crates/xtask/src/coverage.rs @@ -536,3 +536,97 @@ pub fn run(args: &[String]) -> Result<(), String> { None => Err("missing sdk coverage subcommand".to_string()), } } + +#[cfg(test)] +mod tests { + use super::*; + use std::time::{SystemTime, UNIX_EPOCH}; + + fn temp_file_path(prefix: &str) -> PathBuf { + let ns = SystemTime::now() + .duration_since(UNIX_EPOCH) + .expect("system time") + .as_nanos(); + std::env::temp_dir().join(format!("radroots_xtask_coverage_{prefix}_{ns}.tmp")) + } + + #[test] + fn reads_summary_totals_from_llvm_cov_json() { + let path = temp_file_path("summary"); + fs::write( + &path, + r#"{ + "data": [ + { + "totals": { + "functions": {"percent": 91.25}, + "lines": {"percent": 88.5}, + "regions": {"percent": 86.75} + } + } + ] +}"#, + ) + .expect("write summary"); + + let summary = read_summary(&path).expect("parse summary"); + assert_eq!(summary.functions_percent, 91.25); + assert_eq!(summary.summary_lines_percent, 88.5); + assert_eq!(summary.summary_regions_percent, 86.75); + + fs::remove_file(path).expect("remove summary"); + } + + #[test] + fn reads_lcov_da_and_branch_metrics() { + let path = temp_file_path("lcov"); + fs::write( + &path, + "DA:1,1\nDA:2,0\nDA:3,1\nBRF:4\nBRH:3\n", + ) + .expect("write lcov"); + + let lcov = read_lcov(&path).expect("parse lcov"); + assert_eq!(lcov.executable_total, 3); + assert_eq!(lcov.executable_covered, 2); + assert!(lcov.branches_available); + assert_eq!(lcov.branch_total, 4); + assert_eq!(lcov.branch_covered, 3); + assert_eq!(lcov.branch_percent, Some(75.0)); + + fs::remove_file(path).expect("remove lcov"); + } + + #[test] + fn gate_fails_when_branch_data_is_required_but_missing() { + let summary = CoverageSummary { + functions_percent: 100.0, + summary_lines_percent: 100.0, + summary_regions_percent: 100.0, + }; + let lcov = LcovCoverage { + executable_total: 10, + executable_covered: 10, + executable_percent: 100.0, + executable_source: ExecutableSource::Da, + branch_total: 0, + branch_covered: 0, + branches_available: false, + branch_percent: None, + }; + let thresholds = CoverageThresholds { + fail_under_exec_lines: 100.0, + fail_under_functions: 100.0, + fail_under_branches: 100.0, + require_branches: true, + }; + + let gate = evaluate_gate(&summary, &lcov, thresholds); + assert!(!gate.pass); + assert!( + gate.fail_reasons + .iter() + .any(|reason| reason == "branches=unavailable") + ); + } +}