commitlint_rs/rule/
footers_empty.rs

1use crate::{message::Message, result::Violation, rule::Rule};
2use serde::{Deserialize, Serialize};
3
4use super::Level;
5
6/// FootersEmpty represents the footer-empty rule.
7#[derive(Clone, Debug, Deserialize, Serialize)]
8#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
9pub struct FootersEmpty {
10    /// Level represents the level of the rule.
11    ///
12    // Note that currently the default literal is not supported.
13    // See: https://github.com/serde-rs/serde/issues/368
14    level: Option<Level>,
15}
16
17/// FooterEmpty represents the footer-empty rule.
18impl Rule for FootersEmpty {
19    const NAME: &'static str = "footers-empty";
20    const LEVEL: Level = Level::Error;
21
22    fn message(&self, _message: &Message) -> String {
23        "footers are empty".to_string()
24    }
25
26    fn validate(&self, message: &Message) -> Option<Violation> {
27        if message.footers.is_none() {
28            return Some(Violation {
29                level: self.level.unwrap_or(Self::LEVEL),
30                message: self.message(message),
31            });
32        }
33
34        None
35    }
36}
37
38/// Default implementation of FooterEmpty.
39impl Default for FootersEmpty {
40    fn default() -> Self {
41        Self {
42            level: Some(Self::LEVEL),
43        }
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use std::collections::HashMap;
50
51    use super::*;
52
53    #[test]
54    fn test_non_empty_footer() {
55        let rule = FootersEmpty::default();
56
57        let mut f = HashMap::new();
58        f.insert("Link".to_string(), "hello".to_string());
59
60        let message = Message {
61            body: Some("Hello world".to_string()),
62            description: Some("broadcast $destroy event on scope destruction".to_string()),
63            footers: Some(f),
64            r#type: Some("feat".to_string()),
65            raw: "feat(scope): broadcast $destroy event on scope destruction
66
67Hello world
68
69Link: hello"
70                .to_string(),
71            scope: Some("scope".to_string()),
72            subject: Some("feat(scope): broadcast $destroy event on scope destruction".to_string()),
73        };
74
75        assert!(rule.validate(&message).is_none());
76    }
77
78    #[test]
79    fn test_empty_footer() {
80        let rule = FootersEmpty::default();
81        let message = Message {
82            body: None,
83            description: None,
84            footers: None,
85            r#type: Some("feat".to_string()),
86            raw: "feat(scope): broadcast $destroy event on scope destruction".to_string(),
87            scope: Some("scope".to_string()),
88            subject: None,
89        };
90
91        let violation = rule.validate(&message);
92        assert!(violation.is_some());
93        assert_eq!(violation.clone().unwrap().level, Level::Error);
94        assert_eq!(violation.unwrap().message, "footers are empty".to_string());
95    }
96}