2
0

shared_test.go 10 KB

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