2019-02-26 13:05:15 +04:00
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 ]
2019-10-19 01:17:00 +04:00
itemsPost , err := infixToPostFix ( items )
2019-02-26 13:05:15 +04:00
if as . NoError ( err , "Could not transform to postfix\nTest: %q" , test . input ) {
2019-10-19 01:17:00 +04:00
val , err := evaluatePostFix ( itemsPost , test . fields )
2019-02-26 13:05:15 +04:00
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" } ,
2019-10-19 01:17:00 +04:00
{ ")(" , nil , "mismatched parentheses" } ,
{ ")123" , nil , "mismatched parentheses" } ,
2019-02-26 13:05:15 +04:00
{ "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" } ,
2019-10-19 01:17:00 +04:00
{ ` ` , nil , "bad expression" } ,
{ ` == ` , nil , "bad expression" } ,
{ ` != ` , nil , "not enough operands" } ,
2019-02-26 13:05:15 +04:00
{ ` !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 ]
2019-10-19 01:17:00 +04:00
itemsPost , err := infixToPostFix ( items )
2019-02-26 13:05:15 +04:00
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 ) {
2019-10-19 01:17:00 +04:00
_ , err := evaluatePostFix ( itemsPost , test . fields )
2019-02-26 13:05:15 +04:00
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 )
}
}
}
}