Skip to content

Commit 5531662

Browse files
RonnyPfannschmidtCursor AIclaude
committed
test(rewrite): add edge case and regression tests for new visitors
Add TestEdgeCases class combining the new visitors (Subscript, IfExp, method call) with existing ones to verify correct behavior in complex scenarios: - Subscript with variable keys, call keys, and nested subscripts - Method calls with arguments, chained calls, and global objects - IfExp with call conditions - Walrus operator in subscript keys - Single-evaluation guarantees for all new visitors - Custom assert messages still work with new decomposition - Complex assertions combining multiple visitor types Co-authored-by: Cursor AI <ai@cursor.sh> Co-authored-by: Anthropic Claude Opus 4 <claude@anthropic.com>
1 parent 6369f54 commit 5531662

1 file changed

Lines changed: 190 additions & 0 deletions

File tree

testing/test_assertrewrite_coverage.py

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -947,3 +947,193 @@ def items():
947947
return [1, 2, 3]
948948
assert [x * 2 for x in items()] == [2, 4, 7]
949949
""")
950+
951+
952+
# ---------------------------------------------------------------------------
953+
# Edge cases: combinations of new visitors with existing ones
954+
# ---------------------------------------------------------------------------
955+
956+
957+
class TestEdgeCases:
958+
"""Regression and edge-case tests combining multiple expression types."""
959+
960+
def test_subscript_with_variable_key(self) -> None:
961+
"""Subscript where the key is a variable (not constant)."""
962+
assert_introspects(
963+
"""
964+
def check():
965+
d = {"hello": 42}
966+
key = "hello"
967+
assert d[key] == 100
968+
""",
969+
must_contain=["where 42 = ", "['hello']"],
970+
)
971+
972+
def test_subscript_with_call_key(self) -> None:
973+
"""Subscript where the key is a function call."""
974+
assert_introspects(
975+
"""
976+
def check():
977+
d = {0: "zero", 1: "one"}
978+
def get_key():
979+
return 0
980+
assert d[get_key()] == "wrong"
981+
""",
982+
must_contain=["'zero'", "'wrong'"],
983+
)
984+
985+
def test_nested_subscript(self) -> None:
986+
"""Nested subscript: d[k1][k2]."""
987+
assert_introspects(
988+
"""
989+
def check():
990+
d = {"a": {"b": 42}}
991+
assert d["a"]["b"] == 100
992+
""",
993+
must_contain=["42", "100"],
994+
)
995+
996+
def test_method_call_with_args(self) -> None:
997+
"""Method call with arguments shows flat format."""
998+
assert_introspects(
999+
"""
1000+
def check():
1001+
class Calculator:
1002+
def add(self, a, b):
1003+
return a + b
1004+
def __repr__(self):
1005+
return "Calc()"
1006+
c = Calculator()
1007+
assert c.add(2, 3) == 10
1008+
""",
1009+
must_contain=["where 5 = Calc().add(2, 3)"],
1010+
)
1011+
1012+
def test_chained_method_calls(self) -> None:
1013+
"""Chained method call: obj.method1().method2()."""
1014+
assert_introspects(
1015+
"""
1016+
def check():
1017+
class Builder:
1018+
def __init__(self, val=0):
1019+
self.val = val
1020+
def add(self, n):
1021+
return Builder(self.val + n)
1022+
def result(self):
1023+
return self.val
1024+
def __repr__(self):
1025+
return f"Builder({self.val})"
1026+
b = Builder()
1027+
assert b.add(5).result() == 100
1028+
""",
1029+
must_contain=["where 5 = ", ".result()"],
1030+
)
1031+
1032+
def test_subscript_on_method_result(self) -> None:
1033+
"""Subscript on method return value: obj.method()[key]."""
1034+
assert_introspects(
1035+
"""
1036+
def check():
1037+
class Store:
1038+
def get_data(self):
1039+
return {"x": 42}
1040+
def __repr__(self):
1041+
return "Store()"
1042+
s = Store()
1043+
assert s.get_data()["x"] == 100
1044+
""",
1045+
must_contain=["42", "100"],
1046+
)
1047+
1048+
def test_ifexp_with_call_condition(self) -> None:
1049+
"""IfExp where condition is a function call."""
1050+
assert_introspects(
1051+
"""
1052+
def check():
1053+
def is_ready():
1054+
return False
1055+
assert (1 if is_ready() else 0) == 1
1056+
""",
1057+
must_contain=["if False else"],
1058+
)
1059+
1060+
def test_walrus_in_subscript(self) -> None:
1061+
"""Walrus operator used as subscript key."""
1062+
assert_semantically_equivalent("""
1063+
def check():
1064+
d = {1: "one", 2: "two"}
1065+
x = 1
1066+
assert d[(y := x + 1)] == "wrong"
1067+
""")
1068+
1069+
def test_method_call_single_evaluation(self) -> None:
1070+
"""Method with side effects is only called once."""
1071+
assert_single_evaluation("""
1072+
def check():
1073+
class Obj:
1074+
def compute(self):
1075+
counter[0] += 1
1076+
return 42
1077+
obj = Obj()
1078+
assert obj.compute() == 100
1079+
""")
1080+
1081+
def test_subscript_single_evaluation(self) -> None:
1082+
"""Custom __getitem__ with side effects is only called once."""
1083+
assert_single_evaluation("""
1084+
def check():
1085+
class CountingList:
1086+
def __init__(self, items):
1087+
self.items = items
1088+
def __getitem__(self, idx):
1089+
counter[0] += 1
1090+
return self.items[idx]
1091+
def __repr__(self):
1092+
return repr(self.items)
1093+
lst = CountingList([10, 20, 30])
1094+
assert lst[1] == 99
1095+
""")
1096+
1097+
def test_ifexp_condition_single_evaluation(self) -> None:
1098+
"""IfExp condition with side effects is only evaluated once."""
1099+
assert_single_evaluation("""
1100+
def check():
1101+
def check_flag():
1102+
counter[0] += 1
1103+
return True
1104+
assert (0 if check_flag() else 1) == 99
1105+
""")
1106+
1107+
def test_complex_assertion_semantics(self) -> None:
1108+
"""Complex assertion combining multiple new visitors."""
1109+
assert_semantically_equivalent("""
1110+
def check():
1111+
class Config:
1112+
def __init__(self):
1113+
self.data = {"timeout": 30}
1114+
def get(self, key):
1115+
return self.data[key]
1116+
cfg = Config()
1117+
flag = True
1118+
assert (cfg.get("timeout") if flag else 0) > 60
1119+
""")
1120+
1121+
def test_assert_with_message_still_works(self) -> None:
1122+
"""Assert with a custom message still works with new visitors."""
1123+
msg = get_failure_message("""
1124+
def check():
1125+
d = {"key": 42}
1126+
assert d["key"] == 100, "custom failure message"
1127+
""")
1128+
assert "custom failure message" in msg
1129+
1130+
def test_method_call_on_global(self) -> None:
1131+
"""Method call on a global/module-level object."""
1132+
assert_introspects(
1133+
"""
1134+
items = [1, 2, 3]
1135+
def check():
1136+
assert items.count(99) == 1
1137+
""",
1138+
must_contain=["where 0 = [1, 2, 3].count(99)"],
1139+
)

0 commit comments

Comments
 (0)