Files
agent-orchestrator-benchmark/calculators/builder-adversary-stateless/run-05/calc/test_parser.py

155 lines
4.4 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."""
import unittest
from calc.lexer import tokenize
from calc.parser import BinOp, Num, ParseError, Unary, parse
def p(src):
return parse(tokenize(src))
class TestPrecedence(unittest.TestCase):
"""D1 — * and / bind tighter than + and -."""
def test_add_mul(self):
# 1+2*3 → BinOp('+', Num(1), BinOp('*', Num(2), Num(3)))
self.assertEqual(p("1+2*3"), BinOp("+", Num(1), BinOp("*", Num(2), Num(3))))
def test_mul_add(self):
# 2*3+4 → BinOp('+', BinOp('*', Num(2), Num(3)), Num(4))
self.assertEqual(p("2*3+4"), BinOp("+", BinOp("*", Num(2), Num(3)), Num(4)))
def test_add_div(self):
# 1+8/4 → BinOp('+', Num(1), BinOp('/', Num(8), Num(4)))
self.assertEqual(p("1+8/4"), BinOp("+", Num(1), BinOp("/", Num(8), Num(4))))
def test_sub_mul(self):
# 10-2*3 → BinOp('-', Num(10), BinOp('*', Num(2), Num(3)))
self.assertEqual(
p("10-2*3"), BinOp("-", Num(10), BinOp("*", Num(2), Num(3)))
)
def test_single_number(self):
self.assertEqual(p("42"), Num(42))
def test_single_float(self):
self.assertEqual(p("3.14"), Num(3.14))
class TestLeftAssociativity(unittest.TestCase):
"""D2 — same-precedence operators associate left."""
def test_sub_sub(self):
# 8-3-2 → BinOp('-', BinOp('-', Num(8), Num(3)), Num(2))
self.assertEqual(
p("8-3-2"), BinOp("-", BinOp("-", Num(8), Num(3)), Num(2))
)
def test_div_div(self):
# 8/4/2 → BinOp('/', BinOp('/', Num(8), Num(4)), Num(2))
self.assertEqual(
p("8/4/2"), BinOp("/", BinOp("/", Num(8), Num(4)), Num(2))
)
def test_add_add(self):
# 1+2+3 → BinOp('+', BinOp('+', Num(1), Num(2)), Num(3))
self.assertEqual(
p("1+2+3"), BinOp("+", BinOp("+", Num(1), Num(2)), Num(3))
)
def test_mul_mul(self):
# 2*3*4 → BinOp('*', BinOp('*', Num(2), Num(3)), Num(4))
self.assertEqual(
p("2*3*4"), BinOp("*", BinOp("*", Num(2), Num(3)), Num(4))
)
class TestParentheses(unittest.TestCase):
"""D3 — parentheses override precedence."""
def test_parens_override_mul(self):
# (1+2)*3 → BinOp('*', BinOp('+', Num(1), Num(2)), Num(3))
self.assertEqual(
p("(1+2)*3"), BinOp("*", BinOp("+", Num(1), Num(2)), Num(3))
)
def test_nested_parens(self):
# ((1+2)) → BinOp('+', Num(1), Num(2))
self.assertEqual(p("((1+2))"), BinOp("+", Num(1), Num(2)))
def test_parens_inside_add(self):
# 1+(2+3) → BinOp('+', Num(1), BinOp('+', Num(2), Num(3)))
self.assertEqual(
p("1+(2+3)"), BinOp("+", Num(1), BinOp("+", Num(2), Num(3)))
)
def test_parens_alone(self):
self.assertEqual(p("(5)"), Num(5))
class TestUnaryMinus(unittest.TestCase):
"""D4 — unary minus."""
def test_leading_unary(self):
# -5 → Unary('-', Num(5))
self.assertEqual(p("-5"), Unary("-", Num(5)))
def test_unary_of_paren(self):
# -(1+2) → Unary('-', BinOp('+', Num(1), Num(2)))
self.assertEqual(
p("-(1+2)"), Unary("-", BinOp("+", Num(1), Num(2)))
)
def test_mul_unary(self):
# 3 * -2 → BinOp('*', Num(3), Unary('-', Num(2)))
self.assertEqual(
p("3 * -2"), BinOp("*", Num(3), Unary("-", Num(2)))
)
def test_double_unary(self):
# --5 → Unary('-', Unary('-', Num(5)))
self.assertEqual(p("--5"), Unary("-", Unary("-", Num(5))))
def test_unary_in_add(self):
# 1 + -2 → BinOp('+', Num(1), Unary('-', Num(2)))
self.assertEqual(
p("1 + -2"), BinOp("+", Num(1), Unary("-", Num(2)))
)
class TestErrors(unittest.TestCase):
"""D5 — malformed input raises ParseError."""
def _raises(self, src):
with self.assertRaises(ParseError):
p(src)
def test_trailing_op(self):
self._raises("1 +")
def test_unclosed_paren(self):
self._raises("(1")
def test_two_numbers(self):
self._raises("1 2")
def test_close_before_open(self):
self._raises(")(")
def test_empty(self):
self._raises("")
def test_just_op(self):
self._raises("*")
def test_mismatched_parens(self):
self._raises("(1+2")
def test_extra_close(self):
self._raises("(1+2))")
if __name__ == "__main__":
unittest.main()