github.com/hamba/avro/v2@v2.22.1-0.20240518180522-aff3955acf7d/encoder_record_test.go (about) 1 package avro_test 2 3 import ( 4 "bytes" 5 "testing" 6 7 "github.com/hamba/avro/v2" 8 "github.com/stretchr/testify/assert" 9 "github.com/stretchr/testify/require" 10 ) 11 12 func TestEncoder_RecordStruct(t *testing.T) { 13 defer ConfigTeardown() 14 15 schema := `{ 16 "type": "record", 17 "name": "test", 18 "fields" : [ 19 {"name": "a", "type": "long"}, 20 {"name": "b", "type": "string"} 21 ] 22 }` 23 obj := TestRecord{A: 27, B: "foo"} 24 buf := &bytes.Buffer{} 25 enc, err := avro.NewEncoder(schema, buf) 26 require.NoError(t, err) 27 28 err = enc.Encode(obj) 29 30 require.NoError(t, err) 31 assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes()) 32 } 33 34 func TestEncoder_RecordStructPtr(t *testing.T) { 35 defer ConfigTeardown() 36 37 schema := `{ 38 "type": "record", 39 "name": "test", 40 "fields" : [ 41 {"name": "a", "type": "long"}, 42 {"name": "b", "type": "string"} 43 ] 44 }` 45 obj := &TestRecord{A: 27, B: "foo"} 46 buf := &bytes.Buffer{} 47 enc, err := avro.NewEncoder(schema, buf) 48 require.NoError(t, err) 49 50 err = enc.Encode(obj) 51 52 require.NoError(t, err) 53 assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes()) 54 } 55 56 func TestEncoder_RecordStructPtrNil(t *testing.T) { 57 defer ConfigTeardown() 58 59 schema := `{ 60 "type": "record", 61 "name": "test", 62 "fields" : [ 63 {"name": "a", "type": "long"}, 64 {"name": "b", "type": "string"} 65 ] 66 }` 67 var obj *TestRecord 68 buf := &bytes.Buffer{} 69 enc, err := avro.NewEncoder(schema, buf) 70 require.NoError(t, err) 71 72 err = enc.Encode(obj) 73 74 assert.Error(t, err) 75 } 76 77 func TestEncoder_RecordStructMissingRequiredField(t *testing.T) { 78 defer ConfigTeardown() 79 80 schema := `{ 81 "type": "record", 82 "name": "test", 83 "fields" : [ 84 {"name": "a", "type": "long"}, 85 {"name": "b", "type": "string"} 86 ] 87 }` 88 obj := TestPartialRecord{B: "foo"} 89 buf := &bytes.Buffer{} 90 enc, err := avro.NewEncoder(schema, buf) 91 require.NoError(t, err) 92 93 err = enc.Encode(obj) 94 95 assert.Error(t, err) 96 } 97 98 func TestEncoder_RecordStructWithDefault(t *testing.T) { 99 defer ConfigTeardown() 100 101 schema := `{ 102 "type": "record", 103 "name": "test", 104 "fields" : [ 105 {"name": "a", "type": "long", "default": 27}, 106 {"name": "b", "type": "string"} 107 ] 108 }` 109 obj := TestPartialRecord{B: "foo"} 110 buf := &bytes.Buffer{} 111 enc, err := avro.NewEncoder(schema, buf) 112 require.NoError(t, err) 113 114 err = enc.Encode(obj) 115 116 require.NoError(t, err) 117 assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes()) 118 } 119 120 func TestEncoder_RecordStructPartialWithNullDefault(t *testing.T) { 121 defer ConfigTeardown() 122 123 schema := `{ 124 "type": "record", 125 "name": "test", 126 "fields" : [ 127 {"name": "a", "type": ["null", "string"], "default": null}, 128 {"name": "b", "type": "string"} 129 ] 130 }` 131 obj := TestPartialRecord{B: "foo"} 132 buf := &bytes.Buffer{} 133 enc, err := avro.NewEncoder(schema, buf) 134 require.NoError(t, err) 135 136 err = enc.Encode(obj) 137 138 require.NoError(t, err) 139 assert.Equal(t, []byte{0x00, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes()) 140 } 141 142 func TestEncoder_RecordStructPartialWithSubRecordDefault(t *testing.T) { 143 defer ConfigTeardown() 144 145 _, err := avro.Parse(`{ 146 "type": "record", 147 "name": "test", 148 "fields" : [ 149 {"name": "a", "type": "long"}, 150 {"name": "b", "type": "string"} 151 ] 152 }`) 153 require.NoError(t, err) 154 155 schema := `{ 156 "type": "record", 157 "name": "parent", 158 "fields" : [ 159 { 160 "name": "a", 161 "type": "test", 162 "default": {"a": 1000, "b": "def b"} 163 }, 164 {"name": "b", "type": "string"} 165 ] 166 }` 167 obj := TestPartialRecord{B: "foo"} 168 buf := &bytes.Buffer{} 169 enc, err := avro.NewEncoder(schema, buf) 170 require.NoError(t, err) 171 172 err = enc.Encode(obj) 173 require.NoError(t, err) 174 175 assert.Equal(t, []byte{0xd0, 0xf, 0xa, 0x64, 0x65, 0x66, 0x20, 0x62, 0x6, 0x66, 0x6f, 0x6f}, buf.Bytes()) 176 } 177 178 func TestEncoder_RecordStructWithNullDefault(t *testing.T) { 179 defer ConfigTeardown() 180 181 schema := `{ 182 "type": "record", 183 "name": "test", 184 "fields" : [ 185 {"name": "a", "type": "null", "default": null}, 186 {"name": "b", "type": "string"} 187 ] 188 }` 189 obj := TestPartialRecord{B: "foo"} 190 buf := &bytes.Buffer{} 191 enc, err := avro.NewEncoder(schema, buf) 192 require.NoError(t, err) 193 194 err = enc.Encode(obj) 195 196 require.NoError(t, err) 197 assert.Equal(t, []byte{0x06, 0x66, 0x6f, 0x6f}, buf.Bytes()) 198 } 199 200 func TestEncoder_RecordStructFieldError(t *testing.T) { 201 defer ConfigTeardown() 202 203 schema := `{ 204 "type": "record", 205 "name": "test", 206 "fields" : [ 207 {"name": "a", "type": "string"}, 208 {"name": "b", "type": "string"} 209 ] 210 }` 211 obj := TestRecord{A: 27, B: "foo"} 212 buf := &bytes.Buffer{} 213 enc, err := avro.NewEncoder(schema, buf) 214 require.NoError(t, err) 215 216 err = enc.Encode(obj) 217 218 assert.Error(t, err) 219 } 220 221 func TestEncoder_RecordEmbeddedStruct(t *testing.T) { 222 defer ConfigTeardown() 223 224 schema := `{ 225 "type": "record", 226 "name": "test", 227 "fields" : [ 228 {"name": "a", "type": "long"}, 229 {"name": "b", "type": "string"}, 230 {"name": "c", "type": "string"} 231 ] 232 }` 233 obj := TestEmbeddedRecord{TestEmbed: TestEmbed{A: 27, B: "foo"}, C: "bar"} 234 buf := &bytes.Buffer{} 235 enc, err := avro.NewEncoder(schema, buf) 236 require.NoError(t, err) 237 238 err = enc.Encode(obj) 239 240 require.NoError(t, err) 241 assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f, 0x06, 0x62, 0x61, 0x72}, buf.Bytes()) 242 } 243 244 func TestEncoder_RecordEmbeddedPtrStruct(t *testing.T) { 245 defer ConfigTeardown() 246 247 schema := `{ 248 "type": "record", 249 "name": "test", 250 "fields" : [ 251 {"name": "a", "type": "long"}, 252 {"name": "b", "type": "string"}, 253 {"name": "c", "type": "string"} 254 ] 255 }` 256 obj := TestEmbeddedPtrRecord{TestEmbed: &TestEmbed{A: 27, B: "foo"}, C: "bar"} 257 buf := &bytes.Buffer{} 258 enc, err := avro.NewEncoder(schema, buf) 259 require.NoError(t, err) 260 261 err = enc.Encode(obj) 262 263 require.NoError(t, err) 264 assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f, 0x06, 0x62, 0x61, 0x72}, buf.Bytes()) 265 } 266 267 func TestEncoder_RecordEmbeddedPtrStructNull(t *testing.T) { 268 defer ConfigTeardown() 269 270 schema := `{ 271 "type": "record", 272 "name": "test", 273 "fields" : [ 274 {"name": "a", "type": "long"}, 275 {"name": "b", "type": "string"}, 276 {"name": "c", "type": "string"} 277 ] 278 }` 279 obj := TestEmbeddedPtrRecord{C: "foo"} 280 buf := &bytes.Buffer{} 281 enc, err := avro.NewEncoder(schema, buf) 282 require.NoError(t, err) 283 284 err = enc.Encode(obj) 285 286 assert.Error(t, err) 287 } 288 289 func TestEncoder_RecordEmbeddedIntStruct(t *testing.T) { 290 defer ConfigTeardown() 291 292 schema := `{ 293 "type": "record", 294 "name": "test", 295 "fields" : [ 296 {"name": "a", "type": "long"}, 297 {"name": "b", "type": "string"} 298 ] 299 }` 300 obj := TestEmbeddedIntRecord{TestEmbedInt: 27, B: "foo"} 301 buf := &bytes.Buffer{} 302 enc, err := avro.NewEncoder(schema, buf) 303 require.NoError(t, err) 304 305 err = enc.Encode(obj) 306 307 assert.Error(t, err) 308 } 309 310 func TestEncoder_RecordUnexportedStruct(t *testing.T) { 311 defer ConfigTeardown() 312 313 schema := `{ 314 "type": "record", 315 "name": "test", 316 "fields" : [ 317 {"name": "a", "type": "long"}, 318 {"name": "b", "type": "string"} 319 ] 320 }` 321 obj := TestUnexportedRecord{A: 27, b: "foo"} 322 buf := &bytes.Buffer{} 323 enc, err := avro.NewEncoder(schema, buf) 324 require.NoError(t, err) 325 326 err = enc.Encode(obj) 327 328 assert.Error(t, err) 329 } 330 331 func TestEncoder_RecordMap(t *testing.T) { 332 defer ConfigTeardown() 333 334 schema := `{ 335 "type": "record", 336 "name": "test", 337 "fields" : [ 338 {"name": "a", "type": "long"}, 339 {"name": "b", "type": "string"} 340 ] 341 }` 342 obj := map[string]any{"a": int64(27), "b": "foo"} 343 buf := &bytes.Buffer{} 344 enc, err := avro.NewEncoder(schema, buf) 345 require.NoError(t, err) 346 347 err = enc.Encode(obj) 348 349 require.NoError(t, err) 350 assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes()) 351 } 352 353 func TestEncoder_RecordMapNested(t *testing.T) { 354 defer ConfigTeardown() 355 356 schema := `{ 357 "type": "record", 358 "name": "parent", 359 "fields" : [ 360 {"name": "a", "type": { 361 "type": "record", 362 "name": "test", 363 "fields" : [ 364 {"name": "a", "type": "long"}, 365 {"name": "b", "type": "string"} 366 ]} 367 }, 368 {"name": "b", "type": "string"} 369 ] 370 }` 371 obj := map[string]any{"a": map[string]any{ 372 "a": int64(27), 373 "b": "bar", 374 }, "b": "foo"} 375 buf := &bytes.Buffer{} 376 enc, err := avro.NewEncoder(schema, buf) 377 require.NoError(t, err) 378 379 err = enc.Encode(obj) 380 381 require.NoError(t, err) 382 assert.Equal(t, []byte{0x36, 0x6, 0x62, 0x61, 0x72, 0x6, 0x66, 0x6f, 0x6f}, buf.Bytes()) 383 } 384 385 func TestEncoder_RecordMapNilValue(t *testing.T) { 386 defer ConfigTeardown() 387 388 schema := `{ 389 "type": "record", 390 "name": "test", 391 "fields" : [ 392 {"name": "a", "type": "long"}, 393 {"name": "b", "type": "string"} 394 ] 395 }` 396 obj := map[string]any{"a": int64(27), "b": nil} 397 buf := &bytes.Buffer{} 398 enc, err := avro.NewEncoder(schema, buf) 399 require.NoError(t, err) 400 401 err = enc.Encode(obj) 402 403 assert.Error(t, err) 404 } 405 406 func TestEncoder_RecordMapMissingRequiredField(t *testing.T) { 407 defer ConfigTeardown() 408 409 schema := `{ 410 "type": "record", 411 "name": "test", 412 "fields" : [ 413 {"name": "a", "type": "long"}, 414 {"name": "b", "type": "string"} 415 ] 416 }` 417 obj := map[string]any{"b": "foo"} 418 buf := &bytes.Buffer{} 419 enc, err := avro.NewEncoder(schema, buf) 420 require.NoError(t, err) 421 422 err = enc.Encode(obj) 423 424 assert.Error(t, err) 425 } 426 427 func TestEncoder_RecordMapWithDefault(t *testing.T) { 428 defer ConfigTeardown() 429 430 schema := `{ 431 "type": "record", 432 "name": "test", 433 "fields" : [ 434 {"name": "a", "type": "long", "default": 27}, 435 {"name": "b", "type": "string"} 436 ] 437 }` 438 obj := map[string]any{"b": "foo"} 439 buf := &bytes.Buffer{} 440 enc, err := avro.NewEncoder(schema, buf) 441 require.NoError(t, err) 442 443 err = enc.Encode(obj) 444 445 require.NoError(t, err) 446 assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes()) 447 } 448 449 func TestEncoder_RecordMapWithSubRecordDefault(t *testing.T) { 450 defer ConfigTeardown() 451 452 _, err := avro.Parse(`{ 453 "type": "record", 454 "name": "test", 455 "fields" : [ 456 {"name": "a", "type": "long"}, 457 {"name": "b", "type": "string"} 458 ] 459 }`) 460 require.NoError(t, err) 461 462 schema := `{ 463 "type": "record", 464 "name": "parent", 465 "fields" : [ 466 { 467 "name": "a", 468 "type": "test", 469 "default": {"a": 1000, "b": "def b"} 470 }, 471 {"name": "b", "type": "string"} 472 ] 473 }` 474 475 obj := map[string]any{"b": "foo"} 476 buf := &bytes.Buffer{} 477 enc, err := avro.NewEncoder(schema, buf) 478 require.NoError(t, err) 479 480 err = enc.Encode(obj) 481 require.NoError(t, err) 482 483 assert.Equal(t, []byte{0xd0, 0xf, 0xa, 0x64, 0x65, 0x66, 0x20, 0x62, 0x6, 0x66, 0x6f, 0x6f}, buf.Bytes()) 484 } 485 486 func TestEncoder_RecordMapWithNullDefault(t *testing.T) { 487 defer ConfigTeardown() 488 489 schema := `{ 490 "type": "record", 491 "name": "test", 492 "fields" : [ 493 {"name": "a", "type": "null", "default": null}, 494 {"name": "b", "type": "string"} 495 ] 496 }` 497 obj := map[string]any{"b": "foo"} 498 buf := &bytes.Buffer{} 499 enc, err := avro.NewEncoder(schema, buf) 500 require.NoError(t, err) 501 502 err = enc.Encode(obj) 503 504 require.NoError(t, err) 505 assert.Equal(t, []byte{0x06, 0x66, 0x6f, 0x6f}, buf.Bytes()) 506 } 507 508 func TestEncoder_RecordMapWithUnionNullDefault(t *testing.T) { 509 defer ConfigTeardown() 510 511 schema := `{ 512 "type": "record", 513 "name": "test", 514 "fields" : [ 515 {"name": "a", "type": ["null", "string"], "default": null}, 516 {"name": "b", "type": "string"} 517 ] 518 }` 519 obj := map[string]any{"b": "foo"} 520 buf := &bytes.Buffer{} 521 enc, err := avro.NewEncoder(schema, buf) 522 require.NoError(t, err) 523 524 err = enc.Encode(obj) 525 526 require.NoError(t, err) 527 assert.Equal(t, []byte{0x00, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes()) 528 } 529 530 func TestEncoder_RecordMapWithUnionStringDefault(t *testing.T) { 531 defer ConfigTeardown() 532 533 schema := `{ 534 "type": "record", 535 "name": "test", 536 "fields" : [ 537 {"name": "a", "type": ["string", "null"], "default": "test"}, 538 {"name": "b", "type": "string"} 539 ] 540 }` 541 obj := map[string]any{"b": "foo"} 542 buf := &bytes.Buffer{} 543 enc, err := avro.NewEncoder(schema, buf) 544 require.NoError(t, err) 545 546 err = enc.Encode(obj) 547 548 require.NoError(t, err) 549 assert.Equal(t, []byte{0x0, 0x8, 0x74, 0x65, 0x73, 0x74, 0x6, 0x66, 0x6f, 0x6f}, buf.Bytes()) 550 } 551 552 func TestEncoder_RecordMapInvalidKeyType(t *testing.T) { 553 defer ConfigTeardown() 554 555 schema := `{ 556 "type": "record", 557 "name": "test", 558 "fields" : [ 559 {"name": "a", "type": "null", "default": null}, 560 {"name": "b", "type": "string"} 561 ] 562 }` 563 obj := map[int]any{1: int64(27), 2: "foo"} 564 buf := &bytes.Buffer{} 565 enc, err := avro.NewEncoder(schema, buf) 566 require.NoError(t, err) 567 568 err = enc.Encode(obj) 569 570 assert.Error(t, err) 571 } 572 573 func TestEncoder_RecordMapInvalidValueType(t *testing.T) { 574 defer ConfigTeardown() 575 576 schema := `{ 577 "type": "record", 578 "name": "test", 579 "fields" : [ 580 {"name": "a", "type": "null", "default": null}, 581 {"name": "b", "type": "string"} 582 ] 583 }` 584 obj := map[string]string{"a": "test", "b": "foo"} 585 buf := &bytes.Buffer{} 586 enc, err := avro.NewEncoder(schema, buf) 587 require.NoError(t, err) 588 589 err = enc.Encode(obj) 590 591 assert.Error(t, err) 592 } 593 594 func TestEncoder_RefStruct(t *testing.T) { 595 defer ConfigTeardown() 596 597 schema := `{ 598 "type": "record", 599 "name": "parent", 600 "fields" : [ 601 {"name": "a", "type": { 602 "type": "record", 603 "name": "test", 604 "fields" : [ 605 {"name": "a", "type": "long"}, 606 {"name": "b", "type": "string"} 607 ]} 608 }, 609 {"name": "b", "type": "test"} 610 ] 611 }` 612 obj := TestNestedRecord{ 613 A: TestRecord{A: 27, B: "foo"}, 614 B: TestRecord{A: 27, B: "foo"}, 615 } 616 buf := &bytes.Buffer{} 617 enc, err := avro.NewEncoder(schema, buf) 618 require.NoError(t, err) 619 620 err = enc.Encode(obj) 621 622 require.NoError(t, err) 623 assert.Equal(t, []byte{0x36, 0x06, 0x66, 0x6f, 0x6f, 0x36, 0x06, 0x66, 0x6f, 0x6f}, buf.Bytes()) 624 }