github.com/anchore/syft@v1.4.2-0.20240516191711-1bec1fc5d397/syft/format/internal/stream/seekable_reader_test.go (about)

     1  package stream
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"reflect"
     7  	"testing"
     8  
     9  	"github.com/stretchr/testify/assert"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  func TestSeekableReader(t *testing.T) {
    14  	tests := []struct {
    15  		name    string
    16  		input   io.Reader
    17  		assert  func(io.Reader, io.ReadSeeker)
    18  		wantErr require.ErrorAssertionFunc
    19  	}{
    20  		{
    21  			name:    "nil reader",
    22  			input:   nil,
    23  			wantErr: require.Error,
    24  		},
    25  		{
    26  			name:  "empty reader",
    27  			input: bytes.NewBuffer([]byte{}), // does not implement io.Seeker (but does implement io.Reader)
    28  			assert: func(input io.Reader, got io.ReadSeeker) {
    29  				impl, ok := got.(*bytes.Reader) // implements bytes.Reader
    30  				require.True(t, ok)
    31  				_, err := impl.Seek(0, io.SeekStart)
    32  				require.NoError(t, err)
    33  				content, err := io.ReadAll(impl)
    34  				require.NoError(t, err)
    35  				require.Equal(t, []byte{}, content)
    36  			},
    37  		},
    38  		{
    39  			name:  "empty read seeker",
    40  			input: bytes.NewReader([]byte{}), // implements io.ReadSeeker
    41  			assert: func(input io.Reader, got io.ReadSeeker) {
    42  				impl, ok := got.(*bytes.Reader)
    43  				require.True(t, ok)
    44  				_, err := impl.Seek(0, io.SeekStart)
    45  				require.NoError(t, err)
    46  				content, err := io.ReadAll(impl)
    47  				require.NoError(t, err)
    48  				require.Equal(t, []byte{}, content)
    49  
    50  				// assert this is the same read seeker (reflect tt.input pointer is the same as the impl pointer
    51  				inputImpl, ok := input.(*bytes.Reader)
    52  				require.True(t, ok)
    53  				assert.Equal(t, reflect.ValueOf(inputImpl).Pointer(), reflect.ValueOf(impl).Pointer())
    54  			},
    55  		},
    56  		{
    57  			name:  "non-empty read seeker",
    58  			input: bytes.NewReader([]byte("hello world!")), // implements io.ReadSeeker
    59  			assert: func(input io.Reader, got io.ReadSeeker) {
    60  				impl, ok := got.(*bytes.Reader)
    61  				require.True(t, ok)
    62  				_, err := impl.Seek(0, io.SeekStart)
    63  				require.NoError(t, err)
    64  				content, err := io.ReadAll(impl)
    65  				require.NoError(t, err)
    66  				require.Equal(t, []byte("hello world!"), content)
    67  
    68  				// assert this is the same read seeker (reflect tt.input pointer is the same as the impl pointer
    69  				inputImpl, ok := input.(*bytes.Reader)
    70  				require.True(t, ok)
    71  				assert.Equal(t, reflect.ValueOf(inputImpl).Pointer(), reflect.ValueOf(impl).Pointer())
    72  			},
    73  		},
    74  		{
    75  			name:  "non-empty reader",
    76  			input: bytes.NewBufferString("hello world!"), // does not implement io.Seeker (but does implement io.Reader)
    77  			assert: func(input io.Reader, got io.ReadSeeker) {
    78  				impl, ok := got.(*bytes.Reader)
    79  				require.True(t, ok)
    80  				_, err := impl.Seek(0, io.SeekStart)
    81  				require.NoError(t, err)
    82  				content, err := io.ReadAll(impl)
    83  				require.NoError(t, err)
    84  				require.Equal(t, []byte("hello world!"), content)
    85  			},
    86  		},
    87  	}
    88  	for _, tt := range tests {
    89  		t.Run(tt.name, func(t *testing.T) {
    90  			if tt.wantErr == nil {
    91  				tt.wantErr = require.NoError
    92  			}
    93  			got, err := SeekableReader(tt.input)
    94  			tt.wantErr(t, err)
    95  			if err != nil {
    96  				return
    97  			}
    98  			tt.assert(tt.input, got)
    99  		})
   100  	}
   101  }