代码拉取完成,页面将自动刷新
package gval
import (
"context"
"fmt"
"testing"
"text/scanner"
)
func TestNoParameter(t *testing.T) {
testEvaluate(
[]evaluationTest{
{
name: "Number",
expression: "100",
want: 100.0,
},
{
name: "Single PLUS",
expression: "51 + 49",
want: 100.0,
},
{
name: "Single MINUS",
expression: "100 - 51",
want: 49.0,
},
{
name: "Single BITWISE AND",
expression: "100 & 50",
want: 32.0,
},
{
name: "Single BITWISE OR",
expression: "100 | 50",
want: 118.0,
},
{
name: "Single BITWISE XOR",
expression: "100 ^ 50",
want: 86.0,
},
{
name: "Single shift left",
expression: "2 << 1",
want: 4.0,
},
{
name: "Single shift right",
expression: "2 >> 1",
want: 1.0,
},
{
name: "Single BITWISE NOT",
expression: "~10",
want: -11.0,
},
{
name: "Single MULTIPLY",
expression: "5 * 20",
want: 100.0,
},
{
name: "Single DIVIDE",
expression: "100 / 20",
want: 5.0,
},
{
name: "Single even MODULUS",
expression: "100 % 2",
want: 0.0,
},
{
name: "Single odd MODULUS",
expression: "101 % 2",
want: 1.0,
},
{
name: "Single EXPONENT",
expression: "10 ** 2",
want: 100.0,
},
{
name: "Compound PLUS",
expression: "20 + 30 + 50",
want: 100.0,
},
{
name: "Compound BITWISE AND",
expression: "20 & 30 & 50",
want: 16.0,
},
{
name: "Mutiple operators",
expression: "20 * 5 - 49",
want: 51.0,
},
{
name: "Parenthesis usage",
expression: "100 - (5 * 10)",
want: 50.0,
},
{
name: "Nested parentheses",
expression: "50 + (5 * (15 - 5))",
want: 100.0,
},
{
name: "Nested parentheses with bitwise",
expression: "100 ^ (23 * (2 | 5))",
want: 197.0,
},
{
name: "Logical OR operation of two clauses",
expression: "(1 == 1) || (true == true)",
want: true,
},
{
name: "Logical AND operation of two clauses",
expression: "(1 == 1) && (true == true)",
want: true,
},
{
name: "Implicit boolean",
expression: "2 > 1",
want: true,
},
{
name: "Equal test minus numbers and no spaces",
expression: "-1==-1",
want: true,
},
{
name: "Compound boolean",
expression: "5 < 10 && 1 < 5",
want: true,
},
{
name: "Evaluated true && false operation (for issue #8)",
expression: "1 > 10 && 11 > 10",
want: false,
},
{
name: "Evaluated true && false operation (for issue #8)",
expression: "true == true && false == true",
want: false,
},
{
name: "Parenthesis boolean",
expression: "10 < 50 && (1 != 2 && 1 > 0)",
want: true,
},
{
name: "Comparison of string constants",
expression: `"foo" == "foo"`,
want: true,
},
{
name: "NEQ comparison of string constants",
expression: `"foo" != "bar"`,
want: true,
},
{
name: "REQ comparison of string constants",
expression: `"foobar" =~ "oba"`,
want: true,
},
{
name: "NREQ comparison of string constants",
expression: `"foo" !~ "bar"`,
want: true,
},
{
name: "Multiplicative/additive order",
expression: "5 + 10 * 2",
want: 25.0,
},
{
name: "Multiple constant multiplications",
expression: "10 * 10 * 10",
want: 1000.0,
},
{
name: "Multiple adds/multiplications",
expression: "10 * 10 * 10 + 1 * 10 * 10",
want: 1100.0,
},
{
name: "Modulus operatorPrecedence",
expression: "1 + 101 % 2 * 5",
want: 6.0,
},
{
name: "Exponent operatorPrecedence",
expression: "1 + 5 ** 3 % 2 * 5",
want: 6.0,
},
{
name: "Bit shift operatorPrecedence",
expression: "50 << 1 & 90",
want: 64.0,
},
{
name: "Bit shift operatorPrecedence",
expression: "90 & 50 << 1",
want: 64.0,
},
{
name: "Bit shift operatorPrecedence amongst non-bitwise",
expression: "90 + 50 << 1 * 5",
want: 4480.0,
},
{
name: "Order of non-commutative same-operatorPrecedence operators (additive)",
expression: "1 - 2 - 4 - 8",
want: -13.0,
},
{
name: "Order of non-commutative same-operatorPrecedence operators (multiplicative)",
expression: "1 * 4 / 2 * 8",
want: 16.0,
},
{
name: "Null coalesce operatorPrecedence",
expression: "true ?? true ? 100 + 200 : 400",
want: 300.0,
},
{
name: "Identical date equivalence",
expression: `"2014-01-02 14:12:22" == "2014-01-02 14:12:22"`,
want: true,
},
{
name: "Positive date GT",
expression: `"2014-01-02 14:12:22" > "2014-01-02 12:12:22"`,
want: true,
},
{
name: "Negative date GT",
expression: `"2014-01-02 14:12:22" > "2014-01-02 16:12:22"`,
want: false,
},
{
name: "Positive date GTE",
expression: `"2014-01-02 14:12:22" >= "2014-01-02 12:12:22"`,
want: true,
},
{
name: "Negative date GTE",
expression: `"2014-01-02 14:12:22" >= "2014-01-02 16:12:22"`,
want: false,
},
{
name: "Positive date LT",
expression: `"2014-01-02 14:12:22" < "2014-01-02 16:12:22"`,
want: true,
},
{
name: "Negative date LT",
expression: `"2014-01-02 14:12:22" < "2014-01-02 11:12:22"`,
want: false,
},
{
name: "Positive date LTE",
expression: `"2014-01-02 09:12:22" <= "2014-01-02 12:12:22"`,
want: true,
},
{
name: "Negative date LTE",
expression: `"2014-01-02 14:12:22" <= "2014-01-02 11:12:22"`,
want: false,
},
{
name: "Sign prefix comparison",
expression: "-1 < 0",
want: true,
},
{
name: "Lexicographic LT",
expression: `"ab" < "abc"`,
want: true,
},
{
name: "Lexicographic LTE",
expression: `"ab" <= "abc"`,
want: true,
},
{
name: "Lexicographic GT",
expression: `"aba" > "abc"`,
want: false,
},
{
name: "Lexicographic GTE",
expression: `"aba" >= "abc"`,
want: false,
},
{
name: "Boolean sign prefix comparison",
expression: "!true == false",
want: true,
},
{
name: "Inversion of clause",
expression: "!(10 < 0)",
want: true,
},
{
name: "Negation after modifier",
expression: "10 * -10",
want: -100.0,
},
{
name: "Ternary with single boolean",
expression: "true ? 10",
want: 10.0,
},
{
name: "Ternary nil with single boolean",
expression: "false ? 10",
want: nil,
},
{
name: "Ternary with comparator boolean",
expression: "10 > 5 ? 35.50",
want: 35.50,
},
{
name: "Ternary nil with comparator boolean",
expression: "1 > 5 ? 35.50",
want: nil,
},
{
name: "Ternary with parentheses",
expression: "(5 * (15 - 5)) > 5 ? 35.50",
want: 35.50,
},
{
name: "Ternary operatorPrecedence",
expression: "true ? 35.50 > 10",
want: true,
},
{
name: "Ternary-else",
expression: "false ? 35.50 : 50",
want: 50.0,
},
{
name: "Ternary-else inside clause",
expression: "(false ? 5 : 35.50) > 10",
want: true,
},
{
name: "Ternary-else (true-case) inside clause",
expression: "(true ? 1 : 5) < 10",
want: true,
},
{
name: "Ternary-else before comparator (negative case)",
expression: "true ? 1 : 5 > 10",
want: 1.0,
},
{
name: "Nested ternaries (#32)",
expression: "(2 == 2) ? 1 : (true ? 2 : 3)",
want: 1.0,
},
{
name: "Nested ternaries, right case (#32)",
expression: "false ? 1 : (true ? 2 : 3)",
want: 2.0,
},
{
name: "Doubly-nested ternaries (#32)",
expression: "true ? (false ? 1 : (false ? 2 : 3)) : (false ? 4 : 5)",
want: 3.0,
},
{
name: "String to string concat",
expression: `"foo" + "bar" == "foobar"`,
want: true,
},
{
name: "String to float64 concat",
expression: `"foo" + 123 == "foo123"`,
want: true,
},
{
name: "Float64 to string concat",
expression: `123 + "bar" == "123bar"`,
want: true,
},
{
name: "String to date concat",
expression: `"foo" + "02/05/1970" == "foobar"`,
want: false,
},
{
name: "String to bool concat",
expression: `"foo" + true == "footrue"`,
want: true,
},
{
name: "Bool to string concat",
expression: `true + "bar" == "truebar"`,
want: true,
},
{
name: "Null coalesce left",
expression: "1 ?? 2",
want: 1.0,
},
{
name: "Array membership literals",
expression: "1 in [1, 2, 3]",
want: true,
},
{
name: "Array membership literal with inversion",
expression: "!(1 in [1, 2, 3])",
want: false,
},
{
name: "Logical operator reordering (#30)",
expression: "(true && true) || (true && false)",
want: true,
},
{
name: "Logical operator reordering without parens (#30)",
expression: "true && true || true && false",
want: true,
},
{
name: "Logical operator reordering with multiple OR (#30)",
expression: "false || true && true || false",
want: true,
},
{
name: "Left-side multiple consecutive (should be reordered) operators",
expression: "(10 * 10 * 10) > 10",
want: true,
},
{
name: "Three-part non-paren logical op reordering (#44)",
expression: "false && true || true",
want: true,
},
{
name: "Three-part non-paren logical op reordering (#44), second one",
expression: "true || false && true",
want: true,
},
{
name: "Logical operator reordering without parens (#45)",
expression: "true && true || false && false",
want: true,
},
{
name: "Single function",
expression: "foo()",
extension: Function("foo", func(arguments ...interface{}) (interface{}, error) {
return true, nil
}),
want: true,
},
{
name: "Func with argument",
expression: "passthrough(1)",
extension: Function("passthrough", func(arguments ...interface{}) (interface{}, error) {
return arguments[0], nil
}),
want: 1.0,
},
{
name: "Func with arguments",
expression: "passthrough(1, 2)",
extension: Function("passthrough", func(arguments ...interface{}) (interface{}, error) {
return arguments[0].(float64) + arguments[1].(float64), nil
}),
want: 3.0,
},
{
name: "Nested function with operatorPrecedence",
expression: "sum(1, sum(2, 3), 2 + 2, true ? 4 : 5)",
extension: Function("sum", func(arguments ...interface{}) (interface{}, error) {
sum := 0.0
for _, v := range arguments {
sum += v.(float64)
}
return sum, nil
}),
want: 14.0,
},
{
name: "Empty function and modifier, compared",
expression: "numeric()-1 > 0",
extension: Function("numeric", func(arguments ...interface{}) (interface{}, error) {
return 2.0, nil
}),
want: true,
},
{
name: "Empty function comparator",
expression: "numeric() > 0",
extension: Function("numeric", func(arguments ...interface{}) (interface{}, error) {
return 2.0, nil
}),
want: true,
},
{
name: "Empty function logical operator",
expression: "success() && !false",
extension: Function("success", func(arguments ...interface{}) (interface{}, error) {
return true, nil
}),
want: true,
},
{
name: "Empty function ternary",
expression: "nope() ? 1 : 2.0",
extension: Function("nope", func(arguments ...interface{}) (interface{}, error) {
return false, nil
}),
want: 2.0,
},
{
name: "Empty function null coalesce",
expression: "null() ?? 2",
extension: Function("null", func(arguments ...interface{}) (interface{}, error) {
return nil, nil
}),
want: 2.0,
},
{
name: "Empty function with prefix",
expression: "-ten()",
extension: Function("ten", func(arguments ...interface{}) (interface{}, error) {
return 10.0, nil
}),
want: -10.0,
},
{
name: "Empty function as part of chain",
expression: "10 - numeric() - 2",
extension: Function("numeric", func(arguments ...interface{}) (interface{}, error) {
return 5.0, nil
}),
want: 3.0,
},
{
name: "Empty function near separator",
expression: "10 in [1, 2, 3, ten(), 8]",
extension: Function("ten", func(arguments ...interface{}) (interface{}, error) {
return 10.0, nil
}),
want: true,
},
{
name: "Enclosed empty function with modifier and comparator (#28)",
expression: "(ten() - 1) > 3",
extension: Function("ten", func(arguments ...interface{}) (interface{}, error) {
return 10.0, nil
}),
want: true,
},
{
name: "Array",
expression: `[(ten() - 1) > 3, (ten() - 1),"hey"]`,
extension: Function("ten", func(arguments ...interface{}) (interface{}, error) {
return 10.0, nil
}),
want: []interface{}{true, 9., "hey"},
},
{
name: "Object",
expression: `{1: (ten() - 1) > 3, 7 + ".X" : (ten() - 1),"hello" : "hey"}`,
extension: Function("ten", func(arguments ...interface{}) (interface{}, error) {
return 10.0, nil
}),
want: map[string]interface{}{"1": true, "7.X": 9., "hello": "hey"},
},
{
name: "Object negativ value",
expression: `{1: -1,"hello" : "hey"}`,
want: map[string]interface{}{"1": -1., "hello": "hey"},
},
{
name: "Empty Array",
expression: `[]`,
want: []interface{}{},
},
{
name: "Empty Object",
expression: `{}`,
want: map[string]interface{}{},
},
{
name: "Variadic",
expression: `sum(1,2,3,4)`,
extension: Function("sum", func(arguments ...float64) (interface{}, error) {
sum := 0.
for _, a := range arguments {
sum += a
}
return sum, nil
}),
want: 10.0,
},
{
name: "Ident Operator",
expression: `1 plus 1`,
extension: InfixNumberOperator("plus", func(a, b float64) (interface{}, error) {
return a + b, nil
}),
want: 2.0,
},
{
name: "Postfix Operator",
expression: `4§`,
extension: PostfixOperator("§", func(_ context.Context, _ *Parser, eval Evaluable) (Evaluable, error) {
return func(ctx context.Context, parameter interface{}) (interface{}, error) {
i, err := eval.EvalInt(ctx, parameter)
if err != nil {
return nil, err
}
return fmt.Sprintf("§%d", i), nil
}, nil
}),
want: "§4",
},
{
name: "Tabs as non-whitespace",
expression: "4\t5\t6",
extension: NewLanguage(
Init(func(ctx context.Context, p *Parser) (Evaluable, error) {
p.SetWhitespace('\n', '\r', ' ')
return p.ParseExpression(ctx)
}),
InfixNumberOperator("\t", func(a, b float64) (interface{}, error) {
return a * b, nil
}),
),
want: 120.0,
},
{
name: "Handle all other prefixes",
expression: "^foo + $bar + &baz",
extension: DefaultExtension(func(ctx context.Context, p *Parser) (Evaluable, error) {
var mul int
switch p.TokenText() {
case "^":
mul = 1
case "$":
mul = 2
case "&":
mul = 3
}
switch p.Scan() {
case scanner.Ident:
return p.Const(mul * len(p.TokenText())), nil
default:
return nil, p.Expected("length multiplier", scanner.Ident)
}
}),
want: 18.0,
},
{
name: "Embed languages",
expression: "left { 5 + 5 } right",
extension: func() Language {
step := func(ctx context.Context, p *Parser, cur Evaluable) (Evaluable, error) {
next, err := p.ParseExpression(ctx)
if err != nil {
return nil, err
}
return func(ctx context.Context, parameter interface{}) (interface{}, error) {
us, err := cur.EvalString(ctx, parameter)
if err != nil {
return nil, err
}
them, err := next.EvalString(ctx, parameter)
if err != nil {
return nil, err
}
return us + them, nil
}, nil
}
return NewLanguage(
Init(func(ctx context.Context, p *Parser) (Evaluable, error) {
p.SetWhitespace()
p.SetMode(0)
return p.ParseExpression(ctx)
}),
DefaultExtension(func(ctx context.Context, p *Parser) (Evaluable, error) {
return step(ctx, p, p.Const(p.TokenText()))
}),
PrefixExtension(scanner.EOF, func(ctx context.Context, p *Parser) (Evaluable, error) {
return p.Const(""), nil
}),
PrefixExtension('{', func(ctx context.Context, p *Parser) (Evaluable, error) {
eval, err := p.ParseSublanguage(ctx, Full())
if err != nil {
return nil, err
}
switch p.Scan() {
case '}':
default:
return nil, p.Expected("embedded", '}')
}
return step(ctx, p, eval)
}),
)
}(),
want: "left 10 right",
},
{
name: "Late binding",
expression: "5 * [ 10 * { 20 / [ 10 ] } ]",
extension: func() Language {
var inner, outer Language
parseCurly := func(ctx context.Context, p *Parser) (Evaluable, error) {
eval, err := p.ParseSublanguage(ctx, outer)
if err != nil {
return nil, err
}
if p.Scan() != '}' {
return nil, p.Expected("end", '}')
}
return eval, nil
}
parseSquare := func(ctx context.Context, p *Parser) (Evaluable, error) {
eval, err := p.ParseSublanguage(ctx, inner)
if err != nil {
return nil, err
}
if p.Scan() != ']' {
return nil, p.Expected("end", ']')
}
return eval, nil
}
inner = Full(PrefixExtension('{', parseCurly))
outer = Full(PrefixExtension('[', parseSquare))
return outer
}(),
want: 100.0,
},
},
t,
)
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。