1// Copyright 2017 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 15package ini_test 16 17import ( 18 "bytes" 19 "io/ioutil" 20 "testing" 21 22 . "github.com/smartystreets/goconvey/convey" 23 "gopkg.in/ini.v1" 24) 25 26func TestEmpty(t *testing.T) { 27 Convey("Create an empty object", t, func() { 28 f := ini.Empty() 29 So(f, ShouldNotBeNil) 30 31 // Should only have the default section 32 So(len(f.Sections()), ShouldEqual, 1) 33 34 // Default section should not contain any key 35 So(len(f.Section("").Keys()), ShouldBeZeroValue) 36 }) 37} 38 39func TestFile_NewSection(t *testing.T) { 40 Convey("Create a new section", t, func() { 41 f := ini.Empty() 42 So(f, ShouldNotBeNil) 43 44 sec, err := f.NewSection("author") 45 So(err, ShouldBeNil) 46 So(sec, ShouldNotBeNil) 47 So(sec.Name(), ShouldEqual, "author") 48 49 So(f.SectionStrings(), ShouldResemble, []string{ini.DefaultSection, "author"}) 50 51 Convey("With duplicated name", func() { 52 sec, err := f.NewSection("author") 53 So(err, ShouldBeNil) 54 So(sec, ShouldNotBeNil) 55 56 // Does nothing if section already exists 57 So(f.SectionStrings(), ShouldResemble, []string{ini.DefaultSection, "author"}) 58 }) 59 60 Convey("With empty string", func() { 61 _, err := f.NewSection("") 62 So(err, ShouldNotBeNil) 63 }) 64 }) 65} 66 67func TestFile_NewRawSection(t *testing.T) { 68 Convey("Create a new raw section", t, func() { 69 f := ini.Empty() 70 So(f, ShouldNotBeNil) 71 72 sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000 73111111111111111111100000000000111000000000`) 74 So(err, ShouldBeNil) 75 So(sec, ShouldNotBeNil) 76 So(sec.Name(), ShouldEqual, "comments") 77 78 So(f.SectionStrings(), ShouldResemble, []string{ini.DefaultSection, "comments"}) 79 So(f.Section("comments").Body(), ShouldEqual, `1111111111111111111000000000000000001110000 80111111111111111111100000000000111000000000`) 81 82 Convey("With duplicated name", func() { 83 sec, err := f.NewRawSection("comments", `1111111111111111111000000000000000001110000`) 84 So(err, ShouldBeNil) 85 So(sec, ShouldNotBeNil) 86 So(f.SectionStrings(), ShouldResemble, []string{ini.DefaultSection, "comments"}) 87 88 // Overwrite previous existed section 89 So(f.Section("comments").Body(), ShouldEqual, `1111111111111111111000000000000000001110000`) 90 }) 91 92 Convey("With empty string", func() { 93 _, err := f.NewRawSection("", "") 94 So(err, ShouldNotBeNil) 95 }) 96 }) 97} 98 99func TestFile_NewSections(t *testing.T) { 100 Convey("Create new sections", t, func() { 101 f := ini.Empty() 102 So(f, ShouldNotBeNil) 103 104 So(f.NewSections("package", "author"), ShouldBeNil) 105 So(f.SectionStrings(), ShouldResemble, []string{ini.DefaultSection, "package", "author"}) 106 107 Convey("With duplicated name", func() { 108 So(f.NewSections("author", "features"), ShouldBeNil) 109 110 // Ignore section already exists 111 So(f.SectionStrings(), ShouldResemble, []string{ini.DefaultSection, "package", "author", "features"}) 112 }) 113 114 Convey("With empty string", func() { 115 So(f.NewSections("", ""), ShouldNotBeNil) 116 }) 117 }) 118} 119 120func TestFile_GetSection(t *testing.T) { 121 Convey("Get a section", t, func() { 122 f, err := ini.Load(fullConf) 123 So(err, ShouldBeNil) 124 So(f, ShouldNotBeNil) 125 126 sec, err := f.GetSection("author") 127 So(err, ShouldBeNil) 128 So(sec, ShouldNotBeNil) 129 So(sec.Name(), ShouldEqual, "author") 130 131 Convey("Section not exists", func() { 132 _, err := f.GetSection("404") 133 So(err, ShouldNotBeNil) 134 }) 135 }) 136} 137 138func TestFile_Section(t *testing.T) { 139 Convey("Get a section", t, func() { 140 f, err := ini.Load(fullConf) 141 So(err, ShouldBeNil) 142 So(f, ShouldNotBeNil) 143 144 sec := f.Section("author") 145 So(sec, ShouldNotBeNil) 146 So(sec.Name(), ShouldEqual, "author") 147 148 Convey("Section not exists", func() { 149 sec := f.Section("404") 150 So(sec, ShouldNotBeNil) 151 So(sec.Name(), ShouldEqual, "404") 152 }) 153 }) 154 155 Convey("Get default section in lower case with insensitive load", t, func() { 156 f, err := ini.InsensitiveLoad([]byte(` 157[default] 158NAME = ini 159VERSION = v1`)) 160 So(err, ShouldBeNil) 161 So(f, ShouldNotBeNil) 162 163 So(f.Section("").Key("name").String(), ShouldEqual, "ini") 164 So(f.Section("").Key("version").String(), ShouldEqual, "v1") 165 }) 166} 167 168func TestFile_Sections(t *testing.T) { 169 Convey("Get all sections", t, func() { 170 f, err := ini.Load(fullConf) 171 So(err, ShouldBeNil) 172 So(f, ShouldNotBeNil) 173 174 secs := f.Sections() 175 names := []string{ini.DefaultSection, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"} 176 So(len(secs), ShouldEqual, len(names)) 177 for i, name := range names { 178 So(secs[i].Name(), ShouldEqual, name) 179 } 180 }) 181} 182 183func TestFile_ChildSections(t *testing.T) { 184 Convey("Get child sections by parent name", t, func() { 185 f, err := ini.Load([]byte(` 186[node] 187[node.biz1] 188[node.biz2] 189[node.biz3] 190[node.bizN] 191`)) 192 So(err, ShouldBeNil) 193 So(f, ShouldNotBeNil) 194 195 children := f.ChildSections("node") 196 names := []string{"node.biz1", "node.biz2", "node.biz3", "node.bizN"} 197 So(len(children), ShouldEqual, len(names)) 198 for i, name := range names { 199 So(children[i].Name(), ShouldEqual, name) 200 } 201 }) 202} 203 204func TestFile_SectionStrings(t *testing.T) { 205 Convey("Get all section names", t, func() { 206 f, err := ini.Load(fullConf) 207 So(err, ShouldBeNil) 208 So(f, ShouldNotBeNil) 209 210 So(f.SectionStrings(), ShouldResemble, []string{ini.DefaultSection, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "string escapes", "advance"}) 211 }) 212} 213 214func TestFile_DeleteSection(t *testing.T) { 215 Convey("Delete a section", t, func() { 216 f := ini.Empty() 217 So(f, ShouldNotBeNil) 218 219 f.NewSections("author", "package", "features") 220 f.DeleteSection("features") 221 f.DeleteSection("") 222 So(f.SectionStrings(), ShouldResemble, []string{"author", "package"}) 223 }) 224} 225 226func TestFile_Append(t *testing.T) { 227 Convey("Append a data source", t, func() { 228 f := ini.Empty() 229 So(f, ShouldNotBeNil) 230 231 So(f.Append(minimalConf, []byte(` 232[author] 233NAME = Unknwon`)), ShouldBeNil) 234 235 Convey("With bad input", func() { 236 So(f.Append(123), ShouldNotBeNil) 237 So(f.Append(minimalConf, 123), ShouldNotBeNil) 238 }) 239 }) 240} 241 242func TestFile_WriteTo(t *testing.T) { 243 Convey("Write content to somewhere", t, func() { 244 f, err := ini.Load(fullConf) 245 So(err, ShouldBeNil) 246 So(f, ShouldNotBeNil) 247 248 f.Section("author").Comment = `Information about package author 249# Bio can be written in multiple lines.` 250 f.Section("author").Key("NAME").Comment = "This is author name" 251 f.Section("note").NewBooleanKey("boolean_key") 252 f.Section("note").NewKey("more", "notes") 253 254 var buf bytes.Buffer 255 _, err = f.WriteTo(&buf) 256 So(err, ShouldBeNil) 257 258 golden := "testdata/TestFile_WriteTo.golden" 259 if *update { 260 ioutil.WriteFile(golden, buf.Bytes(), 0644) 261 } 262 263 expected, err := ioutil.ReadFile(golden) 264 So(err, ShouldBeNil) 265 So(buf.String(), ShouldEqual, string(expected)) 266 }) 267 268 Convey("Support multiline comments", t, func() { 269 f, err := ini.Load([]byte(` 270# 271# general.domain 272# 273# Domain name of XX system. 274domain = mydomain.com 275`)) 276 So(err, ShouldBeNil) 277 278 f.Section("").Key("test").Comment = "Multiline\nComment" 279 280 var buf bytes.Buffer 281 _, err = f.WriteTo(&buf) 282 So(err, ShouldBeNil) 283 284 So(buf.String(), ShouldEqual, `# 285# general.domain 286# 287# Domain name of XX system. 288domain = mydomain.com 289; Multiline 290; Comment 291test = 292 293`) 294 295 }) 296} 297 298func TestFile_SaveTo(t *testing.T) { 299 Convey("Write content to somewhere", t, func() { 300 f, err := ini.Load(fullConf) 301 So(err, ShouldBeNil) 302 So(f, ShouldNotBeNil) 303 304 So(f.SaveTo("testdata/conf_out.ini"), ShouldBeNil) 305 So(f.SaveToIndent("testdata/conf_out.ini", "\t"), ShouldBeNil) 306 }) 307} 308 309// Inspired by https://github.com/go-ini/ini/issues/207 310func TestReloadAfterShadowLoad(t *testing.T) { 311 Convey("Reload file after ShadowLoad", t, func() { 312 f, err := ini.ShadowLoad([]byte(` 313[slice] 314v = 1 315v = 2 316v = 3 317`)) 318 So(err, ShouldBeNil) 319 So(f, ShouldNotBeNil) 320 321 So(f.Section("slice").Key("v").ValueWithShadows(), ShouldResemble, []string{"1", "2", "3"}) 322 323 So(f.Reload(), ShouldBeNil) 324 So(f.Section("slice").Key("v").ValueWithShadows(), ShouldResemble, []string{"1", "2", "3"}) 325 }) 326} 327