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