Refactored match to use function chaining
This commit is contained in:
+91
-88
@@ -6,181 +6,184 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func pathString(path QueryPath) string {
|
||||
result := "["
|
||||
for _, v := range path {
|
||||
result += fmt.Sprintf("%T:%v, ", v, v)
|
||||
// dump path tree to a string
|
||||
func pathString(root PathFn) string {
|
||||
result := fmt.Sprintf("%T:")
|
||||
switch fn := root.(type) {
|
||||
case *terminatingFn:
|
||||
result += "{}"
|
||||
case *matchKeyFn:
|
||||
result += fmt.Sprintf("{%s}", fn.Name)
|
||||
result += pathString(fn.next)
|
||||
case *matchIndexFn:
|
||||
result += fmt.Sprintf("{%d}", fn.Idx)
|
||||
result += pathString(fn.next)
|
||||
case *matchSliceFn:
|
||||
result += fmt.Sprintf("{%d:%d:%d}",
|
||||
fn.Start, fn.End, fn.Step)
|
||||
result += pathString(fn.next)
|
||||
case *matchAnyFn:
|
||||
result += "{}"
|
||||
result += pathString(fn.next)
|
||||
case *matchUnionFn:
|
||||
result += "{["
|
||||
for _, v := range fn.Union {
|
||||
result += pathString(v)
|
||||
}
|
||||
result += "]}"
|
||||
case *matchRecursiveFn:
|
||||
result += "{}"
|
||||
result += pathString(fn.next)
|
||||
}
|
||||
return result + "]"
|
||||
return result
|
||||
}
|
||||
|
||||
func assertPathMatch(t *testing.T, path, ref QueryPath) bool {
|
||||
if len(path) != len(ref) {
|
||||
t.Errorf("lengths do not match: %v vs %v",
|
||||
pathString(path), pathString(ref))
|
||||
func assertPathMatch(t *testing.T, path, ref *QueryPath) bool {
|
||||
pathStr := pathString(path.root)
|
||||
refStr := pathString(ref.root)
|
||||
if pathStr != refStr {
|
||||
t.Errorf("paths do not match: %v vs %v")
|
||||
t.Log("test:", pathStr)
|
||||
t.Log("ref: ", refStr)
|
||||
return false
|
||||
} else {
|
||||
for i, v := range ref {
|
||||
pass := false
|
||||
node := path[i]
|
||||
// compare by value
|
||||
switch refNode := v.(type) {
|
||||
case *matchKeyFn:
|
||||
castNode, ok := node.(*matchKeyFn)
|
||||
pass = ok && (*refNode == *castNode)
|
||||
case *matchIndexFn:
|
||||
castNode, ok := node.(*matchIndexFn)
|
||||
pass = ok && (*refNode == *castNode)
|
||||
case *matchSliceFn:
|
||||
castNode, ok := node.(*matchSliceFn)
|
||||
pass = ok && (*refNode == *castNode)
|
||||
case *matchAnyFn:
|
||||
castNode, ok := node.(*matchAnyFn)
|
||||
pass = ok && (*refNode == *castNode)
|
||||
case *matchUnionFn:
|
||||
castNode, ok := node.(*matchUnionFn)
|
||||
// special case - comapre all contents
|
||||
pass = ok && assertPathMatch(t, castNode.Union, refNode.Union)
|
||||
case *matchRecursiveFn:
|
||||
castNode, ok := node.(*matchRecursiveFn)
|
||||
pass = ok && (*refNode == *castNode)
|
||||
}
|
||||
if !pass {
|
||||
t.Errorf("paths do not match at index %d: %v vs %v",
|
||||
i, pathString(path), pathString(ref))
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func assertPath(t *testing.T, query string, ref QueryPath) {
|
||||
func assertPath(t *testing.T, query string, ref *QueryPath) {
|
||||
_, flow := lex(query)
|
||||
path := parse(flow)
|
||||
assertPathMatch(t, path, ref)
|
||||
}
|
||||
|
||||
func buildPath(parts... PathFn) *QueryPath {
|
||||
path := newQueryPath()
|
||||
for _, v := range parts {
|
||||
path.Append(v)
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func TestPathRoot(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$",
|
||||
QueryPath{
|
||||
buildPath(
|
||||
// empty
|
||||
})
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathKey(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$.foo",
|
||||
QueryPath{
|
||||
&matchKeyFn{ "foo" },
|
||||
})
|
||||
buildPath(
|
||||
newMatchKeyFn("foo"),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathBracketKey(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$[foo]",
|
||||
QueryPath{
|
||||
&matchKeyFn{ "foo" },
|
||||
})
|
||||
buildPath(
|
||||
newMatchKeyFn("foo"),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathBracketStringKey(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$['foo']",
|
||||
QueryPath{
|
||||
&matchKeyFn{ "foo" },
|
||||
})
|
||||
buildPath(
|
||||
newMatchKeyFn("foo"),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathIndex(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$[123]",
|
||||
QueryPath{
|
||||
&matchIndexFn{ 123 },
|
||||
})
|
||||
buildPath(
|
||||
newMatchIndexFn(123),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathSliceStart(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$[123:]",
|
||||
QueryPath{
|
||||
&matchSliceFn{ 123, math.MaxInt64, 1 },
|
||||
})
|
||||
buildPath(
|
||||
newMatchSliceFn(123, math.MaxInt64, 1),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathSliceStartEnd(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$[123:456]",
|
||||
QueryPath{
|
||||
&matchSliceFn{ 123, 456, 1 },
|
||||
})
|
||||
buildPath(
|
||||
newMatchSliceFn(123, 456, 1),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathSliceStartEndColon(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$[123:456:]",
|
||||
QueryPath{
|
||||
&matchSliceFn{ 123, 456, 1 },
|
||||
})
|
||||
buildPath(
|
||||
newMatchSliceFn(123, 456, 1),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathSliceStartStep(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$[123::7]",
|
||||
QueryPath{
|
||||
&matchSliceFn{ 123, math.MaxInt64, 7 },
|
||||
})
|
||||
buildPath(
|
||||
newMatchSliceFn(123, math.MaxInt64, 7),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathSliceEndStep(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$[:456:7]",
|
||||
QueryPath{
|
||||
&matchSliceFn{ 0, 456, 7 },
|
||||
})
|
||||
buildPath(
|
||||
newMatchSliceFn(0, 456, 7),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathSliceStep(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$[::7]",
|
||||
QueryPath{
|
||||
&matchSliceFn{ 0, math.MaxInt64, 7 },
|
||||
})
|
||||
buildPath(
|
||||
newMatchSliceFn(0, math.MaxInt64, 7),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathSliceAll(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$[123:456:7]",
|
||||
QueryPath{
|
||||
&matchSliceFn{ 123, 456, 7 },
|
||||
})
|
||||
buildPath(
|
||||
newMatchSliceFn(123, 456, 7),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathAny(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$.*",
|
||||
QueryPath{
|
||||
&matchAnyFn{},
|
||||
})
|
||||
buildPath(
|
||||
newMatchAnyFn(),
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathUnion(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$[foo, bar, baz]",
|
||||
QueryPath{
|
||||
buildPath(
|
||||
&matchUnionFn{ []PathFn {
|
||||
&matchKeyFn{ "foo" },
|
||||
&matchKeyFn{ "bar" },
|
||||
&matchKeyFn{ "baz" },
|
||||
newMatchKeyFn("foo"),
|
||||
newMatchKeyFn("bar"),
|
||||
newMatchKeyFn("baz"),
|
||||
}},
|
||||
})
|
||||
))
|
||||
}
|
||||
|
||||
func TestPathRecurse(t *testing.T) {
|
||||
assertPath(t,
|
||||
"$..*",
|
||||
QueryPath{
|
||||
&matchRecursiveFn{},
|
||||
})
|
||||
buildPath(
|
||||
newMatchRecursiveFn(),
|
||||
))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user