package logscanner import ( "regexp" "strings" "testing" "unicode/utf8" ) func TestTruncateUTF8(t *testing.T) { cases := []struct { name string in string maxBytes int want string }{ { name: "shorter than cap untouched", in: "hello", maxBytes: 100, want: "hello", }, { name: "ASCII truncation", in: "abcdefghij", maxBytes: 5, want: "abcde…", }, { name: "cuts on rune boundary inside multibyte", in: "abcdé", maxBytes: 5, want: "abcd…", }, { name: "preserves valid utf-8 when cap lands mid-codepoint", in: "ééééééé", maxBytes: 5, want: "éé…", }, { name: "empty input untouched", in: "", maxBytes: 5, want: "", }, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { got := truncateUTF8(c.in, c.maxBytes) if got != c.want { t.Errorf("got %q want %q", got, c.want) } if !utf8.ValidString(got) { t.Errorf("result not valid UTF-8: %q", got) } }) } } func TestNonEmpty(t *testing.T) { if nonEmpty("a", "b") != "a" { t.Error("first non-empty wins") } if nonEmpty("", "b") != "b" { t.Error("fallback when first empty") } if nonEmpty("", "") != "" { t.Error("both empty yields empty") } } func TestIndexName_UnamedGroupsStable(t *testing.T) { // Each unnamed group should get a distinct fallback name so // JSON serialization doesn't collapse $4..$N onto a single key. re := mustCompile(t, `(\w+) (\w+) (\w+) (\w+) (\w+)`) seen := map[string]bool{} for i := 1; i <= 5; i++ { name := indexName(re, i) if seen[name] { t.Errorf("indexName(%d) = %q collides with prior group", i, name) } seen[name] = true if !strings.HasPrefix(name, "$") { t.Errorf("unnamed group %d should fall back to $N form, got %q", i, name) } } } func TestIndexName_NamedGroupWins(t *testing.T) { re := mustCompile(t, `(?P\d+) (\w+)`) if got := indexName(re, 1); got != "code" { t.Errorf("named group should win: %q", got) } if got := indexName(re, 2); got != "$2" { t.Errorf("second (unnamed) group: %q", got) } } // mustCompile is a local helper so the test file is self-contained. func mustCompile(t *testing.T, pattern string) interface{ SubexpNames() []string } { t.Helper() r, err := regexp.Compile(pattern) if err != nil { t.Fatalf("compile %q: %v", pattern, err) } return r }