github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/codec_default_internal_test.go (about) 1 package avro 2 3 import ( 4 "bytes" 5 "errors" 6 "math" 7 "math/big" 8 "testing" 9 10 "github.com/stretchr/testify/assert" 11 "github.com/stretchr/testify/require" 12 ) 13 14 type testEnumTextUnmarshaler int 15 16 func (m *testEnumTextUnmarshaler) UnmarshalText(data []byte) error { 17 switch string(data) { 18 case "foo": 19 *m = 0 20 return nil 21 case "bar": 22 *m = 1 23 return nil 24 default: 25 return errors.New("unknown symbol") 26 } 27 } 28 29 func ConfigTeardown() { 30 // Reset the caches 31 DefaultConfig = Config{}.Freeze() 32 } 33 34 func TestDecoder_InvalidDefault(t *testing.T) { 35 defer ConfigTeardown() 36 37 data := []byte{0x6, 0x66, 0x6f, 0x6f} 38 39 schema := MustParse(`{ 40 "type": "record", 41 "name": "test", 42 "fields" : [ 43 {"name": "a", "type": "string"}, 44 {"name": "b", "type": "boolean", "default": true} 45 ] 46 }`) 47 48 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 49 // alter default value to force encoding failure 50 schema.(*RecordSchema).fields[1].def = "invalid value" 51 52 dec := NewDecoderForSchema(schema, bytes.NewReader(data)) 53 54 var got map[string]any 55 err := dec.Decode(&got) 56 57 require.Error(t, err) 58 } 59 60 func TestDecoder_IgnoreField(t *testing.T) { 61 defer ConfigTeardown() 62 63 // write schema 64 // `{ 65 // // "type": "record", 66 // // "name": "test", 67 // // "fields" : [ 68 // // {"name": "a", "type": "string"} 69 // // ] 70 // // }` 71 72 // {"a": "foo"} 73 data := []byte{0x6, 0x66, 0x6f, 0x6f} 74 75 schema := MustParse(`{ 76 "type": "record", 77 "name": "test", 78 "fields" : [ 79 {"name": "a", "type": "string"}, 80 {"name": "b", "type": "float", "default": 10.45} 81 ] 82 }`) 83 84 schema.(*RecordSchema).Fields()[0].action = FieldIgnore 85 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 86 87 type TestRecord struct { 88 A string `avro:"a"` 89 B float32 `avro:"b"` 90 } 91 92 var got TestRecord 93 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 94 95 require.NoError(t, err) 96 assert.Equal(t, TestRecord{B: 10.45, A: ""}, got) 97 } 98 99 func TestDecoder_DefaultBool(t *testing.T) { 100 defer ConfigTeardown() 101 102 // write schema 103 // `{ 104 // // "type": "record", 105 // // "name": "test", 106 // // "fields" : [ 107 // // {"name": "a", "type": "string"} 108 // // ] 109 // // }` 110 111 // {"a": "foo"} 112 data := []byte{0x6, 0x66, 0x6f, 0x6f} 113 114 schema := MustParse(`{ 115 "type": "record", 116 "name": "test", 117 "fields" : [ 118 {"name": "a", "type": "string"}, 119 {"name": "b", "type": "boolean", "default": true} 120 ] 121 }`) 122 123 // hack: set field action to force decode default behavior 124 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 125 126 dec := NewDecoderForSchema(schema, bytes.NewReader(data)) 127 128 type TestRecord struct { 129 A string `avro:"a"` 130 B bool `avro:"b"` 131 } 132 133 var got TestRecord 134 err := dec.Decode(&got) 135 136 require.NoError(t, err) 137 assert.Equal(t, TestRecord{B: true, A: "foo"}, got) 138 } 139 140 func TestDecoder_DefaultInt(t *testing.T) { 141 defer ConfigTeardown() 142 143 data := []byte{0x6, 0x66, 0x6f, 0x6f} 144 145 schema := MustParse(`{ 146 "type": "record", 147 "name": "test", 148 "fields" : [ 149 {"name": "a", "type": "string"}, 150 {"name": "b", "type": "int", "default": 1000} 151 ] 152 }`) 153 154 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 155 156 dec := NewDecoderForSchema(schema, bytes.NewReader(data)) 157 158 type TestRecord struct { 159 A string `avro:"a"` 160 B int32 `avro:"b"` 161 } 162 163 var got TestRecord 164 err := dec.Decode(&got) 165 166 require.NoError(t, err) 167 assert.Equal(t, TestRecord{B: 1000, A: "foo"}, got) 168 } 169 170 func TestDecoder_DefaultLong(t *testing.T) { 171 defer ConfigTeardown() 172 173 data := []byte{0x6, 0x66, 0x6f, 0x6f} 174 175 schema := MustParse(`{ 176 "type": "record", 177 "name": "test", 178 "fields" : [ 179 {"name": "a", "type": "string"}, 180 {"name": "b", "type": "long", "default": 1000} 181 ] 182 }`) 183 184 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 185 186 type TestRecord struct { 187 A string `avro:"a"` 188 B int64 `avro:"b"` 189 } 190 191 var got TestRecord 192 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 193 194 require.NoError(t, err) 195 assert.Equal(t, TestRecord{B: 1000, A: "foo"}, got) 196 } 197 198 func TestDecoder_DefaultFloat(t *testing.T) { 199 defer ConfigTeardown() 200 201 data := []byte{0x6, 0x66, 0x6f, 0x6f} 202 203 schema := MustParse(`{ 204 "type": "record", 205 "name": "test", 206 "fields" : [ 207 {"name": "a", "type": "string"}, 208 {"name": "b", "type": "float", "default": 10.45} 209 ] 210 }`) 211 212 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 213 214 type TestRecord struct { 215 A string `avro:"a"` 216 B float32 `avro:"b"` 217 } 218 219 var got TestRecord 220 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 221 222 require.NoError(t, err) 223 assert.Equal(t, TestRecord{B: 10.45, A: "foo"}, got) 224 } 225 226 func TestDecoder_DefaultDouble(t *testing.T) { 227 defer ConfigTeardown() 228 229 data := []byte{0x6, 0x66, 0x6f, 0x6f} 230 231 schema := MustParse(`{ 232 "type": "record", 233 "name": "test", 234 "fields" : [ 235 {"name": "a", "type": "string"}, 236 {"name": "b", "type": "double", "default": 10.45} 237 ] 238 }`) 239 240 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 241 242 type TestRecord struct { 243 A string `avro:"a"` 244 B float64 `avro:"b"` 245 } 246 247 var got TestRecord 248 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 249 250 require.NoError(t, err) 251 assert.Equal(t, TestRecord{B: 10.45, A: "foo"}, got) 252 } 253 254 func TestDecoder_DefaultBytes(t *testing.T) { 255 defer ConfigTeardown() 256 257 data := []byte{0x6, 0x66, 0x6f, 0x6f} 258 259 schema := MustParse(`{ 260 "type": "record", 261 "name": "test", 262 "fields" : [ 263 {"name": "a", "type": "string"}, 264 {"name": "b", "type": "bytes", "default": "value"} 265 ] 266 }`) 267 268 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 269 270 type TestRecord struct { 271 A string `avro:"a"` 272 B []byte `avro:"b"` 273 } 274 275 var got TestRecord 276 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 277 278 require.NoError(t, err) 279 assert.Equal(t, TestRecord{B: []byte("value"), A: "foo"}, got) 280 } 281 282 func TestDecoder_DefaultString(t *testing.T) { 283 defer ConfigTeardown() 284 285 data := []byte{0x6, 0x66, 0x6f, 0x6f} 286 287 schema := MustParse(`{ 288 "type": "record", 289 "name": "test", 290 "fields" : [ 291 {"name": "a", "type": "string"}, 292 {"name": "b", "type": "string", "default": "value"} 293 ] 294 }`) 295 296 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 297 298 type TestRecord struct { 299 A string `avro:"a"` 300 B string `avro:"b"` 301 } 302 303 var got TestRecord 304 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 305 306 require.NoError(t, err) 307 assert.Equal(t, TestRecord{B: "value", A: "foo"}, got) 308 } 309 310 func TestDecoder_DefaultEnum(t *testing.T) { 311 defer ConfigTeardown() 312 313 data := []byte{0x6, 0x66, 0x6f, 0x6f} 314 315 schema := MustParse(`{ 316 "type": "record", 317 "name": "test", 318 "fields" : [ 319 {"name": "a", "type": "string"}, 320 { 321 "name": "b", 322 "type": { 323 "type": "enum", 324 "name": "test.enum", 325 "symbols": ["foo", "bar"] 326 }, 327 "default": "bar" 328 } 329 ] 330 }`) 331 332 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 333 334 t.Run("simple", func(t *testing.T) { 335 type TestRecord struct { 336 A string `avro:"a"` 337 B string `avro:"b"` 338 } 339 340 var got TestRecord 341 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 342 343 require.NoError(t, err) 344 assert.Equal(t, TestRecord{B: "bar", A: "foo"}, got) 345 346 }) 347 348 t.Run("TextUnmarshaler", func(t *testing.T) { 349 type TestRecord struct { 350 A string `avro:"a"` 351 B testEnumTextUnmarshaler `avro:"b"` 352 } 353 354 var got TestRecord 355 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 356 357 require.NoError(t, err) 358 assert.Equal(t, TestRecord{B: 1, A: "foo"}, got) 359 }) 360 361 t.Run("TextUnmarshaler Ptr", func(t *testing.T) { 362 type TestRecord struct { 363 A string `avro:"a"` 364 B *testEnumTextUnmarshaler `avro:"b"` 365 } 366 367 var got TestRecord 368 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 369 370 require.NoError(t, err) 371 var v testEnumTextUnmarshaler = 1 372 assert.Equal(t, TestRecord{B: &v, A: "foo"}, got) 373 }) 374 } 375 376 func TestDecoder_DefaultUnion(t *testing.T) { 377 defer ConfigTeardown() 378 379 data := []byte{0x6, 0x66, 0x6f, 0x6f} 380 381 t.Run("null default", func(t *testing.T) { 382 type TestRecord struct { 383 A string `avro:"a"` 384 B *string `avro:"b"` 385 } 386 387 schema := MustParse(`{ 388 "type": "record", 389 "name": "test", 390 "fields" : [ 391 {"name": "a", "type": "string"}, 392 {"name": "b", "type": ["null", "long"], "default": null} 393 ] 394 }`) 395 396 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 397 398 var got TestRecord 399 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 400 401 require.NoError(t, err) 402 assert.Equal(t, TestRecord{B: nil, A: "foo"}, got) 403 }) 404 405 t.Run("not null default", func(t *testing.T) { 406 type TestRecord struct { 407 A string `avro:"a"` 408 B any `avro:"b"` 409 } 410 411 schema := MustParse(`{ 412 "type": "record", 413 "name": "test", 414 "fields" : [ 415 {"name": "a", "type": "string"}, 416 {"name": "b", "type": ["string", "long"], "default": "bar"} 417 ] 418 }`) 419 420 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 421 422 var got TestRecord 423 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 424 425 require.NoError(t, err) 426 assert.Equal(t, TestRecord{B: "bar", A: "foo"}, got) 427 }) 428 429 t.Run("map receiver", func(t *testing.T) { 430 type TestRecord struct { 431 A string `avro:"a"` 432 B map[string]any `avro:"b"` 433 } 434 435 schema := MustParse(`{ 436 "type": "record", 437 "name": "test", 438 "fields" : [ 439 {"name": "a", "type": "string"}, 440 {"name": "b", "type": ["string", "long"], "default": "bar"} 441 ] 442 }`) 443 444 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 445 446 var got TestRecord 447 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 448 449 require.NoError(t, err) 450 assert.Equal(t, TestRecord{B: map[string]any{"string": "bar"}, A: "foo"}, got) 451 }) 452 } 453 454 func TestDecoder_DefaultArray(t *testing.T) { 455 defer ConfigTeardown() 456 457 data := []byte{0x6, 0x66, 0x6f, 0x6f} 458 459 schema := MustParse(`{ 460 "type": "record", 461 "name": "test", 462 "fields" : [ 463 {"name": "a", "type": "string"}, 464 { 465 "name": "b", 466 "type": { 467 "type": "array", "items": "int" 468 }, 469 "default":[1, 2, 3, 4] 470 } 471 ] 472 }`) 473 474 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 475 476 dec := NewDecoderForSchema(schema, bytes.NewReader(data)) 477 478 type TestRecord struct { 479 A string `avro:"a"` 480 B []int16 `avro:"b"` 481 } 482 483 var got TestRecord 484 err := dec.Decode(&got) 485 486 require.NoError(t, err) 487 assert.Equal(t, TestRecord{B: []int16{1, 2, 3, 4}, A: "foo"}, got) 488 } 489 490 func TestDecoder_DefaultMap(t *testing.T) { 491 defer ConfigTeardown() 492 493 data := []byte{0x6, 0x66, 0x6f, 0x6f} 494 495 schema := MustParse(`{ 496 "type": "record", 497 "name": "test", 498 "fields" : [ 499 {"name": "a", "type": "string"}, 500 { 501 "name": "b", 502 "type": { 503 "type": "map", "values": "string" 504 }, 505 "default": {"foo":"bar"} 506 } 507 ] 508 }`) 509 510 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 511 512 dec := NewDecoderForSchema(schema, bytes.NewReader(data)) 513 514 type TestRecord struct { 515 A string `avro:"a"` 516 B map[string]string `avro:"b"` 517 } 518 519 var got TestRecord 520 err := dec.Decode(&got) 521 522 require.NoError(t, err) 523 assert.Equal(t, TestRecord{B: map[string]string{"foo": "bar"}, A: "foo"}, got) 524 } 525 526 func TestDecoder_DefaultRecord(t *testing.T) { 527 defer ConfigTeardown() 528 529 data := []byte{0x6, 0x66, 0x6f, 0x6f} 530 531 schema := MustParse(`{ 532 "type": "record", 533 "name": "test", 534 "fields" : [ 535 {"name": "a", "type": "string"}, 536 { 537 "name": "b", 538 "type": { 539 "type": "record", 540 "name": "test.record", 541 "fields" : [ 542 {"name": "a", "type": "string"}, 543 {"name": "b", "type": "string"} 544 ] 545 }, 546 "default": {"a":"foo", "b": "bar"} 547 } 548 ] 549 }`) 550 551 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 552 553 t.Run("struct", func(t *testing.T) { 554 dec := NewDecoderForSchema(schema, bytes.NewReader(data)) 555 556 type subRecord struct { 557 A string `avro:"a"` 558 B string `avro:"b"` 559 } 560 type TestRecord struct { 561 A string `avro:"a"` 562 B subRecord `avro:"b"` 563 } 564 565 var got TestRecord 566 err := dec.Decode(&got) 567 568 require.NoError(t, err) 569 assert.Equal(t, TestRecord{B: subRecord{A: "foo", B: "bar"}, A: "foo"}, got) 570 }) 571 572 t.Run("map", func(t *testing.T) { 573 dec := NewDecoderForSchema(schema, bytes.NewReader(data)) 574 575 var got map[string]any 576 err := dec.Decode(&got) 577 578 require.NoError(t, err) 579 assert.Equal(t, map[string]any{"b": map[string]any{"a": "foo", "b": "bar"}, "a": "foo"}, got) 580 }) 581 } 582 583 func TestDecoder_DefaultRef(t *testing.T) { 584 defer ConfigTeardown() 585 586 data := []byte{0x6, 0x66, 0x6f, 0x6f} 587 588 _ = MustParse(`{ 589 "type": "record", 590 "name": "test.embed", 591 "fields" : [ 592 {"name": "a", "type": "string"} 593 ] 594 }`) 595 596 schema := MustParse(`{ 597 "type": "record", 598 "name": "test", 599 "fields" : [ 600 {"name": "a", "type": "string"}, 601 {"name": "b", "type": "test.embed", "default": {"a": "foo"}} 602 ] 603 }`) 604 605 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 606 607 dec := NewDecoderForSchema(schema, bytes.NewReader(data)) 608 609 var got map[string]any 610 err := dec.Decode(&got) 611 612 require.NoError(t, err) 613 assert.Equal(t, map[string]any{"b": map[string]any{"a": "foo"}, "a": "foo"}, got) 614 } 615 616 func TestDecoder_DefaultFixed(t *testing.T) { 617 defer ConfigTeardown() 618 619 data := []byte{0x6, 0x66, 0x6f, 0x6f} 620 621 t.Run("array", func(t *testing.T) { 622 schema := MustParse(`{ 623 "type": "record", 624 "name": "test", 625 "fields" : [ 626 {"name": "a", "type": "string"}, 627 { 628 "name": "b", 629 "type": { 630 "type": "fixed", 631 "name": "test.fixed", 632 "size": 3 633 }, 634 "default": "foo" 635 } 636 ] 637 }`) 638 639 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 640 641 type TestRecord struct { 642 A string `avro:"a"` 643 B [3]byte `avro:"b"` 644 } 645 646 var got TestRecord 647 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 648 649 require.NoError(t, err) 650 assert.Equal(t, TestRecord{B: [3]byte{'f', 'o', 'o'}, A: "foo"}, got) 651 }) 652 653 t.Run("uint64", func(t *testing.T) { 654 schema := MustParse(`{ 655 "type": "record", 656 "name": "test", 657 "fields" : [ 658 {"name": "a", "type": "string"}, 659 { 660 "name": "b", 661 "type": { 662 "type": "fixed", 663 "name": "test.fixed", 664 "size": 8 665 }, 666 "default": "\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff" 667 } 668 ] 669 }`) 670 671 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 672 673 type TestRecord struct { 674 A string `avro:"a"` 675 B uint64 `avro:"b"` 676 } 677 678 var got TestRecord 679 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 680 681 require.NoError(t, err) 682 assert.Equal(t, TestRecord{B: uint64(math.MaxUint64), A: "foo"}, got) 683 }) 684 685 t.Run("duration", func(t *testing.T) { 686 schema := MustParse(`{ 687 "type": "record", 688 "name": "test", 689 "fields" : [ 690 {"name": "a", "type": "string"}, 691 { 692 "name": "b", 693 "type": { 694 "type": "fixed", 695 "name": "test.fixed", 696 "logicalType":"duration", 697 "size":12 698 }, 699 "default": "\u000c\u0000\u0000\u0000\u0022\u0000\u0000\u0000\u0052\u00aa\u0008\u0000" 700 } 701 ] 702 }`) 703 704 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 705 706 type TestRecord struct { 707 A string `avro:"a"` 708 B LogicalDuration `avro:"b"` 709 } 710 711 var got TestRecord 712 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 713 714 require.NoError(t, err) 715 716 assert.Equal(t, uint32(12), got.B.Months) 717 assert.Equal(t, uint32(34), got.B.Days) 718 assert.Equal(t, uint32(567890), got.B.Milliseconds) 719 assert.Equal(t, "foo", got.A) 720 }) 721 722 t.Run("rat", func(t *testing.T) { 723 schema := MustParse(`{ 724 "type": "record", 725 "name": "test", 726 "fields" : [ 727 {"name": "a", "type": "string"}, 728 { 729 "name": "b", 730 "type": { 731 "type": "fixed", 732 "name": "test.fixed", 733 "size": 6, 734 "logicalType":"decimal", 735 "precision":4, 736 "scale":2 737 }, 738 "default": "\u0000\u0000\u0000\u0000\u0087\u0078" 739 } 740 ] 741 }`) 742 schema.(*RecordSchema).Fields()[1].action = FieldSetDefault 743 744 type TestRecord struct { 745 A string `avro:"a"` 746 B big.Rat `avro:"b"` 747 } 748 749 var got TestRecord 750 err := NewDecoderForSchema(schema, bytes.NewReader(data)).Decode(&got) 751 752 require.NoError(t, err) 753 assert.Equal(t, big.NewRat(1734, 5), &got.B) 754 assert.Equal(t, "foo", got.A) 755 }) 756 }