commitlint_rs/rule/
body_max_length.rs

1use crate::{message::Message, result::Violation, rule::Rule};
2use serde::{Deserialize, Serialize};
3
4use super::Level;
5
6/// BodyMaxLength represents the body-max-length rule.
7#[derive(Clone, Debug, Deserialize, Serialize)]
8#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
9pub struct BodyMaxLength {
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    /// Length represents the maximum length of the body.
17    length: usize,
18}
19
20/// BodyMaxLength represents the body-max-length rule.
21impl Rule for BodyMaxLength {
22    const NAME: &'static str = "body-max-length";
23    const LEVEL: Level = Level::Error;
24
25    fn message(&self, _message: &Message) -> String {
26        format!("body is longer than {} characters", self.length)
27    }
28
29    fn validate(&self, message: &Message) -> Option<Violation> {
30        match &message.body {
31            Some(body) => {
32                if body.len() >= self.length {
33                    return Some(Violation {
34                        level: self.level.unwrap_or(Self::LEVEL),
35                        message: self.message(message),
36                    });
37                }
38            }
39            None => {
40                return Some(Violation {
41                    level: self.level.unwrap_or(Self::LEVEL),
42                    message: self.message(message),
43                })
44            }
45        }
46
47        None
48    }
49}
50
51/// Default implementation of BodyMaxLength.
52impl Default for BodyMaxLength {
53    fn default() -> Self {
54        Self {
55            level: Some(Self::LEVEL),
56            length: 72,
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_long_body() {
67        let rule = BodyMaxLength {
68            length: usize::MAX, // Long length for testing
69            ..Default::default()
70        };
71        let message = Message {
72            body: Some("Hello world".to_string()),
73            description: Some("broadcast $destroy event on scope destruction".to_string()),
74            footers: None,
75            r#type: Some("feat".to_string()),
76            raw: "feat(scope): broadcast $destroy event on scope destruction
77
78Hey!"
79                .to_string(),
80            scope: Some("scope".to_string()),
81            subject: Some("feat(scope): broadcast $destroy event on scope destruction".to_string()),
82        };
83
84        assert!(rule.validate(&message).is_none());
85    }
86
87    #[test]
88    fn test_short_body() {
89        let rule = BodyMaxLength {
90            length: 10, // Short length for testing
91            ..Default::default()
92        };
93        let message = Message {
94            body: Some("Hello, I'm a long body".to_string()),
95            description: None,
96            footers: None,
97            r#type: Some("feat".to_string()),
98            raw: "feat(scope): broadcast $destroy event on scope destruction
99
100Hello, I'm a long body"
101                .to_string(),
102            scope: Some("scope".to_string()),
103            subject: None,
104        };
105
106        let violation = rule.validate(&message);
107        assert!(violation.is_some());
108        assert_eq!(violation.clone().unwrap().level, Level::Error);
109        assert_eq!(
110            violation.unwrap().message,
111            format!("body is longer than {} characters", rule.length)
112        );
113    }
114}