@@ -570,74 +570,147 @@ func assertKV(t *testing.T, r Record, kv log.KeyValue) {
570
570
}
571
571
572
572
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
576
582
}{
583
+ // Edge case: limit is negative, no truncation should occur
577
584
{
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
+ },
596
589
},
590
+
591
+ // Edge case: string is already shorter than the limit, no truncation
592
+ // should occur
597
593
{
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
+ },
601
600
},
601
+
602
+ // Edge case: truncation happens with ASCII characters only
602
603
{
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
+ },
606
610
},
611
+
612
+ // Truncation including multi-byte characters (UTF-8)
607
613
{
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
+ },
611
623
},
624
+
625
+ // Truncation with invalid UTF-8 characters
612
626
{
613
- input : "value" ,
614
- want : "value" ,
615
- limit : 6 ,
627
+ name : "InvalidUTF-8" ,
628
+ groups : []group {
629
+ {11 , "Invalid\x80 text" , "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\x80 World" , "Hello" },
635
+ {11 , "Hello\x80 World\x80 !" , "HelloWorld!" },
636
+ {15 , "Hello\x80 World\x80 Test" , "HelloWorldTest" },
637
+ {15 , "Hello\x80 \x80 \x80 World\x80 Test" , "HelloWorldTest" },
638
+ {15 , "\x80 \x80 \x80 Hello\x80 \x80 \x80 World\x80 Test\x80 \x80 " , "HelloWorldTest" },
639
+ },
616
640
},
641
+
642
+ // Truncation with mixed validn and invalid UTF-8 characters
617
643
{
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\x80 World๐๐" , "๐ HelloWorld๐๐" },
651
+ {14 , "๐\x80 Hello\x80 World๐๐" , "๐ HelloWorld๐๐" },
652
+ {14 , "๐\x80 Hello\x80 World๐\x80 ๐" , "๐ HelloWorld๐๐" },
653
+ {14 , "๐\x80 Hello\x80 World๐\x80 ๐\x80 " , "๐ HelloWorld๐๐" },
654
+ {14 , "\x80 ๐\x80 Hello\x80 World๐\x80 ๐\x80 " , "๐ HelloWorld๐๐" },
655
+ },
621
656
},
657
+
658
+ // Edge case: empty string, should return empty string
622
659
{
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
+ },
626
664
},
665
+
666
+ // Edge case: limit is 0, should return an empty string
627
667
{
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
+ },
631
673
},
632
674
}
633
675
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))\n got: %q([]rune%v)\n want %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
+ }
640
706
}
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\x80 World๐\x80 ๐\x80 " ))
641
714
}
642
715
643
716
func BenchmarkWalkAttributes (b * testing.B ) {
0 commit comments