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 }
140 }
141
142 #[test]
143 fn test_formatter_format_terminal() {
144 let formatter = OutputFormatter::new(OutputFormat::Terminal);
145 let result = create_test_result();
146 let output = formatter.format(&result);
147 assert!(
148 output.contains("Pass")
149 || output.contains("pass")
150 || output.contains("PASS")
151 || output.contains("No findings")
152 || !output.is_empty()
153 );
154 }
155
156 #[test]
157 fn test_formatter_format_json() {
158 let formatter = OutputFormatter::new(OutputFormat::Json);
159 let result = create_test_result();
160 let output = formatter.format(&result);
161 assert!(output.starts_with('{'));
162 assert!(output.ends_with('}'));
163 }
164
165 #[test]
166 fn test_formatter_format_sarif() {
167 let formatter = OutputFormatter::new(OutputFormat::Sarif);
168 let result = create_test_result();
169 let output = formatter.format(&result);
170 assert!(output.contains("sarif") || output.contains("$schema"));
171 }
172
173 #[test]
174 fn test_formatter_format_html() {
175 let formatter = OutputFormatter::new(OutputFormat::Html);
176 let result = create_test_result();
177 let output = formatter.format(&result);
178 assert!(output.contains("<html>") || output.contains("<!DOCTYPE"));
179 }
180
181 #[test]
182 fn test_formatter_format_markdown() {
183 let formatter = OutputFormatter::new(OutputFormat::Markdown);
184 let result = create_test_result();
185 let output = formatter.format(&result);
186 assert!(output.contains('#') || output.contains("##"));
187 }
188}