|
|
package astexpr
|
|
|
|
|
|
import (
|
|
|
"math/rand"
|
|
|
"testing"
|
|
|
"time"
|
|
|
)
|
|
|
|
|
|
func TestParseAndExecSimple(t *testing.T) {
|
|
|
type U struct {
|
|
|
Expr string
|
|
|
R float64
|
|
|
}
|
|
|
exprs := []U{
|
|
|
{"1", 1},
|
|
|
{"--1", 1},
|
|
|
{"1+2", 3},
|
|
|
{"-1+2", 1},
|
|
|
{"-(1+2)", -3},
|
|
|
{"-(1+2)*5", -15},
|
|
|
{"-(1+2)*5/3", -5},
|
|
|
{"1+(-(1+2)*5/3)", -4},
|
|
|
{"3^4", 81},
|
|
|
{"3^4.5", 140.29611541307906},
|
|
|
{"3.5^4.5", 280.7412308013823},
|
|
|
{"8%2", 0},
|
|
|
{"8%3", 2},
|
|
|
{"8%3.5", 2},
|
|
|
{"1e2", 100},
|
|
|
{"1e+2", 100},
|
|
|
{"1e-2", 0.01},
|
|
|
{"1e-2+1e2", 100.01},
|
|
|
{"1e-2+1e2*6/3", 200.01},
|
|
|
{"(1e-2+1e2)*6/3", 200.02},
|
|
|
{"(88*8)+(1+1+1+1)+(6/1.5)-(99%9*(2^4))", 712},
|
|
|
{"1/3*3", 1},
|
|
|
{"123_456_789", 123456789},
|
|
|
{"123_456_789___", 123456789},
|
|
|
{"pi", 3.141592653589793},
|
|
|
{"abs(1)", 1},
|
|
|
{"abs(-1)", 1},
|
|
|
{"ceil(90.2)", 91},
|
|
|
{"ceil(90.8)", 91},
|
|
|
{"ceil(90.0)", 90},
|
|
|
{"floor(90.2)", 90},
|
|
|
{"floor(90.8)", 90},
|
|
|
{"floor(90.0)", 90},
|
|
|
{"round(90.0)", 90},
|
|
|
{"round(90.4)", 90},
|
|
|
{"round(90.5)", 91},
|
|
|
{"round(90.9)", 91},
|
|
|
{"sqrt(4)", 2},
|
|
|
{"cbrt(27)", 3},
|
|
|
{"sqrt(4) + cbrt(27)", 5},
|
|
|
{"sqrt(2^2) + cbrt(3^3)", 5},
|
|
|
{"127^2+5/2-sqrt(2^2) + cbrt(3^3)", 16132.5},
|
|
|
{"max(2)", 2},
|
|
|
{"max(abs(1)+10)", 11},
|
|
|
{"max(abs(1)+10)*2-1", 21},
|
|
|
{"max(2,3.5)", 3.5},
|
|
|
{"max(2^3,3+abs(-1)*6)", 9},
|
|
|
{"max(2^3,3+abs(-1)*6, 20)", 20},
|
|
|
{"max(2^3,3+abs(-1)*6,ceil(9.4))", 10},
|
|
|
{"max(1,2,3,4,5,6,10,7,4,5,6,9.8)", 10},
|
|
|
{"min(3.5)", 3.5},
|
|
|
{"min(ceil(1.2))", 2},
|
|
|
{"min(2,3.5)", 2},
|
|
|
{"min(2^3,3+abs(-1)*6)", 8},
|
|
|
{"min(2^3,3+abs(-1)*6,1^10)", 1},
|
|
|
{"min(99.1,0.2,3,4,5,6,10,7,4,5,6,9.8)", 0.2},
|
|
|
{"max(2^3,3^2)", 9},
|
|
|
{"min(2^3,3^2)", 8},
|
|
|
{"noerr(1/0)", 0},
|
|
|
{"noerr(1/(1-1))", 0},
|
|
|
{"0.1+0.2", 0.3},
|
|
|
{"0.3-0.1", 0.2},
|
|
|
{"10^-1", 0.1},
|
|
|
{"10^-2", 0.01},
|
|
|
{"10^-1*100", 10},
|
|
|
{"10%0", 0},
|
|
|
}
|
|
|
for _, e := range exprs {
|
|
|
r, _ := ParseAndExec(e.Expr)
|
|
|
if r != e.R {
|
|
|
t.Error(e, " ParseAndExec:", r)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func TestParseAndExecTrigonometric(t *testing.T) {
|
|
|
type U struct {
|
|
|
Expr string
|
|
|
RadianMode float64
|
|
|
AngleMode float64
|
|
|
}
|
|
|
exprs := []U{
|
|
|
{"sin(pi/2)", 1, 0.027412133592044294},
|
|
|
{"csc(pi/2)", 1, 36.48019577324057},
|
|
|
{"cos(0)", 1, 1},
|
|
|
{"sec(0)", 1, 1},
|
|
|
{"tan(pi/4)", 1, 0.013708642534394057},
|
|
|
{"cot(pi/4)", 1, 72.94668290394674},
|
|
|
|
|
|
{"sin(90)", 0.893996663600558, 1},
|
|
|
{"csc(90)", 1.1185724071637082, 1},
|
|
|
{"cos(0)", 1, 1},
|
|
|
{"sec(0)", 1, 1},
|
|
|
{"tan(45)", 1.6197751905438615, 1},
|
|
|
{"cot(45)", 0.6173696237835551, 1},
|
|
|
}
|
|
|
for _, e := range exprs {
|
|
|
TrigonometricMode = RadianMode
|
|
|
r, _ := ParseAndExec(e.Expr)
|
|
|
if r != e.RadianMode {
|
|
|
t.Error(e, " ParseAndExec RadianMode:", r)
|
|
|
}
|
|
|
TrigonometricMode = AngleMode
|
|
|
r, _ = ParseAndExec(e.Expr)
|
|
|
if r != e.AngleMode {
|
|
|
t.Error(e, " ParseAndExec AngleMode:", r)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func TestRegFunction(t *testing.T) {
|
|
|
funs := []struct {
|
|
|
Name string
|
|
|
Argc int
|
|
|
Fun func(expr ...ExprAST) float64
|
|
|
Exp string
|
|
|
R float64
|
|
|
}{
|
|
|
{
|
|
|
"double",
|
|
|
1,
|
|
|
func(expr ...ExprAST) float64 {
|
|
|
return ExprASTResult(expr[0]) * 2
|
|
|
},
|
|
|
"double(6)",
|
|
|
12,
|
|
|
},
|
|
|
{
|
|
|
"percentage50",
|
|
|
1,
|
|
|
func(expr ...ExprAST) float64 {
|
|
|
return ExprASTResult(expr[0]) / 2
|
|
|
},
|
|
|
"percentage50(6)",
|
|
|
3,
|
|
|
},
|
|
|
{
|
|
|
"range",
|
|
|
0,
|
|
|
func(expr ...ExprAST) float64 {
|
|
|
return 10.0
|
|
|
},
|
|
|
"range()",
|
|
|
10,
|
|
|
},
|
|
|
{
|
|
|
"choice",
|
|
|
-1,
|
|
|
func(expr ...ExprAST) float64 {
|
|
|
rand.Seed(time.Now().UnixNano())
|
|
|
return ExprASTResult(expr[rand.Intn(len(expr))])
|
|
|
},
|
|
|
"choice(1.1, 9.8, 2.5, 100)",
|
|
|
10,
|
|
|
},
|
|
|
}
|
|
|
for _, f := range funs {
|
|
|
_ = RegFunction(f.Name, f.Argc, f.Fun)
|
|
|
r, err := ParseAndExec(f.Exp)
|
|
|
if f.Name == "choice" {
|
|
|
if !inSlices(r, []float64{1.1, 9.8, 2.5, 100}) {
|
|
|
t.Error(err, "RegFunction errors when register new function: ", f.Name)
|
|
|
}
|
|
|
continue
|
|
|
} else if r != f.R {
|
|
|
t.Error(err, "RegFunction errors when register new function: ", f.Name)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
func TestParseAndExecError(t *testing.T) {
|
|
|
exprs := []string{
|
|
|
"(",
|
|
|
"((((((",
|
|
|
"((xscdfddff",
|
|
|
"(1",
|
|
|
"(1+",
|
|
|
"1+",
|
|
|
"1*",
|
|
|
"+2344",
|
|
|
"3+(",
|
|
|
"4+(90-",
|
|
|
"3-(4*7-2)+",
|
|
|
"3-(4*7-2)+98*",
|
|
|
"1#1",
|
|
|
"_123_456_789___",
|
|
|
"1ee3+3",
|
|
|
"sin()",
|
|
|
"sin",
|
|
|
"pi(",
|
|
|
"sin(1, 50)",
|
|
|
"max",
|
|
|
"max()",
|
|
|
"max(1,)",
|
|
|
"max(1,4,6,7,5,)",
|
|
|
"min",
|
|
|
"min(,)",
|
|
|
"min()",
|
|
|
"min(1,)",
|
|
|
"min(1,998,4,23,234,2,)",
|
|
|
"min(1,998,4,23,234,2,,,)",
|
|
|
"1/0",
|
|
|
"99.9 / (2-1-1)",
|
|
|
"(1+2)3",
|
|
|
"1+1 111",
|
|
|
"1+1 111+2",
|
|
|
"1 3",
|
|
|
"1 3-",
|
|
|
}
|
|
|
for _, e := range exprs {
|
|
|
_, err := ParseAndExec(e)
|
|
|
if err == nil {
|
|
|
t.Error(e, " this is error expr!")
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
func inSlices(target float64, s []float64) bool {
|
|
|
for _, v := range s {
|
|
|
if v == target {
|
|
|
return true
|
|
|
}
|
|
|
}
|
|
|
return false
|
|
|
} |
...
|
...
|
|