github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/covermerger/bq_csv_reader_test.go (about) 1 // Copyright 2025 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package covermerger 5 6 import ( 7 "bytes" 8 "compress/gzip" 9 "errors" 10 "fmt" 11 "io" 12 "testing" 13 14 "github.com/google/syzkaller/pkg/gcs" 15 gcsmocks "github.com/google/syzkaller/pkg/gcs/mocks" 16 "github.com/stretchr/testify/assert" 17 "github.com/stretchr/testify/mock" 18 ) 19 20 func TestGCSGZIPMultiReader_Read(t *testing.T) { 21 tests := []struct { 22 name string 23 inputFiles []string 24 inputBytes [][]byte 25 26 wantBytes []byte 27 wantErr error 28 }{ 29 { 30 name: "single file, single read", 31 inputFiles: []string{"file1"}, 32 inputBytes: [][]byte{gzBytes("1")}, 33 wantBytes: []byte("1"), 34 wantErr: nil, 35 }, 36 { 37 name: "single file, multiple reads", 38 inputFiles: []string{"file1"}, 39 inputBytes: [][]byte{gzBytes("123")}, 40 wantBytes: []byte("123"), 41 wantErr: nil, 42 }, 43 { 44 name: "multiple files, multiple reads", 45 inputFiles: []string{"file1", "file2", "file3"}, 46 inputBytes: [][]byte{gzBytes("123"), gzBytes("456"), gzBytes("789")}, 47 wantBytes: []byte("123456789"), 48 wantErr: nil, 49 }, 50 { 51 name: "multiple files, badbytes", 52 inputFiles: []string{"file1", "file2", "file3"}, 53 inputBytes: [][]byte{gzBytes("123"), gzBytes("456"), []byte("789")}, 54 wantBytes: []byte("123456"), 55 wantErr: fmt.Errorf("err calling gzip.NewReader: %w", errors.New("unexpected EOF")), 56 }, 57 } 58 59 for _, test := range tests { 60 t.Run(test.name, func(t *testing.T) { 61 mr := &gcsGZIPMultiReader{ 62 gcsClient: makeGCSClientMock(t, test.inputFiles, test.inputBytes), 63 gcsFiles: test.inputFiles, 64 } 65 gotBytes, gotErr := io.ReadAll(mr) 66 assert.NoError(t, mr.Close()) 67 assert.Equal(t, test.wantErr, gotErr) 68 assert.Equal(t, test.wantBytes, gotBytes) 69 }) 70 } 71 } 72 73 func makeGCSClientMock(t *testing.T, files []string, bytes [][]byte) gcs.Client { 74 gcsClientMock := gcsmocks.NewClient(t) 75 for i, file := range files { 76 rcMock := &readCloserMock{} 77 for _, b := range bytes[i] { 78 rcMock.On("Read", mock.Anything). 79 Run(func(args mock.Arguments) { 80 arg := args.Get(0).([]byte) 81 arg[0] = b 82 }). 83 Return(1, nil).Once() 84 } 85 rcMock.On("Read", mock.Anything). 86 Return(0, io.EOF). 87 On("Close"). 88 Return(nil).Once() 89 90 gcsClientMock.EXPECT(). 91 FileReader(file). 92 Return(rcMock, nil) 93 } 94 return gcsClientMock 95 } 96 97 type readCloserMock struct { 98 mock.Mock 99 } 100 101 func (m *readCloserMock) Read(p []byte) (n int, err error) { 102 args := m.Called(p) 103 return args.Int(0), args.Error(1) 104 } 105 106 func (m *readCloserMock) Close() (err error) { 107 args := m.Called() 108 return args.Error(0) 109 } 110 111 func gzBytes(str string) []byte { 112 buf := &bytes.Buffer{} 113 gzw := gzip.NewWriter(buf) 114 gzw.Write([]byte(str)) 115 gzw.Close() 116 return buf.Bytes() 117 }