Skip to content

Commit e6fef27

Browse files
committed
Update TestTruncate to validate on char (not byte)
1 parent 58fdf2a commit e6fef27

File tree

1 file changed

+121
-48
lines changed

1 file changed

+121
-48
lines changed

โ€Žsdk/log/record_test.go

Lines changed: 121 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -570,74 +570,147 @@ func assertKV(t *testing.T, r Record, kv log.KeyValue) {
570570
}
571571

572572
func TestTruncate(t *testing.T) {
573-
testcases := []struct {
574-
input, want string
575-
limit int
573+
type group struct {
574+
limit int
575+
input string
576+
expected string
577+
}
578+
579+
tests := []struct {
580+
name string
581+
groups []group
576582
}{
583+
// Edge case: limit is negative, no truncation should occur
577584
{
578-
input: "value",
579-
want: "value",
580-
limit: -1,
581-
},
582-
{
583-
input: "value",
584-
want: "",
585-
limit: 0,
586-
},
587-
{
588-
input: "value",
589-
want: "v",
590-
limit: 1,
591-
},
592-
{
593-
input: "value",
594-
want: "va",
595-
limit: 2,
585+
name: "NoTruncation",
586+
groups: []group{
587+
{-1, "No truncation!", "No truncation!"},
588+
},
596589
},
590+
591+
// Edge case: string is already shorter than the limit, no truncation
592+
// should occur
597593
{
598-
input: "value",
599-
want: "val",
600-
limit: 3,
594+
name: "ShortText",
595+
groups: []group{
596+
{10, "Short text", "Short text"},
597+
{15, "Short text", "Short text"},
598+
{100, "Short text", "Short text"},
599+
},
601600
},
601+
602+
// Edge case: truncation happens with ASCII characters only
602603
{
603-
input: "value",
604-
want: "valu",
605-
limit: 4,
604+
name: "ASCIIOnly",
605+
groups: []group{
606+
{1, "Hello World!", "H"},
607+
{5, "Hello World!", "Hello"},
608+
{12, "Hello World!", "Hello World!"},
609+
},
606610
},
611+
612+
// Truncation including multi-byte characters (UTF-8)
607613
{
608-
input: "value",
609-
want: "value",
610-
limit: 5,
614+
name: "ValidUTF-8",
615+
groups: []group{
616+
{7, "Hello, ไธ–็•Œ", "Hello, "},
617+
{8, "Hello, ไธ–็•Œ", "Hello, ไธ–"},
618+
{2, "ใ“ใ‚“ใซใกใฏ", "ใ“ใ‚“"},
619+
{3, "ใ“ใ‚“ใซใกใฏ", "ใ“ใ‚“ใซ"},
620+
{5, "ใ“ใ‚“ใซใกใฏ", "ใ“ใ‚“ใซใกใฏ"},
621+
{12, "ใ“ใ‚“ใซใกใฏ", "ใ“ใ‚“ใซใกใฏ"},
622+
},
611623
},
624+
625+
// Truncation with invalid UTF-8 characters
612626
{
613-
input: "value",
614-
want: "value",
615-
limit: 6,
627+
name: "InvalidUTF-8",
628+
groups: []group{
629+
{11, "Invalid\x80text", "Invalidtext"},
630+
// Do not modify invalid text if equal to limit.
631+
{11, "Valid text\x80", "Valid text\x80"},
632+
// Do not modify invalid text if under limit.
633+
{15, "Valid text\x80", "Valid text\x80"},
634+
{5, "Hello\x80World", "Hello"},
635+
{11, "Hello\x80World\x80!", "HelloWorld!"},
636+
{15, "Hello\x80World\x80Test", "HelloWorldTest"},
637+
{15, "Hello\x80\x80\x80World\x80Test", "HelloWorldTest"},
638+
{15, "\x80\x80\x80Hello\x80\x80\x80World\x80Test\x80\x80", "HelloWorldTest"},
639+
},
616640
},
641+
642+
// Truncation with mixed validn and invalid UTF-8 characters
617643
{
618-
input: "โ‚ฌโ‚ฌโ‚ฌโ‚ฌ", // 3 bytes each
619-
want: "โ‚ฌโ‚ฌโ‚ฌ",
620-
limit: 10,
644+
name: "MixedUTF-8",
645+
groups: []group{
646+
{6, "โ‚ฌ"[0:2] + "helloโ‚ฌโ‚ฌ", "helloโ‚ฌ"},
647+
{6, "โ‚ฌ" + "โ‚ฌ"[0:2] + "hello", "โ‚ฌhello"},
648+
{11, "Valid text\x80๐Ÿ“œ", "Valid text๐Ÿ“œ"},
649+
{11, "Valid text๐Ÿ“œ\x80", "Valid text๐Ÿ“œ"},
650+
{14, "๐Ÿ˜Š Hello\x80World๐ŸŒ๐Ÿš€", "๐Ÿ˜Š HelloWorld๐ŸŒ๐Ÿš€"},
651+
{14, "๐Ÿ˜Š\x80 Hello\x80World๐ŸŒ๐Ÿš€", "๐Ÿ˜Š HelloWorld๐ŸŒ๐Ÿš€"},
652+
{14, "๐Ÿ˜Š\x80 Hello\x80World๐ŸŒ\x80๐Ÿš€", "๐Ÿ˜Š HelloWorld๐ŸŒ๐Ÿš€"},
653+
{14, "๐Ÿ˜Š\x80 Hello\x80World๐ŸŒ\x80๐Ÿš€\x80", "๐Ÿ˜Š HelloWorld๐ŸŒ๐Ÿš€"},
654+
{14, "\x80๐Ÿ˜Š\x80 Hello\x80World๐ŸŒ\x80๐Ÿš€\x80", "๐Ÿ˜Š HelloWorld๐ŸŒ๐Ÿš€"},
655+
},
621656
},
657+
658+
// Edge case: empty string, should return empty string
622659
{
623-
input: "โ‚ฌ"[0:2] + "helloโ‚ฌโ‚ฌ", // corrupted first rune, then over limit
624-
want: "helloโ‚ฌ",
625-
limit: 10,
660+
name: "Empty",
661+
groups: []group{
662+
{5, "", ""},
663+
},
626664
},
665+
666+
// Edge case: limit is 0, should return an empty string
627667
{
628-
input: "โ‚ฌ"[0:2] + "hello", // corrupted first rune, then not over limit
629-
want: "hello",
630-
limit: 10,
668+
name: "Zero",
669+
groups: []group{
670+
{0, "Some text", ""},
671+
{0, "", ""},
672+
},
631673
},
632674
}
633675

634-
for _, tc := range testcases {
635-
name := fmt.Sprintf("%s/%d", tc.input, tc.limit)
636-
t.Run(name, func(t *testing.T) {
637-
t.Log(tc.input, len(tc.input), tc.limit)
638-
assert.Equal(t, tc.want, truncate(tc.input, tc.limit))
639-
})
676+
for _, tt := range tests {
677+
for _, g := range tt.groups {
678+
t.Run(tt.name, func(t *testing.T) {
679+
t.Parallel()
680+
681+
got := truncate(g.limit, g.input)
682+
assert.Equalf(
683+
t, g.expected, got,
684+
"input: %q([]rune%v))\ngot: %q([]rune%v)\nwant %q([]rune%v)",
685+
g.input, []rune(g.input),
686+
got, []rune(got),
687+
g.expected, []rune(g.expected),
688+
)
689+
})
690+
}
691+
}
692+
}
693+
694+
func BenchmarkTruncate(b *testing.B) {
695+
run := func(limit int, input string) func(b *testing.B) {
696+
return func(b *testing.B) {
697+
b.ReportAllocs()
698+
b.RunParallel(func(pb *testing.PB) {
699+
var out string
700+
for pb.Next() {
701+
out = truncate(limit, input)
702+
}
703+
_ = out
704+
})
705+
}
640706
}
707+
b.Run("Unlimited", run(-1, "hello ๐Ÿ˜Š world ๐ŸŒ๐Ÿš€"))
708+
b.Run("Zero", run(0, "Some text"))
709+
b.Run("Short", run(10, "Short Text"))
710+
b.Run("ASCII", run(5, "Hello, World!"))
711+
b.Run("ValidUTF-8", run(10, "hello ๐Ÿ˜Š world ๐ŸŒ๐Ÿš€"))
712+
b.Run("InvalidUTF-8", run(6, "โ‚ฌ"[0:2]+"helloโ‚ฌโ‚ฌ"))
713+
b.Run("MixedUTF-8", run(14, "\x80๐Ÿ˜Š\x80 Hello\x80World๐ŸŒ\x80๐Ÿš€\x80"))
641714
}
642715

643716
func BenchmarkWalkAttributes(b *testing.B) {

0 commit comments

Comments
ย (0)