github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/codec_generic_internal_test.go (about) 1 package avro 2 3 import ( 4 "bytes" 5 "math/big" 6 "testing" 7 "time" 8 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 ) 12 13 func TestGenericDecode(t *testing.T) { 14 tests := []struct { 15 name string 16 data []byte 17 schema string 18 want any 19 wantErr require.ErrorAssertionFunc 20 }{ 21 22 { 23 name: "Bool", 24 data: []byte{0x01}, 25 schema: "boolean", 26 want: true, 27 wantErr: require.NoError, 28 }, 29 { 30 name: "Int", 31 data: []byte{0x36}, 32 schema: "int", 33 want: 27, 34 wantErr: require.NoError, 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: require.NoError, 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: require.NoError, 49 }, 50 { 51 name: "Long", 52 data: []byte{0x36}, 53 schema: "long", 54 want: int64(27), 55 wantErr: require.NoError, 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: require.NoError, 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: require.NoError, 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: require.NoError, 77 }, 78 { 79 name: "Long Local-Timestamp-Millis", 80 data: []byte{0x90, 0xB2, 0xAE, 0xC3, 0xEC, 0x5B}, 81 schema: `{"type":"long","logicalType":"local-timestamp-millis"}`, 82 want: time.Date(2020, 1, 2, 3, 4, 5, 0, time.Local), 83 wantErr: require.NoError, 84 }, 85 { 86 name: "Long Local-Timestamp-Micros", 87 data: []byte{0x80, 0xCD, 0xB7, 0xA2, 0xEE, 0xC7, 0xCD, 0x05}, 88 schema: `{"type":"long","logicalType":"local-timestamp-micros"}`, 89 want: time.Date(2020, 1, 2, 3, 4, 5, 0, time.Local), 90 wantErr: require.NoError, 91 }, 92 { 93 name: "Float", 94 data: []byte{0x33, 0x33, 0x93, 0x3F}, 95 schema: "float", 96 want: float32(1.15), 97 wantErr: require.NoError, 98 }, 99 { 100 name: "Double", 101 data: []byte{0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0xF2, 0x3F}, 102 schema: "double", 103 want: float64(1.15), 104 wantErr: require.NoError, 105 }, 106 { 107 name: "String", 108 data: []byte{0x06, 0x66, 0x6F, 0x6F}, 109 schema: "string", 110 want: "foo", 111 wantErr: require.NoError, 112 }, 113 { 114 name: "Bytes", 115 data: []byte{0x08, 0xEC, 0xAB, 0x44, 0x00}, 116 schema: "bytes", 117 want: []byte{0xEC, 0xAB, 0x44, 0x00}, 118 wantErr: require.NoError, 119 }, 120 { 121 name: "Bytes Decimal", 122 data: []byte{0x6, 0x00, 0x87, 0x78}, 123 schema: `{"type":"bytes","logicalType":"decimal","precision":4,"scale":2}`, 124 want: big.NewRat(1734, 5), 125 wantErr: require.NoError, 126 }, 127 { 128 name: "Record", 129 data: []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, 130 schema: `{"type": "record", "name": "test", "fields" : [{"name": "a", "type": "long"}, {"name": "b", "type": "string"}]}`, 131 want: map[string]any{"a": int64(27), "b": "foo"}, 132 wantErr: require.NoError, 133 }, 134 { 135 name: "Ref", 136 data: []byte{0x36, 0x06, 0x66, 0x6f, 0x6f, 0x36, 0x06, 0x66, 0x6f, 0x6f}, 137 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"}]}`, 138 want: map[string]any{"a": map[string]any{"a": int64(27), "b": "foo"}, "b": map[string]any{"a": int64(27), "b": "foo"}}, 139 wantErr: require.NoError, 140 }, 141 { 142 name: "Array", 143 data: []byte{0x04, 0x36, 0x38, 0x0}, 144 schema: `{"type":"array", "items": "int"}`, 145 want: []any{27, 28}, 146 wantErr: require.NoError, 147 }, 148 { 149 name: "Map", 150 data: []byte{0x02, 0x06, 0x66, 0x6F, 0x6F, 0x06, 0x66, 0x6F, 0x6F, 0x00}, 151 schema: `{"type":"map", "values": "string"}`, 152 want: map[string]any{"foo": "foo"}, 153 wantErr: require.NoError, 154 }, 155 { 156 name: "Enum", 157 data: []byte{0x02}, 158 schema: `{"type":"enum", "name": "test", "symbols": ["foo", "bar"]}`, 159 want: "bar", 160 wantErr: require.NoError, 161 }, 162 { 163 name: "Enum Invalid Symbol", 164 data: []byte{0x04}, 165 schema: `{"type":"enum", "name": "test", "symbols": ["foo", "bar"]}`, 166 want: nil, 167 wantErr: require.Error, 168 }, 169 { 170 name: "Union", 171 data: []byte{0x02, 0x06, 0x66, 0x6F, 0x6F}, 172 schema: `["null", "string"]`, 173 want: map[string]any{"string": "foo"}, 174 wantErr: require.NoError, 175 }, 176 { 177 name: "Union Zero Index", 178 // 0x80 represents 128. So the bytes below will result in 0 179 // as a result of zig-zag encoding. 180 data: []byte{0x80, 0x80, 0x80, 0x80, 0x30}, 181 schema: `["null"]`, 182 wantErr: require.NoError, 183 }, 184 { 185 name: "Union Nil", 186 data: []byte{0x00}, 187 schema: `["null", "string"]`, 188 want: nil, 189 wantErr: require.NoError, 190 }, 191 { 192 name: "Union Named", 193 data: []byte{0x02, 0x02}, 194 schema: `["null", {"type":"enum", "name": "test", "symbols": ["foo", "bar"]}]`, 195 want: map[string]any{"test": "bar"}, 196 wantErr: require.NoError, 197 }, 198 { 199 name: "Union Invalid Schema", 200 data: []byte{0x04}, 201 schema: `["null", "string"]`, 202 want: nil, 203 wantErr: require.Error, 204 }, 205 { 206 name: "Fixed", 207 data: []byte{0x66, 0x6F, 0x6F, 0x66, 0x6F, 0x6F}, 208 schema: `{"type":"fixed", "name": "test", "size": 6}`, 209 want: [6]byte{'f', 'o', 'o', 'f', 'o', 'o'}, 210 wantErr: require.NoError, 211 }, 212 { 213 name: "Fixed Decimal", 214 data: []byte{0x00, 0x00, 0x00, 0x00, 0x87, 0x78}, 215 schema: `{"type":"fixed", "name": "test", "size": 6,"logicalType":"decimal","precision":4,"scale":2}`, 216 want: big.NewRat(1734, 5), 217 wantErr: require.NoError, 218 }, 219 } 220 221 for _, test := range tests { 222 test := test 223 t.Run(test.name, func(t *testing.T) { 224 defer ConfigTeardown() 225 226 schema := MustParse(test.schema) 227 r := NewReader(bytes.NewReader(test.data), 10) 228 229 typ, err := genericReceiver(schema) 230 require.NoError(t, err) 231 dec := decoderOfType(DefaultConfig.(*frozenConfig), schema, typ) 232 233 got := genericDecode(typ, dec, r) 234 235 test.wantErr(t, r.Error) 236 assert.Equal(t, test.want, got) 237 }) 238 } 239 } 240 241 func TestGenericReceiver_UnsupportedType(t *testing.T) { 242 schema := NewPrimitiveSchema(Type("test"), nil) 243 244 _, err := genericReceiver(schema) 245 246 assert.Error(t, err) 247 }