diff options
| author | Murilo Ijanc <[email protected]> | 2026-07-27 21:12:05 -0300 |
|---|---|---|
| committer | Murilo Ijanc <[email protected]> | 2026-07-27 21:12:05 -0300 |
| commit | 97b49ae7081b989274b313532ff17c71694097a9 (patch) | |
| tree | 6595e0d5a39d04971a71e886bc3f8cc589741f5d /internal/bot | |
| parent | 83ce95cf10fd9e9d581362453c558239d37ae06e (diff) | |
| download | telegram-0.2.1.tar.gz | |
cep.is/go v0.2.0 exposes the municipality as Error.Faixa, which is what
internal/lookup existed to work around: v0.1.0 discarded the 404 body, so
the bot re-issued the request just to read the block back.
The extra GET on the 404 path is gone, and with it the second timeout,
the body size cap and the "is it still a 404?" check that guarded it.
The replies are byte for byte what they were -- the formatting tests did
not change a single assertion, only the type they build.
Diffstat (limited to 'internal/bot')
| -rw-r--r-- | internal/bot/bot.go | 8 | ||||
| -rw-r--r-- | internal/bot/format.go | 33 | ||||
| -rw-r--r-- | internal/bot/format_test.go | 29 |
3 files changed, 45 insertions, 25 deletions
diff --git a/internal/bot/bot.go b/internal/bot/bot.go index 4abf02c..b361841 100644 --- a/internal/bot/bot.go +++ b/internal/bot/bot.go @@ -13,15 +13,13 @@ import ( cepis "cep.is/go" - "cep.is/telegrambot/internal/lookup" "cep.is/telegrambot/internal/telegram" ) // Lookups is the subset of the cep.is client this bot needs. Depending on the // interface rather than the concrete client keeps the seam narrow and visible. // -// A failure may be a [*lookup.NotFoundError], which still matches -// cepis.ErrCEPNotFound and additionally names the municipality the CEP would +// A failure may be a [*cepis.Error] carrying the municipality the CEP would // belong to; nothing here has to know that, because [ErrorMessage] reads it. type Lookups interface { Lookup(ctx context.Context, cep string) (*cepis.Address, error) @@ -273,8 +271,8 @@ func inlineErrorTitle(err error) string { // Titles and descriptions are plain text for Telegram, so nothing here is // escaped: HTML applies to the message body alone. func inlineErrorDescription(err error) string { - if faixa := lookup.FaixaOf(err); faixa != nil { - return "Cairia em " + faixa.Place() + " — toque para ver" + if faixa := faixaOf(err); faixa != nil { + return "Cairia em " + place(faixa) + " — toque para ver" } return "Toque para enviar o motivo" } diff --git a/internal/bot/format.go b/internal/bot/format.go index b94dee4..86a0ac9 100644 --- a/internal/bot/format.go +++ b/internal/bot/format.go @@ -9,8 +9,6 @@ import ( "time" cepis "cep.is/go" - - "cep.is/telegrambot/internal/lookup" ) // ParseMode is the formatting Telegram applies to every message this bot sends. @@ -197,14 +195,14 @@ const ( // CEPs are spread over nearly five thousand numbers — so its ends are the // extremes of what exists, not a list of what is valid, and the reply says so. func notFoundMessage(err error) string { - faixa := lookup.FaixaOf(err) + faixa := faixaOf(err) if faixa == nil || faixa.Localidade == "" { return notFoundHead + "\n" + notFoundAdvice } var b strings.Builder b.WriteString(notFoundHead + "\n") - b.WriteString("Ele cairia em <b>" + esc(faixa.Place()) + "</b>") + b.WriteString("Ele cairia em <b>" + esc(place(faixa)) + "</b>") count := faixaCount(faixa) span := faixaSpan(faixa) @@ -225,10 +223,33 @@ func notFoundMessage(err error) string { return b.String() } +// faixaOf returns the municipality the API named on a 404, or nil when it named +// none. Any error is safe to pass, including nil: only a *cepis.Error carrying +// a faixa yields one. +func faixaOf(err error) *cepis.Faixa { + var cerr *cepis.Error + if errors.As(err, &cerr) { + return cerr.Faixa + } + return nil +} + +// place is the municipality as it is written to a user: "Areal/RJ", or just +// "Areal" when the API sent no UF. +func place(faixa *cepis.Faixa) string { + if faixa == nil { + return "" + } + if faixa.UF == "" { + return faixa.Localidade + } + return faixa.Localidade + "/" + faixa.UF +} + // faixaCount renders how many CEPs the municipality has, or "" when the API did // not say. Without it the two ends of the range read as a count of one big // block, which is the misreading the number exists to prevent. -func faixaCount(faixa *lookup.Faixa) string { +func faixaCount(faixa *cepis.Faixa) string { switch { case faixa.CEPs <= 0: return "" @@ -241,7 +262,7 @@ func faixaCount(faixa *lookup.Faixa) string { // faixaSpan renders the ends of the range, or "" when they are missing or are // the same number — "de X a X" is not a range, and printing a single CEP there // would hand the user a guess to try. -func faixaSpan(faixa *lookup.Faixa) string { +func faixaSpan(faixa *cepis.Faixa) string { first, last := maskCEP(faixa.CEPIni), maskCEP(faixa.CEPFim) if first == "" || last == "" || first == last { return "" diff --git a/internal/bot/format_test.go b/internal/bot/format_test.go index 513db36..8e10b3e 100644 --- a/internal/bot/format_test.go +++ b/internal/bot/format_test.go @@ -7,8 +7,6 @@ import ( "testing" cepis "cep.is/go" - - "cep.is/telegrambot/internal/lookup" ) func decodeAddress(t *testing.T, body string) *cepis.Address { @@ -118,11 +116,14 @@ func TestErrorMessagesAreDistinct(t *testing.T) { } } -func notFound(faixa *lookup.Faixa) error { - return &lookup.NotFoundError{Faixa: faixa, Err: cepis.ErrCEPNotFound} +// notFound builds the error the client library returns for a CEP absent from +// the DNE, with the municipality the API named on the 404 — or without one, +// for a CEP in a band no municipality owns. +func notFound(faixa *cepis.Faixa) error { + return &cepis.Error{Kind: cepis.ErrCEPNotFound, Faixa: faixa} } -var areal = &lookup.Faixa{ +var areal = &cepis.Faixa{ Localidade: "Areal", UF: "RJ", Estado: "Rio de Janeiro", Regiao: "Sudeste", IBGE: "3300225", CEPIni: "25845001", CEPFim: "25849899", CEPs: 118, } @@ -168,7 +169,7 @@ func TestNotFoundWithoutFaixaIsUnchanged(t *testing.T) { for name, err := range map[string]error{ "plain sentinel": cepis.ErrCEPNotFound, "no faixa": notFound(nil), - "empty faixa": notFound(&lookup.Faixa{}), + "empty faixa": notFound(&cepis.Faixa{}), } { if got := ErrorMessage(err); got != want { t.Fatalf("%s:\n got %q\nwant %q", name, got, want) @@ -177,7 +178,7 @@ func TestNotFoundWithoutFaixaIsUnchanged(t *testing.T) { } func TestNotFoundEscapesTheMunicipality(t *testing.T) { - text := ErrorMessage(notFound(&lookup.Faixa{ + text := ErrorMessage(notFound(&cepis.Faixa{ Localidade: "Santa <b>Rita</b> & Cia", UF: "M&G", CEPIni: "25845001", CEPFim: "25849899", CEPs: 2, })) @@ -194,32 +195,32 @@ func TestNotFoundEscapesTheMunicipality(t *testing.T) { // take the sentence down with it. func TestNotFoundDegradesFieldByField(t *testing.T) { cases := map[string]struct { - faixa *lookup.Faixa + faixa *cepis.Faixa present []string absent []string }{ "no count": { - faixa: &lookup.Faixa{Localidade: "Areal", UF: "RJ", CEPIni: "25845001", CEPFim: "25849899"}, + faixa: &cepis.Faixa{Localidade: "Areal", UF: "RJ", CEPIni: "25845001", CEPFim: "25849899"}, present: []string{"Areal/RJ", "25845-001", "25849-899", "esparsa"}, absent: []string{"CEPs,"}, }, "no range": { - faixa: &lookup.Faixa{Localidade: "Areal", UF: "RJ", CEPs: 118}, + faixa: &cepis.Faixa{Localidade: "Areal", UF: "RJ", CEPs: 118}, present: []string{"Areal/RJ", "118 CEPs"}, absent: []string{"<code>", "esparsa"}, }, "only the name": { - faixa: &lookup.Faixa{Localidade: "Areal"}, + faixa: &cepis.Faixa{Localidade: "Areal"}, present: []string{"cairia em <b>Areal</b>."}, absent: []string{"<code>", "esparsa", "Areal/"}, }, "single CEP": { - faixa: &lookup.Faixa{Localidade: "Vila", UF: "SP", CEPIni: "12345678", CEPFim: "12345678", CEPs: 1}, + faixa: &cepis.Faixa{Localidade: "Vila", UF: "SP", CEPIni: "12345678", CEPFim: "12345678", CEPs: 1}, present: []string{"1 CEP."}, absent: []string{"12345-678"}, }, "unusable range": { - faixa: &lookup.Faixa{Localidade: "Areal", UF: "RJ", CEPIni: "abc", CEPFim: "2584", CEPs: 118}, + faixa: &cepis.Faixa{Localidade: "Areal", UF: "RJ", CEPIni: "abc", CEPFim: "2584", CEPs: 118}, present: []string{"118 CEPs."}, absent: []string{"abc", "2584"}, }, @@ -251,7 +252,7 @@ func TestInlineErrorDescriptionNamesTheMunicipality(t *testing.T) { } // Titles and descriptions are plain text: escaping them would show the // entities to the user. - got := inlineErrorDescription(notFound(&lookup.Faixa{Localidade: "Santa & Cia", UF: "SP"})) + got := inlineErrorDescription(notFound(&cepis.Faixa{Localidade: "Santa & Cia", UF: "SP"})) if !strings.Contains(got, "Santa & Cia/SP") { t.Fatalf("description = %q", got) } |