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  }