zero_bounce/utility/structures/
validation.rs

1use chrono::NaiveDateTime;
2
3use serde::Deserialize;
4
5use crate::utility::structures::custom_deserialize::deserialize_naive_date;
6
7
8#[derive(Clone, Debug, Deserialize)]
9pub struct ZBValidation {
10    pub address: String,
11    pub status: String,
12    pub sub_status: String,
13    pub free_email: bool,
14    pub did_you_mean: Option<String>,
15    pub account: Option<String>,
16    pub domain: Option<String>,
17    pub domain_age_days: Option<String>,
18    pub smtp_provider: Option<String>,
19    pub mx_record: Option<String>,
20    pub mx_found: Option<String>,
21    pub firstname: Option<String>,
22    pub lastname: Option<String>,
23    pub gender: Option<String>,
24    pub country: Option<String>,
25    pub region: Option<String>,
26    pub city: Option<String>,
27    pub zipcode: Option<String>,
28
29    #[serde(deserialize_with="deserialize_naive_date")]
30    pub processed_at: NaiveDateTime,
31}
32
33
34#[derive(Clone, Debug, Deserialize)]
35pub struct ZBBatchError {
36    pub error: String,
37    pub email_address: String,
38}
39
40
41#[derive(Clone, Debug, Deserialize)]
42pub struct ZBBatchValidation {
43    pub email_batch: Vec<ZBValidation>,
44    pub errors: Vec<ZBBatchError>,
45}
46
47#[cfg(test)]
48mod test {
49    use serde_json::{Result as SerdeResult, from_str};
50
51    use super::*;
52    use crate::utility::mock_constants::VALIDATION_RESPONSE_VALID;
53    use crate::utility::mock_constants::VALIDATION_RESPONSE_INVALID;
54    use crate::utility::mock_constants::VALIDATION_RESPONSE_NULL_FIELDS;
55    use crate::utility::mock_constants::BATCH_VALIDATION_WITH_ERROR;
56    use crate::utility::mock_constants::BATCH_VALIDATION_ERROR_ONLY;
57    use crate::utility::mock_constants::BATCH_VALIDATION_NO_ERROR;
58
59    #[test]
60    fn test_validation_invalid_json() {
61        let validation_res: SerdeResult<ZBValidation> = from_str("");
62        assert!(validation_res.is_err());
63    }
64
65    #[test]
66    fn test_validation_missing_expected_fields() {
67        let validation_res: SerdeResult<ZBValidation> = from_str(VALIDATION_RESPONSE_NULL_FIELDS);
68        assert!(validation_res.is_ok());
69
70        let validation = validation_res.unwrap();
71        assert_eq!(validation.did_you_mean, None);
72        assert_eq!(validation.domain_age_days, Some("".to_string()));
73    }
74
75    #[test]
76    fn test_validation_invalid_email_status() {
77        let validation_res: SerdeResult<ZBValidation> = from_str(VALIDATION_RESPONSE_INVALID);
78        assert!(validation_res.is_ok());
79
80        let validation = validation_res.unwrap();
81        assert_eq!(validation.status, "invalid".to_string());
82        assert_eq!(validation.sub_status, "mailbox_not_found".to_string());
83        assert_eq!(validation.did_you_mean, None);
84        assert_eq!(validation.smtp_provider, Some("example".to_string()));
85        assert_eq!(validation.free_email, false);
86
87        let expected_date = NaiveDateTime::new(
88            chrono::NaiveDate::from_ymd_opt(2023, 3, 23).unwrap(),
89            chrono::NaiveTime::from_hms_milli_opt(12, 30, 28, 3).unwrap(),
90        );
91        assert_eq!(validation.processed_at, expected_date);
92    }
93
94    #[test]
95    fn test_validation_valid_email_status() {
96        let validation_res: SerdeResult<ZBValidation> = from_str(VALIDATION_RESPONSE_VALID);
97        assert!(validation_res.is_ok());
98
99        let validation = validation_res.unwrap();
100        assert_eq!(validation.status, "valid".to_string());
101        assert_eq!(validation.sub_status, "".to_string());
102        assert_eq!(validation.did_you_mean, None);
103        assert_eq!(validation.smtp_provider, Some("example".to_string()));
104        assert_eq!(validation.free_email, false);
105
106        let expected_date = NaiveDateTime::new(
107            chrono::NaiveDate::from_ymd_opt(2023, 3, 23).unwrap(),
108            chrono::NaiveTime::from_hms_milli_opt(13, 30, 28, 105).unwrap(),
109        );
110        assert_eq!(validation.processed_at, expected_date);
111    }
112
113    #[test]
114    fn test_batch_error_only_content() {
115        let batch: SerdeResult<ZBBatchValidation> = from_str(BATCH_VALIDATION_ERROR_ONLY);
116        assert!(batch.is_ok());
117
118        let batch_object = batch.unwrap();
119        assert_eq!(batch_object.email_batch.len(), 0);
120        assert_eq!(batch_object.errors.len(), 1);
121    }
122
123    #[test]
124    fn test_batch_validation_and_error_content() {
125        let batch: SerdeResult<ZBBatchValidation> = from_str(BATCH_VALIDATION_WITH_ERROR);
126        assert!(batch.is_ok());
127
128        let batch_object = batch.unwrap();
129        assert_eq!(batch_object.email_batch.len(), 1);
130        assert_eq!(batch_object.errors.len(), 1);
131    }
132
133    #[test]
134    fn test_batch_validation_only_content() {
135        let batch: SerdeResult<ZBBatchValidation> = from_str(BATCH_VALIDATION_NO_ERROR);
136        assert!(batch.is_ok());
137
138        let batch_object = batch.unwrap();
139        assert_eq!(batch_object.email_batch.len(), 1);
140        assert_eq!(batch_object.errors.len(), 0);
141    }
142
143}