add cnf/json parse() and get() + minimal tests
This commit is contained in:
parent
05e6b5a847
commit
ad7c79d2f9
|
@ -0,0 +1,54 @@
|
||||||
|
package cnf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Json struct {
|
||||||
|
data interface{}
|
||||||
|
parsed bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse extract a reader as its JSON representation
|
||||||
|
func (d *Json) Parse(_reader io.Reader) error {
|
||||||
|
|
||||||
|
// 1. get json decoder
|
||||||
|
decoder := json.NewDecoder(_reader)
|
||||||
|
err := decoder.Decode(&d.data)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
d.parsed = true
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the value of a dot-separated path, and if it exists
|
||||||
|
func (d *Json) Get(_path string) (string, bool) {
|
||||||
|
|
||||||
|
// 1. extract path
|
||||||
|
path := strings.Split(_path, ".")
|
||||||
|
|
||||||
|
// 2. Iterate over path / nested fields
|
||||||
|
current := d.data
|
||||||
|
for _, field := range path {
|
||||||
|
fmap, ok := current.(map[string]interface{})
|
||||||
|
if !ok { // incomplete path
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
child, ok := fmap[field]
|
||||||
|
if !ok { // incomplete path
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
current = child
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Only return if string value
|
||||||
|
value, ok := current.(string)
|
||||||
|
return value, ok
|
||||||
|
}
|
|
@ -0,0 +1,81 @@
|
||||||
|
package cnf
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSimpleJson(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
raw string
|
||||||
|
key string
|
||||||
|
}{
|
||||||
|
{`{ "key": "value" }`, "key"},
|
||||||
|
{`{ "ignore": "xxx", "key": "value" }`, "key"},
|
||||||
|
{`{ "parent": { "child": "value" } }`, "parent.child"},
|
||||||
|
{`{ "ignore": "xxx", "parent": { "child": "value" } }`, "parent.child"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
|
||||||
|
parser := new(Json)
|
||||||
|
reader := bytes.NewBufferString(test.raw)
|
||||||
|
|
||||||
|
// try to extract value
|
||||||
|
err := parser.Parse(reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("parse error: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract value
|
||||||
|
value, found := parser.Get(test.key)
|
||||||
|
if !found {
|
||||||
|
t.Errorf("expected a result, got none")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// check value
|
||||||
|
if value != "value" {
|
||||||
|
t.Errorf("expected 'value' got '%s'", value)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNotString(t *testing.T) {
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
raw string
|
||||||
|
key string
|
||||||
|
}{
|
||||||
|
{`{ "key": ["value"] }`, "key"},
|
||||||
|
{`{ "key": {"subkey": "value"} }`, "key"},
|
||||||
|
{`{ "parent": { "child": [ "value" ] } }`, "parent.child"},
|
||||||
|
{`{ "parent": { "child": { "subkey": "value" } } }`, "parent.child"},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
|
||||||
|
parser := new(Json)
|
||||||
|
reader := bytes.NewBufferString(test.raw)
|
||||||
|
|
||||||
|
// try to extract value
|
||||||
|
err := parser.Parse(reader)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("parse error: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract value
|
||||||
|
value, found := parser.Get(test.key)
|
||||||
|
if found || len(value) > 0 {
|
||||||
|
t.Errorf("expected no result, got '%s'", value)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue