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 }