karbon_framework/validation/constraints/string/
regex.rs1use crate::validation::constraints::{Constraint, ConstraintResult, ConstraintViolation};
2
3pub struct Regex {
7 pub pattern: regex::Regex,
8 pub message: String,
9 pub should_match: bool,
10}
11
12impl Regex {
13 pub fn new(pattern: &str) -> Self {
14 Self {
15 pattern: regex::Regex::new(pattern).expect("Invalid regex pattern"),
16 message: "This value is not valid.".to_string(),
17 should_match: true,
18 }
19 }
20
21 pub fn with_message(mut self, message: impl Into<String>) -> Self {
22 self.message = message.into();
23 self
24 }
25
26 pub fn should_match(mut self, should_match: bool) -> Self {
28 self.should_match = should_match;
29 self
30 }
31}
32
33impl Constraint for Regex {
34 fn validate(&self, value: &str) -> ConstraintResult {
35 let matches = self.pattern.is_match(value);
36
37 if matches != self.should_match {
38 return Err(ConstraintViolation::new(
39 self.name(),
40 &self.message,
41 value,
42 ));
43 }
44 Ok(())
45 }
46
47 fn name(&self) -> &'static str {
48 "Regex"
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[test]
57 fn test_matching_pattern() {
58 let constraint = Regex::new(r"^\d{5}$"); assert!(constraint.validate("75001").is_ok());
60 assert!(constraint.validate("12345").is_ok());
61 assert!(constraint.validate("1234").is_err());
62 assert!(constraint.validate("123456").is_err());
63 assert!(constraint.validate("abcde").is_err());
64 }
65
66 #[test]
67 fn test_not_matching() {
68 let constraint = Regex::new(r"<script").should_match(false);
69 assert!(constraint.validate("hello world").is_ok());
70 assert!(constraint.validate("<script>alert('xss')</script>").is_err());
71 }
72
73 #[test]
74 fn test_complex_pattern() {
75 let constraint = Regex::new(r"^[A-Z]{2}-\d{3}$");
76 assert!(constraint.validate("FR-123").is_ok());
77 assert!(constraint.validate("US-456").is_ok());
78 assert!(constraint.validate("fr-123").is_err());
79 assert!(constraint.validate("FRA-123").is_err());
80 }
81
82 #[test]
83 fn test_custom_message() {
84 let constraint = Regex::new(r"^\d+$").with_message("Seuls les chiffres sont autorisés.");
85 let err = constraint.validate("abc").unwrap_err();
86 assert_eq!(err.message, "Seuls les chiffres sont autorisés.");
87 }
88}