github.com/aavshr/aws-sdk-go@v1.41.3/service/dynamodb/dynamodbattribute/marshaler_test.go (about) 1 package dynamodbattribute 2 3 import ( 4 "encoding/json" 5 "math" 6 "reflect" 7 "testing" 8 9 "github.com/aavshr/aws-sdk-go/aws" 10 "github.com/aavshr/aws-sdk-go/aws/awserr" 11 "github.com/aavshr/aws-sdk-go/aws/awsutil" 12 "github.com/aavshr/aws-sdk-go/service/dynamodb" 13 ) 14 15 type simpleMarshalStruct struct { 16 Byte []byte 17 String string 18 Int int 19 Uint uint 20 Float32 float32 21 Float64 float64 22 Bool bool 23 Null *interface{} 24 } 25 26 type complexMarshalStruct struct { 27 Simple []simpleMarshalStruct 28 } 29 30 type myByteStruct struct { 31 Byte []byte 32 } 33 34 type myByteSetStruct struct { 35 ByteSet [][]byte 36 } 37 38 type marshallerTestInput struct { 39 input interface{} 40 expected interface{} 41 err awserr.Error 42 } 43 44 var marshalerScalarInputs = []marshallerTestInput{ 45 { 46 input: nil, 47 expected: &dynamodb.AttributeValue{NULL: &trueValue}, 48 }, 49 { 50 input: "some string", 51 expected: &dynamodb.AttributeValue{S: aws.String("some string")}, 52 }, 53 { 54 input: true, 55 expected: &dynamodb.AttributeValue{BOOL: &trueValue}, 56 }, 57 { 58 input: false, 59 expected: &dynamodb.AttributeValue{BOOL: &falseValue}, 60 }, 61 { 62 input: 3.14, 63 expected: &dynamodb.AttributeValue{N: aws.String("3.14")}, 64 }, 65 { 66 input: math.MaxFloat32, 67 expected: &dynamodb.AttributeValue{N: aws.String("340282346638528860000000000000000000000")}, 68 }, 69 { 70 input: math.MaxFloat64, 71 expected: &dynamodb.AttributeValue{N: aws.String("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")}, 72 }, 73 { 74 input: 12, 75 expected: &dynamodb.AttributeValue{N: aws.String("12")}, 76 }, 77 { 78 input: Number("12"), 79 expected: &dynamodb.AttributeValue{N: aws.String("12")}, 80 }, 81 { 82 input: json.Number("456"), 83 expected: &dynamodb.AttributeValue{N: aws.String("456")}, 84 }, 85 { 86 input: simpleMarshalStruct{}, 87 expected: &dynamodb.AttributeValue{ 88 M: map[string]*dynamodb.AttributeValue{ 89 "Byte": {NULL: &trueValue}, 90 "Bool": {BOOL: &falseValue}, 91 "Float32": {N: aws.String("0")}, 92 "Float64": {N: aws.String("0")}, 93 "Int": {N: aws.String("0")}, 94 "Null": {NULL: &trueValue}, 95 "String": {NULL: &trueValue}, 96 "Uint": {N: aws.String("0")}, 97 }, 98 }, 99 }, 100 } 101 102 var marshallerMapTestInputs = []marshallerTestInput{ 103 // Scalar tests 104 { 105 input: nil, 106 expected: map[string]*dynamodb.AttributeValue{}, 107 }, 108 { 109 input: map[string]interface{}{"string": "some string"}, 110 expected: map[string]*dynamodb.AttributeValue{"string": {S: aws.String("some string")}}, 111 }, 112 { 113 input: map[string]interface{}{"bool": true}, 114 expected: map[string]*dynamodb.AttributeValue{"bool": {BOOL: &trueValue}}, 115 }, 116 { 117 input: map[string]interface{}{"bool": false}, 118 expected: map[string]*dynamodb.AttributeValue{"bool": {BOOL: &falseValue}}, 119 }, 120 { 121 input: map[string]interface{}{"null": nil}, 122 expected: map[string]*dynamodb.AttributeValue{"null": {NULL: &trueValue}}, 123 }, 124 { 125 input: map[string]interface{}{"float": 3.14}, 126 expected: map[string]*dynamodb.AttributeValue{"float": {N: aws.String("3.14")}}, 127 }, 128 { 129 input: map[string]interface{}{"float": math.MaxFloat32}, 130 expected: map[string]*dynamodb.AttributeValue{"float": {N: aws.String("340282346638528860000000000000000000000")}}, 131 }, 132 { 133 input: map[string]interface{}{"float": math.MaxFloat64}, 134 expected: map[string]*dynamodb.AttributeValue{"float": {N: aws.String("179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000")}}, 135 }, 136 { 137 input: map[string]interface{}{"num": 12.}, 138 expected: map[string]*dynamodb.AttributeValue{"num": {N: aws.String("12")}}, 139 }, 140 { 141 input: map[string]interface{}{"byte": []byte{48, 49}}, 142 expected: map[string]*dynamodb.AttributeValue{"byte": {B: []byte{48, 49}}}, 143 }, 144 { 145 input: struct{ Byte []byte }{Byte: []byte{48, 49}}, 146 expected: map[string]*dynamodb.AttributeValue{"Byte": {B: []byte{48, 49}}}, 147 }, 148 { 149 input: map[string]interface{}{"byte_set": [][]byte{{48, 49}, {50, 51}}}, 150 expected: map[string]*dynamodb.AttributeValue{"byte_set": {BS: [][]byte{{48, 49}, {50, 51}}}}, 151 }, 152 { 153 input: struct{ ByteSet [][]byte }{ByteSet: [][]byte{{48, 49}, {50, 51}}}, 154 expected: map[string]*dynamodb.AttributeValue{"ByteSet": {BS: [][]byte{{48, 49}, {50, 51}}}}, 155 }, 156 // List 157 { 158 input: map[string]interface{}{"list": []interface{}{"a string", 12., 3.14, true, nil, false}}, 159 expected: map[string]*dynamodb.AttributeValue{ 160 "list": { 161 L: []*dynamodb.AttributeValue{ 162 {S: aws.String("a string")}, 163 {N: aws.String("12")}, 164 {N: aws.String("3.14")}, 165 {BOOL: &trueValue}, 166 {NULL: &trueValue}, 167 {BOOL: &falseValue}, 168 }, 169 }, 170 }, 171 }, 172 // Map 173 { 174 input: map[string]interface{}{"map": map[string]interface{}{"nestednum": 12.}}, 175 expected: map[string]*dynamodb.AttributeValue{ 176 "map": { 177 M: map[string]*dynamodb.AttributeValue{ 178 "nestednum": { 179 N: aws.String("12"), 180 }, 181 }, 182 }, 183 }, 184 }, 185 // Structs 186 { 187 input: simpleMarshalStruct{}, 188 expected: map[string]*dynamodb.AttributeValue{ 189 "Byte": {NULL: &trueValue}, 190 "Bool": {BOOL: &falseValue}, 191 "Float32": {N: aws.String("0")}, 192 "Float64": {N: aws.String("0")}, 193 "Int": {N: aws.String("0")}, 194 "Null": {NULL: &trueValue}, 195 "String": {NULL: &trueValue}, 196 "Uint": {N: aws.String("0")}, 197 }, 198 }, 199 { 200 input: complexMarshalStruct{}, 201 expected: map[string]*dynamodb.AttributeValue{ 202 "Simple": {NULL: &trueValue}, 203 }, 204 }, 205 { 206 input: struct { 207 Simple []string `json:"simple"` 208 }{}, 209 expected: map[string]*dynamodb.AttributeValue{ 210 "simple": {NULL: &trueValue}, 211 }, 212 }, 213 { 214 input: struct { 215 Simple []string `json:"simple,omitempty"` 216 }{}, 217 expected: map[string]*dynamodb.AttributeValue{}, 218 }, 219 { 220 input: struct { 221 Simple []string `json:"-"` 222 }{}, 223 expected: map[string]*dynamodb.AttributeValue{}, 224 }, 225 { 226 input: complexMarshalStruct{Simple: []simpleMarshalStruct{{Int: -2}, {Uint: 5}}}, 227 expected: map[string]*dynamodb.AttributeValue{ 228 "Simple": { 229 L: []*dynamodb.AttributeValue{ 230 { 231 M: map[string]*dynamodb.AttributeValue{ 232 "Byte": {NULL: &trueValue}, 233 "Bool": {BOOL: &falseValue}, 234 "Float32": {N: aws.String("0")}, 235 "Float64": {N: aws.String("0")}, 236 "Int": {N: aws.String("-2")}, 237 "Null": {NULL: &trueValue}, 238 "String": {NULL: &trueValue}, 239 "Uint": {N: aws.String("0")}, 240 }, 241 }, 242 { 243 M: map[string]*dynamodb.AttributeValue{ 244 "Byte": {NULL: &trueValue}, 245 "Bool": {BOOL: &falseValue}, 246 "Float32": {N: aws.String("0")}, 247 "Float64": {N: aws.String("0")}, 248 "Int": {N: aws.String("0")}, 249 "Null": {NULL: &trueValue}, 250 "String": {NULL: &trueValue}, 251 "Uint": {N: aws.String("5")}, 252 }, 253 }, 254 }, 255 }, 256 }, 257 }, 258 } 259 260 var marshallerListTestInputs = []marshallerTestInput{ 261 { 262 input: nil, 263 expected: []*dynamodb.AttributeValue{}, 264 }, 265 { 266 input: []interface{}{}, 267 expected: []*dynamodb.AttributeValue{}, 268 }, 269 { 270 input: []simpleMarshalStruct{}, 271 expected: []*dynamodb.AttributeValue{}, 272 }, 273 { 274 input: []interface{}{"a string", 12., 3.14, true, nil, false}, 275 expected: []*dynamodb.AttributeValue{ 276 {S: aws.String("a string")}, 277 {N: aws.String("12")}, 278 {N: aws.String("3.14")}, 279 {BOOL: &trueValue}, 280 {NULL: &trueValue}, 281 {BOOL: &falseValue}, 282 }, 283 }, 284 { 285 input: []simpleMarshalStruct{{}}, 286 expected: []*dynamodb.AttributeValue{ 287 { 288 M: map[string]*dynamodb.AttributeValue{ 289 "Byte": {NULL: &trueValue}, 290 "Bool": {BOOL: &falseValue}, 291 "Float32": {N: aws.String("0")}, 292 "Float64": {N: aws.String("0")}, 293 "Int": {N: aws.String("0")}, 294 "Null": {NULL: &trueValue}, 295 "String": {NULL: &trueValue}, 296 "Uint": {N: aws.String("0")}, 297 }, 298 }, 299 }, 300 }, 301 } 302 303 func Test_New_Marshal(t *testing.T) { 304 for _, test := range marshalerScalarInputs { 305 testMarshal(t, test) 306 } 307 } 308 309 func testMarshal(t *testing.T, test marshallerTestInput) { 310 actual, err := Marshal(test.input) 311 if test.err != nil { 312 if err == nil { 313 t.Errorf("Marshal with input %#v retured %#v, expected error `%s`", test.input, actual, test.err) 314 } else if err.Error() != test.err.Error() { 315 t.Errorf("Marshal with input %#v retured error `%s`, expected error `%s`", test.input, err, test.err) 316 } 317 } else { 318 if err != nil { 319 t.Errorf("Marshal with input %#v retured error `%s`", test.input, err) 320 } 321 compareObjects(t, test.expected, actual) 322 } 323 } 324 325 func Test_New_Unmarshal(t *testing.T) { 326 // Using the same inputs from Marshal, test the reverse mapping. 327 for i, test := range marshalerScalarInputs { 328 if test.input == nil { 329 continue 330 } 331 actual := reflect.New(reflect.TypeOf(test.input)).Interface() 332 if err := Unmarshal(test.expected.(*dynamodb.AttributeValue), actual); err != nil { 333 t.Errorf("Unmarshal %d, with input %#v retured error `%s`", i+1, test.expected, err) 334 } 335 compareObjects(t, test.input, reflect.ValueOf(actual).Elem().Interface()) 336 } 337 } 338 339 func Test_New_UnmarshalError(t *testing.T) { 340 // Test that we get an error using Unmarshal to convert to a nil value. 341 expected := &InvalidUnmarshalError{Type: reflect.TypeOf(nil)} 342 if err := Unmarshal(nil, nil); err == nil { 343 t.Errorf("Unmarshal with input %T returned no error, expected error `%v`", nil, expected) 344 } else if err.Error() != expected.Error() { 345 t.Errorf("Unmarshal with input %T returned error `%v`, expected error `%v`", nil, err, expected) 346 } 347 348 // Test that we get an error using Unmarshal to convert to a non-pointer value. 349 var actual map[string]interface{} 350 expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual)} 351 if err := Unmarshal(nil, actual); err == nil { 352 t.Errorf("Unmarshal with input %T returned no error, expected error `%v`", actual, expected) 353 } else if err.Error() != expected.Error() { 354 t.Errorf("Unmarshal with input %T returned error `%v`, expected error `%v`", actual, err, expected) 355 } 356 357 // Test that we get an error using Unmarshal to convert to nil struct. 358 var actual2 *struct{ A int } 359 expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual2)} 360 if err := Unmarshal(nil, actual2); err == nil { 361 t.Errorf("Unmarshal with input %T returned no error, expected error `%v`", actual2, expected) 362 } else if err.Error() != expected.Error() { 363 t.Errorf("Unmarshal with input %T returned error `%v`, expected error `%v`", actual2, err, expected) 364 } 365 } 366 367 func Test_New_MarshalMap(t *testing.T) { 368 for _, test := range marshallerMapTestInputs { 369 testMarshalMap(t, test) 370 } 371 } 372 373 func testMarshalMap(t *testing.T, test marshallerTestInput) { 374 actual, err := MarshalMap(test.input) 375 if test.err != nil { 376 if err == nil { 377 t.Errorf("MarshalMap with input %#v retured %#v, expected error `%s`", test.input, actual, test.err) 378 } else if err.Error() != test.err.Error() { 379 t.Errorf("MarshalMap with input %#v retured error `%s`, expected error `%s`", test.input, err, test.err) 380 } 381 } else { 382 if err != nil { 383 t.Errorf("MarshalMap with input %#v retured error `%s`", test.input, err) 384 } 385 compareObjects(t, test.expected, actual) 386 } 387 } 388 389 func Test_New_UnmarshalMap(t *testing.T) { 390 // Using the same inputs from MarshalMap, test the reverse mapping. 391 for i, test := range marshallerMapTestInputs { 392 if test.input == nil { 393 continue 394 } 395 actual := reflect.New(reflect.TypeOf(test.input)).Interface() 396 if err := UnmarshalMap(test.expected.(map[string]*dynamodb.AttributeValue), actual); err != nil { 397 t.Errorf("Unmarshal %d, with input %#v retured error `%s`", i+1, test.expected, err) 398 } 399 compareObjects(t, test.input, reflect.ValueOf(actual).Elem().Interface()) 400 } 401 } 402 403 func Test_New_UnmarshalMapError(t *testing.T) { 404 // Test that we get an error using UnmarshalMap to convert to a nil value. 405 expected := &InvalidUnmarshalError{Type: reflect.TypeOf(nil)} 406 if err := UnmarshalMap(nil, nil); err == nil { 407 t.Errorf("UnmarshalMap with input %T returned no error, expected error `%v`", nil, expected) 408 } else if err.Error() != expected.Error() { 409 t.Errorf("UnmarshalMap with input %T returned error `%v`, expected error `%v`", nil, err, expected) 410 } 411 412 // Test that we get an error using UnmarshalMap to convert to a non-pointer value. 413 var actual map[string]interface{} 414 expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual)} 415 if err := UnmarshalMap(nil, actual); err == nil { 416 t.Errorf("UnmarshalMap with input %T returned no error, expected error `%v`", actual, expected) 417 } else if err.Error() != expected.Error() { 418 t.Errorf("UnmarshalMap with input %T returned error `%v`, expected error `%v`", actual, err, expected) 419 } 420 421 // Test that we get an error using UnmarshalMap to convert to nil struct. 422 var actual2 *struct{ A int } 423 expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual2)} 424 if err := UnmarshalMap(nil, actual2); err == nil { 425 t.Errorf("UnmarshalMap with input %T returned no error, expected error `%v`", actual2, expected) 426 } else if err.Error() != expected.Error() { 427 t.Errorf("UnmarshalMap with input %T returned error `%v`, expected error `%v`", actual2, err, expected) 428 } 429 } 430 431 func Test_New_MarshalList(t *testing.T) { 432 for _, test := range marshallerListTestInputs { 433 testMarshalList(t, test) 434 } 435 } 436 437 func testMarshalList(t *testing.T, test marshallerTestInput) { 438 actual, err := MarshalList(test.input) 439 if test.err != nil { 440 if err == nil { 441 t.Errorf("MarshalList with input %#v retured %#v, expected error `%s`", test.input, actual, test.err) 442 } else if err.Error() != test.err.Error() { 443 t.Errorf("MarshalList with input %#v retured error `%s`, expected error `%s`", test.input, err, test.err) 444 } 445 } else { 446 if err != nil { 447 t.Errorf("MarshalList with input %#v retured error `%s`", test.input, err) 448 } 449 compareObjects(t, test.expected, actual) 450 } 451 } 452 453 func Test_New_UnmarshalList(t *testing.T) { 454 // Using the same inputs from MarshalList, test the reverse mapping. 455 for i, test := range marshallerListTestInputs { 456 if test.input == nil { 457 continue 458 } 459 iv := reflect.ValueOf(test.input) 460 461 actual := reflect.New(iv.Type()) 462 if iv.Kind() == reflect.Slice { 463 actual.Elem().Set(reflect.MakeSlice(iv.Type(), iv.Len(), iv.Cap())) 464 } 465 466 if err := UnmarshalList(test.expected.([]*dynamodb.AttributeValue), actual.Interface()); err != nil { 467 t.Errorf("Unmarshal %d, with input %#v retured error `%s`", i+1, test.expected, err) 468 } 469 compareObjects(t, test.input, actual.Elem().Interface()) 470 } 471 } 472 473 func Test_New_UnmarshalListError(t *testing.T) { 474 // Test that we get an error using UnmarshalList to convert to a nil value. 475 expected := &InvalidUnmarshalError{Type: reflect.TypeOf(nil)} 476 if err := UnmarshalList(nil, nil); err == nil { 477 t.Errorf("UnmarshalList with input %T returned no error, expected error `%v`", nil, expected) 478 } else if err.Error() != expected.Error() { 479 t.Errorf("UnmarshalList with input %T returned error `%v`, expected error `%v`", nil, err, expected) 480 } 481 482 // Test that we get an error using UnmarshalList to convert to a non-pointer value. 483 var actual map[string]interface{} 484 expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual)} 485 if err := UnmarshalList(nil, actual); err == nil { 486 t.Errorf("UnmarshalList with input %T returned no error, expected error `%v`", actual, expected) 487 } else if err.Error() != expected.Error() { 488 t.Errorf("UnmarshalList with input %T returned error `%v`, expected error `%v`", actual, err, expected) 489 } 490 491 // Test that we get an error using UnmarshalList to convert to nil struct. 492 var actual2 *struct{ A int } 493 expected = &InvalidUnmarshalError{Type: reflect.TypeOf(actual2)} 494 if err := UnmarshalList(nil, actual2); err == nil { 495 t.Errorf("UnmarshalList with input %T returned no error, expected error `%v`", actual2, expected) 496 } else if err.Error() != expected.Error() { 497 t.Errorf("UnmarshalList with input %T returned error `%v`, expected error `%v`", actual2, err, expected) 498 } 499 } 500 501 // see github issue #1594 502 func TestDecodeArrayType(t *testing.T) { 503 cases := []struct { 504 to, from interface{} 505 }{ 506 { 507 &[2]int{1, 2}, 508 &[2]int{}, 509 }, 510 { 511 &[2]int64{1, 2}, 512 &[2]int64{}, 513 }, 514 { 515 &[2]byte{1, 2}, 516 &[2]byte{}, 517 }, 518 { 519 &[2]bool{true, false}, 520 &[2]bool{}, 521 }, 522 { 523 &[2]string{"1", "2"}, 524 &[2]string{}, 525 }, 526 { 527 &[2][]string{{"1", "2"}}, 528 &[2][]string{}, 529 }, 530 } 531 532 for _, c := range cases { 533 marshaled, err := Marshal(c.to) 534 if err != nil { 535 t.Errorf("expected no error, but received %v", err) 536 } 537 538 if err = Unmarshal(marshaled, c.from); err != nil { 539 t.Errorf("expected no error, but received %v", err) 540 } 541 542 if !reflect.DeepEqual(c.to, c.from) { 543 t.Errorf("expected %v, but received %v", c.to, c.from) 544 } 545 } 546 } 547 548 func compareObjects(t *testing.T, expected interface{}, actual interface{}) { 549 if !reflect.DeepEqual(expected, actual) { 550 ev := reflect.ValueOf(expected) 551 av := reflect.ValueOf(actual) 552 t.Errorf("\nExpected kind(%s,%T):\n%s\nActual kind(%s,%T):\n%s\n", 553 ev.Kind(), 554 ev.Interface(), 555 awsutil.Prettify(expected), 556 av.Kind(), 557 ev.Interface(), 558 awsutil.Prettify(actual)) 559 } 560 } 561 562 func BenchmarkMarshalOneMember(b *testing.B) { 563 fieldCache = fieldCacher{} 564 565 simple := simpleMarshalStruct{ 566 String: "abc", 567 Int: 123, 568 Uint: 123, 569 Float32: 123.321, 570 Float64: 123.321, 571 Bool: true, 572 Null: nil, 573 } 574 575 type MyCompositeStruct struct { 576 A simpleMarshalStruct `dynamodbav:"a"` 577 } 578 b.RunParallel(func(pb *testing.PB) { 579 for pb.Next() { 580 if _, err := Marshal(MyCompositeStruct{ 581 A: simple, 582 }); err != nil { 583 b.Error("unexpected error:", err) 584 } 585 } 586 }) 587 } 588 589 func BenchmarkMarshalTwoMembers(b *testing.B) { 590 fieldCache = fieldCacher{} 591 592 simple := simpleMarshalStruct{ 593 String: "abc", 594 Int: 123, 595 Uint: 123, 596 Float32: 123.321, 597 Float64: 123.321, 598 Bool: true, 599 Null: nil, 600 } 601 602 type MyCompositeStruct struct { 603 A simpleMarshalStruct `dynamodbav:"a"` 604 B simpleMarshalStruct `dynamodbav:"b"` 605 } 606 b.RunParallel(func(pb *testing.PB) { 607 for pb.Next() { 608 if _, err := Marshal(MyCompositeStruct{ 609 A: simple, 610 B: simple, 611 }); err != nil { 612 b.Error("unexpected error:", err) 613 } 614 } 615 }) 616 } 617 618 func BenchmarkUnmarshalOneMember(b *testing.B) { 619 fieldCache = fieldCacher{} 620 621 myStructAVMap, _ := Marshal(simpleMarshalStruct{ 622 String: "abc", 623 Int: 123, 624 Uint: 123, 625 Float32: 123.321, 626 Float64: 123.321, 627 Bool: true, 628 Null: nil, 629 }) 630 631 type MyCompositeStructOne struct { 632 A simpleMarshalStruct `dynamodbav:"a"` 633 } 634 var out MyCompositeStructOne 635 avMap := map[string]*dynamodb.AttributeValue{ 636 "a": myStructAVMap, 637 } 638 b.RunParallel(func(pb *testing.PB) { 639 for pb.Next() { 640 if err := Unmarshal(&dynamodb.AttributeValue{M: avMap}, &out); err != nil { 641 b.Error("unexpected error:", err) 642 } 643 } 644 }) 645 } 646 647 func BenchmarkUnmarshalTwoMembers(b *testing.B) { 648 fieldCache = fieldCacher{} 649 650 myStructAVMap, _ := Marshal(simpleMarshalStruct{ 651 String: "abc", 652 Int: 123, 653 Uint: 123, 654 Float32: 123.321, 655 Float64: 123.321, 656 Bool: true, 657 Null: nil, 658 }) 659 660 type MyCompositeStructTwo struct { 661 A simpleMarshalStruct `dynamodbav:"a"` 662 B simpleMarshalStruct `dynamodbav:"b"` 663 } 664 var out MyCompositeStructTwo 665 avMap := map[string]*dynamodb.AttributeValue{ 666 "a": myStructAVMap, 667 "b": myStructAVMap, 668 } 669 b.RunParallel(func(pb *testing.PB) { 670 for pb.Next() { 671 if err := Unmarshal(&dynamodb.AttributeValue{M: avMap}, &out); err != nil { 672 b.Error("unexpected error:", err) 673 } 674 } 675 }) 676 } 677 678 func Test_Encode_YAML_TagKey(t *testing.T) { 679 input := struct { 680 String string `yaml:"string"` 681 EmptyString string `yaml:"empty"` 682 OmitString string `yaml:"omitted,omitempty"` 683 Ignored string `yaml:"-"` 684 Byte []byte `yaml:"byte"` 685 Float32 float32 `yaml:"float32"` 686 Float64 float64 `yaml:"float64"` 687 Int int `yaml:"int"` 688 Uint uint `yaml:"uint"` 689 Slice []string `yaml:"slice"` 690 Map map[string]int `yaml:"map"` 691 NoTag string 692 }{ 693 String: "String", 694 Ignored: "Ignored", 695 Slice: []string{"one", "two"}, 696 Map: map[string]int{ 697 "one": 1, 698 "two": 2, 699 }, 700 NoTag: "NoTag", 701 } 702 703 expected := &dynamodb.AttributeValue{ 704 M: map[string]*dynamodb.AttributeValue{ 705 "string": {S: aws.String("String")}, 706 "empty": {NULL: &trueValue}, 707 "byte": {NULL: &trueValue}, 708 "float32": {N: aws.String("0")}, 709 "float64": {N: aws.String("0")}, 710 "int": {N: aws.String("0")}, 711 "uint": {N: aws.String("0")}, 712 "slice": { 713 L: []*dynamodb.AttributeValue{ 714 {S: aws.String("one")}, 715 {S: aws.String("two")}, 716 }, 717 }, 718 "map": { 719 M: map[string]*dynamodb.AttributeValue{ 720 "one": {N: aws.String("1")}, 721 "two": {N: aws.String("2")}, 722 }, 723 }, 724 "NoTag": {S: aws.String("NoTag")}, 725 }, 726 } 727 728 enc := NewEncoder(func(e *Encoder) { 729 e.TagKey = "yaml" 730 }) 731 732 actual, err := enc.Encode(input) 733 if err != nil { 734 t.Errorf("Encode with input %#v retured error `%s`, expected nil", input, err) 735 } 736 737 compareObjects(t, expected, actual) 738 }