github.com/aavshr/aws-sdk-go@v1.41.3/service/dynamodb/dynamodbattribute/decode_test.go (about)

     1  package dynamodbattribute
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"reflect"
     7  	"strconv"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/aavshr/aws-sdk-go/aws"
    12  	"github.com/aavshr/aws-sdk-go/aws/awserr"
    13  	"github.com/aavshr/aws-sdk-go/service/dynamodb"
    14  )
    15  
    16  func TestUnmarshalErrorTypes(t *testing.T) {
    17  	var _ awserr.Error = (*UnmarshalTypeError)(nil)
    18  	var _ awserr.Error = (*InvalidUnmarshalError)(nil)
    19  }
    20  
    21  func TestUnmarshalShared(t *testing.T) {
    22  	for i, c := range sharedTestCases {
    23  		err := Unmarshal(c.in, c.actual)
    24  		assertConvertTest(t, i, c.actual, c.expected, err, c.err)
    25  	}
    26  }
    27  
    28  func TestUnmarshal(t *testing.T) {
    29  	cases := []struct {
    30  		in               *dynamodb.AttributeValue
    31  		actual, expected interface{}
    32  		err              error
    33  	}{
    34  		//------------
    35  		// Sets
    36  		//------------
    37  		{
    38  			in: &dynamodb.AttributeValue{BS: [][]byte{
    39  				{48, 49}, {50, 51},
    40  			}},
    41  			actual:   &[][]byte{},
    42  			expected: [][]byte{{48, 49}, {50, 51}},
    43  		},
    44  		{
    45  			in: &dynamodb.AttributeValue{NS: []*string{
    46  				aws.String("123"), aws.String("321"),
    47  			}},
    48  			actual:   &[]int{},
    49  			expected: []int{123, 321},
    50  		},
    51  		{
    52  			in: &dynamodb.AttributeValue{NS: []*string{
    53  				aws.String("123"), aws.String("321"),
    54  			}},
    55  			actual:   &[]interface{}{},
    56  			expected: []interface{}{123., 321.},
    57  		},
    58  		{
    59  			in: &dynamodb.AttributeValue{SS: []*string{
    60  				aws.String("abc"), aws.String("123"),
    61  			}},
    62  			actual:   &[]string{},
    63  			expected: &[]string{"abc", "123"},
    64  		},
    65  		{
    66  			in: &dynamodb.AttributeValue{SS: []*string{
    67  				aws.String("abc"), aws.String("123"),
    68  			}},
    69  			actual:   &[]*string{},
    70  			expected: &[]*string{aws.String("abc"), aws.String("123")},
    71  		},
    72  		//------------
    73  		// Interfaces
    74  		//------------
    75  		{
    76  			in: &dynamodb.AttributeValue{B: []byte{48, 49}},
    77  			actual: func() interface{} {
    78  				var v interface{}
    79  				return &v
    80  			}(),
    81  			expected: []byte{48, 49},
    82  		},
    83  		{
    84  			in: &dynamodb.AttributeValue{BS: [][]byte{
    85  				{48, 49}, {50, 51},
    86  			}},
    87  			actual: func() interface{} {
    88  				var v interface{}
    89  				return &v
    90  			}(),
    91  			expected: [][]byte{{48, 49}, {50, 51}},
    92  		},
    93  		{
    94  			in: &dynamodb.AttributeValue{BOOL: aws.Bool(true)},
    95  			actual: func() interface{} {
    96  				var v interface{}
    97  				return &v
    98  			}(),
    99  			expected: bool(true),
   100  		},
   101  		{
   102  			in: &dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{
   103  				{S: aws.String("abc")}, {S: aws.String("123")},
   104  			}},
   105  			actual: func() interface{} {
   106  				var v interface{}
   107  				return &v
   108  			}(),
   109  			expected: []interface{}{"abc", "123"},
   110  		},
   111  		{
   112  			in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
   113  				"123": {S: aws.String("abc")},
   114  				"abc": {S: aws.String("123")},
   115  			}},
   116  			actual: func() interface{} {
   117  				var v interface{}
   118  				return &v
   119  			}(),
   120  			expected: map[string]interface{}{"123": "abc", "abc": "123"},
   121  		},
   122  		{
   123  			in: &dynamodb.AttributeValue{N: aws.String("123")},
   124  			actual: func() interface{} {
   125  				var v interface{}
   126  				return &v
   127  			}(),
   128  			expected: float64(123),
   129  		},
   130  		{
   131  			in: &dynamodb.AttributeValue{NS: []*string{
   132  				aws.String("123"), aws.String("321"),
   133  			}},
   134  			actual: func() interface{} {
   135  				var v interface{}
   136  				return &v
   137  			}(),
   138  			expected: []float64{123., 321.},
   139  		},
   140  		{
   141  			in: &dynamodb.AttributeValue{S: aws.String("123")},
   142  			actual: func() interface{} {
   143  				var v interface{}
   144  				return &v
   145  			}(),
   146  			expected: "123",
   147  		},
   148  		{
   149  			in: &dynamodb.AttributeValue{SS: []*string{
   150  				aws.String("123"), aws.String("321"),
   151  			}},
   152  			actual: func() interface{} {
   153  				var v interface{}
   154  				return &v
   155  			}(),
   156  			expected: []string{"123", "321"},
   157  		},
   158  		{
   159  			in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
   160  				"abc": {S: aws.String("123")},
   161  				"Cba": {S: aws.String("321")},
   162  			}},
   163  			actual:   &struct{ Abc, Cba string }{},
   164  			expected: struct{ Abc, Cba string }{Abc: "123", Cba: "321"},
   165  		},
   166  		{
   167  			in:     &dynamodb.AttributeValue{N: aws.String("512")},
   168  			actual: new(uint8),
   169  			err: &UnmarshalTypeError{
   170  				Value: fmt.Sprintf("number overflow, 512"),
   171  				Type:  reflect.TypeOf(uint8(0)),
   172  			},
   173  		},
   174  		// -------
   175  		// Empty Values
   176  		// -------
   177  		{
   178  			in:       &dynamodb.AttributeValue{B: []byte{}},
   179  			actual:   &[]byte{},
   180  			expected: []byte{},
   181  		},
   182  		{
   183  			in:       &dynamodb.AttributeValue{BS: [][]byte{}},
   184  			actual:   &[][]byte{},
   185  			expected: [][]byte{},
   186  		},
   187  		{
   188  			in:       &dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{}},
   189  			actual:   &[]interface{}{},
   190  			expected: []interface{}{},
   191  		},
   192  		{
   193  			in:       &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{}},
   194  			actual:   &map[string]interface{}{},
   195  			expected: map[string]interface{}{},
   196  		},
   197  		{
   198  			in:     &dynamodb.AttributeValue{N: aws.String("")},
   199  			actual: new(int),
   200  			err:    fmt.Errorf("invalid syntax"),
   201  		},
   202  		{
   203  			in:       &dynamodb.AttributeValue{NS: []*string{}},
   204  			actual:   &[]*string{},
   205  			expected: []*string{},
   206  		},
   207  		{
   208  			in:       &dynamodb.AttributeValue{S: aws.String("")},
   209  			actual:   new(string),
   210  			expected: "",
   211  		},
   212  		{
   213  			in:       &dynamodb.AttributeValue{SS: []*string{}},
   214  			actual:   &[]*string{},
   215  			expected: []*string{},
   216  		},
   217  	}
   218  
   219  	for i, c := range cases {
   220  		err := Unmarshal(c.in, c.actual)
   221  		assertConvertTest(t, i, c.actual, c.expected, err, c.err)
   222  	}
   223  }
   224  
   225  func TestInterfaceInput(t *testing.T) {
   226  	var v interface{}
   227  	expected := []interface{}{"abc", "123"}
   228  	err := Unmarshal(&dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{
   229  		{S: aws.String("abc")}, {S: aws.String("123")},
   230  	}}, &v)
   231  	assertConvertTest(t, 0, v, expected, err, nil)
   232  }
   233  
   234  func TestUnmarshalError(t *testing.T) {
   235  	cases := []struct {
   236  		in               *dynamodb.AttributeValue
   237  		actual, expected interface{}
   238  		err              error
   239  	}{
   240  		{
   241  			in:       &dynamodb.AttributeValue{},
   242  			actual:   int(0),
   243  			expected: nil,
   244  			err:      &InvalidUnmarshalError{Type: reflect.TypeOf(int(0))},
   245  		},
   246  	}
   247  
   248  	for i, c := range cases {
   249  		err := Unmarshal(c.in, c.actual)
   250  		assertConvertTest(t, i, c.actual, c.expected, err, c.err)
   251  	}
   252  }
   253  
   254  func TestUnmarshalListShared(t *testing.T) {
   255  	for i, c := range sharedListTestCases {
   256  		err := UnmarshalList(c.in, c.actual)
   257  		assertConvertTest(t, i, c.actual, c.expected, err, c.err)
   258  	}
   259  }
   260  
   261  func TestUnmarshalListError(t *testing.T) {
   262  	cases := []struct {
   263  		in               []*dynamodb.AttributeValue
   264  		actual, expected interface{}
   265  		err              error
   266  	}{
   267  		{
   268  			in:       []*dynamodb.AttributeValue{},
   269  			actual:   []interface{}{},
   270  			expected: nil,
   271  			err:      &InvalidUnmarshalError{Type: reflect.TypeOf([]interface{}{})},
   272  		},
   273  	}
   274  
   275  	for i, c := range cases {
   276  		err := UnmarshalList(c.in, c.actual)
   277  		assertConvertTest(t, i, c.actual, c.expected, err, c.err)
   278  	}
   279  }
   280  
   281  func TestUnmarshalConvertToData(t *testing.T) {
   282  	type T struct {
   283  		Int       int
   284  		Str       string
   285  		ByteSlice []byte
   286  		StrSlice  []string
   287  	}
   288  
   289  	exp := T{
   290  		Int:       42,
   291  		Str:       "foo",
   292  		ByteSlice: []byte{42, 97, 83},
   293  		StrSlice:  []string{"cat", "dog"},
   294  	}
   295  	av, err := ConvertToMap(exp)
   296  	if err != nil {
   297  		t.Fatalf("expect no error, got %v", err)
   298  	}
   299  
   300  	var act T
   301  	err = UnmarshalMap(av, &act)
   302  	assertConvertTest(t, 0, act, exp, err, nil)
   303  }
   304  
   305  func TestUnmarshalMapShared(t *testing.T) {
   306  	for i, c := range sharedMapTestCases {
   307  		err := UnmarshalMap(c.in, c.actual)
   308  		assertConvertTest(t, i, c.actual, c.expected, err, c.err)
   309  	}
   310  }
   311  
   312  func TestUnmarshalMapError(t *testing.T) {
   313  	cases := []struct {
   314  		in               map[string]*dynamodb.AttributeValue
   315  		actual, expected interface{}
   316  		err              error
   317  	}{
   318  		{
   319  			in:       map[string]*dynamodb.AttributeValue{},
   320  			actual:   map[string]interface{}{},
   321  			expected: nil,
   322  			err:      &InvalidUnmarshalError{Type: reflect.TypeOf(map[string]interface{}{})},
   323  		},
   324  		{
   325  			in: map[string]*dynamodb.AttributeValue{
   326  				"BOOL": {BOOL: aws.Bool(true)},
   327  			},
   328  			actual:   &map[int]interface{}{},
   329  			expected: nil,
   330  			err:      &UnmarshalTypeError{Value: "map string key", Type: reflect.TypeOf(int(0))},
   331  		},
   332  	}
   333  
   334  	for i, c := range cases {
   335  		err := UnmarshalMap(c.in, c.actual)
   336  		assertConvertTest(t, i, c.actual, c.expected, err, c.err)
   337  	}
   338  }
   339  
   340  func TestUnmarshalListOfMaps(t *testing.T) {
   341  	type testItem struct {
   342  		Value  string
   343  		Value2 int
   344  	}
   345  
   346  	cases := []struct {
   347  		in               []map[string]*dynamodb.AttributeValue
   348  		actual, expected interface{}
   349  		err              error
   350  	}{
   351  		{ // Simple map conversion.
   352  			in: []map[string]*dynamodb.AttributeValue{
   353  				{
   354  					"Value": &dynamodb.AttributeValue{
   355  						BOOL: aws.Bool(true),
   356  					},
   357  				},
   358  			},
   359  			actual: &[]map[string]interface{}{},
   360  			expected: []map[string]interface{}{
   361  				{
   362  					"Value": true,
   363  				},
   364  			},
   365  		},
   366  		{ // attribute to struct.
   367  			in: []map[string]*dynamodb.AttributeValue{
   368  				{
   369  					"Value": &dynamodb.AttributeValue{
   370  						S: aws.String("abc"),
   371  					},
   372  					"Value2": &dynamodb.AttributeValue{
   373  						N: aws.String("123"),
   374  					},
   375  				},
   376  			},
   377  			actual: &[]testItem{},
   378  			expected: []testItem{
   379  				{
   380  					Value:  "abc",
   381  					Value2: 123,
   382  				},
   383  			},
   384  		},
   385  	}
   386  
   387  	for i, c := range cases {
   388  		err := UnmarshalListOfMaps(c.in, c.actual)
   389  		assertConvertTest(t, i, c.actual, c.expected, err, c.err)
   390  	}
   391  }
   392  
   393  type unmarshalUnmarshaler struct {
   394  	Value  string
   395  	Value2 int
   396  	Value3 bool
   397  	Value4 time.Time
   398  }
   399  
   400  func (u *unmarshalUnmarshaler) UnmarshalDynamoDBAttributeValue(av *dynamodb.AttributeValue) error {
   401  	if av.M == nil {
   402  		return fmt.Errorf("expected AttributeValue to be map")
   403  	}
   404  
   405  	if v, ok := av.M["abc"]; !ok {
   406  		return fmt.Errorf("expected `abc` map key")
   407  	} else if v.S == nil {
   408  		return fmt.Errorf("expected `abc` map value string")
   409  	} else {
   410  		u.Value = *v.S
   411  	}
   412  
   413  	if v, ok := av.M["def"]; !ok {
   414  		return fmt.Errorf("expected `def` map key")
   415  	} else if v.N == nil {
   416  		return fmt.Errorf("expected `def` map value number")
   417  	} else {
   418  		n, err := strconv.ParseInt(*v.N, 10, 64)
   419  		if err != nil {
   420  			return err
   421  		}
   422  		u.Value2 = int(n)
   423  	}
   424  
   425  	if v, ok := av.M["ghi"]; !ok {
   426  		return fmt.Errorf("expected `ghi` map key")
   427  	} else if v.BOOL == nil {
   428  		return fmt.Errorf("expected `ghi` map value number")
   429  	} else {
   430  		u.Value3 = *v.BOOL
   431  	}
   432  
   433  	if v, ok := av.M["jkl"]; !ok {
   434  		return fmt.Errorf("expected `jkl` map key")
   435  	} else if v.S == nil {
   436  		return fmt.Errorf("expected `jkl` map value string")
   437  	} else {
   438  		t, err := time.Parse(time.RFC3339, *v.S)
   439  		if err != nil {
   440  			return err
   441  		}
   442  		u.Value4 = t
   443  	}
   444  
   445  	return nil
   446  }
   447  
   448  func TestUnmarshalUnmashaler(t *testing.T) {
   449  	u := &unmarshalUnmarshaler{}
   450  	av := &dynamodb.AttributeValue{
   451  		M: map[string]*dynamodb.AttributeValue{
   452  			"abc": {S: aws.String("value")},
   453  			"def": {N: aws.String("123")},
   454  			"ghi": {BOOL: aws.Bool(true)},
   455  			"jkl": {S: aws.String("2016-05-03T17:06:26.209072Z")},
   456  		},
   457  	}
   458  
   459  	err := Unmarshal(av, u)
   460  	if err != nil {
   461  		t.Errorf("expect no error, got %v", err)
   462  	}
   463  
   464  	if e, a := "value", u.Value; e != a {
   465  		t.Errorf("expect %v, got %v", e, a)
   466  	}
   467  	if e, a := 123, u.Value2; e != a {
   468  		t.Errorf("expect %v, got %v", e, a)
   469  	}
   470  	if e, a := true, u.Value3; e != a {
   471  		t.Errorf("expect %v, got %v", e, a)
   472  	}
   473  	if e, a := testDate, u.Value4; e != a {
   474  		t.Errorf("expect %v, got %v", e, a)
   475  	}
   476  }
   477  
   478  func TestDecodeUseNumber(t *testing.T) {
   479  	u := map[string]interface{}{}
   480  	av := &dynamodb.AttributeValue{
   481  		M: map[string]*dynamodb.AttributeValue{
   482  			"abc": {S: aws.String("value")},
   483  			"def": {N: aws.String("123")},
   484  			"ghi": {BOOL: aws.Bool(true)},
   485  		},
   486  	}
   487  
   488  	decoder := NewDecoder(func(d *Decoder) {
   489  		d.UseNumber = true
   490  	})
   491  	err := decoder.Decode(av, &u)
   492  	if err != nil {
   493  		t.Errorf("expect no error, got %v", err)
   494  	}
   495  
   496  	if e, a := "value", u["abc"]; e != a {
   497  		t.Errorf("expect %v, got %v", e, a)
   498  	}
   499  	n := u["def"].(Number)
   500  	if e, a := "123", n.String(); e != a {
   501  		t.Errorf("expect %v, got %v", e, a)
   502  	}
   503  	if e, a := true, u["ghi"]; e != a {
   504  		t.Errorf("expect %v, got %v", e, a)
   505  	}
   506  }
   507  
   508  func TestDecodeUseJsonNumber(t *testing.T) {
   509  	u := map[string]interface{}{}
   510  	av := &dynamodb.AttributeValue{
   511  		M: map[string]*dynamodb.AttributeValue{
   512  			"abc": {S: aws.String("value")},
   513  			"def": {N: aws.String("123")},
   514  			"ghi": {BOOL: aws.Bool(true)},
   515  		},
   516  	}
   517  
   518  	decoder := NewDecoder(func(d *Decoder) {
   519  		d.UseJsonNumber = true
   520  	})
   521  	err := decoder.Decode(av, &u)
   522  	if err != nil {
   523  		t.Errorf("expect no error, got %v", err)
   524  	}
   525  
   526  	if e, a := "value", u["abc"]; e != a {
   527  		t.Errorf("expect %v, got %v", e, a)
   528  	}
   529  	n := u["def"].(json.Number)
   530  	if e, a := "123", n.String(); e != a {
   531  		t.Errorf("expect %v, got %v", e, a)
   532  	}
   533  	if e, a := true, u["ghi"]; e != a {
   534  		t.Errorf("expect %v, got %v", e, a)
   535  	}
   536  }
   537  
   538  func TestDecodeUseNumberNumberSet(t *testing.T) {
   539  	u := map[string]interface{}{}
   540  	av := &dynamodb.AttributeValue{
   541  		M: map[string]*dynamodb.AttributeValue{
   542  			"ns": {
   543  				NS: []*string{
   544  					aws.String("123"), aws.String("321"),
   545  				},
   546  			},
   547  		},
   548  	}
   549  
   550  	decoder := NewDecoder(func(d *Decoder) {
   551  		d.UseNumber = true
   552  	})
   553  	err := decoder.Decode(av, &u)
   554  	if err != nil {
   555  		t.Errorf("expect no error, got %v", err)
   556  	}
   557  
   558  	ns := u["ns"].([]Number)
   559  
   560  	if e, a := "123", ns[0].String(); e != a {
   561  		t.Errorf("expect %v, got %v", e, a)
   562  	}
   563  	if e, a := "321", ns[1].String(); e != a {
   564  		t.Errorf("expect %v, got %v", e, a)
   565  	}
   566  }
   567  
   568  func TestDecodeEmbeddedPointerStruct(t *testing.T) {
   569  	type B struct {
   570  		Bint int
   571  	}
   572  	type C struct {
   573  		Cint int
   574  	}
   575  	type A struct {
   576  		Aint int
   577  		*B
   578  		*C
   579  	}
   580  	av := &dynamodb.AttributeValue{
   581  		M: map[string]*dynamodb.AttributeValue{
   582  			"Aint": {
   583  				N: aws.String("321"),
   584  			},
   585  			"Bint": {
   586  				N: aws.String("123"),
   587  			},
   588  		},
   589  	}
   590  	decoder := NewDecoder()
   591  	a := A{}
   592  	err := decoder.Decode(av, &a)
   593  	if err != nil {
   594  		t.Errorf("expect no error, got %v", err)
   595  	}
   596  	if e, a := 321, a.Aint; e != a {
   597  		t.Errorf("expect %v, got %v", e, a)
   598  	}
   599  	// Embedded pointer struct can be created automatically.
   600  	if e, a := 123, a.Bint; e != a {
   601  		t.Errorf("expect %v, got %v", e, a)
   602  	}
   603  	// But not for absent fields.
   604  	if a.C != nil {
   605  		t.Errorf("expect nil, got %v", a.C)
   606  	}
   607  }
   608  
   609  func TestDecodeBooleanOverlay(t *testing.T) {
   610  	type BooleanOverlay bool
   611  
   612  	av := &dynamodb.AttributeValue{
   613  		BOOL: aws.Bool(true),
   614  	}
   615  
   616  	decoder := NewDecoder()
   617  
   618  	var v BooleanOverlay
   619  
   620  	err := decoder.Decode(av, &v)
   621  	if err != nil {
   622  		t.Errorf("expect no error, got %v", err)
   623  	}
   624  	if e, a := BooleanOverlay(true), v; e != a {
   625  		t.Errorf("expect %v, got %v", e, a)
   626  	}
   627  }
   628  
   629  func TestDecodeUnixTime(t *testing.T) {
   630  	type A struct {
   631  		Normal time.Time
   632  		Tagged time.Time `dynamodbav:",unixtime"`
   633  		Typed  UnixTime
   634  	}
   635  
   636  	expect := A{
   637  		Normal: time.Unix(123, 0).UTC(),
   638  		Tagged: time.Unix(456, 0),
   639  		Typed:  UnixTime(time.Unix(789, 0)),
   640  	}
   641  
   642  	input := &dynamodb.AttributeValue{
   643  		M: map[string]*dynamodb.AttributeValue{
   644  			"Normal": {
   645  				S: aws.String("1970-01-01T00:02:03Z"),
   646  			},
   647  			"Tagged": {
   648  				N: aws.String("456"),
   649  			},
   650  			"Typed": {
   651  				N: aws.String("789"),
   652  			},
   653  		},
   654  	}
   655  	actual := A{}
   656  
   657  	err := Unmarshal(input, &actual)
   658  	if err != nil {
   659  		t.Errorf("expect no error, got %v", err)
   660  	}
   661  	if e, a := expect, actual; e != a {
   662  		t.Errorf("expect %v, got %v", e, a)
   663  	}
   664  }
   665  
   666  func TestDecodeAliasedUnixTime(t *testing.T) {
   667  	type A struct {
   668  		Normal AliasedTime
   669  		Tagged AliasedTime `dynamodbav:",unixtime"`
   670  	}
   671  
   672  	expect := A{
   673  		Normal: AliasedTime(time.Unix(123, 0).UTC()),
   674  		Tagged: AliasedTime(time.Unix(456, 0)),
   675  	}
   676  
   677  	input := &dynamodb.AttributeValue{
   678  		M: map[string]*dynamodb.AttributeValue{
   679  			"Normal": {
   680  				S: aws.String("1970-01-01T00:02:03Z"),
   681  			},
   682  			"Tagged": {
   683  				N: aws.String("456"),
   684  			},
   685  		},
   686  	}
   687  	actual := A{}
   688  
   689  	err := Unmarshal(input, &actual)
   690  	if err != nil {
   691  		t.Errorf("expect no error, got %v", err)
   692  	}
   693  	if expect != actual {
   694  		t.Errorf("expect %v, got %v", expect, actual)
   695  	}
   696  }
   697  
   698  func TestDecoderFieldByIndex(t *testing.T) {
   699  	type (
   700  		Middle struct{ Inner int }
   701  		Outer  struct{ *Middle }
   702  	)
   703  	var outer Outer
   704  
   705  	outerType := reflect.TypeOf(outer)
   706  	outerValue := reflect.ValueOf(&outer)
   707  	outerFields := unionStructFields(outerType, MarshalOptions{})
   708  	innerField, _ := outerFields.FieldByName("Inner")
   709  
   710  	f := decoderFieldByIndex(outerValue.Elem(), innerField.Index)
   711  	if outer.Middle == nil {
   712  		t.Errorf("expected outer.Middle to be non-nil")
   713  	}
   714  	if f.Kind() != reflect.Int || f.Int() != int64(outer.Inner) {
   715  		t.Error("expected f to be an int with value equal to outer.Inner")
   716  	}
   717  }
   718  
   719  func TestDecodeAliasType(t *testing.T) {
   720  	type Str string
   721  	type Int int
   722  	type Uint uint
   723  	type TT struct {
   724  		A Str
   725  		B Int
   726  		C Uint
   727  		S Str
   728  	}
   729  
   730  	expect := TT{
   731  		A: "12345",
   732  		B: 12345,
   733  		C: 12345,
   734  		S: "string",
   735  	}
   736  	m := map[string]*dynamodb.AttributeValue{
   737  		"A": {
   738  			N: aws.String("12345"),
   739  		},
   740  		"B": {
   741  			N: aws.String("12345"),
   742  		},
   743  		"C": {
   744  			N: aws.String("12345"),
   745  		},
   746  		"S": {
   747  			S: aws.String("string"),
   748  		},
   749  	}
   750  
   751  	var actual TT
   752  	err := UnmarshalMap(m, &actual)
   753  	if err != nil {
   754  		t.Fatalf("expect no error, got %v", err)
   755  	}
   756  
   757  	if !reflect.DeepEqual(expect, actual) {
   758  		t.Errorf("expect:\n%v\nactual:\n%v", expect, actual)
   759  	}
   760  }