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    ///
19    /// CLI aliases: `codeclimate`, `gitlab-codequality`, `gitlab-code-quality`.
20    CodeClimate,
21    /// GitHub-flavored sticky PR comment markdown.
22    PrCommentGithub,
23    /// GitLab-flavored sticky MR comment markdown.
24    PrCommentGitlab,
25    /// GitHub PR review JSON envelope.
26    ReviewGithub,
27    /// GitLab MR review JSON envelope.
28    ReviewGitlab,
29    /// Shields.io-compatible SVG badge (health command only).
30    Badge,
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn output_format_default_is_human() {
39        let format = OutputFormat::default();
40        assert!(matches!(format, OutputFormat::Human));
41    }
42
43    #[test]
44    fn output_format_all_variants_constructible() {
45        // Verify all variants can be constructed and pattern-matched
46        assert!(matches!(OutputFormat::Human, OutputFormat::Human));
47        assert!(matches!(OutputFormat::Json, OutputFormat::Json));
48        assert!(matches!(OutputFormat::Sarif, OutputFormat::Sarif));
49        assert!(matches!(OutputFormat::Compact, OutputFormat::Compact));
50        assert!(matches!(OutputFormat::Markdown, OutputFormat::Markdown));
51        assert!(matches!(
52            OutputFormat::CodeClimate,
53            OutputFormat::CodeClimate
54        ));
55        assert!(matches!(
56            OutputFormat::PrCommentGithub,
57            OutputFormat::PrCommentGithub
58        ));
59        assert!(matches!(
60            OutputFormat::PrCommentGitlab,
61            OutputFormat::PrCommentGitlab
62        ));
63        assert!(matches!(
64            OutputFormat::ReviewGithub,
65            OutputFormat::ReviewGithub
66        ));
67        assert!(matches!(
68            OutputFormat::ReviewGitlab,
69            OutputFormat::ReviewGitlab
70        ));
71        assert!(matches!(OutputFormat::Badge, OutputFormat::Badge));
72    }
73
74    #[test]
75    fn output_format_debug_impl() {
76        // Verify Debug is derived and produces reasonable output
77        let human = format!("{:?}", OutputFormat::Human);
78        assert_eq!(human, "Human");
79        let json = format!("{:?}", OutputFormat::Json);
80        assert_eq!(json, "Json");
81        let sarif = format!("{:?}", OutputFormat::Sarif);
82        assert_eq!(sarif, "Sarif");
83        let compact = format!("{:?}", OutputFormat::Compact);
84        assert_eq!(compact, "Compact");
85        let markdown = format!("{:?}", OutputFormat::Markdown);
86        assert_eq!(markdown, "Markdown");
87        let codeclimate = format!("{:?}", OutputFormat::CodeClimate);
88        assert_eq!(codeclimate, "CodeClimate");
89        let pr_comment_github = format!("{:?}", OutputFormat::PrCommentGithub);
90        assert_eq!(pr_comment_github, "PrCommentGithub");
91        let pr_comment_gitlab = format!("{:?}", OutputFormat::PrCommentGitlab);
92        assert_eq!(pr_comment_gitlab, "PrCommentGitlab");
93        let review_github = format!("{:?}", OutputFormat::ReviewGithub);
94        assert_eq!(review_github, "ReviewGithub");
95        let review_gitlab = format!("{:?}", OutputFormat::ReviewGitlab);
96        assert_eq!(review_gitlab, "ReviewGitlab");
97        let badge = format!("{:?}", OutputFormat::Badge);
98        assert_eq!(badge, "Badge");
99    }
100
101    #[test]
102    fn output_format_copy() {
103        let original = OutputFormat::Json;
104        let copied = original;
105        assert!(matches!(copied, OutputFormat::Json));
106        // Original still usable (Copy)
107        assert!(matches!(original, OutputFormat::Json));
108    }
109
110    #[test]
111    #[expect(
112        clippy::clone_on_copy,
113        reason = "explicitly testing the Clone impl for coverage"
114    )]
115    fn output_format_clone_all_variants() {
116        let variants = [
117            OutputFormat::Human,
118            OutputFormat::Json,
119            OutputFormat::Sarif,
120            OutputFormat::Compact,
121            OutputFormat::Markdown,
122            OutputFormat::CodeClimate,
123            OutputFormat::PrCommentGithub,
124            OutputFormat::PrCommentGitlab,
125            OutputFormat::ReviewGithub,
126            OutputFormat::ReviewGitlab,
127            OutputFormat::Badge,
128        ];
129        for variant in variants {
130            let cloned = variant.clone();
131            // Debug output must match between original and clone
132            assert_eq!(format!("{cloned:?}"), format!("{variant:?}"));
133        }
134    }
135
136    #[test]
137    #[expect(
138        clippy::clone_on_copy,
139        reason = "explicitly testing the Clone impl for coverage"
140    )]
141    fn output_format_clone_preserves_variant() {
142        let badge = OutputFormat::Badge;
143        let cloned = badge.clone();
144        assert!(matches!(cloned, OutputFormat::Badge));
145
146        let codeclimate = OutputFormat::CodeClimate;
147        let cloned = codeclimate.clone();
148        assert!(matches!(cloned, OutputFormat::CodeClimate));
149    }
150
151    #[test]
152    fn output_format_default_matches_human_debug() {
153        // Default variant should produce "Human" debug string
154        assert_eq!(format!("{:?}", OutputFormat::default()), "Human");
155    }
156
157    #[test]
158    fn output_format_variants_are_distinct() {
159        // Verify each variant has a unique debug representation
160        let debug_strings: Vec<String> = [
161            OutputFormat::Human,
162            OutputFormat::Json,
163            OutputFormat::Sarif,
164            OutputFormat::Compact,
165            OutputFormat::Markdown,
166            OutputFormat::CodeClimate,
167            OutputFormat::PrCommentGithub,
168            OutputFormat::PrCommentGitlab,
169            OutputFormat::ReviewGithub,
170            OutputFormat::ReviewGitlab,
171            OutputFormat::Badge,
172        ]
173        .iter()
174        .map(|v| format!("{v:?}"))
175        .collect();
176
177        for (i, a) in debug_strings.iter().enumerate() {
178            for (j, b) in debug_strings.iter().enumerate() {
179                if i != j {
180                    assert_ne!(
181                        a, b,
182                        "variants at index {i} and {j} have the same debug output"
183                    );
184                }
185            }
186        }
187    }
188}