github.com/hamba/avro@v1.8.0/encoder_union_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 TestEncoder_UnionMap(t *testing.T) { 14 defer ConfigTeardown() 15 16 schema := `["null", "string"]` 17 buf := bytes.NewBuffer([]byte{}) 18 enc, err := avro.NewEncoder(schema, buf) 19 assert.NoError(t, err) 20 21 err = enc.Encode(map[string]interface{}{"string": "foo"}) 22 23 assert.NoError(t, err) 24 assert.Equal(t, []byte{0x02, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes()) 25 } 26 27 func TestEncoder_UnionMapRecord(t *testing.T) { 28 defer ConfigTeardown() 29 30 schema := `["null", { 31 "type": "record", 32 "name": "test", 33 "fields" : [ 34 {"name": "a", "type": ["string", "null"], "default": "test"}, 35 {"name": "b", "type": "string"} 36 ] 37 }]` 38 buf := bytes.NewBuffer([]byte{}) 39 enc, err := avro.NewEncoder(schema, buf) 40 assert.NoError(t, err) 41 42 err = enc.Encode(map[string]interface{}{"test": map[string]interface{}{"b": "foo"}}) 43 44 assert.NoError(t, err) 45 assert.Equal(t, []byte{0x02, 0x00, 0x08, 0x74, 0x65, 0x73, 0x74, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes()) 46 } 47 48 func TestEncoder_UnionMapNamed(t *testing.T) { 49 defer ConfigTeardown() 50 51 schema := `["null", {"type":"enum", "name": "test", "symbols": ["foo", "bar"]}]` 52 buf := bytes.NewBuffer([]byte{}) 53 enc, err := avro.NewEncoder(schema, buf) 54 assert.NoError(t, err) 55 56 err = enc.Encode(map[string]interface{}{"test": "bar"}) 57 58 assert.NoError(t, err) 59 assert.Equal(t, []byte{0x02, 0x02}, buf.Bytes()) 60 } 61 62 func TestEncoder_UnionMapNull(t *testing.T) { 63 defer ConfigTeardown() 64 65 schema := `["null", "string"]` 66 buf := bytes.NewBuffer([]byte{}) 67 enc, err := avro.NewEncoder(schema, buf) 68 assert.NoError(t, err) 69 70 var m map[string]interface{} 71 err = enc.Encode(m) 72 73 assert.NoError(t, err) 74 assert.Equal(t, []byte{0x00}, buf.Bytes()) 75 } 76 77 func TestEncoder_UnionMapMultipleEntries(t *testing.T) { 78 defer ConfigTeardown() 79 80 schema := `["null", "string", "int"]` 81 buf := bytes.NewBuffer([]byte{}) 82 enc, err := avro.NewEncoder(schema, buf) 83 assert.NoError(t, err) 84 85 err = enc.Encode(map[string]interface{}{"string": "foo", "int": 27}) 86 87 assert.Error(t, err) 88 } 89 90 func TestEncoder_UnionMapWithTime(t *testing.T) { 91 defer ConfigTeardown() 92 93 schema := `["null", {"type": "long", "logicalType": "timestamp-micros"}]` 94 buf := bytes.NewBuffer([]byte{}) 95 enc, err := avro.NewEncoder(schema, buf) 96 assert.NoError(t, err) 97 98 m := map[string]interface{}{ 99 "long.timestamp-micros": time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC), 100 } 101 err = enc.Encode(m) 102 103 assert.NoError(t, err) 104 assert.Equal(t, []byte{0x02, 0x80, 0xCD, 0xB7, 0xA2, 0xEE, 0xC7, 0xCD, 0x05}, buf.Bytes()) 105 } 106 107 func TestEncoder_UnionMapWithDuration(t *testing.T) { 108 defer ConfigTeardown() 109 110 schema := `["null", {"type": "int", "logicalType": "time-millis"}]` 111 buf := bytes.NewBuffer([]byte{}) 112 enc, err := avro.NewEncoder(schema, buf) 113 assert.NoError(t, err) 114 115 m := map[string]interface{}{ 116 "int.time-millis": 123456789 * time.Millisecond, 117 } 118 err = enc.Encode(m) 119 120 assert.NoError(t, err) 121 assert.Equal(t, []byte{0x02, 0xAA, 0xB4, 0xDE, 0x75}, buf.Bytes()) 122 } 123 124 func TestEncoder_UnionMapWithDecimal(t *testing.T) { 125 defer ConfigTeardown() 126 127 t.Run("low scale", func(t *testing.T) { 128 schema := `["null", {"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}]` 129 buf := bytes.NewBuffer([]byte{}) 130 enc, err := avro.NewEncoder(schema, buf) 131 assert.NoError(t, err) 132 133 m := map[string]interface{}{ 134 "bytes.decimal": big.NewRat(1734, 5), 135 } 136 err = enc.Encode(m) 137 138 assert.NoError(t, err) 139 assert.Equal(t, []byte{0x02, 0x6, 0x00, 0x87, 0x78}, buf.Bytes()) 140 }) 141 142 t.Run("high scale", func(t *testing.T) { 143 schema := `["null", {"type": "bytes", "logicalType": "decimal", "precision": 77, "scale": 38}]` 144 buf := bytes.NewBuffer([]byte{}) 145 enc, err := avro.NewEncoder(schema, buf) 146 assert.NoError(t, err) 147 148 m := map[string]interface{}{ 149 "bytes.decimal": big.NewRat(1734, 5), 150 } 151 err = enc.Encode(m) 152 153 assert.NoError(t, err) 154 assert.Equal(t, []byte{0x2, 0x22, 0x65, 0xea, 0x55, 0xc, 0x11, 0x8, 0xf7, 0xc3, 0xb8, 0xec, 0x53, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0}, buf.Bytes()) 155 }) 156 } 157 158 func TestEncoder_UnionMapInvalidType(t *testing.T) { 159 defer ConfigTeardown() 160 161 schema := `["null", "string"]` 162 buf := bytes.NewBuffer([]byte{}) 163 enc, err := avro.NewEncoder(schema, buf) 164 assert.NoError(t, err) 165 166 err = enc.Encode(map[string]interface{}{"long": 27}) 167 168 assert.Error(t, err) 169 } 170 171 func TestEncoder_UnionMapInvalidMap(t *testing.T) { 172 defer ConfigTeardown() 173 174 schema := `["null", "string"]` 175 buf := bytes.NewBuffer([]byte{}) 176 enc, err := avro.NewEncoder(schema, buf) 177 assert.NoError(t, err) 178 179 err = enc.Encode(map[string]string{}) 180 181 assert.Error(t, err) 182 } 183 184 func TestEncoder_UnionPtr(t *testing.T) { 185 defer ConfigTeardown() 186 187 schema := `["null", "string"]` 188 buf := bytes.NewBuffer([]byte{}) 189 enc, err := avro.NewEncoder(schema, buf) 190 assert.NoError(t, err) 191 192 str := "foo" 193 err = enc.Encode(&str) 194 195 assert.NoError(t, err) 196 assert.Equal(t, []byte{0x02, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes()) 197 } 198 199 func TestEncoder_UnionPtrReversed(t *testing.T) { 200 defer ConfigTeardown() 201 202 schema := `["string", "null"]` 203 buf := bytes.NewBuffer([]byte{}) 204 enc, err := avro.NewEncoder(schema, buf) 205 assert.NoError(t, err) 206 207 str := "foo" 208 err = enc.Encode(&str) 209 210 assert.NoError(t, err) 211 assert.Equal(t, []byte{0x00, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes()) 212 } 213 214 func TestEncoder_UnionPtrNull(t *testing.T) { 215 defer ConfigTeardown() 216 217 schema := `["null", "string"]` 218 buf := bytes.NewBuffer([]byte{}) 219 enc, err := avro.NewEncoder(schema, buf) 220 assert.NoError(t, err) 221 222 var str *string 223 err = enc.Encode(str) 224 225 assert.NoError(t, err) 226 assert.Equal(t, []byte{0x00}, buf.Bytes()) 227 } 228 229 func TestEncoder_UnionPtrReversedNull(t *testing.T) { 230 defer ConfigTeardown() 231 232 schema := `["string", "null"]` 233 buf := bytes.NewBuffer([]byte{}) 234 enc, err := avro.NewEncoder(schema, buf) 235 assert.NoError(t, err) 236 237 var str *string 238 err = enc.Encode(str) 239 240 assert.NoError(t, err) 241 assert.Equal(t, []byte{0x02}, buf.Bytes()) 242 } 243 244 func TestEncoder_UnionPtrNotNullable(t *testing.T) { 245 defer ConfigTeardown() 246 247 schema := `["null", "string", "int"]` 248 buf := bytes.NewBuffer([]byte{}) 249 enc, err := avro.NewEncoder(schema, buf) 250 assert.NoError(t, err) 251 252 str := "test" 253 err = enc.Encode(&str) 254 255 assert.Error(t, err) 256 } 257 258 func TestEncoder_UnionInterface(t *testing.T) { 259 defer ConfigTeardown() 260 261 schema := `["int", "string"]` 262 buf := bytes.NewBuffer([]byte{}) 263 enc, err := avro.NewEncoder(schema, buf) 264 assert.NoError(t, err) 265 266 var val interface{} = "foo" 267 err = enc.Encode(val) 268 269 assert.NoError(t, err) 270 assert.Equal(t, []byte{0x02, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes()) 271 } 272 273 func TestEncoder_UnionInterfaceRecord(t *testing.T) { 274 defer ConfigTeardown() 275 276 avro.Register("test", &TestRecord{}) 277 278 schema := `["int", {"type": "record", "name": "test", "fields" : [{"name": "a", "type": "long"}, {"name": "b", "type": "string"}]}]` 279 buf := bytes.NewBuffer([]byte{}) 280 enc, err := avro.NewEncoder(schema, buf) 281 assert.NoError(t, err) 282 283 var val interface{} = &TestRecord{A: 27, B: "foo"} 284 err = enc.Encode(val) 285 286 assert.NoError(t, err) 287 assert.Equal(t, []byte{0x02, 0x36, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes()) 288 } 289 290 func TestEncoder_UnionInterfaceRecordNonPtr(t *testing.T) { 291 defer ConfigTeardown() 292 293 avro.Register("test", TestRecord{}) 294 295 schema := `["int", {"type": "record", "name": "test", "fields" : [{"name": "a", "type": "long"}, {"name": "b", "type": "string"}]}]` 296 buf := bytes.NewBuffer([]byte{}) 297 enc, err := avro.NewEncoder(schema, buf) 298 assert.NoError(t, err) 299 300 var val interface{} = TestRecord{A: 27, B: "foo"} 301 err = enc.Encode(val) 302 303 assert.NoError(t, err) 304 assert.Equal(t, []byte{0x02, 0x36, 0x06, 0x66, 0x6F, 0x6F}, buf.Bytes()) 305 } 306 307 func TestEncoder_UnionInterfaceMap(t *testing.T) { 308 defer ConfigTeardown() 309 310 avro.Register("map:int", map[string]int{}) 311 312 schema := `["int", {"type": "map", "values": "int"}]` 313 buf := bytes.NewBuffer([]byte{}) 314 enc, err := avro.NewEncoder(schema, buf) 315 assert.NoError(t, err) 316 317 var val interface{} = map[string]int{"foo": 27} 318 err = enc.Encode(val) 319 320 assert.NoError(t, err) 321 assert.Equal(t, []byte{0x02, 0x01, 0x0a, 0x06, 0x66, 0x6f, 0x6f, 0x36, 0x00}, buf.Bytes()) 322 } 323 324 func TestEncoder_UnionInterfaceInMapWithBool(t *testing.T) { 325 defer ConfigTeardown() 326 327 schema := `{"type":"map", "values": ["null", "boolean"]}` 328 buf := bytes.NewBuffer([]byte{}) 329 enc, err := avro.NewEncoder(schema, buf) 330 assert.NoError(t, err) 331 332 err = enc.Encode(map[string]interface{}{"foo": true}) 333 334 assert.NoError(t, err) 335 assert.Equal(t, []byte{0x01, 0x0c, 0x06, 0x66, 0x6F, 0x6F, 0x02, 0x01, 0x00}, buf.Bytes()) 336 } 337 338 func TestEncoder_UnionInterfaceArray(t *testing.T) { 339 defer ConfigTeardown() 340 341 avro.Register("array:int", []int{}) 342 343 schema := `["int", {"type": "array", "items": "int"}]` 344 buf := bytes.NewBuffer([]byte{}) 345 enc, err := avro.NewEncoder(schema, buf) 346 assert.NoError(t, err) 347 348 var val interface{} = []int{27} 349 err = enc.Encode(val) 350 351 assert.NoError(t, err) 352 assert.Equal(t, []byte{0x02, 0x01, 0x02, 0x36, 0x00}, buf.Bytes()) 353 } 354 355 func TestEncoder_UnionInterfaceNull(t *testing.T) { 356 defer ConfigTeardown() 357 358 schema := `{"type": "record", "name": "test", "fields" : [{"name": "a", "type": ["null", "string", "int"]}]}` 359 buf := bytes.NewBuffer([]byte{}) 360 enc, err := avro.NewEncoder(schema, buf) 361 assert.NoError(t, err) 362 363 err = enc.Encode(&TestUnion{A: nil}) 364 365 assert.NoError(t, err) 366 assert.Equal(t, []byte{0x00}, buf.Bytes()) 367 } 368 369 func TestEncoder_UnionInterfaceNamed(t *testing.T) { 370 defer ConfigTeardown() 371 372 avro.Register("test", "") 373 374 schema := `["null", {"type":"enum", "name": "test", "symbols": ["A", "B"]}]` 375 buf := bytes.NewBuffer([]byte{}) 376 enc, err := avro.NewEncoder(schema, buf) 377 assert.NoError(t, err) 378 379 var val interface{} = "B" 380 err = enc.Encode(val) 381 382 assert.NoError(t, err) 383 assert.Equal(t, []byte{0x02, 0x02}, buf.Bytes()) 384 } 385 386 func TestEncoder_UnionInterfaceWithTime(t *testing.T) { 387 defer ConfigTeardown() 388 389 schema := `["null", {"type": "long", "logicalType": "timestamp-micros"}]` 390 buf := bytes.NewBuffer([]byte{}) 391 enc, err := avro.NewEncoder(schema, buf) 392 assert.NoError(t, err) 393 394 var val interface{} = time.Date(2020, 1, 2, 3, 4, 5, 0, time.UTC) 395 err = enc.Encode(val) 396 397 assert.NoError(t, err) 398 assert.Equal(t, []byte{0x02, 0x80, 0xCD, 0xB7, 0xA2, 0xEE, 0xC7, 0xCD, 0x05}, buf.Bytes()) 399 } 400 401 func TestEncoder_UnionInterfaceWithDuration(t *testing.T) { 402 defer ConfigTeardown() 403 404 schema := `["null", {"type": "int", "logicalType": "time-millis"}]` 405 buf := bytes.NewBuffer([]byte{}) 406 enc, err := avro.NewEncoder(schema, buf) 407 assert.NoError(t, err) 408 409 var val interface{} = 123456789 * time.Millisecond 410 err = enc.Encode(val) 411 412 assert.NoError(t, err) 413 assert.Equal(t, []byte{0x02, 0xAA, 0xB4, 0xDE, 0x75}, buf.Bytes()) 414 } 415 416 func TestEncoder_UnionInterfaceWithDecimal(t *testing.T) { 417 defer ConfigTeardown() 418 419 t.Run("low scale", func(t *testing.T) { 420 schema := `["null", {"type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2}]` 421 buf := bytes.NewBuffer([]byte{}) 422 enc, err := avro.NewEncoder(schema, buf) 423 assert.NoError(t, err) 424 425 var val interface{} = big.NewRat(1734, 5) 426 err = enc.Encode(val) 427 428 assert.NoError(t, err) 429 assert.Equal(t, []byte{0x02, 0x6, 0x00, 0x87, 0x78}, buf.Bytes()) 430 }) 431 432 t.Run("high scale", func(t *testing.T) { 433 schema := `["null", {"type": "bytes", "logicalType": "decimal", "precision": 77, "scale": 38}]` 434 buf := bytes.NewBuffer([]byte{}) 435 enc, err := avro.NewEncoder(schema, buf) 436 assert.NoError(t, err) 437 438 var val interface{} = big.NewRat(1734, 5) 439 err = enc.Encode(val) 440 441 assert.NoError(t, err) 442 assert.Equal(t, []byte{0x2, 0x22, 0x65, 0xea, 0x55, 0xc, 0x11, 0x8, 0xf7, 0xc3, 0xb8, 0xec, 0x53, 0xff, 0x80, 0x0, 0x0, 0x0, 0x0}, buf.Bytes()) 443 }) 444 445 } 446 447 func TestEncoder_UnionInterfaceUnregisteredType(t *testing.T) { 448 defer ConfigTeardown() 449 450 schema := `["int", {"type": "record", "name": "test", "fields" : [{"name": "a", "type": "long"}, {"name": "b", "type": "string"}]}]` 451 buf := bytes.NewBuffer([]byte{}) 452 enc, err := avro.NewEncoder(schema, buf) 453 assert.NoError(t, err) 454 455 var val interface{} = &TestRecord{} 456 err = enc.Encode(val) 457 458 assert.Error(t, err) 459 } 460 461 func TestEncoder_UnionInterfaceNotInSchema(t *testing.T) { 462 defer ConfigTeardown() 463 464 avro.Register("test", &TestRecord{}) 465 466 schema := `["int", "string"]` 467 buf := bytes.NewBuffer([]byte{}) 468 enc, err := avro.NewEncoder(schema, buf) 469 assert.NoError(t, err) 470 471 var val interface{} = &TestRecord{} 472 err = enc.Encode(val) 473 474 assert.Error(t, err) 475 }