Something went wrong. Try again.
The agent that grows with you
Something went wrong. Try again.
16 kB · 511 lines
Python
at bb/theme
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512"""Tests for the V4A patch format parser."""
from types import SimpleNamespace
from tools.patch_parser import ( OperationType, apply_v4a_operations, parse_v4a_patch,)
class TestParseUpdateFile: def test_basic_update(self): patch = """\*** Begin Patch*** Update File: src/main.py@@ def greet @@ def greet():- print("hello")+ print("hi")*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None assert len(ops) == 1
op = ops[0] assert op.operation == OperationType.UPDATE assert op.file_path == "src/main.py" assert len(op.hunks) == 1
hunk = op.hunks[0] assert hunk.context_hint == "def greet" prefixes = [l.prefix for l in hunk.lines] assert " " in prefixes assert "-" in prefixes assert "+" in prefixes
def test_multiple_hunks(self): patch = """\*** Begin Patch*** Update File: f.py@@ first @@ a-b+c@@ second @@ x-y+z*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None assert len(ops) == 1 assert len(ops[0].hunks) == 2 assert ops[0].hunks[0].context_hint == "first" assert ops[0].hunks[1].context_hint == "second"
class TestParseAddFile: def test_add_file(self): patch = """\*** Begin Patch*** Add File: new/module.py+import os++print("hello")*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None assert len(ops) == 1
op = ops[0] assert op.operation == OperationType.ADD assert op.file_path == "new/module.py" assert len(op.hunks) == 1
contents = [l.content for l in op.hunks[0].lines if l.prefix == "+"] assert contents[0] == "import os" assert contents[2] == 'print("hello")'
class TestParseDeleteFile: def test_delete_file(self): patch = """\*** Begin Patch*** Delete File: old/stuff.py*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None assert len(ops) == 1 assert ops[0].operation == OperationType.DELETE assert ops[0].file_path == "old/stuff.py"
class TestParseMoveFile: def test_move_file(self): patch = """\*** Begin Patch*** Move File: old/path.py -> new/path.py*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None assert len(ops) == 1 assert ops[0].operation == OperationType.MOVE assert ops[0].file_path == "old/path.py" assert ops[0].new_path == "new/path.py"
class TestParseInvalidPatch: def test_empty_patch_returns_empty_ops(self): ops, err = parse_v4a_patch("") assert err is None assert ops == []
def test_no_begin_marker_still_parses(self): patch = """\*** Update File: f.py line1-old+new*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None assert len(ops) == 1
def test_multiple_operations(self): patch = """\*** Begin Patch*** Add File: a.py+content_a*** Delete File: b.py*** Update File: c.py keep-remove+add*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None assert len(ops) == 3 assert ops[0].operation == OperationType.ADD assert ops[1].operation == OperationType.DELETE assert ops[2].operation == OperationType.UPDATE
class TestApplyUpdate: def test_preserves_non_prefix_pipe_characters_in_unmodified_lines(self): patch = """\*** Begin Patch*** Update File: sample.py@@ result @@ result = 1- return result+ return result + 1*** End Patch""" operations, err = parse_v4a_patch(patch) assert err is None
class FakeFileOps: def __init__(self): self.written = None
def read_file_raw(self, path): return SimpleNamespace( content=( 'def run():\n' ' cmd = "echo a | sed s/a/b/"\n' ' result = 1\n' ' return result' ), error=None, )
def write_file(self, path, content): self.written = content return SimpleNamespace(error=None)
file_ops = FakeFileOps()
result = apply_v4a_operations(operations, file_ops)
assert result.success is True assert file_ops.written == ( 'def run():\n' ' cmd = "echo a | sed s/a/b/"\n' ' result = 1\n' ' return result + 1' )
class TestAdditionOnlyHunks: """Regression tests for #3081 — addition-only hunks were silently dropped."""
def test_addition_only_hunk_with_context_hint(self): """A hunk with only + lines should insert at the context hint location.""" patch = """\*** Begin Patch*** Update File: src/app.py@@ def main @@+def helper():+ return 42*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None assert len(ops) == 1 assert len(ops[0].hunks) == 1
hunk = ops[0].hunks[0] # All lines should be additions assert all(l.prefix == '+' for l in hunk.lines)
# Apply to a file that contains the context hint class FakeFileOps: written = None def read_file_raw(self, path): return SimpleNamespace( content="def main():\n pass\n", error=None, ) def write_file(self, path, content): self.written = content return SimpleNamespace(error=None)
file_ops = FakeFileOps() result = apply_v4a_operations(ops, file_ops) assert result.success is True assert "def helper():" in file_ops.written assert "return 42" in file_ops.written
def test_addition_only_hunk_without_context_hint(self): """A hunk with only + lines and no context hint appends at end of file.""" patch = """\*** Begin Patch*** Update File: src/app.py+def new_func():+ return True*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None
class FakeFileOps: written = None def read_file_raw(self, path): return SimpleNamespace( content="existing = True\n", error=None, ) def write_file(self, path, content): self.written = content return SimpleNamespace(error=None)
file_ops = FakeFileOps() result = apply_v4a_operations(ops, file_ops) assert result.success is True assert file_ops.written.endswith("def new_func():\n return True\n") assert "existing = True" in file_ops.written
class TestReadFileRaw: """Bug 1 regression tests — files > 2000 lines and lines > 2000 chars."""
def test_apply_update_file_over_2000_lines(self): """A hunk targeting line 2200 must not truncate the file to 2000 lines.""" patch = """\*** Begin Patch*** Update File: big.py@@ marker_at_2200 @@ line_2200-old_value+new_value*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None
# Build a 2500-line file; the hunk targets a region at line 2200 lines = [f"line_{i}" for i in range(1, 2501)] lines[2199] = "line_2200" # index 2199 = line 2200 lines[2200] = "old_value" file_content = "\n".join(lines)
class FakeFileOps: written = None def read_file_raw(self, path): return SimpleNamespace(content=file_content, error=None) def write_file(self, path, content): self.written = content return SimpleNamespace(error=None)
file_ops = FakeFileOps() result = apply_v4a_operations(ops, file_ops) assert result.success is True written_lines = file_ops.written.split("\n") assert len(written_lines) == 2500, ( f"Expected 2500 lines, got {len(written_lines)}" ) assert "new_value" in file_ops.written assert "old_value" not in file_ops.written
def test_apply_update_preserves_long_lines(self): """A line > 2000 chars must be preserved verbatim after an unrelated hunk.""" long_line = "x" * 3000 patch = """\*** Begin Patch*** Update File: wide.py@@ short_func @@ def short_func():- return 1+ return 2*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None
file_content = f"def short_func():\n return 1\n{long_line}\n"
class FakeFileOps: written = None def read_file_raw(self, path): return SimpleNamespace(content=file_content, error=None) def write_file(self, path, content): self.written = content return SimpleNamespace(error=None)
file_ops = FakeFileOps() result = apply_v4a_operations(ops, file_ops) assert result.success is True assert long_line in file_ops.written, "Long line was truncated" assert "... [truncated]" not in file_ops.written
class TestValidationPhase: """Bug 2 regression tests — validation prevents partial apply."""
def test_validation_failure_writes_nothing(self): """If one hunk is invalid, no files should be written.""" patch = """\*** Begin Patch*** Update File: a.py def good():- return 1+ return 2*** Update File: b.py THIS LINE DOES NOT EXIST- old+ new*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None
written = {}
class FakeFileOps: def read_file_raw(self, path): files = { "a.py": "def good():\n return 1\n", "b.py": "completely different content\n", } content = files.get(path) if content is None: return SimpleNamespace(content=None, error=f"File not found: {path}") return SimpleNamespace(content=content, error=None)
def write_file(self, path, content): written[path] = content return SimpleNamespace(error=None)
result = apply_v4a_operations(ops, FakeFileOps()) assert result.success is False assert written == {}, f"No files should have been written, got: {list(written.keys())}" assert "validation failed" in result.error.lower()
def test_all_valid_operations_applied(self): """When all operations are valid, all files are written.""" patch = """\*** Begin Patch*** Update File: a.py def foo():- return 1+ return 2*** Update File: b.py def bar():- pass+ return True*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None
written = {}
class FakeFileOps: def read_file_raw(self, path): files = { "a.py": "def foo():\n return 1\n", "b.py": "def bar():\n pass\n", } return SimpleNamespace(content=files[path], error=None)
def write_file(self, path, content): written[path] = content return SimpleNamespace(error=None)
result = apply_v4a_operations(ops, FakeFileOps()) assert result.success is True assert set(written.keys()) == {"a.py", "b.py"}
class TestApplyDelete: """Tests for _apply_delete producing a real unified diff."""
def test_delete_diff_contains_removed_lines(self): """_apply_delete must embed the actual file content in the diff, not a placeholder.""" patch = """\*** Begin Patch*** Delete File: old/stuff.py*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None
class FakeFileOps: deleted = False
def read_file_raw(self, path): return SimpleNamespace( content="def old_func():\n return 42\n", error=None, )
def delete_file(self, path): self.deleted = True return SimpleNamespace(error=None)
file_ops = FakeFileOps() result = apply_v4a_operations(ops, file_ops)
assert result.success is True assert file_ops.deleted is True # Diff must contain the actual removed lines, not a bare comment assert "-def old_func():" in result.diff assert "- return 42" in result.diff assert "/dev/null" in result.diff
def test_delete_diff_fallback_on_empty_file(self): """An empty file should produce the fallback comment diff.""" patch = """\*** Begin Patch*** Delete File: empty.py*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None
class FakeFileOps: def read_file_raw(self, path): return SimpleNamespace(content="", error=None)
def delete_file(self, path): return SimpleNamespace(error=None)
result = apply_v4a_operations(ops, FakeFileOps()) assert result.success is True # unified_diff produces nothing for two empty inputs — fallback comment expected assert "Deleted" in result.diff or result.diff.strip() == ""
class TestCountOccurrences: def test_basic(self): from tools.patch_parser import _count_occurrences assert _count_occurrences("aaa", "a") == 3 assert _count_occurrences("aaa", "aa") == 2 assert _count_occurrences("hello world", "xyz") == 0 assert _count_occurrences("", "x") == 0
class TestParseErrorSignalling: """Bug 3 regression tests — parse_v4a_patch must signal errors, not swallow them."""
def test_update_with_no_hunks_returns_error(self): """An UPDATE with no hunk lines is a malformed patch and should error.""" patch = """\*** Begin Patch*** Update File: foo.py*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is not None, "Expected a parse error for hunk-less UPDATE" assert ops == []
def test_move_without_destination_returns_error(self): """A MOVE without '->' syntax should not silently produce a broken operation.""" # The move regex requires '->' so this will be treated as an unrecognised # line and the op is never created. Confirm nothing crashes and ops is empty. patch = """\*** Begin Patch*** Move File: src/foo.py*** End Patch""" ops, err = parse_v4a_patch(patch) # Either parse sees zero ops (fine) or returns an error (also fine). # What is NOT acceptable is ops=[MOVE op with empty new_path] + err=None. if ops: assert err is not None, ( "MOVE with missing destination must either produce empty ops or an error" )
def test_valid_patch_returns_no_error(self): """A well-formed patch must still return err=None.""" patch = """\*** Begin Patch*** Update File: f.py ctx-old+new*** End Patch""" ops, err = parse_v4a_patch(patch) assert err is None assert len(ops) == 1