1use std::collections::HashMap;
2
3use crate::rule::rule_result::{CountCategory, RuleResult, RuleResultMetadata};
4use crate::rule::{PasswordData, Rule};
5
6pub const ERROR_CODE_MIN: &str = "TOO_SHORT";
7pub const ERROR_CODE_MAX: &str = "TOO_LONG";
8
9pub struct LengthRule {
25 min_length: usize,
26 max_length: usize,
27}
28
29impl LengthRule {
30 pub fn new(min_length: usize, max_length: usize) -> Self {
31 Self {
32 min_length,
33 max_length,
34 }
35 }
36 pub fn with_exact_length(length: usize) -> Self {
37 Self {
38 min_length: length,
39 max_length: length,
40 }
41 }
42
43 fn create_rule_result_detail_parameters(&self) -> HashMap<String, String> {
44 let mut map = HashMap::new();
45 map.insert("min_length".to_string(), self.min_length.to_string());
46 map.insert("max_length".to_string(), self.max_length.to_string());
47 map
48 }
49 fn create_rule_result_metadata(password_data: &PasswordData) -> RuleResultMetadata {
50 RuleResultMetadata::new(CountCategory::Length, password_data.password.len())
51 }
52}
53
54impl Default for LengthRule {
55 fn default() -> Self {
56 LengthRule {
57 min_length: 0,
58 max_length: usize::MAX,
59 }
60 }
61}
62
63impl Rule for LengthRule {
64 fn validate(&self, password_data: &PasswordData) -> RuleResult {
65 let mut result = RuleResult::new(true);
66 let length = password_data.password.len();
67 if length < self.min_length {
68 result.add_error(
69 ERROR_CODE_MIN,
70 Some(self.create_rule_result_detail_parameters()),
71 );
72 } else if length > self.max_length {
73 result.add_error(
74 ERROR_CODE_MAX,
75 Some(self.create_rule_result_detail_parameters()),
76 )
77 }
78 result.set_metadata(Self::create_rule_result_metadata(password_data));
79 result
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use crate::rule::length::LengthRule;
86 use crate::rule::rule_result::CountCategory;
87 use crate::rule::{PasswordData, Rule};
88
89 #[test]
90 fn check_metada() {
91 let rule = LengthRule::new(4, 10);
92 let password = PasswordData::with_password("123".to_string());
93 let result = rule.validate(&password);
94 assert!(!result.valid());
95 }
96 #[test]
97 fn check_metadata() {
98 let rule = LengthRule::new(4, 10);
99 let result = rule.validate(&PasswordData::with_password("metadata".to_string()));
100 assert!(result.valid());
101 assert_eq!(8, result.metadata().get_count(CountCategory::Length));
102
103 let result = rule.validate(&PasswordData::with_password("md".to_string()));
104 assert!(!result.valid());
105 assert_eq!(2, result.metadata().get_count(CountCategory::Length));
106 }
107}