1use chrono::NaiveDate;
2use std::fmt;
3
4use crate::Sex;
5
6#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct MRZResult {
10 pub document_type: String,
11 pub country_code: String,
12 pub surnames: String,
13 pub given_names: String,
14 pub document_number: String,
15 pub nationality_country_code: String,
16 pub birth_date: NaiveDate,
17 pub sex: Sex,
18 pub expiry_date: NaiveDate,
19 pub personal_number: String,
20 pub personal_number2: Option<String>,
21}
22
23impl MRZResult {
24 pub fn new(
29 document_type: impl Into<String>,
30 country_code: impl Into<String>,
31 surnames: impl Into<String>,
32 given_names: impl Into<String>,
33 document_number: impl Into<String>,
34 nationality_country_code: impl Into<String>,
35 birth_date: NaiveDate,
36 sex: Sex,
37 expiry_date: NaiveDate,
38 personal_number: impl Into<String>,
39 personal_number2: Option<impl Into<String>>,
40 ) -> Self {
41 MRZResult {
42 document_type: document_type.into(),
43 country_code: country_code.into(),
44 surnames: surnames.into(),
45 given_names: given_names.into(),
46 document_number: document_number.into(),
47 nationality_country_code: nationality_country_code.into(),
48 birth_date,
49 sex,
50 expiry_date,
51 personal_number: personal_number.into(),
52 personal_number2: personal_number2.map(|s| s.into()),
53 }
54 }
55}
56
57impl fmt::Display for MRZResult {
58 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
59 write!(
60 f,
61 "MRZResult {{ document_type: {}, country_code: {}, surnames: {}, given_names: {}, document_number: {}, nationality: {}, birth_date: {}, sex: {:?}, expiry_date: {}, personal_number: {}, personal_number2: {:?} }}",
62 self.document_type,
63 self.country_code,
64 self.surnames,
65 self.given_names,
66 self.document_number,
67 self.nationality_country_code,
68 self.birth_date,
69 self.sex,
70 self.expiry_date,
71 self.personal_number,
72 self.personal_number2,
73 )
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use crate::Sex;
81 use chrono::NaiveDate;
82
83 #[test]
84 fn create_and_compare_results() {
85 let birth = NaiveDate::from_ymd_opt(1990, 5, 20).expect("valid date");
86 let expiry = NaiveDate::from_ymd_opt(2030, 5, 20).expect("valid date");
87
88 let r1 = MRZResult::new(
89 "P",
90 "UTO",
91 "DOE",
92 "JOHN",
93 "123456789",
94 "UTO",
95 birth,
96 Sex::Male,
97 expiry,
98 "ABC123<<<",
99 Some("SECOND".to_string()),
100 );
101
102 let r2 = MRZResult {
103 document_type: "P".into(),
104 country_code: "UTO".into(),
105 surnames: "DOE".into(),
106 given_names: "JOHN".into(),
107 document_number: "123456789".into(),
108 nationality_country_code: "UTO".into(),
109 birth_date: birth,
110 sex: Sex::Male,
111 expiry_date: expiry,
112 personal_number: "ABC123<<<".into(),
113 personal_number2: Some("SECOND".into()),
114 };
115
116 assert_eq!(r1, r2);
117 assert!(r1.personal_number2.is_some());
118 }
119
120 #[test]
121 fn display_contains_key_fields() {
122 let birth = NaiveDate::from_ymd_opt(1985, 1, 1).unwrap();
123 let expiry = NaiveDate::from_ymd_opt(2025, 1, 1).unwrap();
124
125 let r = MRZResult::new(
126 "ID",
127 "GBR",
128 "SMITH",
129 "JANE",
130 "X9876543",
131 "GBR",
132 birth,
133 Sex::Female,
134 expiry,
135 "ZZZ000<<<",
136 None::<String>,
137 );
138
139 let s = format!("{}", r);
140 assert!(s.contains("SMITH"));
141 assert!(s.contains("JANE"));
142 assert!(s.contains("GBR"));
143 }
144}