-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathtest_minify_projection.py
More file actions
282 lines (235 loc) · 11.2 KB
/
Copy pathtest_minify_projection.py
File metadata and controls
282 lines (235 loc) · 11.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
"""Tests for the tree-sitter minified source projection (read view + mapped edits)."""
from __future__ import annotations
import tempfile
from pathlib import Path
from typing import Any
import pytest
from lemoncrow.pro.capabilities.source_projection import (
MinifiedEditError,
apply_minified_edit,
build_minified_projection,
language_for_minify,
minified_line_gutter,
)
from lemoncrow.pro.capabilities.tool_supervision.rich_edit import apply_rich_edits
PY_SAMPLE = '''"""Module docstring."""
import os
def add(a, b):
"""Return the sum."""
# inline note
label = "keep inner spaces"
return a + b
class Worker:
"""Worker doc."""
value = 1
def run(self):
return add(self.value, 2)
'''
def _reconstructs(result: Any) -> bool:
rebuilt = "".join(result.content[s.projected_start : s.projected_end] for s in result.mapping.segments)
return bool(rebuilt == result.content)
def test_strips_comments_and_blanks_keeps_strings_and_docstrings() -> None:
r = build_minified_projection(PY_SAMPLE, "python", path="m.py", include_mapping=True)
assert r.applied
assert "Module docstring" in r.content # docstrings preserved (semantic content)
assert "Return the sum" in r.content
assert "Worker doc" in r.content
assert "# inline note" not in r.content # comment stripped
assert "keep inner spaces" in r.content # string interior preserved verbatim
assert "\n\n\n" not in r.content # blank-line runs collapsed
assert r.saved_tokens > 0
def test_mapping_reconstructs_and_is_idempotent() -> None:
r = build_minified_projection(PY_SAMPLE, "python", path="m.py", include_mapping=True)
assert r.mapping is not None and r.mapping.projection_kind == "minified"
assert _reconstructs(r)
again = build_minified_projection(r.content, "python")
assert (not again.applied) or again.content == r.content
def test_docstrings_preserved_when_minifying() -> None:
src = 'def stub():\n """Only docstring."""\n\n\ndef real():\n # x\n return 1\n'
r = build_minified_projection(src, "python")
assert r.applied # blank lines + comment still yield savings
assert "Only docstring" in r.content # docstring preserved verbatim
assert "# x" not in r.content
def test_unicode_is_byte_safe() -> None:
src = 'def f():\n # café ☕\n return "naïve"\n'
r = build_minified_projection(src, "python", include_mapping=True)
assert r.applied and _reconstructs(r)
assert "café" not in r.content # comment dropped
assert 'return "naïve"' in r.content
def test_go_minifies_without_indentation() -> None:
src = 'package main\n\n// greet\nfunc Greet() {\n\tprintln( "hi" )\n}\n'
r = build_minified_projection(src, "go", path="g.go", include_mapping=True)
assert r.applied and _reconstructs(r)
assert "// greet" not in r.content
assert 'println( "hi" )' in r.content
def test_excluded_language_skips() -> None:
r = build_minified_projection("# Title\n\nsome prose\n", "markdown")
assert not r.applied
def test_language_for_minify_resolution() -> None:
assert language_for_minify("a.py") == "python"
assert language_for_minify("a.go") == "go"
assert language_for_minify("a.md") is None
assert language_for_minify("a.unknownext") is None
def test_edit_round_trip_python_preserves_disk_comment_and_docstring() -> None:
updated, line_start, line_end = apply_minified_edit(PY_SAMPLE, "python", "return a + b", "return a + b + 1")
assert "return a + b + 1" in updated
assert "# inline note" in updated # comment intact on disk
assert "Return the sum" in updated # docstring intact on disk
assert line_start == line_end
def test_edit_round_trip_go() -> None:
src = 'package main\n\nfunc Greet(name string) {\n\tprintln("hi", name) // x\n}\n'
updated, _, _ = apply_minified_edit(src, "go", 'println("hi", name)', 'println("hello", name)')
assert 'println("hello", name)' in updated
assert "// x" in updated # trailing comment intact on disk
def test_edit_ambiguous_raises() -> None:
# The comment makes minification apply; the duplicated statement is ambiguous.
src = "def f():\n # note\n x = 1\n x = 1\n return x\n"
with pytest.raises(MinifiedEditError) as exc:
apply_minified_edit(src, "python", "x = 1", "x = 2")
assert exc.value.code == "ambiguous"
def test_edit_no_match_raises() -> None:
with pytest.raises(MinifiedEditError) as exc:
apply_minified_edit(PY_SAMPLE, "python", "nonexistent_token_xyz", "z")
assert exc.value.code == "no_match"
def test_edit_fuzzy_fallback_recovers_near_miss_reconstruction() -> None:
# old_string is neither an exact match against disk (missing the trailing
# whitespace on the email-config line) nor against the minified view (same
# gap, since minification doesn't add it back) -- a plausible "recalled
# from memory instead of copy-pasted" near miss. The exact-substring check
# in minified space misses it; the new fuzzy fallback should still locate
# the one unambiguous match and splice the edit back onto real disk content.
src = (
"import subprocess\n"
"from pathlib import Path\n"
"\n"
"\n"
"def make_repo(tmp_path: Path) -> Path:\n"
' root = tmp_path / "repo"\n'
" root.mkdir()\n"
' subprocess.run(["git", "init", "-q"], cwd=root, check=True)\n'
' subprocess.run(["git", "config", "user.email", "t@t.com"], cwd=root, check=True) \n'
' subprocess.run(["git", "config", "user.name", "t"], cwd=root, check=True)\n'
" return root\n"
)
old_string = (
"def make_repo(tmp_path: Path) -> Path:\n"
' root = tmp_path / "repo"\n'
" root.mkdir()\n"
' subprocess.run(["git", "init", "-q"], cwd=root, check=True)\n'
' subprocess.run(["git", "config", "user.email", "t@t.com"], cwd=root, check=True)\n'
' subprocess.run(["git", "config", "user.name", "t"], cwd=root, check=True)\n'
" return root"
)
new_string = old_string.replace("return root", "return root.resolve()")
updated, line_start, line_end = apply_minified_edit(src, "python", old_string, new_string)
assert "return root.resolve()" in updated
assert updated.count("subprocess.run") == 3
assert line_start <= line_end
def test_edit_fuzzy_ambiguous_in_minified_space_falls_back_not_crashes() -> None:
# old_string dropped one of several near-identical `import` lines while
# recalling the file from memory; every remaining import line loosely
# matches old_string's first line, and all resulting candidate windows
# converge on the same unique end anchor -- so multiple windows clear the
# similarity floor within the ambiguity margin of each other.
# apply_minified_edit must surface this as a MinifiedEditError(code=
# "ambiguous") -- the same contract as every other failure mode -- and not
# let the underlying FuzzyAmbiguousMatchError escape, which would skip
# rich_edit's fall-through to plain full-text fuzzy matching (its
# `except MinifiedEditError: pass` wouldn't catch a bare ValueError subtype
# it doesn't name).
src = (
"import os\n"
"import sys\n"
"import re\n"
"import json\n"
"\n"
"\n"
"def helper():\n"
" x = 1\n"
" y = 2\n"
" z = 3\n"
" return x + y + z\n"
"\n"
"\n"
"# a trailing module note kept only to give the minifier real savings\n"
"VERSION = 1\n"
)
old_string = (
"import os\n"
"import sys\n"
"import json\n" # 'import re' forgotten
"\n"
"\n"
"def helper():\n"
" x = 1\n"
" y = 2\n"
" z = 3\n"
" return x + y + z"
)
with pytest.raises(MinifiedEditError) as exc:
apply_minified_edit(src, "python", old_string, old_string + " # x")
assert exc.value.code == "ambiguous"
def test_minified_line_gutter_resolves_line_within_multiline_segment() -> None:
# A multi-line exact segment (a docstring here) is copied byte-for-byte
# into the projection -- each of ITS lines must get its own real disk
# line, not the segment's first line repeated. Regression for a bug where
# every projected line inside a >1-line exact segment was stamped with
# `segment.source.start_line`.
src = (
"def f():\n"
" '''Line one.\n"
"\n"
" Line three.\n"
" Line four.\n"
" '''\n"
" # strip me\n"
" a = 1\n"
)
result = build_minified_projection(src, "python", include_mapping=True, path="ds.py")
assert result.applied and result.mapping is not None
gutter = minified_line_gutter(result.content, result.mapping)
disk_lines = src.splitlines()
for gline in gutter.splitlines():
num_str, _, text = gline.partition("\t")
disk_line = disk_lines[int(num_str) - 1]
# Non-blank projected lines must carry non-empty text; a blank
# docstring line (disk line 3 here) legitimately has none.
assert text or disk_line.strip() == ""
# The gutter number's disk line must actually contain this text.
assert disk_line.strip() == text.strip()
# And distinct source lines inside the docstring get DISTINCT numbers.
numbers = [int(gline.partition("\t")[0]) for gline in gutter.splitlines()]
assert numbers == sorted(set(numbers)) # strictly increasing, no repeats
assert numbers == [1, 2, 3, 4, 5, 6, 8] # disk line 7 (dropped comment) absent
def test_edit_dropped_interior_fails_closed() -> None:
# old_string as seen in the minified view spans a comment dropped on disk.
src = "def f():\n a = 1\n # critical\n b = 2\n return a + b\n"
with pytest.raises(MinifiedEditError) as exc:
apply_minified_edit(src, "python", "a = 1\n b = 2", "a = 10\n b = 20")
assert exc.value.code == "comment_inside_span"
def test_rich_edit_minified_fallback_applies() -> None:
disk = "def compute():\n total = 0\n return total\n"
with tempfile.TemporaryDirectory() as d:
f = Path(d) / "m.py"
f.write_text(disk, encoding="utf-8")
res = apply_rich_edits(
[{"file_path": str(f), "old_string": "total = 0", "new_string": "total = 42"}],
repo_root=d,
)
assert not res["rolled_back"]
assert res["applied"][0]["match_mode"] == "minified"
after = f.read_text(encoding="utf-8")
assert "total = 42" in after
assert "total =" not in after
def test_rich_edit_minified_fails_closed_preserves_comment() -> None:
disk = "def f():\n x = 1\n # critical\n y = 2\n return x + y\n"
with tempfile.TemporaryDirectory() as d:
f = Path(d) / "n.py"
f.write_text(disk, encoding="utf-8")
res = apply_rich_edits(
[{"file_path": str(f), "old_string": "x = 1\n y = 2", "new_string": "x = 10\n y = 20"}],
repo_root=d,
)
# minified fails closed (comment inside span) -> fuzzy -> rejected -> rollback
assert res["rolled_back"]
assert "# critical" in f.read_text(encoding="utf-8")