227 lines
7.5 KiB
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]
|
||
|
items_post, err := infixToPostFix(items)
|
||
|
if as.NoError(err, "Could not transform to postfix\nTest: %q", test.input) {
|
||
|
val, err := evaluatePostFix(items_post, 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]
|
||
|
items_post, 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(items_post, 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)
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|