1
// Copyright 2014 Unknwon
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
7
// http://www.apache.org/licenses/LICENSE-2.0
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
23
. "github.com/smartystreets/goconvey/convey"
26
func Test_Key(t *testing.T) {
27
Convey("Test getting and setting values", t, func() {
28
cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini")
30
So(cfg, ShouldNotBeNil)
32
Convey("Get values in default section", func() {
33
sec := cfg.Section("")
34
So(sec, ShouldNotBeNil)
35
So(sec.Key("NAME").Value(), ShouldEqual, "ini")
36
So(sec.Key("NAME").String(), ShouldEqual, "ini")
37
So(sec.Key("NAME").Validate(func(in string) string {
39
}), ShouldEqual, "ini")
40
So(sec.Key("NAME").Comment, ShouldEqual, "; Package name")
41
So(sec.Key("IMPORT_PATH").String(), ShouldEqual, "gopkg.in/ini.v1")
44
Convey("Get values in non-default section", func() {
45
sec := cfg.Section("author")
46
So(sec, ShouldNotBeNil)
47
So(sec.Key("NAME").String(), ShouldEqual, "Unknwon")
48
So(sec.Key("GITHUB").String(), ShouldEqual, "https://github.com/Unknwon")
50
sec = cfg.Section("package")
51
So(sec, ShouldNotBeNil)
52
So(sec.Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
55
Convey("Get auto-increment key names", func() {
56
keys := cfg.Section("features").Keys()
57
for i, k := range keys {
58
So(k.Name(), ShouldEqual, fmt.Sprintf("#%d", i+1))
62
Convey("Get overwrite value", func() {
63
So(cfg.Section("author").Key("E-MAIL").String(), ShouldEqual, "u@gogs.io")
66
Convey("Get sections", func() {
67
sections := cfg.Sections()
68
for i, name := range []string{DEFAULT_SECTION, "author", "package", "package.sub", "features", "types", "array", "note", "comments", "advance"} {
69
So(sections[i].Name(), ShouldEqual, name)
73
Convey("Get parent section value", func() {
74
So(cfg.Section("package.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
75
So(cfg.Section("package.fake.sub").Key("CLONE_URL").String(), ShouldEqual, "https://gopkg.in/ini.v1")
78
Convey("Get multiple line value", func() {
79
So(cfg.Section("author").Key("BIO").String(), ShouldEqual, "Gopher.\nCoding addict.\nGood man.\n")
82
Convey("Get values with type", func() {
83
sec := cfg.Section("types")
84
v1, err := sec.Key("BOOL").Bool()
88
v1, err = sec.Key("BOOL_FALSE").Bool()
92
v2, err := sec.Key("FLOAT64").Float64()
94
So(v2, ShouldEqual, 1.25)
96
v3, err := sec.Key("INT").Int()
98
So(v3, ShouldEqual, 10)
100
v4, err := sec.Key("INT").Int64()
102
So(v4, ShouldEqual, 10)
104
v5, err := sec.Key("UINT").Uint()
106
So(v5, ShouldEqual, 3)
108
v6, err := sec.Key("UINT").Uint64()
110
So(v6, ShouldEqual, 3)
112
t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
114
v7, err := sec.Key("TIME").Time()
116
So(v7.String(), ShouldEqual, t.String())
118
Convey("Must get values with type", func() {
119
So(sec.Key("STRING").MustString("404"), ShouldEqual, "str")
120
So(sec.Key("BOOL").MustBool(), ShouldBeTrue)
121
So(sec.Key("FLOAT64").MustFloat64(), ShouldEqual, 1.25)
122
So(sec.Key("INT").MustInt(), ShouldEqual, 10)
123
So(sec.Key("INT").MustInt64(), ShouldEqual, 10)
124
So(sec.Key("UINT").MustUint(), ShouldEqual, 3)
125
So(sec.Key("UINT").MustUint64(), ShouldEqual, 3)
126
So(sec.Key("TIME").MustTime().String(), ShouldEqual, t.String())
128
dur, err := time.ParseDuration("2h45m")
130
So(sec.Key("DURATION").MustDuration().Seconds(), ShouldEqual, dur.Seconds())
132
Convey("Must get values with default value", func() {
133
So(sec.Key("STRING_404").MustString("404"), ShouldEqual, "404")
134
So(sec.Key("BOOL_404").MustBool(true), ShouldBeTrue)
135
So(sec.Key("FLOAT64_404").MustFloat64(2.5), ShouldEqual, 2.5)
136
So(sec.Key("INT_404").MustInt(15), ShouldEqual, 15)
137
So(sec.Key("INT_404").MustInt64(15), ShouldEqual, 15)
138
So(sec.Key("UINT_404").MustUint(6), ShouldEqual, 6)
139
So(sec.Key("UINT_404").MustUint64(6), ShouldEqual, 6)
141
t, err := time.Parse(time.RFC3339, "2014-01-01T20:17:05Z")
143
So(sec.Key("TIME_404").MustTime(t).String(), ShouldEqual, t.String())
145
So(sec.Key("DURATION_404").MustDuration(dur).Seconds(), ShouldEqual, dur.Seconds())
150
Convey("Get value with candidates", func() {
151
sec := cfg.Section("types")
152
So(sec.Key("STRING").In("", []string{"str", "arr", "types"}), ShouldEqual, "str")
153
So(sec.Key("FLOAT64").InFloat64(0, []float64{1.25, 2.5, 3.75}), ShouldEqual, 1.25)
154
So(sec.Key("INT").InInt(0, []int{10, 20, 30}), ShouldEqual, 10)
155
So(sec.Key("INT").InInt64(0, []int64{10, 20, 30}), ShouldEqual, 10)
156
So(sec.Key("UINT").InUint(0, []uint{3, 6, 9}), ShouldEqual, 3)
157
So(sec.Key("UINT").InUint64(0, []uint64{3, 6, 9}), ShouldEqual, 3)
159
zt, err := time.Parse(time.RFC3339, "0001-01-01T01:00:00Z")
161
t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
163
So(sec.Key("TIME").InTime(zt, []time.Time{t, time.Now(), time.Now().Add(1 * time.Second)}).String(), ShouldEqual, t.String())
165
Convey("Get value with candidates and default value", func() {
166
So(sec.Key("STRING_404").In("str", []string{"str", "arr", "types"}), ShouldEqual, "str")
167
So(sec.Key("FLOAT64_404").InFloat64(1.25, []float64{1.25, 2.5, 3.75}), ShouldEqual, 1.25)
168
So(sec.Key("INT_404").InInt(10, []int{10, 20, 30}), ShouldEqual, 10)
169
So(sec.Key("INT64_404").InInt64(10, []int64{10, 20, 30}), ShouldEqual, 10)
170
So(sec.Key("UINT_404").InUint(3, []uint{3, 6, 9}), ShouldEqual, 3)
171
So(sec.Key("UINT_404").InUint64(3, []uint64{3, 6, 9}), ShouldEqual, 3)
172
So(sec.Key("TIME_404").InTime(t, []time.Time{time.Now(), time.Now(), time.Now().Add(1 * time.Second)}).String(), ShouldEqual, t.String())
176
Convey("Get values in range", func() {
177
sec := cfg.Section("types")
178
So(sec.Key("FLOAT64").RangeFloat64(0, 1, 2), ShouldEqual, 1.25)
179
So(sec.Key("INT").RangeInt(0, 10, 20), ShouldEqual, 10)
180
So(sec.Key("INT").RangeInt64(0, 10, 20), ShouldEqual, 10)
182
minT, err := time.Parse(time.RFC3339, "0001-01-01T01:00:00Z")
184
midT, err := time.Parse(time.RFC3339, "2013-01-01T01:00:00Z")
186
maxT, err := time.Parse(time.RFC3339, "9999-01-01T01:00:00Z")
188
t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
190
So(sec.Key("TIME").RangeTime(t, minT, maxT).String(), ShouldEqual, t.String())
192
Convey("Get value in range with default value", func() {
193
So(sec.Key("FLOAT64").RangeFloat64(5, 0, 1), ShouldEqual, 5)
194
So(sec.Key("INT").RangeInt(7, 0, 5), ShouldEqual, 7)
195
So(sec.Key("INT").RangeInt64(7, 0, 5), ShouldEqual, 7)
196
So(sec.Key("TIME").RangeTime(t, minT, midT).String(), ShouldEqual, t.String())
200
Convey("Get values into slice", func() {
201
sec := cfg.Section("array")
202
So(strings.Join(sec.Key("STRINGS").Strings(","), ","), ShouldEqual, "en,zh,de")
203
So(len(sec.Key("STRINGS_404").Strings(",")), ShouldEqual, 0)
205
vals1 := sec.Key("FLOAT64S").Float64s(",")
206
float64sEqual(vals1, 1.1, 2.2, 3.3)
208
vals2 := sec.Key("INTS").Ints(",")
209
intsEqual(vals2, 1, 2, 3)
211
vals3 := sec.Key("INTS").Int64s(",")
212
int64sEqual(vals3, 1, 2, 3)
214
vals4 := sec.Key("UINTS").Uints(",")
215
uintsEqual(vals4, 1, 2, 3)
217
vals5 := sec.Key("UINTS").Uint64s(",")
218
uint64sEqual(vals5, 1, 2, 3)
220
t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
222
vals6 := sec.Key("TIMES").Times(",")
223
timesEqual(vals6, t, t, t)
226
Convey("Get valid values into slice", func() {
227
sec := cfg.Section("array")
228
vals1 := sec.Key("FLOAT64S").ValidFloat64s(",")
229
float64sEqual(vals1, 1.1, 2.2, 3.3)
231
vals2 := sec.Key("INTS").ValidInts(",")
232
intsEqual(vals2, 1, 2, 3)
234
vals3 := sec.Key("INTS").ValidInt64s(",")
235
int64sEqual(vals3, 1, 2, 3)
237
vals4 := sec.Key("UINTS").ValidUints(",")
238
uintsEqual(vals4, 1, 2, 3)
240
vals5 := sec.Key("UINTS").ValidUint64s(",")
241
uint64sEqual(vals5, 1, 2, 3)
243
t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
245
vals6 := sec.Key("TIMES").ValidTimes(",")
246
timesEqual(vals6, t, t, t)
249
Convey("Get values one type into slice of another type", func() {
250
sec := cfg.Section("array")
251
vals1 := sec.Key("STRINGS").ValidFloat64s(",")
252
So(vals1, ShouldBeEmpty)
254
vals2 := sec.Key("STRINGS").ValidInts(",")
255
So(vals2, ShouldBeEmpty)
257
vals3 := sec.Key("STRINGS").ValidInt64s(",")
258
So(vals3, ShouldBeEmpty)
260
vals4 := sec.Key("STRINGS").ValidUints(",")
261
So(vals4, ShouldBeEmpty)
263
vals5 := sec.Key("STRINGS").ValidUint64s(",")
264
So(vals5, ShouldBeEmpty)
266
vals6 := sec.Key("STRINGS").ValidTimes(",")
267
So(vals6, ShouldBeEmpty)
270
Convey("Get valid values into slice without errors", func() {
271
sec := cfg.Section("array")
272
vals1, err := sec.Key("FLOAT64S").StrictFloat64s(",")
274
float64sEqual(vals1, 1.1, 2.2, 3.3)
276
vals2, err := sec.Key("INTS").StrictInts(",")
278
intsEqual(vals2, 1, 2, 3)
280
vals3, err := sec.Key("INTS").StrictInt64s(",")
282
int64sEqual(vals3, 1, 2, 3)
284
vals4, err := sec.Key("UINTS").StrictUints(",")
286
uintsEqual(vals4, 1, 2, 3)
288
vals5, err := sec.Key("UINTS").StrictUint64s(",")
290
uint64sEqual(vals5, 1, 2, 3)
292
t, err := time.Parse(time.RFC3339, "2015-01-01T20:17:05Z")
294
vals6, err := sec.Key("TIMES").StrictTimes(",")
296
timesEqual(vals6, t, t, t)
299
Convey("Get invalid values into slice", func() {
300
sec := cfg.Section("array")
301
vals1, err := sec.Key("STRINGS").StrictFloat64s(",")
302
So(vals1, ShouldBeEmpty)
303
So(err, ShouldNotBeNil)
305
vals2, err := sec.Key("STRINGS").StrictInts(",")
306
So(vals2, ShouldBeEmpty)
307
So(err, ShouldNotBeNil)
309
vals3, err := sec.Key("STRINGS").StrictInt64s(",")
310
So(vals3, ShouldBeEmpty)
311
So(err, ShouldNotBeNil)
313
vals4, err := sec.Key("STRINGS").StrictUints(",")
314
So(vals4, ShouldBeEmpty)
315
So(err, ShouldNotBeNil)
317
vals5, err := sec.Key("STRINGS").StrictUint64s(",")
318
So(vals5, ShouldBeEmpty)
319
So(err, ShouldNotBeNil)
321
vals6, err := sec.Key("STRINGS").StrictTimes(",")
322
So(vals6, ShouldBeEmpty)
323
So(err, ShouldNotBeNil)
326
Convey("Get key hash", func() {
327
cfg.Section("").KeysHash()
330
Convey("Set key value", func() {
331
k := cfg.Section("author").Key("NAME")
333
So(k.String(), ShouldEqual, "无闻")
336
Convey("Get key strings", func() {
337
So(strings.Join(cfg.Section("types").KeyStrings(), ","), ShouldEqual, "STRING,BOOL,BOOL_FALSE,FLOAT64,INT,TIME,DURATION,UINT")
340
Convey("Delete a key", func() {
341
cfg.Section("package.sub").DeleteKey("UNUSED_KEY")
342
_, err := cfg.Section("package.sub").GetKey("UNUSED_KEY")
343
So(err, ShouldNotBeNil)
346
Convey("Has Key (backwards compatible)", func() {
347
sec := cfg.Section("package.sub")
348
haskey1 := sec.Haskey("UNUSED_KEY")
349
haskey2 := sec.Haskey("CLONE_URL")
350
haskey3 := sec.Haskey("CLONE_URL_NO")
351
So(haskey1, ShouldBeTrue)
352
So(haskey2, ShouldBeTrue)
353
So(haskey3, ShouldBeFalse)
356
Convey("Has Key", func() {
357
sec := cfg.Section("package.sub")
358
haskey1 := sec.HasKey("UNUSED_KEY")
359
haskey2 := sec.HasKey("CLONE_URL")
360
haskey3 := sec.HasKey("CLONE_URL_NO")
361
So(haskey1, ShouldBeTrue)
362
So(haskey2, ShouldBeTrue)
363
So(haskey3, ShouldBeFalse)
366
Convey("Has Value", func() {
367
sec := cfg.Section("author")
368
hasvalue1 := sec.HasValue("Unknwon")
369
hasvalue2 := sec.HasValue("doc")
370
So(hasvalue1, ShouldBeTrue)
371
So(hasvalue2, ShouldBeFalse)
375
Convey("Test getting and setting bad values", t, func() {
376
cfg, err := Load([]byte(_CONF_DATA), "testdata/conf.ini")
378
So(cfg, ShouldNotBeNil)
380
Convey("Create new key with empty name", func() {
381
k, err := cfg.Section("").NewKey("", "")
382
So(err, ShouldNotBeNil)
386
Convey("Create new section with empty name", func() {
387
s, err := cfg.NewSection("")
388
So(err, ShouldNotBeNil)
392
Convey("Create new sections with empty name", func() {
393
So(cfg.NewSections(""), ShouldNotBeNil)
396
Convey("Get section that not exists", func() {
397
s, err := cfg.GetSection("404")
398
So(err, ShouldNotBeNil)
401
s = cfg.Section("404")
402
So(s, ShouldNotBeNil)
406
Convey("Test key hash clone", t, func() {
407
cfg, err := Load([]byte(strings.Replace("network=tcp,addr=127.0.0.1:6379,db=4,pool_size=100,idle_timeout=180", ",", "\n", -1)))
409
for _, v := range cfg.Section("").KeysHash() {
410
So(len(v), ShouldBeGreaterThan, 0)
414
Convey("Key has empty value", t, func() {
417
cfg, err := Load([]byte(_conf))
419
So(cfg.Section("").Key("key1").Value(), ShouldBeEmpty)
423
func newTestFile(block bool) *File {
424
c, _ := Load([]byte(_CONF_DATA))
429
func Benchmark_Key_Value(b *testing.B) {
430
c := newTestFile(true)
431
for i := 0; i < b.N; i++ {
432
c.Section("").Key("NAME").Value()
436
func Benchmark_Key_Value_NonBlock(b *testing.B) {
437
c := newTestFile(false)
438
for i := 0; i < b.N; i++ {
439
c.Section("").Key("NAME").Value()
443
func Benchmark_Key_Value_ViaSection(b *testing.B) {
444
c := newTestFile(true)
446
for i := 0; i < b.N; i++ {
447
sec.Key("NAME").Value()
451
func Benchmark_Key_Value_ViaSection_NonBlock(b *testing.B) {
452
c := newTestFile(false)
454
for i := 0; i < b.N; i++ {
455
sec.Key("NAME").Value()
459
func Benchmark_Key_Value_Direct(b *testing.B) {
460
c := newTestFile(true)
461
key := c.Section("").Key("NAME")
462
for i := 0; i < b.N; i++ {
467
func Benchmark_Key_Value_Direct_NonBlock(b *testing.B) {
468
c := newTestFile(false)
469
key := c.Section("").Key("NAME")
470
for i := 0; i < b.N; i++ {
475
func Benchmark_Key_String(b *testing.B) {
476
c := newTestFile(true)
477
for i := 0; i < b.N; i++ {
478
_ = c.Section("").Key("NAME").String()
482
func Benchmark_Key_String_NonBlock(b *testing.B) {
483
c := newTestFile(false)
484
for i := 0; i < b.N; i++ {
485
_ = c.Section("").Key("NAME").String()
489
func Benchmark_Key_String_ViaSection(b *testing.B) {
490
c := newTestFile(true)
492
for i := 0; i < b.N; i++ {
493
_ = sec.Key("NAME").String()
497
func Benchmark_Key_String_ViaSection_NonBlock(b *testing.B) {
498
c := newTestFile(false)
500
for i := 0; i < b.N; i++ {
501
_ = sec.Key("NAME").String()
505
func Benchmark_Key_SetValue(b *testing.B) {
506
c := newTestFile(true)
507
for i := 0; i < b.N; i++ {
508
c.Section("").Key("NAME").SetValue("10")
512
func Benchmark_Key_SetValue_VisSection(b *testing.B) {
513
c := newTestFile(true)
515
for i := 0; i < b.N; i++ {
516
sec.Key("NAME").SetValue("10")