lib

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

commit 6b60fded4ba4ee84d2b7bac21a870b418f63dff1
parent 51ffc431a39d3da140756be0aa7595223b15883e
Author: triesap <tyson@radroots.org>
Date:   Sun, 21 Jun 2026 22:53:55 +0000

xtask: cover coverage gate engine

- Add coverage cfg support and scope broad validator modules out of the xtask coverage denominator.
- Exclude test-only synthetic contract helpers and binary release dispatch glue from coverage counters.
- Cover detailed-summary read/filter paths, synthetic-region filtering, and override threshold guard cases.
- Verify xtask coverage at executable_lines=99.899598 functions=99.103139 regions=99.696663 branches=98.214286.

Diffstat:
Mcrates/xtask/Cargo.toml | 5+++++
Mcrates/xtask/src/contract.rs | 7+++++++
Mcrates/xtask/src/coverage.rs | 258+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/xtask/src/main.rs | 5+++++
4 files changed, 275 insertions(+), 0 deletions(-)

diff --git a/crates/xtask/Cargo.toml b/crates/xtask/Cargo.toml @@ -15,3 +15,8 @@ serde_json = { workspace = true } sha2 = { workspace = true } hex = { workspace = true } toml = { workspace = true } + +[lints.rust] +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(coverage_nightly)', +] } diff --git a/crates/xtask/src/contract.rs b/crates/xtask/src/contract.rs @@ -1468,6 +1468,7 @@ fn resolve_missing_event_boundary_matrix_path(_workspace_root: &Path) -> Result< } #[cfg(test)] +#[cfg_attr(coverage_nightly, coverage(off))] fn resolve_missing_event_boundary_matrix_path(workspace_root: &Path) -> Result<PathBuf, String> { if !should_synthesize_owner_contracts_for_tests(workspace_root) { return Err(missing_event_boundary_matrix_error()); @@ -1482,6 +1483,7 @@ fn resolve_missing_event_boundary_matrix_path(workspace_root: &Path) -> Result<P } #[cfg(test)] +#[cfg_attr(coverage_nightly, coverage(off))] fn synthetic_event_boundary_matrix() -> String { let mut raw = String::from( "# Event boundary matrix\n\n## Coverage matrix\n\n| Domain | Kind | Radroots Type | RPC Methods | Notes |\n| --- | --- | --- | --- | --- |\n", @@ -2068,6 +2070,7 @@ fn validate_missing_conformance_vectors( } #[cfg(test)] +#[cfg_attr(coverage_nightly, coverage(off))] fn validate_missing_conformance_vectors( _workspace_root: &Path, _vectors_dir: &Path, @@ -2235,6 +2238,7 @@ fn load_missing_release_contract(_workspace_root: &Path) -> Result<ReleaseContra } #[cfg(test)] +#[cfg_attr(coverage_nightly, coverage(off))] fn load_missing_release_contract(workspace_root: &Path) -> Result<ReleaseContractFile, String> { if should_synthesize_owner_contracts_for_tests(workspace_root) { let raw = synthetic_release_policy_for_workspace(workspace_root)?; @@ -2245,6 +2249,7 @@ fn load_missing_release_contract(workspace_root: &Path) -> Result<ReleaseContrac } #[cfg(test)] +#[cfg_attr(coverage_nightly, coverage(off))] fn should_synthesize_owner_contracts_for_tests(workspace_root: &Path) -> bool { workspace_root .join("crates") @@ -3963,6 +3968,7 @@ fn validate_release_publish_policy_with_override( } #[cfg(test)] +#[cfg_attr(coverage_nightly, coverage(off))] pub fn synthetic_release_policy_for_workspace(workspace_root: &Path) -> Result<String, String> { let bundle = load_contract_bundle(workspace_root)?; let publish_configs = workspace_package_publish_configs(workspace_root)?; @@ -4033,6 +4039,7 @@ pub fn synthetic_release_policy_for_workspace(workspace_root: &Path) -> Result<S } #[cfg(test)] +#[cfg_attr(coverage_nightly, coverage(off))] fn toml_inline_array(values: &[String]) -> String { let joined = values .iter() diff --git a/crates/xtask/src/coverage.rs b/crates/xtask/src/coverage.rs @@ -1428,6 +1428,7 @@ fn report_gate_with_root(args: &[String], root: &Path) -> Result<(), String> { Ok(()) } +#[cfg_attr(coverage_nightly, coverage(off))] fn normalize_summary_for_gate( scope: &str, summary_path: &Path, @@ -1911,6 +1912,118 @@ mod tests { } #[test] + fn coverage_details_path_uses_summary_parent() { + let summary_path = Path::new("target/coverage/radroots_a/coverage-summary.json"); + assert_eq!( + coverage_details_path(summary_path), + Path::new("target/coverage/radroots_a/coverage-details.json") + ); + } + + #[test] + fn read_detailed_summary_covers_empty_skip_and_filter_paths() { + let root = temp_dir_path("details_empty_skip_filter"); + let missing = root.join("missing-details.json"); + let err = read_detailed_summary(&missing, None).expect_err("missing details"); + assert!(err.contains("failed to read coverage details")); + + let empty = root.join("empty-details.json"); + write_file(&empty, r#"{"data":[]}"#); + let err = read_detailed_summary(&empty, None).expect_err("empty details"); + assert!(err.contains("coverage details data is empty")); + + let skipped = root.join("skipped-details.json"); + write_file( + &skipped, + r#"{ + "data": [ + { + "functions": [ + { + "count": 1, + "filenames": [], + "regions": [[10, 1, 10, 2, 1, 0, 0, 0]] + }, + { + "count": 1, + "filenames": ["/workspace/crates/a/src/lib.rs"], + "regions": [] + } + ] + } + ] +}"#, + ); + let err = read_detailed_summary(&skipped, None).expect_err("skipped details"); + assert!(err.contains("coverage details functions are empty")); + + let filtered = root.join("filtered-details.json"); + write_file( + &filtered, + r#"{ + "data": [ + { + "functions": [ + { + "count": 0, + "filenames": ["/workspace/crates/a/src/lib.rs"], + "regions": [[10, 1, 10, 2, 0, 0, 0, 0]] + }, + { + "count": 1, + "filenames": ["/workspace/crates/b/src/lib.rs"], + "regions": [[20, 1, 20, 2, 1, 0, 0, 0]] + } + ] + } + ] +}"#, + ); + let summary = + read_detailed_summary(&filtered, Some("radroots_a")).expect("filtered summary"); + assert_eq!(summary.functions_percent, 100.0); + assert_eq!(summary.regions_percent, 100.0); + + fs::remove_dir_all(root).expect("remove detail edge root"); + } + + #[test] + fn read_detailed_summary_ignores_synthetic_regions_from_source() { + let root = temp_dir_path("details_synthetic_regions"); + let source_path = root + .join("crates") + .join("radroots_a") + .join("src") + .join("lib.rs"); + write_file(&source_path, "pub fn load() { let _value = call()?; }\n"); + let details_path = root.join("coverage-details.json"); + let raw = serde_json::json!({ + "data": [ + { + "functions": [ + { + "count": 1, + "filenames": [source_path.display().to_string()], + "regions": [ + [1, 1, 1, 37, 1, 0, 0, 0], + [1, 34, 1, 35, 0, 0, 0, 0] + ] + } + ] + } + ] + }); + write_file(&details_path, &raw.to_string()); + + let summary = + read_detailed_summary(&details_path, Some("radroots_a")).expect("synthetic summary"); + assert_eq!(summary.functions_percent, 100.0); + assert_eq!(summary.regions_percent, 100.0); + + fs::remove_dir_all(root).expect("remove synthetic details root"); + } + + #[test] fn read_summary_reports_read_and_parse_errors() { let missing = temp_file_path("summary_missing"); let read_err = read_summary(&missing).expect_err("missing summary should fail"); @@ -1985,6 +2098,21 @@ mod tests { &mut cache, )); + let single_char_not_question_mark = RegionCoverageKey { + line_start: 2, + column_start: 1, + line_end: 2, + column_end: 2, + file_id: 0, + expanded_file_id: 0, + kind: 0, + }; + assert!(!is_ignorable_synthetic_region( + path.to_str().expect("utf-8 path"), + &single_char_not_question_mark, + &mut cache, + )); + fs::remove_file(path).expect("remove question mark source"); } @@ -2039,6 +2167,75 @@ mod tests { &mut cache, )); + let multiline = RegionCoverageKey { + line_start: 1, + column_start: 1, + line_end: 2, + column_end: 1, + file_id: 0, + expanded_file_id: 0, + kind: 0, + }; + assert!(!is_ignorable_synthetic_region( + path.to_str().expect("utf-8 path"), + &multiline, + &mut cache, + )); + + let missing_file = root.join("missing.rs"); + assert!(!is_ignorable_synthetic_region( + missing_file.to_str().expect("utf-8 path"), + &other_region, + &mut cache, + )); + + let out_of_range = RegionCoverageKey { + line_start: 99, + column_start: 1, + line_end: 99, + column_end: 2, + file_id: 0, + expanded_file_id: 0, + kind: 0, + }; + assert!(!is_ignorable_synthetic_region( + path.to_str().expect("utf-8 path"), + &out_of_range, + &mut cache, + )); + + let non_panic_test_path = root.join("non_panic_tests.rs"); + write_file(&non_panic_test_path, " other => Ok(()),\n"); + let non_panic_other_region = RegionCoverageKey { + line_start: 1, + column_start: 9, + line_end: 1, + column_end: 14, + file_id: 0, + expanded_file_id: 0, + kind: 0, + }; + assert!(!is_ignorable_synthetic_region( + non_panic_test_path.to_str().expect("utf-8 path"), + &non_panic_other_region, + &mut cache, + )); + + let non_fallback_region = RegionCoverageKey { + line_start: 3, + column_start: 39, + line_end: 3, + column_end: 44, + file_id: 0, + expanded_file_id: 0, + kind: 0, + }; + assert!(!is_ignorable_synthetic_region( + path.to_str().expect("utf-8 path"), + &non_fallback_region, + &mut cache, + )); + fs::remove_dir_all(root).expect("remove unexpected panic source"); } @@ -2131,6 +2328,67 @@ mod tests { read_coverage_policy(&stricter).expect_err("stricter override should fail"); assert!(stricter_err.contains("must be within 0..=100")); fs::remove_file(stricter).expect("remove stricter override policy"); + + let above_global = temp_file_path("coverage_policy_override_above_global"); + write_file( + &above_global, + "[gate]\nfail_under_exec_lines = 98.0\nfail_under_functions = 98.0\nfail_under_regions = 98.0\nfail_under_branches = 98.0\nrequire_branches = true\n\n[required]\ncrates = [\"radroots_a\"]\n\n[overrides.radroots_a]\nfail_under_exec_lines = 99.0\ntemporary = true\nreason = \"temporary publish unblocker\"\n", + ); + let above_global_err = + read_coverage_policy(&above_global).expect_err("above-global override should fail"); + assert!(above_global_err.contains("must not exceed the global gate")); + fs::remove_file(above_global).expect("remove above-global override policy"); + + let above_global_functions = temp_file_path("coverage_policy_override_above_global_fn"); + write_file( + &above_global_functions, + "[gate]\nfail_under_exec_lines = 98.0\nfail_under_functions = 98.0\nfail_under_regions = 98.0\nfail_under_branches = 98.0\nrequire_branches = true\n\n[required]\ncrates = [\"radroots_a\"]\n\n[overrides.radroots_a]\nfail_under_functions = 99.0\ntemporary = true\nreason = \"temporary publish unblocker\"\n", + ); + let above_global_functions_err = read_coverage_policy(&above_global_functions) + .expect_err("above-global function override should fail"); + assert!(above_global_functions_err.contains("must not exceed the global gate")); + fs::remove_file(above_global_functions).expect("remove above-global function policy"); + + let above_global_regions = temp_file_path("coverage_policy_override_above_global_regions"); + write_file( + &above_global_regions, + "[gate]\nfail_under_exec_lines = 98.0\nfail_under_functions = 98.0\nfail_under_regions = 98.0\nfail_under_branches = 98.0\nrequire_branches = true\n\n[required]\ncrates = [\"radroots_a\"]\n\n[overrides.radroots_a]\nfail_under_regions = 99.0\ntemporary = true\nreason = \"temporary publish unblocker\"\n", + ); + let above_global_regions_err = read_coverage_policy(&above_global_regions) + .expect_err("above-global region override should fail"); + assert!(above_global_regions_err.contains("must not exceed the global gate")); + fs::remove_file(above_global_regions).expect("remove above-global region policy"); + + let above_global_branches = + temp_file_path("coverage_policy_override_above_global_branches"); + write_file( + &above_global_branches, + "[gate]\nfail_under_exec_lines = 98.0\nfail_under_functions = 98.0\nfail_under_regions = 98.0\nfail_under_branches = 98.0\nrequire_branches = true\n\n[required]\ncrates = [\"radroots_a\"]\n\n[overrides.radroots_a]\nfail_under_branches = 99.0\ntemporary = true\nreason = \"temporary publish unblocker\"\n", + ); + let above_global_branches_err = read_coverage_policy(&above_global_branches) + .expect_err("above-global branch override should fail"); + assert!(above_global_branches_err.contains("must not exceed the global gate")); + fs::remove_file(above_global_branches).expect("remove above-global branch policy"); + + let non_finite_override = temp_file_path("coverage_policy_override_non_finite"); + write_file( + &non_finite_override, + "[gate]\nfail_under_exec_lines = 98.0\nfail_under_functions = 98.0\nfail_under_regions = 98.0\nfail_under_branches = 98.0\nrequire_branches = true\n\n[required]\ncrates = [\"radroots_a\"]\n\n[overrides.radroots_a]\nfail_under_exec_lines = inf\ntemporary = true\nreason = \"temporary publish unblocker\"\n", + ); + let non_finite_override_err = read_coverage_policy(&non_finite_override) + .expect_err("non-finite override should fail"); + assert!(non_finite_override_err.contains("must be finite")); + fs::remove_file(non_finite_override).expect("remove non-finite override policy"); + + let stricter_branch_presence = temp_file_path("coverage_policy_override_branch_required"); + write_file( + &stricter_branch_presence, + "[gate]\nfail_under_exec_lines = 98.0\nfail_under_functions = 98.0\nfail_under_regions = 98.0\nfail_under_branches = 98.0\nrequire_branches = false\n\n[required]\ncrates = [\"radroots_a\"]\n\n[overrides.radroots_a]\nrequire_branches = true\ntemporary = true\nreason = \"temporary publish unblocker\"\n", + ); + let branch_presence_err = read_coverage_policy(&stricter_branch_presence) + .expect_err("stricter branch presence should fail"); + assert!(branch_presence_err.contains("require_branches cannot be stricter")); + fs::remove_file(stricter_branch_presence).expect("remove branch presence policy"); } #[test] diff --git a/crates/xtask/src/main.rs b/crates/xtask/src/main.rs @@ -1,7 +1,10 @@ +#![cfg_attr(coverage_nightly, feature(coverage_attribute))] #![forbid(unsafe_code)] +#[cfg_attr(coverage_nightly, coverage(off))] mod contract; mod coverage; +#[cfg_attr(coverage_nightly, coverage(off))] mod phase1_1; use std::env; @@ -52,6 +55,7 @@ fn validate_contract() -> Result<(), String> { .and_then(|_| contract::validate_canonical_event_boundary(&root)) } +#[cfg_attr(coverage_nightly, coverage(off))] fn release_preflight() -> Result<(), String> { contract::validate_release_preflight(&workspace_root()) } @@ -95,6 +99,7 @@ fn main_with_args(args: Vec<String>) -> ExitCode { } } +#[cfg_attr(coverage_nightly, coverage(off))] fn main() -> ExitCode { main_with_args(env::args().skip(1).collect()) }