struct_test.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. // Copyright 2014 Unknwon
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License"): you may
  4. // not use this file except in compliance with the License. You may obtain
  5. // a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  11. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  12. // License for the specific language governing permissions and limitations
  13. // under the License.
  14. package ini
  15. import (
  16. "strings"
  17. "testing"
  18. "time"
  19. . "github.com/smartystreets/goconvey/convey"
  20. )
  21. type testNested struct {
  22. Cities []string `delim:"|"`
  23. Visits []time.Time
  24. Note string
  25. Unused int `ini:"-"`
  26. }
  27. type testEmbeded struct {
  28. GPA float64
  29. }
  30. type testStruct struct {
  31. Name string `ini:"NAME"`
  32. Age int
  33. Male bool
  34. Money float64
  35. Born time.Time
  36. Time time.Duration `ini:"Duration"`
  37. Others testNested
  38. *testEmbeded `ini:"grade"`
  39. Unused int `ini:"-"`
  40. Unsigned uint
  41. }
  42. const _CONF_DATA_STRUCT = `
  43. NAME = Unknwon
  44. Age = 21
  45. Male = true
  46. Money = 1.25
  47. Born = 1993-10-07T20:17:05Z
  48. Duration = 2h45m
  49. Unsigned = 3
  50. [Others]
  51. Cities = HangZhou|Boston
  52. Visits = 1993-10-07T20:17:05Z, 1993-10-07T20:17:05Z
  53. Note = Hello world!
  54. [grade]
  55. GPA = 2.8
  56. [foo.bar]
  57. Here = there
  58. When = then
  59. `
  60. type unsupport struct {
  61. Byte byte
  62. }
  63. type unsupport2 struct {
  64. Others struct {
  65. Cities byte
  66. }
  67. }
  68. type unsupport3 struct {
  69. Cities byte
  70. }
  71. type unsupport4 struct {
  72. *unsupport3 `ini:"Others"`
  73. }
  74. type defaultValue struct {
  75. Name string
  76. Age int
  77. Male bool
  78. Money float64
  79. Born time.Time
  80. Cities []string
  81. }
  82. type fooBar struct {
  83. Here, When string
  84. }
  85. const _INVALID_DATA_CONF_STRUCT = `
  86. Name =
  87. Age = age
  88. Male = 123
  89. Money = money
  90. Born = nil
  91. Cities =
  92. `
  93. func Test_Struct(t *testing.T) {
  94. Convey("Map to struct", t, func() {
  95. Convey("Map file to struct", func() {
  96. ts := new(testStruct)
  97. So(MapTo(ts, []byte(_CONF_DATA_STRUCT)), ShouldBeNil)
  98. So(ts.Name, ShouldEqual, "Unknwon")
  99. So(ts.Age, ShouldEqual, 21)
  100. So(ts.Male, ShouldBeTrue)
  101. So(ts.Money, ShouldEqual, 1.25)
  102. So(ts.Unsigned, ShouldEqual, 3)
  103. t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
  104. So(err, ShouldBeNil)
  105. So(ts.Born.String(), ShouldEqual, t.String())
  106. dur, err := time.ParseDuration("2h45m")
  107. So(err, ShouldBeNil)
  108. So(ts.Time.Seconds(), ShouldEqual, dur.Seconds())
  109. So(strings.Join(ts.Others.Cities, ","), ShouldEqual, "HangZhou,Boston")
  110. So(ts.Others.Visits[0].String(), ShouldEqual, t.String())
  111. So(ts.Others.Note, ShouldEqual, "Hello world!")
  112. So(ts.testEmbeded.GPA, ShouldEqual, 2.8)
  113. })
  114. Convey("Map section to struct", func() {
  115. foobar := new(fooBar)
  116. f, err := Load([]byte(_CONF_DATA_STRUCT))
  117. So(err, ShouldBeNil)
  118. So(f.Section("foo.bar").MapTo(foobar), ShouldBeNil)
  119. So(foobar.Here, ShouldEqual, "there")
  120. So(foobar.When, ShouldEqual, "then")
  121. })
  122. Convey("Map to non-pointer struct", func() {
  123. cfg, err := Load([]byte(_CONF_DATA_STRUCT))
  124. So(err, ShouldBeNil)
  125. So(cfg, ShouldNotBeNil)
  126. So(cfg.MapTo(testStruct{}), ShouldNotBeNil)
  127. })
  128. Convey("Map to unsupported type", func() {
  129. cfg, err := Load([]byte(_CONF_DATA_STRUCT))
  130. So(err, ShouldBeNil)
  131. So(cfg, ShouldNotBeNil)
  132. cfg.NameMapper = func(raw string) string {
  133. if raw == "Byte" {
  134. return "NAME"
  135. }
  136. return raw
  137. }
  138. So(cfg.MapTo(&unsupport{}), ShouldNotBeNil)
  139. So(cfg.MapTo(&unsupport2{}), ShouldNotBeNil)
  140. So(cfg.MapTo(&unsupport4{}), ShouldNotBeNil)
  141. })
  142. Convey("Map from invalid data source", func() {
  143. So(MapTo(&testStruct{}, "hi"), ShouldNotBeNil)
  144. })
  145. Convey("Map to wrong types and gain default values", func() {
  146. cfg, err := Load([]byte(_INVALID_DATA_CONF_STRUCT))
  147. So(err, ShouldBeNil)
  148. t, err := time.Parse(time.RFC3339, "1993-10-07T20:17:05Z")
  149. So(err, ShouldBeNil)
  150. dv := &defaultValue{"Joe", 10, true, 1.25, t, []string{"HangZhou", "Boston"}}
  151. So(cfg.MapTo(dv), ShouldBeNil)
  152. So(dv.Name, ShouldEqual, "Joe")
  153. So(dv.Age, ShouldEqual, 10)
  154. So(dv.Male, ShouldBeTrue)
  155. So(dv.Money, ShouldEqual, 1.25)
  156. So(dv.Born.String(), ShouldEqual, t.String())
  157. So(strings.Join(dv.Cities, ","), ShouldEqual, "HangZhou,Boston")
  158. })
  159. })
  160. Convey("Reflect from struct", t, func() {
  161. type Embeded struct {
  162. Dates []time.Time `delim:"|"`
  163. Places []string
  164. None []int
  165. }
  166. type Author struct {
  167. Name string `ini:"NAME"`
  168. Male bool
  169. Age int
  170. GPA float64
  171. NeverMind string `ini:"-"`
  172. *Embeded `ini:"infos"`
  173. }
  174. a := &Author{"Unknwon", true, 21, 2.8, "",
  175. &Embeded{
  176. []time.Time{time.Now(), time.Now()},
  177. []string{"HangZhou", "Boston"},
  178. []int{},
  179. }}
  180. cfg := Empty()
  181. So(ReflectFrom(cfg, a), ShouldBeNil)
  182. cfg.SaveTo("testdata/conf_reflect.ini")
  183. Convey("Reflect from non-point struct", func() {
  184. So(ReflectFrom(cfg, Author{}), ShouldNotBeNil)
  185. })
  186. })
  187. }
  188. type testMapper struct {
  189. PackageName string
  190. }
  191. func Test_NameGetter(t *testing.T) {
  192. Convey("Test name mappers", t, func() {
  193. So(MapToWithMapper(&testMapper{}, TitleUnderscore, []byte("packag_name=ini")), ShouldBeNil)
  194. cfg, err := Load([]byte("PACKAGE_NAME=ini"))
  195. So(err, ShouldBeNil)
  196. So(cfg, ShouldNotBeNil)
  197. cfg.NameMapper = AllCapsUnderscore
  198. tg := new(testMapper)
  199. So(cfg.MapTo(tg), ShouldBeNil)
  200. So(tg.PackageName, ShouldEqual, "ini")
  201. })
  202. }