diff options
| author | Murilo Ijanc <[email protected]> | 2026-07-27 20:25:04 -0300 |
|---|---|---|
| committer | Murilo Ijanc <[email protected]> | 2026-07-27 20:53:07 -0300 |
| commit | 82d92ed4291663bae94014b4363064dbb26c6a51 (patch) | |
| tree | 69d91a59c955f1e6ec6fc0007324b5d73b3f0d01 /test | |
| parent | 8e719fc715eb7ae9aa1c842e633f15b5c6cd3688 (diff) | |
| download | dart-82d92ed4291663bae94014b4363064dbb26c6a51.tar.gz | |
A CEP that fails a lookup is rarely a random number: it is usually someone
who knows the city and guessed the digits, and the classic guess is the
-000 that 957 municipalities never received. The API now attaches a faixa
block to the 404 naming the municipality that band belongs to, so the
caller can answer "no, but you were looking at Areal/RJ" instead of just
"no".
It stays an error. Faixa hangs off CepNotFoundException, never off Address,
and cepIni/cepFim are the extremes that actually exist in the municipality
rather than the range the Correios publish — echoing back the published
start would return the very CEP that just failed. The interval is sparse,
which is what ceps is for; it is not a list of alternatives.
Parsing is deliberately forgiving: a missing, empty or malformed block is
null. Losing a clean not-found to a parse error over the hint attached to
it would be a bad trade.
Diffstat (limited to 'test')
| -rw-r--r-- | test/cepis_test.dart | 166 |
1 files changed, 155 insertions, 11 deletions
diff --git a/test/cepis_test.dart b/test/cepis_test.dart index 54df88f..e09601f 100644 --- a/test/cepis_test.dart +++ b/test/cepis_test.dart @@ -23,6 +23,23 @@ const Map<String, dynamic> seAddress = <String, dynamic>{ 'siafi': '7107', }; +const Map<String, dynamic> arealFaixa = <String, dynamic>{ + 'localidade': 'Areal', + 'uf': 'RJ', + 'estado': 'Rio de Janeiro', + 'regiao': 'Sudeste', + 'ibge': '3300225', + 'cep_ini': '25845001', + 'cep_fim': '25849899', + 'ceps': 118, +}; + +String notFound({Map<String, dynamic>? faixa}) => jsonEncode(<String, dynamic>{ + 'erro': 'cep_nao_encontrado', + 'mensagem': 'CEP não existe na base do DNE', + if (faixa != null) 'faixa': faixa, + }); + const String csvHeader = 'cep,logradouro,complemento,unidade,bairro,localidade,uf,estado,regiao,' 'ibge,gia,ddd,siafi'; @@ -184,16 +201,7 @@ void main() { }); test('404 becomes CepNotFoundException and is not retried', () async { - server.routes.respond( - '/99999999', - Reply( - 404, - jsonEncode(<String, String>{ - 'erro': 'cep_nao_encontrado', - 'mensagem': 'CEP não existe na base do DNE', - }), - ), - ); + server.routes.respond('/99999999', Reply(404, notFound())); await expectLater( client.lookup('99999999'), @@ -208,6 +216,127 @@ void main() { expect(server.routes.count('/99999999'), 1); }); + test('a 404 with no faixa leaves it null', () async { + server.routes.respond('/99999999', Reply(404, notFound())); + + await expectLater( + client.lookup('99999999'), + throwsA( + isA<CepNotFoundException>().having( + (CepNotFoundException e) => e.faixa, + 'faixa', + isNull, + ), + ), + ); + }); + + test('a 404 carries the municipality the CEP would belong to', () async { + server.routes.respond( + '/25845000', + Reply(404, notFound(faixa: arealFaixa)), + ); + + await expectLater( + client.lookup('25845000'), + throwsA( + isA<CepNotFoundException>() + .having((CepNotFoundException e) => e.cep, 'cep', '25845000') + .having( + (CepNotFoundException e) => e.faixa, + 'faixa', + const Faixa( + localidade: 'Areal', + uf: 'RJ', + estado: 'Rio de Janeiro', + regiao: 'Sudeste', + ibge: '3300225', + cepIni: '25845001', + cepFim: '25849899', + ceps: 118, + ), + ), + ), + ); + }); + + test('the faixa does not turn a 404 into an address', () async { + server.routes.respond( + '/25845000', + Reply(404, notFound(faixa: arealFaixa)), + ); + + await expectLater( + client.lookup('25845000'), + throwsA(isA<CepNotFoundException>()), + ); + expect(server.routes.count('/25845000'), 1); + }); + + test('the message names the municipality when there is one', () async { + server.routes.respond( + '/25845000', + Reply(404, notFound(faixa: arealFaixa)), + ); + + try { + await client.lookup('25845000'); + fail('expected CepNotFoundException'); + } on CepNotFoundException catch (error) { + expect(error.toString(), contains('Areal/RJ')); + expect(error.toString(), contains('118 CEPs')); + } + }); + + test('an unreadable faixa is null, not a failure', () async { + final bodies = <String>[ + notFound(faixa: <String, dynamic>{}), + notFound(faixa: <String, dynamic>{'uf': 'RJ'}), + jsonEncode(<String, dynamic>{ + 'erro': 'cep_nao_encontrado', + 'faixa': 'Areal', + }), + jsonEncode(<String, dynamic>{ + 'erro': 'cep_nao_encontrado', + 'faixa': <String>[], + }), + '<html>portal</html>', + '', + ]; + + for (final String body in bodies) { + server.routes.respond('/99999999', Reply(404, body)); + + await expectLater( + client.lookup('99999999'), + throwsA( + isA<CepNotFoundException>().having( + (CepNotFoundException e) => e.faixa, + 'faixa', + isNull, + ), + ), + reason: body, + ); + } + }); + + test('a faixa missing the counts still names the municipality', () async { + server.routes.respond( + '/25845000', + Reply(404, notFound(faixa: <String, dynamic>{'localidade': 'Areal'})), + ); + + try { + await client.lookup('25845000'); + fail('expected CepNotFoundException'); + } on CepNotFoundException catch (error) { + expect(error.faixa!.localidade, 'Areal'); + expect(error.faixa!.uf, ''); + expect(error.faixa!.ceps, 0); + } + }); + test('an invalid CEP never leaves the machine', () async { await expectLater( client.lookup('123'), @@ -265,7 +394,7 @@ void main() { server.routes.respond('/01001000', Reply(200, jsonEncode(seAddress))); await client.lookup('01001000'); - expect(server.routes.userAgents.single, startsWith('cepis-dart/0.1.0')); + expect(server.routes.userAgents.single, startsWith('cepis-dart/0.2.0')); }); }); @@ -628,5 +757,20 @@ void main() { expect(one, two); expect(one.hashCode, two.hashCode); }); + + test('two identical faixas are equal', () { + final one = Faixa.fromJson(Map<String, dynamic>.of(arealFaixa)); + final two = Faixa.fromJson(Map<String, dynamic>.of(arealFaixa)); + expect(one, two); + expect(one.hashCode, two.hashCode); + }); + + test('a faixa without a municipality is nothing to report', () { + expect(Faixa.fromJson(<String, dynamic>{}), isNull); + expect( + Faixa.fromJson(<String, dynamic>{'localidade': '', 'uf': 'RJ'}), + isNull, + ); + }); }); } |