1 // Copyright 2017 Frank Schroeder. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
18 "github.com/magiconair/properties/assert"
21 var verbose = flag.Bool("verbose", false, "Verbose output")
24 ErrorHandler = PanicHandler
27 // ----------------------------------------------------------------------------
29 // define test cases in the form of
30 // {"input", "key1", "value1", "key2", "value2", ...}
31 var complexTests = [][]string{
33 {" key=value", "key", "value"}, // SPACE prefix
34 {"\fkey=value", "key", "value"}, // FF prefix
35 {"\tkey=value", "key", "value"}, // TAB prefix
36 {" \f\tkey=value", "key", "value"}, // mix prefix
39 {"key1=value1\nkey2=value2\n", "key1", "value1", "key2", "value2"},
40 {"key1=value1\rkey2=value2\r", "key1", "value1", "key2", "value2"},
41 {"key1=value1\r\nkey2=value2\r\n", "key1", "value1", "key2", "value2"},
44 {"\nkey=value\n", "key", "value"},
45 {"\rkey=value\r", "key", "value"},
46 {"\r\nkey=value\r\n", "key", "value"},
48 // escaped chars in key
49 {"k\\ ey = value", "k ey", "value"},
50 {"k\\:ey = value", "k:ey", "value"},
51 {"k\\=ey = value", "k=ey", "value"},
52 {"k\\fey = value", "k\fey", "value"},
53 {"k\\ney = value", "k\ney", "value"},
54 {"k\\rey = value", "k\rey", "value"},
55 {"k\\tey = value", "k\tey", "value"},
57 // escaped chars in value
58 {"key = v\\ alue", "key", "v alue"},
59 {"key = v\\:alue", "key", "v:alue"},
60 {"key = v\\=alue", "key", "v=alue"},
61 {"key = v\\falue", "key", "v\falue"},
62 {"key = v\\nalue", "key", "v\nalue"},
63 {"key = v\\ralue", "key", "v\ralue"},
64 {"key = v\\talue", "key", "v\talue"},
66 // silently dropped escape character
67 {"k\\zey = value", "kzey", "value"},
68 {"key = v\\zalue", "key", "vzalue"},
71 {"key\\u2318 = value", "key⌘", "value"},
72 {"k\\u2318ey = value", "k⌘ey", "value"},
73 {"key = value\\u2318", "key", "value⌘"},
74 {"key = valu\\u2318e", "key", "valu⌘e"},
77 {"key = valueA,\\\n valueB", "key", "valueA,valueB"}, // SPACE indent
78 {"key = valueA,\\\n\f\f\fvalueB", "key", "valueA,valueB"}, // FF indent
79 {"key = valueA,\\\n\t\t\tvalueB", "key", "valueA,valueB"}, // TAB indent
80 {"key = valueA,\\\n \f\tvalueB", "key", "valueA,valueB"}, // mix indent
83 {"# this is a comment\n! and so is this\nkey1=value1\nkey#2=value#2\n\nkey!3=value!3\n# and another one\n! and the final one", "key1", "value1", "key#2", "value#2", "key!3", "value!3"},
86 {"key=value\nkey2=${key}", "key", "value", "key2", "value"},
87 {"key=value\nkey2=aa${key}", "key", "value", "key2", "aavalue"},
88 {"key=value\nkey2=${key}bb", "key", "value", "key2", "valuebb"},
89 {"key=value\nkey2=aa${key}bb", "key", "value", "key2", "aavaluebb"},
90 {"key=value\nkey2=${key}\nkey3=${key2}", "key", "value", "key2", "value", "key3", "value"},
91 {"key=${USER}", "key", os.Getenv("USER")},
92 {"key=${USER}\nUSER=value", "key", "value", "USER", "value"},
95 // ----------------------------------------------------------------------------
97 var commentTests = []struct {
98 input, key, value string
101 {"key=value", "key", "value", nil},
102 {"#\nkey=value", "key", "value", []string{""}},
103 {"#comment\nkey=value", "key", "value", []string{"comment"}},
104 {"# comment\nkey=value", "key", "value", []string{"comment"}},
105 {"# comment\nkey=value", "key", "value", []string{"comment"}},
106 {"# comment\n\nkey=value", "key", "value", []string{"comment"}},
107 {"# comment1\n# comment2\nkey=value", "key", "value", []string{"comment1", "comment2"}},
108 {"# comment1\n\n# comment2\n\nkey=value", "key", "value", []string{"comment1", "comment2"}},
109 {"!comment\nkey=value", "key", "value", []string{"comment"}},
110 {"! comment\nkey=value", "key", "value", []string{"comment"}},
111 {"! comment\nkey=value", "key", "value", []string{"comment"}},
112 {"! comment\n\nkey=value", "key", "value", []string{"comment"}},
113 {"! comment1\n! comment2\nkey=value", "key", "value", []string{"comment1", "comment2"}},
114 {"! comment1\n\n! comment2\n\nkey=value", "key", "value", []string{"comment1", "comment2"}},
117 // ----------------------------------------------------------------------------
119 var errorTests = []struct {
123 {"key\\u1 = value", "invalid unicode literal"},
124 {"key\\u12 = value", "invalid unicode literal"},
125 {"key\\u123 = value", "invalid unicode literal"},
126 {"key\\u123g = value", "invalid unicode literal"},
127 {"key\\u123", "invalid unicode literal"},
129 // circular references
130 {"key=${key}", "circular reference"},
131 {"key1=${key2}\nkey2=${key1}", "circular reference"},
133 // malformed expressions
134 {"key=${ke", "malformed expression"},
135 {"key=valu${ke", "malformed expression"},
138 // ----------------------------------------------------------------------------
140 var writeTests = []struct {
141 input, output, encoding string
144 {"key = value", "key = value\n", "ISO-8859-1"},
145 {"key = value \\\n continued", "key = value continued\n", "ISO-8859-1"},
146 {"key⌘ = value", "key\\u2318 = value\n", "ISO-8859-1"},
147 {"ke\\ \\:y = value", "ke\\ \\:y = value\n", "ISO-8859-1"},
150 {"key = value", "key = value\n", "UTF-8"},
151 {"key = value \\\n continued", "key = value continued\n", "UTF-8"},
152 {"key⌘ = value⌘", "key⌘ = value⌘\n", "UTF-8"},
153 {"ke\\ \\:y = value", "ke\\ \\:y = value\n", "UTF-8"},
156 // ----------------------------------------------------------------------------
158 var writeCommentTests = []struct {
159 input, output, encoding string
162 {"key = value", "key = value\n", "ISO-8859-1"},
163 {"#\nkey = value", "key = value\n", "ISO-8859-1"},
164 {"#\n#\n#\nkey = value", "key = value\n", "ISO-8859-1"},
165 {"# comment\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"},
166 {"\n# comment\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"},
167 {"# comment\n\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"},
168 {"# comment1\n# comment2\nkey = value", "# comment1\n# comment2\nkey = value\n", "ISO-8859-1"},
169 {"#comment1\nkey1 = value1\n#comment2\nkey2 = value2", "# comment1\nkey1 = value1\n\n# comment2\nkey2 = value2\n", "ISO-8859-1"},
172 {"key = value", "key = value\n", "UTF-8"},
173 {"# comment⌘\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"},
174 {"\n# comment⌘\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"},
175 {"# comment⌘\n\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"},
176 {"# comment1⌘\n# comment2⌘\nkey = value⌘", "# comment1⌘\n# comment2⌘\nkey = value⌘\n", "UTF-8"},
177 {"#comment1⌘\nkey1 = value1⌘\n#comment2⌘\nkey2 = value2⌘", "# comment1⌘\nkey1 = value1⌘\n\n# comment2⌘\nkey2 = value2⌘\n", "UTF-8"},
180 // ----------------------------------------------------------------------------
182 var boolTests = []struct {
186 // valid values for TRUE
187 {"key = 1", "key", false, true},
188 {"key = on", "key", false, true},
189 {"key = On", "key", false, true},
190 {"key = ON", "key", false, true},
191 {"key = true", "key", false, true},
192 {"key = True", "key", false, true},
193 {"key = TRUE", "key", false, true},
194 {"key = yes", "key", false, true},
195 {"key = Yes", "key", false, true},
196 {"key = YES", "key", false, true},
198 // valid values for FALSE (all other)
199 {"key = 0", "key", true, false},
200 {"key = off", "key", true, false},
201 {"key = false", "key", true, false},
202 {"key = no", "key", true, false},
205 {"key = true", "key2", false, false},
208 // ----------------------------------------------------------------------------
210 var durationTests = []struct {
212 def, value time.Duration
215 {"key = 1", "key", 999, 1},
216 {"key = 0", "key", 999, 0},
217 {"key = -1", "key", 999, -1},
218 {"key = 0123", "key", 999, 123},
221 {"key = 0xff", "key", 999, 999},
222 {"key = 1.0", "key", 999, 999},
223 {"key = a", "key", 999, 999},
226 {"key = 1", "key2", 999, 999},
229 // ----------------------------------------------------------------------------
231 var parsedDurationTests = []struct {
233 def, value time.Duration
236 {"key = -1ns", "key", 999, -1 * time.Nanosecond},
237 {"key = 300ms", "key", 999, 300 * time.Millisecond},
238 {"key = 5s", "key", 999, 5 * time.Second},
239 {"key = 3h", "key", 999, 3 * time.Hour},
240 {"key = 2h45m", "key", 999, 2*time.Hour + 45*time.Minute},
243 {"key = 0xff", "key", 999, 999},
244 {"key = 1.0", "key", 999, 999},
245 {"key = a", "key", 999, 999},
246 {"key = 1", "key", 999, 999},
247 {"key = 0", "key", 999, 0},
250 {"key = 1", "key2", 999, 999},
253 // ----------------------------------------------------------------------------
255 var floatTests = []struct {
260 {"key = 1.0", "key", 999, 1.0},
261 {"key = 0.0", "key", 999, 0.0},
262 {"key = -1.0", "key", 999, -1.0},
263 {"key = 1", "key", 999, 1},
264 {"key = 0", "key", 999, 0},
265 {"key = -1", "key", 999, -1},
266 {"key = 0123", "key", 999, 123},
269 {"key = 0xff", "key", 999, 999},
270 {"key = a", "key", 999, 999},
273 {"key = 1", "key2", 999, 999},
276 // ----------------------------------------------------------------------------
278 var int64Tests = []struct {
283 {"key = 1", "key", 999, 1},
284 {"key = 0", "key", 999, 0},
285 {"key = -1", "key", 999, -1},
286 {"key = 0123", "key", 999, 123},
289 {"key = 0xff", "key", 999, 999},
290 {"key = 1.0", "key", 999, 999},
291 {"key = a", "key", 999, 999},
294 {"key = 1", "key2", 999, 999},
297 // ----------------------------------------------------------------------------
299 var uint64Tests = []struct {
304 {"key = 1", "key", 999, 1},
305 {"key = 0", "key", 999, 0},
306 {"key = 0123", "key", 999, 123},
309 {"key = -1", "key", 999, 999},
310 {"key = 0xff", "key", 999, 999},
311 {"key = 1.0", "key", 999, 999},
312 {"key = a", "key", 999, 999},
315 {"key = 1", "key2", 999, 999},
318 // ----------------------------------------------------------------------------
320 var stringTests = []struct {
325 {"key = abc", "key", "def", "abc"},
328 {"key = abc", "key2", "def", "def"},
331 // ----------------------------------------------------------------------------
333 var keysTests = []struct {
338 {"key = abc", []string{"key"}},
339 {"key = abc\nkey2=def", []string{"key", "key2"}},
340 {"key2 = abc\nkey=def", []string{"key2", "key"}},
341 {"key = abc\nkey=def", []string{"key"}},
344 // ----------------------------------------------------------------------------
346 var filterTests = []struct {
352 {"", "", []string{}, ""},
353 {"", "abc", []string{}, ""},
354 {"key=value", "", []string{"key"}, ""},
355 {"key=value", "key=", []string{}, ""},
356 {"key=value\nfoo=bar", "", []string{"foo", "key"}, ""},
357 {"key=value\nfoo=bar", "f", []string{"foo"}, ""},
358 {"key=value\nfoo=bar", "fo", []string{"foo"}, ""},
359 {"key=value\nfoo=bar", "foo", []string{"foo"}, ""},
360 {"key=value\nfoo=bar", "fooo", []string{}, ""},
361 {"key=value\nkey2=value2\nfoo=bar", "ey", []string{"key", "key2"}, ""},
362 {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}, ""},
363 {"key=value\nkey2=value2\nfoo=bar", "^key", []string{"key", "key2"}, ""},
364 {"key=value\nkey2=value2\nfoo=bar", "^(key|foo)", []string{"foo", "key", "key2"}, ""},
365 {"key=value\nkey2=value2\nfoo=bar", "[ abc", nil, "error parsing regexp.*"},
368 // ----------------------------------------------------------------------------
370 var filterPrefixTests = []struct {
375 {"", "", []string{}},
376 {"", "abc", []string{}},
377 {"key=value", "", []string{"key"}},
378 {"key=value", "key=", []string{}},
379 {"key=value\nfoo=bar", "", []string{"foo", "key"}},
380 {"key=value\nfoo=bar", "f", []string{"foo"}},
381 {"key=value\nfoo=bar", "fo", []string{"foo"}},
382 {"key=value\nfoo=bar", "foo", []string{"foo"}},
383 {"key=value\nfoo=bar", "fooo", []string{}},
384 {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}},
387 // ----------------------------------------------------------------------------
389 var filterStripPrefixTests = []struct {
394 {"", "", []string{}},
395 {"", "abc", []string{}},
396 {"key=value", "", []string{"key"}},
397 {"key=value", "key=", []string{}},
398 {"key=value\nfoo=bar", "", []string{"foo", "key"}},
399 {"key=value\nfoo=bar", "f", []string{"foo"}},
400 {"key=value\nfoo=bar", "fo", []string{"foo"}},
401 {"key=value\nfoo=bar", "foo", []string{"foo"}},
402 {"key=value\nfoo=bar", "fooo", []string{}},
403 {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}},
406 // ----------------------------------------------------------------------------
408 var setTests = []struct {
416 {"", "", "", "", false, "", []string{}},
417 {"", "key", "value", "", false, "", []string{"key"}},
418 {"key=value", "key2", "value2", "", false, "", []string{"key", "key2"}},
419 {"key=value", "abc", "value3", "", false, "", []string{"key", "abc"}},
420 {"key=value", "key", "value3", "value", true, "", []string{"key"}},
423 // ----------------------------------------------------------------------------
425 // TestBasic tests basic single key/value combinations with all possible
426 // whitespace, delimiter and newline permutations.
427 func TestBasic(t *testing.T) {
428 testWhitespaceAndDelimiterCombinations(t, "key", "")
429 testWhitespaceAndDelimiterCombinations(t, "key", "value")
430 testWhitespaceAndDelimiterCombinations(t, "key", "value ")
433 func TestComplex(t *testing.T) {
434 for _, test := range complexTests {
435 testKeyValue(t, test[0], test[1:]...)
439 func TestErrors(t *testing.T) {
440 for _, test := range errorTests {
441 _, err := Load([]byte(test.input), ISO_8859_1)
442 assert.Equal(t, err != nil, true, "want error")
443 assert.Equal(t, strings.Contains(err.Error(), test.msg), true)
447 func TestDisableExpansion(t *testing.T) {
448 input := "key=value\nkey2=${key}"
449 p := mustParse(t, input)
450 p.DisableExpansion = true
451 assert.Equal(t, p.MustGet("key"), "value")
452 assert.Equal(t, p.MustGet("key2"), "${key}")
454 // with expansion disabled we can introduce circular references
455 p.MustSet("keyA", "${keyB}")
456 p.MustSet("keyB", "${keyA}")
457 assert.Equal(t, p.MustGet("keyA"), "${keyB}")
458 assert.Equal(t, p.MustGet("keyB"), "${keyA}")
461 func TestDisableExpansionStillUpdatesKeys(t *testing.T) {
464 assert.Equal(t, p.Keys(), []string{"p1"})
465 assert.Equal(t, p.String(), "p1 = a\n")
467 p.DisableExpansion = true
470 assert.Equal(t, p.Keys(), []string{"p1", "p2"})
471 assert.Equal(t, p.String(), "p1 = a\np2 = b\n")
474 func TestMustGet(t *testing.T) {
475 input := "key = value\nkey2 = ghi"
476 p := mustParse(t, input)
477 assert.Equal(t, p.MustGet("key"), "value")
478 assert.Panic(t, func() { p.MustGet("invalid") }, "unknown property: invalid")
481 func TestGetBool(t *testing.T) {
482 for _, test := range boolTests {
483 p := mustParse(t, test.input)
484 assert.Equal(t, p.Len(), 1)
485 assert.Equal(t, p.GetBool(test.key, test.def), test.value)
489 func TestMustGetBool(t *testing.T) {
490 input := "key = true\nkey2 = ghi"
491 p := mustParse(t, input)
492 assert.Equal(t, p.MustGetBool("key"), true)
493 assert.Panic(t, func() { p.MustGetBool("invalid") }, "unknown property: invalid")
496 func TestGetDuration(t *testing.T) {
497 for _, test := range durationTests {
498 p := mustParse(t, test.input)
499 assert.Equal(t, p.Len(), 1)
500 assert.Equal(t, p.GetDuration(test.key, test.def), test.value)
504 func TestMustGetDuration(t *testing.T) {
505 input := "key = 123\nkey2 = ghi"
506 p := mustParse(t, input)
507 assert.Equal(t, p.MustGetDuration("key"), time.Duration(123))
508 assert.Panic(t, func() { p.MustGetDuration("key2") }, "strconv.ParseInt: parsing.*")
509 assert.Panic(t, func() { p.MustGetDuration("invalid") }, "unknown property: invalid")
512 func TestGetParsedDuration(t *testing.T) {
513 for _, test := range parsedDurationTests {
514 p := mustParse(t, test.input)
515 assert.Equal(t, p.Len(), 1)
516 assert.Equal(t, p.GetParsedDuration(test.key, test.def), test.value)
520 func TestMustGetParsedDuration(t *testing.T) {
521 input := "key = 123ms\nkey2 = ghi"
522 p := mustParse(t, input)
523 assert.Equal(t, p.MustGetParsedDuration("key"), 123*time.Millisecond)
524 assert.Panic(t, func() { p.MustGetParsedDuration("key2") }, "time: invalid duration ghi")
525 assert.Panic(t, func() { p.MustGetParsedDuration("invalid") }, "unknown property: invalid")
528 func TestGetFloat64(t *testing.T) {
529 for _, test := range floatTests {
530 p := mustParse(t, test.input)
531 assert.Equal(t, p.Len(), 1)
532 assert.Equal(t, p.GetFloat64(test.key, test.def), test.value)
536 func TestMustGetFloat64(t *testing.T) {
537 input := "key = 123\nkey2 = ghi"
538 p := mustParse(t, input)
539 assert.Equal(t, p.MustGetFloat64("key"), float64(123))
540 assert.Panic(t, func() { p.MustGetFloat64("key2") }, "strconv.ParseFloat: parsing.*")
541 assert.Panic(t, func() { p.MustGetFloat64("invalid") }, "unknown property: invalid")
544 func TestGetInt(t *testing.T) {
545 for _, test := range int64Tests {
546 p := mustParse(t, test.input)
547 assert.Equal(t, p.Len(), 1)
548 assert.Equal(t, p.GetInt(test.key, int(test.def)), int(test.value))
552 func TestMustGetInt(t *testing.T) {
553 input := "key = 123\nkey2 = ghi"
554 p := mustParse(t, input)
555 assert.Equal(t, p.MustGetInt("key"), int(123))
556 assert.Panic(t, func() { p.MustGetInt("key2") }, "strconv.ParseInt: parsing.*")
557 assert.Panic(t, func() { p.MustGetInt("invalid") }, "unknown property: invalid")
560 func TestGetInt64(t *testing.T) {
561 for _, test := range int64Tests {
562 p := mustParse(t, test.input)
563 assert.Equal(t, p.Len(), 1)
564 assert.Equal(t, p.GetInt64(test.key, test.def), test.value)
568 func TestMustGetInt64(t *testing.T) {
569 input := "key = 123\nkey2 = ghi"
570 p := mustParse(t, input)
571 assert.Equal(t, p.MustGetInt64("key"), int64(123))
572 assert.Panic(t, func() { p.MustGetInt64("key2") }, "strconv.ParseInt: parsing.*")
573 assert.Panic(t, func() { p.MustGetInt64("invalid") }, "unknown property: invalid")
576 func TestGetUint(t *testing.T) {
577 for _, test := range uint64Tests {
578 p := mustParse(t, test.input)
579 assert.Equal(t, p.Len(), 1)
580 assert.Equal(t, p.GetUint(test.key, uint(test.def)), uint(test.value))
584 func TestMustGetUint(t *testing.T) {
585 input := "key = 123\nkey2 = ghi"
586 p := mustParse(t, input)
587 assert.Equal(t, p.MustGetUint("key"), uint(123))
588 assert.Panic(t, func() { p.MustGetUint64("key2") }, "strconv.ParseUint: parsing.*")
589 assert.Panic(t, func() { p.MustGetUint64("invalid") }, "unknown property: invalid")
592 func TestGetUint64(t *testing.T) {
593 for _, test := range uint64Tests {
594 p := mustParse(t, test.input)
595 assert.Equal(t, p.Len(), 1)
596 assert.Equal(t, p.GetUint64(test.key, test.def), test.value)
600 func TestMustGetUint64(t *testing.T) {
601 input := "key = 123\nkey2 = ghi"
602 p := mustParse(t, input)
603 assert.Equal(t, p.MustGetUint64("key"), uint64(123))
604 assert.Panic(t, func() { p.MustGetUint64("key2") }, "strconv.ParseUint: parsing.*")
605 assert.Panic(t, func() { p.MustGetUint64("invalid") }, "unknown property: invalid")
608 func TestGetString(t *testing.T) {
609 for _, test := range stringTests {
610 p := mustParse(t, test.input)
611 assert.Equal(t, p.Len(), 1)
612 assert.Equal(t, p.GetString(test.key, test.def), test.value)
616 func TestMustGetString(t *testing.T) {
617 input := `key = value`
618 p := mustParse(t, input)
619 assert.Equal(t, p.MustGetString("key"), "value")
620 assert.Panic(t, func() { p.MustGetString("invalid") }, "unknown property: invalid")
623 func TestComment(t *testing.T) {
624 for _, test := range commentTests {
625 p := mustParse(t, test.input)
626 assert.Equal(t, p.MustGetString(test.key), test.value)
627 assert.Equal(t, p.GetComments(test.key), test.comments)
628 if test.comments != nil {
629 assert.Equal(t, p.GetComment(test.key), test.comments[len(test.comments)-1])
631 assert.Equal(t, p.GetComment(test.key), "")
634 // test setting comments
635 if len(test.comments) > 0 {
636 // set single comment
638 assert.Equal(t, len(p.c), 0)
639 p.SetComment(test.key, test.comments[0])
640 assert.Equal(t, p.GetComment(test.key), test.comments[0])
642 // set multiple comments
644 assert.Equal(t, len(p.c), 0)
645 p.SetComments(test.key, test.comments)
646 assert.Equal(t, p.GetComments(test.key), test.comments)
648 // clear comments for a key
649 p.SetComments(test.key, nil)
650 assert.Equal(t, p.GetComment(test.key), "")
651 assert.Equal(t, p.GetComments(test.key), ([]string)(nil))
656 func TestFilter(t *testing.T) {
657 for _, test := range filterTests {
658 p := mustParse(t, test.input)
659 pp, err := p.Filter(test.pattern)
661 assert.Matches(t, err.Error(), test.err)
664 assert.Equal(t, pp != nil, true, "want properties")
665 assert.Equal(t, pp.Len(), len(test.keys))
666 for _, key := range test.keys {
667 v1, ok1 := p.Get(key)
668 v2, ok2 := pp.Get(key)
669 assert.Equal(t, ok1, true)
670 assert.Equal(t, ok2, true)
671 assert.Equal(t, v1, v2)
676 func TestFilterPrefix(t *testing.T) {
677 for _, test := range filterPrefixTests {
678 p := mustParse(t, test.input)
679 pp := p.FilterPrefix(test.prefix)
680 assert.Equal(t, pp != nil, true, "want properties")
681 assert.Equal(t, pp.Len(), len(test.keys))
682 for _, key := range test.keys {
683 v1, ok1 := p.Get(key)
684 v2, ok2 := pp.Get(key)
685 assert.Equal(t, ok1, true)
686 assert.Equal(t, ok2, true)
687 assert.Equal(t, v1, v2)
692 func TestFilterStripPrefix(t *testing.T) {
693 for _, test := range filterStripPrefixTests {
694 p := mustParse(t, test.input)
695 pp := p.FilterPrefix(test.prefix)
696 assert.Equal(t, pp != nil, true, "want properties")
697 assert.Equal(t, pp.Len(), len(test.keys))
698 for _, key := range test.keys {
699 v1, ok1 := p.Get(key)
700 v2, ok2 := pp.Get(key)
701 assert.Equal(t, ok1, true)
702 assert.Equal(t, ok2, true)
703 assert.Equal(t, v1, v2)
708 func TestKeys(t *testing.T) {
709 for _, test := range keysTests {
710 p := mustParse(t, test.input)
711 assert.Equal(t, p.Len(), len(test.keys))
712 assert.Equal(t, len(p.Keys()), len(test.keys))
713 assert.Equal(t, p.Keys(), test.keys)
717 func TestSet(t *testing.T) {
718 for _, test := range setTests {
719 p := mustParse(t, test.input)
720 prev, ok, err := p.Set(test.key, test.value)
722 assert.Matches(t, err.Error(), test.err)
726 assert.Equal(t, err, nil)
727 assert.Equal(t, ok, test.ok)
729 assert.Equal(t, prev, test.prev)
731 assert.Equal(t, p.Keys(), test.keys)
735 func TestSetValue(t *testing.T) {
736 tests := []interface{}{
738 int8(123), int16(123), int32(123), int64(123), int(123),
739 uint8(123), uint16(123), uint32(123), uint64(123), uint(123),
740 float32(1.23), float64(1.23),
744 for _, v := range tests {
746 err := p.SetValue("x", v)
747 assert.Equal(t, err, nil)
748 assert.Equal(t, p.GetString("x", ""), fmt.Sprintf("%v", v))
752 func TestMustSet(t *testing.T) {
753 input := "key=${key}"
754 p := mustParse(t, input)
755 assert.Panic(t, func() { p.MustSet("key", "${key}") }, "circular reference .*")
758 func TestWrite(t *testing.T) {
759 for _, test := range writeTests {
760 p, err := parse(test.input)
762 buf := new(bytes.Buffer)
764 switch test.encoding {
766 n, err = p.Write(buf, UTF8)
768 n, err = p.Write(buf, ISO_8859_1)
770 assert.Equal(t, err, nil)
771 s := string(buf.Bytes())
772 assert.Equal(t, n, len(test.output), fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
773 assert.Equal(t, s, test.output, fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
777 func TestWriteComment(t *testing.T) {
778 for _, test := range writeCommentTests {
779 p, err := parse(test.input)
781 buf := new(bytes.Buffer)
783 switch test.encoding {
785 n, err = p.WriteComment(buf, "# ", UTF8)
787 n, err = p.WriteComment(buf, "# ", ISO_8859_1)
789 assert.Equal(t, err, nil)
790 s := string(buf.Bytes())
791 assert.Equal(t, n, len(test.output), fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
792 assert.Equal(t, s, test.output, fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
796 func TestCustomExpansionExpression(t *testing.T) {
797 testKeyValuePrePostfix(t, "*[", "]*", "key=value\nkey2=*[key]*", "key", "value", "key2", "value")
800 func TestPanicOn32BitIntOverflow(t *testing.T) {
802 var min, max int64 = math.MinInt32 - 1, math.MaxInt32 + 1
803 input := fmt.Sprintf("min=%d\nmax=%d", min, max)
804 p := mustParse(t, input)
805 assert.Equal(t, p.MustGetInt64("min"), min)
806 assert.Equal(t, p.MustGetInt64("max"), max)
807 assert.Panic(t, func() { p.MustGetInt("min") }, ".* out of range")
808 assert.Panic(t, func() { p.MustGetInt("max") }, ".* out of range")
811 func TestPanicOn32BitUintOverflow(t *testing.T) {
813 var max uint64 = math.MaxUint32 + 1
814 input := fmt.Sprintf("max=%d", max)
815 p := mustParse(t, input)
816 assert.Equal(t, p.MustGetUint64("max"), max)
817 assert.Panic(t, func() { p.MustGetUint("max") }, ".* out of range")
820 func TestDeleteKey(t *testing.T) {
821 input := "#comments should also be gone\nkey=to-be-deleted\nsecond=key"
822 p := mustParse(t, input)
823 assert.Equal(t, len(p.m), 2)
824 assert.Equal(t, len(p.c), 1)
825 assert.Equal(t, len(p.k), 2)
827 assert.Equal(t, len(p.m), 1)
828 assert.Equal(t, len(p.c), 0)
829 assert.Equal(t, len(p.k), 1)
830 assert.Equal(t, p.k[0], "second")
831 assert.Equal(t, p.m["second"], "key")
834 func TestDeleteUnknownKey(t *testing.T) {
835 input := "#comments should also be gone\nkey=to-be-deleted"
836 p := mustParse(t, input)
837 assert.Equal(t, len(p.m), 1)
838 assert.Equal(t, len(p.c), 1)
839 assert.Equal(t, len(p.k), 1)
840 p.Delete("wrong-key")
841 assert.Equal(t, len(p.m), 1)
842 assert.Equal(t, len(p.c), 1)
843 assert.Equal(t, len(p.k), 1)
846 func TestMerge(t *testing.T) {
847 input1 := "#comment\nkey=value\nkey2=value2"
848 input2 := "#another comment\nkey=another value\nkey3=value3"
849 p1 := mustParse(t, input1)
850 p2 := mustParse(t, input2)
852 assert.Equal(t, len(p1.m), 3)
853 assert.Equal(t, len(p1.c), 1)
854 assert.Equal(t, len(p1.k), 3)
855 assert.Equal(t, p1.MustGet("key"), "another value")
856 assert.Equal(t, p1.GetComment("key"), "another comment")
859 func TestMap(t *testing.T) {
860 input := "key=value\nabc=def"
861 p := mustParse(t, input)
862 m := map[string]string{"key": "value", "abc": "def"}
863 assert.Equal(t, p.Map(), m)
866 func TestFilterFunc(t *testing.T) {
867 input := "key=value\nabc=def"
868 p := mustParse(t, input)
869 pp := p.FilterFunc(func(k, v string) bool {
872 m := map[string]string{"key": "value"}
873 assert.Equal(t, pp.Map(), m)
876 // ----------------------------------------------------------------------------
878 // tests all combinations of delimiters, leading and/or trailing whitespace and newlines.
879 func testWhitespaceAndDelimiterCombinations(t *testing.T, key, value string) {
880 whitespace := []string{"", " ", "\f", "\t"}
881 delimiters := []string{"", " ", "=", ":"}
882 newlines := []string{"", "\r", "\n", "\r\n"}
883 for _, dl := range delimiters {
884 for _, ws1 := range whitespace {
885 for _, ws2 := range whitespace {
886 for _, nl := range newlines {
887 // skip the one case where there is nothing between a key and a value
888 if ws1 == "" && dl == "" && ws2 == "" && value != "" {
892 input := fmt.Sprintf("%s%s%s%s%s%s", key, ws1, dl, ws2, value, nl)
893 testKeyValue(t, input, key, value)
900 // tests whether key/value pairs exist for a given input.
901 // keyvalues is expected to be an even number of strings of "key", "value", ...
902 func testKeyValue(t *testing.T, input string, keyvalues ...string) {
903 testKeyValuePrePostfix(t, "${", "}", input, keyvalues...)
906 // tests whether key/value pairs exist for a given input.
907 // keyvalues is expected to be an even number of strings of "key", "value", ...
908 func testKeyValuePrePostfix(t *testing.T, prefix, postfix, input string, keyvalues ...string) {
909 p, err := Load([]byte(input), ISO_8859_1)
910 assert.Equal(t, err, nil)
913 assertKeyValues(t, input, p, keyvalues...)
916 // tests whether key/value pairs exist for a given input.
917 // keyvalues is expected to be an even number of strings of "key", "value", ...
918 func assertKeyValues(t *testing.T, input string, p *Properties, keyvalues ...string) {
919 assert.Equal(t, p != nil, true, "want properties")
920 assert.Equal(t, 2*p.Len(), len(keyvalues), "Odd number of key/value pairs.")
922 for i := 0; i < len(keyvalues); i += 2 {
923 key, value := keyvalues[i], keyvalues[i+1]
926 t.Errorf("No key %q found (input=%q)", key, input)
928 if got, want := v, value; !reflect.DeepEqual(got, want) {
929 t.Errorf("Value %q does not match %q (input=%q)", v, value, input)
934 func mustParse(t *testing.T, s string) *Properties {
937 t.Fatalf("parse failed with %s", err)
942 // prints to stderr if the -verbose flag was given.
943 func printf(format string, args ...interface{}) {
945 fmt.Fprintf(os.Stderr, format, args...)