From 54d3d47daf9190275bbdaf8703b84969a4593451 Mon Sep 17 00:00:00 2001 From: Corey Hulen Date: Fri, 24 Mar 2017 23:31:34 -0700 Subject: PLT-6076 Adding viper libs for config file changes (#5871) * Adding viper libs for config file changes * Removing the old fsnotify lib * updating some missing libs --- .../magiconair/properties/properties_test.go | 934 +++++++++++++++++++++ 1 file changed, 934 insertions(+) create mode 100644 vendor/github.com/magiconair/properties/properties_test.go (limited to 'vendor/github.com/magiconair/properties/properties_test.go') diff --git a/vendor/github.com/magiconair/properties/properties_test.go b/vendor/github.com/magiconair/properties/properties_test.go new file mode 100644 index 000000000..0eac1f492 --- /dev/null +++ b/vendor/github.com/magiconair/properties/properties_test.go @@ -0,0 +1,934 @@ +// Copyright 2017 Frank Schroeder. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package properties + +import ( + "bytes" + "flag" + "fmt" + "math" + "os" + "reflect" + "strings" + "testing" + "time" + + "github.com/magiconair/properties/assert" +) + +var verbose = flag.Bool("verbose", false, "Verbose output") + +func init() { + ErrorHandler = PanicHandler +} + +// ---------------------------------------------------------------------------- + +// define test cases in the form of +// {"input", "key1", "value1", "key2", "value2", ...} +var complexTests = [][]string{ + // whitespace prefix + {" key=value", "key", "value"}, // SPACE prefix + {"\fkey=value", "key", "value"}, // FF prefix + {"\tkey=value", "key", "value"}, // TAB prefix + {" \f\tkey=value", "key", "value"}, // mix prefix + + // multiple keys + {"key1=value1\nkey2=value2\n", "key1", "value1", "key2", "value2"}, + {"key1=value1\rkey2=value2\r", "key1", "value1", "key2", "value2"}, + {"key1=value1\r\nkey2=value2\r\n", "key1", "value1", "key2", "value2"}, + + // blank lines + {"\nkey=value\n", "key", "value"}, + {"\rkey=value\r", "key", "value"}, + {"\r\nkey=value\r\n", "key", "value"}, + + // escaped chars in key + {"k\\ ey = value", "k ey", "value"}, + {"k\\:ey = value", "k:ey", "value"}, + {"k\\=ey = value", "k=ey", "value"}, + {"k\\fey = value", "k\fey", "value"}, + {"k\\ney = value", "k\ney", "value"}, + {"k\\rey = value", "k\rey", "value"}, + {"k\\tey = value", "k\tey", "value"}, + + // escaped chars in value + {"key = v\\ alue", "key", "v alue"}, + {"key = v\\:alue", "key", "v:alue"}, + {"key = v\\=alue", "key", "v=alue"}, + {"key = v\\falue", "key", "v\falue"}, + {"key = v\\nalue", "key", "v\nalue"}, + {"key = v\\ralue", "key", "v\ralue"}, + {"key = v\\talue", "key", "v\talue"}, + + // silently dropped escape character + {"k\\zey = value", "kzey", "value"}, + {"key = v\\zalue", "key", "vzalue"}, + + // unicode literals + {"key\\u2318 = value", "key⌘", "value"}, + {"k\\u2318ey = value", "k⌘ey", "value"}, + {"key = value\\u2318", "key", "value⌘"}, + {"key = valu\\u2318e", "key", "valu⌘e"}, + + // multiline values + {"key = valueA,\\\n valueB", "key", "valueA,valueB"}, // SPACE indent + {"key = valueA,\\\n\f\f\fvalueB", "key", "valueA,valueB"}, // FF indent + {"key = valueA,\\\n\t\t\tvalueB", "key", "valueA,valueB"}, // TAB indent + {"key = valueA,\\\n \f\tvalueB", "key", "valueA,valueB"}, // mix indent + + // comments + {"# 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"}, + + // expansion tests + {"key=value\nkey2=${key}", "key", "value", "key2", "value"}, + {"key=value\nkey2=aa${key}", "key", "value", "key2", "aavalue"}, + {"key=value\nkey2=${key}bb", "key", "value", "key2", "valuebb"}, + {"key=value\nkey2=aa${key}bb", "key", "value", "key2", "aavaluebb"}, + {"key=value\nkey2=${key}\nkey3=${key2}", "key", "value", "key2", "value", "key3", "value"}, + {"key=${USER}", "key", os.Getenv("USER")}, + {"key=${USER}\nUSER=value", "key", "value", "USER", "value"}, +} + +// ---------------------------------------------------------------------------- + +var commentTests = []struct { + input, key, value string + comments []string +}{ + {"key=value", "key", "value", nil}, + {"#\nkey=value", "key", "value", []string{""}}, + {"#comment\nkey=value", "key", "value", []string{"comment"}}, + {"# comment\nkey=value", "key", "value", []string{"comment"}}, + {"# comment\nkey=value", "key", "value", []string{"comment"}}, + {"# comment\n\nkey=value", "key", "value", []string{"comment"}}, + {"# comment1\n# comment2\nkey=value", "key", "value", []string{"comment1", "comment2"}}, + {"# comment1\n\n# comment2\n\nkey=value", "key", "value", []string{"comment1", "comment2"}}, + {"!comment\nkey=value", "key", "value", []string{"comment"}}, + {"! comment\nkey=value", "key", "value", []string{"comment"}}, + {"! comment\nkey=value", "key", "value", []string{"comment"}}, + {"! comment\n\nkey=value", "key", "value", []string{"comment"}}, + {"! comment1\n! comment2\nkey=value", "key", "value", []string{"comment1", "comment2"}}, + {"! comment1\n\n! comment2\n\nkey=value", "key", "value", []string{"comment1", "comment2"}}, +} + +// ---------------------------------------------------------------------------- + +var errorTests = []struct { + input, msg string +}{ + // unicode literals + {"key\\u1 = value", "invalid unicode literal"}, + {"key\\u12 = value", "invalid unicode literal"}, + {"key\\u123 = value", "invalid unicode literal"}, + {"key\\u123g = value", "invalid unicode literal"}, + {"key\\u123", "invalid unicode literal"}, + + // circular references + {"key=${key}", "circular reference"}, + {"key1=${key2}\nkey2=${key1}", "circular reference"}, + + // malformed expressions + {"key=${ke", "malformed expression"}, + {"key=valu${ke", "malformed expression"}, +} + +// ---------------------------------------------------------------------------- + +var writeTests = []struct { + input, output, encoding string +}{ + // ISO-8859-1 tests + {"key = value", "key = value\n", "ISO-8859-1"}, + {"key = value \\\n continued", "key = value continued\n", "ISO-8859-1"}, + {"key⌘ = value", "key\\u2318 = value\n", "ISO-8859-1"}, + {"ke\\ \\:y = value", "ke\\ \\:y = value\n", "ISO-8859-1"}, + + // UTF-8 tests + {"key = value", "key = value\n", "UTF-8"}, + {"key = value \\\n continued", "key = value continued\n", "UTF-8"}, + {"key⌘ = value⌘", "key⌘ = value⌘\n", "UTF-8"}, + {"ke\\ \\:y = value", "ke\\ \\:y = value\n", "UTF-8"}, +} + +// ---------------------------------------------------------------------------- + +var writeCommentTests = []struct { + input, output, encoding string +}{ + // ISO-8859-1 tests + {"key = value", "key = value\n", "ISO-8859-1"}, + {"#\nkey = value", "key = value\n", "ISO-8859-1"}, + {"#\n#\n#\nkey = value", "key = value\n", "ISO-8859-1"}, + {"# comment\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"}, + {"\n# comment\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"}, + {"# comment\n\nkey = value", "# comment\nkey = value\n", "ISO-8859-1"}, + {"# comment1\n# comment2\nkey = value", "# comment1\n# comment2\nkey = value\n", "ISO-8859-1"}, + {"#comment1\nkey1 = value1\n#comment2\nkey2 = value2", "# comment1\nkey1 = value1\n\n# comment2\nkey2 = value2\n", "ISO-8859-1"}, + + // UTF-8 tests + {"key = value", "key = value\n", "UTF-8"}, + {"# comment⌘\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"}, + {"\n# comment⌘\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"}, + {"# comment⌘\n\nkey = value⌘", "# comment⌘\nkey = value⌘\n", "UTF-8"}, + {"# comment1⌘\n# comment2⌘\nkey = value⌘", "# comment1⌘\n# comment2⌘\nkey = value⌘\n", "UTF-8"}, + {"#comment1⌘\nkey1 = value1⌘\n#comment2⌘\nkey2 = value2⌘", "# comment1⌘\nkey1 = value1⌘\n\n# comment2⌘\nkey2 = value2⌘\n", "UTF-8"}, +} + +// ---------------------------------------------------------------------------- + +var boolTests = []struct { + input, key string + def, value bool +}{ + // valid values for TRUE + {"key = 1", "key", false, true}, + {"key = on", "key", false, true}, + {"key = On", "key", false, true}, + {"key = ON", "key", false, true}, + {"key = true", "key", false, true}, + {"key = True", "key", false, true}, + {"key = TRUE", "key", false, true}, + {"key = yes", "key", false, true}, + {"key = Yes", "key", false, true}, + {"key = YES", "key", false, true}, + + // valid values for FALSE (all other) + {"key = 0", "key", true, false}, + {"key = off", "key", true, false}, + {"key = false", "key", true, false}, + {"key = no", "key", true, false}, + + // non existent key + {"key = true", "key2", false, false}, +} + +// ---------------------------------------------------------------------------- + +var durationTests = []struct { + input, key string + def, value time.Duration +}{ + // valid values + {"key = 1", "key", 999, 1}, + {"key = 0", "key", 999, 0}, + {"key = -1", "key", 999, -1}, + {"key = 0123", "key", 999, 123}, + + // invalid values + {"key = 0xff", "key", 999, 999}, + {"key = 1.0", "key", 999, 999}, + {"key = a", "key", 999, 999}, + + // non existent key + {"key = 1", "key2", 999, 999}, +} + +// ---------------------------------------------------------------------------- + +var parsedDurationTests = []struct { + input, key string + def, value time.Duration +}{ + // valid values + {"key = -1ns", "key", 999, -1 * time.Nanosecond}, + {"key = 300ms", "key", 999, 300 * time.Millisecond}, + {"key = 5s", "key", 999, 5 * time.Second}, + {"key = 3h", "key", 999, 3 * time.Hour}, + {"key = 2h45m", "key", 999, 2*time.Hour + 45*time.Minute}, + + // invalid values + {"key = 0xff", "key", 999, 999}, + {"key = 1.0", "key", 999, 999}, + {"key = a", "key", 999, 999}, + {"key = 1", "key", 999, 999}, + {"key = 0", "key", 999, 0}, + + // non existent key + {"key = 1", "key2", 999, 999}, +} + +// ---------------------------------------------------------------------------- + +var floatTests = []struct { + input, key string + def, value float64 +}{ + // valid values + {"key = 1.0", "key", 999, 1.0}, + {"key = 0.0", "key", 999, 0.0}, + {"key = -1.0", "key", 999, -1.0}, + {"key = 1", "key", 999, 1}, + {"key = 0", "key", 999, 0}, + {"key = -1", "key", 999, -1}, + {"key = 0123", "key", 999, 123}, + + // invalid values + {"key = 0xff", "key", 999, 999}, + {"key = a", "key", 999, 999}, + + // non existent key + {"key = 1", "key2", 999, 999}, +} + +// ---------------------------------------------------------------------------- + +var int64Tests = []struct { + input, key string + def, value int64 +}{ + // valid values + {"key = 1", "key", 999, 1}, + {"key = 0", "key", 999, 0}, + {"key = -1", "key", 999, -1}, + {"key = 0123", "key", 999, 123}, + + // invalid values + {"key = 0xff", "key", 999, 999}, + {"key = 1.0", "key", 999, 999}, + {"key = a", "key", 999, 999}, + + // non existent key + {"key = 1", "key2", 999, 999}, +} + +// ---------------------------------------------------------------------------- + +var uint64Tests = []struct { + input, key string + def, value uint64 +}{ + // valid values + {"key = 1", "key", 999, 1}, + {"key = 0", "key", 999, 0}, + {"key = 0123", "key", 999, 123}, + + // invalid values + {"key = -1", "key", 999, 999}, + {"key = 0xff", "key", 999, 999}, + {"key = 1.0", "key", 999, 999}, + {"key = a", "key", 999, 999}, + + // non existent key + {"key = 1", "key2", 999, 999}, +} + +// ---------------------------------------------------------------------------- + +var stringTests = []struct { + input, key string + def, value string +}{ + // valid values + {"key = abc", "key", "def", "abc"}, + + // non existent key + {"key = abc", "key2", "def", "def"}, +} + +// ---------------------------------------------------------------------------- + +var keysTests = []struct { + input string + keys []string +}{ + {"", []string{}}, + {"key = abc", []string{"key"}}, + {"key = abc\nkey2=def", []string{"key", "key2"}}, + {"key2 = abc\nkey=def", []string{"key2", "key"}}, + {"key = abc\nkey=def", []string{"key"}}, +} + +// ---------------------------------------------------------------------------- + +var filterTests = []struct { + input string + pattern string + keys []string + err string +}{ + {"", "", []string{}, ""}, + {"", "abc", []string{}, ""}, + {"key=value", "", []string{"key"}, ""}, + {"key=value", "key=", []string{}, ""}, + {"key=value\nfoo=bar", "", []string{"foo", "key"}, ""}, + {"key=value\nfoo=bar", "f", []string{"foo"}, ""}, + {"key=value\nfoo=bar", "fo", []string{"foo"}, ""}, + {"key=value\nfoo=bar", "foo", []string{"foo"}, ""}, + {"key=value\nfoo=bar", "fooo", []string{}, ""}, + {"key=value\nkey2=value2\nfoo=bar", "ey", []string{"key", "key2"}, ""}, + {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}, ""}, + {"key=value\nkey2=value2\nfoo=bar", "^key", []string{"key", "key2"}, ""}, + {"key=value\nkey2=value2\nfoo=bar", "^(key|foo)", []string{"foo", "key", "key2"}, ""}, + {"key=value\nkey2=value2\nfoo=bar", "[ abc", nil, "error parsing regexp.*"}, +} + +// ---------------------------------------------------------------------------- + +var filterPrefixTests = []struct { + input string + prefix string + keys []string +}{ + {"", "", []string{}}, + {"", "abc", []string{}}, + {"key=value", "", []string{"key"}}, + {"key=value", "key=", []string{}}, + {"key=value\nfoo=bar", "", []string{"foo", "key"}}, + {"key=value\nfoo=bar", "f", []string{"foo"}}, + {"key=value\nfoo=bar", "fo", []string{"foo"}}, + {"key=value\nfoo=bar", "foo", []string{"foo"}}, + {"key=value\nfoo=bar", "fooo", []string{}}, + {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}}, +} + +// ---------------------------------------------------------------------------- + +var filterStripPrefixTests = []struct { + input string + prefix string + keys []string +}{ + {"", "", []string{}}, + {"", "abc", []string{}}, + {"key=value", "", []string{"key"}}, + {"key=value", "key=", []string{}}, + {"key=value\nfoo=bar", "", []string{"foo", "key"}}, + {"key=value\nfoo=bar", "f", []string{"foo"}}, + {"key=value\nfoo=bar", "fo", []string{"foo"}}, + {"key=value\nfoo=bar", "foo", []string{"foo"}}, + {"key=value\nfoo=bar", "fooo", []string{}}, + {"key=value\nkey2=value2\nfoo=bar", "key", []string{"key", "key2"}}, +} + +// ---------------------------------------------------------------------------- + +var setTests = []struct { + input string + key, value string + prev string + ok bool + err string + keys []string +}{ + {"", "", "", "", false, "", []string{}}, + {"", "key", "value", "", false, "", []string{"key"}}, + {"key=value", "key2", "value2", "", false, "", []string{"key", "key2"}}, + {"key=value", "abc", "value3", "", false, "", []string{"key", "abc"}}, + {"key=value", "key", "value3", "value", true, "", []string{"key"}}, +} + +// ---------------------------------------------------------------------------- + +// TestBasic tests basic single key/value combinations with all possible +// whitespace, delimiter and newline permutations. +func TestBasic(t *testing.T) { + testWhitespaceAndDelimiterCombinations(t, "key", "") + testWhitespaceAndDelimiterCombinations(t, "key", "value") + testWhitespaceAndDelimiterCombinations(t, "key", "value ") +} + +func TestComplex(t *testing.T) { + for _, test := range complexTests { + testKeyValue(t, test[0], test[1:]...) + } +} + +func TestErrors(t *testing.T) { + for _, test := range errorTests { + _, err := Load([]byte(test.input), ISO_8859_1) + assert.Equal(t, err != nil, true, "want error") + assert.Equal(t, strings.Contains(err.Error(), test.msg), true) + } +} + +func TestDisableExpansion(t *testing.T) { + input := "key=value\nkey2=${key}" + p := mustParse(t, input) + p.DisableExpansion = true + assert.Equal(t, p.MustGet("key"), "value") + assert.Equal(t, p.MustGet("key2"), "${key}") + + // with expansion disabled we can introduce circular references + p.MustSet("keyA", "${keyB}") + p.MustSet("keyB", "${keyA}") + assert.Equal(t, p.MustGet("keyA"), "${keyB}") + assert.Equal(t, p.MustGet("keyB"), "${keyA}") +} + +func TestMustGet(t *testing.T) { + input := "key = value\nkey2 = ghi" + p := mustParse(t, input) + assert.Equal(t, p.MustGet("key"), "value") + assert.Panic(t, func() { p.MustGet("invalid") }, "unknown property: invalid") +} + +func TestGetBool(t *testing.T) { + for _, test := range boolTests { + p := mustParse(t, test.input) + assert.Equal(t, p.Len(), 1) + assert.Equal(t, p.GetBool(test.key, test.def), test.value) + } +} + +func TestMustGetBool(t *testing.T) { + input := "key = true\nkey2 = ghi" + p := mustParse(t, input) + assert.Equal(t, p.MustGetBool("key"), true) + assert.Panic(t, func() { p.MustGetBool("invalid") }, "unknown property: invalid") +} + +func TestGetDuration(t *testing.T) { + for _, test := range durationTests { + p := mustParse(t, test.input) + assert.Equal(t, p.Len(), 1) + assert.Equal(t, p.GetDuration(test.key, test.def), test.value) + } +} + +func TestMustGetDuration(t *testing.T) { + input := "key = 123\nkey2 = ghi" + p := mustParse(t, input) + assert.Equal(t, p.MustGetDuration("key"), time.Duration(123)) + assert.Panic(t, func() { p.MustGetDuration("key2") }, "strconv.ParseInt: parsing.*") + assert.Panic(t, func() { p.MustGetDuration("invalid") }, "unknown property: invalid") +} + +func TestGetParsedDuration(t *testing.T) { + for _, test := range parsedDurationTests { + p := mustParse(t, test.input) + assert.Equal(t, p.Len(), 1) + assert.Equal(t, p.GetParsedDuration(test.key, test.def), test.value) + } +} + +func TestMustGetParsedDuration(t *testing.T) { + input := "key = 123ms\nkey2 = ghi" + p := mustParse(t, input) + assert.Equal(t, p.MustGetParsedDuration("key"), 123*time.Millisecond) + assert.Panic(t, func() { p.MustGetParsedDuration("key2") }, "time: invalid duration ghi") + assert.Panic(t, func() { p.MustGetParsedDuration("invalid") }, "unknown property: invalid") +} + +func TestGetFloat64(t *testing.T) { + for _, test := range floatTests { + p := mustParse(t, test.input) + assert.Equal(t, p.Len(), 1) + assert.Equal(t, p.GetFloat64(test.key, test.def), test.value) + } +} + +func TestMustGetFloat64(t *testing.T) { + input := "key = 123\nkey2 = ghi" + p := mustParse(t, input) + assert.Equal(t, p.MustGetFloat64("key"), float64(123)) + assert.Panic(t, func() { p.MustGetFloat64("key2") }, "strconv.ParseFloat: parsing.*") + assert.Panic(t, func() { p.MustGetFloat64("invalid") }, "unknown property: invalid") +} + +func TestGetInt(t *testing.T) { + for _, test := range int64Tests { + p := mustParse(t, test.input) + assert.Equal(t, p.Len(), 1) + assert.Equal(t, p.GetInt(test.key, int(test.def)), int(test.value)) + } +} + +func TestMustGetInt(t *testing.T) { + input := "key = 123\nkey2 = ghi" + p := mustParse(t, input) + assert.Equal(t, p.MustGetInt("key"), int(123)) + assert.Panic(t, func() { p.MustGetInt("key2") }, "strconv.ParseInt: parsing.*") + assert.Panic(t, func() { p.MustGetInt("invalid") }, "unknown property: invalid") +} + +func TestGetInt64(t *testing.T) { + for _, test := range int64Tests { + p := mustParse(t, test.input) + assert.Equal(t, p.Len(), 1) + assert.Equal(t, p.GetInt64(test.key, test.def), test.value) + } +} + +func TestMustGetInt64(t *testing.T) { + input := "key = 123\nkey2 = ghi" + p := mustParse(t, input) + assert.Equal(t, p.MustGetInt64("key"), int64(123)) + assert.Panic(t, func() { p.MustGetInt64("key2") }, "strconv.ParseInt: parsing.*") + assert.Panic(t, func() { p.MustGetInt64("invalid") }, "unknown property: invalid") +} + +func TestGetUint(t *testing.T) { + for _, test := range uint64Tests { + p := mustParse(t, test.input) + assert.Equal(t, p.Len(), 1) + assert.Equal(t, p.GetUint(test.key, uint(test.def)), uint(test.value)) + } +} + +func TestMustGetUint(t *testing.T) { + input := "key = 123\nkey2 = ghi" + p := mustParse(t, input) + assert.Equal(t, p.MustGetUint("key"), uint(123)) + assert.Panic(t, func() { p.MustGetUint64("key2") }, "strconv.ParseUint: parsing.*") + assert.Panic(t, func() { p.MustGetUint64("invalid") }, "unknown property: invalid") +} + +func TestGetUint64(t *testing.T) { + for _, test := range uint64Tests { + p := mustParse(t, test.input) + assert.Equal(t, p.Len(), 1) + assert.Equal(t, p.GetUint64(test.key, test.def), test.value) + } +} + +func TestMustGetUint64(t *testing.T) { + input := "key = 123\nkey2 = ghi" + p := mustParse(t, input) + assert.Equal(t, p.MustGetUint64("key"), uint64(123)) + assert.Panic(t, func() { p.MustGetUint64("key2") }, "strconv.ParseUint: parsing.*") + assert.Panic(t, func() { p.MustGetUint64("invalid") }, "unknown property: invalid") +} + +func TestGetString(t *testing.T) { + for _, test := range stringTests { + p := mustParse(t, test.input) + assert.Equal(t, p.Len(), 1) + assert.Equal(t, p.GetString(test.key, test.def), test.value) + } +} + +func TestMustGetString(t *testing.T) { + input := `key = value` + p := mustParse(t, input) + assert.Equal(t, p.MustGetString("key"), "value") + assert.Panic(t, func() { p.MustGetString("invalid") }, "unknown property: invalid") +} + +func TestComment(t *testing.T) { + for _, test := range commentTests { + p := mustParse(t, test.input) + assert.Equal(t, p.MustGetString(test.key), test.value) + assert.Equal(t, p.GetComments(test.key), test.comments) + if test.comments != nil { + assert.Equal(t, p.GetComment(test.key), test.comments[len(test.comments)-1]) + } else { + assert.Equal(t, p.GetComment(test.key), "") + } + + // test setting comments + if len(test.comments) > 0 { + // set single comment + p.ClearComments() + assert.Equal(t, len(p.c), 0) + p.SetComment(test.key, test.comments[0]) + assert.Equal(t, p.GetComment(test.key), test.comments[0]) + + // set multiple comments + p.ClearComments() + assert.Equal(t, len(p.c), 0) + p.SetComments(test.key, test.comments) + assert.Equal(t, p.GetComments(test.key), test.comments) + + // clear comments for a key + p.SetComments(test.key, nil) + assert.Equal(t, p.GetComment(test.key), "") + assert.Equal(t, p.GetComments(test.key), ([]string)(nil)) + } + } +} + +func TestFilter(t *testing.T) { + for _, test := range filterTests { + p := mustParse(t, test.input) + pp, err := p.Filter(test.pattern) + if err != nil { + assert.Matches(t, err.Error(), test.err) + continue + } + assert.Equal(t, pp != nil, true, "want properties") + assert.Equal(t, pp.Len(), len(test.keys)) + for _, key := range test.keys { + v1, ok1 := p.Get(key) + v2, ok2 := pp.Get(key) + assert.Equal(t, ok1, true) + assert.Equal(t, ok2, true) + assert.Equal(t, v1, v2) + } + } +} + +func TestFilterPrefix(t *testing.T) { + for _, test := range filterPrefixTests { + p := mustParse(t, test.input) + pp := p.FilterPrefix(test.prefix) + assert.Equal(t, pp != nil, true, "want properties") + assert.Equal(t, pp.Len(), len(test.keys)) + for _, key := range test.keys { + v1, ok1 := p.Get(key) + v2, ok2 := pp.Get(key) + assert.Equal(t, ok1, true) + assert.Equal(t, ok2, true) + assert.Equal(t, v1, v2) + } + } +} + +func TestFilterStripPrefix(t *testing.T) { + for _, test := range filterStripPrefixTests { + p := mustParse(t, test.input) + pp := p.FilterPrefix(test.prefix) + assert.Equal(t, pp != nil, true, "want properties") + assert.Equal(t, pp.Len(), len(test.keys)) + for _, key := range test.keys { + v1, ok1 := p.Get(key) + v2, ok2 := pp.Get(key) + assert.Equal(t, ok1, true) + assert.Equal(t, ok2, true) + assert.Equal(t, v1, v2) + } + } +} + +func TestKeys(t *testing.T) { + for _, test := range keysTests { + p := mustParse(t, test.input) + assert.Equal(t, p.Len(), len(test.keys)) + assert.Equal(t, len(p.Keys()), len(test.keys)) + assert.Equal(t, p.Keys(), test.keys) + } +} + +func TestSet(t *testing.T) { + for _, test := range setTests { + p := mustParse(t, test.input) + prev, ok, err := p.Set(test.key, test.value) + if test.err != "" { + assert.Matches(t, err.Error(), test.err) + continue + } + + assert.Equal(t, err, nil) + assert.Equal(t, ok, test.ok) + if ok { + assert.Equal(t, prev, test.prev) + } + assert.Equal(t, p.Keys(), test.keys) + } +} + +func TestSetValue(t *testing.T) { + tests := []interface{}{ + true, false, + int8(123), int16(123), int32(123), int64(123), int(123), + uint8(123), uint16(123), uint32(123), uint64(123), uint(123), + float32(1.23), float64(1.23), + "abc", + } + + for _, v := range tests { + p := NewProperties() + err := p.SetValue("x", v) + assert.Equal(t, err, nil) + assert.Equal(t, p.GetString("x", ""), fmt.Sprintf("%v", v)) + } +} + +func TestMustSet(t *testing.T) { + input := "key=${key}" + p := mustParse(t, input) + assert.Panic(t, func() { p.MustSet("key", "${key}") }, "circular reference .*") +} + +func TestWrite(t *testing.T) { + for _, test := range writeTests { + p, err := parse(test.input) + + buf := new(bytes.Buffer) + var n int + switch test.encoding { + case "UTF-8": + n, err = p.Write(buf, UTF8) + case "ISO-8859-1": + n, err = p.Write(buf, ISO_8859_1) + } + assert.Equal(t, err, nil) + s := string(buf.Bytes()) + assert.Equal(t, n, len(test.output), fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s)) + assert.Equal(t, s, test.output, fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s)) + } +} + +func TestWriteComment(t *testing.T) { + for _, test := range writeCommentTests { + p, err := parse(test.input) + + buf := new(bytes.Buffer) + var n int + switch test.encoding { + case "UTF-8": + n, err = p.WriteComment(buf, "# ", UTF8) + case "ISO-8859-1": + n, err = p.WriteComment(buf, "# ", ISO_8859_1) + } + assert.Equal(t, err, nil) + s := string(buf.Bytes()) + assert.Equal(t, n, len(test.output), fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s)) + assert.Equal(t, s, test.output, fmt.Sprintf("input=%q expected=%q obtained=%q", test.input, test.output, s)) + } +} + +func TestCustomExpansionExpression(t *testing.T) { + testKeyValuePrePostfix(t, "*[", "]*", "key=value\nkey2=*[key]*", "key", "value", "key2", "value") +} + +func TestPanicOn32BitIntOverflow(t *testing.T) { + is32Bit = true + var min, max int64 = math.MinInt32 - 1, math.MaxInt32 + 1 + input := fmt.Sprintf("min=%d\nmax=%d", min, max) + p := mustParse(t, input) + assert.Equal(t, p.MustGetInt64("min"), min) + assert.Equal(t, p.MustGetInt64("max"), max) + assert.Panic(t, func() { p.MustGetInt("min") }, ".* out of range") + assert.Panic(t, func() { p.MustGetInt("max") }, ".* out of range") +} + +func TestPanicOn32BitUintOverflow(t *testing.T) { + is32Bit = true + var max uint64 = math.MaxUint32 + 1 + input := fmt.Sprintf("max=%d", max) + p := mustParse(t, input) + assert.Equal(t, p.MustGetUint64("max"), max) + assert.Panic(t, func() { p.MustGetUint("max") }, ".* out of range") +} + +func TestDeleteKey(t *testing.T) { + input := "#comments should also be gone\nkey=to-be-deleted\nsecond=key" + p := mustParse(t, input) + assert.Equal(t, len(p.m), 2) + assert.Equal(t, len(p.c), 1) + assert.Equal(t, len(p.k), 2) + p.Delete("key") + assert.Equal(t, len(p.m), 1) + assert.Equal(t, len(p.c), 0) + assert.Equal(t, len(p.k), 1) + assert.Equal(t, p.k[0], "second") + assert.Equal(t, p.m["second"], "key") +} + +func TestDeleteUnknownKey(t *testing.T) { + input := "#comments should also be gone\nkey=to-be-deleted" + p := mustParse(t, input) + assert.Equal(t, len(p.m), 1) + assert.Equal(t, len(p.c), 1) + assert.Equal(t, len(p.k), 1) + p.Delete("wrong-key") + assert.Equal(t, len(p.m), 1) + assert.Equal(t, len(p.c), 1) + assert.Equal(t, len(p.k), 1) +} + +func TestMerge(t *testing.T) { + input1 := "#comment\nkey=value\nkey2=value2" + input2 := "#another comment\nkey=another value\nkey3=value3" + p1 := mustParse(t, input1) + p2 := mustParse(t, input2) + p1.Merge(p2) + assert.Equal(t, len(p1.m), 3) + assert.Equal(t, len(p1.c), 1) + assert.Equal(t, len(p1.k), 3) + assert.Equal(t, p1.MustGet("key"), "another value") + assert.Equal(t, p1.GetComment("key"), "another comment") +} + +func TestMap(t *testing.T) { + input := "key=value\nabc=def" + p := mustParse(t, input) + m := map[string]string{"key": "value", "abc": "def"} + assert.Equal(t, p.Map(), m) +} + +func TestFilterFunc(t *testing.T) { + input := "key=value\nabc=def" + p := mustParse(t, input) + pp := p.FilterFunc(func(k, v string) bool { + return k != "abc" + }) + m := map[string]string{"key": "value"} + assert.Equal(t, pp.Map(), m) +} + +// ---------------------------------------------------------------------------- + +// tests all combinations of delimiters, leading and/or trailing whitespace and newlines. +func testWhitespaceAndDelimiterCombinations(t *testing.T, key, value string) { + whitespace := []string{"", " ", "\f", "\t"} + delimiters := []string{"", " ", "=", ":"} + newlines := []string{"", "\r", "\n", "\r\n"} + for _, dl := range delimiters { + for _, ws1 := range whitespace { + for _, ws2 := range whitespace { + for _, nl := range newlines { + // skip the one case where there is nothing between a key and a value + if ws1 == "" && dl == "" && ws2 == "" && value != "" { + continue + } + + input := fmt.Sprintf("%s%s%s%s%s%s", key, ws1, dl, ws2, value, nl) + testKeyValue(t, input, key, value) + } + } + } + } +} + +// tests whether key/value pairs exist for a given input. +// keyvalues is expected to be an even number of strings of "key", "value", ... +func testKeyValue(t *testing.T, input string, keyvalues ...string) { + testKeyValuePrePostfix(t, "${", "}", input, keyvalues...) +} + +// tests whether key/value pairs exist for a given input. +// keyvalues is expected to be an even number of strings of "key", "value", ... +func testKeyValuePrePostfix(t *testing.T, prefix, postfix, input string, keyvalues ...string) { + p, err := Load([]byte(input), ISO_8859_1) + assert.Equal(t, err, nil) + p.Prefix = prefix + p.Postfix = postfix + assertKeyValues(t, input, p, keyvalues...) +} + +// tests whether key/value pairs exist for a given input. +// keyvalues is expected to be an even number of strings of "key", "value", ... +func assertKeyValues(t *testing.T, input string, p *Properties, keyvalues ...string) { + assert.Equal(t, p != nil, true, "want properties") + assert.Equal(t, 2*p.Len(), len(keyvalues), "Odd number of key/value pairs.") + + for i := 0; i < len(keyvalues); i += 2 { + key, value := keyvalues[i], keyvalues[i+1] + v, ok := p.Get(key) + if !ok { + t.Errorf("No key %q found (input=%q)", key, input) + } + if got, want := v, value; !reflect.DeepEqual(got, want) { + t.Errorf("Value %q does not match %q (input=%q)", v, value, input) + } + } +} + +func mustParse(t *testing.T, s string) *Properties { + p, err := parse(s) + if err != nil { + t.Fatalf("parse failed with %s", err) + } + return p +} + +// prints to stderr if the -verbose flag was given. +func printf(format string, args ...interface{}) { + if *verbose { + fmt.Fprintf(os.Stderr, format, args...) + } +} -- cgit v1.2.3-1-g7c22