Files
agent-orchestrator-benchmark/calculators/builder-solo/run-01/calc/test_parser.py

126 lines
3.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""Tests for calc/parser.py — covers D1D5 from the parse phase plan."""
import unittest
from calc.lexer import tokenize
from calc.parser import parse, ParseError, Num, BinOp, Unary
def p(src: str):
return parse(tokenize(src))
class TestPrecedence(unittest.TestCase):
"""D1 — * and / bind tighter than + and -"""
def test_mul_over_add(self):
# 1+2*3 => BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))
tree = p("1+2*3")
self.assertEqual(tree, BinOp('+', Num(1), BinOp('*', Num(2), Num(3))))
def test_div_over_sub(self):
# 10-6/2 => BinOp('-', Num(10), BinOp('/', Num(6), Num(2)))
tree = p("10-6/2")
self.assertEqual(tree, BinOp('-', Num(10), BinOp('/', Num(6), Num(2))))
def test_mul_then_add(self):
# 2*3+4 => BinOp('+', BinOp('*', Num(2), Num(3)), Num(4))
tree = p("2*3+4")
self.assertEqual(tree, BinOp('+', BinOp('*', Num(2), Num(3)), Num(4)))
class TestLeftAssociativity(unittest.TestCase):
"""D2 — same-precedence operators associate left"""
def test_sub_left_assoc(self):
# 8-3-2 => BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))
tree = p("8-3-2")
self.assertEqual(tree, BinOp('-', BinOp('-', Num(8), Num(3)), Num(2)))
def test_div_left_assoc(self):
# 8/4/2 => BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))
tree = p("8/4/2")
self.assertEqual(tree, BinOp('/', BinOp('/', Num(8), Num(4)), Num(2)))
def test_add_left_assoc(self):
# 1+2+3 => BinOp('+', BinOp('+', Num(1), Num(2)), Num(3))
tree = p("1+2+3")
self.assertEqual(tree, BinOp('+', BinOp('+', Num(1), Num(2)), Num(3)))
class TestParentheses(unittest.TestCase):
"""D3 — parens override precedence"""
def test_paren_forces_add_under_mul(self):
# (1+2)*3 => BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))
tree = p("(1+2)*3")
self.assertEqual(tree, BinOp('*', BinOp('+', Num(1), Num(2)), Num(3)))
def test_nested_parens(self):
# ((2+3)) => BinOp('+', Num(2), Num(3))
tree = p("((2+3))")
self.assertEqual(tree, BinOp('+', Num(2), Num(3)))
def test_paren_inside_expr(self):
# 1*(2+3)*4 => BinOp('*', BinOp('*', Num(1), BinOp('+', Num(2), Num(3))), Num(4))
tree = p("1*(2+3)*4")
self.assertEqual(
tree,
BinOp('*', BinOp('*', Num(1), BinOp('+', Num(2), Num(3))), Num(4))
)
class TestUnaryMinus(unittest.TestCase):
"""D4 — unary minus"""
def test_leading_unary(self):
# -5 => Unary('-', Num(5))
tree = p("-5")
self.assertEqual(tree, Unary('-', Num(5)))
def test_unary_grouped(self):
# -(1+2) => Unary('-', BinOp('+', Num(1), Num(2)))
tree = p("-(1+2)")
self.assertEqual(tree, Unary('-', BinOp('+', Num(1), Num(2))))
def test_mul_unary(self):
# 3 * -2 => BinOp('*', Num(3), Unary('-', Num(2)))
tree = p("3 * -2")
self.assertEqual(tree, BinOp('*', Num(3), Unary('-', Num(2))))
def test_double_unary(self):
# --5 => Unary('-', Unary('-', Num(5)))
tree = p("--5")
self.assertEqual(tree, Unary('-', Unary('-', Num(5))))
class TestErrors(unittest.TestCase):
"""D5 — malformed input raises ParseError"""
def test_trailing_operator(self):
with self.assertRaises(ParseError):
p("1 +")
def test_unclosed_paren(self):
with self.assertRaises(ParseError):
p("(1")
def test_extra_number(self):
with self.assertRaises(ParseError):
p("1 2")
def test_close_before_open(self):
with self.assertRaises(ParseError):
p(")(")
def test_empty_string(self):
with self.assertRaises(ParseError):
p("")
def test_only_operator(self):
with self.assertRaises(ParseError):
p("+")
if __name__ == "__main__":
unittest.main()