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)); } }