github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/reader_generic_test.go (about)

     1  package avro_test
     2  
     3  import (
     4  	"bytes"
     5  	"math/big"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/hamba/avro/v2"
    10  	"github.com/stretchr/testify/assert"
    11  	"github.com/stretchr/testify/require"
    12  )
    13  
    14  func TestReader_ReadNext(t *testing.T) {
    15  	tests := []struct {
    16  		name    string
    17  		data    []byte
    18  		schema  string
    19  		want    any
    20  		wantErr require.ErrorAssertionFunc
    21  	}{
    22  
    23  		{
    24  			name:    "Bool",
    25  			data:    []byte{0x01},
    26  			schema:  "boolean",
    27  			want:    true,
    28  			wantErr: require.NoError,
    29  		},
    30  		{
    31  			name:    "Int",
    32  			data:    []byte{0x36},
    33  			schema:  "int",
    34  			want:    27,
    35  			wantErr: require.NoError,
    36  		},
    37  		{
    38  			name:    "Int Date",
    39  			data:    []byte{0xAE, 0x9D, 0x02},
    40  			schema:  `{"type":"int","logicalType":"date"}`,
    41  			want:    time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC),
    42  			wantErr: require.NoError,
    43  		},
    44  		{
    45  			name:    "Int Time-Millis",
    46  			data:    []byte{0xAA, 0xB4, 0xDE, 0x75},
    47  			schema:  `{"type":"int","logicalType":"time-millis"}`,
    48  			want:    123456789 * time.Millisecond,
    49  			wantErr: require.NoError,
    50  		},
    51  		{
    52  			name:    "Long",
    53  			data:    []byte{0x36},
    54  			schema:  "long",
    55  			want:    int64(27),
    56  			wantErr: require.NoError,
    57  		},
    58  		{
    59  			name:    "Long Time-Micros",
    60  			data:    []byte{0x86, 0xEA, 0xC8, 0xE9, 0x97, 0x07},
    61  			schema:  `{"type":"long","logicalType":"time-micros"}`,
    62  			want:    123456789123 * time.Microsecond,
    63  			wantErr: require.NoError,
    64  		},
    65  		{
    66  			name:    "Long Timestamp-Millis",
    67  			data:    []byte{0x90, 0xB2, 0xAE, 0xC3, 0xEC, 0x5B},
    68  			schema:  `{"type":"long","logicalType":"timestamp-millis"}`,
    69  			want:    time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC),
    70  			wantErr: require.NoError,
    71  		},
    72  		{
    73  			name:    "Long Timestamp-Micros",
    74  			data:    []byte{0x80, 0xCD, 0xB7, 0xA2, 0xEE, 0xC7, 0xCD, 0x05},
    75  			schema:  `{"type":"long","logicalType":"timestamp-micros"}`,
    76  			want:    time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC),
    77  			wantErr: require.NoError,
    78  		},
    79  		{
    80  			name:    "Float",
    81  			data:    []byte{0x33, 0x33, 0x93, 0x3F},
    82  			schema:  "float",
    83  			want:    float32(1.15),
    84  			wantErr: require.NoError,
    85  		},
    86  		{
    87  			name:    "Double",
    88  			data:    []byte{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xF2, 0x3F},
    89  			schema:  "double",
    90  			want:    float64(1.15),
    91  			wantErr: require.NoError,
    92  		},
    93  		{
    94  			name:    "String",
    95  			data:    []byte{0x06, 0x66, 0x6F, 0x6F},
    96  			schema:  "string",
    97  			want:    "foo",
    98  			wantErr: require.NoError,
    99  		},
   100  		{
   101  			name:    "Bytes",
   102  			data:    []byte{0x08, 0xEC, 0xAB, 0x44, 0x00},
   103  			schema:  "bytes",
   104  			want:    []byte{0xEC, 0xAB, 0x44, 0x00},
   105  			wantErr: require.NoError,
   106  		},
   107  		{
   108  			name:    "Bytes Decimal",
   109  			data:    []byte{0x6, 0x00, 0x87, 0x78},
   110  			schema:  `{"type":"bytes","logicalType":"decimal","precision":4,"scale":2}`,
   111  			want:    big.NewRat(1734, 5),
   112  			wantErr: require.NoError,
   113  		},
   114  		{
   115  			name:    "Record",
   116  			data:    []byte{0x36, 0x06, 0x66, 0x6f, 0x6f},
   117  			schema:  `{"type": "record", "name": "test", "fields" : [{"name": "a", "type": "long"}, {"name": "b", "type": "string"}]}`,
   118  			want:    map[string]any{"a": int64(27), "b": "foo"},
   119  			wantErr: require.NoError,
   120  		},
   121  		{
   122  			name:    "Ref",
   123  			data:    []byte{0x36, 0x06, 0x66, 0x6f, 0x6f, 0x36, 0x06, 0x66, 0x6f, 0x6f},
   124  			schema:  `{"type":"record","name":"parent","fields":[{"name":"a","type":{"type":"record","name":"test","fields":[{"name":"a","type":"long"},{"name":"b","type":"string"}]}},{"name":"b","type":"test"}]}`,
   125  			want:    map[string]any{"a": map[string]any{"a": int64(27), "b": "foo"}, "b": map[string]any{"a": int64(27), "b": "foo"}},
   126  			wantErr: require.NoError,
   127  		},
   128  		{
   129  			name:    "Array",
   130  			data:    []byte{0x04, 0x36, 0x38, 0x0},
   131  			schema:  `{"type":"array", "items": "int"}`,
   132  			want:    []any{27, 28},
   133  			wantErr: require.NoError,
   134  		},
   135  		{
   136  			name:    "Map",
   137  			data:    []byte{0x02, 0x06, 0x66, 0x6F, 0x6F, 0x06, 0x66, 0x6F, 0x6F, 0x00},
   138  			schema:  `{"type":"map", "values": "string"}`,
   139  			want:    map[string]any{"foo": "foo"},
   140  			wantErr: require.NoError,
   141  		},
   142  		{
   143  			name:    "Enum",
   144  			data:    []byte{0x02},
   145  			schema:  `{"type":"enum", "name": "test", "symbols": ["foo", "bar"]}`,
   146  			want:    "bar",
   147  			wantErr: require.NoError,
   148  		},
   149  		{
   150  			name:    "Enum Invalid Symbol",
   151  			data:    []byte{0x04},
   152  			schema:  `{"type":"enum", "name": "test", "symbols": ["foo", "bar"]}`,
   153  			want:    nil,
   154  			wantErr: require.Error,
   155  		},
   156  		{
   157  			name:    "Union",
   158  			data:    []byte{0x02, 0x06, 0x66, 0x6F, 0x6F},
   159  			schema:  `["null", "string"]`,
   160  			want:    map[string]any{"string": "foo"},
   161  			wantErr: require.NoError,
   162  		},
   163  		{
   164  			name:    "Union Nil",
   165  			data:    []byte{0x00},
   166  			schema:  `["null", "string"]`,
   167  			want:    nil,
   168  			wantErr: require.NoError,
   169  		},
   170  		{
   171  			name:    "Union Named",
   172  			data:    []byte{0x02, 0x02},
   173  			schema:  `["null", {"type":"enum", "name": "test", "symbols": ["foo", "bar"]}]`,
   174  			want:    map[string]any{"test": "bar"},
   175  			wantErr: require.NoError,
   176  		},
   177  		{
   178  			name:    "Union Invalid Schema",
   179  			data:    []byte{0x04},
   180  			schema:  `["null", "string"]`,
   181  			want:    nil,
   182  			wantErr: require.Error,
   183  		},
   184  		{
   185  			name:    "Fixed",
   186  			data:    []byte{0x66, 0x6F, 0x6F, 0x66, 0x6F, 0x6F},
   187  			schema:  `{"type":"fixed", "name": "test", "size": 6}`,
   188  			want:    [6]byte{'f', 'o', 'o', 'f', 'o', 'o'},
   189  			wantErr: require.NoError,
   190  		},
   191  		{
   192  			name:    "Fixed Decimal",
   193  			data:    []byte{0x00, 0x00, 0x00, 0x00, 0x87, 0x78},
   194  			schema:  `{"type":"fixed", "name": "test", "size": 6,"logicalType":"decimal","precision":4,"scale":2}`,
   195  			want:    big.NewRat(1734, 5),
   196  			wantErr: require.NoError,
   197  		},
   198  	}
   199  
   200  	for _, test := range tests {
   201  		test := test
   202  		t.Run(test.name, func(t *testing.T) {
   203  			schema := avro.MustParse(test.schema)
   204  			r := avro.NewReader(bytes.NewReader(test.data), 10)
   205  
   206  			got := r.ReadNext(schema)
   207  
   208  			test.wantErr(t, r.Error)
   209  			assert.Equal(t, test.want, got)
   210  		})
   211  	}
   212  }
   213  
   214  func TestReader_ReadNextUnsupportedType(t *testing.T) {
   215  	schema := avro.NewPrimitiveSchema(avro.Type("test"), nil)
   216  	r := avro.NewReader(bytes.NewReader([]byte{0x01}), 10)
   217  
   218  	_ = r.ReadNext(schema)
   219  
   220  	assert.Error(t, r.Error)
   221  }