@@ -20,6 +20,7 @@ package mem_test
2020
2121import (
2222 "bytes"
23+ "fmt"
2324 "testing"
2425
2526 "google.golang.org/grpc/internal"
@@ -265,21 +266,15 @@ func (s) TestBuffer_Split(t *testing.T) {
265266 }
266267 freed = true
267268 }))
268- checkBufData := func (b mem.Buffer , expected []byte ) {
269- t .Helper ()
270- if ! bytes .Equal (b .ReadOnlyData (), expected ) {
271- t .Fatalf ("Buffer did not contain expected data %v, got %v" , expected , b .ReadOnlyData ())
272- }
273- }
274269
275270 buf , split1 := mem .SplitUnsafe (buf , 2 )
276- checkBufData (buf , data [:2 ])
277- checkBufData (split1 , data [2 :])
271+ checkBufData (t , buf , data [:2 ])
272+ checkBufData (t , split1 , data [2 :])
278273
279274 // Check that splitting the buffer more than once works as intended.
280275 split1 , split2 := mem .SplitUnsafe (split1 , 1 )
281- checkBufData (split1 , data [2 :3 ])
282- checkBufData (split2 , data [3 :])
276+ checkBufData (t , split1 , data [2 :3 ])
277+ checkBufData (t , split2 , data [3 :])
283278
284279 // If any of the following frees actually free the buffer, the test will fail.
285280 buf .Free ()
@@ -293,6 +288,158 @@ func (s) TestBuffer_Split(t *testing.T) {
293288 }
294289}
295290
291+ func (s ) TestBuffer_Slice (t * testing.T ) {
292+ ready := false
293+ freed := false
294+ data := []byte {1 , 2 , 3 , 4 }
295+ buf := mem .NewBuffer (& data , poolFunc (func (* []byte ) {
296+ if ! ready {
297+ t .Fatalf ("Freed too early" )
298+ }
299+ freed = true
300+ }))
301+
302+ // Slice the buffer and verify the data.
303+ slice1 := buf .Slice (1 , 3 )
304+ checkBufData (t , slice1 , data [1 :3 ])
305+
306+ // Verify the original buffer is not modified.
307+ checkBufData (t , buf , data )
308+
309+ // Slice the slice.
310+ slice2 := slice1 .Slice (0 , 1 )
311+ checkBufData (t , slice2 , data [1 :2 ])
312+
313+ // Free original and first slice — root should not be freed yet.
314+ buf .Free ()
315+ slice1 .Free ()
316+
317+ // The last slice keeps the root alive.
318+ checkBufData (t , slice2 , data [1 :2 ])
319+
320+ ready = true
321+ slice2 .Free ()
322+
323+ if ! freed {
324+ t .Fatalf ("Buffer never freed" )
325+ }
326+ }
327+
328+ func (s ) TestBuffer_SliceAfterFree (t * testing.T ) {
329+ buf := newBuffer ([]byte ("abcd" ), mem.NopBufferPool {})
330+ buf .Free ()
331+ defer checkForPanic (t , "Cannot slice freed buffer" )
332+ buf .Slice (0 , 2 )
333+ }
334+
335+ func (s ) TestBuffer_SliceBasic (t * testing.T ) {
336+ type sliceCase struct {
337+ start , end int
338+ want []byte
339+ }
340+ cases := []sliceCase {
341+ {1 , 3 , []byte {2 , 3 }},
342+ {0 , 4 , []byte {1 , 2 , 3 , 4 }},
343+ {0 , 0 , []byte {}},
344+ {4 , 4 , []byte {}},
345+ }
346+ ctors := map [string ]func () mem.Buffer {
347+ "pooled" : newPooledBuffer ,
348+ "slice" : newSliceBuf ,
349+ }
350+ for name , newBuf := range ctors {
351+ for _ , tc := range cases {
352+ t .Run (fmt .Sprintf ("%s[%d:%d]" , name , tc .start , tc .end ), func (t * testing.T ) {
353+ buf := newBuf ()
354+ got := buf .Slice (tc .start , tc .end )
355+ checkBufData (t , got , tc .want )
356+ })
357+ }
358+ t .Run (name + " subslice" , func (t * testing.T ) {
359+ buf := newBuf ()
360+ slice := buf .Slice (1 , 3 )
361+ slice2 := slice .Slice (0 , 1 )
362+ checkBufData (t , slice2 , []byte {2 })
363+ })
364+ }
365+ t .Run ("empty buffer" , func (t * testing.T ) {
366+ buf := newEmptyBuf ()
367+ got := buf .Slice (0 , 0 )
368+ checkBufData (t , got , nil )
369+ })
370+ }
371+
372+ func (s ) TestBuffer_SliceBoundsCheck (t * testing.T ) {
373+ type panicCase struct {
374+ name string
375+ start , end int
376+ }
377+ nonEmptyCases := []panicCase {
378+ {"end_out_of_bounds" , 0 , 5 },
379+ {"start_negative" , - 1 , 3 },
380+ {"start_greater_than_end" , 3 , 0 },
381+ }
382+ tests := []struct {
383+ name string
384+ buf func () mem.Buffer
385+ panicCases []panicCase
386+ }{
387+ {
388+ name : "buffer" ,
389+ buf : newPooledBuffer ,
390+ panicCases : nonEmptyCases ,
391+ },
392+ {
393+ name : "SliceBuffer" ,
394+ buf : newSliceBuf ,
395+ panicCases : nonEmptyCases ,
396+ },
397+ {
398+ name : "emptyBuffer" ,
399+ buf : newEmptyBuf ,
400+ panicCases : []panicCase {
401+ {"end_out_of_bounds" , 0 , 1 },
402+ {"start_negative" , - 1 , 0 },
403+ },
404+ },
405+ }
406+ for _ , tt := range tests {
407+ t .Run (tt .name , func (t * testing.T ) {
408+ for _ , pc := range tt .panicCases {
409+ t .Run (pc .name , func (t * testing.T ) {
410+ buf := tt .buf ()
411+ defer func () {
412+ if recover () == nil {
413+ t .Fatalf ("Slice(%d, %d) did not panic" , pc .start , pc .end )
414+ }
415+ }()
416+ buf .Slice (pc .start , pc .end )
417+ })
418+ }
419+ })
420+ }
421+ }
422+
423+ func newPooledBuffer () mem.Buffer {
424+ return newBuffer ([]byte {1 , 2 , 3 , 4 }, mem.NopBufferPool {})
425+ }
426+
427+ func newSliceBuf () mem.Buffer {
428+ return mem.SliceBuffer {1 , 2 , 3 , 4 }
429+ }
430+
431+ func newEmptyBuf () mem.Buffer {
432+ var bs mem.BufferSlice
433+ return bs .MaterializeToBuffer (mem.NopBufferPool {})
434+ }
435+
436+ func checkBufData (t * testing.T , b mem.Buffer , expected []byte ) {
437+ t .Helper ()
438+ if ! bytes .Equal (b .ReadOnlyData (), expected ) {
439+ t .Fatalf ("Buffer did not contain expected data %v, got %v" , expected , b .ReadOnlyData ())
440+ }
441+ }
442+
296443func checkForPanic (t * testing.T , wantErr string ) {
297444 t .Helper ()
298445 r := recover ()
0 commit comments