jsonpath/expression_test.go

227 lines
7.5 KiB
Go

package jsonpath
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
var exprTests = []struct {
input string
fields map[string]Item
expectedValue interface{}
}{
// &&
{"true && true", nil, true},
{"false && true", nil, false},
{"false && false", nil, false},
// ||
{"true || true", nil, true},
{"true || false", nil, true},
{"false || false", nil, false},
// LT
{"10 < 20", nil, true},
{"10 < 10", nil, false},
{"100 < 20", nil, false},
{"@a < 50", map[string]Item{"@a": genValue(`49`, jsonNumber)}, true},
{"@a < 50", map[string]Item{"@a": genValue(`50`, jsonNumber)}, false},
{"@a < 50", map[string]Item{"@a": genValue(`51`, jsonNumber)}, false},
// LE
{"10 <= 20", nil, true},
{"10 <= 10", nil, true},
{"100 <= 20", nil, false},
{"@a <= 54", map[string]Item{"@a": genValue(`53`, jsonNumber)}, true},
{"@a <= 54", map[string]Item{"@a": genValue(`54`, jsonNumber)}, true},
{"@a <= 54", map[string]Item{"@a": genValue(`55`, jsonNumber)}, false},
// GT
{"30 > 20", nil, true},
{"20 > 20", nil, false},
{"10 > 20", nil, false},
{"@a > 50", map[string]Item{"@a": genValue(`49`, jsonNumber)}, false},
{"@a > 50", map[string]Item{"@a": genValue(`50`, jsonNumber)}, false},
{"@a > 50", map[string]Item{"@a": genValue(`51`, jsonNumber)}, true},
// GE
{"30 >= 20", nil, true},
{"20 >= 20", nil, true},
{"10 >= 20", nil, false},
{"@a >= 50", map[string]Item{"@a": genValue(`49`, jsonNumber)}, false},
{"@a >= 50", map[string]Item{"@a": genValue(`50`, jsonNumber)}, true},
{"@a >= 50", map[string]Item{"@a": genValue(`51`, jsonNumber)}, true},
// EQ
{"20 == 20", nil, true},
{"20 == 21", nil, false},
{"true == true", nil, true},
{"true == false", nil, false},
{"@a == @b", map[string]Item{"@a": genValue(`"one"`, jsonString), "@b": genValue(`"one"`, jsonString)}, true},
{"@a == @b", map[string]Item{"@a": genValue(`"one"`, jsonString), "@b": genValue(`"two"`, jsonString)}, false},
{`"fire" == "fire"`, nil, true},
{`"fire" == "water"`, nil, false},
{`@a == "toronto"`, map[string]Item{"@a": genValue(`"toronto"`, jsonString)}, true},
{`@a == "toronto"`, map[string]Item{"@a": genValue(`"los angeles"`, jsonString)}, false},
{`@a == 3.4`, map[string]Item{"@a": genValue(`3.4`, jsonNumber)}, true},
{`@a == 3.4`, map[string]Item{"@a": genValue(`3.41`, jsonNumber)}, false},
{`@a == null`, map[string]Item{"@a": genValue(`null`, jsonNull)}, true},
// NEQ
{"20 != 20", nil, false},
{"20 != 21", nil, true},
{"true != true", nil, false},
{"true != false", nil, true},
{"@a != @b", map[string]Item{"@a": genValue(`"one"`, jsonString), "@b": genValue(`"one"`, jsonString)}, false},
{"@a != @b", map[string]Item{"@a": genValue(`"one"`, jsonString), "@b": genValue(`"two"`, jsonString)}, true},
{`"fire" != "fire"`, nil, false},
{`"fire" != "water"`, nil, true},
{`@a != "toronto"`, map[string]Item{"@a": genValue(`"toronto"`, jsonString)}, false},
{`@a != "toronto"`, map[string]Item{"@a": genValue(`"los angeles"`, jsonString)}, true},
{`@a != 3.4`, map[string]Item{"@a": genValue(`3.4`, jsonNumber)}, false},
{`@a != 3.4`, map[string]Item{"@a": genValue(`3.41`, jsonNumber)}, true},
{`@a != null`, map[string]Item{"@a": genValue(`null`, jsonNull)}, false},
// Plus
{"20 + 7", nil, 27},
{"20 + 6.999999", nil, 26.999999},
// Minus
{"20 - 7", nil, 13},
{"20 - 7.11111", nil, 12.88889},
// Minus Unary
{"-27", nil, -27},
{"30 - -3", nil, 33},
{"30 + -3", nil, 27},
{"2 +++++ 3", nil, 5},
{"2+--3", nil, 5},
// Star
{"20 * 7", nil, 140},
{"20 * 6.999999", nil, 139.99998},
{"20 * -7", nil, -140},
{"-20 * -7", nil, 140},
// Slash
{"20 / 5", nil, 4},
{"20 / 6.999999 - 2.85714326531 <= 0.00000001", nil, true},
// Hat
{"7 ^ 4", nil, 2401},
{"2 ^ -2", nil, 0.25},
{"((7 ^ -4) - 0.00041649312) <= 0.0001", nil, true},
// Mod
{"7.5 % 4", nil, 3.5},
{"2 % -2", nil, 0},
{"11 % 22", nil, 11},
// Negate
{"!true", nil, false},
{"!false", nil, true},
// Mix
{"20 >= 20 || 2 == 2", nil, true},
{"20 > @.test && @.test < 13 && @.test > 1.99994", map[string]Item{"@.test": genValue(`10.23423`, jsonNumber)}, true},
{"20 > @.test && @.test < 13 && @.test > 1.99994", map[string]Item{"@.test": genValue(`15.3423`, jsonNumber)}, false},
}
func genValue(val string, typ int) Item {
return Item{
val: []byte(val),
typ: typ,
}
}
func TestExpressions(t *testing.T) {
as := assert.New(t)
emptyFields := map[string]Item{}
for _, test := range exprTests {
if test.fields == nil {
test.fields = emptyFields
}
lexer := NewSliceLexer([]byte(test.input), EXPRESSION)
items := readerToArray(lexer)
// trim EOF
items = items[0 : len(items)-1]
itemsPost, err := infixToPostFix(items)
if as.NoError(err, "Could not transform to postfix\nTest: %q", test.input) {
val, err := evaluatePostFix(itemsPost, test.fields)
if as.NoError(err, "Could not evaluate postfix\nTest Input: %q\nTest Values:%q\nError:%q", test.input, test.fields, err) {
as.EqualValues(test.expectedValue, val, "\nTest: %q\nActual: %v \nExpected %v\n", test.input, val, test.expectedValue)
}
}
}
}
var exprErrorTests = []struct {
input string
fields map[string]Item
expectedErrorSubstring string
}{
{"@a == @b", map[string]Item{"@a": genValue(`"one"`, jsonString), "@b": genValue("3.4", jsonNumber)}, "cannot be compared"},
{")(", nil, "mismatched parentheses"},
{")123", nil, "mismatched parentheses"},
{"20 == null", nil, "cannot be compared"},
{`"toronto" == null`, nil, "cannot be compared"},
{`false == 20`, nil, "cannot be compared"},
{`"nick" == 20`, nil, "cannot be compared"},
{"20 != null", nil, "cannot be compared"},
{`"toronto" != null`, nil, "cannot be compared"},
{`false != 20`, nil, "cannot be compared"},
{`"nick" != 20`, nil, "cannot be compared"},
{``, nil, "bad expression"},
{`==`, nil, "bad expression"},
{`!=`, nil, "not enough operands"},
{`!23`, nil, "cannot be compared"},
{`"nick" || true`, nil, "cannot be compared"},
{`"nick" >= 3.2`, nil, "cannot be compared"},
{`"nick" >3.2`, nil, "cannot be compared"},
{`"nick" <= 3.2`, nil, "cannot be compared"},
{`"nick" < 3.2`, nil, "cannot be compared"},
{`"nick" + 3.2`, nil, "cannot be compared"},
{`"nick" - 3.2`, nil, "cannot be compared"},
{`"nick" / 3.2`, nil, "cannot be compared"},
{`"nick" * 3.2`, nil, "cannot be compared"},
{`"nick" % 3.2`, nil, "cannot be compared"},
{`"nick"+`, nil, "cannot be compared"},
{`"nick"-`, nil, "cannot be compared"},
{`"nick"^3.2`, nil, "cannot be compared"},
{`@a == null`, map[string]Item{"@a": genValue(`3.41`, jsonNumber)}, "cannot be compared"},
}
func TestBadExpressions(t *testing.T) {
as := assert.New(t)
emptyFields := map[string]Item{}
for _, test := range exprErrorTests {
if test.fields == nil {
test.fields = emptyFields
}
lexer := NewSliceLexer([]byte(test.input), EXPRESSION)
items := readerToArray(lexer)
// trim EOF
items = items[0 : len(items)-1]
itemsPost, err := infixToPostFix(items)
if err != nil {
as.True(strings.Contains(err.Error(), test.expectedErrorSubstring), "Test Input: %q\nError %q does not contain %q", test.input, err.Error(), test.expectedErrorSubstring)
continue
}
if as.NoError(err, "Could not transform to postfix\nTest: %q", test.input) {
_, err := evaluatePostFix(itemsPost, test.fields)
if as.Error(err, "Could not evaluate postfix\nTest Input: %q\nTest Values:%q\nError:%s", test.input, test.fields, err) {
as.True(strings.Contains(err.Error(), test.expectedErrorSubstring), "Test Input: %q\nError %s does not contain %q", test.input, err.Error(), test.expectedErrorSubstring)
}
}
}
}