@@ -735,3 +735,95 @@ func testEncoderErrors(t *testing.T, where jsontest.CasePos, opts []Options, cal
735
735
t .Fatalf ("%s: Encoder.OutputOffset = %v, want %v" , where , gotOffset , wantOffset )
736
736
}
737
737
}
738
+
739
+ // TestEncoderReset tests that the encoder preserves its internal
740
+ // buffer between Reset calls to avoid frequent allocations when reusing the encoder.
741
+ // It ensures that the buffer capacity is maintained while avoiding aliasing
742
+ // issues with [bytes.Buffer].
743
+ func TestEncoderReset (t * testing.T ) {
744
+ // Create an encoder with a reasonably large JSON input to ensure buffer growth.
745
+ largeJSON := `{"key1":"value1","key2":"value2","key3":"value3","key4":"value4","key5":"value5"}` + "\n "
746
+ bb := new (bytes.Buffer )
747
+ enc := NewEncoder (struct { io.Writer }{bb }) // mask out underlying [bytes.Buffer]
748
+
749
+ t .Run ("Test capacity preservation" , func (t * testing.T ) {
750
+ // Write the first JSON value to grow the internal buffer.
751
+ err := enc .WriteValue (append (enc .AvailableBuffer (), largeJSON ... ))
752
+ if err != nil {
753
+ t .Fatalf ("first WriteValue failed: %v" , err )
754
+ }
755
+ if bb .String () != largeJSON {
756
+ t .Fatalf ("first WriteValue = %q, want %q" , bb .String (), largeJSON )
757
+ }
758
+
759
+ // Get the buffer capacity after first use.
760
+ initialCapacity := cap (enc .s .Buf )
761
+ initialCacheCapacity := cap (enc .s .availBuffer )
762
+ if initialCapacity == 0 {
763
+ t .Fatalf ("expected non-zero buffer capacity after first use" )
764
+ }
765
+ if initialCacheCapacity == 0 {
766
+ t .Fatalf ("expected non-zero cache capacity after first use" )
767
+ }
768
+
769
+ // Reset with a new writer - this should preserve the buffer capacity.
770
+ bb .Reset ()
771
+ enc .Reset (struct { io.Writer }{bb })
772
+
773
+ // Verify the buffer capacity is preserved (or at least not smaller).
774
+ preservedCapacity := cap (enc .s .Buf )
775
+ if preservedCapacity < initialCapacity {
776
+ t .Fatalf ("buffer capacity reduced after Reset: got %d, want at least %d" , preservedCapacity , initialCapacity )
777
+ }
778
+ preservedCacheCapacity := cap (enc .s .availBuffer )
779
+ if preservedCacheCapacity < initialCacheCapacity {
780
+ t .Fatalf ("cache capacity reduced after Reset: got %d, want at least %d" , preservedCapacity , initialCapacity )
781
+ }
782
+
783
+ // Write the second JSON value to ensure the encoder still works correctly.
784
+ err = enc .WriteValue (append (enc .AvailableBuffer (), largeJSON ... ))
785
+ if err != nil {
786
+ t .Fatalf ("second WriteValue failed: %v" , err )
787
+ }
788
+ if bb .String () != largeJSON {
789
+ t .Fatalf ("second WriteValue = %q, want %q" , bb .String (), largeJSON )
790
+ }
791
+ })
792
+
793
+ t .Run ("Test aliasing with bytes.Buffer" , func (t * testing.T ) {
794
+ // Test with bytes.Buffer to verify proper aliasing behavior.
795
+ bb .Reset ()
796
+ enc .Reset (bb )
797
+
798
+ // Write the third JSON value to ensure functionality with bytes.Buffer.
799
+ err := enc .WriteValue ([]byte (largeJSON ))
800
+ if err != nil {
801
+ t .Fatalf ("fourth WriteValue failed: %v" , err )
802
+ }
803
+ if bb .String () != largeJSON {
804
+ t .Fatalf ("fourth WriteValue = %q, want %q" , bb .String (), largeJSON )
805
+ }
806
+ // The encoder buffer should alias bytes.Buffer's internal buffer.
807
+ if cap (enc .s .Buf ) == 0 || cap (bb .AvailableBuffer ()) == 0 || & enc .s .Buf [:1 ][0 ] != & bb .AvailableBuffer ()[:1 ][0 ] {
808
+ t .Fatalf ("encoder buffer does not alias bytes.Buffer" )
809
+ }
810
+ })
811
+
812
+ t .Run ("Test aliasing removed after Reset" , func (t * testing.T ) {
813
+ // Reset with a new reader and verify the buffer is not aliased.
814
+ bb .Reset ()
815
+ enc .Reset (struct { io.Writer }{bb })
816
+ err := enc .WriteValue ([]byte (largeJSON ))
817
+ if err != nil {
818
+ t .Fatalf ("fifth WriteValue failed: %v" , err )
819
+ }
820
+ if bb .String () != largeJSON {
821
+ t .Fatalf ("fourth WriteValue = %q, want %q" , bb .String (), largeJSON )
822
+ }
823
+
824
+ // The encoder buffer should not alias the bytes.Buffer's internal buffer.
825
+ if cap (enc .s .Buf ) == 0 || cap (bb .AvailableBuffer ()) == 0 || & enc .s .Buf [:1 ][0 ] == & bb .AvailableBuffer ()[:1 ][0 ] {
826
+ t .Fatalf ("encoder buffer aliases bytes.Buffer" )
827
+ }
828
+ })
829
+ }
0 commit comments