20
from bzrlib.tests import TestCase
20
from breezy.tests import TestCase
22
from bzrlib.iterablefile import IterableFile
23
from bzrlib.patches import (MalformedLine,
22
from breezy.iterablefile import IterableFile
23
from breezy.patches import (MalformedLine,
24
24
MalformedHunkHeader,
25
25
MalformedPatchHeader,
45
45
def datafile(self, filename):
46
46
data_path = os.path.join(os.path.dirname(__file__),
47
47
"test_patches_data", filename)
48
return file(data_path, "rb")
48
return open(data_path, "rb")
50
50
def data_lines(self, filename):
51
51
datafile = self.datafile(filename)
57
57
def test_parse_patches_leading_noise(self):
58
# https://bugs.edge.launchpad.net/bzr/+bug/502076
59
# https://code.edge.launchpad.net/~toshio/bzr/allow-dirty-patches/+merge/18854
58
# https://bugs.launchpad.net/bzr/+bug/502076
59
# https://code.launchpad.net/~toshio/bzr/allow-dirty-patches/+merge/18854
60
60
lines = ["diff -pruN commands.py",
61
"--- orig/commands.py",
62
"+++ mod/dommands.py"]
61
"--- orig/commands.py",
62
"+++ mod/dommands.py"]
63
63
bits = parse_patches(iter(lines), allow_dirty=True)
65
def test_preserve_dirty_head(self):
66
"""Parse a patch containing a dirty header, and preserve lines"""
67
lines = ["=== added directory 'foo/bar'\n",
68
"=== modified file 'orig/commands.py'\n",
69
"--- orig/commands.py\n",
70
"+++ mod/dommands.py\n",
71
"=== modified file 'orig/another.py'\n",
72
"--- orig/another.py\n",
73
"+++ mod/another.py\n"]
74
patches = parse_patches(
75
lines.__iter__(), allow_dirty=True, keep_dirty=True)
76
self.assertLength(2, patches)
77
self.assertEqual(patches[0]['dirty_head'],
78
["=== added directory 'foo/bar'\n",
79
"=== modified file 'orig/commands.py'\n"])
80
self.assertEqual(patches[0]['patch'].get_header().splitlines(True),
81
["--- orig/commands.py\n", "+++ mod/dommands.py\n"])
82
self.assertEqual(patches[1]['dirty_head'],
83
["=== modified file 'orig/another.py'\n"])
84
self.assertEqual(patches[1]['patch'].get_header().splitlines(True),
85
["--- orig/another.py\n", "+++ mod/another.py\n"])
65
87
def testValidPatchHeader(self):
66
88
"""Parse a valid patch header"""
67
89
lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
78
100
def testValidHunkHeader(self):
79
101
"""Parse a valid hunk header"""
80
102
header = "@@ -34,11 +50,6 @@\n"
81
hunk = hunk_from_header(header);
103
hunk = hunk_from_header(header)
82
104
self.assertEqual(hunk.orig_pos, 34)
83
105
self.assertEqual(hunk.orig_range, 11)
84
106
self.assertEqual(hunk.mod_pos, 50)
88
110
def testValidHunkHeader2(self):
89
111
"""Parse a tricky, valid hunk header"""
90
112
header = "@@ -1 +0,0 @@\n"
91
hunk = hunk_from_header(header);
113
hunk = hunk_from_header(header)
92
114
self.assertEqual(hunk.orig_pos, 1)
93
115
self.assertEqual(hunk.orig_range, 1)
94
116
self.assertEqual(hunk.mod_pos, 0)
117
139
self.makeMalformed("@@ -34,11 +50,6.5 @@\n")
118
140
self.makeMalformed("@@ -34,11 +50,-6 @@\n")
120
def lineThing(self,text, type):
142
def lineThing(self, text, type):
121
143
line = parse_line(text)
122
144
self.assertIsInstance(line, type)
123
145
self.assertEqual(str(line), text)
136
158
self.makeMalformedLine("hello\n")
138
160
def testMalformedLineNO_NL(self):
139
"""Parse invalid '\ No newline at end of file' in hunk lines"""
161
"""Parse invalid '\\ No newline at end of file' in hunk lines"""
140
162
self.makeMalformedLine(NO_NL)
142
164
def compare_parsed(self, patchtext):
145
167
pstr = str(patch)
146
168
i = difference_index(patchtext, pstr)
147
169
if i is not None:
148
print "%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i])
149
self.assertEqual (patchtext, str(patch))
170
print("%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i]))
171
self.assertEqual(patchtext, str(patch))
151
173
def testAll(self):
152
174
"""Test parsing a whole patch"""
161
183
self.assertContainsRe(patches[0].oldname, '^bar\t')
162
184
self.assertContainsRe(patches[0].newname, '^qux\t')
163
185
self.assertContainsRe(str(patches[0]),
164
'Binary files bar\t.* and qux\t.* differ\n')
186
'Binary files bar\t.* and qux\t.* differ\n')
166
188
def test_parse_binary_after_normal(self):
167
189
patches = parse_patches(self.data_lines("binary-after-normal.patch"))
170
192
self.assertContainsRe(patches[1].oldname, '^bar\t')
171
193
self.assertContainsRe(patches[1].newname, '^qux\t')
172
194
self.assertContainsRe(str(patches[1]),
173
'Binary files bar\t.* and qux\t.* differ\n')
195
'Binary files bar\t.* and qux\t.* differ\n')
175
197
def test_roundtrip_binary(self):
176
198
patchtext = ''.join(self.data_lines("binary.patch"))
189
211
self.compare_parsed(patchtext)
191
213
def testLineLookup(self):
193
214
"""Make sure we can accurately look up mod line from orig"""
194
215
patch = parse_patch(self.datafile("diff"))
195
216
orig = list(self.datafile("orig"))
205
226
for hunk in patch.hunks:
206
227
for line in hunk.lines:
207
228
if isinstance(line, RemoveLine):
208
next = rem_iter.next()
209
if line.contents != next:
210
sys.stdout.write(" orig:%spatch:%s" % (next,
212
self.assertEqual(line.contents, next)
213
self.assertRaises(StopIteration, rem_iter.next)
229
self.assertEqual(line.contents, next(rem_iter))
230
self.assertRaises(StopIteration, next, rem_iter)
215
232
def testPatching(self):
216
233
"""Test a few patch files, and make sure they work."""
228
245
mod_lines = list(self.datafile(mod))
230
247
patched_file = IterableFile(iter_patched(orig_lines, patch))
233
249
for patch_line in patched_file:
234
250
self.assertEqual(patch_line, mod_lines[count])
239
255
binary_lines = self.data_lines('binary.patch')
240
256
e = self.assertRaises(BinaryFiles, iter_patched, [], binary_lines)
243
258
def test_iter_patched_from_hunks(self):
244
259
"""Test a few patch files, and make sure they work."""
256
271
mod_lines = list(self.datafile(mod))
257
272
iter_patched = iter_patched_from_hunks(orig_lines, parsed.hunks)
258
273
patched_file = IterableFile(iter_patched)
261
275
for patch_line in patched_file:
262
276
self.assertEqual(patch_line, mod_lines[count])