summaryrefslogtreecommitdiffstats
path: root/tests/api.rs
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-27 20:33:37 -0300
committerMurilo Ijanc <[email protected]>2026-07-27 20:33:37 -0300
commit487b4c5628c02130580c675925a1d64b09a5f6cb (patch)
tree240338af0c2c246bb2c689464f63d70b1f27f240 /tests/api.rs
parent4a8c3b675df4b1a6b29904fc2af60605002a7f9e (diff)
downloadrust-487b4c5628c02130580c675925a1d64b09a5f6cb.tar.gz
Carry the municipality of a CEP that does not existHEADv0.2.0main
A 404 from the API now brings a "faixa" naming the municipality the CEP would have belonged to, and NotFound carries it. A CEP that fails is rarely a random number: it is usually someone who knows the city and guessed the digits, so naming the city turns a dead end into an answer the caller can show. It stays an error. The range it carries is the CEPs that actually exist there, not the bounds the Correios publish — those start at the very CEP that just failed — and it is sparse, which is what "ceps" measures. The field is decoration on a failure, so parsing it is entirely defensive: absent, null or malformed all yield None rather than costing a clean not-found. Breaking: NotFound gained a field, hence 0.2.0.
Diffstat (limited to 'tests/api.rs')
-rw-r--r--tests/api.rs99
1 files changed, 98 insertions, 1 deletions
diff --git a/tests/api.rs b/tests/api.rs
index c794687..349c951 100644
--- a/tests/api.rs
+++ b/tests/api.rs
@@ -25,6 +25,13 @@ const SE_ADDRESS: &str = r#"{
"ddd": "11", "siafi": "7107"
}"#;
+/// The `faixa` a 404 carries when the CEP falls inside a municipality.
+///
+/// Areal/RJ, and the numbers are the real ones: 118 CEPs scattered over the
+/// ~4,900 between the two ends, and a `cep_ini` one above the CEP being looked
+/// up — the DNE's own start for Areal is `25845000`, which does not exist.
+const FAIXA: &str = r#","faixa":{"localidade":"Areal","uf":"RJ","estado":"Rio de Janeiro","regiao":"Sudeste","ibge":"3300225","cep_ini":"25845001","cep_fim":"25849899","ceps":118}"#;
+
const CSV_HEADER: &str =
"cep,logradouro,complemento,unidade,bairro,localidade,uf,estado,regiao,ibge,gia,ddd,siafi";
@@ -180,6 +187,12 @@ fn csv_body(rows: &[String]) -> String {
format!("{}\n{}\n", CSV_HEADER, rows.join("\n"))
}
+/// A 404 body, with `extra` spliced in as further fields — a `faixa`, whole or
+/// broken.
+fn not_found_with(extra: &str) -> String {
+ format!(r#"{{"erro":"cep_nao_encontrado","mensagem":"CEP não existe na base do DNE"{extra}}}"#)
+}
+
fn with_geo(precisao: &str, raio_m: i64) -> String {
format!(
r#"{{"cep":"01310100","logradouro":"Avenida Paulista","complemento":"","unidade":"","bairro":"Bela Vista","localidade":"São Paulo","uf":"SP","estado":"São Paulo","regiao":"Sudeste","ibge":"3550308","gia":"1004","ddd":"11","siafi":"7107","geo":{{"lat":-23.5,"lon":-46.6,"raio_m":{raio_m},"precisao":"{precisao}"}}}}"#
@@ -295,8 +308,92 @@ fn not_found() {
let err = server.client().lookup("99999999").unwrap_err();
- assert!(matches!(&err, Error::NotFound { cep } if cep == "99999999"));
+ assert!(matches!(&err, Error::NotFound { cep, .. } if cep == "99999999"));
+ assert!(!err.is_retriable());
+ assert!(err.faixa().is_none());
+ assert_eq!(
+ err.to_string(),
+ "CEP 99999999 does not exist in the DNE database"
+ );
+}
+
+#[test]
+fn not_found_names_the_municipality_when_the_api_does() {
+ let server = Server::start();
+ server.respond("/25845000", vec![Reply::new(404, &not_found_with(FAIXA))]);
+
+ let err = server.client().lookup("25845000").unwrap_err();
+ let faixa = err.faixa().expect("faixa present");
+
+ assert_eq!(faixa.localidade, "Areal");
+ assert_eq!(faixa.uf, "RJ");
+ assert_eq!(faixa.estado, "Rio de Janeiro");
+ assert_eq!(faixa.regiao, "Sudeste");
+ assert_eq!(faixa.ibge, "3300225");
+ assert_eq!(faixa.municipality(), "Areal/RJ");
+
+ // The ends are the CEPs that exist, not the Correios bounds: the published
+ // start for Areal is 25845000 — the CEP that just failed.
+ assert_eq!(faixa.cep_ini, "25845001");
+ assert_eq!(faixa.cep_fim, "25849899");
+ assert_eq!(faixa.ceps, 118);
+}
+
+#[test]
+fn a_faixa_is_still_a_not_found() {
+ let server = Server::start();
+ server.respond("/25845000", vec![Reply::new(404, &not_found_with(FAIXA))]);
+
+ let err = server.client().lookup("25845000").unwrap_err();
+
+ assert!(matches!(&err, Error::NotFound { cep, .. } if cep == "25845000"));
assert!(!err.is_retriable());
+ assert_eq!(
+ err.to_string(),
+ "CEP 25845000 does not exist in the DNE database (it would be in Areal/RJ)"
+ );
+}
+
+#[test]
+fn an_unreadable_faixa_does_not_cost_the_not_found() {
+ for broken in [
+ r#","faixa":null"#,
+ r#","faixa":{}"#,
+ r#","faixa":[]"#,
+ r#","faixa":"Areal""#,
+ r#","faixa":{"uf":"RJ","ceps":118}"#,
+ ] {
+ let server = Server::start();
+ server.respond("/25845000", vec![Reply::new(404, &not_found_with(broken))]);
+
+ let err = server.client().lookup("25845000").unwrap_err();
+
+ assert!(
+ matches!(&err, Error::NotFound { cep, .. } if cep == "25845000"),
+ "expected NotFound for {broken}, got {err:?}"
+ );
+ assert!(err.faixa().is_none(), "expected no faixa for {broken}");
+ }
+}
+
+#[test]
+fn a_faixa_missing_the_extras_still_names_the_municipality() {
+ let server = Server::start();
+ server.respond(
+ "/25845000",
+ vec![Reply::new(
+ 404,
+ &not_found_with(r#","faixa":{"localidade":"Areal"}"#),
+ )],
+ );
+
+ let err = server.client().lookup("25845000").unwrap_err();
+ let faixa = err.faixa().expect("faixa present");
+
+ assert_eq!(faixa.localidade, "Areal");
+ assert_eq!(faixa.uf, "");
+ assert_eq!(faixa.cep_ini, "");
+ assert_eq!(faixa.ceps, 0);
}
#[test]