fix(search): truncate match lines on a rune boundary

truncateLine byte-sliced s[:maxLen-3], which can split a multibyte UTF-8 character and emit an invalid sequence (mojibake) on long non-ASCII match lines. Back off to the nearest rune boundary via utf8.RuneStart. Adds TestTruncateLineRuneSafe.
This commit is contained in:
2026-06-20 00:33:34 +01:00
parent 96db1c7749
commit 549ec2a177
2 changed files with 25 additions and 2 deletions
+17
View File
@@ -8,10 +8,27 @@ import (
"path/filepath"
"strings"
"testing"
"unicode/utf8"
"github.com/lukaszraczylo/mcp-filepuff/internal/config"
)
// truncateLine must back off to a rune boundary so multibyte characters are
// never split into invalid UTF-8.
func TestTruncateLineRuneSafe(t *testing.T) {
s := strings.Repeat("é", 200) // 2 bytes each → 400 bytes
out := truncateLine(s, 50)
if !utf8.ValidString(out) {
t.Errorf("truncated output is not valid UTF-8: %q", out)
}
if !strings.HasSuffix(out, "...") {
t.Errorf("expected ellipsis suffix, got %q", out)
}
if got := truncateLine("hi", 50); got != "hi" {
t.Errorf("short string should be unchanged, got %q", got)
}
}
func TestNew(t *testing.T) {
cfg := config.Default()
logger := slog.New(slog.NewTextHandler(os.Stderr, nil))