mapstructure_bugs_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. package mhayaMapStructure
  2. import (
  3. "reflect"
  4. "testing"
  5. "time"
  6. )
  7. // GH-1, GH-10, GH-96
  8. func TestDecode_NilValue(t *testing.T) {
  9. t.Parallel()
  10. tests := []struct {
  11. name string
  12. in interface{}
  13. target interface{}
  14. out interface{}
  15. metaKeys []string
  16. metaUnused []string
  17. }{
  18. {
  19. "all nil",
  20. &map[string]interface{}{
  21. "vfoo": nil,
  22. "vother": nil,
  23. },
  24. &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
  25. &Map{Vfoo: "", Vother: nil},
  26. []string{"Vfoo", "Vother"},
  27. []string{},
  28. },
  29. {
  30. "partial nil",
  31. &map[string]interface{}{
  32. "vfoo": "baz",
  33. "vother": nil,
  34. },
  35. &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
  36. &Map{Vfoo: "baz", Vother: nil},
  37. []string{"Vfoo", "Vother"},
  38. []string{},
  39. },
  40. {
  41. "partial decode",
  42. &map[string]interface{}{
  43. "vother": nil,
  44. },
  45. &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
  46. &Map{Vfoo: "foo", Vother: nil},
  47. []string{"Vother"},
  48. []string{},
  49. },
  50. {
  51. "unused values",
  52. &map[string]interface{}{
  53. "vbar": "bar",
  54. "vfoo": nil,
  55. "vother": nil,
  56. },
  57. &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
  58. &Map{Vfoo: "", Vother: nil},
  59. []string{"Vfoo", "Vother"},
  60. []string{"vbar"},
  61. },
  62. {
  63. "map interface all nil",
  64. &map[interface{}]interface{}{
  65. "vfoo": nil,
  66. "vother": nil,
  67. },
  68. &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
  69. &Map{Vfoo: "", Vother: nil},
  70. []string{"Vfoo", "Vother"},
  71. []string{},
  72. },
  73. {
  74. "map interface partial nil",
  75. &map[interface{}]interface{}{
  76. "vfoo": "baz",
  77. "vother": nil,
  78. },
  79. &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
  80. &Map{Vfoo: "baz", Vother: nil},
  81. []string{"Vfoo", "Vother"},
  82. []string{},
  83. },
  84. {
  85. "map interface partial decode",
  86. &map[interface{}]interface{}{
  87. "vother": nil,
  88. },
  89. &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
  90. &Map{Vfoo: "foo", Vother: nil},
  91. []string{"Vother"},
  92. []string{},
  93. },
  94. {
  95. "map interface unused values",
  96. &map[interface{}]interface{}{
  97. "vbar": "bar",
  98. "vfoo": nil,
  99. "vother": nil,
  100. },
  101. &Map{Vfoo: "foo", Vother: map[string]string{"foo": "bar"}},
  102. &Map{Vfoo: "", Vother: nil},
  103. []string{"Vfoo", "Vother"},
  104. []string{"vbar"},
  105. },
  106. }
  107. for _, tc := range tests {
  108. t.Run(tc.name, func(t *testing.T) {
  109. config := &DecoderConfig{
  110. Metadata: new(Metadata),
  111. Result: tc.target,
  112. ZeroFields: true,
  113. }
  114. decoder, err := NewDecoder(config)
  115. if err != nil {
  116. t.Fatalf("should not error: %s", err)
  117. }
  118. err = decoder.Decode(tc.in)
  119. if err != nil {
  120. t.Fatalf("should not error: %s", err)
  121. }
  122. if !reflect.DeepEqual(tc.out, tc.target) {
  123. t.Fatalf("%q: TestDecode_NilValue() expected: %#v, got: %#v", tc.name, tc.out, tc.target)
  124. }
  125. if !reflect.DeepEqual(tc.metaKeys, config.Metadata.Keys) {
  126. t.Fatalf("%q: Metadata.Keys mismatch expected: %#v, got: %#v", tc.name, tc.metaKeys, config.Metadata.Keys)
  127. }
  128. if !reflect.DeepEqual(tc.metaUnused, config.Metadata.Unused) {
  129. t.Fatalf("%q: Metadata.Unused mismatch expected: %#v, got: %#v", tc.name, tc.metaUnused, config.Metadata.Unused)
  130. }
  131. })
  132. }
  133. }
  134. // #48
  135. func TestNestedTypePointerWithDefaults(t *testing.T) {
  136. t.Parallel()
  137. input := map[string]interface{}{
  138. "vfoo": "foo",
  139. "vbar": map[string]interface{}{
  140. "vstring": "foo",
  141. "vint": 42,
  142. "vbool": true,
  143. },
  144. }
  145. result := NestedPointer{
  146. Vbar: &Basic{
  147. Vuint: 42,
  148. },
  149. }
  150. err := Decode(input, &result)
  151. if err != nil {
  152. t.Fatalf("got an err: %s", err.Error())
  153. }
  154. if result.Vfoo != "foo" {
  155. t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
  156. }
  157. if result.Vbar.Vstring != "foo" {
  158. t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
  159. }
  160. if result.Vbar.Vint != 42 {
  161. t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
  162. }
  163. if result.Vbar.Vbool != true {
  164. t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
  165. }
  166. if result.Vbar.Vextra != "" {
  167. t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
  168. }
  169. // this is the error
  170. if result.Vbar.Vuint != 42 {
  171. t.Errorf("vuint value should be 42: %#v", result.Vbar.Vuint)
  172. }
  173. }
  174. type NestedSlice struct {
  175. Vfoo string
  176. Vbars []Basic
  177. Vempty []Basic
  178. }
  179. // #48
  180. func TestNestedTypeSliceWithDefaults(t *testing.T) {
  181. t.Parallel()
  182. input := map[string]interface{}{
  183. "vfoo": "foo",
  184. "vbars": []map[string]interface{}{
  185. {"vstring": "foo", "vint": 42, "vbool": true},
  186. {"vint": 42, "vbool": true},
  187. },
  188. "vempty": []map[string]interface{}{
  189. {"vstring": "foo", "vint": 42, "vbool": true},
  190. {"vint": 42, "vbool": true},
  191. },
  192. }
  193. result := NestedSlice{
  194. Vbars: []Basic{
  195. {Vuint: 42},
  196. {Vstring: "foo"},
  197. },
  198. }
  199. err := Decode(input, &result)
  200. if err != nil {
  201. t.Fatalf("got an err: %s", err.Error())
  202. }
  203. if result.Vfoo != "foo" {
  204. t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
  205. }
  206. if result.Vbars[0].Vstring != "foo" {
  207. t.Errorf("vstring value should be 'foo': %#v", result.Vbars[0].Vstring)
  208. }
  209. // this is the error
  210. if result.Vbars[0].Vuint != 42 {
  211. t.Errorf("vuint value should be 42: %#v", result.Vbars[0].Vuint)
  212. }
  213. }
  214. // #48 workaround
  215. func TestNestedTypeWithDefaults(t *testing.T) {
  216. t.Parallel()
  217. input := map[string]interface{}{
  218. "vfoo": "foo",
  219. "vbar": map[string]interface{}{
  220. "vstring": "foo",
  221. "vint": 42,
  222. "vbool": true,
  223. },
  224. }
  225. result := Nested{
  226. Vbar: Basic{
  227. Vuint: 42,
  228. },
  229. }
  230. err := Decode(input, &result)
  231. if err != nil {
  232. t.Fatalf("got an err: %s", err.Error())
  233. }
  234. if result.Vfoo != "foo" {
  235. t.Errorf("vfoo value should be 'foo': %#v", result.Vfoo)
  236. }
  237. if result.Vbar.Vstring != "foo" {
  238. t.Errorf("vstring value should be 'foo': %#v", result.Vbar.Vstring)
  239. }
  240. if result.Vbar.Vint != 42 {
  241. t.Errorf("vint value should be 42: %#v", result.Vbar.Vint)
  242. }
  243. if result.Vbar.Vbool != true {
  244. t.Errorf("vbool value should be true: %#v", result.Vbar.Vbool)
  245. }
  246. if result.Vbar.Vextra != "" {
  247. t.Errorf("vextra value should be empty: %#v", result.Vbar.Vextra)
  248. }
  249. // this is the error
  250. if result.Vbar.Vuint != 42 {
  251. t.Errorf("vuint value should be 42: %#v", result.Vbar.Vuint)
  252. }
  253. }
  254. // #67 panic() on extending slices (decodeSlice with disabled ZeroValues)
  255. func TestDecodeSliceToEmptySliceWOZeroing(t *testing.T) {
  256. t.Parallel()
  257. type TestStruct struct {
  258. Vfoo []string
  259. }
  260. decode := func(m interface{}, rawVal interface{}) error {
  261. config := &DecoderConfig{
  262. Metadata: nil,
  263. Result: rawVal,
  264. ZeroFields: false,
  265. }
  266. decoder, err := NewDecoder(config)
  267. if err != nil {
  268. return err
  269. }
  270. return decoder.Decode(m)
  271. }
  272. {
  273. input := map[string]interface{}{
  274. "vfoo": []string{"1"},
  275. }
  276. result := &TestStruct{}
  277. err := decode(input, &result)
  278. if err != nil {
  279. t.Fatalf("got an err: %s", err.Error())
  280. }
  281. }
  282. {
  283. input := map[string]interface{}{
  284. "vfoo": []string{"1"},
  285. }
  286. result := &TestStruct{
  287. Vfoo: []string{},
  288. }
  289. err := decode(input, &result)
  290. if err != nil {
  291. t.Fatalf("got an err: %s", err.Error())
  292. }
  293. }
  294. {
  295. input := map[string]interface{}{
  296. "vfoo": []string{"2", "3"},
  297. }
  298. result := &TestStruct{
  299. Vfoo: []string{"1"},
  300. }
  301. err := decode(input, &result)
  302. if err != nil {
  303. t.Fatalf("got an err: %s", err.Error())
  304. }
  305. }
  306. }
  307. // #70
  308. func TestNextSquashMapstructure(t *testing.T) {
  309. data := &struct {
  310. Level1 struct {
  311. Level2 struct {
  312. Foo string
  313. } `mapstructure:",squash"`
  314. } `mapstructure:",squash"`
  315. }{}
  316. err := Decode(map[interface{}]interface{}{"foo": "baz"}, &data)
  317. if err != nil {
  318. t.Fatalf("should not error: %s", err)
  319. }
  320. if data.Level1.Level2.Foo != "baz" {
  321. t.Fatal("value should be baz")
  322. }
  323. }
  324. type ImplementsInterfacePointerReceiver struct {
  325. Name string
  326. }
  327. func (i *ImplementsInterfacePointerReceiver) DoStuff() {}
  328. type ImplementsInterfaceValueReceiver string
  329. func (i ImplementsInterfaceValueReceiver) DoStuff() {}
  330. // GH-140 Type error when using DecodeHook to decode into interface
  331. func TestDecode_DecodeHookInterface(t *testing.T) {
  332. t.Parallel()
  333. type Interface interface {
  334. DoStuff()
  335. }
  336. type DecodeIntoInterface struct {
  337. Test Interface
  338. }
  339. testData := map[string]string{"test": "test"}
  340. stringToPointerInterfaceDecodeHook := func(from, to reflect.Type, data interface{}) (interface{}, error) {
  341. if from.Kind() != reflect.String {
  342. return data, nil
  343. }
  344. if to != reflect.TypeOf((*Interface)(nil)).Elem() {
  345. return data, nil
  346. }
  347. // Ensure interface is satisfied
  348. var impl Interface = &ImplementsInterfacePointerReceiver{data.(string)}
  349. return impl, nil
  350. }
  351. stringToValueInterfaceDecodeHook := func(from, to reflect.Type, data interface{}) (interface{}, error) {
  352. if from.Kind() != reflect.String {
  353. return data, nil
  354. }
  355. if to != reflect.TypeOf((*Interface)(nil)).Elem() {
  356. return data, nil
  357. }
  358. // Ensure interface is satisfied
  359. var impl Interface = ImplementsInterfaceValueReceiver(data.(string))
  360. return impl, nil
  361. }
  362. {
  363. decodeInto := new(DecodeIntoInterface)
  364. decoder, _ := NewDecoder(&DecoderConfig{
  365. DecodeHook: stringToPointerInterfaceDecodeHook,
  366. Result: decodeInto,
  367. })
  368. err := decoder.Decode(testData)
  369. if err != nil {
  370. t.Fatalf("Decode returned error: %s", err)
  371. }
  372. expected := &ImplementsInterfacePointerReceiver{"test"}
  373. if !reflect.DeepEqual(decodeInto.Test, expected) {
  374. t.Fatalf("expected: %#v (%T), got: %#v (%T)", decodeInto.Test, decodeInto.Test, expected, expected)
  375. }
  376. }
  377. {
  378. decodeInto := new(DecodeIntoInterface)
  379. decoder, _ := NewDecoder(&DecoderConfig{
  380. DecodeHook: stringToValueInterfaceDecodeHook,
  381. Result: decodeInto,
  382. })
  383. err := decoder.Decode(testData)
  384. if err != nil {
  385. t.Fatalf("Decode returned error: %s", err)
  386. }
  387. expected := ImplementsInterfaceValueReceiver("test")
  388. if !reflect.DeepEqual(decodeInto.Test, expected) {
  389. t.Fatalf("expected: %#v (%T), got: %#v (%T)", decodeInto.Test, decodeInto.Test, expected, expected)
  390. }
  391. }
  392. }
  393. // #103 Check for data type before trying to access its composants prevent a panic error
  394. // in decodeSlice
  395. func TestDecodeBadDataTypeInSlice(t *testing.T) {
  396. t.Parallel()
  397. input := map[string]interface{}{
  398. "Toto": "titi",
  399. }
  400. result := []struct {
  401. Toto string
  402. }{}
  403. if err := Decode(input, &result); err == nil {
  404. t.Error("An error was expected, got nil")
  405. }
  406. }
  407. // #202 Ensure that intermediate maps in the struct -> struct decode process are settable
  408. // and not just the elements within them.
  409. func TestDecodeIntermediateMapsSettable(t *testing.T) {
  410. type Timestamp struct {
  411. Seconds int64
  412. Nanos int32
  413. }
  414. type TsWrapper struct {
  415. Timestamp *Timestamp
  416. }
  417. type TimeWrapper struct {
  418. Timestamp time.Time
  419. }
  420. input := TimeWrapper{
  421. Timestamp: time.Unix(123456789, 987654),
  422. }
  423. expected := TsWrapper{
  424. Timestamp: &Timestamp{
  425. Seconds: 123456789,
  426. Nanos: 987654,
  427. },
  428. }
  429. timePtrType := reflect.TypeOf((*time.Time)(nil))
  430. mapStrInfType := reflect.TypeOf((map[string]interface{})(nil))
  431. var actual TsWrapper
  432. decoder, err := NewDecoder(&DecoderConfig{
  433. Result: &actual,
  434. DecodeHook: func(from, to reflect.Type, data interface{}) (interface{}, error) {
  435. if from == timePtrType && to == mapStrInfType {
  436. ts := data.(*time.Time)
  437. nanos := ts.UnixNano()
  438. seconds := nanos / 1000000000
  439. nanos = nanos % 1000000000
  440. return &map[string]interface{}{
  441. "Seconds": seconds,
  442. "Nanos": int32(nanos),
  443. }, nil
  444. }
  445. return data, nil
  446. },
  447. })
  448. if err != nil {
  449. t.Fatalf("failed to create decoder: %v", err)
  450. }
  451. if err := decoder.Decode(&input); err != nil {
  452. t.Fatalf("failed to decode input: %v", err)
  453. }
  454. if !reflect.DeepEqual(expected, actual) {
  455. t.Fatalf("expected: %#[1]v (%[1]T), got: %#[2]v (%[2]T)", expected, actual)
  456. }
  457. }
  458. // GH-206: decodeInt throws an error for an empty string
  459. func TestDecode_weakEmptyStringToInt(t *testing.T) {
  460. input := map[string]interface{}{
  461. "StringToInt": "",
  462. "StringToUint": "",
  463. "StringToBool": "",
  464. "StringToFloat": "",
  465. }
  466. expectedResultWeak := TypeConversionResult{
  467. StringToInt: 0,
  468. StringToUint: 0,
  469. StringToBool: false,
  470. StringToFloat: 0,
  471. }
  472. // Test weak type conversion
  473. var resultWeak TypeConversionResult
  474. err := WeakDecode(input, &resultWeak)
  475. if err != nil {
  476. t.Fatalf("got an err: %s", err)
  477. }
  478. if !reflect.DeepEqual(resultWeak, expectedResultWeak) {
  479. t.Errorf("expected \n%#v, got: \n%#v", expectedResultWeak, resultWeak)
  480. }
  481. }
  482. // GH-228: Squash cause *time.Time set to zero
  483. func TestMapSquash(t *testing.T) {
  484. type AA struct {
  485. T *time.Time
  486. }
  487. type A struct {
  488. AA
  489. }
  490. v := time.Now()
  491. in := &AA{
  492. T: &v,
  493. }
  494. out := &A{}
  495. d, err := NewDecoder(&DecoderConfig{
  496. Squash: true,
  497. Result: out,
  498. })
  499. if err != nil {
  500. t.Fatalf("err: %s", err)
  501. }
  502. if err := d.Decode(in); err != nil {
  503. t.Fatalf("err: %s", err)
  504. }
  505. // these failed
  506. if !v.Equal(*out.T) {
  507. t.Fatal("expected equal")
  508. }
  509. if out.T.IsZero() {
  510. t.Fatal("expected false")
  511. }
  512. }