1
2
3
4
5 package properties
6
7 import (
8 "bytes"
9 "fmt"
10 "math"
11 "os"
12 "reflect"
13 "regexp"
14 "strings"
15 "testing"
16 "time"
17
18 "github.com/magiconair/properties/assert"
19 )
20
21 func init() {
22 ErrorHandler = PanicHandler
23 }
24
25
26
27
28
29 var complexTests = [][]string{
30
31 {" key=value", "key", "value"},
32 {"\fkey=value", "key", "value"},
33 {"\tkey=value", "key", "value"},
34 {" \f\tkey=value", "key", "value"},
35
36
37 {"key1=value1\nkey2=value2\n", "key1", "value1", "key2", "value2"},
38 {"key1=value1\rkey2=value2\r", "key1", "value1", "key2", "value2"},
39 {"key1=value1\r\nkey2=value2\r\n", "key1", "value1", "key2", "value2"},
40
41
42 {"\nkey=value\n", "key", "value"},
43 {"\rkey=value\r", "key", "value"},
44 {"\r\nkey=value\r\n", "key", "value"},
45 {"\nkey=value\n \nkey2=value2", "key", "value", "key2", "value2"},
46 {"\nkey=value\n\t\nkey2=value2", "key", "value", "key2", "value2"},
47
48
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"},
56
57
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"},
65
66
67 {"k\\zey = value", "kzey", "value"},
68 {"key = v\\zalue", "key", "vzalue"},
69
70
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"},
75
76
77 {"key = valueA,\\\n valueB", "key", "valueA,valueB"},
78 {"key = valueA,\\\n\f\f\fvalueB", "key", "valueA,valueB"},
79 {"key = valueA,\\\n\t\t\tvalueB", "key", "valueA,valueB"},
80 {"key = valueA,\\\n \f\tvalueB", "key", "valueA,valueB"},
81
82
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"},
84
85
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=value\nkey2=${key}${key}", "key", "value", "key2", "valuevalue"},
92 {"key=value\nkey2=${key}${key}${key}${key}", "key", "value", "key2", "valuevaluevaluevalue"},
93 {"key=value\nkey2=${key}${key3}\nkey3=${key}", "key", "value", "key2", "valuevalue", "key3", "value"},
94 {"key=value\nkey2=${key3}${key}${key4}\nkey3=${key}\nkey4=${key}", "key", "value", "key2", "valuevaluevalue", "key3", "value", "key4", "value"},
95 {"key=${USER}", "key", os.Getenv("USER")},
96 {"key=${USER}\nUSER=value", "key", "value", "USER", "value"},
97 }
98
99
100
101 var commentTests = []struct {
102 input, key, value string
103 comments []string
104 }{
105 {"key=value", "key", "value", nil},
106 {"#\nkey=value", "key", "value", []string{""}},
107 {"#comment\nkey=value", "key", "value", []string{"comment"}},
108 {"# comment\nkey=value", "key", "value", []string{"comment"}},
109 {"# comment\nkey=value", "key", "value", []string{"comment"}},
110 {"# comment\n\nkey=value", "key", "value", []string{"comment"}},
111 {"# comment1\n# comment2\nkey=value", "key", "value", []string{"comment1", "comment2"}},
112 {"# comment1\n\n# comment2\n\nkey=value", "key", "value", []string{"comment1", "comment2"}},
113 {"!comment\nkey=value", "key", "value", []string{"comment"}},
114 {"! comment\nkey=value", "key", "value", []string{"comment"}},
115 {"! comment\nkey=value", "key", "value", []string{"comment"}},
116 {"! comment\n\nkey=value", "key", "value", []string{"comment"}},
117 {"! comment1\n! comment2\nkey=value", "key", "value", []string{"comment1", "comment2"}},
118 {"! comment1\n\n! comment2\n\nkey=value", "key", "value", []string{"comment1", "comment2"}},
119 }
120
121
122
123 var errorTests = []struct {
124 input, msg string
125 }{
126
127 {"key\\u1 = value", "invalid unicode literal"},
128 {"key\\u12 = value", "invalid unicode literal"},
129 {"key\\u123 = value", "invalid unicode literal"},
130 {"key\\u123g = value", "invalid unicode literal"},
131 {"key\\u123", "invalid unicode literal"},
132
133
134 {"key=${key}", `circular reference in:\nkey=\$\{key\}`},
135 {"key1=${key2}\nkey2=${key1}", `circular reference in:\n(key1=\$\{key2\}\nkey2=\$\{key1\}|key2=\$\{key1\}\nkey1=\$\{key2\})`},
136
137
138 {"key=${ke", "malformed expression"},
139 {"key=valu${ke", "malformed expression"},
140 }
141
142
143
144 var writeTests = []struct {
145 input, output, encoding string
146 }{
147
148 {"key = value", "key = value\n", "ISO-8859-1"},
149 {"key = value \\\n continued", "key = value continued\n", "ISO-8859-1"},
150 {"key⌘ = value", "key\\u2318 = value\n", "ISO-8859-1"},
151 {"ke\\ \\:y = value", "ke\\ \\:y = value\n", "ISO-8859-1"},
152 {"ke\\\\y = val\\\\ue", "ke\\\\y = val\\\\ue\n", "ISO-8859-1"},
153
154
155 {"key = value", "key = value\n", "UTF-8"},
156 {"key = value \\\n continued", "key = value continued\n", "UTF-8"},
157 {"key⌘ = value⌘", "key⌘ = value⌘\n", "UTF-8"},
158 {"ke\\ \\:y = value", "ke\\ \\:y = value\n", "UTF-8"},
159 {"ke\\\\y = val\\\\ue", "ke\\\\y = val\\\\ue\n", "UTF-8"},
160 }
161
162
163
164 var writeCommentTests = []struct {
165 input, output, encoding string
166 }{
167
168 {"key = value", "key = value\n", "ISO-8859-1"},
169 {"#\nkey = value", "key = value\n", "ISO-8859-1"},
170 {"#\n#\n#\nkey = value", "key = value\n", "ISO-8859-1"},
171 {"# comment\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"},
172 {"\n# comment\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"},
173 {"# comment\n\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"},
174 {"# comment1\n# comment2\nkey = value", "# comment1\n# comment2\nkey = value\n", "ISO-8859-1"},
175 {"#comment1\nkey1 = value1\n#comment2\nkey2 = value2", "# comment1\nkey1 = value1\n\n# comment2\nkey2 = value2\n", "ISO-8859-1"},
176
177 {"# com\\\\ment\nkey = value", "# com\\\\ment\nkey = value\n", "ISO-8859-1"},
178
179
180 {"key = value", "key = value\n", "UTF-8"},
181 {"# comment⌘\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"},
182 {"\n# comment⌘\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"},
183 {"# comment⌘\n\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"},
184 {"# comment1⌘\n# comment2⌘\nkey = value⌘", "# comment1⌘\n# comment2⌘\nkey = value⌘\n", "UTF-8"},
185 {"#comment1⌘\nkey1 = value1⌘\n#comment2⌘\nkey2 = value2⌘", "# comment1⌘\nkey1 = value1⌘\n\n# comment2⌘\nkey2 = value2⌘\n", "UTF-8"},
186
187 {"# com\\\\ment⌘\nkey = value⌘", "# com\\\\ment⌘\nkey = value⌘\n", "UTF-8"},
188 }
189
190
191
192 var boolTests = []struct {
193 input, key string
194 def, value bool
195 }{
196
197 {"key = 1", "key", false, true},
198 {"key = on", "key", false, true},
199 {"key = On", "key", false, true},
200 {"key = ON", "key", false, true},
201 {"key = true", "key", false, true},
202 {"key = True", "key", false, true},
203 {"key = TRUE", "key", false, true},
204 {"key = yes", "key", false, true},
205 {"key = Yes", "key", false, true},
206 {"key = YES", "key", false, true},
207
208
209 {"key = 0", "key", true, false},
210 {"key = off", "key", true, false},
211 {"key = false", "key", true, false},
212 {"key = no", "key", true, false},
213
214
215 {"key = true", "key2", false, false},
216 }
217
218
219
220 var durationTests = []struct {
221 input, key string
222 def, value time.Duration
223 }{
224
225 {"key = 1", "key", 999, 1},
226 {"key = 0", "key", 999, 0},
227 {"key = -1", "key", 999, -1},
228 {"key = 0123", "key", 999, 123},
229
230
231 {"key = 0xff", "key", 999, 999},
232 {"key = 1.0", "key", 999, 999},
233 {"key = a", "key", 999, 999},
234
235
236 {"key = 1", "key2", 999, 999},
237 }
238
239
240
241 var parsedDurationTests = []struct {
242 input, key string
243 def, value time.Duration
244 }{
245
246 {"key = -1ns", "key", 999, -1 * time.Nanosecond},
247 {"key = 300ms", "key", 999, 300 * time.Millisecond},
248 {"key = 5s", "key", 999, 5 * time.Second},
249 {"key = 3h", "key", 999, 3 * time.Hour},
250 {"key = 2h45m", "key", 999, 2*time.Hour + 45*time.Minute},
251
252
253 {"key = 0xff", "key", 999, 999},
254 {"key = 1.0", "key", 999, 999},
255 {"key = a", "key", 999, 999},
256 {"key = 1", "key", 999, 999},
257 {"key = 0", "key", 999, 0},
258
259
260 {"key = 1", "key2", 999, 999},
261 }
262
263
264
265 var floatTests = []struct {
266 input, key string
267 def, value float64
268 }{
269
270 {"key = 1.0", "key", 999, 1.0},
271 {"key = 0.0", "key", 999, 0.0},
272 {"key = -1.0", "key", 999, -1.0},
273 {"key = 1", "key", 999, 1},
274 {"key = 0", "key", 999, 0},
275 {"key = -1", "key", 999, -1},
276 {"key = 0123", "key", 999, 123},
277
278
279 {"key = 0xff", "key", 999, 999},
280 {"key = a", "key", 999, 999},
281
282
283 {"key = 1", "key2", 999, 999},
284 }
285
286
287
288 var int64Tests = []struct {
289 input, key string
290 def, value int64
291 }{
292
293 {"key = 1", "key", 999, 1},
294 {"key = 0", "key", 999, 0},
295 {"key = -1", "key", 999, -1},
296 {"key = 0123", "key", 999, 123},
297
298
299 {"key = 0xff", "key", 999, 999},
300 {"key = 1.0", "key", 999, 999},
301 {"key = a", "key", 999, 999},
302
303
304 {"key = 1", "key2", 999, 999},
305 }
306
307
308
309 var uint64Tests = []struct {
310 input, key string
311 def, value uint64
312 }{
313
314 {"key = 1", "key", 999, 1},
315 {"key = 0", "key", 999, 0},
316 {"key = 0123", "key", 999, 123},
317
318
319 {"key = -1", "key", 999, 999},
320 {"key = 0xff", "key", 999, 999},
321 {"key = 1.0", "key", 999, 999},
322 {"key = a", "key", 999, 999},
323
324
325 {"key = 1", "key2", 999, 999},
326 }
327
328
329
330 var stringTests = []struct {
331 input, key string
332 def, value string
333 }{
334
335 {"key = abc", "key", "def", "abc"},
336 {"key = ab\\\\c", "key", "def", "ab\\c"},
337
338
339 {"key = abc", "key2", "def", "def"},
340 }
341
342
343
344 var keysTests = []struct {
345 input string
346 keys []string
347 }{
348 {"", []string{}},
349 {"key = abc", []string{"key"}},
350 {"key = abc\nkey2=def", []string{"key", "key2"}},
351 {"key2 = abc\nkey=def", []string{"key2", "key"}},
352 {"key = abc\nkey=def", []string{"key"}},
353 {"key\\\\with\\\\backslashes = abc", []string{"key\\with\\backslashes"}},
354 }
355
356
357
358 var filterTests = []struct {
359 input string
360 pattern string
361 keys []string
362 err string
363 }{
364 {"", "", []string{}, ""},
365 {"", "abc", []string{}, ""},
366 {"key=value", "", []string{"key"}, ""},
367 {"key=value", "key=", []string{}, ""},
368 {"key=value\nfoo=bar", "", []string{"foo", "key"}, ""},
369 {"key=value\nfoo=bar", "f", []string{"foo"}, ""},
370 {"key=value\nfoo=bar", "fo", []string{"foo"}, ""},
371 {"key=value\nfoo=bar", "foo", []string{"foo"}, ""},
372 {"key=value\nfoo=bar", "fooo", []string{}, ""},
373 {"key=value\nkey2=value2\nfoo=bar", "ey", []string{"key", "key2"}, ""},
374 {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}, ""},
375 {"key=value\nkey2=value2\nfoo=bar", "^key", []string{"key", "key2"}, ""},
376 {"key=value\nkey2=value2\nfoo=bar", "^(key|foo)", []string{"foo", "key", "key2"}, ""},
377 {"key=value\nkey2=value2\nfoo=bar", "[ abc", nil, "error parsing regexp.*"},
378 }
379
380
381
382 var filterPrefixTests = []struct {
383 input string
384 prefix string
385 keys []string
386 }{
387 {"", "", []string{}},
388 {"", "abc", []string{}},
389 {"key=value", "", []string{"key"}},
390 {"key=value", "key=", []string{}},
391 {"key=value\nfoo=bar", "", []string{"foo", "key"}},
392 {"key=value\nfoo=bar", "f", []string{"foo"}},
393 {"key=value\nfoo=bar", "fo", []string{"foo"}},
394 {"key=value\nfoo=bar", "foo", []string{"foo"}},
395 {"key=value\nfoo=bar", "fooo", []string{}},
396 {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}},
397 }
398
399
400
401 var filterStripPrefixTests = []struct {
402 input string
403 prefix string
404 keys []string
405 }{
406 {"", "", []string{}},
407 {"", "abc", []string{}},
408 {"key=value", "", []string{"key"}},
409 {"key=value", "key=", []string{}},
410 {"key=value\nfoo=bar", "", []string{"foo", "key"}},
411 {"key=value\nfoo=bar", "f", []string{"foo"}},
412 {"key=value\nfoo=bar", "fo", []string{"foo"}},
413 {"key=value\nfoo=bar", "foo", []string{"foo"}},
414 {"key=value\nfoo=bar", "fooo", []string{}},
415 {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}},
416 }
417
418
419
420 var setTests = []struct {
421 input string
422 key, value string
423 prev string
424 ok bool
425 err string
426 keys []string
427 }{
428 {"", "", "", "", false, "", []string{}},
429 {"", "key", "value", "", false, "", []string{"key"}},
430 {"key=value", "key2", "value2", "", false, "", []string{"key", "key2"}},
431 {"key=value", "abc", "value3", "", false, "", []string{"key", "abc"}},
432 {"key=value", "key", "value3", "value", true, "", []string{"key"}},
433 }
434
435
436
437
438
439 func TestBasic(t *testing.T) {
440 testWhitespaceAndDelimiterCombinations(t, "key", "")
441 testWhitespaceAndDelimiterCombinations(t, "key", "value")
442 testWhitespaceAndDelimiterCombinations(t, "key", "value ")
443 }
444
445 func TestComplex(t *testing.T) {
446 for _, test := range complexTests {
447 testKeyValue(t, test[0], test[1:]...)
448 }
449 }
450
451 func TestErrors(t *testing.T) {
452 for _, test := range errorTests {
453 _, err := Load([]byte(test.input), ISO_8859_1)
454 assert.Equal(t, err != nil, true, fmt.Sprintf("want error: %s", test.input))
455 re := regexp.MustCompile(test.msg)
456 assert.Equal(t, re.MatchString(err.Error()), true, fmt.Sprintf("expected %s, got %s", test.msg, err.Error()))
457 }
458 }
459
460 func TestVeryDeep(t *testing.T) {
461 input := "key0=value\n"
462 prefix := "${"
463 postfix := "}"
464 i := 0
465 for i = 0; i < maxExpansionDepth-1; i++ {
466 input += fmt.Sprintf("key%d=%skey%d%s\n", i+1, prefix, i, postfix)
467 }
468
469 p, err := Load([]byte(input), ISO_8859_1)
470 assert.Equal(t, err, nil)
471 p.Prefix = prefix
472 p.Postfix = postfix
473
474 assert.Equal(t, p.MustGet(fmt.Sprintf("key%d", i)), "value")
475
476
477 input += fmt.Sprintf("key%d=%skey%d%s\n", i+1, prefix, i, postfix)
478
479 _, err = Load([]byte(input), ISO_8859_1)
480 assert.Equal(t, err != nil, true, "want error")
481 assert.Equal(t, strings.Contains(err.Error(), "expansion too deep"), true)
482 }
483
484 func TestDisableExpansion(t *testing.T) {
485 input := "key=value\nkey2=${key}"
486 p := mustParse(t, input)
487 p.DisableExpansion = true
488 assert.Equal(t, p.MustGet("key"), "value")
489 assert.Equal(t, p.MustGet("key2"), "${key}")
490
491
492 p.MustSet("keyA", "${keyB}")
493 p.MustSet("keyB", "${keyA}")
494 assert.Equal(t, p.MustGet("keyA"), "${keyB}")
495 assert.Equal(t, p.MustGet("keyB"), "${keyA}")
496 }
497
498 func TestDisableExpansionStillUpdatesKeys(t *testing.T) {
499 p := NewProperties()
500 p.MustSet("p1", "a")
501 assert.Equal(t, p.Keys(), []string{"p1"})
502 assert.Equal(t, p.String(), "p1 = a\n")
503
504 p.DisableExpansion = true
505 p.MustSet("p2", "b")
506
507 assert.Equal(t, p.Keys(), []string{"p1", "p2"})
508 assert.Equal(t, p.String(), "p1 = a\np2 = b\n")
509 }
510
511 func TestMustGet(t *testing.T) {
512 input := "key = value\nkey2 = ghi"
513 p := mustParse(t, input)
514 assert.Equal(t, p.MustGet("key"), "value")
515 assert.Panic(t, func() { p.MustGet("invalid") }, "unknown property: invalid")
516 }
517
518 func TestGetBool(t *testing.T) {
519 for _, test := range boolTests {
520 p := mustParse(t, test.input)
521 assert.Equal(t, p.Len(), 1)
522 assert.Equal(t, p.GetBool(test.key, test.def), test.value)
523 }
524 }
525
526 func TestMustGetBool(t *testing.T) {
527 input := "key = true\nkey2 = ghi"
528 p := mustParse(t, input)
529 assert.Equal(t, p.MustGetBool("key"), true)
530 assert.Panic(t, func() { p.MustGetBool("invalid") }, "unknown property: invalid")
531 }
532
533 func TestGetDuration(t *testing.T) {
534 for _, test := range durationTests {
535 p := mustParse(t, test.input)
536 assert.Equal(t, p.Len(), 1)
537 assert.Equal(t, p.GetDuration(test.key, test.def), test.value)
538 }
539 }
540
541 func TestMustGetDuration(t *testing.T) {
542 input := "key = 123\nkey2 = ghi"
543 p := mustParse(t, input)
544 assert.Equal(t, p.MustGetDuration("key"), time.Duration(123))
545 assert.Panic(t, func() { p.MustGetDuration("key2") }, "strconv.ParseInt: parsing.*")
546 assert.Panic(t, func() { p.MustGetDuration("invalid") }, "unknown property: invalid")
547 }
548
549 func TestGetParsedDuration(t *testing.T) {
550 for _, test := range parsedDurationTests {
551 p := mustParse(t, test.input)
552 assert.Equal(t, p.Len(), 1)
553 assert.Equal(t, p.GetParsedDuration(test.key, test.def), test.value)
554 }
555 }
556
557 func TestGetFloat64(t *testing.T) {
558 for _, test := range floatTests {
559 p := mustParse(t, test.input)
560 assert.Equal(t, p.Len(), 1)
561 assert.Equal(t, p.GetFloat64(test.key, test.def), test.value)
562 }
563 }
564
565 func TestMustGetFloat64(t *testing.T) {
566 input := "key = 123\nkey2 = ghi"
567 p := mustParse(t, input)
568 assert.Equal(t, p.MustGetFloat64("key"), float64(123))
569 assert.Panic(t, func() { p.MustGetFloat64("key2") }, "strconv.ParseFloat: parsing.*")
570 assert.Panic(t, func() { p.MustGetFloat64("invalid") }, "unknown property: invalid")
571 }
572
573 func TestGetInt(t *testing.T) {
574 for _, test := range int64Tests {
575 p := mustParse(t, test.input)
576 assert.Equal(t, p.Len(), 1)
577 assert.Equal(t, p.GetInt(test.key, int(test.def)), int(test.value))
578 }
579 }
580
581 func TestMustGetInt(t *testing.T) {
582 input := "key = 123\nkey2 = ghi"
583 p := mustParse(t, input)
584 assert.Equal(t, p.MustGetInt("key"), int(123))
585 assert.Panic(t, func() { p.MustGetInt("key2") }, "strconv.ParseInt: parsing.*")
586 assert.Panic(t, func() { p.MustGetInt("invalid") }, "unknown property: invalid")
587 }
588
589 func TestGetInt64(t *testing.T) {
590 for _, test := range int64Tests {
591 p := mustParse(t, test.input)
592 assert.Equal(t, p.Len(), 1)
593 assert.Equal(t, p.GetInt64(test.key, test.def), test.value)
594 }
595 }
596
597 func TestMustGetInt64(t *testing.T) {
598 input := "key = 123\nkey2 = ghi"
599 p := mustParse(t, input)
600 assert.Equal(t, p.MustGetInt64("key"), int64(123))
601 assert.Panic(t, func() { p.MustGetInt64("key2") }, "strconv.ParseInt: parsing.*")
602 assert.Panic(t, func() { p.MustGetInt64("invalid") }, "unknown property: invalid")
603 }
604
605 func TestGetUint(t *testing.T) {
606 for _, test := range uint64Tests {
607 p := mustParse(t, test.input)
608 assert.Equal(t, p.Len(), 1)
609 assert.Equal(t, p.GetUint(test.key, uint(test.def)), uint(test.value))
610 }
611 }
612
613 func TestMustGetUint(t *testing.T) {
614 input := "key = 123\nkey2 = ghi"
615 p := mustParse(t, input)
616 assert.Equal(t, p.MustGetUint("key"), uint(123))
617 assert.Panic(t, func() { p.MustGetUint64("key2") }, "strconv.ParseUint: parsing.*")
618 assert.Panic(t, func() { p.MustGetUint64("invalid") }, "unknown property: invalid")
619 }
620
621 func TestGetUint64(t *testing.T) {
622 for _, test := range uint64Tests {
623 p := mustParse(t, test.input)
624 assert.Equal(t, p.Len(), 1)
625 assert.Equal(t, p.GetUint64(test.key, test.def), test.value)
626 }
627 }
628
629 func TestMustGetUint64(t *testing.T) {
630 input := "key = 123\nkey2 = ghi"
631 p := mustParse(t, input)
632 assert.Equal(t, p.MustGetUint64("key"), uint64(123))
633 assert.Panic(t, func() { p.MustGetUint64("key2") }, "strconv.ParseUint: parsing.*")
634 assert.Panic(t, func() { p.MustGetUint64("invalid") }, "unknown property: invalid")
635 }
636
637 func TestGetString(t *testing.T) {
638 for _, test := range stringTests {
639 p := mustParse(t, test.input)
640 assert.Equal(t, p.Len(), 1)
641 assert.Equal(t, p.GetString(test.key, test.def), test.value)
642 }
643 }
644
645 func TestMustGetString(t *testing.T) {
646 input := `key = value`
647 p := mustParse(t, input)
648 assert.Equal(t, p.MustGetString("key"), "value")
649 assert.Panic(t, func() { p.MustGetString("invalid") }, "unknown property: invalid")
650 }
651
652 func TestComment(t *testing.T) {
653 for _, test := range commentTests {
654 p := mustParse(t, test.input)
655 assert.Equal(t, p.MustGetString(test.key), test.value)
656 assert.Equal(t, p.GetComments(test.key), test.comments)
657 if test.comments != nil {
658 assert.Equal(t, p.GetComment(test.key), test.comments[len(test.comments)-1])
659 } else {
660 assert.Equal(t, p.GetComment(test.key), "")
661 }
662
663
664 if len(test.comments) > 0 {
665
666 p.ClearComments()
667 assert.Equal(t, len(p.c), 0)
668 p.SetComment(test.key, test.comments[0])
669 assert.Equal(t, p.GetComment(test.key), test.comments[0])
670
671
672 p.ClearComments()
673 assert.Equal(t, len(p.c), 0)
674 p.SetComments(test.key, test.comments)
675 assert.Equal(t, p.GetComments(test.key), test.comments)
676
677
678 p.SetComments(test.key, nil)
679 assert.Equal(t, p.GetComment(test.key), "")
680 assert.Equal(t, p.GetComments(test.key), ([]string)(nil))
681 }
682 }
683 }
684
685 func TestFilter(t *testing.T) {
686 for _, test := range filterTests {
687 p := mustParse(t, test.input)
688 pp, err := p.Filter(test.pattern)
689 if err != nil {
690 assert.Matches(t, err.Error(), test.err)
691 continue
692 }
693 assert.Equal(t, pp != nil, true, "want properties")
694 assert.Equal(t, pp.Len(), len(test.keys))
695 for _, key := range test.keys {
696 v1, ok1 := p.Get(key)
697 v2, ok2 := pp.Get(key)
698 assert.Equal(t, ok1, true)
699 assert.Equal(t, ok2, true)
700 assert.Equal(t, v1, v2)
701 }
702 }
703 }
704
705 func TestFilterPrefix(t *testing.T) {
706 for _, test := range filterPrefixTests {
707 p := mustParse(t, test.input)
708 pp := p.FilterPrefix(test.prefix)
709 assert.Equal(t, pp != nil, true, "want properties")
710 assert.Equal(t, pp.Len(), len(test.keys))
711 for _, key := range test.keys {
712 v1, ok1 := p.Get(key)
713 v2, ok2 := pp.Get(key)
714 assert.Equal(t, ok1, true)
715 assert.Equal(t, ok2, true)
716 assert.Equal(t, v1, v2)
717 }
718 }
719 }
720
721 func TestFilterStripPrefix(t *testing.T) {
722 for _, test := range filterStripPrefixTests {
723 p := mustParse(t, test.input)
724 pp := p.FilterPrefix(test.prefix)
725 assert.Equal(t, pp != nil, true, "want properties")
726 assert.Equal(t, pp.Len(), len(test.keys))
727 for _, key := range test.keys {
728 v1, ok1 := p.Get(key)
729 v2, ok2 := pp.Get(key)
730 assert.Equal(t, ok1, true)
731 assert.Equal(t, ok2, true)
732 assert.Equal(t, v1, v2)
733 }
734 }
735 }
736
737 func TestKeys(t *testing.T) {
738 for _, test := range keysTests {
739 p := mustParse(t, test.input)
740 assert.Equal(t, p.Len(), len(test.keys))
741 assert.Equal(t, len(p.Keys()), len(test.keys))
742 assert.Equal(t, p.Keys(), test.keys)
743 }
744 }
745
746 func TestSet(t *testing.T) {
747 for _, test := range setTests {
748 p := mustParse(t, test.input)
749 prev, ok, err := p.Set(test.key, test.value)
750 if test.err != "" {
751 assert.Matches(t, err.Error(), test.err)
752 continue
753 }
754
755 assert.Equal(t, err, nil)
756 assert.Equal(t, ok, test.ok)
757 if ok {
758 assert.Equal(t, prev, test.prev)
759 }
760 assert.Equal(t, p.Keys(), test.keys)
761 }
762 }
763
764 func TestSetValue(t *testing.T) {
765 tests := []interface{}{
766 true, false,
767 int8(123), int16(123), int32(123), int64(123), int(123),
768 uint8(123), uint16(123), uint32(123), uint64(123), uint(123),
769 float32(1.23), float64(1.23),
770 "abc",
771 }
772
773 for _, v := range tests {
774 p := NewProperties()
775 err := p.SetValue("x", v)
776 assert.Equal(t, err, nil)
777 assert.Equal(t, p.GetString("x", ""), fmt.Sprintf("%v", v))
778 }
779 }
780
781 func TestMustSet(t *testing.T) {
782 input := "key=${key}"
783 p := mustParse(t, input)
784 e := `circular reference in:\nkey=\$\{key\}`
785 assert.Panic(t, func() { p.MustSet("key", "${key}") }, e)
786 }
787
788 func TestWrite(t *testing.T) {
789 for _, test := range writeTests {
790 p, err := parse(test.input)
791
792 buf := new(bytes.Buffer)
793 var n int
794 switch test.encoding {
795 case "UTF-8":
796 n, err = p.Write(buf, UTF8)
797 case "ISO-8859-1":
798 n, err = p.Write(buf, ISO_8859_1)
799 }
800 assert.Equal(t, err, nil)
801 s := buf.String()
802 assert.Equal(t, n, len(test.output), fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
803 assert.Equal(t, s, test.output, fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
804 }
805 }
806
807 func TestWriteComment(t *testing.T) {
808 for _, test := range writeCommentTests {
809 p, err := parse(test.input)
810
811 buf := new(bytes.Buffer)
812 var n int
813 switch test.encoding {
814 case "UTF-8":
815 n, err = p.WriteComment(buf, "# ", UTF8)
816 case "ISO-8859-1":
817 n, err = p.WriteComment(buf, "# ", ISO_8859_1)
818 }
819 assert.Equal(t, err, nil)
820 s := buf.String()
821 assert.Equal(t, n, len(test.output), fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
822 assert.Equal(t, s, test.output, fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s))
823 }
824 }
825
826 func TestCustomExpansionExpression(t *testing.T) {
827 testKeyValuePrePostfix(t, "*[", "]*", "key=value\nkey2=*[key]*", "key", "value", "key2", "value")
828 }
829
830 func TestPanicOn32BitIntOverflow(t *testing.T) {
831 is32Bit = true
832 var min, max int64 = math.MinInt32 - 1, math.MaxInt32 + 1
833 input := fmt.Sprintf("min=%d\nmax=%d", min, max)
834 p := mustParse(t, input)
835 assert.Equal(t, p.MustGetInt64("min"), min)
836 assert.Equal(t, p.MustGetInt64("max"), max)
837 assert.Panic(t, func() { p.MustGetInt("min") }, ".* out of range")
838 assert.Panic(t, func() { p.MustGetInt("max") }, ".* out of range")
839 }
840
841 func TestPanicOn32BitUintOverflow(t *testing.T) {
842 is32Bit = true
843 var max uint64 = math.MaxUint32 + 1
844 input := fmt.Sprintf("max=%d", max)
845 p := mustParse(t, input)
846 assert.Equal(t, p.MustGetUint64("max"), max)
847 assert.Panic(t, func() { p.MustGetUint("max") }, ".* out of range")
848 }
849
850 func TestDeleteKey(t *testing.T) {
851 input := "#comments should also be gone\nkey=to-be-deleted\nsecond=key"
852 p := mustParse(t, input)
853 assert.Equal(t, len(p.m), 2)
854 assert.Equal(t, len(p.c), 1)
855 assert.Equal(t, len(p.k), 2)
856 p.Delete("key")
857 assert.Equal(t, len(p.m), 1)
858 assert.Equal(t, len(p.c), 0)
859 assert.Equal(t, len(p.k), 1)
860 assert.Equal(t, p.k[0], "second")
861 assert.Equal(t, p.m["second"], "key")
862 }
863
864 func TestDeleteUnknownKey(t *testing.T) {
865 input := "#comments should also be gone\nkey=to-be-deleted"
866 p := mustParse(t, input)
867 assert.Equal(t, len(p.m), 1)
868 assert.Equal(t, len(p.c), 1)
869 assert.Equal(t, len(p.k), 1)
870 p.Delete("wrong-key")
871 assert.Equal(t, len(p.m), 1)
872 assert.Equal(t, len(p.c), 1)
873 assert.Equal(t, len(p.k), 1)
874 }
875
876 func TestMerge(t *testing.T) {
877 input1 := "#comment\nkey=value\nkey2=value2"
878 input2 := "#another comment\nkey=another value\nkey3=value3"
879 p1 := mustParse(t, input1)
880 p2 := mustParse(t, input2)
881 p1.Merge(p2)
882 assert.Equal(t, len(p1.m), 3)
883 assert.Equal(t, len(p1.c), 1)
884 assert.Equal(t, len(p1.k), 3)
885 assert.Equal(t, p1.MustGet("key"), "another value")
886 assert.Equal(t, p1.GetComment("key"), "another comment")
887 }
888
889 func TestMap(t *testing.T) {
890 input := "key=value\nabc=def"
891 p := mustParse(t, input)
892 m := map[string]string{"key": "value", "abc": "def"}
893 assert.Equal(t, p.Map(), m)
894 }
895
896 func TestFilterFunc(t *testing.T) {
897 input := "key=value\nabc=def"
898 p := mustParse(t, input)
899 pp := p.FilterFunc(func(k, v string) bool {
900 return k != "abc"
901 })
902 m := map[string]string{"key": "value"}
903 assert.Equal(t, pp.Map(), m)
904 }
905
906 func TestLoad(t *testing.T) {
907 x := "key=${value}\nvalue=${key}"
908 p := NewProperties()
909 p.DisableExpansion = true
910 err := p.Load([]byte(x), UTF8)
911 assert.Equal(t, err, nil)
912 }
913
914
915
916
917
918
919
920
921
922
923
924
925
926 func BenchmarkMerge(b *testing.B) {
927 for _, n := range []int{1e2, 1e3, 1e4, 1e5} {
928 p := generateProperties(n)
929 b.Run(fmt.Sprintf("num_properties_%d", n), func(b *testing.B) {
930 for i := 0; i < b.N; i++ {
931 p.Merge(p)
932 }
933 })
934 }
935 }
936
937 func generateProperties(n int) *Properties {
938 p := NewProperties()
939 for i := 0; i < n; i++ {
940 s := fmt.Sprintf("%v", i)
941 p.Set(s, s)
942 }
943 return p
944 }
945
946
947
948
949 func testWhitespaceAndDelimiterCombinations(t *testing.T, key, value string) {
950 whitespace := []string{"", " ", "\f", "\t"}
951 delimiters := []string{"", " ", "=", ":"}
952 newlines := []string{"", "\r", "\n", "\r\n"}
953 for _, dl := range delimiters {
954 for _, ws1 := range whitespace {
955 for _, ws2 := range whitespace {
956 for _, nl := range newlines {
957
958 if ws1 == "" && dl == "" && ws2 == "" && value != "" {
959 continue
960 }
961
962 input := fmt.Sprintf("%s%s%s%s%s%s", key, ws1, dl, ws2, value, nl)
963 testKeyValue(t, input, key, value)
964 }
965 }
966 }
967 }
968 }
969
970
971
972 func testKeyValue(t *testing.T, input string, keyvalues ...string) {
973 testKeyValuePrePostfix(t, "${", "}", input, keyvalues...)
974 }
975
976
977
978 func testKeyValuePrePostfix(t *testing.T, prefix, postfix, input string, keyvalues ...string) {
979 p, err := Load([]byte(input), ISO_8859_1)
980 assert.Equal(t, err, nil)
981 p.Prefix = prefix
982 p.Postfix = postfix
983 assertKeyValues(t, input, p, keyvalues...)
984 }
985
986
987
988 func assertKeyValues(t *testing.T, input string, p *Properties, keyvalues ...string) {
989 assert.Equal(t, p != nil, true, "want properties")
990 assert.Equal(t, 2*p.Len(), len(keyvalues), "Odd number of key/value pairs.")
991
992 for i := 0; i < len(keyvalues); i += 2 {
993 key, value := keyvalues[i], keyvalues[i+1]
994 v, ok := p.Get(key)
995 if !ok {
996 t.Errorf("No key %q found (input=%q)", key, input)
997 }
998 if got, want := v, value; !reflect.DeepEqual(got, want) {
999 t.Errorf("Value %q does not match %q (input=%q)", v, value, input)
1000 }
1001 }
1002 }
1003
1004 func mustParse(t *testing.T, s string) *Properties {
1005 p, err := parse(s)
1006 if err != nil {
1007 t.Fatalf("parse failed with %s", err)
1008 }
1009 return p
1010 }
1011
View as plain text