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

121 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 covering DoD gates D1D5."""
import unittest
from calc.lexer import tokenize
from calc.parser import parse, ParseError, Num, BinOp, Unary
def p(src: str):
"""Shorthand: tokenize then parse."""
return parse(tokenize(src))
class TestD1Precedence(unittest.TestCase):
def test_mul_binds_tighter_than_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_binds_tighter_than_sub(self):
# 9-6/2 => BinOp('-', Num(9), BinOp('/', Num(6), Num(2)))
tree = p("9-6/2")
self.assertEqual(tree, BinOp("-", Num(9), BinOp("/", Num(6), Num(2))))
def test_add_before_mul_different_shape(self):
# 1+2*3 must NOT parse as (1+2)*3
tree = p("1+2*3")
self.assertNotEqual(tree, BinOp("*", BinOp("+", Num(1), Num(2)), Num(3)))
class TestD2LeftAssociativity(unittest.TestCase):
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)))
def test_mul_left_assoc(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 TestD3Parentheses(unittest.TestCase):
def test_parens_override_precedence(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)) (extra parens transparent)
tree = p("((2+3))")
self.assertEqual(tree, BinOp("+", Num(2), Num(3)))
def test_parens_and_precedence_mixed(self):
# 2*(3+4*5) => BinOp('*', Num(2), BinOp('+', Num(3), BinOp('*', Num(4), Num(5))))
tree = p("2*(3+4*5)")
self.assertEqual(
tree,
BinOp("*", Num(2), BinOp("+", Num(3), BinOp("*", Num(4), Num(5)))),
)
class TestD4UnaryMinus(unittest.TestCase):
def test_leading_unary(self):
# -5 => Unary('-', Num(5))
tree = p("-5")
self.assertEqual(tree, Unary("-", Num(5)))
def test_unary_in_parens(self):
# -(1+2) => Unary('-', BinOp('+', Num(1), Num(2)))
tree = p("-(1+2)")
self.assertEqual(tree, Unary("-", BinOp("+", Num(1), Num(2))))
def test_unary_after_binop(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 TestD5Errors(unittest.TestCase):
def _raises(self, src: str):
with self.assertRaises(ParseError, msg=f"expected ParseError for {src!r}"):
p(src)
def test_trailing_operator(self):
self._raises("1 +")
def test_unclosed_paren(self):
self._raises("(1")
def test_two_numbers_no_op(self):
self._raises("1 2")
def test_close_before_open(self):
self._raises(")(")
def test_empty_string(self):
self._raises("")
def test_open_close_no_expr(self):
# "()" should fail — no expression inside
self._raises("()")
if __name__ == "__main__":
unittest.main()