#![expect(
clippy::float_cmp,
reason = "CC and coverage are deterministic from the fixture; exact equality is the right comparison"
)]
use cargo_crap::complexity;
use cargo_crap::coverage;
use cargo_crap::merge::{MissingCoveragePolicy, merge};
use std::path::PathBuf;
fn fixture_root() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("tests/fixtures/sample_project")
}
#[test]
fn end_to_end_pipeline_produces_ranked_scores() {
let root = fixture_root();
let complexity =
complexity::analyze_tree(&root.join("src"), &[] as &[&str]).expect("analyze_tree");
let names: Vec<_> = complexity.iter().map(|f| f.name.as_str()).collect();
assert!(names.contains(&"trivial"), "trivial fn not found");
assert!(names.contains(&"moderate"), "moderate fn not found");
assert!(names.contains(&"crappy"), "crappy fn not found");
let coverage = coverage::parse_lcov(&root.join("lcov.info")).expect("parse_lcov");
assert!(
!coverage.is_empty(),
"parsed LCOV should have at least one file"
);
let entries = merge(complexity, coverage, MissingCoveragePolicy::Pessimistic).entries;
assert!(!entries.is_empty(), "merge produced no entries");
let by_name: std::collections::HashMap<_, _> =
entries.iter().map(|e| (e.function.as_str(), e)).collect();
let trivial = by_name.get("trivial").expect("trivial in results");
let moderate = by_name.get("moderate").expect("moderate in results");
let crappy = by_name.get("crappy").expect("crappy in results");
assert!(
crappy.crap > moderate.crap,
"crappy ({}) should outrank moderate ({})",
crappy.crap,
moderate.crap
);
assert!(
moderate.crap > trivial.crap,
"moderate ({}) should outrank trivial ({})",
moderate.crap,
trivial.crap
);
assert_eq!(
entries[0].function, "crappy",
"expected 'crappy' at top of ranked list, got {}",
entries[0].function
);
assert_eq!(
trivial.cyclomatic, 1.0,
"trivial should have CC=1, got {}",
trivial.cyclomatic
);
for entry in &entries {
assert!(
entry.coverage.is_some(),
"path matching failed for {} — coverage is None",
entry.function
);
}
}
#[test]
fn json_output_round_trips() {
let root = fixture_root();
let complexity =
complexity::analyze_tree(&root.join("src"), &[] as &[&str]).expect("analyze_tree");
let coverage = coverage::parse_lcov(&root.join("lcov.info")).expect("parse_lcov");
let entries = merge(complexity, coverage, MissingCoveragePolicy::Pessimistic).entries;
let mut buf = Vec::new();
cargo_crap::report::render(
&entries,
30.0,
cargo_crap::report::Format::Json,
None,
&mut buf,
)
.expect("render");
let parsed: serde_json::Value =
serde_json::from_slice(&buf).expect("JSON output must be parseable");
assert!(parsed.is_object(), "JSON output must be an envelope object");
assert!(
parsed["entries"].is_array(),
"envelope must contain an `entries` array"
);
}