1use crate::error::FieldError;
2use crate::field::FormField;
3
4#[derive(Clone)]
10pub struct Form {
11 fields: Vec<FormField>,
12}
13
14impl Form {
15 pub fn new() -> Self { Self { fields: Vec::new() } }
16
17 pub fn field(mut self, f: FormField) -> Self { self.fields.push(f); self }
18
19 pub fn add_field(&mut self, f: FormField) { self.fields.push(f); }
20
21 pub fn validate_all(&self) -> bool {
23 let results: Vec<bool> = self.fields.iter().map(|f| f.validate()).collect();
26 results.iter().all(|&v| v)
27 }
28
29 pub fn errors(&self) -> Vec<FieldError> {
31 self.fields.iter().flat_map(|f| f.errors()).collect()
32 }
33
34 pub fn field_named(&self, name: &str) -> Option<&FormField> {
36 self.fields.iter().find(|f| f.name == name)
37 }
38
39 pub fn is_valid(&self) -> bool {
43 self.fields.iter().all(|f| f.is_valid())
44 }
45
46 pub fn reset(&self) {
48 self.fields.iter().for_each(|f| f.reset());
49 }
50
51 pub fn len(&self) -> usize { self.fields.len() }
53 pub fn is_empty(&self) -> bool { self.fields.is_empty() }
54
55 pub fn submit(&self, on_valid: impl FnOnce()) -> bool {
65 let valid = self.validate_all();
66 if valid {
67 on_valid();
68 }
69 valid
70 }
71}
72
73impl Default for Form { fn default() -> Self { Self::new() } }
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78 use crate::field::FormField;
79 use crate::validator::Required;
80
81 #[test]
82 fn form_new_empty() {
83 let f = Form::new();
84 assert!(f.is_empty());
85 assert_eq!(f.len(), 0);
86 }
87
88 #[test]
89 fn form_add_field() {
90 let mut f = Form::new();
91 f.add_field(FormField::new("email"));
92 assert_eq!(f.len(), 1);
93 }
94
95 #[test]
96 fn form_validate_all_passes() {
97 let form = Form::new()
98 .field(FormField::new("name").rule(Required));
99 form.field_named("name").unwrap().set("alice");
100 assert!(form.validate_all());
101 }
102
103 #[test]
104 fn form_validate_all_fails() {
105 let form = Form::new()
106 .field(FormField::new("name").rule(Required));
107 assert!(!form.validate_all());
108 }
109
110 #[test]
111 fn form_errors_returns_all() {
112 let form = Form::new()
113 .field(FormField::new("name").rule(Required))
114 .field(FormField::new("email").rule(Required));
115 form.validate_all();
116 assert_eq!(form.errors().len(), 2);
117 }
118
119 #[test]
120 fn form_field_named() {
121 let form = Form::new()
122 .field(FormField::new("username"));
123 assert!(form.field_named("username").is_some());
124 assert!(form.field_named("missing").is_none());
125 }
126
127 #[test]
128 fn form_reset_clears_all() {
129 let form = Form::new()
130 .field(FormField::new("name").rule(Required));
131 form.field_named("name").unwrap().set("alice");
132 form.validate_all();
133 form.reset();
134 assert_eq!(form.field_named("name").unwrap().get(), "");
135 assert!(form.errors().is_empty());
136 }
137
138 #[test]
139 fn form_is_valid_after_validate() {
140 let form = Form::new()
141 .field(FormField::new("name").rule(Required));
142 form.field_named("name").unwrap().set("bob");
143 form.validate_all();
144 assert!(form.is_valid());
145 }
146
147 #[test]
148 fn submit_runs_the_callback_only_when_valid() {
149 let form = Form::new().field(FormField::new("name").rule(Required));
150 let mut ran = false;
151 assert!(!form.submit(|| ran = true), "submit must return false when a required field is empty");
152 assert!(!ran, "the callback must not run on a failed submit");
153
154 form.field_named("name").unwrap().set("alice");
155 let mut ran2 = false;
156 assert!(form.submit(|| ran2 = true));
157 assert!(ran2, "the callback must run once validation passes");
158 }
159
160 #[test]
161 fn cloning_a_form_shares_the_same_fields() {
162 let form = Form::new().field(FormField::new("name").rule(Required));
163 let clone = form.clone();
164 clone.field_named("name").unwrap().set("alice");
165 assert!(form.field_named("name").unwrap().is_touched(), "a clone's write must be visible through the original Form");
166 }
167}