1package dynamodbattribute 2 3import ( 4 "reflect" 5 "testing" 6 7 "github.com/aws/aws-sdk-go/aws" 8 "github.com/aws/aws-sdk-go/service/dynamodb" 9) 10 11type testEmptyCollectionsNumericalScalars struct { 12 String string 13 14 Uint8 uint8 15 Uint16 uint16 16 Uint32 uint32 17 Uint64 uint64 18 19 Int8 int8 20 Int16 int16 21 Int32 int32 22 Int64 int64 23 24 Float32 float32 25 Float64 float64 26} 27 28type testEmptyCollectionsOmittedNumericalScalars struct { 29 String string `dynamodbav:",omitempty"` 30 31 Uint8 uint8 `dynamodbav:",omitempty"` 32 Uint16 uint16 `dynamodbav:",omitempty"` 33 Uint32 uint32 `dynamodbav:",omitempty"` 34 Uint64 uint64 `dynamodbav:",omitempty"` 35 36 Int8 int8 `dynamodbav:",omitempty"` 37 Int16 int16 `dynamodbav:",omitempty"` 38 Int32 int32 `dynamodbav:",omitempty"` 39 Int64 int64 `dynamodbav:",omitempty"` 40 41 Float32 float32 `dynamodbav:",omitempty"` 42 Float64 float64 `dynamodbav:",omitempty"` 43} 44 45type testEmptyCollectionsPtrScalars struct { 46 PtrString *string 47 48 PtrUint8 *uint8 49 PtrUint16 *uint16 50 PtrUint32 *uint32 51 PtrUint64 *uint64 52 53 PtrInt8 *int8 54 PtrInt16 *int16 55 PtrInt32 *int32 56 PtrInt64 *int64 57 58 PtrFloat32 *float32 59 PtrFloat64 *float64 60} 61 62type testEmptyCollectionsOmittedPtrNumericalScalars struct { 63 PtrUint8 *uint8 `dynamodbav:",omitempty"` 64 PtrUint16 *uint16 `dynamodbav:",omitempty"` 65 PtrUint32 *uint32 `dynamodbav:",omitempty"` 66 PtrUint64 *uint64 `dynamodbav:",omitempty"` 67 68 PtrInt8 *int8 `dynamodbav:",omitempty"` 69 PtrInt16 *int16 `dynamodbav:",omitempty"` 70 PtrInt32 *int32 `dynamodbav:",omitempty"` 71 PtrInt64 *int64 `dynamodbav:",omitempty"` 72 73 PtrFloat32 *float32 `dynamodbav:",omitempty"` 74 PtrFloat64 *float64 `dynamodbav:",omitempty"` 75} 76 77type testEmptyCollectionTypes struct { 78 Map map[string]string 79 Slice []string 80 ByteSlice []byte 81 ByteArray [4]byte 82 ZeroArray [0]byte 83 BinarySet [][]byte `dynamodbav:",binaryset"` 84 NumberSet []int `dynamodbav:",numberset"` 85 StringSet []string `dynamodbav:",stringset"` 86} 87 88type testEmptyCollectionTypesOmitted struct { 89 Map map[string]string `dynamodbav:",omitempty"` 90 Slice []string `dynamodbav:",omitempty"` 91 ByteSlice []byte `dynamodbav:",omitempty"` 92 ByteArray [4]byte `dynamodbav:",omitempty"` 93 ZeroArray [0]byte `dynamodbav:",omitempty"` 94 BinarySet [][]byte `dynamodbav:",binaryset,omitempty"` 95 NumberSet []int `dynamodbav:",numberset,omitempty"` 96 StringSet []string `dynamodbav:",stringset,omitempty"` 97} 98 99type testEmptyCollectionStruct struct { 100 Int int 101} 102 103type testEmptyCollectionStructOmitted struct { 104 Slice []string `dynamodbav:",omitempty"` 105} 106 107var sharedEmptyCollectionsTestCases = []struct { 108 encoderOpts func(encoder *Encoder) 109 in *dynamodb.AttributeValue 110 actual, expected interface{} 111 err error 112}{ 113 // scalars with zero value 114 0: { 115 in: &dynamodb.AttributeValue{ 116 M: map[string]*dynamodb.AttributeValue{ 117 "String": {NULL: aws.Bool(true)}, 118 "Uint8": {N: aws.String("0")}, 119 "Uint16": {N: aws.String("0")}, 120 "Uint32": {N: aws.String("0")}, 121 "Uint64": {N: aws.String("0")}, 122 "Int8": {N: aws.String("0")}, 123 "Int16": {N: aws.String("0")}, 124 "Int32": {N: aws.String("0")}, 125 "Int64": {N: aws.String("0")}, 126 "Float32": {N: aws.String("0")}, 127 "Float64": {N: aws.String("0")}, 128 }, 129 }, 130 actual: &testEmptyCollectionsNumericalScalars{}, 131 expected: testEmptyCollectionsNumericalScalars{}, 132 }, 133 // scalars with non-zero values 134 1: { 135 in: &dynamodb.AttributeValue{ 136 M: map[string]*dynamodb.AttributeValue{ 137 "String": {S: aws.String("test string")}, 138 "Uint8": {N: aws.String("1")}, 139 "Uint16": {N: aws.String("2")}, 140 "Uint32": {N: aws.String("3")}, 141 "Uint64": {N: aws.String("4")}, 142 "Int8": {N: aws.String("-5")}, 143 "Int16": {N: aws.String("-6")}, 144 "Int32": {N: aws.String("-7")}, 145 "Int64": {N: aws.String("-8")}, 146 "Float32": {N: aws.String("9.9")}, 147 "Float64": {N: aws.String("10.1")}, 148 }, 149 }, 150 actual: &testEmptyCollectionsNumericalScalars{}, 151 expected: testEmptyCollectionsNumericalScalars{ 152 String: "test string", 153 Uint8: 1, 154 Uint16: 2, 155 Uint32: 3, 156 Uint64: 4, 157 Int8: -5, 158 Int16: -6, 159 Int32: -7, 160 Int64: -8, 161 Float32: 9.9, 162 Float64: 10.1, 163 }, 164 }, 165 // omittable scalars with zero value 166 2: { 167 in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{}}, 168 actual: &testEmptyCollectionsOmittedNumericalScalars{}, 169 expected: testEmptyCollectionsOmittedNumericalScalars{}, 170 }, 171 // omittable scalars with non-zero value 172 3: { 173 in: &dynamodb.AttributeValue{ 174 M: map[string]*dynamodb.AttributeValue{ 175 "String": {S: aws.String("test string")}, 176 "Uint8": {N: aws.String("1")}, 177 "Uint16": {N: aws.String("2")}, 178 "Uint32": {N: aws.String("3")}, 179 "Uint64": {N: aws.String("4")}, 180 "Int8": {N: aws.String("-5")}, 181 "Int16": {N: aws.String("-6")}, 182 "Int32": {N: aws.String("-7")}, 183 "Int64": {N: aws.String("-8")}, 184 "Float32": {N: aws.String("9.9")}, 185 "Float64": {N: aws.String("10.1")}, 186 }, 187 }, 188 actual: &testEmptyCollectionsOmittedNumericalScalars{}, 189 expected: testEmptyCollectionsOmittedNumericalScalars{ 190 String: "test string", 191 Uint8: 1, 192 Uint16: 2, 193 Uint32: 3, 194 Uint64: 4, 195 Int8: -5, 196 Int16: -6, 197 Int32: -7, 198 Int64: -8, 199 Float32: 9.9, 200 Float64: 10.1, 201 }, 202 }, 203 // nil pointer scalars 204 4: { 205 in: &dynamodb.AttributeValue{ 206 M: map[string]*dynamodb.AttributeValue{ 207 "PtrString": {NULL: aws.Bool(true)}, 208 "PtrUint8": {NULL: aws.Bool(true)}, 209 "PtrUint16": {NULL: aws.Bool(true)}, 210 "PtrUint32": {NULL: aws.Bool(true)}, 211 "PtrUint64": {NULL: aws.Bool(true)}, 212 "PtrInt8": {NULL: aws.Bool(true)}, 213 "PtrInt16": {NULL: aws.Bool(true)}, 214 "PtrInt32": {NULL: aws.Bool(true)}, 215 "PtrInt64": {NULL: aws.Bool(true)}, 216 "PtrFloat32": {NULL: aws.Bool(true)}, 217 "PtrFloat64": {NULL: aws.Bool(true)}, 218 }, 219 }, 220 actual: &testEmptyCollectionsPtrScalars{}, 221 expected: testEmptyCollectionsPtrScalars{}, 222 }, 223 // non-nil pointer to scalars with zero value 224 5: { 225 in: &dynamodb.AttributeValue{ 226 M: map[string]*dynamodb.AttributeValue{ 227 "PtrString": {NULL: aws.Bool(true)}, 228 "PtrUint8": {N: aws.String("0")}, 229 "PtrUint16": {N: aws.String("0")}, 230 "PtrUint32": {N: aws.String("0")}, 231 "PtrUint64": {N: aws.String("0")}, 232 "PtrInt8": {N: aws.String("0")}, 233 "PtrInt16": {N: aws.String("0")}, 234 "PtrInt32": {N: aws.String("0")}, 235 "PtrInt64": {N: aws.String("0")}, 236 "PtrFloat32": {N: aws.String("0")}, 237 "PtrFloat64": {N: aws.String("0")}, 238 }, 239 }, 240 actual: &testEmptyCollectionsPtrScalars{}, 241 expected: testEmptyCollectionsPtrScalars{ 242 PtrUint8: aws.Uint8(0), 243 PtrUint16: aws.Uint16(0), 244 PtrUint32: aws.Uint32(0), 245 PtrUint64: aws.Uint64(0), 246 PtrInt8: aws.Int8(0), 247 PtrInt16: aws.Int16(0), 248 PtrInt32: aws.Int32(0), 249 PtrInt64: aws.Int64(0), 250 PtrFloat32: aws.Float32(0), 251 PtrFloat64: aws.Float64(0), 252 }, 253 }, 254 // pointer scalars non-nil non-zero 255 6: { 256 in: &dynamodb.AttributeValue{ 257 M: map[string]*dynamodb.AttributeValue{ 258 "PtrString": {S: aws.String("test string")}, 259 "PtrUint8": {N: aws.String("1")}, 260 "PtrUint16": {N: aws.String("2")}, 261 "PtrUint32": {N: aws.String("3")}, 262 "PtrUint64": {N: aws.String("4")}, 263 "PtrInt8": {N: aws.String("-5")}, 264 "PtrInt16": {N: aws.String("-6")}, 265 "PtrInt32": {N: aws.String("-7")}, 266 "PtrInt64": {N: aws.String("-8")}, 267 "PtrFloat32": {N: aws.String("9.9")}, 268 "PtrFloat64": {N: aws.String("10.1")}, 269 }, 270 }, 271 actual: &testEmptyCollectionsPtrScalars{}, 272 expected: testEmptyCollectionsPtrScalars{ 273 PtrString: aws.String("test string"), 274 PtrUint8: aws.Uint8(1), 275 PtrUint16: aws.Uint16(2), 276 PtrUint32: aws.Uint32(3), 277 PtrUint64: aws.Uint64(4), 278 PtrInt8: aws.Int8(-5), 279 PtrInt16: aws.Int16(-6), 280 PtrInt32: aws.Int32(-7), 281 PtrInt64: aws.Int64(-8), 282 PtrFloat32: aws.Float32(9.9), 283 PtrFloat64: aws.Float64(10.1), 284 }, 285 }, 286 // omittable nil pointer scalars 287 7: { 288 in: &dynamodb.AttributeValue{ 289 M: map[string]*dynamodb.AttributeValue{}, 290 }, 291 actual: &testEmptyCollectionsOmittedPtrNumericalScalars{}, 292 expected: testEmptyCollectionsOmittedPtrNumericalScalars{}, 293 }, 294 // omittable non-nil pointer to scalars with zero value 295 8: { 296 in: &dynamodb.AttributeValue{ 297 M: map[string]*dynamodb.AttributeValue{ 298 "PtrUint8": {N: aws.String("0")}, 299 "PtrUint16": {N: aws.String("0")}, 300 "PtrUint32": {N: aws.String("0")}, 301 "PtrUint64": {N: aws.String("0")}, 302 "PtrInt8": {N: aws.String("0")}, 303 "PtrInt16": {N: aws.String("0")}, 304 "PtrInt32": {N: aws.String("0")}, 305 "PtrInt64": {N: aws.String("0")}, 306 "PtrFloat32": {N: aws.String("0")}, 307 "PtrFloat64": {N: aws.String("0")}, 308 }, 309 }, 310 actual: &testEmptyCollectionsOmittedPtrNumericalScalars{}, 311 expected: testEmptyCollectionsOmittedPtrNumericalScalars{ 312 PtrUint8: aws.Uint8(0), 313 PtrUint16: aws.Uint16(0), 314 PtrUint32: aws.Uint32(0), 315 PtrUint64: aws.Uint64(0), 316 PtrInt8: aws.Int8(0), 317 PtrInt16: aws.Int16(0), 318 PtrInt32: aws.Int32(0), 319 PtrInt64: aws.Int64(0), 320 PtrFloat32: aws.Float32(0), 321 PtrFloat64: aws.Float64(0), 322 }, 323 }, 324 // omittable non-nil pointer to non-zero scalar 325 9: { 326 in: &dynamodb.AttributeValue{ 327 M: map[string]*dynamodb.AttributeValue{ 328 "PtrUint8": {N: aws.String("1")}, 329 "PtrUint16": {N: aws.String("2")}, 330 "PtrUint32": {N: aws.String("3")}, 331 "PtrUint64": {N: aws.String("4")}, 332 "PtrInt8": {N: aws.String("-5")}, 333 "PtrInt16": {N: aws.String("-6")}, 334 "PtrInt32": {N: aws.String("-7")}, 335 "PtrInt64": {N: aws.String("-8")}, 336 "PtrFloat32": {N: aws.String("9.9")}, 337 "PtrFloat64": {N: aws.String("10.1")}, 338 }, 339 }, 340 actual: &testEmptyCollectionsOmittedPtrNumericalScalars{}, 341 expected: testEmptyCollectionsOmittedPtrNumericalScalars{ 342 PtrUint8: aws.Uint8(1), 343 PtrUint16: aws.Uint16(2), 344 PtrUint32: aws.Uint32(3), 345 PtrUint64: aws.Uint64(4), 346 PtrInt8: aws.Int8(-5), 347 PtrInt16: aws.Int16(-6), 348 PtrInt32: aws.Int32(-7), 349 PtrInt64: aws.Int64(-8), 350 PtrFloat32: aws.Float32(9.9), 351 PtrFloat64: aws.Float64(10.1), 352 }, 353 }, 354 // maps, slices nil values 355 10: { 356 in: &dynamodb.AttributeValue{ 357 M: map[string]*dynamodb.AttributeValue{ 358 "Map": {NULL: aws.Bool(true)}, 359 "Slice": {NULL: aws.Bool(true)}, 360 "ByteSlice": {NULL: aws.Bool(true)}, 361 "ByteArray": {B: make([]byte, 4)}, 362 "ZeroArray": {B: make([]byte, 0)}, 363 "BinarySet": {NULL: aws.Bool(true)}, 364 "NumberSet": {NULL: aws.Bool(true)}, 365 "StringSet": {NULL: aws.Bool(true)}, 366 }, 367 }, 368 actual: &testEmptyCollectionTypes{}, 369 expected: testEmptyCollectionTypes{}, 370 }, 371 // maps, slices zero values 372 11: { 373 in: &dynamodb.AttributeValue{ 374 M: map[string]*dynamodb.AttributeValue{ 375 "Map": {M: map[string]*dynamodb.AttributeValue{}}, 376 "Slice": {L: []*dynamodb.AttributeValue{}}, 377 "ByteSlice": {B: []byte{}}, 378 "ByteArray": {B: make([]byte, 4)}, 379 "ZeroArray": {B: make([]byte, 0)}, 380 "BinarySet": {BS: [][]byte{}}, 381 "NumberSet": {NS: []*string{}}, 382 "StringSet": {SS: []*string{}}, 383 }, 384 }, 385 actual: &testEmptyCollectionTypes{}, 386 expected: testEmptyCollectionTypes{ 387 Map: map[string]string{}, 388 Slice: []string{}, 389 ByteSlice: []byte{}, 390 ByteArray: [4]byte{}, 391 ZeroArray: [0]byte{}, 392 BinarySet: [][]byte{}, 393 NumberSet: []int{}, 394 StringSet: []string{}, 395 }, 396 }, 397 // maps, slices non-zero values 398 12: { 399 in: &dynamodb.AttributeValue{ 400 M: map[string]*dynamodb.AttributeValue{ 401 "Map": { 402 M: map[string]*dynamodb.AttributeValue{ 403 "key": {S: aws.String("value")}, 404 }, 405 }, 406 "Slice": {L: []*dynamodb.AttributeValue{{S: aws.String("test")}, {S: aws.String("slice")}}}, 407 "ByteSlice": {B: []byte{0, 1}}, 408 "ByteArray": {B: []byte{0, 1, 2, 3}}, 409 "ZeroArray": {B: make([]byte, 0)}, 410 "BinarySet": {BS: [][]byte{{0, 1}, {2, 3}}}, 411 "NumberSet": {NS: []*string{aws.String("0"), aws.String("1")}}, 412 "StringSet": {SS: []*string{aws.String("test"), aws.String("slice")}}, 413 }, 414 }, 415 actual: &testEmptyCollectionTypes{}, 416 expected: testEmptyCollectionTypes{ 417 Map: map[string]string{"key": "value"}, 418 Slice: []string{"test", "slice"}, 419 ByteSlice: []byte{0, 1}, 420 ByteArray: [4]byte{0, 1, 2, 3}, 421 ZeroArray: [0]byte{}, 422 BinarySet: [][]byte{{0, 1}, {2, 3}}, 423 NumberSet: []int{0, 1}, 424 StringSet: []string{"test", "slice"}, 425 }, 426 }, 427 // omittable maps, slices nil values 428 13: { 429 in: &dynamodb.AttributeValue{ 430 M: map[string]*dynamodb.AttributeValue{ 431 "ByteArray": {B: make([]byte, 4)}, 432 }, 433 }, 434 actual: &testEmptyCollectionTypesOmitted{}, 435 expected: testEmptyCollectionTypesOmitted{}, 436 }, 437 // omittable maps, slices zero values 438 14: { 439 in: &dynamodb.AttributeValue{ 440 M: map[string]*dynamodb.AttributeValue{ 441 "Map": {M: map[string]*dynamodb.AttributeValue{}}, 442 "Slice": {L: []*dynamodb.AttributeValue{}}, 443 "ByteSlice": {B: []byte{}}, 444 "ByteArray": {B: make([]byte, 4)}, 445 "BinarySet": {BS: [][]byte{}}, 446 "NumberSet": {NS: []*string{}}, 447 "StringSet": {SS: []*string{}}, 448 }, 449 }, 450 actual: &testEmptyCollectionTypesOmitted{}, 451 expected: testEmptyCollectionTypesOmitted{ 452 Map: map[string]string{}, 453 Slice: []string{}, 454 ByteSlice: []byte{}, 455 ByteArray: [4]byte{}, 456 BinarySet: [][]byte{}, 457 NumberSet: []int{}, 458 StringSet: []string{}, 459 }, 460 }, 461 // omittable maps, slices non-zero values 462 15: { 463 in: &dynamodb.AttributeValue{ 464 M: map[string]*dynamodb.AttributeValue{ 465 "Map": { 466 M: map[string]*dynamodb.AttributeValue{ 467 "key": {S: aws.String("value")}, 468 }, 469 }, 470 "Slice": {L: []*dynamodb.AttributeValue{{S: aws.String("test")}, {S: aws.String("slice")}}}, 471 "ByteSlice": {B: []byte{0, 1}}, 472 "ByteArray": {B: []byte{0, 1, 2, 3}}, 473 "BinarySet": {BS: [][]byte{{0, 1}, {2, 3}}}, 474 "NumberSet": {NS: []*string{aws.String("0"), aws.String("1")}}, 475 "StringSet": {SS: []*string{aws.String("test"), aws.String("slice")}}, 476 }, 477 }, 478 actual: &testEmptyCollectionTypesOmitted{}, 479 expected: testEmptyCollectionTypesOmitted{ 480 Map: map[string]string{"key": "value"}, 481 Slice: []string{"test", "slice"}, 482 ByteSlice: []byte{0, 1}, 483 ByteArray: [4]byte{0, 1, 2, 3}, 484 ZeroArray: [0]byte{}, 485 BinarySet: [][]byte{{0, 1}, {2, 3}}, 486 NumberSet: []int{0, 1}, 487 StringSet: []string{"test", "slice"}, 488 }, 489 }, 490 // structs with members zero 491 16: { 492 in: &dynamodb.AttributeValue{ 493 M: map[string]*dynamodb.AttributeValue{ 494 "Struct": { 495 M: map[string]*dynamodb.AttributeValue{ 496 "Int": {N: aws.String("0")}, 497 }, 498 }, 499 "PtrStruct": {NULL: aws.Bool(true)}, 500 }, 501 }, 502 actual: &struct { 503 Struct testEmptyCollectionStruct 504 PtrStruct *testEmptyCollectionStruct 505 }{}, 506 expected: struct { 507 Struct testEmptyCollectionStruct 508 PtrStruct *testEmptyCollectionStruct 509 }{}, 510 }, 511 // structs with members non-zero value 512 17: { 513 in: &dynamodb.AttributeValue{ 514 M: map[string]*dynamodb.AttributeValue{ 515 "Struct": { 516 M: map[string]*dynamodb.AttributeValue{ 517 "Int": {N: aws.String("1")}, 518 }, 519 }, 520 "PtrStruct": { 521 M: map[string]*dynamodb.AttributeValue{ 522 "Int": {N: aws.String("1")}, 523 }, 524 }, 525 }, 526 }, 527 actual: &struct { 528 Struct testEmptyCollectionStruct 529 PtrStruct *testEmptyCollectionStruct 530 }{}, 531 expected: struct { 532 Struct testEmptyCollectionStruct 533 PtrStruct *testEmptyCollectionStruct 534 }{ 535 Struct: testEmptyCollectionStruct{Int: 1}, 536 PtrStruct: &testEmptyCollectionStruct{Int: 1}, 537 }, 538 }, 539 // struct with omittable members zero value 540 18: { 541 in: &dynamodb.AttributeValue{ 542 M: map[string]*dynamodb.AttributeValue{ 543 "Struct": {M: map[string]*dynamodb.AttributeValue{}}, 544 "PtrStruct": {NULL: aws.Bool(true)}, 545 }, 546 }, 547 actual: &struct { 548 Struct testEmptyCollectionStructOmitted 549 PtrStruct *testEmptyCollectionStructOmitted 550 }{}, 551 expected: struct { 552 Struct testEmptyCollectionStructOmitted 553 PtrStruct *testEmptyCollectionStructOmitted 554 }{}, 555 }, 556 // omittable struct with omittable members zero value 557 19: { 558 in: &dynamodb.AttributeValue{ 559 M: map[string]*dynamodb.AttributeValue{ 560 "Struct": {M: map[string]*dynamodb.AttributeValue{}}, 561 }, 562 }, 563 actual: &struct { 564 Struct testEmptyCollectionStructOmitted `dynamodbav:",omitempty"` 565 PtrStruct *testEmptyCollectionStructOmitted `dynamodbav:",omitempty"` 566 }{}, 567 expected: struct { 568 Struct testEmptyCollectionStructOmitted `dynamodbav:",omitempty"` 569 PtrStruct *testEmptyCollectionStructOmitted `dynamodbav:",omitempty"` 570 }{}, 571 }, 572 // omittable struct with omittable members non-zero value 573 20: { 574 in: &dynamodb.AttributeValue{ 575 M: map[string]*dynamodb.AttributeValue{ 576 "Struct": { 577 M: map[string]*dynamodb.AttributeValue{ 578 "Slice": {L: []*dynamodb.AttributeValue{{S: aws.String("test")}}}, 579 }, 580 }, 581 "InitPtrStruct": { 582 M: map[string]*dynamodb.AttributeValue{ 583 "Slice": {L: []*dynamodb.AttributeValue{{S: aws.String("test")}}}, 584 }, 585 }, 586 }, 587 }, 588 actual: &struct { 589 Struct testEmptyCollectionStructOmitted `dynamodbav:",omitempty"` 590 InitPtrStruct *testEmptyCollectionStructOmitted `dynamodbav:",omitempty"` 591 }{}, 592 expected: struct { 593 Struct testEmptyCollectionStructOmitted `dynamodbav:",omitempty"` 594 InitPtrStruct *testEmptyCollectionStructOmitted `dynamodbav:",omitempty"` 595 }{ 596 Struct: testEmptyCollectionStructOmitted{Slice: []string{"test"}}, 597 InitPtrStruct: &testEmptyCollectionStructOmitted{Slice: []string{"test"}}, 598 }, 599 }, 600 21: { // empty slice and NullEmptyByteSlice disabled 601 encoderOpts: func(encoder *Encoder) { 602 encoder.NullEmptyByteSlice = false 603 }, 604 in: &dynamodb.AttributeValue{ 605 B: []byte{}, 606 }, 607 actual: &[]byte{}, 608 expected: []byte{}, 609 }, 610 22: { // empty slice and NullEmptyByteSlice disabled, and omitempty 611 encoderOpts: func(encoder *Encoder) { 612 encoder.NullEmptyByteSlice = false 613 }, 614 in: &dynamodb.AttributeValue{ 615 M: map[string]*dynamodb.AttributeValue{}, 616 }, 617 actual: &struct { 618 Value []byte `dynamodbav:",omitempty"` 619 }{}, 620 expected: struct { 621 Value []byte `dynamodbav:",omitempty"` 622 }{}, 623 }, 624} 625 626func TestMarshalEmptyCollections(t *testing.T) { 627 for i, c := range sharedEmptyCollectionsTestCases { 628 encoder := NewEncoder(func(e *Encoder) { 629 e.EnableEmptyCollections = true 630 if c.encoderOpts != nil { 631 c.encoderOpts(e) 632 } 633 }) 634 av, err := encoder.Encode(c.expected) 635 assertConvertTest(t, i, av, c.in, err, c.err) 636 } 637} 638 639func TestEmptyCollectionsSpecialCases(t *testing.T) { 640 // ptr string non nil with empty value 641 642 type SpecialCases struct { 643 PtrString *string 644 OmittedPtrString *string `dynamodbav:",omitempty"` 645 } 646 647 expectedEncode := &dynamodb.AttributeValue{ 648 M: map[string]*dynamodb.AttributeValue{ 649 "PtrString": {NULL: aws.Bool(true)}, 650 }, 651 } 652 expectedDecode := SpecialCases{} 653 654 encoder := NewEncoder(func(encoder *Encoder) { 655 encoder.EnableEmptyCollections = true 656 }) 657 658 actualEncode, err := encoder.Encode(&SpecialCases{ 659 PtrString: aws.String(""), 660 OmittedPtrString: aws.String(""), 661 }) 662 if err != nil { 663 t.Fatalf("expected no err got %v", err) 664 } 665 if e, a := expectedEncode, actualEncode; !reflect.DeepEqual(e, a) { 666 t.Errorf("expected %v, got %v", e, a) 667 } 668 669 decoder := NewDecoder(func(decoder *Decoder) { 670 decoder.EnableEmptyCollections = true 671 }) 672 673 var actualDecode SpecialCases 674 err = decoder.Decode(&dynamodb.AttributeValue{}, &actualDecode) 675 if err != nil { 676 t.Fatalf("expected no err got %v", err) 677 } 678 if e, a := expectedDecode, actualDecode; !reflect.DeepEqual(e, a) { 679 t.Errorf("expected %v, got %v", e, a) 680 } 681} 682 683func TestUnmarshalEmptyCollections(t *testing.T) { 684 for i, c := range sharedEmptyCollectionsTestCases { 685 decoder := NewDecoder(func(d *Decoder) { 686 d.EnableEmptyCollections = true 687 }) 688 err := decoder.Decode(c.in, c.actual) 689 assertConvertTest(t, i, c.actual, c.expected, err, c.err) 690 } 691} 692