File size: 4,725 Bytes
9aa5185 | 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 | """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(self, path, offset=1, limit=500):
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'
)
|