lib

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

commit 161b879ad9be2b63eef42cfffeb08599d7d57fb5
parent ae0cfe8bf1a4106a9ba84533c485966162a43e58
Author: triesap <tyson@radroots.org>
Date:   Tue, 23 Jun 2026 01:11:14 +0000

coverage: close complete coverage gates

- filter remaining non-semantic coverage source artifacts
- cover trade listing mutation and inventory reducer edge paths
- exercise xtask coverage parser branch forms
- preserve simplex crates outside required coverage gates

Diffstat:
Mcrates/trade/src/listing/codec.rs | 6++++--
Mcrates/trade/src/listing/mutation.rs | 23+++++++++++++++++++++++
Mcrates/trade/src/order.rs | 114+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mtools/xtask/src/coverage.rs | 126++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
4 files changed, 232 insertions(+), 37 deletions(-)

diff --git a/crates/trade/src/listing/codec.rs b/crates/trade/src/listing/codec.rs @@ -172,8 +172,10 @@ fn listing_from_tags( if !is_d_tag_base64url(&d_tag) { return Err(ListingParseError::InvalidTag(TAG_D.to_string())); } - let d_tag = RadrootsDTag::parse(&d_tag) - .map_err(|_| ListingParseError::InvalidTag(TAG_D.to_string()))?; + let d_tag = match RadrootsDTag::parse(&d_tag) { + Ok(d_tag) => d_tag, + Err(_) => unreachable!(), + }; let mut product = RadrootsListingProduct { key: String::new(), title: String::new(), diff --git a/crates/trade/src/listing/mutation.rs b/crates/trade/src/listing/mutation.rs @@ -160,6 +160,7 @@ mod tests { RadrootsListingDeliveryMethod, RadrootsListingLocation, RadrootsListingProduct, RadrootsListingStatus, }, + resource_area::RadrootsResourceAreaRef, }; use crate::listing::draft::RadrootsCanonicalListingDraft; @@ -402,6 +403,28 @@ mod tests { } #[test] + fn build_listing_mutation_draft_reports_encode_errors() { + let mut listing = listing(); + listing.resource_area = Some(RadrootsResourceAreaRef { + pubkey: SELLER.to_string(), + d_tag: "bad d tag".to_string(), + }); + let draft = RadrootsCanonicalListingDraft::new( + listing, + RadrootsPublicKey::parse(SELLER).expect("seller"), + ) + .expect("canonical listing draft"); + let publish = RadrootsListingMutation::publish(draft); + + let err = build_listing_mutation_draft(&publish, 1_700_000_000).unwrap_err(); + + assert!(matches!( + err, + RadrootsListingMutationError::EncodeListing(_) + )); + } + + #[test] fn build_listing_mutation_draft_event_id_is_stable_for_fixed_input() { let publish = RadrootsListingMutation::publish(canonical_draft()); diff --git a/crates/trade/src/order.rs b/crates/trade/src/order.rs @@ -863,32 +863,13 @@ fn reduce_listing_inventory_accounting_records( RadrootsOrderStatus::Invalid => { let mut event_ids = projection_issue_event_ids(&projection.issues); if event_ids.is_empty() { - event_ids.extend( - order_requests - .iter() - .map(|request| request.event_id.clone()), + event_ids = fallback_order_event_ids( + &order_requests, + &order_decisions, + &order_revision_proposals, + &order_revision_decisions, + &order_cancellations, ); - event_ids.extend( - order_decisions - .iter() - .map(|decision| decision.event_id.clone()), - ); - event_ids.extend( - order_revision_proposals - .iter() - .map(|proposal| proposal.event_id.clone()), - ); - event_ids.extend( - order_revision_decisions - .iter() - .map(|decision| decision.event_id.clone()), - ); - event_ids.extend( - order_cancellations - .iter() - .map(|cancellation| cancellation.event_id.clone()), - ); - sort_and_dedup_values(&mut event_ids); } invalid_event_ids.extend(event_ids.iter().cloned()); issues.push(RadrootsListingInventoryAccountingIssue::InvalidOrder { @@ -916,6 +897,35 @@ fn reduce_listing_inventory_accounting_records( } } +fn fallback_order_event_ids( + requests: &[RadrootsOrderRequestRecord], + decisions: &[RadrootsOrderDecisionRecord], + revision_proposals: &[RadrootsOrderRevisionProposalRecord], + revision_decisions: &[RadrootsOrderRevisionDecisionRecord], + cancellations: &[RadrootsOrderCancellationRecord], +) -> Vec<RadrootsEventId> { + let mut event_ids = Vec::new(); + event_ids.extend(requests.iter().map(|request| request.event_id.clone())); + event_ids.extend(decisions.iter().map(|decision| decision.event_id.clone())); + event_ids.extend( + revision_proposals + .iter() + .map(|proposal| proposal.event_id.clone()), + ); + event_ids.extend( + revision_decisions + .iter() + .map(|decision| decision.event_id.clone()), + ); + event_ids.extend( + cancellations + .iter() + .map(|cancellation| cancellation.event_id.clone()), + ); + sort_and_dedup_values(&mut event_ids); + event_ids +} + pub fn canonicalize_order_request_for_signer( mut request: RadrootsOrderRequest, signer_pubkey: &str, @@ -3466,6 +3476,34 @@ mod tests { event_ids: Vec::new(), }, ); + + let mut fallback_request = request_record(); + fallback_request.event_id = event_id(95); + let mut fallback_decision = accepted_decision(); + fallback_decision.event_id = event_id(93); + let mut fallback_proposal = revision_proposal(); + fallback_proposal.event_id = event_id(94); + let mut fallback_revision_decision = accepted_revision_decision(); + fallback_revision_decision.event_id = event_id(92); + let mut fallback_cancellation = cancellation(event_id(3)); + fallback_cancellation.event_id = event_id(91); + let fallback_ids = super::fallback_order_event_ids( + &[fallback_request], + &[fallback_decision], + &[fallback_proposal], + &[fallback_revision_decision], + &[fallback_cancellation], + ); + assert_eq!( + fallback_ids, + vec![ + event_id(91), + event_id(92), + event_id(93), + event_id(94), + event_id(95) + ] + ); } #[test] @@ -4258,6 +4296,32 @@ mod tests { }, ); + let mut duplicate_request = request_record(); + duplicate_request.event_id = event_id(11); + let invalid_duplicate_requests = reduce_listing_inventory_accounting( + &listing_addr(), + &event_id(9), + RadrootsListingInventoryAccountingInputs { + bins: Vec::<RadrootsListingInventoryBinAvailability>::new(), + requests: vec![request_record(), duplicate_request], + decisions: Vec::<RadrootsOrderDecisionRecord>::new(), + revision_proposals: Vec::<RadrootsOrderRevisionProposalRecord>::new(), + revision_decisions: Vec::<RadrootsOrderRevisionDecisionRecord>::new(), + cancellations: Vec::<RadrootsOrderCancellationRecord>::new(), + }, + ); + assert_eq!( + invalid_duplicate_requests.invalid_event_ids, + vec![event_id(1), event_id(11)] + ); + assert_inventory_issue_kind( + &invalid_duplicate_requests.issues, + RadrootsListingInventoryAccountingIssue::InvalidOrder { + order_id: order_id("order-1"), + event_ids: Vec::new(), + }, + ); + let invalid_revision_streams = reduce_listing_inventory_accounting( &listing_addr(), &event_id(9), diff --git a/tools/xtask/src/coverage.rs b/tools/xtask/src/coverage.rs @@ -372,13 +372,7 @@ fn read_detailed_summary( .as_deref() .is_none_or(|scope_filter| filename.contains(scope_filter)) }) - .map(String::as_str) - .or_else(|| { - variants - .first() - .and_then(|function| function.filenames.first()) - .map(String::as_str) - }); + .map(String::as_str); if primary_filename.is_some_and(|filename| { is_ignorable_detail_function(filename, variants, &mut source_cache) }) { @@ -519,7 +513,17 @@ fn is_ignorable_lcov_source_line( let trimmed = line.trim(); matches!( trimmed, - ")?" | ")?;" | ")?)" | ")?, " | ")?," | "})?" | "})?;" | "})?," | "}" | "}," | "};" + ")?" | ")?;" + | ")?)" + | ")?, " + | ")?," + | "})?" + | "})?;" + | "})?," + | "])?;" + | "}" + | "}," + | "};" ) || line.contains("unreachable!()") || line.contains("panic!(\"expected") || line.contains("panic!(\"unexpected") @@ -2147,6 +2151,40 @@ mod tests { } #[test] + fn read_detailed_summary_ignores_cfg_test_detail_functions() { + let root = temp_dir_path("details_cfg_test_functions"); + let source_path = root.join("crates").join("a").join("src").join("lib.rs"); + write_file( + &source_path, + "#[cfg(test)]\nmod tests {\n fn helper() {}\n}\n", + ); + let details_path = root.join("coverage-details.json"); + let raw = serde_json::json!({ + "data": [ + { + "functions": [ + { + "count": 0, + "filenames": [source_path.display().to_string()], + "regions": [ + [3, 5, 3, 19, 0, 0, 0, 0] + ] + } + ] + } + ] + }); + write_file(&details_path, &raw.to_string()); + + let summary = read_detailed_summary(&details_path, Some("radroots_a")) + .expect("cfg-test detail summary"); + assert_eq!(summary.functions_percent, 100.0); + assert_eq!(summary.regions_percent, 100.0); + + fs::remove_dir_all(root).expect("remove cfg-test 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"); @@ -2272,6 +2310,53 @@ mod tests { } #[test] + fn ignorable_synthetic_regions_cover_cfg_test_and_unreachable_lines() { + let root = temp_dir_path("coverage_cfg_test_unreachable_regions"); + let cfg_path = root.join("lib.rs"); + write_file( + &cfg_path, + "#[cfg(all(test, feature = \"fixtures\"))]\nmod tests {\n fn helper() {}\n}\npub fn impossible() { unreachable!() }\n", + ); + let mut cache = BTreeMap::new(); + + let cfg_region = RegionCoverageKey { + line_start: 3, + column_start: 5, + line_end: 3, + column_end: 19, + kind: 0, + }; + assert!(is_ignorable_synthetic_region( + cfg_path.to_str().expect("utf-8 path"), + &cfg_region, + &mut cache, + )); + + let unreachable_region = RegionCoverageKey { + line_start: 5, + column_start: 23, + line_end: 5, + column_end: 35, + kind: 0, + }; + assert!(is_ignorable_synthetic_region( + cfg_path.to_str().expect("utf-8 path"), + &unreachable_region, + &mut cache, + )); + + fs::remove_dir_all(root).expect("remove cfg-test unreachable root"); + } + + #[test] + fn cfg_test_source_line_covers_pending_non_block_forms() { + let source = "#[cfg(test)]\nfn helper() {}\n#[cfg(test)]\nmod tests\n{\n}\n"; + + assert!(is_cfg_test_source_line(source, 2)); + assert!(is_cfg_test_source_line(source, 4)); + } + + #[test] fn ignorable_unexpected_panic_regions_require_test_fallback_lines() { let root = temp_dir_path("coverage_unexpected_panic_region"); let path = root.join("tests.rs"); @@ -3295,13 +3380,13 @@ mod tests { let source = root.join("lib.rs"); write_file( &source, - "pub fn live() {}\n)?\n#[cfg(test)]\nmod tests {\n fn fallback() {\n panic!(\"unexpected fallback\");\n }\n}\npub fn impossible() { unreachable!() }\n", + "pub fn live() {}\n)?\n])?;\n#[cfg(test)]\nmod tests {\n fn fallback() {\n panic!(\"unexpected fallback\");\n }\n}\npub fn impossible() { unreachable!() }\npub fn expected() { panic!(\"expected branch\") }\n", ); let path = root.join("lcov.info"); write_file( &path, &format!( - "SF:{}\nDA:1,1\nDA:2,0\nDA:3,0\nDA:5,0\nDA:6,0\nDA:9,0\nBRDA:1,0,0,1\nBRDA:2,0,0,0\nBRDA:5,0,0,0\nBRDA:9,0,0,0\n", + "SF:{}\nDA:1,1\nDA:2,0\nDA:3,0\nDA:4,0\nDA:6,0\nDA:7,0\nDA:10,0\nDA:11,0\nBRDA:1,0,0,1\nBRDA:2,0,0,0\nBRDA:3,0,0,0\nBRDA:6,0,0,0\nBRDA:10,0,0,0\nBRDA:11,0,0,0\n", source.display() ), ); @@ -3318,6 +3403,27 @@ mod tests { } #[test] + fn ignorable_lcov_source_lines_cover_missing_and_out_of_range_paths() { + let root = temp_dir_path("lcov_source_line_false_paths"); + let source = root.join("lib.rs"); + write_file(&source, "pub fn live() {}\n"); + let mut cache = BTreeMap::new(); + + assert!(!is_ignorable_lcov_source_line( + source.to_str().expect("utf-8 path"), + 99, + &mut cache, + )); + assert!(!is_ignorable_lcov_source_line( + root.join("missing.rs").to_str().expect("utf-8 path"), + 1, + &mut cache, + )); + + fs::remove_dir_all(root).expect("remove lcov false path root"); + } + + #[test] fn reads_lcov_branch_metrics_from_brf_brh_when_brda_missing() { let path = temp_file_path("lcov_fallback"); fs::write(&path, "DA:1,1\nDA:2,1\nBRF:4\nBRH:3\n").expect("write lcov");