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, 'captive portal', {} ], '/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\.2\.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();