scripts/tests/reproduction_utils/test_call_sites.py
scripts/tests/reproduction_utils/test_call_sites.pyBrowse 41 files
2,361 tokens
8,154 bytes
Token encoding: o200k_base
Snapshot a9fb1c3
← Back to SKILL.md
1import subprocess2import sys3from pathlib import Path4 5import pytest6 7sys.path.insert(0, str(Path(__file__).resolve().parents[2]))8 9import mechanical_refactor_reproduction_utils as rr10from mechanical_refactor_reproduction_utils import (11 Repro,12 _def_span,13 _find_class,14 _find_def,15 _replace_span,16 _slice_span,17 dedent,18 exec_command,19 git_add_and_commit,20 verify_mechanical_refactor,21)22from reproduction_testlib import _apply, _commit, _git, _write # noqa: F40123 24 25def test_lowered_call_text_preserves_magic_trailing_comma(tmp_path: Path) -> None:26 """A magic trailing comma in the original call survives the textual lowering."""27 (tmp_path / "m.py").write_text("x = Old.foo(\n self.r,\n a,\n b,\n)\n")28 r = Repro("b", "t").lower_call_sites("foo", "Old", paths=["m.py"])29 _apply(r, tmp_path)30 assert (tmp_path / "m.py").read_text() == "x = self.r.foo(\n a,\n b,\n)\n"31 32 33# --- lower_call_sites ----------------------------------------------------------34 35 36def test_lower_call_sites_moves_receiver_out_of_args(tmp_path: Path) -> None:37 """Owner.foo(receiver, rest) becomes receiver.foo(rest)."""38 (tmp_path / "m.py").write_text("x = ModelRunner.foo(self.r, a, b)\n")39 r = Repro("b", "t").lower_call_sites("foo", "ModelRunner", paths=["m.py"])40 _apply(r, tmp_path)41 assert (tmp_path / "m.py").read_text() == "x = self.r.foo(a, b)\n"42 43 44def test_lower_call_sites_handles_only_receiver_arg(tmp_path: Path) -> None:45 """Owner.foo(receiver) becomes receiver.foo() without re-lowering the result."""46 (tmp_path / "m.py").write_text("ModelRunner.foo(self.r)\n")47 r = Repro("b", "t").lower_call_sites("foo", "ModelRunner", paths=["m.py"])48 _apply(r, tmp_path)49 assert (tmp_path / "m.py").read_text() == "self.r.foo()\n"50 51 52def test_lower_call_sites_ignores_a_different_owner(tmp_path: Path) -> None:53 """A same-named call on another receiver (e.g. the moved body's own call) is untouched."""54 (tmp_path / "m.py").write_text("worker.foo(zmq)\n")55 r = Repro("b", "t").lower_call_sites("foo", "ModelRunner", paths=["m.py"])56 _apply(r, tmp_path)57 assert (tmp_path / "m.py").read_text() == "worker.foo(zmq)\n"58 59 60def test_lower_call_sites_preserves_magic_trailing_comma(tmp_path: Path) -> None:61 """A magic trailing comma is kept so the formatter re-explodes the lowered call."""62 (tmp_path / "m.py").write_text("ModelRunner.foo(\n self.r,\n a,\n)\n")63 r = Repro("b", "t").lower_call_sites("foo", "ModelRunner", paths=["m.py"])64 _apply(r, tmp_path)65 assert (tmp_path / "m.py").read_text() == "self.r.foo(\n a,\n)\n"66 67 68# --- requalify_call_sites ------------------------------------------------------69 70 71# --- requalify_call_sites ------------------------------------------------------72 73 74def test_requalify_call_sites_drops_the_qualifier(tmp_path: Path) -> None:75 """Owner.bar(args) becomes bar(args) when bar moves to a free function."""76 (tmp_path / "m.py").write_text("y = ModelRunner.bar(a, b)\n")77 r = Repro("b", "t").requalify_call_sites("bar", "ModelRunner", paths=["m.py"])78 _apply(r, tmp_path)79 assert (tmp_path / "m.py").read_text() == "y = bar(a, b)\n"80 81 82def test_route_call_sites_through_field_inserts_the_field(tmp_path: Path) -> None:83 """recv.bar(a) becomes recv.updater.bar(a) when bar moves onto a collaborator field."""84 (tmp_path / "m.py").write_text("y = self.worker.runner.bar(a)\n")85 r = Repro("b", "t").route_call_sites_through_field(86 "bar", field="updater", paths=["m.py"]87 )88 _apply(r, tmp_path)89 assert (tmp_path / "m.py").read_text() == "y = self.worker.runner.updater.bar(a)\n"90 91 92def test_route_call_sites_through_field_skips_an_already_routed_call(93 tmp_path: Path,94) -> None:95 """A call already going through the field is left alone, so the pass converges."""96 (tmp_path / "m.py").write_text("y = self.runner.updater.bar(a)\n")97 r = Repro("b", "t").route_call_sites_through_field(98 "bar", field="updater", paths=["m.py"]99 )100 _apply(r, tmp_path)101 assert (tmp_path / "m.py").read_text() == "y = self.runner.updater.bar(a)\n"102 103 104def test_route_call_sites_through_field_honors_owner_filter(tmp_path: Path) -> None:105 """With owner set, only calls on that exact receiver are routed through the field."""106 (tmp_path / "m.py").write_text("a = x.bar(1)\nb = y.bar(2)\n")107 r = Repro("b", "t").route_call_sites_through_field(108 "bar", field="updater", paths=["m.py"], owner="x"109 )110 _apply(r, tmp_path)111 assert (tmp_path / "m.py").read_text() == "a = x.updater.bar(1)\nb = y.bar(2)\n"112 113 114# --- adversarial audit: call-site rewrites ---------------------------------------115 116 117# --- adversarial audit: call-site rewrites ---------------------------------------118 119 120def test_requalify_call_sites_matches_a_zero_argument_call(tmp_path: Path) -> None:121 """Owner.bar() with no arguments is requalified to bar()."""122 (tmp_path / "m.py").write_text("y = Owner.bar()\n")123 r = Repro("b", "t").requalify_call_sites("bar", "Owner", paths=["m.py"])124 _apply(r, tmp_path)125 assert (tmp_path / "m.py").read_text() == "y = bar()\n"126 127 128def test_lower_call_sites_preserves_comments_inside_a_multiline_call(129 tmp_path: Path,130) -> None:131 """A comment between arguments of the rewritten call must survive."""132 (tmp_path / "m.py").write_text(133 "x = Old.foo(\n self.r,\n a, # keep me\n b,\n)\n"134 )135 r = Repro("b", "t").lower_call_sites("foo", "Old", paths=["m.py"])136 _apply(r, tmp_path)137 assert "# keep me" in (tmp_path / "m.py").read_text()138 139 140def test_lower_call_sites_preserves_arg_literal_spelling(tmp_path: Path) -> None:141 """Hex literals and quote styles inside the rewritten call must not be normalized."""142 (tmp_path / "m.py").write_text('x = Old.foo(self.r, 0x10, "s")\n')143 r = Repro("b", "t").lower_call_sites("foo", "Old", paths=["m.py"])144 _apply(r, tmp_path)145 assert (tmp_path / "m.py").read_text() == 'x = self.r.foo(0x10, "s")\n'146 147 148def test_lower_call_sites_lowers_a_nested_matching_call_too(tmp_path: Path) -> None:149 """A matching call nested inside another matching call is lowered as well."""150 (tmp_path / "m.py").write_text("x = Old.foo(self.r, Old.foo(self.q, 1))\n")151 r = Repro("b", "t").lower_call_sites("foo", "Old", paths=["m.py"])152 _apply(r, tmp_path)153 assert (tmp_path / "m.py").read_text() == "x = self.r.foo(self.q.foo(1))\n"154 155 156def test_lower_call_sites_magic_comma_with_sole_receiver_arg_stays_valid(157 tmp_path: Path,158) -> None:159 """Lowering a magic-comma call whose only argument is the receiver stays valid Python."""160 (tmp_path / "m.py").write_text("Owner.foo(\n self.r,\n)\n")161 r = Repro("b", "t").lower_call_sites("foo", "Owner", paths=["m.py"])162 _apply(r, tmp_path)163 out = (tmp_path / "m.py").read_text()164 compile(out, "m.py", "exec")165 166 167def test_call_rewrite_is_column_accurate_on_non_ascii_lines(tmp_path: Path) -> None:168 """A call after a non-ASCII string on the same line is rewritten at the right columns."""169 (tmp_path / "m.py").write_text('x = "中文"; y = Owner.foo(self.r, 1)\n')170 r = Repro("b", "t").lower_call_sites("foo", "Owner", paths=["m.py"])171 _apply(r, tmp_path)172 assert (tmp_path / "m.py").read_text() == 'x = "中文"; y = self.r.foo(1)\n'173 174 175def test_call_rewrite_survives_a_form_feed_line_start(tmp_path: Path) -> None:176 """A form feed at a line start must not shift the rewrite onto the wrong line."""177 (tmp_path / "m.py").write_text("a = 1\n\x0cb = 2\ny = Owner.foo(self.r, 1)\n")178 r = Repro("b", "t").lower_call_sites("foo", "Owner", paths=["m.py"])179 _apply(r, tmp_path)180 assert (tmp_path / "m.py").read_text() == "a = 1\n\x0cb = 2\ny = self.r.foo(1)\n"181 182 183def test_requalify_call_sites_preserves_redundant_parens_in_kwargs(184 tmp_path: Path,185) -> None:186 """Redundant parentheses around a keyword value survive the requalification."""187 (tmp_path / "m.py").write_text("y = Old.bar(\n a=1,\n b=(2),\n)\n")188 r = Repro("b", "t").requalify_call_sites("bar", "Old", paths=["m.py"])189 _apply(r, tmp_path)190 assert "b=(2)" in (tmp_path / "m.py").read_text()191