1use crate::{SwiftField, ValidationResult};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
90pub struct Field52D {
91 pub name_and_address: Vec<String>,
93}
94
95impl Field52D {
96 pub fn new(name_and_address: Vec<String>) -> Result<Self, crate::ParseError> {
98 if name_and_address.is_empty() {
99 return Err(crate::ParseError::InvalidFieldFormat {
100 field_tag: "52D".to_string(),
101 message: "Name and address cannot be empty".to_string(),
102 });
103 }
104
105 if name_and_address.len() > 4 {
106 return Err(crate::ParseError::InvalidFieldFormat {
107 field_tag: "52D".to_string(),
108 message: "Too many name/address lines (max 4)".to_string(),
109 });
110 }
111
112 for (i, line) in name_and_address.iter().enumerate() {
113 if line.len() > 35 {
114 return Err(crate::ParseError::InvalidFieldFormat {
115 field_tag: "52D".to_string(),
116 message: format!("Line {} too long (max 35 characters)", i + 1),
117 });
118 }
119
120 if !line.chars().all(|c| c.is_ascii() && !c.is_control()) {
122 return Err(crate::ParseError::InvalidFieldFormat {
123 field_tag: "52D".to_string(),
124 message: format!("Line {} contains invalid characters", i + 1),
125 });
126 }
127 }
128
129 Ok(Field52D { name_and_address })
130 }
131
132 pub fn from_string(content: impl Into<String>) -> Result<Self, crate::ParseError> {
134 let content = content.into();
135 let lines: Vec<String> = content.lines().map(|s| s.to_string()).collect();
136 Self::new(lines)
137 }
138
139 pub fn name_and_address(&self) -> &[String] {
141 &self.name_and_address
142 }
143
144 pub fn line_count(&self) -> usize {
146 self.name_and_address.len()
147 }
148
149 pub fn line(&self, index: usize) -> Option<&str> {
151 self.name_and_address.get(index).map(|s| s.as_str())
152 }
153
154 pub fn add_line(&mut self, line: String) -> Result<(), crate::ParseError> {
156 if self.name_and_address.len() >= 4 {
157 return Err(crate::ParseError::InvalidFieldFormat {
158 field_tag: "52D".to_string(),
159 message: "Cannot add more lines (max 4)".to_string(),
160 });
161 }
162
163 if line.len() > 35 {
164 return Err(crate::ParseError::InvalidFieldFormat {
165 field_tag: "52D".to_string(),
166 message: "Line too long (max 35 characters)".to_string(),
167 });
168 }
169
170 if !line.chars().all(|c| c.is_ascii() && !c.is_control()) {
171 return Err(crate::ParseError::InvalidFieldFormat {
172 field_tag: "52D".to_string(),
173 message: "Line contains invalid characters".to_string(),
174 });
175 }
176
177 self.name_and_address.push(line);
178 Ok(())
179 }
180
181 pub fn description(&self) -> String {
183 format!("Ordering Institution ({} lines)", self.line_count())
184 }
185}
186
187impl SwiftField for Field52D {
188 fn parse(content: &str) -> crate::Result<Self> {
189 let content = content.trim();
190 if content.is_empty() {
191 return Err(crate::ParseError::InvalidFieldFormat {
192 field_tag: "52D".to_string(),
193 message: "Field content cannot be empty".to_string(),
194 });
195 }
196
197 let content = if let Some(stripped) = content.strip_prefix(":52D:") {
198 stripped
199 } else if let Some(stripped) = content.strip_prefix("52D:") {
200 stripped
201 } else {
202 content
203 };
204
205 let lines: Vec<String> = content.lines().map(|s| s.to_string()).collect();
206
207 Field52D::new(lines)
208 }
209
210 fn to_swift_string(&self) -> String {
211 format!(":52D:{}", self.name_and_address.join("\n"))
212 }
213
214 fn validate(&self) -> ValidationResult {
215 use crate::errors::ValidationError;
216
217 let mut errors = Vec::new();
218
219 if self.name_and_address.is_empty() {
220 errors.push(ValidationError::ValueValidation {
221 field_tag: "52D".to_string(),
222 message: "Name and address cannot be empty".to_string(),
223 });
224 }
225
226 if self.name_and_address.len() > 4 {
227 errors.push(ValidationError::LengthValidation {
228 field_tag: "52D".to_string(),
229 expected: "max 4 lines".to_string(),
230 actual: self.name_and_address.len(),
231 });
232 }
233
234 for (i, line) in self.name_and_address.iter().enumerate() {
235 if line.len() > 35 {
236 errors.push(ValidationError::LengthValidation {
237 field_tag: "52D".to_string(),
238 expected: format!("max 35 characters for line {}", i + 1),
239 actual: line.len(),
240 });
241 }
242
243 if !line.chars().all(|c| c.is_ascii() && !c.is_control()) {
244 errors.push(ValidationError::FormatValidation {
245 field_tag: "52D".to_string(),
246 message: format!("Line {} contains invalid characters", i + 1),
247 });
248 }
249 }
250
251 ValidationResult {
252 is_valid: errors.is_empty(),
253 errors,
254 warnings: Vec::new(),
255 }
256 }
257
258 fn format_spec() -> &'static str {
259 "4*35x"
260 }
261}
262
263impl std::fmt::Display for Field52D {
264 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
265 write!(f, "{}", self.name_and_address.join("\n"))
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 #[test]
274 fn test_field52d_creation() {
275 let lines = vec![
276 "ABC BANK".to_string(),
277 "123 MAIN STREET".to_string(),
278 "NEW YORK NY 10001".to_string(),
279 ];
280 let field = Field52D::new(lines.clone()).unwrap();
281 assert_eq!(field.name_and_address(), &lines);
282 assert_eq!(field.line_count(), 3);
283 assert_eq!(field.line(0), Some("ABC BANK"));
284 assert_eq!(field.line(1), Some("123 MAIN STREET"));
285 assert_eq!(field.line(2), Some("NEW YORK NY 10001"));
286 assert_eq!(field.line(3), None);
287 }
288
289 #[test]
290 fn test_field52d_creation_single_line() {
291 let lines = vec!["ABC BANK".to_string()];
292 let field = Field52D::new(lines.clone()).unwrap();
293 assert_eq!(field.name_and_address(), &lines);
294 assert_eq!(field.line_count(), 1);
295 }
296
297 #[test]
298 fn test_field52d_from_string() {
299 let content = "ABC BANK\n123 MAIN STREET\nNEW YORK NY 10001";
300 let field = Field52D::from_string(content).unwrap();
301 assert_eq!(field.line_count(), 3);
302 assert_eq!(field.line(0), Some("ABC BANK"));
303 assert_eq!(field.line(1), Some("123 MAIN STREET"));
304 assert_eq!(field.line(2), Some("NEW YORK NY 10001"));
305 }
306
307 #[test]
308 fn test_field52d_parse() {
309 let field = Field52D::parse("ABC BANK\n123 MAIN STREET").unwrap();
310 assert_eq!(field.line_count(), 2);
311 assert_eq!(field.line(0), Some("ABC BANK"));
312 assert_eq!(field.line(1), Some("123 MAIN STREET"));
313 }
314
315 #[test]
316 fn test_field52d_parse_with_tag() {
317 let field = Field52D::parse(":52D:ABC BANK\n123 MAIN STREET").unwrap();
318 assert_eq!(field.line_count(), 2);
319 assert_eq!(field.line(0), Some("ABC BANK"));
320 assert_eq!(field.line(1), Some("123 MAIN STREET"));
321 }
322
323 #[test]
324 fn test_field52d_to_swift_string() {
325 let lines = vec!["ABC BANK".to_string(), "123 MAIN STREET".to_string()];
326 let field = Field52D::new(lines).unwrap();
327 assert_eq!(field.to_swift_string(), ":52D:ABC BANK\n123 MAIN STREET");
328 }
329
330 #[test]
331 fn test_field52d_display() {
332 let lines = vec!["ABC BANK".to_string(), "123 MAIN STREET".to_string()];
333 let field = Field52D::new(lines).unwrap();
334 assert_eq!(format!("{}", field), "ABC BANK\n123 MAIN STREET");
335 }
336
337 #[test]
338 fn test_field52d_description() {
339 let lines = vec!["ABC BANK".to_string(), "123 MAIN STREET".to_string()];
340 let field = Field52D::new(lines).unwrap();
341 assert_eq!(field.description(), "Ordering Institution (2 lines)");
342 }
343
344 #[test]
345 fn test_field52d_add_line() {
346 let lines = vec!["ABC BANK".to_string()];
347 let mut field = Field52D::new(lines).unwrap();
348
349 field.add_line("123 MAIN STREET".to_string()).unwrap();
350 assert_eq!(field.line_count(), 2);
351 assert_eq!(field.line(1), Some("123 MAIN STREET"));
352
353 field.add_line("NEW YORK NY 10001".to_string()).unwrap();
354 assert_eq!(field.line_count(), 3);
355
356 field.add_line("USA".to_string()).unwrap();
357 assert_eq!(field.line_count(), 4);
358
359 let result = field.add_line("TOO MANY LINES".to_string());
361 assert!(result.is_err());
362 }
363
364 #[test]
365 fn test_field52d_validation_empty() {
366 let result = Field52D::new(vec![]);
367 assert!(result.is_err());
368 assert!(result.unwrap_err().to_string().contains("cannot be empty"));
369 }
370
371 #[test]
372 fn test_field52d_validation_too_many_lines() {
373 let lines = vec![
374 "Line 1".to_string(),
375 "Line 2".to_string(),
376 "Line 3".to_string(),
377 "Line 4".to_string(),
378 "Line 5".to_string(), ];
380 let result = Field52D::new(lines);
381 assert!(result.is_err());
382 assert!(result.unwrap_err().to_string().contains("max 4"));
383 }
384
385 #[test]
386 fn test_field52d_validation_line_too_long() {
387 let lines = vec!["A".repeat(36)]; let result = Field52D::new(lines);
389 assert!(result.is_err());
390 assert!(result.unwrap_err().to_string().contains("too long"));
391 }
392
393 #[test]
394 fn test_field52d_validation_invalid_characters() {
395 let lines = vec!["ABC BANK\x00".to_string()]; let result = Field52D::new(lines);
397 assert!(result.is_err());
398 assert!(
399 result
400 .unwrap_err()
401 .to_string()
402 .contains("invalid characters")
403 );
404 }
405
406 #[test]
407 fn test_field52d_validate() {
408 let lines = vec!["ABC BANK".to_string(), "123 MAIN STREET".to_string()];
409 let field = Field52D::new(lines).unwrap();
410 let validation = field.validate();
411 assert!(validation.is_valid);
412 assert!(validation.errors.is_empty());
413 }
414
415 #[test]
416 fn test_field52d_validate_errors() {
417 let lines = vec!["A".repeat(36)]; let field = Field52D {
419 name_and_address: lines,
420 };
421 let validation = field.validate();
422 assert!(!validation.is_valid);
423 assert!(!validation.errors.is_empty());
424 }
425}