decode_hooks_test.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. package mhayaMapStructure
  2. import (
  3. "errors"
  4. "math/big"
  5. "net"
  6. "reflect"
  7. "testing"
  8. "time"
  9. )
  10. func TestComposeDecodeHookFunc(t *testing.T) {
  11. f1 := func(
  12. f reflect.Kind,
  13. t reflect.Kind,
  14. data interface{}) (interface{}, error) {
  15. return data.(string) + "foo", nil
  16. }
  17. f2 := func(
  18. f reflect.Kind,
  19. t reflect.Kind,
  20. data interface{}) (interface{}, error) {
  21. return data.(string) + "bar", nil
  22. }
  23. f := ComposeDecodeHookFunc(f1, f2)
  24. result, err := DecodeHookExec(
  25. f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
  26. if err != nil {
  27. t.Fatalf("bad: %s", err)
  28. }
  29. if result.(string) != "foobar" {
  30. t.Fatalf("bad: %#v", result)
  31. }
  32. }
  33. func TestComposeDecodeHookFunc_err(t *testing.T) {
  34. f1 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
  35. return nil, errors.New("foo")
  36. }
  37. f2 := func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error) {
  38. panic("NOPE")
  39. }
  40. f := ComposeDecodeHookFunc(f1, f2)
  41. _, err := DecodeHookExec(
  42. f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
  43. if err.Error() != "foo" {
  44. t.Fatalf("bad: %s", err)
  45. }
  46. }
  47. func TestComposeDecodeHookFunc_kinds(t *testing.T) {
  48. var f2From reflect.Kind
  49. f1 := func(
  50. f reflect.Kind,
  51. t reflect.Kind,
  52. data interface{}) (interface{}, error) {
  53. return int(42), nil
  54. }
  55. f2 := func(
  56. f reflect.Kind,
  57. t reflect.Kind,
  58. data interface{}) (interface{}, error) {
  59. f2From = f
  60. return data, nil
  61. }
  62. f := ComposeDecodeHookFunc(f1, f2)
  63. _, err := DecodeHookExec(
  64. f, reflect.ValueOf(""), reflect.ValueOf([]byte("")))
  65. if err != nil {
  66. t.Fatalf("bad: %s", err)
  67. }
  68. if f2From != reflect.Int {
  69. t.Fatalf("bad: %#v", f2From)
  70. }
  71. }
  72. func TestComposeDecodeHookFunc_safe_nofuncs(t *testing.T) {
  73. f := ComposeDecodeHookFunc()
  74. type myStruct2 struct {
  75. MyInt int
  76. }
  77. type myStruct1 struct {
  78. Blah map[string]myStruct2
  79. }
  80. src := &myStruct1{Blah: map[string]myStruct2{
  81. "test": {
  82. MyInt: 1,
  83. },
  84. }}
  85. dst := &myStruct1{}
  86. dConf := &DecoderConfig{
  87. Result: dst,
  88. ErrorUnused: true,
  89. DecodeHook: f,
  90. }
  91. d, err := NewDecoder(dConf)
  92. if err != nil {
  93. t.Fatal(err)
  94. }
  95. err = d.Decode(src)
  96. if err != nil {
  97. t.Fatal(err)
  98. }
  99. }
  100. func TestStringToSliceHookFunc(t *testing.T) {
  101. f := StringToSliceHookFunc(",")
  102. strValue := reflect.ValueOf("42")
  103. sliceValue := reflect.ValueOf([]byte("42"))
  104. cases := []struct {
  105. f, t reflect.Value
  106. result interface{}
  107. err bool
  108. }{
  109. {sliceValue, sliceValue, []byte("42"), false},
  110. {strValue, strValue, "42", false},
  111. {
  112. reflect.ValueOf("foo,bar,baz"),
  113. sliceValue,
  114. []string{"foo", "bar", "baz"},
  115. false,
  116. },
  117. {
  118. reflect.ValueOf(""),
  119. sliceValue,
  120. []string{},
  121. false,
  122. },
  123. }
  124. for i, tc := range cases {
  125. actual, err := DecodeHookExec(f, tc.f, tc.t)
  126. if tc.err != (err != nil) {
  127. t.Fatalf("case %d: expected err %#v", i, tc.err)
  128. }
  129. if !reflect.DeepEqual(actual, tc.result) {
  130. t.Fatalf(
  131. "case %d: expected %#v, got %#v",
  132. i, tc.result, actual)
  133. }
  134. }
  135. }
  136. func TestStringToTimeDurationHookFunc(t *testing.T) {
  137. f := StringToTimeDurationHookFunc()
  138. timeValue := reflect.ValueOf(time.Duration(5))
  139. strValue := reflect.ValueOf("")
  140. cases := []struct {
  141. f, t reflect.Value
  142. result interface{}
  143. err bool
  144. }{
  145. {reflect.ValueOf("5s"), timeValue, 5 * time.Second, false},
  146. {reflect.ValueOf("5"), timeValue, time.Duration(0), true},
  147. {reflect.ValueOf("5"), strValue, "5", false},
  148. }
  149. for i, tc := range cases {
  150. actual, err := DecodeHookExec(f, tc.f, tc.t)
  151. if tc.err != (err != nil) {
  152. t.Fatalf("case %d: expected err %#v", i, tc.err)
  153. }
  154. if !reflect.DeepEqual(actual, tc.result) {
  155. t.Fatalf(
  156. "case %d: expected %#v, got %#v",
  157. i, tc.result, actual)
  158. }
  159. }
  160. }
  161. func TestStringToTimeHookFunc(t *testing.T) {
  162. strValue := reflect.ValueOf("5")
  163. timeValue := reflect.ValueOf(time.Time{})
  164. cases := []struct {
  165. f, t reflect.Value
  166. layout string
  167. result interface{}
  168. err bool
  169. }{
  170. {reflect.ValueOf("2006-01-02T15:04:05Z"), timeValue, time.RFC3339,
  171. time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC), false},
  172. {strValue, timeValue, time.RFC3339, time.Time{}, true},
  173. {strValue, strValue, time.RFC3339, "5", false},
  174. }
  175. for i, tc := range cases {
  176. f := StringToTimeHookFunc(tc.layout)
  177. actual, err := DecodeHookExec(f, tc.f, tc.t)
  178. if tc.err != (err != nil) {
  179. t.Fatalf("case %d: expected err %#v", i, tc.err)
  180. }
  181. if !reflect.DeepEqual(actual, tc.result) {
  182. t.Fatalf(
  183. "case %d: expected %#v, got %#v",
  184. i, tc.result, actual)
  185. }
  186. }
  187. }
  188. func TestStringToIPHookFunc(t *testing.T) {
  189. strValue := reflect.ValueOf("5")
  190. ipValue := reflect.ValueOf(net.IP{})
  191. cases := []struct {
  192. f, t reflect.Value
  193. result interface{}
  194. err bool
  195. }{
  196. {reflect.ValueOf("1.2.3.4"), ipValue,
  197. net.IPv4(0x01, 0x02, 0x03, 0x04), false},
  198. {strValue, ipValue, net.IP{}, true},
  199. {strValue, strValue, "5", false},
  200. }
  201. for i, tc := range cases {
  202. f := StringToIPHookFunc()
  203. actual, err := DecodeHookExec(f, tc.f, tc.t)
  204. if tc.err != (err != nil) {
  205. t.Fatalf("case %d: expected err %#v", i, tc.err)
  206. }
  207. if !reflect.DeepEqual(actual, tc.result) {
  208. t.Fatalf(
  209. "case %d: expected %#v, got %#v",
  210. i, tc.result, actual)
  211. }
  212. }
  213. }
  214. func TestStringToIPNetHookFunc(t *testing.T) {
  215. strValue := reflect.ValueOf("5")
  216. ipNetValue := reflect.ValueOf(net.IPNet{})
  217. var nilNet *net.IPNet = nil
  218. cases := []struct {
  219. f, t reflect.Value
  220. result interface{}
  221. err bool
  222. }{
  223. {reflect.ValueOf("1.2.3.4/24"), ipNetValue,
  224. &net.IPNet{
  225. IP: net.IP{0x01, 0x02, 0x03, 0x00},
  226. Mask: net.IPv4Mask(0xff, 0xff, 0xff, 0x00),
  227. }, false},
  228. {strValue, ipNetValue, nilNet, true},
  229. {strValue, strValue, "5", false},
  230. }
  231. for i, tc := range cases {
  232. f := StringToIPNetHookFunc()
  233. actual, err := DecodeHookExec(f, tc.f, tc.t)
  234. if tc.err != (err != nil) {
  235. t.Fatalf("case %d: expected err %#v", i, tc.err)
  236. }
  237. if !reflect.DeepEqual(actual, tc.result) {
  238. t.Fatalf(
  239. "case %d: expected %#v, got %#v",
  240. i, tc.result, actual)
  241. }
  242. }
  243. }
  244. func TestWeaklyTypedHook(t *testing.T) {
  245. var f DecodeHookFunc = WeaklyTypedHook
  246. strValue := reflect.ValueOf("")
  247. cases := []struct {
  248. f, t reflect.Value
  249. result interface{}
  250. err bool
  251. }{
  252. // TO STRING
  253. {
  254. reflect.ValueOf(false),
  255. strValue,
  256. "0",
  257. false,
  258. },
  259. {
  260. reflect.ValueOf(true),
  261. strValue,
  262. "1",
  263. false,
  264. },
  265. {
  266. reflect.ValueOf(float32(7)),
  267. strValue,
  268. "7",
  269. false,
  270. },
  271. {
  272. reflect.ValueOf(int(7)),
  273. strValue,
  274. "7",
  275. false,
  276. },
  277. {
  278. reflect.ValueOf([]uint8("foo")),
  279. strValue,
  280. "foo",
  281. false,
  282. },
  283. {
  284. reflect.ValueOf(uint(7)),
  285. strValue,
  286. "7",
  287. false,
  288. },
  289. }
  290. for i, tc := range cases {
  291. actual, err := DecodeHookExec(f, tc.f, tc.t)
  292. if tc.err != (err != nil) {
  293. t.Fatalf("case %d: expected err %#v", i, tc.err)
  294. }
  295. if !reflect.DeepEqual(actual, tc.result) {
  296. t.Fatalf(
  297. "case %d: expected %#v, got %#v",
  298. i, tc.result, actual)
  299. }
  300. }
  301. }
  302. func TestStructToMapHookFuncTabled(t *testing.T) {
  303. var f DecodeHookFunc = RecursiveStructToMapHookFunc()
  304. type b struct {
  305. TestKey string
  306. }
  307. type a struct {
  308. Sub b
  309. }
  310. testStruct := a{
  311. Sub: b{
  312. TestKey: "testval",
  313. },
  314. }
  315. testMap := map[string]interface{}{
  316. "Sub": map[string]interface{}{
  317. "TestKey": "testval",
  318. },
  319. }
  320. cases := []struct {
  321. name string
  322. receiver interface{}
  323. input interface{}
  324. expected interface{}
  325. err bool
  326. }{
  327. {
  328. "map receiver",
  329. func() interface{} {
  330. var res map[string]interface{}
  331. return &res
  332. }(),
  333. testStruct,
  334. &testMap,
  335. false,
  336. },
  337. {
  338. "interface receiver",
  339. func() interface{} {
  340. var res interface{}
  341. return &res
  342. }(),
  343. testStruct,
  344. func() interface{} {
  345. var exp interface{} = testMap
  346. return &exp
  347. }(),
  348. false,
  349. },
  350. {
  351. "slice receiver errors",
  352. func() interface{} {
  353. var res []string
  354. return &res
  355. }(),
  356. testStruct,
  357. new([]string),
  358. true,
  359. },
  360. {
  361. "slice to slice - no change",
  362. func() interface{} {
  363. var res []string
  364. return &res
  365. }(),
  366. []string{"a", "b"},
  367. &[]string{"a", "b"},
  368. false,
  369. },
  370. {
  371. "string to string - no change",
  372. func() interface{} {
  373. var res string
  374. return &res
  375. }(),
  376. "test",
  377. func() *string {
  378. s := "test"
  379. return &s
  380. }(),
  381. false,
  382. },
  383. }
  384. for _, tc := range cases {
  385. t.Run(tc.name, func(t *testing.T) {
  386. cfg := &DecoderConfig{
  387. DecodeHook: f,
  388. Result: tc.receiver,
  389. }
  390. d, err := NewDecoder(cfg)
  391. if err != nil {
  392. t.Fatalf("unexpected err %#v", err)
  393. }
  394. err = d.Decode(tc.input)
  395. if tc.err != (err != nil) {
  396. t.Fatalf("expected err %#v", err)
  397. }
  398. if !reflect.DeepEqual(tc.expected, tc.receiver) {
  399. t.Fatalf("expected %#v, got %#v",
  400. tc.expected, tc.receiver)
  401. }
  402. })
  403. }
  404. }
  405. func TestTextUnmarshallerHookFunc(t *testing.T) {
  406. cases := []struct {
  407. f, t reflect.Value
  408. result interface{}
  409. err bool
  410. }{
  411. {reflect.ValueOf("42"), reflect.ValueOf(big.Int{}), big.NewInt(42), false},
  412. {reflect.ValueOf("invalid"), reflect.ValueOf(big.Int{}), nil, true},
  413. {reflect.ValueOf("5"), reflect.ValueOf("5"), "5", false},
  414. }
  415. for i, tc := range cases {
  416. f := TextUnmarshallerHookFunc()
  417. actual, err := DecodeHookExec(f, tc.f, tc.t)
  418. if tc.err != (err != nil) {
  419. t.Fatalf("case %d: expected err %#v", i, tc.err)
  420. }
  421. if !reflect.DeepEqual(actual, tc.result) {
  422. t.Fatalf(
  423. "case %d: expected %#v, got %#v",
  424. i, tc.result, actual)
  425. }
  426. }
  427. }