namespace Cepis.Tests;
/// A single lookup: the happy path, the coordinate, and the refusals.
public sealed class LookupTests : HttpTestBase
{
[Fact]
public async Task ReadsEveryField()
{
Server.Respond("/01001000", Reply.Of(200, Fixtures.SeAddress));
var address = await Client.LookupAsync("01001-000");
Assert.Equal("01001000", address.Cep);
Assert.Equal("01001-000", address.FormattedCep);
Assert.Equal("Praça da Sé", address.Logradouro);
Assert.Equal("lado ímpar", address.Complemento);
Assert.Equal("", address.Unidade);
Assert.Equal("Sé", address.Bairro);
Assert.Equal("São Paulo", address.Localidade);
Assert.Equal("SP", address.UF);
Assert.Equal("São Paulo", address.Estado);
Assert.Equal("Sudeste", address.Regiao);
Assert.Equal("3550308", address.Ibge);
Assert.Equal("1004", address.Gia);
Assert.Equal("11", address.Ddd);
Assert.Equal("7107", address.Siafi);
}
[Fact]
public async Task TheMaskIsStrippedBeforeTheRequest()
{
Server.Respond("/01001000", Reply.Of(200, Fixtures.SeAddress));
await Client.LookupAsync("01001-000");
Assert.Equal("/01001000", Assert.Single(Server.Calls).Path);
}
[Fact]
public async Task ReadsTheCoordinate()
{
Server.Respond("/01001000", Reply.Of(200, Fixtures.SeAddress));
var address = await Client.LookupAsync("01001000");
var geo = address.Geo;
Assert.NotNull(geo);
Assert.Equal(-23.567202, geo.Lat, 6);
Assert.Equal(-46.649659, geo.Lon, 6);
Assert.Equal(1084, geo.RaioM);
Assert.Equal("logradouro", geo.Precisao);
Assert.True(geo.IsPrecise);
}
[Fact]
public async Task AnAbsentCoordinateIsNull()
{
Server.Respond("/20040020", Reply.Of(200, Fixtures.NoGeoAddress));
var address = await Client.LookupAsync("20040020");
Assert.Null(address.Geo);
Assert.Equal("Rio de Janeiro", address.Localidade);
}
[Fact]
public async Task AMalformedCoordinateDoesNotLoseTheAddress()
{
Server.Respond("/01001000", Reply.Of(200, Fixtures.BrokenGeoAddress));
var address = await Client.LookupAsync("01001000");
Assert.Null(address.Geo);
Assert.Equal("São Paulo", address.Localidade);
}
[Fact]
public async Task ACoordinateOfTheWrongShapeIsDropped()
{
Server.Respond("/01001000", Reply.Of(200, """{"cep":"01001000","localidade":"X","geo":[]}"""));
var address = await Client.LookupAsync("01001000");
Assert.Null(address.Geo);
Assert.Equal("X", address.Localidade);
}
[Fact]
public async Task AFieldThisLibraryDoesNotKnowIsKept()
{
Server.Respond("/01001000", Reply.Of(200, Fixtures.FutureAddress));
var address = await Client.LookupAsync("01001000");
Assert.Equal("São Paulo", address.Localidade);
var extra = address.Extra;
Assert.NotNull(extra);
Assert.Equal("01000000", extra["cep_pai"].GetString());
}
[Fact]
public async Task AMissingCepThrows()
{
Server.Respond("/99999999", Reply.Of(404, Fixtures.NotFound));
var failure = await Assert.ThrowsAsync(
() => Client.LookupAsync("99999999"));
Assert.Contains("99999999", failure.Message, StringComparison.Ordinal);
}
[Fact]
public async Task A404IsNeverRetried()
{
Server.Respond("/99999999", Reply.Of(404, Fixtures.NotFound));
await Assert.ThrowsAsync(() => Client.LookupAsync("99999999"));
Assert.Equal(1, Server.Count("/99999999"));
}
[Fact]
public async Task A400CarriesTheApiMessage()
{
Server.Respond("/00000000", Reply.Of(400, Fixtures.InvalidCep));
var failure = await Assert.ThrowsAsync(
() => Client.LookupAsync("00000000"));
Assert.Equal("CEP deve ter 8 dígitos", failure.Message);
Assert.Equal(1, Server.Count("/00000000"));
}
[Fact]
public async Task AMalformedCepCostsNoRequest()
{
await Assert.ThrowsAsync(() => Client.LookupAsync("1234567"));
Assert.Empty(Server.Calls);
}
[Fact]
public async Task AnUnintelligibleBodyIsDiagnosed()
{
Server.Respond("/01001000", Reply.Of(200, "captive portal"));
await Assert.ThrowsAsync(() => Client.LookupAsync("01001000"));
}
[Fact]
public async Task AJsonBodyThatIsNotAnObjectIsDiagnosed()
{
Server.Respond("/01001000", Reply.Of(200, "null"));
await Assert.ThrowsAsync(() => Client.LookupAsync("01001000"));
}
[Fact]
public async Task ACancelledCallDoesNotBecomeANetworkError()
{
Server.Respond("/01001000", Reply.Of(200, Fixtures.SeAddress));
using var cancellation = new CancellationTokenSource();
await cancellation.CancelAsync();
await Assert.ThrowsAnyAsync(
() => Client.LookupAsync("01001000", cancellation.Token));
}
}