tgbot: тесты на экранирование пути/причин и формат download_id в opErr

Финальная сверка спек notifications отметила два сценария спеки без
прицельного теста (спецсимволы в пути раскладки/причинах, формат id в
opErr) — поведение верное, но регресс не ловился. Закрываю тестами.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
av
2026-07-18 16:09:48 +03:00
co-authored by Claude Opus 4.8
parent f75d6b1f91
commit 023fdacda5
+33
View File
@@ -413,6 +413,39 @@ func TestBot_NotifyFailedEscapesExternalText(t *testing.T) {
}
}
// Карточка ревью: спецсимволы во внешнем пути раскладки и в причинах
// распознавания экранируются (esc после tailPath/join), сырая разметка не
// просачивается. Закрывает сценарий «Внешний путь и причины экранируются».
func TestReviewCard_EscapesPathAndReasons(t *testing.T) {
b, _, _, _ := newTestBot(t, []int64{7})
rd := reviewData(store.StateReview)
rd.Recognition.Reasons = `["Tom & Jerry <b>x</b>"]`
rd.Preview[0].Dst = "/srv/media/series/A & B <x>/file <y>.mkv"
text, _ := b.renderCard(rd)
if !strings.Contains(text, "Tom &amp; Jerry &lt;b&gt;x&lt;/b&gt;") {
t.Errorf("причины не экранированы:\n%s", text)
}
if !strings.Contains(text, "A &amp; B &lt;x&gt;") || !strings.Contains(text, "file &lt;y&gt;.mkv") {
t.Errorf("путь раскладки не экранирован:\n%s", text)
}
if strings.Contains(text, "<b>") || strings.Contains(text, "<x>") {
t.Errorf("сырая разметка просочилась:\n%s", text)
}
}
// opErr: при наличии download id он уходит моноширинным (tap-to-copy) под
// ключом download_id=; без id — дружелюбный текст без ключа. Закрывает сценарий
// «Id в сообщении об ошибке копируется».
func TestOpErr_IDMonospace(t *testing.T) {
if got := opErr("Не удалось выполнить действие", tid); !strings.Contains(got, "download_id="+idCode(tid)) {
t.Errorf("id не моноширинным под ключом download_id: %q", got)
}
if got := opErr("Готово", ""); strings.Contains(got, "download_id") {
t.Errorf("без id ключа download_id быть не должно: %q", got)
}
}
func TestBot_CallbackRetry(t *testing.T) {
b, _, _, rev := newTestBot(t, []int64{7})
rev.data = reviewData(store.StateFailed)