Skip to main content

fallow_config/config/
format.rs

1/// Output format for results.
2///
3/// This is CLI-only (via `--format` flag), not stored in config files.
4#[derive(Debug, Default, Clone, Copy)]
5pub enum OutputFormat {
6    /// Human-readable terminal output with source context.
7    #[default]
8    Human,
9    /// Machine-readable JSON.
10    Json,
11    /// SARIF format for GitHub Code Scanning.
12    Sarif,
13    /// One issue per line (grep-friendly).
14    Compact,
15    /// Markdown for PR comments.
16    Markdown,
17    /// `CodeClimate` JSON for GitLab Code Quality.
18    CodeClimate,
19    /// Shields.io-compatible SVG badge (health command only).
20    Badge,
21}
22
23#[cfg(test)]
24mod tests {
25    use super::*;
26
27    #[test]
28    fn output_format_default_is_human() {
29        let format = OutputFormat::default();
30        assert!(matches!(format, OutputFormat::Human));
31    }
32
33    #[test]
34    fn output_format_all_variants_constructible() {
35        // Verify all variants can be constructed and pattern-matched
36        assert!(matches!(OutputFormat::Human, OutputFormat::Human));
37        assert!(matches!(OutputFormat::Json, OutputFormat::Json));
38        assert!(matches!(OutputFormat::Sarif, OutputFormat::Sarif));
39        assert!(matches!(OutputFormat::Compact, OutputFormat::Compact));
40        assert!(matches!(OutputFormat::Markdown, OutputFormat::Markdown));
41        assert!(matches!(
42            OutputFormat::CodeClimate,
43            OutputFormat::CodeClimate
44        ));
45        assert!(matches!(OutputFormat::Badge, OutputFormat::Badge));
46    }
47
48    #[test]
49    fn output_format_debug_impl() {
50        // Verify Debug is derived and produces reasonable output
51        let human = format!("{:?}", OutputFormat::Human);
52        assert_eq!(human, "Human");
53        let json = format!("{:?}", OutputFormat::Json);
54        assert_eq!(json, "Json");
55        let sarif = format!("{:?}", OutputFormat::Sarif);
56        assert_eq!(sarif, "Sarif");
57        let compact = format!("{:?}", OutputFormat::Compact);
58        assert_eq!(compact, "Compact");
59        let markdown = format!("{:?}", OutputFormat::Markdown);
60        assert_eq!(markdown, "Markdown");
61        let codeclimate = format!("{:?}", OutputFormat::CodeClimate);
62        assert_eq!(codeclimate, "CodeClimate");
63        let badge = format!("{:?}", OutputFormat::Badge);
64        assert_eq!(badge, "Badge");
65    }
66
67    #[test]
68    fn output_format_copy() {
69        let original = OutputFormat::Json;
70        let copied = original;
71        assert!(matches!(copied, OutputFormat::Json));
72        // Original still usable (Copy)
73        assert!(matches!(original, OutputFormat::Json));
74    }
75
76    #[test]
77    #[expect(
78        clippy::clone_on_copy,
79        reason = "explicitly testing the Clone impl for coverage"
80    )]
81    fn output_format_clone_all_variants() {
82        let variants = [
83            OutputFormat::Human,
84            OutputFormat::Json,
85            OutputFormat::Sarif,
86            OutputFormat::Compact,
87            OutputFormat::Markdown,
88            OutputFormat::CodeClimate,
89            OutputFormat::Badge,
90        ];
91        for variant in variants {
92            let cloned = variant.clone();
93            // Debug output must match between original and clone
94            assert_eq!(format!("{cloned:?}"), format!("{variant:?}"));
95        }
96    }
97
98    #[test]
99    #[expect(
100        clippy::clone_on_copy,
101        reason = "explicitly testing the Clone impl for coverage"
102    )]
103    fn output_format_clone_preserves_variant() {
104        let badge = OutputFormat::Badge;
105        let cloned = badge.clone();
106        assert!(matches!(cloned, OutputFormat::Badge));
107
108        let codeclimate = OutputFormat::CodeClimate;
109        let cloned = codeclimate.clone();
110        assert!(matches!(cloned, OutputFormat::CodeClimate));
111    }
112
113    #[test]
114    fn output_format_default_matches_human_debug() {
115        // Default variant should produce "Human" debug string
116        assert_eq!(format!("{:?}", OutputFormat::default()), "Human");
117    }
118
119    #[test]
120    fn output_format_variants_are_distinct() {
121        // Verify each variant has a unique debug representation
122        let debug_strings: Vec<String> = [
123            OutputFormat::Human,
124            OutputFormat::Json,
125            OutputFormat::Sarif,
126            OutputFormat::Compact,
127            OutputFormat::Markdown,
128            OutputFormat::CodeClimate,
129            OutputFormat::Badge,
130        ]
131        .iter()
132        .map(|v| format!("{v:?}"))
133        .collect();
134
135        for (i, a) in debug_strings.iter().enumerate() {
136            for (j, b) in debug_strings.iter().enumerate() {
137                if i != j {
138                    assert_ne!(
139                        a, b,
140                        "variants at index {i} and {j} have the same debug output"
141                    );
142                }
143            }
144        }
145    }
146}