cc_audit/output/
formatter.rs1use crate::cli::OutputFormat;
4use crate::reporter::{
5 Reporter, html::HtmlReporter, json::JsonReporter, markdown::MarkdownReporter,
6 sarif::SarifReporter, terminal::TerminalReporter,
7};
8use crate::rules::ScanResult;
9
10pub struct OutputFormatter {
12 format: OutputFormat,
13 strict: bool,
14 verbose: bool,
15}
16
17impl OutputFormatter {
18 pub fn new(format: OutputFormat) -> Self {
20 Self {
21 format,
22 strict: false,
23 verbose: false,
24 }
25 }
26
27 pub fn with_strict(mut self, strict: bool) -> Self {
29 self.strict = strict;
30 self
31 }
32
33 pub fn with_verbose(mut self, verbose: bool) -> Self {
35 self.verbose = verbose;
36 self
37 }
38
39 pub fn format(&self, result: &ScanResult) -> String {
41 match self.format {
42 OutputFormat::Terminal => {
43 let reporter = TerminalReporter::new(self.strict, self.verbose);
44 reporter.report(result)
45 }
46 OutputFormat::Json => {
47 let reporter = JsonReporter::new();
48 reporter.report(result)
49 }
50 OutputFormat::Sarif => {
51 let reporter = SarifReporter::new();
52 reporter.report(result)
53 }
54 OutputFormat::Html => {
55 let reporter = HtmlReporter::new();
56 reporter.report(result)
57 }
58 OutputFormat::Markdown => {
59 let reporter = MarkdownReporter::new();
60 reporter.report(result)
61 }
62 }
63 }
64
65 pub fn extension(&self) -> &'static str {
67 match self.format {
68 OutputFormat::Terminal => "txt",
69 OutputFormat::Json => "json",
70 OutputFormat::Sarif => "sarif",
71 OutputFormat::Html => "html",
72 OutputFormat::Markdown => "md",
73 }
74 }
75}
76
77impl Default for OutputFormatter {
78 fn default() -> Self {
79 Self::new(OutputFormat::Terminal)
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86
87 #[test]
88 fn test_formatter_extensions() {
89 assert_eq!(
90 OutputFormatter::new(OutputFormat::Terminal).extension(),
91 "txt"
92 );
93 assert_eq!(OutputFormatter::new(OutputFormat::Json).extension(), "json");
94 assert_eq!(
95 OutputFormatter::new(OutputFormat::Sarif).extension(),
96 "sarif"
97 );
98 assert_eq!(OutputFormatter::new(OutputFormat::Html).extension(), "html");
99 assert_eq!(
100 OutputFormatter::new(OutputFormat::Markdown).extension(),
101 "md"
102 );
103 }
104
105 #[test]
106 fn test_formatter_builder() {
107 let formatter = OutputFormatter::new(OutputFormat::Terminal)
108 .with_strict(true)
109 .with_verbose(true);
110
111 assert!(formatter.strict);
112 assert!(formatter.verbose);
113 }
114
115 #[test]
116 fn test_formatter_default() {
117 let formatter = OutputFormatter::default();
118 assert_eq!(formatter.format, OutputFormat::Terminal);
119 assert!(!formatter.strict);
120 assert!(!formatter.verbose);
121 }
122
123 fn create_test_result() -> crate::rules::ScanResult {
124 crate::rules::ScanResult {
125 version: "1.0.0".to_string(),
126 scanned_at: "2024-01-01T00:00:00Z".to_string(),
127 target: "/test".to_string(),
128 summary: crate::rules::Summary {
129 critical: 0,
130 high: 0,
131 medium: 0,
132 low: 0,
133 passed: true,
134 errors: 0,
135 warnings: 0,
136 },
137 findings: Vec::new(),
138 risk_score: None,
139 elapsed_ms: 0,
140 }
141 }
142
143 #[test]
144 fn test_formatter_format_terminal() {
145 let formatter = OutputFormatter::new(OutputFormat::Terminal);
146 let result = create_test_result();
147 let output = formatter.format(&result);
148 assert!(
149 output.contains("Pass")
150 || output.contains("pass")
151 || output.contains("PASS")
152 || output.contains("No findings")
153 || !output.is_empty()
154 );
155 }
156
157 #[test]
158 fn test_formatter_format_json() {
159 let formatter = OutputFormatter::new(OutputFormat::Json);
160 let result = create_test_result();
161 let output = formatter.format(&result);
162 assert!(output.starts_with('{'));
163 assert!(output.ends_with('}'));
164 }
165
166 #[test]
167 fn test_formatter_format_sarif() {
168 let formatter = OutputFormatter::new(OutputFormat::Sarif);
169 let result = create_test_result();
170 let output = formatter.format(&result);
171 assert!(output.contains("sarif") || output.contains("$schema"));
172 }
173
174 #[test]
175 fn test_formatter_format_html() {
176 let formatter = OutputFormatter::new(OutputFormat::Html);
177 let result = create_test_result();
178 let output = formatter.format(&result);
179 assert!(output.contains("<html>") || output.contains("<!DOCTYPE"));
180 }
181
182 #[test]
183 fn test_formatter_format_markdown() {
184 let formatter = OutputFormatter::new(OutputFormat::Markdown);
185 let result = create_test_result();
186 let output = formatter.format(&result);
187 assert!(output.contains('#') || output.contains("##"));
188 }
189}