blob: 411463c4446c9a3857dfb84ee59923e8c9d052ab [file] [log] [blame]
package evaluator
import (
"math"
"matheval/ast"
"matheval/token"
"testing"
)
func TestEvalNumberLit(t *testing.T) {
result, err := Eval(&ast.NumberLit{Value: 42.5})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result != 42.5 {
t.Fatalf("expected 42.5, got %v", result)
}
}
func TestEvalAddition(t *testing.T) {
node := &ast.BinaryExpr{
Op: token.Plus,
Left: &ast.NumberLit{Value: 1},
Right: &ast.NumberLit{Value: 2},
}
result, err := Eval(node)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result != 3 {
t.Fatalf("expected 3, got %v", result)
}
}
func TestEvalSubtraction(t *testing.T) {
node := &ast.BinaryExpr{
Op: token.Minus,
Left: &ast.NumberLit{Value: 10},
Right: &ast.NumberLit{Value: 4},
}
result, err := Eval(node)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result != 6 {
t.Fatalf("expected 6, got %v", result)
}
}
func TestEvalMultiplication(t *testing.T) {
node := &ast.BinaryExpr{
Op: token.Star,
Left: &ast.NumberLit{Value: 3},
Right: &ast.NumberLit{Value: 7},
}
result, err := Eval(node)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result != 21 {
t.Fatalf("expected 21, got %v", result)
}
}
func TestEvalDivision(t *testing.T) {
node := &ast.BinaryExpr{
Op: token.Slash,
Left: &ast.NumberLit{Value: 10},
Right: &ast.NumberLit{Value: 4},
}
result, err := Eval(node)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result != 2.5 {
t.Fatalf("expected 2.5, got %v", result)
}
}
func TestEvalDivisionByZero(t *testing.T) {
node := &ast.BinaryExpr{
Op: token.Slash,
Left: &ast.NumberLit{Value: 5},
Right: &ast.NumberLit{Value: 0},
}
_, err := Eval(node)
if err == nil {
t.Fatal("expected division by zero error")
}
}
func TestEvalNestedExpr(t *testing.T) {
// (1 + 2) * (8 / 4) = 3 * 2 = 6
node := &ast.BinaryExpr{
Op: token.Star,
Left: &ast.BinaryExpr{
Op: token.Plus,
Left: &ast.NumberLit{Value: 1},
Right: &ast.NumberLit{Value: 2},
},
Right: &ast.BinaryExpr{
Op: token.Slash,
Left: &ast.NumberLit{Value: 8},
Right: &ast.NumberLit{Value: 4},
},
}
result, err := Eval(node)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result != 6 {
t.Fatalf("expected 6, got %v", result)
}
}
func TestEvalDeeplyNested(t *testing.T) {
// ((2 + 3) * 4) - (10 / 5) = 20 - 2 = 18
node := &ast.BinaryExpr{
Op: token.Minus,
Left: &ast.BinaryExpr{
Op: token.Star,
Left: &ast.BinaryExpr{
Op: token.Plus,
Left: &ast.NumberLit{Value: 2},
Right: &ast.NumberLit{Value: 3},
},
Right: &ast.NumberLit{Value: 4},
},
Right: &ast.BinaryExpr{
Op: token.Slash,
Left: &ast.NumberLit{Value: 10},
Right: &ast.NumberLit{Value: 5},
},
}
result, err := Eval(node)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if result != 18 {
t.Fatalf("expected 18, got %v", result)
}
}
func TestEvalDivisionByZeroInSubExpr(t *testing.T) {
// 1 + (2 / 0) — error should propagate
node := &ast.BinaryExpr{
Op: token.Plus,
Left: &ast.NumberLit{Value: 1},
Right: &ast.BinaryExpr{
Op: token.Slash,
Left: &ast.NumberLit{Value: 2},
Right: &ast.NumberLit{Value: 0},
},
}
_, err := Eval(node)
if err == nil {
t.Fatal("expected division by zero error from sub-expression")
}
}
func TestEvalFloatingPoint(t *testing.T) {
// 1.5 + 2.3 = 3.8
node := &ast.BinaryExpr{
Op: token.Plus,
Left: &ast.NumberLit{Value: 1.5},
Right: &ast.NumberLit{Value: 2.3},
}
result, err := Eval(node)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if math.Abs(result-3.8) > 1e-12 {
t.Fatalf("expected 3.8, got %v", result)
}
}