fallow_cli/health_types/
mod.rs1mod coverage;
8mod scores;
9mod targets;
10mod trends;
11mod vital_signs;
12
13pub use coverage::*;
14pub use scores::*;
15pub use targets::*;
16pub use trends::*;
17pub use vital_signs::*;
18
19#[derive(Debug, serde::Serialize)]
21pub struct HealthReport {
22 pub findings: Vec<HealthFinding>,
24 pub summary: HealthSummary,
26 #[serde(skip_serializing_if = "Option::is_none")]
28 pub vital_signs: Option<VitalSigns>,
29 #[serde(skip_serializing_if = "Option::is_none")]
31 pub health_score: Option<HealthScore>,
32 #[serde(skip_serializing_if = "Vec::is_empty")]
34 pub file_scores: Vec<FileHealthScore>,
35 #[serde(skip_serializing_if = "Option::is_none")]
37 pub coverage_gaps: Option<CoverageGaps>,
38 #[serde(skip_serializing_if = "Vec::is_empty")]
40 pub hotspots: Vec<HotspotEntry>,
41 #[serde(skip_serializing_if = "Option::is_none")]
43 pub hotspot_summary: Option<HotspotSummary>,
44 #[serde(skip_serializing_if = "Vec::is_empty")]
46 pub targets: Vec<RefactoringTarget>,
47 #[serde(skip_serializing_if = "Option::is_none")]
49 pub target_thresholds: Option<TargetThresholds>,
50 #[serde(skip_serializing_if = "Option::is_none")]
52 pub health_trend: Option<HealthTrend>,
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58
59 #[test]
60 fn health_report_skips_empty_collections() {
61 let report = HealthReport {
62 findings: vec![],
63 summary: HealthSummary {
64 files_analyzed: 0,
65 functions_analyzed: 0,
66 functions_above_threshold: 0,
67 max_cyclomatic_threshold: 20,
68 max_cognitive_threshold: 15,
69 files_scored: None,
70 average_maintainability: None,
71 coverage_model: None,
72 istanbul_matched: None,
73 istanbul_total: None,
74 },
75 vital_signs: None,
76 health_score: None,
77 file_scores: vec![],
78 coverage_gaps: None,
79 hotspots: vec![],
80 hotspot_summary: None,
81 targets: vec![],
82 target_thresholds: None,
83 health_trend: None,
84 };
85 let json = serde_json::to_string(&report).unwrap();
86 assert!(!json.contains("file_scores"));
88 assert!(!json.contains("hotspots"));
89 assert!(!json.contains("hotspot_summary"));
90 assert!(!json.contains("targets"));
91 assert!(!json.contains("vital_signs"));
92 assert!(!json.contains("health_score"));
93 }
94
95 #[test]
96 fn health_score_none_skipped_in_report() {
97 let report = HealthReport {
98 findings: vec![],
99 summary: HealthSummary {
100 files_analyzed: 0,
101 functions_analyzed: 0,
102 functions_above_threshold: 0,
103 max_cyclomatic_threshold: 20,
104 max_cognitive_threshold: 15,
105 files_scored: None,
106 average_maintainability: None,
107 coverage_model: None,
108 istanbul_matched: None,
109 istanbul_total: None,
110 },
111 vital_signs: None,
112 health_score: None,
113 file_scores: vec![],
114 coverage_gaps: None,
115 hotspots: vec![],
116 hotspot_summary: None,
117 targets: vec![],
118 target_thresholds: None,
119 health_trend: None,
120 };
121 let json = serde_json::to_string(&report).unwrap();
122 assert!(!json.contains("health_score"));
123 }
124}