github.com/richardwilkes/toolbox@v1.121.0/eval/evaluator_test.go (about) 1 // Copyright (c) 2016-2024 by Richard A. Wilkes. All rights reserved. 2 // 3 // This Source Code Form is subject to the terms of the Mozilla Public 4 // License, version 2.0. If a copy of the MPL was not distributed with 5 // this file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 // 7 // This Source Code Form is "Incompatible With Secondary Licenses", as 8 // defined by the Mozilla Public License, version 2.0. 9 10 package eval_test 11 12 import ( 13 "fmt" 14 "testing" 15 16 "github.com/richardwilkes/toolbox/check" 17 "github.com/richardwilkes/toolbox/eval" 18 "github.com/richardwilkes/toolbox/xmath/fixed" 19 ) 20 21 var ( 22 numExpr = []string{ 23 "1 + 1", "2", "2.0000000000000000", 24 "1.3 + 1.5", "2.8", "2.7999999999999998", 25 "1.3+1.5", "2.8", "2.7999999999999998", 26 "1.30015 + 1.5", "2.8001", "2.8001499999999999", 27 "1 / 3", "0.3333", "0.3333333333333333", 28 "1 / 3 + 10", "10.3333", "10.3333333333333339", 29 "1 / (3 + 10)", "0.0769", "0.0769230769230769", 30 "-1 / (3 + 10)", "-0.0769", "-0.0769230769230769", 31 "1 / 0", "0", "0.0000000000000000", 32 "sqrt(9)", "3", "3.0000000000000000", 33 "sqrt(2)", "1.4142", "1.4142135623730951", 34 "sqrt(cbrt(8)+7)", "3", "3.0000000000000000", 35 " sqrt\t( cbrt ( 8 ) + 7.0000 ) ", "3", "3.0000000000000000", 36 "$foo + $bar", "24", "24.0000000000000000", 37 "$foo / $bar", "11", "11.0000000000000000", 38 "2 + 1e-2", "2.01", "2.0099999999999998", 39 "2 + 1e2", "102", "102.0000000000000000", 40 "(1 + 1) + 1", "3", "3.0000000000000000", 41 "(1 + (1 + 1))", "3", "3.0000000000000000", 42 "(1 + ((1) + 1))", "3", "3.0000000000000000", 43 "(1 + (((1)) + 1))", "3", "3.0000000000000000", 44 "1 + abs(1)", "2", "2.0000000000000000", 45 "(1 + abs(1))", "2", "2.0000000000000000", 46 "1 + (abs(1))", "2", "2.0000000000000000", 47 "(abs(1)) + 1", "2", "2.0000000000000000", 48 "(1 + abs(1)) + 1", "3", "3.0000000000000000", 49 "max(0, 1)", "1", "1.0000000000000000", 50 "(1 + max(0, 0)) - 10", "-9", "-9.0000000000000000", 51 "abs(-12)", "12", "12.0000000000000000", 52 "min(0, 1)", "0", "0.0000000000000000", 53 "(1 + (2 * max(3, min(-4, 5) + 2) - ((14 - (13 - (12 - (11 - (10 - (9 - (8 - (7 + 6))))))))))) - 10", "-1", "-1.0000000000000000", 54 } 55 strExpr = []string{ 56 "foo + bar", "foobar", 57 "foo + \n bar", "foobar", 58 "$other", "22 + 2", 59 "if($foo > $bar, yes, no)", "yes", 60 "if($foo < $bar, yes, no)", "no", 61 } 62 ) 63 64 func TestFixedEvaluator(t *testing.T) { 65 e := eval.NewFixedEvaluator[fixed.D4](resolver{}, true) 66 for i := 0; i < len(numExpr); i += 3 { 67 result, err := e.Evaluate(numExpr[i]) 68 check.NoError(t, err, "%d: %s == %s", i, numExpr[i], numExpr[i+1]) 69 check.Equal(t, numExpr[i+1], fmt.Sprintf("%v", result), "%d: %s == %s", i, numExpr[i], numExpr[i+1]) 70 } 71 for i := 0; i < len(strExpr); i += 2 { 72 result, err := e.Evaluate(strExpr[i]) 73 check.NoError(t, err, "%d: %s == %s", i, strExpr[i], strExpr[i+1]) 74 check.Equal(t, strExpr[i+1], result, "%d: %s == %s", i, strExpr[i], strExpr[i+1]) 75 } 76 77 result, err := e.Evaluate("2 > 1") 78 check.NoError(t, err) 79 check.Equal(t, true, result) 80 81 e = eval.NewFixedEvaluator[fixed.D4](resolver{}, false) 82 _, err = e.Evaluate("1 / 0") 83 check.Error(t, err) 84 } 85 86 func TestFloatEvaluator(t *testing.T) { 87 e := eval.NewFloatEvaluator[float64](resolver{}, true) 88 for i := 0; i < len(numExpr); i += 3 { 89 result, err := e.Evaluate(numExpr[i]) 90 check.NoError(t, err, "%d: %s == %s", i, numExpr[i], numExpr[i+2]) 91 check.Equal(t, numExpr[i+2], fmt.Sprintf("%0.16f", result), "%d: %s == %s", i, numExpr[i], numExpr[i+2]) 92 } 93 for i := 0; i < len(strExpr); i += 2 { 94 result, err := e.Evaluate(strExpr[i]) 95 check.NoError(t, err, "%d: %s == %s", i, strExpr[i], strExpr[i+1]) 96 check.Equal(t, strExpr[i+1], result, "%d: %s == %s", i, strExpr[i], strExpr[i+1]) 97 } 98 99 result, err := e.Evaluate("2 > 1") 100 check.NoError(t, err) 101 check.Equal(t, true, result) 102 103 e = eval.NewFloatEvaluator[float64](resolver{}, false) 104 _, err = e.Evaluate("1 / 0") 105 check.Error(t, err) 106 } 107 108 type resolver struct{} 109 110 func (r resolver) ResolveVariable(variableName string) string { 111 switch variableName { 112 case "foo": 113 return "22" 114 case "bar": 115 return "2" 116 default: 117 return "$foo + $bar" 118 } 119 }