Added tests for Set() Fixed bug in Set() which was not properly checking for circular references. Added MustSet(). Migrated to gopkg.in/check.v1.
diff --git a/README.md b/README.md index 1270e64..bd8b1b5 100644 --- a/README.md +++ b/README.md
@@ -10,6 +10,9 @@ Filenames can also contain environment variables like in `/home/${USER}/myapp.properties`. +Comments and the order of keys are preserved. Comments can be modified +and can be written to the output. + The properties library supports both ISO-8859-1 and UTF-8 encoded data. Starting from version 1.3.0 the behavior of the MustXXX() functions is @@ -41,9 +44,23 @@ $ go get -u github.com/magiconair/properties ``` +For testing and debugging you need the [go-check](https://github.com/go-check/check) library + +``` +$ go get -u gopkg.in/check.v1 +``` + History ------- +v1.5.0, 18 Nov 2014 +------------------- + * Added support for single and multi-line comments (reading, writing and updating) + * The order of keys is now preserved + * Calling Set() with an empty key now silently ignores the call and does not create a new entry + * Added a MustSet() method + * Migrated test library from launchpad.net/gocheck to gopkg.in/check.v1 + v1.4.1, 13 Nov 2014 ------------------- * (Issue #1) Fixed bug in Keys() method which returned an empty string
diff --git a/load_test.go b/load_test.go index 66f9b7c..9d1e3b6 100644 --- a/load_test.go +++ b/load_test.go
@@ -10,7 +10,7 @@ "os" "strings" - . "launchpad.net/gocheck" + . "gopkg.in/check.v1" ) type LoadSuite struct {
diff --git a/properties.go b/properties.go index bba79d5..e9aca7a 100644 --- a/properties.go +++ b/properties.go
@@ -430,15 +430,49 @@ // contains the previous value. If the value contains a // circular reference or a malformed expression then // an error is returned. +// An empty key is silently ignored. func (p *Properties) Set(key, value string) (prev string, ok bool, err error) { + if key == "" { + return "", false, nil + } + + // to check for a circular reference we temporarily need + // to set the new value. If there is an error then revert + // to the previous state. Only if all tests are successful + // then we add the key to the p.k list. + prev, ok = p.Get(key) + p.m[key] = value + + // now check for a circular reference _, err = p.expand(value) if err != nil { + + // revert to the previous state + if ok { + p.m[key] = prev + } else { + delete(p.m, key) + } + return "", false, err } - v, ok := p.Get(key) - p.m[key] = value - return v, ok, nil + if !ok { + p.k = append(p.k, key) + } + + return prev, ok, nil +} + +// MustSet sets the property key to the corresponding value. +// If a value for key existed before then ok is true and prev +// contains the previous value. An empty key is silently ignored. +func (p *Properties) MustSet(key, value string) (prev string, ok bool) { + prev, ok, err := p.Set(key, value) + if err != nil { + ErrorHandler(err) + } + return prev, ok } // String returns a string of all expanded 'key = value' pairs.
diff --git a/properties_test.go b/properties_test.go index fa998ef..fda5b15 100644 --- a/properties_test.go +++ b/properties_test.go
@@ -14,7 +14,7 @@ "testing" "time" - . "launchpad.net/gocheck" + . "gopkg.in/check.v1" ) func Test(t *testing.T) { TestingT(t) } @@ -376,6 +376,23 @@ // ---------------------------------------------------------------------------- +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 (l *TestSuite) TestBasic(c *C) { @@ -630,6 +647,32 @@ } } +func (l *TestSuite) TestSet(c *C) { + for _, test := range setTests { + p, err := parse(test.input) + c.Assert(err, IsNil) + prev, ok, err := p.Set(test.key, test.value) + if test.err != "" { + c.Assert(err, ErrorMatches, test.err) + continue + } + + c.Assert(err, IsNil) + c.Assert(ok, Equals, test.ok) + if ok { + c.Assert(prev, Equals, test.prev) + } + c.Assert(p.Keys(), DeepEquals, test.keys) + } +} + +func (l *TestSuite) TestMustSet(c *C) { + input := "key=${key}" + p, err := parse(input) + c.Assert(err, IsNil) + c.Assert(func() { p.MustSet("key", "${key}") }, PanicMatches, "Circular reference .*") +} + func (l *TestSuite) TestWrite(c *C) { for _, test := range writeTests { p, err := parse(test.input)