summaryrefslogtreecommitdiffstats
path: root/internal/bot/format_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/bot/format_test.go')
-rw-r--r--internal/bot/format_test.go141
1 files changed, 141 insertions, 0 deletions
diff --git a/internal/bot/format_test.go b/internal/bot/format_test.go
index 56b8dda..513db36 100644
--- a/internal/bot/format_test.go
+++ b/internal/bot/format_test.go
@@ -7,6 +7,8 @@ import (
"testing"
cepis "cep.is/go"
+
+ "cep.is/telegrambot/internal/lookup"
)
func decodeAddress(t *testing.T, body string) *cepis.Address {
@@ -116,6 +118,145 @@ func TestErrorMessagesAreDistinct(t *testing.T) {
}
}
+func notFound(faixa *lookup.Faixa) error {
+ return &lookup.NotFoundError{Faixa: faixa, Err: cepis.ErrCEPNotFound}
+}
+
+var areal = &lookup.Faixa{
+ Localidade: "Areal", UF: "RJ", Estado: "Rio de Janeiro", Regiao: "Sudeste",
+ IBGE: "3300225", CEPIni: "25845001", CEPFim: "25849899", CEPs: 118,
+}
+
+func TestNotFoundNamesTheMunicipality(t *testing.T) {
+ text := ErrorMessage(notFound(areal))
+
+ for _, needed := range []string{
+ "não encontrado", "Areal/RJ", "118 CEPs", "25845-001", "25849-899",
+ "esparsa", "Confira os oito dígitos",
+ } {
+ if !strings.Contains(text, needed) {
+ t.Fatalf("reply is missing %q:\n%s", needed, text)
+ }
+ }
+}
+
+// The municipality is context on a failure. A reply that looks like a hit would
+// have someone write the city down as the answer.
+func TestNotFoundDoesNotLookLikeAnAnswer(t *testing.T) {
+ text := ErrorMessage(notFound(areal))
+
+ if strings.Contains(text, "📮") {
+ t.Fatalf("the found-address marker leaked into a failure:\n%s", text)
+ }
+ if !strings.HasPrefix(text, notFoundHead) {
+ t.Fatalf("the reply must open by saying the CEP does not exist:\n%s", text)
+ }
+ if !strings.HasSuffix(text, notFoundAdvice) {
+ t.Fatalf("the reply must close with the usual advice:\n%s", text)
+ }
+ if strings.Contains(text, "25845-000") {
+ t.Fatalf("the reply suggests the CEP that just failed:\n%s", text)
+ }
+}
+
+// Absence of a faixa must be indistinguishable from the day before this
+// existed, byte for byte.
+func TestNotFoundWithoutFaixaIsUnchanged(t *testing.T) {
+ const want = "🔍 CEP não encontrado na base dos Correios (DNE).\n" +
+ "Confira os oito dígitos — a base é atualizada a cada quinze dias."
+
+ for name, err := range map[string]error{
+ "plain sentinel": cepis.ErrCEPNotFound,
+ "no faixa": notFound(nil),
+ "empty faixa": notFound(&lookup.Faixa{}),
+ } {
+ if got := ErrorMessage(err); got != want {
+ t.Fatalf("%s:\n got %q\nwant %q", name, got, want)
+ }
+ }
+}
+
+func TestNotFoundEscapesTheMunicipality(t *testing.T) {
+ text := ErrorMessage(notFound(&lookup.Faixa{
+ Localidade: "Santa <b>Rita</b> & Cia", UF: "M&G",
+ CEPIni: "25845001", CEPFim: "25849899", CEPs: 2,
+ }))
+
+ if strings.Contains(text, "<b>Rita</b>") {
+ t.Fatalf("the municipality name must be escaped:\n%s", text)
+ }
+ if !strings.Contains(text, "Santa &lt;b&gt;Rita&lt;/b&gt; &amp; Cia/M&amp;G") {
+ t.Fatalf("escaping is wrong:\n%s", text)
+ }
+}
+
+// Every field of the faixa is optional in practice, and a missing one may not
+// take the sentence down with it.
+func TestNotFoundDegradesFieldByField(t *testing.T) {
+ cases := map[string]struct {
+ faixa *lookup.Faixa
+ present []string
+ absent []string
+ }{
+ "no count": {
+ faixa: &lookup.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},
+ present: []string{"Areal/RJ", "118 CEPs"},
+ absent: []string{"<code>", "esparsa"},
+ },
+ "only the name": {
+ faixa: &lookup.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},
+ present: []string{"1 CEP."},
+ absent: []string{"12345-678"},
+ },
+ "unusable range": {
+ faixa: &lookup.Faixa{Localidade: "Areal", UF: "RJ", CEPIni: "abc", CEPFim: "2584", CEPs: 118},
+ present: []string{"118 CEPs."},
+ absent: []string{"abc", "2584"},
+ },
+ }
+
+ for name, tc := range cases {
+ t.Run(name, func(t *testing.T) {
+ text := ErrorMessage(notFound(tc.faixa))
+ for _, needed := range tc.present {
+ if !strings.Contains(text, needed) {
+ t.Fatalf("missing %q:\n%s", needed, text)
+ }
+ }
+ for _, unwanted := range tc.absent {
+ if strings.Contains(text, unwanted) {
+ t.Fatalf("should not carry %q:\n%s", unwanted, text)
+ }
+ }
+ })
+ }
+}
+
+func TestInlineErrorDescriptionNamesTheMunicipality(t *testing.T) {
+ if got := inlineErrorDescription(notFound(areal)); got != "Cairia em Areal/RJ — toque para ver" {
+ t.Fatalf("description = %q", got)
+ }
+ if got := inlineErrorDescription(cepis.ErrCEPNotFound); got != "Toque para enviar o motivo" {
+ t.Fatalf("description without a faixa = %q", got)
+ }
+ // 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"}))
+ if !strings.Contains(got, "Santa & Cia/SP") {
+ t.Fatalf("description = %q", got)
+ }
+}
+
func TestHelpMentionsEveryEntryPoint(t *testing.T) {
text := HelpMessage("cepisbot")
for _, needed := range []string{"01001-000", "/cep 01001000", "@cepisbot 01001000", "https://cep.is"} {