#[test]
fn test_evidence_summary_handles_missing_value_in_complexity() {
let mut why = create_test_why_iteration(1, 0.5);
why.add_evidence(Evidence::new(
EvidenceSource::Complexity,
PathBuf::from("test.rs"),
"complexity".to_string(),
serde_json::json!({"threshold": 20}), "Unknown".to_string(),
));
let summary = EvidenceSummary::from_whys(&[why]);
assert_eq!(summary.complexity_violations, 0); }
#[test]
fn test_evidence_summary_handles_missing_threshold_in_complexity() {
let mut why = create_test_why_iteration(1, 0.5);
why.add_evidence(Evidence::new(
EvidenceSource::Complexity,
PathBuf::from("test.rs"),
"complexity".to_string(),
serde_json::json!({"value": 25}), "High".to_string(),
));
let summary = EvidenceSummary::from_whys(&[why]);
assert_eq!(summary.complexity_violations, 1);
}
#[test]
fn test_evidence_summary_handles_non_numeric_tdg() {
let mut why = create_test_why_iteration(1, 0.5);
why.add_evidence(Evidence::new(
EvidenceSource::TDG,
PathBuf::from("test.rs"),
"tdg".to_string(),
serde_json::json!("not a number"),
"Invalid".to_string(),
));
let summary = EvidenceSummary::from_whys(&[why]);
assert_eq!(summary.tdg_score, 0.0); }
#[test]
fn test_why_iteration_with_many_evidence_items() {
let mut why = create_test_why_iteration(1, 0.5);
for _ in 0..100 {
why.add_evidence(create_test_evidence(EvidenceSource::SATD));
}
assert_eq!(why.evidence.len(), 100);
}
#[test]
fn test_debug_analysis_with_many_whys() {
let mut analysis = create_test_debug_analysis();
for depth in 1..=10 {
analysis
.whys
.push(create_test_why_iteration(depth, depth as f64 / 10.0));
}
assert_eq!(analysis.whys.len(), 10);
assert_eq!(analysis.whys[9].depth, 10);
}
#[test]
fn test_evidence_with_very_long_strings() {
let long_metric = "a".repeat(10000);
let long_interpretation = "b".repeat(10000);
let evidence = Evidence::new(
EvidenceSource::ManualInspection,
PathBuf::from("test.rs"),
long_metric.clone(),
serde_json::json!(null),
long_interpretation.clone(),
);
assert_eq!(evidence.metric.len(), 10000);
assert_eq!(evidence.interpretation.len(), 10000);
}
#[test]
fn test_recommendation_with_very_long_action() {
let long_action = "x".repeat(10000);
let rec = Recommendation::high(long_action.clone(), None);
assert_eq!(rec.action.len(), 10000);
}
proptest! {
#[test]
fn prop_confidence_always_clamped(confidence in -100.0f64..100.0) {
let why = WhyIteration::new(
1,
"Why?".to_string(),
"Hypothesis".to_string(),
).with_confidence(confidence);
prop_assert!(why.confidence >= 0.0);
prop_assert!(why.confidence <= 1.0);
}
#[test]
fn prop_depth_preserved(depth in 1u8..=10) {
let why = WhyIteration::new(
depth,
"Question".to_string(),
"Hypothesis".to_string(),
);
prop_assert_eq!(why.depth, depth);
}
#[test]
fn prop_evidence_count_preserved(count in 0usize..50) {
let mut why = WhyIteration::new(1, "Q".to_string(), "H".to_string());
for _ in 0..count {
why.add_evidence(Evidence::new(
EvidenceSource::ManualInspection,
PathBuf::from("test.rs"),
"metric".to_string(),
serde_json::json!(null),
"interpretation".to_string(),
));
}
prop_assert_eq!(why.evidence.len(), count);
}
#[test]
fn prop_serialization_roundtrip_debug_analysis(issue in "\\PC{1,100}") {
let analysis = DebugAnalysis::new(issue.clone());
let json = serde_json::to_string(&analysis)
.expect("Serialization should succeed");
let deserialized: DebugAnalysis = serde_json::from_str(&json)
.expect("Deserialization should succeed");
prop_assert_eq!(deserialized.issue, issue);
}
#[test]
fn prop_satd_count_accumulates(counts in proptest::collection::vec(0u64..100, 1..10)) {
let mut whys = Vec::new();
for (i, count) in counts.iter().enumerate() {
let mut why = create_test_why_iteration((i + 1) as u8, 0.5);
why.add_evidence(Evidence::new(
EvidenceSource::SATD,
PathBuf::from("test.rs"),
"satd".to_string(),
serde_json::json!({"count": count}),
"markers".to_string(),
));
whys.push(why);
}
let summary = EvidenceSummary::from_whys(&whys);
let expected: u64 = counts.iter().sum();
prop_assert_eq!(summary.satd_markers, expected as usize);
}
#[test]
fn prop_complexity_violations_count_correctly(
values in proptest::collection::vec(0.0f64..100.0, 1..20)
) {
let mut why = create_test_why_iteration(1, 0.5);
for (i, value) in values.iter().enumerate() {
why.add_evidence(Evidence::new(
EvidenceSource::Complexity,
PathBuf::from(format!("file{}.rs", i)),
"complexity".to_string(),
serde_json::json!({"value": value, "threshold": 20.0}),
"metrics".to_string(),
));
}
let summary = EvidenceSummary::from_whys(&[why]);
let expected = values.iter().filter(|&&v| v > 20.0).count();
prop_assert_eq!(summary.complexity_violations, expected);
}
#[test]
fn prop_git_churn_threshold_at_10(commit_count in 0u64..100) {
let mut why = create_test_why_iteration(1, 0.5);
why.add_evidence(Evidence::new(
EvidenceSource::GitChurn,
PathBuf::from("test.rs"),
"churn".to_string(),
serde_json::json!({"commit_count": commit_count}),
"churn".to_string(),
));
let summary = EvidenceSummary::from_whys(&[why]);
prop_assert_eq!(summary.git_churn_high, commit_count > 10);
}
#[test]
fn prop_priority_serialization_stable(priority in prop::sample::select(vec![
Priority::High,
Priority::Medium,
Priority::Low,
])) {
let json = serde_json::to_string(&priority).unwrap();
let roundtrip: Priority = serde_json::from_str(&json).expect("serde roundtrip");
prop_assert_eq!(roundtrip, priority);
}
}
#[test]
fn test_complete_analysis_workflow() {
let mut analysis = DebugAnalysis::new("Memory leak in parser".to_string());
let mut why1 = WhyIteration::new(
1,
"Why is there a memory leak?".to_string(),
"Buffer not freed after use".to_string(),
)
.with_confidence(0.6);
why1.add_evidence(create_test_evidence(EvidenceSource::Complexity));
analysis.whys.push(why1);
let mut why2 = WhyIteration::new(
2,
"Why is the buffer not freed?".to_string(),
"Early return bypasses cleanup".to_string(),
)
.with_confidence(0.7);
why2.add_evidence(create_test_evidence(EvidenceSource::SATD));
analysis.whys.push(why2);
let mut why3 = WhyIteration::new(
3,
"Why does early return bypass cleanup?".to_string(),
"Missing RAII pattern".to_string(),
)
.with_confidence(0.85);
why3.add_evidence(create_test_evidence(EvidenceSource::TDG));
analysis.whys.push(why3);
analysis.root_cause = Some("Missing RAII pattern for resource management".to_string());
analysis.recommendations.push(Recommendation::high(
"Implement Drop trait for buffer wrapper".to_string(),
Some(PathBuf::from("src/parser/buffer.rs")),
));
analysis.recommendations.push(Recommendation::medium(
"Add unit tests for cleanup paths".to_string(),
Some(PathBuf::from("tests/parser_tests.rs")),
));
analysis.evidence_summary = EvidenceSummary::from_whys(&analysis.whys);
assert_eq!(analysis.issue, "Memory leak in parser");
assert_eq!(analysis.whys.len(), 3);
assert!(analysis.root_cause.is_some());
assert_eq!(analysis.recommendations.len(), 2);
assert!(analysis.evidence_summary.complexity_violations > 0);
assert!(analysis.evidence_summary.satd_markers > 0);
}
#[test]
fn test_all_evidence_sources_in_summary() {
let mut why = create_test_why_iteration(1, 0.5);
why.add_evidence(create_test_evidence(EvidenceSource::Complexity));
why.add_evidence(create_test_evidence(EvidenceSource::SATD));
why.add_evidence(create_test_evidence(EvidenceSource::TDG));
why.add_evidence(create_test_evidence(EvidenceSource::GitChurn));
why.add_evidence(create_test_evidence(EvidenceSource::DeadCode));
why.add_evidence(create_test_evidence(EvidenceSource::ManualInspection));
let summary = EvidenceSummary::from_whys(&[why]);
assert_eq!(summary.complexity_violations, 1);
assert_eq!(summary.satd_markers, 5);
assert!((summary.tdg_score - 40.0).abs() < f64::EPSILON);
assert!(summary.git_churn_high);
}