1 Star 0 Fork 0

缘灭.H/gval

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
gval_noparameter_test.go 18.67 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818
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,
)
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/org_mkg/gval.git
git@gitee.com:org_mkg/gval.git
org_mkg
gval
gval
master

搜索帮助