1use crate::{SwiftField, ValidationError, ValidationResult};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
136pub struct Field72 {
137 pub information: Vec<String>,
139}
140
141impl Field72 {
142 pub fn new(information: Vec<String>) -> Result<Self, crate::ParseError> {
144 if information.is_empty() {
145 return Err(crate::ParseError::InvalidFieldFormat {
146 field_tag: "72".to_string(),
147 message: "Sender to receiver information cannot be empty".to_string(),
148 });
149 }
150
151 if information.len() > 6 {
152 return Err(crate::ParseError::InvalidFieldFormat {
153 field_tag: "72".to_string(),
154 message: "Too many lines (max 6)".to_string(),
155 });
156 }
157
158 for (i, line) in information.iter().enumerate() {
159 if line.len() > 35 {
160 return Err(crate::ParseError::InvalidFieldFormat {
161 field_tag: "72".to_string(),
162 message: format!("Line {} too long (max 35 characters)", i + 1),
163 });
164 }
165
166 if !line.chars().all(|c| c.is_ascii() && !c.is_control()) {
168 return Err(crate::ParseError::InvalidFieldFormat {
169 field_tag: "72".to_string(),
170 message: format!("Line {} contains invalid characters", i + 1),
171 });
172 }
173 }
174
175 Ok(Field72 { information })
176 }
177
178 pub fn from_string(content: impl Into<String>) -> Result<Self, crate::ParseError> {
180 let content = content.into();
181 let lines: Vec<String> = content.lines().map(|s| s.to_string()).collect();
182 Self::new(lines)
183 }
184
185 pub fn information(&self) -> &[String] {
187 &self.information
188 }
189
190 pub fn line_count(&self) -> usize {
192 self.information.len()
193 }
194
195 pub fn line(&self, index: usize) -> Option<&str> {
197 self.information.get(index).map(|s| s.as_str())
198 }
199
200 pub fn add_line(&mut self, line: String) -> Result<(), crate::ParseError> {
202 if self.information.len() >= 6 {
203 return Err(crate::ParseError::InvalidFieldFormat {
204 field_tag: "72".to_string(),
205 message: "Cannot add more lines (max 6)".to_string(),
206 });
207 }
208
209 if line.len() > 35 {
210 return Err(crate::ParseError::InvalidFieldFormat {
211 field_tag: "72".to_string(),
212 message: "Line too long (max 35 characters)".to_string(),
213 });
214 }
215
216 if !line.chars().all(|c| c.is_ascii() && !c.is_control()) {
217 return Err(crate::ParseError::InvalidFieldFormat {
218 field_tag: "72".to_string(),
219 message: "Line contains invalid characters".to_string(),
220 });
221 }
222
223 self.information.push(line);
224 Ok(())
225 }
226
227 pub fn description(&self) -> String {
229 format!(
230 "Sender to Receiver Information ({} lines)",
231 self.line_count()
232 )
233 }
234}
235
236impl SwiftField for Field72 {
237 fn parse(value: &str) -> Result<Self, crate::ParseError> {
238 let content = if let Some(stripped) = value.strip_prefix(":72:") {
239 stripped } else if let Some(stripped) = value.strip_prefix("72:") {
241 stripped } else {
243 value
244 };
245
246 let content = content.trim();
247
248 if content.is_empty() {
249 return Err(crate::ParseError::InvalidFieldFormat {
250 field_tag: "72".to_string(),
251 message: "Field content cannot be empty".to_string(),
252 });
253 }
254
255 Self::from_string(content)
256 }
257
258 fn to_swift_string(&self) -> String {
259 format!(":72:{}", self.information.join("\n"))
260 }
261
262 fn validate(&self) -> ValidationResult {
263 let mut errors = Vec::new();
264
265 if self.information.is_empty() {
267 errors.push(ValidationError::ValueValidation {
268 field_tag: "72".to_string(),
269 message: "Information cannot be empty".to_string(),
270 });
271 }
272
273 if self.information.len() > 6 {
274 errors.push(ValidationError::LengthValidation {
275 field_tag: "72".to_string(),
276 expected: "max 6 lines".to_string(),
277 actual: self.information.len(),
278 });
279 }
280
281 for (i, line) in self.information.iter().enumerate() {
283 if line.len() > 35 {
284 errors.push(ValidationError::LengthValidation {
285 field_tag: "72".to_string(),
286 expected: format!("max 35 characters for line {}", i + 1),
287 actual: line.len(),
288 });
289 }
290
291 if !line.chars().all(|c| c.is_ascii() && !c.is_control()) {
292 errors.push(ValidationError::FormatValidation {
293 field_tag: "72".to_string(),
294 message: format!("Line {} contains invalid characters", i + 1),
295 });
296 }
297 }
298
299 ValidationResult {
300 is_valid: errors.is_empty(),
301 errors,
302 warnings: Vec::new(),
303 }
304 }
305
306 fn format_spec() -> &'static str {
307 "6*35x"
308 }
309}
310
311impl std::fmt::Display for Field72 {
312 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
313 write!(f, "{}", self.information.join("\n"))
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320
321 #[test]
322 fn test_field72_creation() {
323 let lines = vec!["/INS/CHQS".to_string(), "/BENEFRES/BE".to_string()];
324 let field = Field72::new(lines.clone()).unwrap();
325 assert_eq!(field.information(), &lines);
326 assert_eq!(field.line_count(), 2);
327 }
328
329 #[test]
330 fn test_field72_from_string() {
331 let content = "/INS/CHQS\n/BENEFRES/BE\n/ORDERRES/DE";
332 let field = Field72::from_string(content).unwrap();
333 assert_eq!(field.line_count(), 3);
334 assert_eq!(field.line(0), Some("/INS/CHQS"));
335 assert_eq!(field.line(1), Some("/BENEFRES/BE"));
336 assert_eq!(field.line(2), Some("/ORDERRES/DE"));
337 }
338
339 #[test]
340 fn test_field72_parse() {
341 let field = Field72::parse("/INS/CHQS\n/BENEFRES/BE").unwrap();
342 assert_eq!(field.line_count(), 2);
343 assert_eq!(field.line(0), Some("/INS/CHQS"));
344 assert_eq!(field.line(1), Some("/BENEFRES/BE"));
345 }
346
347 #[test]
348 fn test_field72_parse_with_prefix() {
349 let field = Field72::parse(":72:/INS/CHQS\n/BENEFRES/BE").unwrap();
350 assert_eq!(field.line_count(), 2);
351 assert_eq!(field.line(0), Some("/INS/CHQS"));
352 }
353
354 #[test]
355 fn test_field72_to_swift_string() {
356 let lines = vec!["/INS/CHQS".to_string(), "/BENEFRES/BE".to_string()];
357 let field = Field72::new(lines).unwrap();
358 assert_eq!(field.to_swift_string(), ":72:/INS/CHQS\n/BENEFRES/BE");
359 }
360
361 #[test]
362 fn test_field72_add_line() {
363 let mut field = Field72::new(vec!["/INS/CHQS".to_string()]).unwrap();
364 field.add_line("/BENEFRES/BE".to_string()).unwrap();
365 assert_eq!(field.line_count(), 2);
366 assert_eq!(field.line(1), Some("/BENEFRES/BE"));
367 }
368
369 #[test]
370 fn test_field72_too_many_lines() {
371 let lines = vec![
372 "Line 1".to_string(),
373 "Line 2".to_string(),
374 "Line 3".to_string(),
375 "Line 4".to_string(),
376 "Line 5".to_string(),
377 "Line 6".to_string(),
378 "Line 7".to_string(), ];
380 let result = Field72::new(lines);
381 assert!(result.is_err());
382 }
383
384 #[test]
385 fn test_field72_line_too_long() {
386 let lines = vec!["A".repeat(36)]; let result = Field72::new(lines);
388 assert!(result.is_err());
389 }
390
391 #[test]
392 fn test_field72_empty() {
393 let result = Field72::new(vec![]);
394 assert!(result.is_err());
395 }
396
397 #[test]
398 fn test_field72_validation() {
399 let field = Field72::new(vec!["/INS/CHQS".to_string()]).unwrap();
400 let validation = field.validate();
401 assert!(validation.is_valid);
402 assert!(validation.errors.is_empty());
403 }
404
405 #[test]
406 fn test_field72_display() {
407 let field =
408 Field72::new(vec!["/INS/CHQS".to_string(), "/BENEFRES/BE".to_string()]).unwrap();
409 assert_eq!(format!("{}", field), "/INS/CHQS\n/BENEFRES/BE");
410 }
411
412 #[test]
413 fn test_field72_description() {
414 let field =
415 Field72::new(vec!["/INS/CHQS".to_string(), "/BENEFRES/BE".to_string()]).unwrap();
416 assert_eq!(
417 field.description(),
418 "Sender to Receiver Information (2 lines)"
419 );
420 }
421
422 #[test]
423 fn test_field72_line_access() {
424 let field = Field72::new(vec!["/INS/CHQS".to_string()]).unwrap();
425 assert_eq!(field.line(0), Some("/INS/CHQS"));
426 assert_eq!(field.line(1), None);
427 }
428
429 #[test]
430 fn test_field72_add_line_max_reached() {
431 let mut field = Field72::new(vec![
432 "Line 1".to_string(),
433 "Line 2".to_string(),
434 "Line 3".to_string(),
435 "Line 4".to_string(),
436 "Line 5".to_string(),
437 "Line 6".to_string(),
438 ])
439 .unwrap();
440
441 let result = field.add_line("Line 7".to_string());
442 assert!(result.is_err());
443 }
444}