mx20022_validate/schema/
mod.rs1pub mod constraints;
21
22use crate::error::ValidationResult;
23use crate::rules::RuleRegistry;
24use constraints::ConstraintSet;
25
26pub struct SchemaValidator {
43 constraints: ConstraintSet,
44 registry: RuleRegistry,
45}
46
47impl SchemaValidator {
48 pub fn new(constraints: ConstraintSet, registry: RuleRegistry) -> Self {
50 Self {
51 constraints,
52 registry,
53 }
54 }
55
56 pub fn with_defaults() -> Self {
58 Self::new(ConstraintSet::new(), RuleRegistry::with_defaults())
59 }
60
61 pub fn validate_field(&self, path: &str, value: &str) -> ValidationResult {
67 self.constraints.validate_field(path, value, &self.registry)
68 }
69
70 pub fn registry_mut(&mut self) -> &mut RuleRegistry {
72 &mut self.registry
73 }
74
75 pub fn constraints_mut(&mut self) -> &mut ConstraintSet {
77 &mut self.constraints
78 }
79
80 pub fn validate_fields<'a>(
82 &self,
83 fields: impl IntoIterator<Item = (&'a str, &'a str)>,
84 ) -> ValidationResult {
85 let mut result = ValidationResult::default();
86 for (path, value) in fields {
87 result.merge(self.validate_field(path, value));
88 }
89 result
90 }
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96 use constraints::FieldConstraint;
97
98 #[test]
99 fn with_defaults_produces_valid_for_unconstrained_path() {
100 let validator = SchemaValidator::with_defaults();
101 let result = validator.validate_field("/any/path", "any value");
102 assert!(result.is_valid());
103 }
104
105 #[test]
106 fn validate_field_iban() {
107 let mut cs = ConstraintSet::new();
108 cs.add(FieldConstraint::new("/iban", ["IBAN_CHECK"]));
109 let validator = SchemaValidator::new(cs, RuleRegistry::with_defaults());
110
111 assert!(validator
112 .validate_field("/iban", "GB82WEST12345698765432")
113 .is_valid());
114 assert!(!validator.validate_field("/iban", "NOTANIBAN").is_valid());
115 }
116
117 #[test]
118 fn validate_fields_merges_results() {
119 let mut cs = ConstraintSet::new();
120 cs.add(FieldConstraint::new("/iban", ["IBAN_CHECK"]));
121 cs.add(FieldConstraint::new("/bic", ["BIC_CHECK"]));
122 let validator = SchemaValidator::new(cs, RuleRegistry::with_defaults());
123
124 let result = validator.validate_fields([("/iban", "NOTANIBAN"), ("/bic", "NOTABIC")]);
125 assert!(!result.is_valid());
127 assert!(result.error_count() >= 2);
128 }
129
130 #[test]
131 fn validate_fields_all_valid() {
132 let mut cs = ConstraintSet::new();
133 cs.add(FieldConstraint::new("/iban", ["IBAN_CHECK"]));
134 cs.add(FieldConstraint::new("/bic", ["BIC_CHECK"]));
135 let validator = SchemaValidator::new(cs, RuleRegistry::with_defaults());
136
137 let result =
138 validator.validate_fields([("/iban", "GB82WEST12345698765432"), ("/bic", "AAAAGB2L")]);
139 assert!(result.is_valid());
140 }
141}