textmachine/backend/internal/obs/logging_truncate_test.go

56 lines
1.9 KiB
Go
Raw Blame History

package obs
import (
"strings"
"testing"
)
// logging_truncate_test.go: the logged-body truncation keeps BOTH ends (mini-run finding Д3). The
// mini-run enabled LOG_LLM_BODIES specifically to read the banknote block a model appends at the END
// of its answer, and a tail-cut had removed exactly that — the debug channel was documented as the way
// to see it and could not show it.
func TestTruncateForLogKeepsBothEnds(t *testing.T) {
body := []byte("HEAD-MARKER" + strings.Repeat("x", 5000) + "TAIL-MARKER")
got := truncateForLog(body, 200)
if !strings.Contains(got, "HEAD-MARKER") {
t.Errorf("the head must survive truncation:\n%s", got)
}
if !strings.Contains(got, "TAIL-MARKER") {
t.Errorf("the TAIL must survive truncation — the banknote block lives there:\n%s", got)
}
if !strings.Contains(got, "truncated") {
t.Errorf("a truncated body must say so (else it reads as a short one):\n%s", got)
}
if len(got) > 400 {
t.Errorf("truncation must actually bound the output, got %d bytes", len(got))
}
}
// TestTruncateForLogShortBodyUnchanged: a body under the cap is passed through byte-for-byte.
func TestTruncateForLogShortBodyUnchanged(t *testing.T) {
body := []byte("короткое тело ответа")
if got := truncateForLog(body, 4096); got != string(body) {
t.Errorf("a short body must be unchanged, got %q", got)
}
}
// TestTruncateForLogCutsOnRuneBoundaries: the cut must not split a multi-byte rune, or the log line
// becomes invalid UTF-8 — the exact shape that makes a Cyrillic transcript unreadable in a viewer.
func TestTruncateForLogCutsOnRuneBoundaries(t *testing.T) {
for cap := 20; cap < 60; cap++ {
got := truncateForLog([]byte(strings.Repeat("ы", 400)), cap)
if !isValidUTF8(got) {
t.Fatalf("cap=%d produced invalid UTF-8: %q", cap, got)
}
}
}
func isValidUTF8(s string) bool {
for _, r := range s {
if r == '<27>' {
return false
}
}
return true
}