2018-01-29 19:44:18 +00:00
|
|
|
package query
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
"time"
|
2018-09-05 15:36:14 +00:00
|
|
|
|
|
|
|
"github.com/pelletier/go-toml"
|
2018-01-29 19:44:18 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type queryTestNode struct {
|
|
|
|
value interface{}
|
|
|
|
position toml.Position
|
|
|
|
}
|
|
|
|
|
|
|
|
func valueString(root interface{}) string {
|
|
|
|
result := "" //fmt.Sprintf("%T:", root)
|
|
|
|
switch node := root.(type) {
|
|
|
|
case *Result:
|
|
|
|
items := []string{}
|
|
|
|
for i, v := range node.Values() {
|
|
|
|
items = append(items, fmt.Sprintf("%s:%s",
|
|
|
|
node.Positions()[i].String(), valueString(v)))
|
|
|
|
}
|
|
|
|
sort.Strings(items)
|
|
|
|
result = "[" + strings.Join(items, ", ") + "]"
|
|
|
|
case queryTestNode:
|
|
|
|
result = fmt.Sprintf("%s:%s",
|
|
|
|
node.position.String(), valueString(node.value))
|
|
|
|
case []interface{}:
|
|
|
|
items := []string{}
|
|
|
|
for _, v := range node {
|
|
|
|
items = append(items, valueString(v))
|
|
|
|
}
|
|
|
|
sort.Strings(items)
|
|
|
|
result = "[" + strings.Join(items, ", ") + "]"
|
|
|
|
case *toml.Tree:
|
|
|
|
// workaround for unreliable map key ordering
|
|
|
|
items := []string{}
|
|
|
|
for _, k := range node.Keys() {
|
|
|
|
v := node.GetPath([]string{k})
|
|
|
|
items = append(items, k+":"+valueString(v))
|
|
|
|
}
|
|
|
|
sort.Strings(items)
|
|
|
|
result = "{" + strings.Join(items, ", ") + "}"
|
|
|
|
case map[string]interface{}:
|
|
|
|
// workaround for unreliable map key ordering
|
|
|
|
items := []string{}
|
|
|
|
for k, v := range node {
|
|
|
|
items = append(items, k+":"+valueString(v))
|
|
|
|
}
|
|
|
|
sort.Strings(items)
|
|
|
|
result = "{" + strings.Join(items, ", ") + "}"
|
|
|
|
case int64:
|
|
|
|
result += fmt.Sprintf("%d", node)
|
|
|
|
case string:
|
|
|
|
result += "'" + node + "'"
|
|
|
|
case float64:
|
|
|
|
result += fmt.Sprintf("%f", node)
|
|
|
|
case bool:
|
|
|
|
result += fmt.Sprintf("%t", node)
|
|
|
|
case time.Time:
|
|
|
|
result += fmt.Sprintf("'%v'", node)
|
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertValue(t *testing.T, result, ref interface{}) {
|
|
|
|
pathStr := valueString(result)
|
|
|
|
refStr := valueString(ref)
|
|
|
|
if pathStr != refStr {
|
|
|
|
t.Errorf("values do not match")
|
|
|
|
t.Log("test:", pathStr)
|
|
|
|
t.Log("ref: ", refStr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func assertQueryPositions(t *testing.T, tomlDoc string, query string, ref []interface{}) {
|
|
|
|
tree, err := toml.Load(tomlDoc)
|
|
|
|
if err != nil {
|
|
|
|
t.Errorf("Non-nil toml parse error: %v", err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
q, err := Compile(query)
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
results := q.Execute(tree)
|
|
|
|
assertValue(t, results, ref)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQueryRoot(t *testing.T) {
|
|
|
|
assertQueryPositions(t,
|
|
|
|
"a = 42",
|
|
|
|
"$",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(42),
|
|
|
|
}, toml.Position{1, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQueryKey(t *testing.T) {
|
|
|
|
assertQueryPositions(t,
|
|
|
|
"[foo]\na = 42",
|
|
|
|
"$.foo.a",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
int64(42), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQueryKeyString(t *testing.T) {
|
|
|
|
assertQueryPositions(t,
|
|
|
|
"[foo]\na = 42",
|
|
|
|
"$.foo['a']",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
int64(42), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQueryIndex(t *testing.T) {
|
|
|
|
assertQueryPositions(t,
|
|
|
|
"[foo]\na = [1,2,3,4,5,6,7,8,9,0]",
|
|
|
|
"$.foo.a[5]",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
int64(6), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQuerySliceRange(t *testing.T) {
|
|
|
|
assertQueryPositions(t,
|
|
|
|
"[foo]\na = [1,2,3,4,5,6,7,8,9,0]",
|
|
|
|
"$.foo.a[0:5]",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
int64(1), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(2), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(3), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(4), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(5), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQuerySliceStep(t *testing.T) {
|
|
|
|
assertQueryPositions(t,
|
|
|
|
"[foo]\na = [1,2,3,4,5,6,7,8,9,0]",
|
|
|
|
"$.foo.a[0:5:2]",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
int64(1), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(3), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(5), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQueryAny(t *testing.T) {
|
|
|
|
assertQueryPositions(t,
|
|
|
|
"[foo.bar]\na=1\nb=2\n[foo.baz]\na=3\nb=4",
|
|
|
|
"$.foo.*",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(1),
|
|
|
|
"b": int64(2),
|
|
|
|
}, toml.Position{1, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(3),
|
|
|
|
"b": int64(4),
|
|
|
|
}, toml.Position{4, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
func TestQueryUnionSimple(t *testing.T) {
|
|
|
|
assertQueryPositions(t,
|
|
|
|
"[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6",
|
|
|
|
"$.*[bar,foo]",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(1),
|
|
|
|
"b": int64(2),
|
|
|
|
}, toml.Position{1, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(3),
|
|
|
|
"b": int64(4),
|
|
|
|
}, toml.Position{4, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(5),
|
|
|
|
"b": int64(6),
|
|
|
|
}, toml.Position{7, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQueryRecursionAll(t *testing.T) {
|
|
|
|
assertQueryPositions(t,
|
|
|
|
"[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6",
|
|
|
|
"$..*",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"foo": map[string]interface{}{
|
|
|
|
"bar": map[string]interface{}{
|
|
|
|
"a": int64(1),
|
|
|
|
"b": int64(2),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"baz": map[string]interface{}{
|
|
|
|
"foo": map[string]interface{}{
|
|
|
|
"a": int64(3),
|
|
|
|
"b": int64(4),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
"gorf": map[string]interface{}{
|
|
|
|
"foo": map[string]interface{}{
|
|
|
|
"a": int64(5),
|
|
|
|
"b": int64(6),
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}, toml.Position{1, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"bar": map[string]interface{}{
|
|
|
|
"a": int64(1),
|
|
|
|
"b": int64(2),
|
|
|
|
},
|
|
|
|
}, toml.Position{1, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(1),
|
|
|
|
"b": int64(2),
|
|
|
|
}, toml.Position{1, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(1), toml.Position{2, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(2), toml.Position{3, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"foo": map[string]interface{}{
|
|
|
|
"a": int64(3),
|
|
|
|
"b": int64(4),
|
|
|
|
},
|
|
|
|
}, toml.Position{4, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(3),
|
|
|
|
"b": int64(4),
|
|
|
|
}, toml.Position{4, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(3), toml.Position{5, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(4), toml.Position{6, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"foo": map[string]interface{}{
|
|
|
|
"a": int64(5),
|
|
|
|
"b": int64(6),
|
|
|
|
},
|
|
|
|
}, toml.Position{7, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(5),
|
|
|
|
"b": int64(6),
|
|
|
|
}, toml.Position{7, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(5), toml.Position{8, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(6), toml.Position{9, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQueryRecursionUnionSimple(t *testing.T) {
|
|
|
|
assertQueryPositions(t,
|
|
|
|
"[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6",
|
|
|
|
"$..['foo','bar']",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"bar": map[string]interface{}{
|
|
|
|
"a": int64(1),
|
|
|
|
"b": int64(2),
|
|
|
|
},
|
|
|
|
}, toml.Position{1, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(3),
|
|
|
|
"b": int64(4),
|
|
|
|
}, toml.Position{4, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(1),
|
|
|
|
"b": int64(2),
|
|
|
|
}, toml.Position{1, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"a": int64(5),
|
|
|
|
"b": int64(6),
|
|
|
|
}, toml.Position{7, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestQueryFilterFn(t *testing.T) {
|
|
|
|
buff, err := ioutil.ReadFile("../example.toml")
|
|
|
|
if err != nil {
|
|
|
|
t.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
assertQueryPositions(t, string(buff),
|
|
|
|
"$..[?(int)]",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
int64(8001), toml.Position{13, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(8001), toml.Position{13, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(8002), toml.Position{13, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
int64(5000), toml.Position{14, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
assertQueryPositions(t, string(buff),
|
|
|
|
"$..[?(string)]",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
"TOML Example", toml.Position{3, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
"Tom Preston-Werner", toml.Position{6, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
"GitHub", toml.Position{7, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
"GitHub Cofounder & CEO\nLikes tater tots and beer.",
|
|
|
|
toml.Position{8, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
"192.168.1.1", toml.Position{12, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
"10.0.0.1", toml.Position{21, 3},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
"eqdc10", toml.Position{22, 3},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
"10.0.0.2", toml.Position{25, 3},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
"eqdc10", toml.Position{26, 3},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
assertQueryPositions(t, string(buff),
|
|
|
|
"$..[?(float)]",
|
2018-09-05 15:36:14 +00:00
|
|
|
[]interface{}{ // no float values in document
|
2018-01-29 19:44:18 +00:00
|
|
|
})
|
|
|
|
|
|
|
|
tv, _ := time.Parse(time.RFC3339, "1979-05-27T07:32:00Z")
|
|
|
|
assertQueryPositions(t, string(buff),
|
|
|
|
"$..[?(tree)]",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"name": "Tom Preston-Werner",
|
|
|
|
"organization": "GitHub",
|
|
|
|
"bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.",
|
|
|
|
"dob": tv,
|
|
|
|
}, toml.Position{5, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"server": "192.168.1.1",
|
|
|
|
"ports": []interface{}{int64(8001), int64(8001), int64(8002)},
|
|
|
|
"connection_max": int64(5000),
|
|
|
|
"enabled": true,
|
|
|
|
}, toml.Position{11, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"alpha": map[string]interface{}{
|
|
|
|
"ip": "10.0.0.1",
|
|
|
|
"dc": "eqdc10",
|
|
|
|
},
|
|
|
|
"beta": map[string]interface{}{
|
|
|
|
"ip": "10.0.0.2",
|
|
|
|
"dc": "eqdc10",
|
|
|
|
},
|
|
|
|
}, toml.Position{17, 1},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"ip": "10.0.0.1",
|
|
|
|
"dc": "eqdc10",
|
|
|
|
}, toml.Position{20, 3},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"ip": "10.0.0.2",
|
|
|
|
"dc": "eqdc10",
|
|
|
|
}, toml.Position{24, 3},
|
|
|
|
},
|
|
|
|
queryTestNode{
|
|
|
|
map[string]interface{}{
|
|
|
|
"data": []interface{}{
|
|
|
|
[]interface{}{"gamma", "delta"},
|
|
|
|
[]interface{}{int64(1), int64(2)},
|
|
|
|
},
|
|
|
|
}, toml.Position{28, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
assertQueryPositions(t, string(buff),
|
|
|
|
"$..[?(time)]",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
tv, toml.Position{9, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
|
|
|
|
assertQueryPositions(t, string(buff),
|
|
|
|
"$..[?(bool)]",
|
|
|
|
[]interface{}{
|
|
|
|
queryTestNode{
|
|
|
|
true, toml.Position{15, 1},
|
|
|
|
},
|
|
|
|
})
|
|
|
|
}
|