converter_test.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package conversion
  14. import (
  15. "encoding/json"
  16. "fmt"
  17. "reflect"
  18. "strconv"
  19. "strings"
  20. "testing"
  21. "github.com/google/gofuzz"
  22. flag "github.com/spf13/pflag"
  23. "k8s.io/kubernetes/pkg/util/diff"
  24. )
  25. var fuzzIters = flag.Int("fuzz-iters", 50, "How many fuzzing iterations to do.")
  26. // Test a weird version/kind embedding format.
  27. type MyWeirdCustomEmbeddedVersionKindField struct {
  28. ID string `json:"ID,omitempty"`
  29. APIVersion string `json:"myVersionKey,omitempty"`
  30. ObjectKind string `json:"myKindKey,omitempty"`
  31. Z string `json:"Z,omitempty"`
  32. Y uint64 `json:"Y,omitempty"`
  33. }
  34. type TestType1 struct {
  35. MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
  36. A string `json:"A,omitempty"`
  37. B int `json:"B,omitempty"`
  38. C int8 `json:"C,omitempty"`
  39. D int16 `json:"D,omitempty"`
  40. E int32 `json:"E,omitempty"`
  41. F int64 `json:"F,omitempty"`
  42. G uint `json:"G,omitempty"`
  43. H uint8 `json:"H,omitempty"`
  44. I uint16 `json:"I,omitempty"`
  45. J uint32 `json:"J,omitempty"`
  46. K uint64 `json:"K,omitempty"`
  47. L bool `json:"L,omitempty"`
  48. M map[string]int `json:"M,omitempty"`
  49. N map[string]TestType2 `json:"N,omitempty"`
  50. O *TestType2 `json:"O,omitempty"`
  51. P []TestType2 `json:"Q,omitempty"`
  52. }
  53. type TestType2 struct {
  54. A string `json:"A,omitempty"`
  55. B int `json:"B,omitempty"`
  56. }
  57. type ExternalTestType2 struct {
  58. A string `json:"A,omitempty"`
  59. B int `json:"B,omitempty"`
  60. }
  61. type ExternalTestType1 struct {
  62. MyWeirdCustomEmbeddedVersionKindField `json:",inline"`
  63. A string `json:"A,omitempty"`
  64. B int `json:"B,omitempty"`
  65. C int8 `json:"C,omitempty"`
  66. D int16 `json:"D,omitempty"`
  67. E int32 `json:"E,omitempty"`
  68. F int64 `json:"F,omitempty"`
  69. G uint `json:"G,omitempty"`
  70. H uint8 `json:"H,omitempty"`
  71. I uint16 `json:"I,omitempty"`
  72. J uint32 `json:"J,omitempty"`
  73. K uint64 `json:"K,omitempty"`
  74. L bool `json:"L,omitempty"`
  75. M map[string]int `json:"M,omitempty"`
  76. N map[string]ExternalTestType2 `json:"N,omitempty"`
  77. O *ExternalTestType2 `json:"O,omitempty"`
  78. P []ExternalTestType2 `json:"Q,omitempty"`
  79. }
  80. func testLogger(t *testing.T) DebugLogger {
  81. // We don't set logger to eliminate rubbish logs in tests.
  82. // If you want to switch it, simply switch it to: "return t"
  83. return nil
  84. }
  85. func TestConverter_byteSlice(t *testing.T) {
  86. c := NewConverter(DefaultNameFunc)
  87. src := []byte{1, 2, 3}
  88. dest := []byte{}
  89. err := c.Convert(&src, &dest, 0, nil)
  90. if err != nil {
  91. t.Fatalf("expected no error")
  92. }
  93. if e, a := src, dest; !reflect.DeepEqual(e, a) {
  94. t.Errorf("expected %#v, got %#v", e, a)
  95. }
  96. }
  97. func TestConverter_MismatchedTypes(t *testing.T) {
  98. c := NewConverter(DefaultNameFunc)
  99. err := c.RegisterConversionFunc(
  100. func(in *[]string, out *int, s Scope) error {
  101. if str, err := strconv.Atoi((*in)[0]); err != nil {
  102. return err
  103. } else {
  104. *out = str
  105. return nil
  106. }
  107. },
  108. )
  109. if err != nil {
  110. t.Fatalf("Unexpected error: %v", err)
  111. }
  112. src := []string{"5"}
  113. var dest *int
  114. err = c.Convert(&src, &dest, 0, nil)
  115. if err != nil {
  116. t.Fatalf("unexpected error: %v", err)
  117. }
  118. if e, a := 5, *dest; e != a {
  119. t.Errorf("expected %#v, got %#v", e, a)
  120. }
  121. }
  122. func TestConverter_DefaultConvert(t *testing.T) {
  123. type A struct {
  124. Foo string
  125. Baz int
  126. }
  127. type B struct {
  128. Bar string
  129. Baz int
  130. }
  131. c := NewConverter(DefaultNameFunc)
  132. c.Debug = testLogger(t)
  133. c.nameFunc = func(t reflect.Type) string { return "MyType" }
  134. // Ensure conversion funcs can call DefaultConvert to get default behavior,
  135. // then fixup remaining fields manually
  136. err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
  137. if err := s.DefaultConvert(in, out, IgnoreMissingFields); err != nil {
  138. return err
  139. }
  140. out.Bar = in.Foo
  141. return nil
  142. })
  143. if err != nil {
  144. t.Fatalf("unexpected error %v", err)
  145. }
  146. x := A{"hello, intrepid test reader!", 3}
  147. y := B{}
  148. err = c.Convert(&x, &y, 0, nil)
  149. if err != nil {
  150. t.Fatalf("unexpected error %v", err)
  151. }
  152. if e, a := x.Foo, y.Bar; e != a {
  153. t.Errorf("expected %v, got %v", e, a)
  154. }
  155. if e, a := x.Baz, y.Baz; e != a {
  156. t.Errorf("expected %v, got %v", e, a)
  157. }
  158. }
  159. func TestConverter_DeepCopy(t *testing.T) {
  160. type A struct {
  161. Foo *string
  162. Bar []string
  163. Baz interface{}
  164. Qux map[string]string
  165. }
  166. c := NewConverter(DefaultNameFunc)
  167. c.Debug = testLogger(t)
  168. foo, baz := "foo", "baz"
  169. x := A{
  170. Foo: &foo,
  171. Bar: []string{"bar"},
  172. Baz: &baz,
  173. Qux: map[string]string{"qux": "qux"},
  174. }
  175. y := A{}
  176. if err := c.Convert(&x, &y, 0, nil); err != nil {
  177. t.Fatalf("unexpected error %v", err)
  178. }
  179. *x.Foo = "foo2"
  180. x.Bar[0] = "bar2"
  181. *x.Baz.(*string) = "baz2"
  182. x.Qux["qux"] = "qux2"
  183. if e, a := *x.Foo, *y.Foo; e == a {
  184. t.Errorf("expected difference between %v and %v", e, a)
  185. }
  186. if e, a := x.Bar, y.Bar; reflect.DeepEqual(e, a) {
  187. t.Errorf("expected difference between %v and %v", e, a)
  188. }
  189. if e, a := *x.Baz.(*string), *y.Baz.(*string); e == a {
  190. t.Errorf("expected difference between %v and %v", e, a)
  191. }
  192. if e, a := x.Qux, y.Qux; reflect.DeepEqual(e, a) {
  193. t.Errorf("expected difference between %v and %v", e, a)
  194. }
  195. }
  196. func TestConverter_CallsRegisteredFunctions(t *testing.T) {
  197. type A struct {
  198. Foo string
  199. Baz int
  200. }
  201. type B struct {
  202. Bar string
  203. Baz int
  204. }
  205. type C struct{}
  206. c := NewConverter(DefaultNameFunc)
  207. c.Debug = testLogger(t)
  208. err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
  209. out.Bar = in.Foo
  210. return s.Convert(&in.Baz, &out.Baz, 0)
  211. })
  212. if err != nil {
  213. t.Fatalf("unexpected error %v", err)
  214. }
  215. err = c.RegisterConversionFunc(func(in *B, out *A, s Scope) error {
  216. out.Foo = in.Bar
  217. return s.Convert(&in.Baz, &out.Baz, 0)
  218. })
  219. if err != nil {
  220. t.Fatalf("unexpected error %v", err)
  221. }
  222. x := A{"hello, intrepid test reader!", 3}
  223. y := B{}
  224. err = c.Convert(&x, &y, 0, nil)
  225. if err != nil {
  226. t.Fatalf("unexpected error %v", err)
  227. }
  228. if e, a := x.Foo, y.Bar; e != a {
  229. t.Errorf("expected %v, got %v", e, a)
  230. }
  231. if e, a := x.Baz, y.Baz; e != a {
  232. t.Errorf("expected %v, got %v", e, a)
  233. }
  234. z := B{"all your test are belong to us", 42}
  235. w := A{}
  236. err = c.Convert(&z, &w, 0, nil)
  237. if err != nil {
  238. t.Fatalf("unexpected error %v", err)
  239. }
  240. if e, a := z.Bar, w.Foo; e != a {
  241. t.Errorf("expected %v, got %v", e, a)
  242. }
  243. if e, a := z.Baz, w.Baz; e != a {
  244. t.Errorf("expected %v, got %v", e, a)
  245. }
  246. err = c.RegisterConversionFunc(func(in *A, out *C, s Scope) error {
  247. return fmt.Errorf("C can't store an A, silly")
  248. })
  249. if err != nil {
  250. t.Fatalf("unexpected error %v", err)
  251. }
  252. err = c.Convert(&A{}, &C{}, 0, nil)
  253. if err == nil {
  254. t.Errorf("unexpected non-error")
  255. }
  256. }
  257. func TestConverter_IgnoredConversion(t *testing.T) {
  258. type A struct{}
  259. type B struct{}
  260. count := 0
  261. c := NewConverter(DefaultNameFunc)
  262. if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
  263. count++
  264. return nil
  265. }); err != nil {
  266. t.Fatalf("unexpected error %v", err)
  267. }
  268. if err := c.RegisterIgnoredConversion(&A{}, &B{}); err != nil {
  269. t.Fatal(err)
  270. }
  271. a := A{}
  272. b := B{}
  273. if err := c.Convert(&a, &b, 0, nil); err != nil {
  274. t.Errorf("%v", err)
  275. }
  276. if count != 0 {
  277. t.Errorf("unexpected number of conversion invocations")
  278. }
  279. }
  280. func TestConverter_IgnoredConversionNested(t *testing.T) {
  281. type C string
  282. type A struct {
  283. C C
  284. }
  285. type B struct {
  286. C C
  287. }
  288. c := NewConverter(DefaultNameFunc)
  289. typed := C("")
  290. if err := c.RegisterIgnoredConversion(&typed, &typed); err != nil {
  291. t.Fatal(err)
  292. }
  293. a := A{C: C("test")}
  294. b := B{C: C("other")}
  295. if err := c.Convert(&a, &b, AllowDifferentFieldTypeNames, nil); err != nil {
  296. t.Errorf("%v", err)
  297. }
  298. if b.C != C("other") {
  299. t.Errorf("expected no conversion of field C: %#v", b)
  300. }
  301. }
  302. func TestConverter_GeneratedConversionOverriden(t *testing.T) {
  303. type A struct{}
  304. type B struct{}
  305. c := NewConverter(DefaultNameFunc)
  306. if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
  307. return nil
  308. }); err != nil {
  309. t.Fatalf("unexpected error %v", err)
  310. }
  311. if err := c.RegisterGeneratedConversionFunc(func(in *A, out *B, s Scope) error {
  312. return fmt.Errorf("generated function should be overriden")
  313. }); err != nil {
  314. t.Fatalf("unexpected error %v", err)
  315. }
  316. a := A{}
  317. b := B{}
  318. if err := c.Convert(&a, &b, 0, nil); err != nil {
  319. t.Errorf("%v", err)
  320. }
  321. }
  322. func TestConverter_WithConversionOverriden(t *testing.T) {
  323. type A struct{}
  324. type B struct{}
  325. c := NewConverter(DefaultNameFunc)
  326. if err := c.RegisterConversionFunc(func(in *A, out *B, s Scope) error {
  327. return fmt.Errorf("conversion function should be overriden")
  328. }); err != nil {
  329. t.Fatalf("unexpected error %v", err)
  330. }
  331. if err := c.RegisterGeneratedConversionFunc(func(in *A, out *B, s Scope) error {
  332. return fmt.Errorf("generated function should be overriden")
  333. }); err != nil {
  334. t.Fatalf("unexpected error %v", err)
  335. }
  336. ext := NewConversionFuncs()
  337. ext.Add(func(in *A, out *B, s Scope) error {
  338. return nil
  339. })
  340. newc := c.WithConversions(ext)
  341. a := A{}
  342. b := B{}
  343. if err := c.Convert(&a, &b, 0, nil); err == nil || err.Error() != "conversion function should be overriden" {
  344. t.Errorf("unexpected error: %v", err)
  345. }
  346. if err := newc.Convert(&a, &b, 0, nil); err != nil {
  347. t.Errorf("%v", err)
  348. }
  349. }
  350. func TestConverter_MapsStringArrays(t *testing.T) {
  351. type A struct {
  352. Foo string
  353. Baz int
  354. Other string
  355. }
  356. c := NewConverter(DefaultNameFunc)
  357. c.Debug = testLogger(t)
  358. if err := c.RegisterConversionFunc(func(input *[]string, out *string, s Scope) error {
  359. if len(*input) == 0 {
  360. *out = ""
  361. }
  362. *out = (*input)[0]
  363. return nil
  364. }); err != nil {
  365. t.Fatalf("unexpected error %v", err)
  366. }
  367. x := map[string][]string{
  368. "Foo": {"bar"},
  369. "Baz": {"1"},
  370. "Other": {"", "test"},
  371. "other": {"wrong"},
  372. }
  373. y := A{"test", 2, "something"}
  374. if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames, nil); err == nil {
  375. t.Error("unexpected non-error")
  376. }
  377. if err := c.RegisterConversionFunc(func(input *[]string, out *int, s Scope) error {
  378. if len(*input) == 0 {
  379. *out = 0
  380. }
  381. str := (*input)[0]
  382. i, err := strconv.Atoi(str)
  383. if err != nil {
  384. return err
  385. }
  386. *out = i
  387. return nil
  388. }); err != nil {
  389. t.Fatalf("unexpected error %v", err)
  390. }
  391. if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames, nil); err != nil {
  392. t.Fatalf("unexpected error %v", err)
  393. }
  394. if !reflect.DeepEqual(y, A{"bar", 1, ""}) {
  395. t.Errorf("unexpected result: %#v", y)
  396. }
  397. }
  398. func TestConverter_MapsStringArraysWithMappingKey(t *testing.T) {
  399. type A struct {
  400. Foo string `json:"test"`
  401. Baz int
  402. Other string
  403. }
  404. c := NewConverter(DefaultNameFunc)
  405. c.Debug = testLogger(t)
  406. if err := c.RegisterConversionFunc(func(input *[]string, out *string, s Scope) error {
  407. if len(*input) == 0 {
  408. *out = ""
  409. }
  410. *out = (*input)[0]
  411. return nil
  412. }); err != nil {
  413. t.Fatalf("unexpected error %v", err)
  414. }
  415. x := map[string][]string{
  416. "Foo": {"bar"},
  417. "test": {"baz"},
  418. }
  419. y := A{"", 0, ""}
  420. if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames|IgnoreMissingFields, &Meta{}); err != nil {
  421. t.Fatalf("unexpected error %v", err)
  422. }
  423. if !reflect.DeepEqual(y, A{"bar", 0, ""}) {
  424. t.Errorf("unexpected result: %#v", y)
  425. }
  426. mapping := func(key string, sourceTag, destTag reflect.StructTag) (source string, dest string) {
  427. if s := destTag.Get("json"); len(s) > 0 {
  428. return strings.SplitN(s, ",", 2)[0], key
  429. }
  430. return key, key
  431. }
  432. if err := c.Convert(&x, &y, AllowDifferentFieldTypeNames|IgnoreMissingFields, &Meta{KeyNameMapping: mapping}); err != nil {
  433. t.Fatalf("unexpected error %v", err)
  434. }
  435. if !reflect.DeepEqual(y, A{"baz", 0, ""}) {
  436. t.Errorf("unexpected result: %#v", y)
  437. }
  438. }
  439. func TestConverter_fuzz(t *testing.T) {
  440. // Use the same types from the scheme test.
  441. table := []struct {
  442. from, to, check interface{}
  443. }{
  444. {&TestType1{}, &ExternalTestType1{}, &TestType1{}},
  445. {&ExternalTestType1{}, &TestType1{}, &ExternalTestType1{}},
  446. }
  447. f := fuzz.New().NilChance(.5).NumElements(0, 100)
  448. c := NewConverter(DefaultNameFunc)
  449. c.nameFunc = func(t reflect.Type) string {
  450. // Hide the fact that we don't have separate packages for these things.
  451. return map[reflect.Type]string{
  452. reflect.TypeOf(TestType1{}): "TestType1",
  453. reflect.TypeOf(ExternalTestType1{}): "TestType1",
  454. reflect.TypeOf(TestType2{}): "TestType2",
  455. reflect.TypeOf(ExternalTestType2{}): "TestType2",
  456. }[t]
  457. }
  458. c.Debug = testLogger(t)
  459. for i, item := range table {
  460. for j := 0; j < *fuzzIters; j++ {
  461. f.Fuzz(item.from)
  462. err := c.Convert(item.from, item.to, 0, nil)
  463. if err != nil {
  464. t.Errorf("(%v, %v): unexpected error: %v", i, j, err)
  465. continue
  466. }
  467. err = c.Convert(item.to, item.check, 0, nil)
  468. if err != nil {
  469. t.Errorf("(%v, %v): unexpected error: %v", i, j, err)
  470. continue
  471. }
  472. if e, a := item.from, item.check; !reflect.DeepEqual(e, a) {
  473. t.Errorf("(%v, %v): unexpected diff: %v", i, j, objDiff(e, a))
  474. }
  475. }
  476. }
  477. }
  478. func TestConverter_MapElemAddr(t *testing.T) {
  479. type Foo struct {
  480. A map[int]int
  481. }
  482. type Bar struct {
  483. A map[string]string
  484. }
  485. c := NewConverter(DefaultNameFunc)
  486. c.Debug = testLogger(t)
  487. err := c.RegisterConversionFunc(
  488. func(in *int, out *string, s Scope) error {
  489. *out = fmt.Sprintf("%v", *in)
  490. return nil
  491. },
  492. )
  493. if err != nil {
  494. t.Fatalf("Unexpected error: %v", err)
  495. }
  496. err = c.RegisterConversionFunc(
  497. func(in *string, out *int, s Scope) error {
  498. if str, err := strconv.Atoi(*in); err != nil {
  499. return err
  500. } else {
  501. *out = str
  502. return nil
  503. }
  504. },
  505. )
  506. if err != nil {
  507. t.Fatalf("Unexpected error: %v", err)
  508. }
  509. f := fuzz.New().NilChance(0).NumElements(3, 3)
  510. first := Foo{}
  511. second := Bar{}
  512. f.Fuzz(&first)
  513. err = c.Convert(&first, &second, AllowDifferentFieldTypeNames, nil)
  514. if err != nil {
  515. t.Fatalf("Unexpected error: %v", err)
  516. }
  517. third := Foo{}
  518. err = c.Convert(&second, &third, AllowDifferentFieldTypeNames, nil)
  519. if e, a := first, third; !reflect.DeepEqual(e, a) {
  520. t.Errorf("Unexpected diff: %v", objDiff(e, a))
  521. }
  522. }
  523. func TestConverter_tags(t *testing.T) {
  524. type Foo struct {
  525. A string `test:"foo"`
  526. }
  527. type Bar struct {
  528. A string `test:"bar"`
  529. }
  530. c := NewConverter(DefaultNameFunc)
  531. c.Debug = testLogger(t)
  532. err := c.RegisterConversionFunc(
  533. func(in *string, out *string, s Scope) error {
  534. if e, a := "foo", s.SrcTag().Get("test"); e != a {
  535. t.Errorf("expected %v, got %v", e, a)
  536. }
  537. if e, a := "bar", s.DestTag().Get("test"); e != a {
  538. t.Errorf("expected %v, got %v", e, a)
  539. }
  540. return nil
  541. },
  542. )
  543. if err != nil {
  544. t.Fatalf("Unexpected error: %v", err)
  545. }
  546. err = c.Convert(&Foo{}, &Bar{}, AllowDifferentFieldTypeNames, nil)
  547. if err != nil {
  548. t.Fatalf("Unexpected error: %v", err)
  549. }
  550. }
  551. func TestConverter_meta(t *testing.T) {
  552. type Foo struct{ A string }
  553. type Bar struct{ A string }
  554. c := NewConverter(DefaultNameFunc)
  555. c.Debug = testLogger(t)
  556. checks := 0
  557. err := c.RegisterConversionFunc(
  558. func(in *Foo, out *Bar, s Scope) error {
  559. if s.Meta() == nil {
  560. t.Errorf("Meta did not get passed!")
  561. }
  562. checks++
  563. s.Convert(&in.A, &out.A, 0)
  564. return nil
  565. },
  566. )
  567. if err != nil {
  568. t.Fatalf("Unexpected error: %v", err)
  569. }
  570. err = c.RegisterConversionFunc(
  571. func(in *string, out *string, s Scope) error {
  572. if s.Meta() == nil {
  573. t.Errorf("Meta did not get passed a second time!")
  574. }
  575. checks++
  576. return nil
  577. },
  578. )
  579. if err != nil {
  580. t.Fatalf("Unexpected error: %v", err)
  581. }
  582. err = c.Convert(&Foo{}, &Bar{}, 0, &Meta{})
  583. if err != nil {
  584. t.Fatalf("Unexpected error: %v", err)
  585. }
  586. if checks != 2 {
  587. t.Errorf("Registered functions did not get called.")
  588. }
  589. }
  590. func TestConverter_flags(t *testing.T) {
  591. type Foo struct{ A string }
  592. type Bar struct{ A string }
  593. table := []struct {
  594. from, to interface{}
  595. flags FieldMatchingFlags
  596. shouldSucceed bool
  597. }{
  598. // Check that DestFromSource allows extra fields only in source.
  599. {
  600. from: &struct{ A string }{},
  601. to: &struct{ A, B string }{},
  602. flags: DestFromSource,
  603. shouldSucceed: false,
  604. }, {
  605. from: &struct{ A, B string }{},
  606. to: &struct{ A string }{},
  607. flags: DestFromSource,
  608. shouldSucceed: true,
  609. },
  610. // Check that SourceToDest allows for extra fields only in dest.
  611. {
  612. from: &struct{ A string }{},
  613. to: &struct{ A, B string }{},
  614. flags: SourceToDest,
  615. shouldSucceed: true,
  616. }, {
  617. from: &struct{ A, B string }{},
  618. to: &struct{ A string }{},
  619. flags: SourceToDest,
  620. shouldSucceed: false,
  621. },
  622. // Check that IgnoreMissingFields makes the above failure cases pass.
  623. {
  624. from: &struct{ A string }{},
  625. to: &struct{ A, B string }{},
  626. flags: DestFromSource | IgnoreMissingFields,
  627. shouldSucceed: true,
  628. }, {
  629. from: &struct{ A, B string }{},
  630. to: &struct{ A string }{},
  631. flags: SourceToDest | IgnoreMissingFields,
  632. shouldSucceed: true,
  633. },
  634. // Check that the field type name must match unless
  635. // AllowDifferentFieldTypeNames is specified.
  636. {
  637. from: &struct{ A, B Foo }{},
  638. to: &struct{ A Bar }{},
  639. flags: DestFromSource,
  640. shouldSucceed: false,
  641. }, {
  642. from: &struct{ A Foo }{},
  643. to: &struct{ A, B Bar }{},
  644. flags: SourceToDest,
  645. shouldSucceed: false,
  646. }, {
  647. from: &struct{ A, B Foo }{},
  648. to: &struct{ A Bar }{},
  649. flags: DestFromSource | AllowDifferentFieldTypeNames,
  650. shouldSucceed: true,
  651. }, {
  652. from: &struct{ A Foo }{},
  653. to: &struct{ A, B Bar }{},
  654. flags: SourceToDest | AllowDifferentFieldTypeNames,
  655. shouldSucceed: true,
  656. },
  657. }
  658. f := fuzz.New().NilChance(.5).NumElements(0, 100)
  659. c := NewConverter(DefaultNameFunc)
  660. c.Debug = testLogger(t)
  661. for i, item := range table {
  662. for j := 0; j < *fuzzIters; j++ {
  663. f.Fuzz(item.from)
  664. err := c.Convert(item.from, item.to, item.flags, nil)
  665. if item.shouldSucceed && err != nil {
  666. t.Errorf("(%v, %v): unexpected error: %v", i, j, err)
  667. continue
  668. }
  669. if !item.shouldSucceed && err == nil {
  670. t.Errorf("(%v, %v): unexpected non-error", i, j)
  671. continue
  672. }
  673. }
  674. }
  675. }
  676. func TestConverter_FieldRename(t *testing.T) {
  677. type WeirdMeta struct {
  678. Name string
  679. Type string
  680. }
  681. type NameMeta struct {
  682. Name string
  683. }
  684. type TypeMeta struct {
  685. Type string
  686. }
  687. type A struct {
  688. WeirdMeta
  689. }
  690. type B struct {
  691. TypeMeta
  692. NameMeta
  693. }
  694. c := NewConverter(DefaultNameFunc)
  695. err := c.SetStructFieldCopy(WeirdMeta{}, "WeirdMeta", TypeMeta{}, "TypeMeta")
  696. if err != nil {
  697. t.Fatalf("unexpected error %v", err)
  698. }
  699. err = c.SetStructFieldCopy(WeirdMeta{}, "WeirdMeta", NameMeta{}, "NameMeta")
  700. if err != nil {
  701. t.Fatalf("unexpected error %v", err)
  702. }
  703. err = c.SetStructFieldCopy(TypeMeta{}, "TypeMeta", WeirdMeta{}, "WeirdMeta")
  704. if err != nil {
  705. t.Fatalf("unexpected error %v", err)
  706. }
  707. err = c.SetStructFieldCopy(NameMeta{}, "NameMeta", WeirdMeta{}, "WeirdMeta")
  708. if err != nil {
  709. t.Fatalf("unexpected error %v", err)
  710. }
  711. c.Debug = testLogger(t)
  712. aVal := &A{
  713. WeirdMeta: WeirdMeta{
  714. Name: "Foo",
  715. Type: "Bar",
  716. },
  717. }
  718. bVal := &B{
  719. TypeMeta: TypeMeta{"Bar"},
  720. NameMeta: NameMeta{"Foo"},
  721. }
  722. table := map[string]struct {
  723. from, to, expect interface{}
  724. flags FieldMatchingFlags
  725. }{
  726. "to": {
  727. aVal,
  728. &B{},
  729. bVal,
  730. AllowDifferentFieldTypeNames | SourceToDest | IgnoreMissingFields,
  731. },
  732. "from": {
  733. bVal,
  734. &A{},
  735. aVal,
  736. AllowDifferentFieldTypeNames | SourceToDest,
  737. },
  738. "toDestFirst": {
  739. aVal,
  740. &B{},
  741. bVal,
  742. AllowDifferentFieldTypeNames,
  743. },
  744. "fromDestFirst": {
  745. bVal,
  746. &A{},
  747. aVal,
  748. AllowDifferentFieldTypeNames | IgnoreMissingFields,
  749. },
  750. }
  751. for name, item := range table {
  752. err := c.Convert(item.from, item.to, item.flags, nil)
  753. if err != nil {
  754. t.Errorf("%v: unexpected error: %v", name, err)
  755. continue
  756. }
  757. if e, a := item.expect, item.to; !reflect.DeepEqual(e, a) {
  758. t.Errorf("%v: unexpected diff: %v", name, objDiff(e, a))
  759. }
  760. }
  761. }
  762. func objDiff(a, b interface{}) string {
  763. ab, err := json.Marshal(a)
  764. if err != nil {
  765. panic("a")
  766. }
  767. bb, err := json.Marshal(b)
  768. if err != nil {
  769. panic("b")
  770. }
  771. return diff.StringDiff(string(ab), string(bb))
  772. // An alternate diff attempt, in case json isn't showing you
  773. // the difference. (reflect.DeepEqual makes a distinction between
  774. // nil and empty slices, for example.)
  775. //return diff.StringDiff(
  776. // fmt.Sprintf("%#v", a),
  777. // fmt.Sprintf("%#v", b),
  778. //)
  779. }