summaryrefslogtreecommitdiffstats
path: root/t/03-lookup.t
diff options
context:
space:
mode:
authorMurilo Ijanc <[email protected]>2026-07-26 14:40:05 -0300
committerMurilo Ijanc <[email protected]>2026-07-26 14:40:05 -0300
commit0bc578d6d334c7f1ccaf329cd61bb8bce76b7f59 (patch)
tree86f73108f0432fd8330edcaab8b8ae7018322dee /t/03-lookup.t
downloadperl-6661cb35162c38099b86f248b938f5e4d4d11515.tar.gz
Initial importv0.1.0
Diffstat (limited to 't/03-lookup.t')
-rw-r--r--t/03-lookup.t187
1 files changed, 187 insertions, 0 deletions
diff --git a/t/03-lookup.t b/t/03-lookup.t
new file mode 100644
index 0000000..5fb3937
--- /dev/null
+++ b/t/03-lookup.t
@@ -0,0 +1,187 @@
+use strict;
+use warnings;
+use utf8;
+
+use FindBin ();
+use lib "$FindBin::Bin/lib";
+
+use Test::More;
+use TestServer qw(se_address json new_client);
+
+use Cepis;
+
+{
+ my $server = TestServer->new(
+ routes => { '/01001000' => [ 200, json( se_address() ), {} ] } );
+ my $client = new_client($server);
+
+ my $address = $client->lookup('01001-000');
+ is( $address->localidade, 'São Paulo', 'localidade' );
+ is( $address->uf, 'SP', 'uf' );
+ is( $address->logradouro, 'Praça da Sé', 'logradouro' );
+ is( $address->cep, '01001000', 'cep comes back unmasked' );
+ is( $address->formatted_cep, '01001-000', 'formatted_cep applies the mask' );
+ is( $address->unidade, '', 'an absent field is an empty string' );
+ is( $address->geo, undef, 'no geo block means no geo' );
+ is( $server->count('/01001000'), 1, 'exactly one request was made' );
+ $server->stop;
+}
+
+{
+ my $body = { %{ se_address() },
+ geo => { lat => -23.567202, lon => -46.649659, raio_m => 1084, precisao => 'logradouro' }
+ };
+ my $server = TestServer->new( routes => { '/01310100' => [ 200, json($body), {} ] } );
+ my $client = new_client($server);
+
+ my $geo = $client->lookup('01310100')->geo;
+ isa_ok( $geo, 'Cepis::Geo' );
+ cmp_ok( abs( $geo->lat + 23.567202 ), '<', 1e-9, 'lat' );
+ cmp_ok( abs( $geo->lon + 46.649659 ), '<', 1e-9, 'lon' );
+ is( $geo->raio_m, 1084, 'raio_m' );
+ is( $geo->precisao, 'logradouro', 'precisao' );
+ ok( $geo->is_precise, 'a street coordinate is precise' );
+ $server->stop;
+}
+
+{
+ my $body = { %{ se_address() },
+ geo => { lat => -23.5, lon => -46.6, raio_m => 22000, precisao => 'localidade' } };
+ my $server = TestServer->new( routes => { '/01001000' => [ 200, json($body), {} ] } );
+ my $client = new_client($server);
+
+ my $geo = $client->lookup('01001000')->geo;
+ ok( !$geo->is_precise, 'a municipality centroid is not precise' );
+ is( $geo->raio_m, 22000, 'the radius gives the error away' );
+ $server->stop;
+}
+
+{
+ my $body = { %{ se_address() }, geo => { lat => 'not a number' } };
+ my $server = TestServer->new( routes => { '/01001000' => [ 200, json($body), {} ] } );
+ my $client = new_client($server);
+
+ my $address = $client->lookup('01001000');
+ is( $address->geo, undef, 'a malformed geo block is dropped' );
+ is( $address->localidade, 'São Paulo', 'and the address survives it' );
+ $server->stop;
+}
+
+{
+ my $body = { %{ se_address() }, campo_do_futuro => 'value' };
+ my $server = TestServer->new( routes => { '/01001000' => [ 200, json($body), {} ] } );
+ my $client = new_client($server);
+
+ my $address = $client->lookup('01001000');
+ is( $address->field('campo_do_futuro'), 'value', 'an unknown field is preserved' );
+ is( $address->raw->{campo_do_futuro}, 'value', 'and is reachable through raw' );
+ is( $address->localidade, 'São Paulo', 'and does not break construction' );
+ $server->stop;
+}
+
+{
+ my $server = TestServer->new(
+ routes => {
+ '/99999999' => [
+ 404,
+ json( { erro => 'cep_nao_encontrado', mensagem => 'CEP não existe na base do DNE' } ),
+ {}
+ ]
+ }
+ );
+ my $client = new_client($server);
+
+ my $ok = eval { $client->lookup('99999999'); 1 };
+ ok( !$ok, 'a missing CEP throws' );
+ isa_ok( $@, 'Cepis::Error::CEPNotFound' );
+ like( "$@", qr/99999999/, 'the message names the CEP' );
+ is( $server->count('/99999999'), 1, 'a 404 is not retried' );
+ $server->stop;
+}
+
+{
+ my $server = TestServer->new(
+ routes => { '/01001000' => [ 200, json( se_address() ), {} ] } );
+ my $client = new_client($server);
+
+ my $ok = eval { $client->lookup('123'); 1 };
+ ok( !$ok, 'a malformed CEP throws' );
+ isa_ok( $@, 'Cepis::Error::InvalidCEP' );
+ is( scalar( $server->calls ), 0, 'and never leaves the machine' );
+ $server->stop;
+}
+
+{
+ my $server = TestServer->new(
+ routes => {
+ '/00000000' => [
+ 400,
+ json( { erro => 'cep_invalido', mensagem => 'rejected by the API' } ), {}
+ ]
+ }
+ );
+ my $client = new_client($server);
+
+ my $ok = eval { $client->lookup('00000000'); 1 };
+ ok( !$ok, 'a 400 throws' );
+ isa_ok( $@, 'Cepis::Error::InvalidCEP' );
+ like( "$@", qr/rejected by the API/, "the API's own message comes through" );
+ is( $server->count('/00000000'), 1, 'a 400 is not retried' );
+ $server->stop;
+}
+
+{
+ my $server = TestServer->new(
+ routes => {
+ '/01001000' => [ 200, '<html>captive portal</html>', {} ],
+ '/01001001' => [ 200, '[1,2,3]', {} ],
+ }
+ );
+ my $client = new_client($server);
+
+ my $ok = eval { $client->lookup('01001000'); 1 };
+ ok( !$ok, 'a body that is not JSON throws' );
+ isa_ok( $@, 'Cepis::Error::InvalidResponse' );
+ like( "$@", qr/captive portal/, 'the message quotes what came back' );
+
+ $ok = eval { $client->lookup('01001001'); 1 };
+ ok( !$ok, 'a JSON array is not an address' );
+ isa_ok( $@, 'Cepis::Error::InvalidResponse' );
+ $server->stop;
+}
+
+{
+ my $server = TestServer->new(
+ handler => sub {
+ my ( $path, $seen, $headers ) = @_;
+ return [ 200, json( { %{ se_address() }, unidade => $headers->{'user-agent'} } ), {} ];
+ }
+ );
+ my $client = new_client($server);
+
+ like(
+ $client->lookup('01001000')->unidade,
+ qr{\Acepis-perl/0\.1\.0 \(\+https://cep\.is\)\z},
+ 'the request identifies the library'
+ );
+ $server->stop;
+}
+
+{
+ my $server = TestServer->new(
+ handler => sub {
+ my ( $path, $seen, $headers ) = @_;
+ return [ 200, json( { %{ se_address() }, unidade => $headers->{accept} } ), {} ];
+ }
+ );
+ my $client = new_client($server);
+
+ like(
+ $client->lookup('01001000')->unidade,
+ qr{application/json},
+ 'and sends an Accept header'
+ );
+ $server->stop;
+}
+
+done_testing();