shared_test.go 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389
  1. package dynamodbattribute
  2. import (
  3. "reflect"
  4. "testing"
  5. "time"
  6. "github.com/aws/aws-sdk-go/aws"
  7. "github.com/aws/aws-sdk-go/service/dynamodb"
  8. "github.com/stretchr/testify/assert"
  9. )
  10. type testBinarySetStruct struct {
  11. Binarys [][]byte `dynamodbav:",binaryset"`
  12. }
  13. type testNumberSetStruct struct {
  14. Numbers []int `dynamodbav:",numberset"`
  15. }
  16. type testStringSetStruct struct {
  17. Strings []string `dynamodbav:",stringset"`
  18. }
  19. type testIntAsStringStruct struct {
  20. Value int `dynamodbav:",string"`
  21. }
  22. type testOmitEmptyStruct struct {
  23. Value string `dynamodbav:",omitempty"`
  24. Value2 *string `dynamodbav:",omitempty"`
  25. Value3 int
  26. }
  27. type testAliasedString string
  28. type testAliasedStringSlice []string
  29. type testAliasedInt int
  30. type testAliasedIntSlice []int
  31. type testAliasedMap map[string]int
  32. type testAliasedSlice []string
  33. type testAliasedByteSlice []byte
  34. type testAliasedStruct struct {
  35. Value testAliasedString
  36. Value2 testAliasedInt
  37. Value3 testAliasedMap
  38. Value4 testAliasedSlice
  39. Value5 testAliasedByteSlice
  40. Value6 []testAliasedInt
  41. Value7 []testAliasedString
  42. Value8 []testAliasedByteSlice `dynamodbav:",binaryset"`
  43. Value9 []testAliasedInt `dynamodbav:",numberset"`
  44. Value10 []testAliasedString `dynamodbav:",stringset"`
  45. Value11 testAliasedIntSlice
  46. Value12 testAliasedStringSlice
  47. }
  48. type testNamedPointer *int
  49. var testDate, _ = time.Parse(time.RFC3339, "2016-05-03T17:06:26.209072Z")
  50. var sharedTestCases = []struct {
  51. in *dynamodb.AttributeValue
  52. actual, expected interface{}
  53. err error
  54. }{
  55. { // Binary slice
  56. in: &dynamodb.AttributeValue{B: []byte{48, 49}},
  57. actual: &[]byte{},
  58. expected: []byte{48, 49},
  59. },
  60. { // Binary slice
  61. in: &dynamodb.AttributeValue{B: []byte{48, 49}},
  62. actual: &[]byte{},
  63. expected: []byte{48, 49},
  64. },
  65. { // Binary slice oversized
  66. in: &dynamodb.AttributeValue{B: []byte{48, 49}},
  67. actual: func() *[]byte {
  68. v := make([]byte, 0, 10)
  69. return &v
  70. }(),
  71. expected: []byte{48, 49},
  72. },
  73. { // Binary slice pointer
  74. in: &dynamodb.AttributeValue{B: []byte{48, 49}},
  75. actual: func() **[]byte {
  76. v := make([]byte, 0, 10)
  77. v2 := &v
  78. return &v2
  79. }(),
  80. expected: []byte{48, 49},
  81. },
  82. { // Bool
  83. in: &dynamodb.AttributeValue{BOOL: aws.Bool(true)},
  84. actual: new(bool),
  85. expected: true,
  86. },
  87. { // List
  88. in: &dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{
  89. {N: aws.String("123")},
  90. }},
  91. actual: &[]int{},
  92. expected: []int{123},
  93. },
  94. { // Map, interface
  95. in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
  96. "abc": {N: aws.String("123")},
  97. }},
  98. actual: &map[string]int{},
  99. expected: map[string]int{"abc": 123},
  100. },
  101. { // Map, struct
  102. in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
  103. "Abc": {N: aws.String("123")},
  104. }},
  105. actual: &struct{ Abc int }{},
  106. expected: struct{ Abc int }{Abc: 123},
  107. },
  108. { // Map, struct
  109. in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
  110. "abc": {N: aws.String("123")},
  111. }},
  112. actual: &struct {
  113. Abc int `json:"abc" dynamodbav:"abc"`
  114. }{},
  115. expected: struct {
  116. Abc int `json:"abc" dynamodbav:"abc"`
  117. }{Abc: 123},
  118. },
  119. { // Number, int
  120. in: &dynamodb.AttributeValue{N: aws.String("123")},
  121. actual: new(int),
  122. expected: 123,
  123. },
  124. { // Number, Float
  125. in: &dynamodb.AttributeValue{N: aws.String("123.1")},
  126. actual: new(float64),
  127. expected: float64(123.1),
  128. },
  129. { // Null
  130. in: &dynamodb.AttributeValue{NULL: aws.Bool(true)},
  131. actual: new(string),
  132. expected: "",
  133. },
  134. { // Null ptr
  135. in: &dynamodb.AttributeValue{NULL: aws.Bool(true)},
  136. actual: new(*string),
  137. expected: nil,
  138. },
  139. { // String
  140. in: &dynamodb.AttributeValue{S: aws.String("abc")},
  141. actual: new(string),
  142. expected: "abc",
  143. },
  144. { // Binary Set
  145. in: &dynamodb.AttributeValue{
  146. M: map[string]*dynamodb.AttributeValue{
  147. "Binarys": {BS: [][]byte{{48, 49}, {50, 51}}},
  148. },
  149. },
  150. actual: &testBinarySetStruct{},
  151. expected: testBinarySetStruct{Binarys: [][]byte{{48, 49}, {50, 51}}},
  152. },
  153. { // Number Set
  154. in: &dynamodb.AttributeValue{
  155. M: map[string]*dynamodb.AttributeValue{
  156. "Numbers": {NS: []*string{aws.String("123"), aws.String("321")}},
  157. },
  158. },
  159. actual: &testNumberSetStruct{},
  160. expected: testNumberSetStruct{Numbers: []int{123, 321}},
  161. },
  162. { // String Set
  163. in: &dynamodb.AttributeValue{
  164. M: map[string]*dynamodb.AttributeValue{
  165. "Strings": {SS: []*string{aws.String("abc"), aws.String("efg")}},
  166. },
  167. },
  168. actual: &testStringSetStruct{},
  169. expected: testStringSetStruct{Strings: []string{"abc", "efg"}},
  170. },
  171. { // Int value as string
  172. in: &dynamodb.AttributeValue{
  173. M: map[string]*dynamodb.AttributeValue{
  174. "Value": {S: aws.String("123")},
  175. },
  176. },
  177. actual: &testIntAsStringStruct{},
  178. expected: testIntAsStringStruct{Value: 123},
  179. },
  180. { // Omitempty
  181. in: &dynamodb.AttributeValue{
  182. M: map[string]*dynamodb.AttributeValue{
  183. "Value3": {N: aws.String("0")},
  184. },
  185. },
  186. actual: &testOmitEmptyStruct{},
  187. expected: testOmitEmptyStruct{Value: "", Value2: nil, Value3: 0},
  188. },
  189. { // aliased type
  190. in: &dynamodb.AttributeValue{
  191. M: map[string]*dynamodb.AttributeValue{
  192. "Value": {S: aws.String("123")},
  193. "Value2": {N: aws.String("123")},
  194. "Value3": {M: map[string]*dynamodb.AttributeValue{
  195. "Key": {N: aws.String("321")},
  196. }},
  197. "Value4": {L: []*dynamodb.AttributeValue{
  198. {S: aws.String("1")},
  199. {S: aws.String("2")},
  200. {S: aws.String("3")},
  201. }},
  202. "Value5": {B: []byte{0, 1, 2}},
  203. "Value6": {L: []*dynamodb.AttributeValue{
  204. {N: aws.String("1")},
  205. {N: aws.String("2")},
  206. {N: aws.String("3")},
  207. }},
  208. "Value7": {L: []*dynamodb.AttributeValue{
  209. {S: aws.String("1")},
  210. {S: aws.String("2")},
  211. {S: aws.String("3")},
  212. }},
  213. "Value8": {BS: [][]byte{
  214. {0, 1, 2}, {3, 4, 5},
  215. }},
  216. "Value9": {NS: []*string{
  217. aws.String("1"),
  218. aws.String("2"),
  219. aws.String("3"),
  220. }},
  221. "Value10": {SS: []*string{
  222. aws.String("1"),
  223. aws.String("2"),
  224. aws.String("3"),
  225. }},
  226. "Value11": {L: []*dynamodb.AttributeValue{
  227. {N: aws.String("1")},
  228. {N: aws.String("2")},
  229. {N: aws.String("3")},
  230. }},
  231. "Value12": {L: []*dynamodb.AttributeValue{
  232. {S: aws.String("1")},
  233. {S: aws.String("2")},
  234. {S: aws.String("3")},
  235. }},
  236. },
  237. },
  238. actual: &testAliasedStruct{},
  239. expected: testAliasedStruct{
  240. Value: "123", Value2: 123,
  241. Value3: testAliasedMap{
  242. "Key": 321,
  243. },
  244. Value4: testAliasedSlice{"1", "2", "3"},
  245. Value5: testAliasedByteSlice{0, 1, 2},
  246. Value6: []testAliasedInt{1, 2, 3},
  247. Value7: []testAliasedString{"1", "2", "3"},
  248. Value8: []testAliasedByteSlice{
  249. {0, 1, 2},
  250. {3, 4, 5},
  251. },
  252. Value9: []testAliasedInt{1, 2, 3},
  253. Value10: []testAliasedString{"1", "2", "3"},
  254. Value11: testAliasedIntSlice{1, 2, 3},
  255. Value12: testAliasedStringSlice{"1", "2", "3"},
  256. },
  257. },
  258. {
  259. in: &dynamodb.AttributeValue{N: aws.String("123")},
  260. actual: new(testNamedPointer),
  261. expected: testNamedPointer(aws.Int(123)),
  262. },
  263. { // time.Time
  264. in: &dynamodb.AttributeValue{S: aws.String("2016-05-03T17:06:26.209072Z")},
  265. actual: new(time.Time),
  266. expected: testDate,
  267. },
  268. { // time.Time List
  269. in: &dynamodb.AttributeValue{L: []*dynamodb.AttributeValue{
  270. {S: aws.String("2016-05-03T17:06:26.209072Z")},
  271. {S: aws.String("2016-05-04T17:06:26.209072Z")},
  272. }},
  273. actual: new([]time.Time),
  274. expected: []time.Time{testDate, testDate.Add(24 * time.Hour)},
  275. },
  276. { // time.Time struct
  277. in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
  278. "abc": {S: aws.String("2016-05-03T17:06:26.209072Z")},
  279. }},
  280. actual: &struct {
  281. Abc time.Time `json:"abc" dynamodbav:"abc"`
  282. }{},
  283. expected: struct {
  284. Abc time.Time `json:"abc" dynamodbav:"abc"`
  285. }{Abc: testDate},
  286. },
  287. { // time.Time ptr struct
  288. in: &dynamodb.AttributeValue{M: map[string]*dynamodb.AttributeValue{
  289. "abc": {S: aws.String("2016-05-03T17:06:26.209072Z")},
  290. }},
  291. actual: &struct {
  292. Abc *time.Time `json:"abc" dynamodbav:"abc"`
  293. }{},
  294. expected: struct {
  295. Abc *time.Time `json:"abc" dynamodbav:"abc"`
  296. }{Abc: &testDate},
  297. },
  298. }
  299. var sharedListTestCases = []struct {
  300. in []*dynamodb.AttributeValue
  301. actual, expected interface{}
  302. err error
  303. }{
  304. {
  305. in: []*dynamodb.AttributeValue{
  306. {B: []byte{48, 49}},
  307. {BOOL: aws.Bool(true)},
  308. {N: aws.String("123")},
  309. {S: aws.String("123")},
  310. },
  311. actual: func() *[]interface{} {
  312. v := []interface{}{}
  313. return &v
  314. }(),
  315. expected: []interface{}{[]byte{48, 49}, true, 123., "123"},
  316. },
  317. {
  318. in: []*dynamodb.AttributeValue{
  319. {N: aws.String("1")},
  320. {N: aws.String("2")},
  321. {N: aws.String("3")},
  322. },
  323. actual: &[]interface{}{},
  324. expected: []interface{}{1., 2., 3.},
  325. },
  326. }
  327. var sharedMapTestCases = []struct {
  328. in map[string]*dynamodb.AttributeValue
  329. actual, expected interface{}
  330. err error
  331. }{
  332. {
  333. in: map[string]*dynamodb.AttributeValue{
  334. "B": {B: []byte{48, 49}},
  335. "BOOL": {BOOL: aws.Bool(true)},
  336. "N": {N: aws.String("123")},
  337. "S": {S: aws.String("123")},
  338. },
  339. actual: &map[string]interface{}{},
  340. expected: map[string]interface{}{
  341. "B": []byte{48, 49}, "BOOL": true,
  342. "N": 123., "S": "123",
  343. },
  344. },
  345. }
  346. func assertConvertTest(t *testing.T, i int, actual, expected interface{}, err, expectedErr error) {
  347. i++
  348. if expectedErr != nil {
  349. if err != nil {
  350. assert.Equal(t, expectedErr, err, "case %d", i)
  351. } else {
  352. assert.Fail(t, "", "case %d, expected error, %v", i)
  353. }
  354. } else if err != nil {
  355. assert.Fail(t, "", "case %d, expect no error, got %v", i, err)
  356. } else {
  357. assert.Equal(t, ptrToValue(expected), ptrToValue(actual), "case %d", i)
  358. }
  359. }
  360. func ptrToValue(in interface{}) interface{} {
  361. v := reflect.ValueOf(in)
  362. if v.Kind() == reflect.Ptr {
  363. v = v.Elem()
  364. }
  365. if !v.IsValid() {
  366. return nil
  367. }
  368. if v.Kind() == reflect.Ptr {
  369. return ptrToValue(v.Interface())
  370. }
  371. return v.Interface()
  372. }