diff options
| author | Murilo Ijanc <[email protected]> | 2026-07-27 20:21:38 -0300 |
|---|---|---|
| committer | Murilo Ijanc <[email protected]> | 2026-07-27 20:21:38 -0300 |
| commit | f9f1d248f3a3a2b781507195e00527db1e39f8d3 (patch) | |
| tree | f99b24f5923e436339b8e8ddb8af6ac854488439 /test | |
| parent | 075683ff44a254e99adbad8a0372ef80ff06151a (diff) | |
| download | elixir-f9f1d248f3a3a2b781507195e00527db1e39f8d3.tar.gz | |
A CEP that fails is rarely a random number: it is usually someone who
knows the city and guessed, most often the -000 that 957 municipalities
never received. The API now answers 404 with an optional faixa naming
the municipality that number would have belonged to, so the caller can
say "you are in Areal, but not at that number" instead of a dead end.
It stays an error. Cepis.Faixa hangs off Cepis.NotFoundError as context
for the failure, never as an address, and parsing is deliberately
tolerant: an absent, truncated or unreadable faixa yields nil rather
than costing the caller a clean definitive answer.
The bounds are the smallest and largest CEP that actually exist there,
not the range the Correios publish, and almost nothing between them is
valid — hence ceps and density/1, so nobody reads the pair as a list of
numbers to try.
Diffstat (limited to 'test')
| -rw-r--r-- | test/cepis/lookup_test.exs | 74 | ||||
| -rw-r--r-- | test/cepis_test.exs | 20 | ||||
| -rw-r--r-- | test/support/server_case.ex | 20 |
3 files changed, 114 insertions, 0 deletions
diff --git a/test/cepis/lookup_test.exs b/test/cepis/lookup_test.exs index b68ecbe..39d9d31 100644 --- a/test/cepis/lookup_test.exs +++ b/test/cepis/lookup_test.exs @@ -87,6 +87,80 @@ defmodule Cepis.LookupTest do assert Exception.message(error) =~ "99999999" end + test "a not-found names the municipality the CEP would belong to", %{ + server: server, + client: client + } do + body = not_found_fixture(%{"faixa" => faixa_fixture()}) + FakeServer.respond(server, "/25845000", {404, json(body), []}) + + assert {:error, %Cepis.NotFoundError{cep: "25845000", faixa: faixa} = error} = + Cepis.lookup("25845-000", client) + + assert faixa.localidade == "Areal" + assert faixa.uf == "RJ" + assert faixa.estado == "Rio de Janeiro" + assert faixa.regiao == "Sudeste" + assert faixa.ibge == "3300225" + assert faixa.cep_ini == "25845001" + assert faixa.cep_fim == "25849899" + assert faixa.ceps == 118 + + assert Exception.message(error) =~ "Areal/RJ" + assert Exception.message(error) =~ "25845000 does not exist" + end + + test "a not-found in a band no municipality owns has no faixa", %{ + server: server, + client: client + } do + FakeServer.respond(server, "/99999999", {404, json(not_found_fixture()), []}) + + assert {:error, %Cepis.NotFoundError{faixa: nil} = error} = Cepis.lookup("99999999", client) + assert Exception.message(error) == "CEP 99999999 does not exist in the DNE database" + end + + test "a malformed faixa does not become a parse failure", %{server: server, client: client} do + bodies = [ + not_found_fixture(%{"faixa" => %{}}), + not_found_fixture(%{"faixa" => %{"uf" => "RJ"}}), + not_found_fixture(%{"faixa" => %{"localidade" => ""}}), + not_found_fixture(%{"faixa" => "Areal"}), + # the API omits the field rather than nulling it, but a null must not + # cost the caller the error either + not_found_fixture(%{"faixa" => :null}) + ] + + for {body, index} <- Enum.with_index(bodies) do + path = "/2584500#{index}" + FakeServer.respond(server, path, {404, json(body), []}) + + assert {:error, %Cepis.NotFoundError{faixa: nil}} = + Cepis.lookup(String.trim_leading(path, "/"), client) + end + end + + test "a 404 body that is not JSON is still a clean not-found", %{ + server: server, + client: client + } do + FakeServer.respond(server, "/99999999", {404, "<html>gateway</html>", []}) + + assert {:error, %Cepis.NotFoundError{cep: "99999999", faixa: nil}} = + Cepis.lookup("99999999", client) + end + + test "a faixa keeps whatever the API sends, even partially", %{server: server, client: client} do + body = not_found_fixture(%{"faixa" => %{"localidade" => "Areal", "ceps" => "118"}}) + FakeServer.respond(server, "/25845000", {404, json(body), []}) + + assert {:error, %Cepis.NotFoundError{faixa: faixa}} = Cepis.lookup("25845000", client) + assert faixa.localidade == "Areal" + assert faixa.ceps == 118 + assert faixa.cep_ini == "" + assert Cepis.Faixa.density(faixa) == 0.0 + end + test "a 404 is never retried", %{server: server, client: client} do FakeServer.respond(server, "/99999999", {404, json(%{"erro" => "cep_nao_encontrado"}), []}) diff --git a/test/cepis_test.exs b/test/cepis_test.exs index a6bedb1..df9256a 100644 --- a/test/cepis_test.exs +++ b/test/cepis_test.exs @@ -67,6 +67,26 @@ defmodule CepisTest do end end + describe "Cepis.Faixa.density/1" do + test "measures how sparse the range really is" do + faixa = %Cepis.Faixa{cep_ini: "25845001", cep_fim: "25849899", ceps: 118} + + assert_in_delta Cepis.Faixa.density(faixa), 0.024, 0.001 + assert Cepis.Faixa.density(faixa) < 1.0 + end + + test "is 0.0 when the bounds are not two readable numbers" do + assert Cepis.Faixa.density(%Cepis.Faixa{}) == 0.0 + assert Cepis.Faixa.density(%Cepis.Faixa{cep_ini: "25845001", ceps: 118}) == 0.0 + assert Cepis.Faixa.density(%Cepis.Faixa{cep_ini: "x", cep_fim: "y", ceps: 118}) == 0.0 + end + + test "is 0.0 when the bounds are inverted" do + faixa = %Cepis.Faixa{cep_ini: "25849899", cep_fim: "25845001", ceps: 118} + assert Cepis.Faixa.density(faixa) == 0.0 + end + end + describe "Cepis.Address.formatted_cep/1" do test "adds the mask" do assert Cepis.Address.formatted_cep(%Cepis.Address{cep: "01001000"}) == "01001-000" diff --git a/test/support/server_case.ex b/test/support/server_case.ex index a64bb05..8af08cb 100644 --- a/test/support/server_case.ex +++ b/test/support/server_case.ex @@ -44,8 +44,28 @@ defmodule Cepis.ServerCase do @csv_header "cep,logradouro,complemento,unidade,bairro,localidade,uf,estado,regiao,ibge,gia,ddd,siafi" + @faixa %{ + "localidade" => "Areal", + "uf" => "RJ", + "estado" => "Rio de Janeiro", + "regiao" => "Sudeste", + "ibge" => "3300225", + "cep_ini" => "25845001", + "cep_fim" => "25849899", + "ceps" => 118 + } + def address_fixture(extra \\ %{}), do: Map.merge(@address, extra) + def faixa_fixture(extra \\ %{}), do: Map.merge(@faixa, extra) + + def not_found_fixture(extra \\ %{}) do + Map.merge( + %{"erro" => "cep_nao_encontrado", "mensagem" => "CEP não existe na base do DNE"}, + extra + ) + end + def json(term), do: IO.iodata_to_binary(:json.encode(term)) def csv(rows), do: Enum.join([@csv_header | rows], "\n") <> "\n" |