rust_diff_analyzer/output/
json.rs1use masterror::AppError;
5use serde::Serialize;
6
7use super::formatter::Formatter;
8use crate::{config::Config, error::OutputError, types::AnalysisResult};
9
10pub struct JsonFormatter;
12
13#[derive(Serialize)]
14struct JsonOutput<'a> {
15 summary: &'a crate::types::Summary,
16 changes: Vec<JsonChange<'a>>,
17}
18
19#[derive(Serialize)]
20struct JsonChange<'a> {
21 file: String,
22 unit: &'a str,
23 kind: &'a str,
24 visibility: &'a str,
25 classification: &'a str,
26 lines_added: usize,
27 lines_removed: usize,
28}
29
30impl Formatter for JsonFormatter {
31 fn format(&self, result: &AnalysisResult, config: &Config) -> Result<String, AppError> {
32 let changes: Vec<JsonChange> = if config.output.include_details {
33 result
34 .changes
35 .iter()
36 .map(|c| JsonChange {
37 file: c.file_path.to_string_lossy().to_string(),
38 unit: &c.unit.name,
39 kind: c.unit.kind.as_str(),
40 visibility: c.unit.visibility.as_str(),
41 classification: c.classification.as_str(),
42 lines_added: c.lines_added,
43 lines_removed: c.lines_removed,
44 })
45 .collect()
46 } else {
47 vec![]
48 };
49
50 let output = JsonOutput {
51 summary: &result.summary,
52 changes,
53 };
54
55 serde_json::to_string_pretty(&output).map_err(|e| {
56 AppError::from(OutputError {
57 format: "json".to_string(),
58 message: e.to_string(),
59 })
60 })
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use crate::types::{AnalysisScope, Summary};
68
69 #[test]
70 fn test_json_format() {
71 let result = AnalysisResult::new(
72 vec![],
73 Summary {
74 prod_functions: 3,
75 prod_structs: 1,
76 prod_other: 0,
77 test_units: 5,
78 prod_lines_added: 30,
79 prod_lines_removed: 10,
80 test_lines_added: 50,
81 test_lines_removed: 20,
82 weighted_score: 15,
83 exceeds_limit: false,
84 },
85 AnalysisScope::new(),
86 );
87
88 let config = Config::default();
89 let output = JsonFormatter
90 .format(&result, &config)
91 .expect("format should succeed");
92
93 assert!(output.contains("\"prod_functions\": 3"));
94 assert!(output.contains("\"weighted_score\": 15"));
95 }
96}