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)