ini_test.go 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310
  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. "flag"
  18. "io/ioutil"
  19. "testing"
  20. . "github.com/smartystreets/goconvey/convey"
  21. "gopkg.in/ini.v1"
  22. )
  23. const (
  24. confData = `
  25. ; Package name
  26. NAME = ini
  27. ; Package version
  28. VERSION = v1
  29. ; Package import path
  30. IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s
  31. # Information about package author
  32. # Bio can be written in multiple lines.
  33. [author]
  34. NAME = Unknwon ; Succeeding comment
  35. E-MAIL = fake@localhost
  36. GITHUB = https://github.com/%(NAME)s
  37. BIO = """Gopher.
  38. Coding addict.
  39. Good man.
  40. """ # Succeeding comment`
  41. minimalConf = "testdata/minimal.ini"
  42. fullConf = "testdata/full.ini"
  43. notFoundConf = "testdata/404.ini"
  44. )
  45. var update = flag.Bool("update", false, "Update .golden files")
  46. func TestLoad(t *testing.T) {
  47. Convey("Load from good data sources", t, func() {
  48. f, err := ini.Load([]byte(`
  49. NAME = ini
  50. VERSION = v1
  51. IMPORT_PATH = gopkg.in/%(NAME)s.%(VERSION)s`),
  52. "testdata/minimal.ini",
  53. ioutil.NopCloser(bytes.NewReader([]byte(`
  54. [author]
  55. NAME = Unknwon
  56. `))),
  57. )
  58. So(err, ShouldBeNil)
  59. So(f, ShouldNotBeNil)
  60. // Validate values make sure all sources are loaded correctly
  61. sec := f.Section("")
  62. So(sec.Key("NAME").String(), ShouldEqual, "ini")
  63. So(sec.Key("VERSION").String(), ShouldEqual, "v1")
  64. So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "gopkg.in/ini.v1")
  65. sec = f.Section("author")
  66. So(sec.Key("NAME").String(), ShouldEqual, "Unknwon")
  67. So(sec.Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
  68. })
  69. Convey("Load from bad data sources", t, func() {
  70. Convey("Invalid input", func() {
  71. _, err := ini.Load(notFoundConf)
  72. So(err, ShouldNotBeNil)
  73. })
  74. Convey("Unsupported type", func() {
  75. _, err := ini.Load(123)
  76. So(err, ShouldNotBeNil)
  77. })
  78. })
  79. Convey("Can't properly parse INI files containing `#` or `;` in value", t, func() {
  80. f, err := ini.Load([]byte(`
  81. [author]
  82. NAME = U#n#k#n#w#o#n
  83. GITHUB = U;n;k;n;w;o;n
  84. `))
  85. So(err, ShouldBeNil)
  86. So(f, ShouldNotBeNil)
  87. sec := f.Section("author")
  88. nameValue := sec.Key("NAME").String()
  89. githubValue := sec.Key("GITHUB").String()
  90. So(nameValue, ShouldEqual, "U")
  91. So(githubValue, ShouldEqual, "U")
  92. })
  93. Convey("Can't parse small python-compatible INI files", t, func() {
  94. f, err := ini.Load([]byte(`
  95. [long]
  96. long_rsa_private_key = -----BEGIN RSA PRIVATE KEY-----
  97. foo
  98. bar
  99. foobar
  100. barfoo
  101. -----END RSA PRIVATE KEY-----
  102. `))
  103. So(err, ShouldNotBeNil)
  104. So(f, ShouldBeNil)
  105. So(err.Error(), ShouldEqual, "key-value delimiter not found: foo\n")
  106. })
  107. Convey("Can't parse big python-compatible INI files", t, func() {
  108. f, err := ini.Load([]byte(`
  109. [long]
  110. long_rsa_private_key = -----BEGIN RSA PRIVATE KEY-----
  111. 1foo
  112. 2bar
  113. 3foobar
  114. 4barfoo
  115. 5foo
  116. 6bar
  117. 7foobar
  118. 8barfoo
  119. 9foo
  120. 10bar
  121. 11foobar
  122. 12barfoo
  123. 13foo
  124. 14bar
  125. 15foobar
  126. 16barfoo
  127. 17foo
  128. 18bar
  129. 19foobar
  130. 20barfoo
  131. 21foo
  132. 22bar
  133. 23foobar
  134. 24barfoo
  135. 25foo
  136. 26bar
  137. 27foobar
  138. 28barfoo
  139. 29foo
  140. 30bar
  141. 31foobar
  142. 32barfoo
  143. 33foo
  144. 34bar
  145. 35foobar
  146. 36barfoo
  147. 37foo
  148. 38bar
  149. 39foobar
  150. 40barfoo
  151. 41foo
  152. 42bar
  153. 43foobar
  154. 44barfoo
  155. 45foo
  156. 46bar
  157. 47foobar
  158. 48barfoo
  159. 49foo
  160. 50bar
  161. 51foobar
  162. 52barfoo
  163. 53foo
  164. 54bar
  165. 55foobar
  166. 56barfoo
  167. 57foo
  168. 58bar
  169. 59foobar
  170. 60barfoo
  171. 61foo
  172. 62bar
  173. 63foobar
  174. 64barfoo
  175. 65foo
  176. 66bar
  177. 67foobar
  178. 68barfoo
  179. 69foo
  180. 70bar
  181. 71foobar
  182. 72barfoo
  183. 73foo
  184. 74bar
  185. 75foobar
  186. 76barfoo
  187. 77foo
  188. 78bar
  189. 79foobar
  190. 80barfoo
  191. 81foo
  192. 82bar
  193. 83foobar
  194. 84barfoo
  195. 85foo
  196. 86bar
  197. 87foobar
  198. 88barfoo
  199. 89foo
  200. 90bar
  201. 91foobar
  202. 92barfoo
  203. 93foo
  204. 94bar
  205. 95foobar
  206. 96barfoo
  207. -----END RSA PRIVATE KEY-----
  208. `))
  209. So(err, ShouldNotBeNil)
  210. So(f, ShouldBeNil)
  211. So(err.Error(), ShouldEqual, "key-value delimiter not found: 1foo\n")
  212. })
  213. }
  214. func TestLooseLoad(t *testing.T) {
  215. Convey("Load from data sources with option `Loose` true", t, func() {
  216. f, err := ini.LoadSources(ini.LoadOptions{Loose: true}, notFoundConf, minimalConf)
  217. So(err, ShouldBeNil)
  218. So(f, ShouldNotBeNil)
  219. Convey("Inverse case", func() {
  220. _, err = ini.Load(notFoundConf)
  221. So(err, ShouldNotBeNil)
  222. })
  223. })
  224. }
  225. func TestInsensitiveLoad(t *testing.T) {
  226. Convey("Insensitive to section and key names", t, func() {
  227. f, err := ini.InsensitiveLoad(minimalConf)
  228. So(err, ShouldBeNil)
  229. So(f, ShouldNotBeNil)
  230. So(f.Section("Author").Key("e-mail").String(), ShouldEqual, "u@gogs.io")
  231. Convey("Write out", func() {
  232. var buf bytes.Buffer
  233. _, err := f.WriteTo(&buf)
  234. So(err, ShouldBeNil)
  235. So(buf.String(), ShouldEqual, `[author]
  236. e-mail = u@gogs.io
  237. `)
  238. })
  239. Convey("Inverse case", func() {
  240. f, err := ini.Load(minimalConf)
  241. So(err, ShouldBeNil)
  242. So(f, ShouldNotBeNil)
  243. So(f.Section("Author").Key("e-mail").String(), ShouldBeEmpty)
  244. })
  245. })
  246. // Ref: https://github.com/go-ini/ini/issues/198
  247. Convey("Insensitive load with default section", t, func() {
  248. f, err := ini.InsensitiveLoad([]byte(`
  249. user = unknwon
  250. [profile]
  251. email = unknwon@local
  252. `))
  253. So(err, ShouldBeNil)
  254. So(f, ShouldNotBeNil)
  255. So(f.Section(ini.DefaultSection).Key("user").String(), ShouldEqual, "unknwon")
  256. })
  257. }
  258. func TestLoadSources(t *testing.T) {
  259. Convey("Load from data sources with options", t, func() {
  260. Convey("with true `AllowPythonMultilineValues`", func() {
  261. Convey("Ignore nonexistent files", func() {
  262. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true, Loose: true}, notFoundConf, minimalConf)
  263. So(err, ShouldBeNil)
  264. So(f, ShouldNotBeNil)
  265. Convey("Inverse case", func() {
  266. _, err = ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, notFoundConf)
  267. So(err, ShouldNotBeNil)
  268. })
  269. })
  270. Convey("Insensitive to section and key names", func() {
  271. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true, Insensitive: true}, minimalConf)
  272. So(err, ShouldBeNil)
  273. So(f, ShouldNotBeNil)
  274. So(f.Section("Author").Key("e-mail").String(), ShouldEqual, "u@gogs.io")
  275. Convey("Write out", func() {
  276. var buf bytes.Buffer
  277. _, err := f.WriteTo(&buf)
  278. So(err, ShouldBeNil)
  279. So(buf.String(), ShouldEqual, `[author]
  280. e-mail = u@gogs.io
  281. `)
  282. })
  283. Convey("Inverse case", func() {
  284. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, minimalConf)
  285. So(err, ShouldBeNil)
  286. So(f, ShouldNotBeNil)
  287. So(f.Section("Author").Key("e-mail").String(), ShouldBeEmpty)
  288. })
  289. })
  290. Convey("Ignore continuation lines", func() {
  291. f, err := ini.LoadSources(ini.LoadOptions{
  292. AllowPythonMultilineValues: true,
  293. IgnoreContinuation: true,
  294. }, []byte(`
  295. key1=a\b\
  296. key2=c\d\
  297. key3=value`))
  298. So(err, ShouldBeNil)
  299. So(f, ShouldNotBeNil)
  300. So(f.Section("").Key("key1").String(), ShouldEqual, `a\b\`)
  301. So(f.Section("").Key("key2").String(), ShouldEqual, `c\d\`)
  302. So(f.Section("").Key("key3").String(), ShouldEqual, "value")
  303. Convey("Inverse case", func() {
  304. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(`
  305. key1=a\b\
  306. key2=c\d\`))
  307. So(err, ShouldBeNil)
  308. So(f, ShouldNotBeNil)
  309. So(f.Section("").Key("key1").String(), ShouldEqual, `a\bkey2=c\d`)
  310. })
  311. })
  312. Convey("Ignore inline comments", func() {
  313. f, err := ini.LoadSources(ini.LoadOptions{
  314. AllowPythonMultilineValues: true,
  315. IgnoreInlineComment: true,
  316. }, []byte(`
  317. key1=value ;comment
  318. key2=value2 #comment2
  319. key3=val#ue #comment3`))
  320. So(err, ShouldBeNil)
  321. So(f, ShouldNotBeNil)
  322. So(f.Section("").Key("key1").String(), ShouldEqual, `value ;comment`)
  323. So(f.Section("").Key("key2").String(), ShouldEqual, `value2 #comment2`)
  324. So(f.Section("").Key("key3").String(), ShouldEqual, `val#ue #comment3`)
  325. Convey("Inverse case", func() {
  326. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(`
  327. key1=value ;comment
  328. key2=value2 #comment2`))
  329. So(err, ShouldBeNil)
  330. So(f, ShouldNotBeNil)
  331. So(f.Section("").Key("key1").String(), ShouldEqual, `value`)
  332. So(f.Section("").Key("key1").Comment, ShouldEqual, `;comment`)
  333. So(f.Section("").Key("key2").String(), ShouldEqual, `value2`)
  334. So(f.Section("").Key("key2").Comment, ShouldEqual, `#comment2`)
  335. })
  336. })
  337. Convey("Skip unrecognizable lines", func() {
  338. f, err := ini.LoadSources(ini.LoadOptions{
  339. SkipUnrecognizableLines: true,
  340. }, []byte(`
  341. GenerationDepth: 13
  342. BiomeRarityScale: 100
  343. ################
  344. # Biome Groups #
  345. ################
  346. BiomeGroup(NormalBiomes, 3, 99, RoofedForestEnchanted, ForestSakura, FloatingJungle
  347. BiomeGroup(IceBiomes, 4, 85, Ice Plains)
  348. `))
  349. So(err, ShouldBeNil)
  350. So(f, ShouldNotBeNil)
  351. So(f.Section("").Key("GenerationDepth").String(), ShouldEqual, "13")
  352. So(f.Section("").Key("BiomeRarityScale").String(), ShouldEqual, "100")
  353. So(f.Section("").HasKey("BiomeGroup"), ShouldBeFalse)
  354. })
  355. Convey("Allow boolean type keys", func() {
  356. f, err := ini.LoadSources(ini.LoadOptions{
  357. AllowPythonMultilineValues: true,
  358. AllowBooleanKeys: true,
  359. }, []byte(`
  360. key1=hello
  361. #key2
  362. key3`))
  363. So(err, ShouldBeNil)
  364. So(f, ShouldNotBeNil)
  365. So(f.Section("").KeyStrings(), ShouldResemble, []string{"key1", "key3"})
  366. So(f.Section("").Key("key3").MustBool(false), ShouldBeTrue)
  367. Convey("Write out", func() {
  368. var buf bytes.Buffer
  369. _, err := f.WriteTo(&buf)
  370. So(err, ShouldBeNil)
  371. So(buf.String(), ShouldEqual, `key1 = hello
  372. # key2
  373. key3
  374. `)
  375. })
  376. Convey("Inverse case", func() {
  377. _, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(`
  378. key1=hello
  379. #key2
  380. key3`))
  381. So(err, ShouldNotBeNil)
  382. })
  383. })
  384. Convey("Allow shadow keys", func() {
  385. f, err := ini.LoadSources(ini.LoadOptions{AllowShadows: true, AllowPythonMultilineValues: true}, []byte(`
  386. [remote "origin"]
  387. url = https://github.com/Antergone/test1.git
  388. url = https://github.com/Antergone/test2.git
  389. fetch = +refs/heads/*:refs/remotes/origin/*`))
  390. So(err, ShouldBeNil)
  391. So(f, ShouldNotBeNil)
  392. So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test1.git")
  393. So(f.Section(`remote "origin"`).Key("url").ValueWithShadows(), ShouldResemble, []string{
  394. "https://github.com/Antergone/test1.git",
  395. "https://github.com/Antergone/test2.git",
  396. })
  397. So(f.Section(`remote "origin"`).Key("fetch").String(), ShouldEqual, "+refs/heads/*:refs/remotes/origin/*")
  398. Convey("Write out", func() {
  399. var buf bytes.Buffer
  400. _, err := f.WriteTo(&buf)
  401. So(err, ShouldBeNil)
  402. So(buf.String(), ShouldEqual, `[remote "origin"]
  403. url = https://github.com/Antergone/test1.git
  404. url = https://github.com/Antergone/test2.git
  405. fetch = +refs/heads/*:refs/remotes/origin/*
  406. `)
  407. })
  408. Convey("Inverse case", func() {
  409. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(`
  410. [remote "origin"]
  411. url = https://github.com/Antergone/test1.git
  412. url = https://github.com/Antergone/test2.git`))
  413. So(err, ShouldBeNil)
  414. So(f, ShouldNotBeNil)
  415. So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test2.git")
  416. })
  417. })
  418. Convey("Unescape double quotes inside value", func() {
  419. f, err := ini.LoadSources(ini.LoadOptions{
  420. AllowPythonMultilineValues: true,
  421. UnescapeValueDoubleQuotes: true,
  422. }, []byte(`
  423. create_repo="创建了仓库 <a href=\"%s\">%s</a>"`))
  424. So(err, ShouldBeNil)
  425. So(f, ShouldNotBeNil)
  426. So(f.Section("").Key("create_repo").String(), ShouldEqual, `创建了仓库 <a href="%s">%s</a>`)
  427. Convey("Inverse case", func() {
  428. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(`
  429. create_repo="创建了仓库 <a href=\"%s\">%s</a>"`))
  430. So(err, ShouldBeNil)
  431. So(f, ShouldNotBeNil)
  432. So(f.Section("").Key("create_repo").String(), ShouldEqual, `"创建了仓库 <a href=\"%s\">%s</a>"`)
  433. })
  434. })
  435. Convey("Unescape comment symbols inside value", func() {
  436. f, err := ini.LoadSources(ini.LoadOptions{
  437. AllowPythonMultilineValues: true,
  438. IgnoreInlineComment: true,
  439. UnescapeValueCommentSymbols: true,
  440. }, []byte(`
  441. key = test value <span style="color: %s\; background: %s">more text</span>
  442. `))
  443. So(err, ShouldBeNil)
  444. So(f, ShouldNotBeNil)
  445. So(f.Section("").Key("key").String(), ShouldEqual, `test value <span style="color: %s; background: %s">more text</span>`)
  446. })
  447. Convey("Can parse small python-compatible INI files", func() {
  448. f, err := ini.LoadSources(ini.LoadOptions{
  449. AllowPythonMultilineValues: true,
  450. Insensitive: true,
  451. UnparseableSections: []string{"core_lesson", "comments"},
  452. }, []byte(`
  453. [long]
  454. long_rsa_private_key = -----BEGIN RSA PRIVATE KEY-----
  455. foo
  456. bar
  457. foobar
  458. barfoo
  459. -----END RSA PRIVATE KEY-----
  460. multiline_list =
  461. first
  462. second
  463. third
  464. `))
  465. So(err, ShouldBeNil)
  466. So(f, ShouldNotBeNil)
  467. So(f.Section("long").Key("long_rsa_private_key").String(), ShouldEqual, "-----BEGIN RSA PRIVATE KEY-----\nfoo\nbar\nfoobar\nbarfoo\n-----END RSA PRIVATE KEY-----")
  468. So(f.Section("long").Key("multiline_list").String(), ShouldEqual, "\nfirst\nsecond\nthird")
  469. })
  470. Convey("Can parse big python-compatible INI files", func() {
  471. f, err := ini.LoadSources(ini.LoadOptions{
  472. AllowPythonMultilineValues: true,
  473. Insensitive: true,
  474. UnparseableSections: []string{"core_lesson", "comments"},
  475. }, []byte(`
  476. [long]
  477. long_rsa_private_key = -----BEGIN RSA PRIVATE KEY-----
  478. 1foo
  479. 2bar
  480. 3foobar
  481. 4barfoo
  482. 5foo
  483. 6bar
  484. 7foobar
  485. 8barfoo
  486. 9foo
  487. 10bar
  488. 11foobar
  489. 12barfoo
  490. 13foo
  491. 14bar
  492. 15foobar
  493. 16barfoo
  494. 17foo
  495. 18bar
  496. 19foobar
  497. 20barfoo
  498. 21foo
  499. 22bar
  500. 23foobar
  501. 24barfoo
  502. 25foo
  503. 26bar
  504. 27foobar
  505. 28barfoo
  506. 29foo
  507. 30bar
  508. 31foobar
  509. 32barfoo
  510. 33foo
  511. 34bar
  512. 35foobar
  513. 36barfoo
  514. 37foo
  515. 38bar
  516. 39foobar
  517. 40barfoo
  518. 41foo
  519. 42bar
  520. 43foobar
  521. 44barfoo
  522. 45foo
  523. 46bar
  524. 47foobar
  525. 48barfoo
  526. 49foo
  527. 50bar
  528. 51foobar
  529. 52barfoo
  530. 53foo
  531. 54bar
  532. 55foobar
  533. 56barfoo
  534. 57foo
  535. 58bar
  536. 59foobar
  537. 60barfoo
  538. 61foo
  539. 62bar
  540. 63foobar
  541. 64barfoo
  542. 65foo
  543. 66bar
  544. 67foobar
  545. 68barfoo
  546. 69foo
  547. 70bar
  548. 71foobar
  549. 72barfoo
  550. 73foo
  551. 74bar
  552. 75foobar
  553. 76barfoo
  554. 77foo
  555. 78bar
  556. 79foobar
  557. 80barfoo
  558. 81foo
  559. 82bar
  560. 83foobar
  561. 84barfoo
  562. 85foo
  563. 86bar
  564. 87foobar
  565. 88barfoo
  566. 89foo
  567. 90bar
  568. 91foobar
  569. 92barfoo
  570. 93foo
  571. 94bar
  572. 95foobar
  573. 96barfoo
  574. -----END RSA PRIVATE KEY-----
  575. `))
  576. So(err, ShouldBeNil)
  577. So(f, ShouldNotBeNil)
  578. So(f.Section("long").Key("long_rsa_private_key").String(), ShouldEqual, `-----BEGIN RSA PRIVATE KEY-----
  579. 1foo
  580. 2bar
  581. 3foobar
  582. 4barfoo
  583. 5foo
  584. 6bar
  585. 7foobar
  586. 8barfoo
  587. 9foo
  588. 10bar
  589. 11foobar
  590. 12barfoo
  591. 13foo
  592. 14bar
  593. 15foobar
  594. 16barfoo
  595. 17foo
  596. 18bar
  597. 19foobar
  598. 20barfoo
  599. 21foo
  600. 22bar
  601. 23foobar
  602. 24barfoo
  603. 25foo
  604. 26bar
  605. 27foobar
  606. 28barfoo
  607. 29foo
  608. 30bar
  609. 31foobar
  610. 32barfoo
  611. 33foo
  612. 34bar
  613. 35foobar
  614. 36barfoo
  615. 37foo
  616. 38bar
  617. 39foobar
  618. 40barfoo
  619. 41foo
  620. 42bar
  621. 43foobar
  622. 44barfoo
  623. 45foo
  624. 46bar
  625. 47foobar
  626. 48barfoo
  627. 49foo
  628. 50bar
  629. 51foobar
  630. 52barfoo
  631. 53foo
  632. 54bar
  633. 55foobar
  634. 56barfoo
  635. 57foo
  636. 58bar
  637. 59foobar
  638. 60barfoo
  639. 61foo
  640. 62bar
  641. 63foobar
  642. 64barfoo
  643. 65foo
  644. 66bar
  645. 67foobar
  646. 68barfoo
  647. 69foo
  648. 70bar
  649. 71foobar
  650. 72barfoo
  651. 73foo
  652. 74bar
  653. 75foobar
  654. 76barfoo
  655. 77foo
  656. 78bar
  657. 79foobar
  658. 80barfoo
  659. 81foo
  660. 82bar
  661. 83foobar
  662. 84barfoo
  663. 85foo
  664. 86bar
  665. 87foobar
  666. 88barfoo
  667. 89foo
  668. 90bar
  669. 91foobar
  670. 92barfoo
  671. 93foo
  672. 94bar
  673. 95foobar
  674. 96barfoo
  675. -----END RSA PRIVATE KEY-----`)
  676. })
  677. Convey("Allow unparsable sections", func() {
  678. f, err := ini.LoadSources(ini.LoadOptions{
  679. AllowPythonMultilineValues: true,
  680. Insensitive: true,
  681. UnparseableSections: []string{"core_lesson", "comments"},
  682. }, []byte(`
  683. Lesson_Location = 87
  684. Lesson_Status = C
  685. Score = 3
  686. Time = 00:02:30
  687. [CORE_LESSON]
  688. my lesson state data – 1111111111111111111000000000000000001110000
  689. 111111111111111111100000000000111000000000 – end my lesson state data
  690. [COMMENTS]
  691. <1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`))
  692. So(err, ShouldBeNil)
  693. So(f, ShouldNotBeNil)
  694. So(f.Section("").Key("score").String(), ShouldEqual, "3")
  695. So(f.Section("").Body(), ShouldBeEmpty)
  696. So(f.Section("core_lesson").Body(), ShouldEqual, `my lesson state data – 1111111111111111111000000000000000001110000
  697. 111111111111111111100000000000111000000000 – end my lesson state data`)
  698. So(f.Section("comments").Body(), ShouldEqual, `<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`)
  699. Convey("Write out", func() {
  700. var buf bytes.Buffer
  701. _, err := f.WriteTo(&buf)
  702. So(err, ShouldBeNil)
  703. So(buf.String(), ShouldEqual, `lesson_location = 87
  704. lesson_status = C
  705. score = 3
  706. time = 00:02:30
  707. [core_lesson]
  708. my lesson state data – 1111111111111111111000000000000000001110000
  709. 111111111111111111100000000000111000000000 – end my lesson state data
  710. [comments]
  711. <1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>
  712. `)
  713. })
  714. Convey("Inverse case", func() {
  715. _, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: true}, []byte(`
  716. [CORE_LESSON]
  717. my lesson state data – 1111111111111111111000000000000000001110000
  718. 111111111111111111100000000000111000000000 – end my lesson state data`))
  719. So(err, ShouldNotBeNil)
  720. })
  721. })
  722. Convey("And false `SpaceBeforeInlineComment`", func() {
  723. Convey("Can't parse INI files containing `#` or `;` in value", func() {
  724. f, err := ini.LoadSources(
  725. ini.LoadOptions{AllowPythonMultilineValues: false, SpaceBeforeInlineComment: false},
  726. []byte(`
  727. [author]
  728. NAME = U#n#k#n#w#o#n
  729. GITHUB = U;n;k;n;w;o;n
  730. `))
  731. So(err, ShouldBeNil)
  732. So(f, ShouldNotBeNil)
  733. sec := f.Section("author")
  734. nameValue := sec.Key("NAME").String()
  735. githubValue := sec.Key("GITHUB").String()
  736. So(nameValue, ShouldEqual, "U")
  737. So(githubValue, ShouldEqual, "U")
  738. })
  739. })
  740. Convey("And true `SpaceBeforeInlineComment`", func() {
  741. Convey("Can parse INI files containing `#` or `;` in value", func() {
  742. f, err := ini.LoadSources(
  743. ini.LoadOptions{AllowPythonMultilineValues: false, SpaceBeforeInlineComment: true},
  744. []byte(`
  745. [author]
  746. NAME = U#n#k#n#w#o#n
  747. GITHUB = U;n;k;n;w;o;n
  748. `))
  749. So(err, ShouldBeNil)
  750. So(f, ShouldNotBeNil)
  751. sec := f.Section("author")
  752. nameValue := sec.Key("NAME").String()
  753. githubValue := sec.Key("GITHUB").String()
  754. So(nameValue, ShouldEqual, "U#n#k#n#w#o#n")
  755. So(githubValue, ShouldEqual, "U;n;k;n;w;o;n")
  756. })
  757. })
  758. })
  759. Convey("with false `AllowPythonMultilineValues`", func() {
  760. Convey("Ignore nonexistent files", func() {
  761. f, err := ini.LoadSources(ini.LoadOptions{
  762. AllowPythonMultilineValues: false,
  763. Loose: true,
  764. }, notFoundConf, minimalConf)
  765. So(err, ShouldBeNil)
  766. So(f, ShouldNotBeNil)
  767. Convey("Inverse case", func() {
  768. _, err = ini.LoadSources(ini.LoadOptions{
  769. AllowPythonMultilineValues: false,
  770. }, notFoundConf)
  771. So(err, ShouldNotBeNil)
  772. })
  773. })
  774. Convey("Insensitive to section and key names", func() {
  775. f, err := ini.LoadSources(ini.LoadOptions{
  776. AllowPythonMultilineValues: false,
  777. Insensitive: true,
  778. }, minimalConf)
  779. So(err, ShouldBeNil)
  780. So(f, ShouldNotBeNil)
  781. So(f.Section("Author").Key("e-mail").String(), ShouldEqual, "u@gogs.io")
  782. Convey("Write out", func() {
  783. var buf bytes.Buffer
  784. _, err := f.WriteTo(&buf)
  785. So(err, ShouldBeNil)
  786. So(buf.String(), ShouldEqual, `[author]
  787. e-mail = u@gogs.io
  788. `)
  789. })
  790. Convey("Inverse case", func() {
  791. f, err := ini.LoadSources(ini.LoadOptions{
  792. AllowPythonMultilineValues: false,
  793. }, minimalConf)
  794. So(err, ShouldBeNil)
  795. So(f, ShouldNotBeNil)
  796. So(f.Section("Author").Key("e-mail").String(), ShouldBeEmpty)
  797. })
  798. })
  799. Convey("Ignore continuation lines", func() {
  800. f, err := ini.LoadSources(ini.LoadOptions{
  801. AllowPythonMultilineValues: false,
  802. IgnoreContinuation: true,
  803. }, []byte(`
  804. key1=a\b\
  805. key2=c\d\
  806. key3=value`))
  807. So(err, ShouldBeNil)
  808. So(f, ShouldNotBeNil)
  809. So(f.Section("").Key("key1").String(), ShouldEqual, `a\b\`)
  810. So(f.Section("").Key("key2").String(), ShouldEqual, `c\d\`)
  811. So(f.Section("").Key("key3").String(), ShouldEqual, "value")
  812. Convey("Inverse case", func() {
  813. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(`
  814. key1=a\b\
  815. key2=c\d\`))
  816. So(err, ShouldBeNil)
  817. So(f, ShouldNotBeNil)
  818. So(f.Section("").Key("key1").String(), ShouldEqual, `a\bkey2=c\d`)
  819. })
  820. })
  821. Convey("Ignore inline comments", func() {
  822. f, err := ini.LoadSources(ini.LoadOptions{
  823. AllowPythonMultilineValues: false,
  824. IgnoreInlineComment: true,
  825. }, []byte(`
  826. key1=value ;comment
  827. key2=value2 #comment2
  828. key3=val#ue #comment3`))
  829. So(err, ShouldBeNil)
  830. So(f, ShouldNotBeNil)
  831. So(f.Section("").Key("key1").String(), ShouldEqual, `value ;comment`)
  832. So(f.Section("").Key("key2").String(), ShouldEqual, `value2 #comment2`)
  833. So(f.Section("").Key("key3").String(), ShouldEqual, `val#ue #comment3`)
  834. Convey("Inverse case", func() {
  835. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(`
  836. key1=value ;comment
  837. key2=value2 #comment2`))
  838. So(err, ShouldBeNil)
  839. So(f, ShouldNotBeNil)
  840. So(f.Section("").Key("key1").String(), ShouldEqual, `value`)
  841. So(f.Section("").Key("key1").Comment, ShouldEqual, `;comment`)
  842. So(f.Section("").Key("key2").String(), ShouldEqual, `value2`)
  843. So(f.Section("").Key("key2").Comment, ShouldEqual, `#comment2`)
  844. })
  845. })
  846. Convey("Allow boolean type keys", func() {
  847. f, err := ini.LoadSources(ini.LoadOptions{
  848. AllowPythonMultilineValues: false,
  849. AllowBooleanKeys: true,
  850. }, []byte(`
  851. key1=hello
  852. #key2
  853. key3`))
  854. So(err, ShouldBeNil)
  855. So(f, ShouldNotBeNil)
  856. So(f.Section("").KeyStrings(), ShouldResemble, []string{"key1", "key3"})
  857. So(f.Section("").Key("key3").MustBool(false), ShouldBeTrue)
  858. Convey("Write out", func() {
  859. var buf bytes.Buffer
  860. _, err := f.WriteTo(&buf)
  861. So(err, ShouldBeNil)
  862. So(buf.String(), ShouldEqual, `key1 = hello
  863. # key2
  864. key3
  865. `)
  866. })
  867. Convey("Inverse case", func() {
  868. _, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(`
  869. key1=hello
  870. #key2
  871. key3`))
  872. So(err, ShouldNotBeNil)
  873. })
  874. })
  875. Convey("Allow shadow keys", func() {
  876. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false, AllowShadows: true}, []byte(`
  877. [remote "origin"]
  878. url = https://github.com/Antergone/test1.git
  879. url = https://github.com/Antergone/test2.git
  880. fetch = +refs/heads/*:refs/remotes/origin/*`))
  881. So(err, ShouldBeNil)
  882. So(f, ShouldNotBeNil)
  883. So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test1.git")
  884. So(f.Section(`remote "origin"`).Key("url").ValueWithShadows(), ShouldResemble, []string{
  885. "https://github.com/Antergone/test1.git",
  886. "https://github.com/Antergone/test2.git",
  887. })
  888. So(f.Section(`remote "origin"`).Key("fetch").String(), ShouldEqual, "+refs/heads/*:refs/remotes/origin/*")
  889. Convey("Write out", func() {
  890. var buf bytes.Buffer
  891. _, err := f.WriteTo(&buf)
  892. So(err, ShouldBeNil)
  893. So(buf.String(), ShouldEqual, `[remote "origin"]
  894. url = https://github.com/Antergone/test1.git
  895. url = https://github.com/Antergone/test2.git
  896. fetch = +refs/heads/*:refs/remotes/origin/*
  897. `)
  898. })
  899. Convey("Inverse case", func() {
  900. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(`
  901. [remote "origin"]
  902. url = https://github.com/Antergone/test1.git
  903. url = https://github.com/Antergone/test2.git`))
  904. So(err, ShouldBeNil)
  905. So(f, ShouldNotBeNil)
  906. So(f.Section(`remote "origin"`).Key("url").String(), ShouldEqual, "https://github.com/Antergone/test2.git")
  907. })
  908. })
  909. Convey("Unescape double quotes inside value", func() {
  910. f, err := ini.LoadSources(ini.LoadOptions{
  911. AllowPythonMultilineValues: false,
  912. UnescapeValueDoubleQuotes: true,
  913. }, []byte(`
  914. create_repo="创建了仓库 <a href=\"%s\">%s</a>"`))
  915. So(err, ShouldBeNil)
  916. So(f, ShouldNotBeNil)
  917. So(f.Section("").Key("create_repo").String(), ShouldEqual, `创建了仓库 <a href="%s">%s</a>`)
  918. Convey("Inverse case", func() {
  919. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(`
  920. create_repo="创建了仓库 <a href=\"%s\">%s</a>"`))
  921. So(err, ShouldBeNil)
  922. So(f, ShouldNotBeNil)
  923. So(f.Section("").Key("create_repo").String(), ShouldEqual, `"创建了仓库 <a href=\"%s\">%s</a>"`)
  924. })
  925. })
  926. Convey("Unescape comment symbols inside value", func() {
  927. f, err := ini.LoadSources(ini.LoadOptions{
  928. AllowPythonMultilineValues: false,
  929. IgnoreInlineComment: true,
  930. UnescapeValueCommentSymbols: true,
  931. }, []byte(`
  932. key = test value <span style="color: %s\; background: %s">more text</span>
  933. `))
  934. So(err, ShouldBeNil)
  935. So(f, ShouldNotBeNil)
  936. So(f.Section("").Key("key").String(), ShouldEqual, `test value <span style="color: %s; background: %s">more text</span>`)
  937. })
  938. Convey("Can't parse small python-compatible INI files", func() {
  939. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(`
  940. [long]
  941. long_rsa_private_key = -----BEGIN RSA PRIVATE KEY-----
  942. foo
  943. bar
  944. foobar
  945. barfoo
  946. -----END RSA PRIVATE KEY-----
  947. `))
  948. So(err, ShouldNotBeNil)
  949. So(f, ShouldBeNil)
  950. So(err.Error(), ShouldEqual, "key-value delimiter not found: foo\n")
  951. })
  952. Convey("Can't parse big python-compatible INI files", func() {
  953. f, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(`
  954. [long]
  955. long_rsa_private_key = -----BEGIN RSA PRIVATE KEY-----
  956. 1foo
  957. 2bar
  958. 3foobar
  959. 4barfoo
  960. 5foo
  961. 6bar
  962. 7foobar
  963. 8barfoo
  964. 9foo
  965. 10bar
  966. 11foobar
  967. 12barfoo
  968. 13foo
  969. 14bar
  970. 15foobar
  971. 16barfoo
  972. 17foo
  973. 18bar
  974. 19foobar
  975. 20barfoo
  976. 21foo
  977. 22bar
  978. 23foobar
  979. 24barfoo
  980. 25foo
  981. 26bar
  982. 27foobar
  983. 28barfoo
  984. 29foo
  985. 30bar
  986. 31foobar
  987. 32barfoo
  988. 33foo
  989. 34bar
  990. 35foobar
  991. 36barfoo
  992. 37foo
  993. 38bar
  994. 39foobar
  995. 40barfoo
  996. 41foo
  997. 42bar
  998. 43foobar
  999. 44barfoo
  1000. 45foo
  1001. 46bar
  1002. 47foobar
  1003. 48barfoo
  1004. 49foo
  1005. 50bar
  1006. 51foobar
  1007. 52barfoo
  1008. 53foo
  1009. 54bar
  1010. 55foobar
  1011. 56barfoo
  1012. 57foo
  1013. 58bar
  1014. 59foobar
  1015. 60barfoo
  1016. 61foo
  1017. 62bar
  1018. 63foobar
  1019. 64barfoo
  1020. 65foo
  1021. 66bar
  1022. 67foobar
  1023. 68barfoo
  1024. 69foo
  1025. 70bar
  1026. 71foobar
  1027. 72barfoo
  1028. 73foo
  1029. 74bar
  1030. 75foobar
  1031. 76barfoo
  1032. 77foo
  1033. 78bar
  1034. 79foobar
  1035. 80barfoo
  1036. 81foo
  1037. 82bar
  1038. 83foobar
  1039. 84barfoo
  1040. 85foo
  1041. 86bar
  1042. 87foobar
  1043. 88barfoo
  1044. 89foo
  1045. 90bar
  1046. 91foobar
  1047. 92barfoo
  1048. 93foo
  1049. 94bar
  1050. 95foobar
  1051. 96barfoo
  1052. -----END RSA PRIVATE KEY-----
  1053. `))
  1054. So(err, ShouldNotBeNil)
  1055. So(f, ShouldBeNil)
  1056. So(err.Error(), ShouldEqual, "key-value delimiter not found: 1foo\n")
  1057. })
  1058. Convey("Allow unparsable sections", func() {
  1059. f, err := ini.LoadSources(ini.LoadOptions{
  1060. AllowPythonMultilineValues: false,
  1061. Insensitive: true,
  1062. UnparseableSections: []string{"core_lesson", "comments"},
  1063. }, []byte(`
  1064. Lesson_Location = 87
  1065. Lesson_Status = C
  1066. Score = 3
  1067. Time = 00:02:30
  1068. [CORE_LESSON]
  1069. my lesson state data – 1111111111111111111000000000000000001110000
  1070. 111111111111111111100000000000111000000000 – end my lesson state data
  1071. [COMMENTS]
  1072. <1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`))
  1073. So(err, ShouldBeNil)
  1074. So(f, ShouldNotBeNil)
  1075. So(f.Section("").Key("score").String(), ShouldEqual, "3")
  1076. So(f.Section("").Body(), ShouldBeEmpty)
  1077. So(f.Section("core_lesson").Body(), ShouldEqual, `my lesson state data – 1111111111111111111000000000000000001110000
  1078. 111111111111111111100000000000111000000000 – end my lesson state data`)
  1079. So(f.Section("comments").Body(), ShouldEqual, `<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>`)
  1080. Convey("Write out", func() {
  1081. var buf bytes.Buffer
  1082. _, err := f.WriteTo(&buf)
  1083. So(err, ShouldBeNil)
  1084. So(buf.String(), ShouldEqual, `lesson_location = 87
  1085. lesson_status = C
  1086. score = 3
  1087. time = 00:02:30
  1088. [core_lesson]
  1089. my lesson state data – 1111111111111111111000000000000000001110000
  1090. 111111111111111111100000000000111000000000 – end my lesson state data
  1091. [comments]
  1092. <1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>
  1093. `)
  1094. })
  1095. Convey("Inverse case", func() {
  1096. _, err := ini.LoadSources(ini.LoadOptions{AllowPythonMultilineValues: false}, []byte(`
  1097. [CORE_LESSON]
  1098. my lesson state data – 1111111111111111111000000000000000001110000
  1099. 111111111111111111100000000000111000000000 – end my lesson state data`))
  1100. So(err, ShouldNotBeNil)
  1101. })
  1102. })
  1103. Convey("And false `SpaceBeforeInlineComment`", func() {
  1104. Convey("Can't parse INI files containing `#` or `;` in value", func() {
  1105. f, err := ini.LoadSources(
  1106. ini.LoadOptions{AllowPythonMultilineValues: true, SpaceBeforeInlineComment: false},
  1107. []byte(`
  1108. [author]
  1109. NAME = U#n#k#n#w#o#n
  1110. GITHUB = U;n;k;n;w;o;n
  1111. `))
  1112. So(err, ShouldBeNil)
  1113. So(f, ShouldNotBeNil)
  1114. sec := f.Section("author")
  1115. nameValue := sec.Key("NAME").String()
  1116. githubValue := sec.Key("GITHUB").String()
  1117. So(nameValue, ShouldEqual, "U")
  1118. So(githubValue, ShouldEqual, "U")
  1119. })
  1120. })
  1121. Convey("And true `SpaceBeforeInlineComment`", func() {
  1122. Convey("Can parse INI files containing `#` or `;` in value", func() {
  1123. f, err := ini.LoadSources(
  1124. ini.LoadOptions{AllowPythonMultilineValues: true, SpaceBeforeInlineComment: true},
  1125. []byte(`
  1126. [author]
  1127. NAME = U#n#k#n#w#o#n
  1128. GITHUB = U;n;k;n;w;o;n
  1129. `))
  1130. So(err, ShouldBeNil)
  1131. So(f, ShouldNotBeNil)
  1132. sec := f.Section("author")
  1133. nameValue := sec.Key("NAME").String()
  1134. githubValue := sec.Key("GITHUB").String()
  1135. So(nameValue, ShouldEqual, "U#n#k#n#w#o#n")
  1136. So(githubValue, ShouldEqual, "U;n;k;n;w;o;n")
  1137. })
  1138. })
  1139. })
  1140. })
  1141. }
  1142. func Test_KeyValueDelimiters(t *testing.T) {
  1143. Convey("Custom key-value delimiters", t, func() {
  1144. f, err := ini.LoadSources(ini.LoadOptions{
  1145. KeyValueDelimiters: "?!",
  1146. }, []byte(`
  1147. [section]
  1148. key1?value1
  1149. key2!value2
  1150. `))
  1151. So(err, ShouldBeNil)
  1152. So(f, ShouldNotBeNil)
  1153. So(f.Section("section").Key("key1").String(), ShouldEqual, "value1")
  1154. So(f.Section("section").Key("key2").String(), ShouldEqual, "value2")
  1155. })
  1156. }
  1157. func Test_PreserveSurroundedQuote(t *testing.T) {
  1158. Convey("Preserve surrounded quote test", t, func() {
  1159. f, err := ini.LoadSources(ini.LoadOptions{
  1160. PreserveSurroundedQuote: true,
  1161. }, []byte(`
  1162. [section]
  1163. key1 = "value1"
  1164. key2 = value2
  1165. `))
  1166. So(err, ShouldBeNil)
  1167. So(f, ShouldNotBeNil)
  1168. So(f.Section("section").Key("key1").String(), ShouldEqual, "\"value1\"")
  1169. So(f.Section("section").Key("key2").String(), ShouldEqual, "value2")
  1170. })
  1171. Convey("Preserve surrounded quote test inverse test", t, func() {
  1172. f, err := ini.LoadSources(ini.LoadOptions{
  1173. PreserveSurroundedQuote: false,
  1174. }, []byte(`
  1175. [section]
  1176. key1 = "value1"
  1177. key2 = value2
  1178. `))
  1179. So(err, ShouldBeNil)
  1180. So(f, ShouldNotBeNil)
  1181. So(f.Section("section").Key("key1").String(), ShouldEqual, "value1")
  1182. So(f.Section("section").Key("key2").String(), ShouldEqual, "value2")
  1183. })
  1184. }