brasilapi_client/definitions/
cep.rs1use crate::{client::*, constants::cep::{SVC_V1_URL, SVC_V2_URL}, errors::*, request::*, commons::EmptyOption};
2use serde::{Deserialize, Serialize};
3
4pub enum EnumCepRequestVersion {
8 V1,
10 V2
12}
13
14#[derive(Serialize, Deserialize, Debug)]
15#[serde(rename_all = "camelCase")]
16pub struct Coordinates {
18 pub latitude: String,
20 pub longitude: String
22}
23
24impl PartialEq for Coordinates {
25 fn eq(&self, other: &Self) -> bool {
26 self.latitude == other.latitude && self.longitude == other.longitude
27 }
28}
29
30#[derive(Serialize, Deserialize, Debug)]
31#[serde(rename_all = "camelCase")]
32pub struct Location
34{
35 pub coordinates: EmptyOption<Coordinates>
37}
38
39impl Default for Location {
40 fn default() -> Self {
41 Location { coordinates: EmptyOption::Some(Coordinates { latitude: String::new(), longitude: String::new() }) }
42 }
43}
44
45impl PartialEq for Location {
46 fn eq(&self, other: &Self) -> bool {
47 self.coordinates.as_option() == other.coordinates.as_option()
48 }
49}
50
51#[derive(Serialize, Deserialize, Debug)]
52#[serde(rename_all = "camelCase")]
53pub struct CepResponseData {
55 pub cep: String,
57 pub state: String,
59 pub city: String,
61 pub neighborhood: String,
63 pub street: String,
65 pub service: String,
67 #[serde(default)]
69 pub location: Location
70}
71
72impl PartialEq for CepResponseData {
73 fn eq(&self, other: &Self) -> bool {
74 self.cep == other.cep
75 && self.state == other.state
76 && self.city == other.city
77 && self.neighborhood == other.neighborhood
78 && self.street == other.street
79 && self.location == other.location
80 }
81}
82
83impl BrasilApiClient {
84 pub async fn get_cep(&self, cep: &str, cep_version: Option<EnumCepRequestVersion>) -> Result<CepResponseData, Error> {
85 lazy_static! {
86 static ref RE: regex::Regex = regex::Regex::new(r"[^0-9]").unwrap();
87 }
88 let cepver = cep_version.unwrap_or(EnumCepRequestVersion::V1);
89 let url = match cepver {
90 EnumCepRequestVersion::V2 => SVC_V2_URL,
91 _ => SVC_V1_URL
92 };
93
94 let temp_zipcode = RE.replace_all(cep, "");
95 if temp_zipcode.is_empty() || temp_zipcode.len() > 8 {
96 return Err(Error::InvalidInputLenError
97 {
98 name: "cep".to_string(),
99 min: 8,
100 max: 8
101 })
102 }
103
104 Ok(get::<(), CepResponseData>(
105 &format!("{}/{}/{}", self.base_url, url, temp_zipcode)
106 ).await?)
107 }
108}
109
110
111#[cfg(test)]
112mod tests {
113 use super::*;
114 use crate::client::tests::*;
115 use futures_await_test::async_test;
116
117 #[async_test]
118 async fn testc_invalid_input_minlen_none_ver() {
119 let resp = cli().get_cep("09777", None)
120 .await;
121
122 assert!(resp.is_err());
123 }
124
125 #[async_test]
126 async fn test_invalid_input_empty_none_ver() {
127 let resp = cli().get_cep("", None)
128 .await;
129
130 assert!(resp.is_err());
131 }
132
133 #[async_test]
134 async fn test_invalid_cep() {
135 let resp = cli().get_cep("12345678", None)
136 .await;
137
138 assert!(resp.is_err());
139 }
140
141 #[async_test]
142 async fn test_valid_none_ver() {
143 let resp = cli().get_cep("01402-000", None).await;
144 assert!(resp.is_ok());
145
146 let expected_text = r#"{"cep":"01402000","state":"SP","city":"São Paulo","neighborhood":"Jardim Paulista","street":"Avenida Brigadeiro Luís Antônio","service":"viacep"}"#;
147 let mut expected_json = serde_json::from_str::<CepResponseData>(expected_text).unwrap();
148 expected_json.service = "".into();
149
150 let mut from_svc = resp.unwrap();
151 from_svc.service = "".into();
152
153 assert_eq!(from_svc, expected_json);
154 }
155
156 #[async_test]
157 async fn test_valid_v1_same_as_none() {
158 let resp_v1 = cli().get_cep("01402-000", Some(EnumCepRequestVersion::V1)).await;
159 let resp_none = cli().get_cep("01402-000", None).await;
160 assert!(resp_v1.is_ok());
161 assert!(resp_none.is_ok());
162
163 let expected_text = r#"{"cep":"01402000","state":"SP","city":"São Paulo","neighborhood":"Jardim Paulista","street":"Avenida Brigadeiro Luís Antônio","service":"viacep"}"#;
164 let mut expected_json = serde_json::from_str::<CepResponseData>(expected_text).unwrap();
165 expected_json.service = "".into();
166
167 let mut from_svc = resp_v1.unwrap();
168 from_svc.service = "".into();
169
170 assert_eq!(from_svc, expected_json);
171
172 let mut from_svc_none = resp_none.unwrap();
173 from_svc_none.service = "".into();
174
175 assert_eq!(from_svc, from_svc_none);
176 }
177
178 #[async_test]
179 async fn test_valid_v2() {
180 let resp = cli().get_cep("01402-000", Some(EnumCepRequestVersion::V2)).await;
181 assert!(resp.is_ok());
182
183 let expected_text = r#"{"cep":"01402000","state":"SP","city":"São Paulo","neighborhood":"Jardim Paulista","street":"Avenida Brigadeiro Luís Antônio","service":"viacep","location":{"type":"Point","coordinates":{"longitude":"-46.6573802","latitude":"-23.57555"}}}"#;
184 let mut expected_json = serde_json::from_str::<CepResponseData>(expected_text).unwrap();
186 expected_json.service = "".into();
187
188 let mut from_svc = resp.unwrap();
189 from_svc.service = "".into();
190
191 assert_eq!(from_svc, expected_json);
192 }
193
194 #[async_test]
195 async fn test_valid_v2_not_equals_v1() {
196 let resp_v2 = cli().get_cep("01402-000", Some(EnumCepRequestVersion::V2)).await;
197 let resp_none = cli().get_cep("01402-000", None).await;
198 assert!(resp_v2.is_ok());
199 assert!(resp_none.is_ok());
200
201 let expected_text = r#"{"cep":"01402000","state":"SP","city":"São Paulo","neighborhood":"Jardim Paulista","street":"Avenida Brigadeiro Luís Antônio","service":"viacep","location":{"type":"Point","coordinates":{"longitude":"-46.6573802","latitude":"-23.57555"}}}"#;
202 let mut expected_json = serde_json::from_str::<CepResponseData>(expected_text).unwrap();
203 expected_json.service = "".into();
204
205 let mut from_svc = resp_v2.unwrap();
206 from_svc.service = "".into();
207
208 assert_eq!(from_svc, expected_json);
209
210 let mut from_svc_none = resp_none.unwrap();
211 from_svc_none.service = "".into();
212
213 assert_ne!(from_svc, from_svc_none);
214 }
215}