X-Git-Url: https://git.giacomolli.uk/onechat/blobdiff_plain/153f3f9b4b09d521412eacca30eddeed395c3f41..4a931bccab5879ab708647b2df8dadc052f128bf:/telegram_test.go?ds=sidebyside diff --git a/telegram_test.go b/telegram_test.go index a1a1ed2..81e6e18 100644 --- a/telegram_test.go +++ b/telegram_test.go @@ -21,7 +21,7 @@ func TestOwnerTalksToTheAgentThroughTelegram(t *testing.T) { telegram := newTelegramFake(t) bot, _ := telegramStartTestBot(t, telegram) - socket := startTestDaemonWithBot(t, server, bot) + socket := daemonStartTestWithBot(t, server, bot) terminal := terminalStartTestClient(t, socket) terminal.WaitFor(t, "[connected to OneChat]") @@ -43,7 +43,7 @@ func TestOwnerTalksToTheAgentThroughTelegram(t *testing.T) { func TestBotIgnoresEveryoneButTheOwner(t *testing.T) { telegram := newTelegramFake(t) bot, logs := telegramStartTestBot(t, telegram) - socket := startTestDaemonWithBot(t, newModelFake(t), bot) + socket := daemonStartTestWithBot(t, newModelFake(t), bot) terminal := terminalStartTestClient(t, socket) terminal.WaitFor(t, "[connected to OneChat]") @@ -81,7 +81,7 @@ func TestBotIgnoresEveryoneButTheOwner(t *testing.T) { func TestBotAnswersThatOnlyTextIsSupported(t *testing.T) { telegram := newTelegramFake(t) bot, _ := telegramStartTestBot(t, telegram) - startTestDaemonWithBot(t, newModelFake(t), bot) + daemonStartTestWithBot(t, newModelFake(t), bot) telegram.Add(TelegramUpdate{ UpdateID: 1, @@ -106,7 +106,7 @@ func TestStopFromTelegramInterruptsTheTurn(t *testing.T) { telegram := newTelegramFake(t) bot, _ := telegramStartTestBot(t, telegram) - startTestDaemonWithBot(t, server, bot) + daemonStartTestWithBot(t, server, bot) telegram.Add(TelegramUpdate{ UpdateID: 1, @@ -149,7 +149,7 @@ func TestBotStartsAtTheStoredOffset(t *testing.T) { Message: telegramOwnerMessage("new after the restart"), }) - socket := startTestDaemonWithBot(t, server, bot) + socket := daemonStartTestWithBot(t, server, bot) terminal := terminalStartTestClient(t, socket) terminal.WaitFor(t, "[connected to OneChat]") telegramWaitForSent(t, telegram, "ok") @@ -189,7 +189,7 @@ func TestBotTriesAgainAfterFailures(t *testing.T) { } bot, logs := telegramStartTestBot(t, telegram) - startTestDaemonWithBot(t, server, bot) + daemonStartTestWithBot(t, server, bot) telegram.Add(TelegramUpdate{ UpdateID: 1, @@ -236,7 +236,7 @@ func TestRepliesGoAsRichMessages(t *testing.T) { telegram := newTelegramFake(t) bot, _ := telegramStartTestBot(t, telegram) - socket := startTestDaemonWithBot(t, server, bot) + socket := daemonStartTestWithBot(t, server, bot) terminal := terminalStartTestClient(t, socket) terminal.WaitFor(t, "[connected to OneChat]") @@ -390,6 +390,111 @@ func TestLongReplyGoesAsRichMessagesSplitBetweenBlocks(t *testing.T) { require.Equal(t, []string{paragraphs, table}, telegram.Sent()) } +func TestReplyTagsGoAsText(t *testing.T) { + testCases := []struct { + name string + status int + sent []string + }{ + { + name: "rich message escapes the tag outside code", + sent: []string{"a <details> & tag and ``"}, + }, + { + name: "entity fallback shows the tag as written", + status: http.StatusBadRequest, + sent: []string{"a
& tag and "}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + telegram := newTelegramFake(t) + telegram.fail = func(call TelegramFakeCall) (int, string) { + if call.method != "sendRichMessage" { + return 0, "" + } + + return tc.status, "Bad Request" + } + + bot, _ := telegramStartTestBot(t, telegram) + bot.post(t.Context(), Event{ + Kind: "reply", + Text: "a
& tag and ``", + }) + + require.Equal(t, tc.sent, telegram.Sent()) + }) + } +} + +func TestLongReplySplitCountsTheEscapedTags(t *testing.T) { + paragraph := "A tag.\n\n" + count := telegramRichBytes / len(paragraph) + reply := strings.Repeat(paragraph, count) + require.LessOrEqual(t, len(reply), telegramRichBytes) + + telegram := newTelegramFake(t) + bot, _ := telegramStartTestBot(t, telegram) + bot.post(t.Context(), Event{ + Kind: "reply", + Text: reply, + }) + + sent := telegram.Sent() + require.Len(t, sent, 2) + require.Equal(t, telegramEscapeTags(reply), strings.Join(sent, "")) + + for _, markdown := range sent { + require.LessOrEqual(t, len(markdown), telegramRichBytes) + } +} + +func TestRefusedRichPartGoesWithTheTextAsWritten(t *testing.T) { + paragraph := "A & c.\n\n" + reply := strings.Repeat(paragraph, telegramRichBytes/len(paragraph)) + + telegram := newTelegramFake(t) + refused := false + telegram.fail = func(call TelegramFakeCall) (int, string) { + if call.method != "sendRichMessage" || refused { + return 0, "" + } + + refused = true + + return http.StatusBadRequest, "Bad Request" + } + + bot, _ := telegramStartTestBot(t, telegram) + bot.post(t.Context(), Event{ + Kind: "reply", + Text: reply, + }) + + var fallback, rich []string + for _, call := range telegram.Calls() { + switch { + case !call.ok: + case call.method == "sendMessage": + fallback = append(fallback, call.params["text"].(string)) + case call.method == "sendRichMessage": + rich = append(rich, call.params["rich_message"].(map[string]any)["markdown"].(string)) + } + } + + require.Greater(t, len(fallback), 1) + require.Len(t, rich, 1) + require.True(t, strings.HasPrefix(reply, strings.Join(fallback, "")), "fallback text is not the reply as written") + + for _, text := range fallback { + require.LessOrEqual(t, telegramUTF16Units(text), telegramMessageUnits) + } + + require.True(t, reply == strings.Join(fallback, "")+telegramUnescapeTags(rich[0]), "reply is not sent once and whole") +} + func TestRefusedEntitiesGoAgainAsPlainText(t *testing.T) { telegram := newTelegramFake(t) telegram.fail = func(call TelegramFakeCall) (int, string) { @@ -423,7 +528,7 @@ func TestBotLogsNoTokenWhenTheNetworkFails(t *testing.T) { telegram.Close() bot, logs := telegramStartTestBot(t, telegram) - startTestDaemonWithBot(t, newModelFake(t), bot) + daemonStartTestWithBot(t, newModelFake(t), bot) require.Eventually(t, func() bool { return strings.Count(logs.String(), "no valid answer") >= 2 @@ -568,6 +673,12 @@ func TestSplitRich(t *testing.T) { limit: 3, parts: []string{"ab", "\u00e9c", "d"}, }, + { + name: "long line is not cut inside an entity", + markdown: "abc&def", + limit: 6, + parts: []string{"abc", "&d", "ef"}, + }, } for _, tc := range testCases {