key_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  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_test
  15. import (
  16. "bytes"
  17. "fmt"
  18. "strings"
  19. "testing"
  20. "time"
  21. . "github.com/smartystreets/goconvey/convey"
  22. "gopkg.in/ini.v1"
  23. )
  24. func TestKey_AddShadow(t *testing.T) {
  25. Convey("Add shadow to a key", t, func() {
  26. f, err := ini.ShadowLoad([]byte(`
  27. [notes]
  28. -: note1`))
  29. So(err, ShouldBeNil)
  30. So(f, ShouldNotBeNil)
  31. k, err := f.Section("").NewKey("NAME", "ini")
  32. So(err, ShouldBeNil)
  33. So(k, ShouldNotBeNil)
  34. So(k.AddShadow("ini.v1"), ShouldBeNil)
  35. So(k.ValueWithShadows(), ShouldResemble, []string{"ini", "ini.v1"})
  36. Convey("Add shadow to boolean key", func() {
  37. k, err := f.Section("").NewBooleanKey("published")
  38. So(err, ShouldBeNil)
  39. So(k, ShouldNotBeNil)
  40. So(k.AddShadow("beta"), ShouldNotBeNil)
  41. })
  42. Convey("Add shadow to auto-increment key", func() {
  43. So(f.Section("notes").Key("#1").AddShadow("beta"), ShouldNotBeNil)
  44. })
  45. })
  46. Convey("Shadow is not allowed", t, func() {
  47. f := ini.Empty()
  48. So(f, ShouldNotBeNil)
  49. k, err := f.Section("").NewKey("NAME", "ini")
  50. So(err, ShouldBeNil)
  51. So(k, ShouldNotBeNil)
  52. So(k.AddShadow("ini.v1"), ShouldNotBeNil)
  53. })
  54. }
  55. // Helpers for slice tests.
  56. func float64sEqual(values []float64, expected ...float64) {
  57. So(values, ShouldHaveLength, len(expected))
  58. for i, v := range expected {
  59. So(values[i], ShouldEqual, v)
  60. }
  61. }
  62. func intsEqual(values []int, expected ...int) {
  63. So(values, ShouldHaveLength, len(expected))
  64. for i, v := range expected {
  65. So(values[i], ShouldEqual, v)
  66. }
  67. }
  68. func int64sEqual(values []int64, expected ...int64) {
  69. So(values, ShouldHaveLength, len(expected))
  70. for i, v := range expected {
  71. So(values[i], ShouldEqual, v)
  72. }
  73. }
  74. func uintsEqual(values []uint, expected ...uint) {
  75. So(values, ShouldHaveLength, len(expected))
  76. for i, v := range expected {
  77. So(values[i], ShouldEqual, v)
  78. }
  79. }
  80. func uint64sEqual(values []uint64, expected ...uint64) {
  81. So(values, ShouldHaveLength, len(expected))
  82. for i, v := range expected {
  83. So(values[i], ShouldEqual, v)
  84. }
  85. }
  86. func boolsEqual(values []bool, expected ...bool) {
  87. So(values, ShouldHaveLength, len(expected))
  88. for i, v := range expected {
  89. So(values[i], ShouldEqual, v)
  90. }
  91. }
  92. func timesEqual(values []time.Time, expected ...time.Time) {
  93. So(values, ShouldHaveLength, len(expected))
  94. for i, v := range expected {
  95. So(values[i].String(), ShouldEqual, v.String())
  96. }
  97. }
  98. func TestKey_Helpers(t *testing.T) {
  99. Convey("Getting and setting values", t, func() {
  100. f, err := ini.Load(fullConf)
  101. So(err, ShouldBeNil)
  102. So(f, ShouldNotBeNil)
  103. Convey("Get string representation", func() {
  104. sec := f.Section("")
  105. So(sec, ShouldNotBeNil)
  106. So(sec.Key("NAME").Value(), ShouldEqual, "ini")
  107. So(sec.Key("NAME").String(), ShouldEqual, "ini")
  108. So(sec.Key("NAME").Validate(func(in string) string {
  109. return in
  110. }), ShouldEqual, "ini")
  111. So(sec.Key("NAME").Comment, ShouldEqual, "; Package name")
  112. So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "gopkg.in/ini.v1")
  113. Convey("With ValueMapper", func() {
  114. f.ValueMapper = func(in string) string {
  115. if in == "gopkg.in/%(NAME)s.%(VERSION)s" {
  116. return "github.com/go-ini/ini"
  117. }
  118. return in
  119. }
  120. So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "github.com/go-ini/ini")
  121. })
  122. })
  123. Convey("Get values in non-default section", func() {
  124. sec := f.Section("author")
  125. So(sec, ShouldNotBeNil)
  126. So(sec.Key("NAME").String(), ShouldEqual, "Unknwon")
  127. So(sec.Key("GITHUB").String(), ShouldEqual, "https://github.com/Unknwon")
  128. sec = f.Section("package")
  129. So(sec, ShouldNotBeNil)
  130. So(sec.Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
  131. })
  132. Convey("Get auto-increment key names", func() {
  133. keys := f.Section("features").Keys()
  134. for i, k := range keys {
  135. So(k.Name(), ShouldEqual, fmt.Sprintf("#%d", i+1))
  136. }
  137. })
  138. Convey("Get parent-keys that are available to the child section", func() {
  139. parentKeys := f.Section("package.sub").ParentKeys()
  140. for _, k := range parentKeys {
  141. So(k.Name(), ShouldEqual, "CLONE_URL")
  142. }
  143. })
  144. Convey("Get overwrite value", func() {
  145. So(f.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
  146. })
  147. Convey("Get sections", func() {
  148. sections := f.Sections()
  149. for i, name := range []string{ini.DefaultSection, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"} {
  150. So(sections[i].Name(), ShouldEqual, name)
  151. }
  152. })
  153. Convey("Get parent section value", func() {
  154. So(f.Section("package.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
  155. So(f.Section("package.fake.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
  156. })
  157. Convey("Get multiple line value", func() {
  158. So(f.Section("author").Key("BIO").String(), ShouldEqual, "Gopher.\nCoding addict.\nGood man.\n")
  159. })
  160. Convey("Get values with type", func() {
  161. sec := f.Section("types")
  162. v1, err := sec.Key("BOOL").Bool()
  163. So(err, ShouldBeNil)
  164. So(v1, ShouldBeTrue)
  165. v1, err = sec.Key("BOOL_FALSE").Bool()
  166. So(err, ShouldBeNil)
  167. So(v1, ShouldBeFalse)
  168. v2, err := sec.Key("FLOAT64").Float64()
  169. So(err, ShouldBeNil)
  170. So(v2, ShouldEqual, 1.25)
  171. v3, err := sec.Key("INT").Int()
  172. So(err, ShouldBeNil)
  173. So(v3, ShouldEqual, 10)
  174. v4, err := sec.Key("INT").Int64()
  175. So(err, ShouldBeNil)
  176. So(v4, ShouldEqual, 10)
  177. v5, err := sec.Key("UINT").Uint()
  178. So(err, ShouldBeNil)
  179. So(v5, ShouldEqual, 3)
  180. v6, err := sec.Key("UINT").Uint64()
  181. So(err, ShouldBeNil)
  182. So(v6, ShouldEqual, 3)
  183. t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
  184. So(err, ShouldBeNil)
  185. v7, err := sec.Key("TIME").Time()
  186. So(err, ShouldBeNil)
  187. So(v7.String(), ShouldEqual, t.String())
  188. v8, err := sec.Key("HEX_NUMBER").Int()
  189. So(err, ShouldBeNil)
  190. So(v8, ShouldEqual, 0x3000)
  191. Convey("Must get values with type", func() {
  192. So(sec.Key("STRING").MustString("404"), ShouldEqual, "str")
  193. So(sec.Key("BOOL").MustBool(), ShouldBeTrue)
  194. So(sec.Key("FLOAT64").MustFloat64(), ShouldEqual, 1.25)
  195. So(sec.Key("INT").MustInt(), ShouldEqual, 10)
  196. So(sec.Key("INT").MustInt64(), ShouldEqual, 10)
  197. So(sec.Key("UINT").MustUint(), ShouldEqual, 3)
  198. So(sec.Key("UINT").MustUint64(), ShouldEqual, 3)
  199. So(sec.Key("TIME").MustTime().String(), ShouldEqual, t.String())
  200. So(sec.Key("HEX_NUMBER").MustInt(), ShouldEqual, 0x3000)
  201. dur, err := time.ParseDuration("2h45m")
  202. So(err, ShouldBeNil)
  203. So(sec.Key("DURATION").MustDuration().Seconds(), ShouldEqual, dur.Seconds())
  204. Convey("Must get values with default value", func() {
  205. So(sec.Key("STRING_404").MustString("404"), ShouldEqual, "404")
  206. So(sec.Key("BOOL_404").MustBool(true), ShouldBeTrue)
  207. So(sec.Key("FLOAT64_404").MustFloat64(2.5), ShouldEqual, 2.5)
  208. So(sec.Key("INT_404").MustInt(15), ShouldEqual, 15)
  209. So(sec.Key("INT64_404").MustInt64(15), ShouldEqual, 15)
  210. So(sec.Key("UINT_404").MustUint(6), ShouldEqual, 6)
  211. So(sec.Key("UINT64_404").MustUint64(6), ShouldEqual, 6)
  212. So(sec.Key("HEX_NUMBER_404").MustInt(0x3001), ShouldEqual, 0x3001)
  213. t, err := time.Parse(time.RFC3339, "2014-01-01T20:17:05Z")
  214. So(err, ShouldBeNil)
  215. So(sec.Key("TIME_404").MustTime(t).String(), ShouldEqual, t.String())
  216. So(sec.Key("DURATION_404").MustDuration(dur).Seconds(), ShouldEqual, dur.Seconds())
  217. Convey("Must should set default as key value", func() {
  218. So(sec.Key("STRING_404").String(), ShouldEqual, "404")
  219. So(sec.Key("BOOL_404").String(), ShouldEqual, "true")
  220. So(sec.Key("FLOAT64_404").String(), ShouldEqual, "2.5")
  221. So(sec.Key("INT_404").String(), ShouldEqual, "15")
  222. So(sec.Key("INT64_404").String(), ShouldEqual, "15")
  223. So(sec.Key("UINT_404").String(), ShouldEqual, "6")
  224. So(sec.Key("UINT64_404").String(), ShouldEqual, "6")
  225. So(sec.Key("TIME_404").String(), ShouldEqual, "2014-01-01T20:17:05Z")
  226. So(sec.Key("DURATION_404").String(), ShouldEqual, "2h45m0s")
  227. So(sec.Key("HEX_NUMBER_404").String(), ShouldEqual, "12289")
  228. })
  229. })
  230. })
  231. })
  232. Convey("Get value with candidates", func() {
  233. sec := f.Section("types")
  234. So(sec.Key("STRING").In("", []string{"str", "arr", "types"}), ShouldEqual, "str")
  235. So(sec.Key("FLOAT64").InFloat64(0, []float64{1.25, 2.5, 3.75}), ShouldEqual, 1.25)
  236. So(sec.Key("INT").InInt(0, []int{10, 20, 30}), ShouldEqual, 10)
  237. So(sec.Key("INT").InInt64(0, []int64{10, 20, 30}), ShouldEqual, 10)
  238. So(sec.Key("UINT").InUint(0, []uint{3, 6, 9}), ShouldEqual, 3)
  239. So(sec.Key("UINT").InUint64(0, []uint64{3, 6, 9}), ShouldEqual, 3)
  240. zt, err := time.Parse(time.RFC3339, "0001-01-01T01:00:00Z")
  241. So(err, ShouldBeNil)
  242. t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
  243. So(err, ShouldBeNil)
  244. So(sec.Key("TIME").InTime(zt, []time.Time{t, time.Now(), time.Now().Add(1 * time.Second)}).String(), ShouldEqual, t.String())
  245. Convey("Get value with candidates and default value", func() {
  246. So(sec.Key("STRING_404").In("str", []string{"str", "arr", "types"}), ShouldEqual, "str")
  247. So(sec.Key("FLOAT64_404").InFloat64(1.25, []float64{1.25, 2.5, 3.75}), ShouldEqual, 1.25)
  248. So(sec.Key("INT_404").InInt(10, []int{10, 20, 30}), ShouldEqual, 10)
  249. So(sec.Key("INT64_404").InInt64(10, []int64{10, 20, 30}), ShouldEqual, 10)
  250. So(sec.Key("UINT_404").InUint(3, []uint{3, 6, 9}), ShouldEqual, 3)
  251. So(sec.Key("UINT_404").InUint64(3, []uint64{3, 6, 9}), ShouldEqual, 3)
  252. So(sec.Key("TIME_404").InTime(t, []time.Time{time.Now(), time.Now(), time.Now().Add(1 * time.Second)}).String(), ShouldEqual, t.String())
  253. })
  254. })
  255. Convey("Get values in range", func() {
  256. sec := f.Section("types")
  257. So(sec.Key("FLOAT64").RangeFloat64(0, 1, 2), ShouldEqual, 1.25)
  258. So(sec.Key("INT").RangeInt(0, 10, 20), ShouldEqual, 10)
  259. So(sec.Key("INT").RangeInt64(0, 10, 20), ShouldEqual, 10)
  260. minT, err := time.Parse(time.RFC3339, "0001-01-01T01:00:00Z")
  261. So(err, ShouldBeNil)
  262. midT, err := time.Parse(time.RFC3339, "2013-01-01T01:00:00Z")
  263. So(err, ShouldBeNil)
  264. maxT, err := time.Parse(time.RFC3339, "9999-01-01T01:00:00Z")
  265. So(err, ShouldBeNil)
  266. t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
  267. So(err, ShouldBeNil)
  268. So(sec.Key("TIME").RangeTime(t, minT, maxT).String(), ShouldEqual, t.String())
  269. Convey("Get value in range with default value", func() {
  270. So(sec.Key("FLOAT64").RangeFloat64(5, 0, 1), ShouldEqual, 5)
  271. So(sec.Key("INT").RangeInt(7, 0, 5), ShouldEqual, 7)
  272. So(sec.Key("INT").RangeInt64(7, 0, 5), ShouldEqual, 7)
  273. So(sec.Key("TIME").RangeTime(t, minT, midT).String(), ShouldEqual, t.String())
  274. })
  275. })
  276. Convey("Get values into slice", func() {
  277. sec := f.Section("array")
  278. So(strings.Join(sec.Key("STRINGS").Strings(","), ","), ShouldEqual, "en,zh,de")
  279. So(len(sec.Key("STRINGS_404").Strings(",")), ShouldEqual, 0)
  280. vals1 := sec.Key("FLOAT64S").Float64s(",")
  281. float64sEqual(vals1, 1.1, 2.2, 3.3)
  282. vals2 := sec.Key("INTS").Ints(",")
  283. intsEqual(vals2, 1, 2, 3)
  284. vals3 := sec.Key("INTS").Int64s(",")
  285. int64sEqual(vals3, 1, 2, 3)
  286. vals4 := sec.Key("UINTS").Uints(",")
  287. uintsEqual(vals4, 1, 2, 3)
  288. vals5 := sec.Key("UINTS").Uint64s(",")
  289. uint64sEqual(vals5, 1, 2, 3)
  290. vals6 := sec.Key("BOOLS").Bools(",")
  291. boolsEqual(vals6, true, false, false)
  292. t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
  293. So(err, ShouldBeNil)
  294. vals7 := sec.Key("TIMES").Times(",")
  295. timesEqual(vals7, t, t, t)
  296. })
  297. Convey("Test string slice escapes", func() {
  298. sec := f.Section("string escapes")
  299. So(sec.Key("key1").Strings(","), ShouldResemble, []string{"value1", "value2", "value3"})
  300. So(sec.Key("key2").Strings(","), ShouldResemble, []string{"value1, value2"})
  301. So(sec.Key("key3").Strings(","), ShouldResemble, []string{`val\ue1`, "value2"})
  302. So(sec.Key("key4").Strings(","), ShouldResemble, []string{`value1\`, `value\\2`})
  303. So(sec.Key("key5").Strings(",,"), ShouldResemble, []string{"value1,, value2"})
  304. So(sec.Key("key6").Strings(" "), ShouldResemble, []string{"aaa", "bbb and space", "ccc"})
  305. })
  306. Convey("Get valid values into slice", func() {
  307. sec := f.Section("array")
  308. vals1 := sec.Key("FLOAT64S").ValidFloat64s(",")
  309. float64sEqual(vals1, 1.1, 2.2, 3.3)
  310. vals2 := sec.Key("INTS").ValidInts(",")
  311. intsEqual(vals2, 1, 2, 3)
  312. vals3 := sec.Key("INTS").ValidInt64s(",")
  313. int64sEqual(vals3, 1, 2, 3)
  314. vals4 := sec.Key("UINTS").ValidUints(",")
  315. uintsEqual(vals4, 1, 2, 3)
  316. vals5 := sec.Key("UINTS").ValidUint64s(",")
  317. uint64sEqual(vals5, 1, 2, 3)
  318. vals6 := sec.Key("BOOLS").ValidBools(",")
  319. boolsEqual(vals6, true, false, false)
  320. t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
  321. So(err, ShouldBeNil)
  322. vals7 := sec.Key("TIMES").ValidTimes(",")
  323. timesEqual(vals7, t, t, t)
  324. })
  325. Convey("Get values one type into slice of another type", func() {
  326. sec := f.Section("array")
  327. vals1 := sec.Key("STRINGS").ValidFloat64s(",")
  328. So(vals1, ShouldBeEmpty)
  329. vals2 := sec.Key("STRINGS").ValidInts(",")
  330. So(vals2, ShouldBeEmpty)
  331. vals3 := sec.Key("STRINGS").ValidInt64s(",")
  332. So(vals3, ShouldBeEmpty)
  333. vals4 := sec.Key("STRINGS").ValidUints(",")
  334. So(vals4, ShouldBeEmpty)
  335. vals5 := sec.Key("STRINGS").ValidUint64s(",")
  336. So(vals5, ShouldBeEmpty)
  337. vals6 := sec.Key("STRINGS").ValidBools(",")
  338. So(vals6, ShouldBeEmpty)
  339. vals7 := sec.Key("STRINGS").ValidTimes(",")
  340. So(vals7, ShouldBeEmpty)
  341. })
  342. Convey("Get valid values into slice without errors", func() {
  343. sec := f.Section("array")
  344. vals1, err := sec.Key("FLOAT64S").StrictFloat64s(",")
  345. So(err, ShouldBeNil)
  346. float64sEqual(vals1, 1.1, 2.2, 3.3)
  347. vals2, err := sec.Key("INTS").StrictInts(",")
  348. So(err, ShouldBeNil)
  349. intsEqual(vals2, 1, 2, 3)
  350. vals3, err := sec.Key("INTS").StrictInt64s(",")
  351. So(err, ShouldBeNil)
  352. int64sEqual(vals3, 1, 2, 3)
  353. vals4, err := sec.Key("UINTS").StrictUints(",")
  354. So(err, ShouldBeNil)
  355. uintsEqual(vals4, 1, 2, 3)
  356. vals5, err := sec.Key("UINTS").StrictUint64s(",")
  357. So(err, ShouldBeNil)
  358. uint64sEqual(vals5, 1, 2, 3)
  359. vals6, err := sec.Key("BOOLS").StrictBools(",")
  360. So(err, ShouldBeNil)
  361. boolsEqual(vals6, true, false, false)
  362. t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
  363. So(err, ShouldBeNil)
  364. vals7, err := sec.Key("TIMES").StrictTimes(",")
  365. So(err, ShouldBeNil)
  366. timesEqual(vals7, t, t, t)
  367. })
  368. Convey("Get invalid values into slice", func() {
  369. sec := f.Section("array")
  370. vals1, err := sec.Key("STRINGS").StrictFloat64s(",")
  371. So(vals1, ShouldBeEmpty)
  372. So(err, ShouldNotBeNil)
  373. vals2, err := sec.Key("STRINGS").StrictInts(",")
  374. So(vals2, ShouldBeEmpty)
  375. So(err, ShouldNotBeNil)
  376. vals3, err := sec.Key("STRINGS").StrictInt64s(",")
  377. So(vals3, ShouldBeEmpty)
  378. So(err, ShouldNotBeNil)
  379. vals4, err := sec.Key("STRINGS").StrictUints(",")
  380. So(vals4, ShouldBeEmpty)
  381. So(err, ShouldNotBeNil)
  382. vals5, err := sec.Key("STRINGS").StrictUint64s(",")
  383. So(vals5, ShouldBeEmpty)
  384. So(err, ShouldNotBeNil)
  385. vals6, err := sec.Key("STRINGS").StrictBools(",")
  386. So(vals6, ShouldBeEmpty)
  387. So(err, ShouldNotBeNil)
  388. vals7, err := sec.Key("STRINGS").StrictTimes(",")
  389. So(vals7, ShouldBeEmpty)
  390. So(err, ShouldNotBeNil)
  391. })
  392. })
  393. }
  394. func TestKey_StringsWithShadows(t *testing.T) {
  395. Convey("Get strings of shadows of a key", t, func() {
  396. f, err := ini.ShadowLoad([]byte(""))
  397. So(err, ShouldBeNil)
  398. So(f, ShouldNotBeNil)
  399. k, err := f.Section("").NewKey("NUMS", "1,2")
  400. So(err, ShouldBeNil)
  401. So(k, ShouldNotBeNil)
  402. k, err = f.Section("").NewKey("NUMS", "4,5,6")
  403. So(err, ShouldBeNil)
  404. So(k, ShouldNotBeNil)
  405. So(k.StringsWithShadows(","), ShouldResemble, []string{"1", "2", "4", "5", "6"})
  406. })
  407. }
  408. func TestKey_SetValue(t *testing.T) {
  409. Convey("Set value of key", t, func() {
  410. f := ini.Empty()
  411. So(f, ShouldNotBeNil)
  412. k, err := f.Section("").NewKey("NAME", "ini")
  413. So(err, ShouldBeNil)
  414. So(k, ShouldNotBeNil)
  415. So(k.Value(), ShouldEqual, "ini")
  416. k.SetValue("ini.v1")
  417. So(k.Value(), ShouldEqual, "ini.v1")
  418. })
  419. }
  420. func TestKey_NestedValues(t *testing.T) {
  421. Convey("Read and write nested values", t, func() {
  422. f, err := ini.LoadSources(ini.LoadOptions{
  423. AllowNestedValues: true,
  424. }, []byte(`
  425. aws_access_key_id = foo
  426. aws_secret_access_key = bar
  427. region = us-west-2
  428. s3 =
  429. max_concurrent_requests=10
  430. max_queue_size=1000`))
  431. So(err, ShouldBeNil)
  432. So(f, ShouldNotBeNil)
  433. So(f.Section("").Key("s3").NestedValues(), ShouldResemble, []string{"max_concurrent_requests=10", "max_queue_size=1000"})
  434. var buf bytes.Buffer
  435. _, err = f.WriteTo(&buf)
  436. So(err, ShouldBeNil)
  437. So(buf.String(), ShouldEqual, `aws_access_key_id = foo
  438. aws_secret_access_key = bar
  439. region = us-west-2
  440. s3 =
  441. max_concurrent_requests=10
  442. max_queue_size=1000
  443. `)
  444. })
  445. }
  446. func TestRecursiveValues(t *testing.T) {
  447. Convey("Recursive values should not reflect on same key", t, func() {
  448. f, err := ini.Load([]byte(`
  449. NAME = ini
  450. expires = yes
  451. [package]
  452. NAME = %(NAME)s
  453. expires = %(expires)s`))
  454. So(err, ShouldBeNil)
  455. So(f, ShouldNotBeNil)
  456. So(f.Section("package").Key("NAME").String(), ShouldEqual, "ini")
  457. So(f.Section("package").Key("expires").String(), ShouldEqual, "yes")
  458. })
  459. Convey("Recursive value with no target found", t, func() {
  460. f, err := ini.Load([]byte(`
  461. [foo]
  462. bar = %(missing)s
  463. `))
  464. So(err, ShouldBeNil)
  465. So(f, ShouldNotBeNil)
  466. So(f.Section("foo").Key("bar").String(), ShouldEqual, "%(missing)s")
  467. })
  468. }