/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/tests/test_patches.py

  • Committer: Jelmer Vernooij
  • Date: 2019-10-28 01:38:39 UTC
  • mto: This revision was merged to the branch mainline in revision 7412.
  • Revision ID: jelmer@jelmer.uk-20191028013839-q63zzm4yr0id9b3o
Allow unknown extras in git commits when just inspecting revisions, rather than importing.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
import os.path
19
19
 
20
 
from bzrlib.tests import TestCase
 
20
from breezy.tests import TestCase
21
21
 
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,
26
26
                            BinaryPatch,
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")
49
49
 
50
50
    def data_lines(self, filename):
51
 
        datafile = self.datafile(filename)
52
 
        try:
 
51
        with self.datafile(filename) as datafile:
53
52
            return datafile.readlines()
54
 
        finally:
55
 
            datafile.close()
56
53
 
57
54
    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
60
 
        lines = ["diff -pruN commands.py",
61
 
            "--- orig/commands.py",
62
 
            "+++ mod/dommands.py"]
63
 
        bits = parse_patches(iter(lines), allow_dirty=True)
 
55
        # https://bugs.launchpad.net/bzr/+bug/502076
 
56
        # https://code.launchpad.net/~toshio/bzr/allow-dirty-patches/+merge/18854
 
57
        lines = [b"diff -pruN commands.py",
 
58
                 b"--- orig/commands.py",
 
59
                 b"+++ mod/dommands.py"]
 
60
        bits = list(parse_patches(iter(lines), allow_dirty=True))
 
61
 
 
62
    def test_preserve_dirty_head(self):
 
63
        """Parse a patch containing a dirty header, and preserve lines"""
 
64
        lines = [b"=== added directory 'foo/bar'\n",
 
65
                 b"=== modified file 'orig/commands.py'\n",
 
66
                 b"--- orig/commands.py\n",
 
67
                 b"+++ mod/dommands.py\n",
 
68
                 b"=== modified file 'orig/another.py'\n",
 
69
                 b"--- orig/another.py\n",
 
70
                 b"+++ mod/another.py\n"]
 
71
        patches = list(parse_patches(
 
72
            lines.__iter__(), allow_dirty=True, keep_dirty=True))
 
73
        self.assertLength(2, patches)
 
74
        self.assertEqual(patches[0]['dirty_head'],
 
75
                         [b"=== added directory 'foo/bar'\n",
 
76
                          b"=== modified file 'orig/commands.py'\n"])
 
77
        self.assertEqual(patches[0]['patch'].get_header().splitlines(True),
 
78
                         [b"--- orig/commands.py\n", b"+++ mod/dommands.py\n"])
 
79
        self.assertEqual(patches[1]['dirty_head'],
 
80
                         [b"=== modified file 'orig/another.py'\n"])
 
81
        self.assertEqual(patches[1]['patch'].get_header().splitlines(True),
 
82
                         [b"--- orig/another.py\n", b"+++ mod/another.py\n"])
64
83
 
65
84
    def testValidPatchHeader(self):
66
85
        """Parse a valid patch header"""
67
 
        lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
 
86
        lines = b"--- orig/commands.py\n+++ mod/dommands.py\n".split(b'\n')
68
87
        (orig, mod) = get_patch_names(lines.__iter__())
69
 
        self.assertEqual(orig, "orig/commands.py")
70
 
        self.assertEqual(mod, "mod/dommands.py")
 
88
        self.assertEqual(orig, b"orig/commands.py")
 
89
        self.assertEqual(mod, b"mod/dommands.py")
71
90
 
72
91
    def testInvalidPatchHeader(self):
73
92
        """Parse an invalid patch header"""
74
 
        lines = "-- orig/commands.py\n+++ mod/dommands.py".split('\n')
 
93
        lines = b"-- orig/commands.py\n+++ mod/dommands.py".split(b'\n')
75
94
        self.assertRaises(MalformedPatchHeader, get_patch_names,
76
95
                          lines.__iter__())
77
96
 
78
97
    def testValidHunkHeader(self):
79
98
        """Parse a valid hunk header"""
80
 
        header = "@@ -34,11 +50,6 @@\n"
81
 
        hunk = hunk_from_header(header);
 
99
        header = b"@@ -34,11 +50,6 @@\n"
 
100
        hunk = hunk_from_header(header)
82
101
        self.assertEqual(hunk.orig_pos, 34)
83
102
        self.assertEqual(hunk.orig_range, 11)
84
103
        self.assertEqual(hunk.mod_pos, 50)
85
104
        self.assertEqual(hunk.mod_range, 6)
86
 
        self.assertEqual(str(hunk), header)
 
105
        self.assertEqual(hunk.as_bytes(), header)
87
106
 
88
107
    def testValidHunkHeader2(self):
89
108
        """Parse a tricky, valid hunk header"""
90
 
        header = "@@ -1 +0,0 @@\n"
91
 
        hunk = hunk_from_header(header);
 
109
        header = b"@@ -1 +0,0 @@\n"
 
110
        hunk = hunk_from_header(header)
92
111
        self.assertEqual(hunk.orig_pos, 1)
93
112
        self.assertEqual(hunk.orig_range, 1)
94
113
        self.assertEqual(hunk.mod_pos, 0)
95
114
        self.assertEqual(hunk.mod_range, 0)
96
 
        self.assertEqual(str(hunk), header)
 
115
        self.assertEqual(hunk.as_bytes(), header)
97
116
 
98
117
    def testPDiff(self):
99
118
        """Parse a hunk header produced by diff -p"""
100
 
        header = "@@ -407,7 +292,7 @@ bzr 0.18rc1  2007-07-10\n"
 
119
        header = b"@@ -407,7 +292,7 @@ bzr 0.18rc1  2007-07-10\n"
101
120
        hunk = hunk_from_header(header)
102
 
        self.assertEqual('bzr 0.18rc1  2007-07-10', hunk.tail)
103
 
        self.assertEqual(header, str(hunk))
 
121
        self.assertEqual(b'bzr 0.18rc1  2007-07-10', hunk.tail)
 
122
        self.assertEqual(header, hunk.as_bytes())
104
123
 
105
124
    def makeMalformed(self, header):
106
125
        self.assertRaises(MalformedHunkHeader, hunk_from_header, header)
107
126
 
108
127
    def testInvalidHeader(self):
109
128
        """Parse an invalid hunk header"""
110
 
        self.makeMalformed(" -34,11 +50,6 \n")
111
 
        self.makeMalformed("@@ +50,6 -34,11 @@\n")
112
 
        self.makeMalformed("@@ -34,11 +50,6 @@")
113
 
        self.makeMalformed("@@ -34.5,11 +50,6 @@\n")
114
 
        self.makeMalformed("@@-34,11 +50,6@@\n")
115
 
        self.makeMalformed("@@ 34,11 50,6 @@\n")
116
 
        self.makeMalformed("@@ -34,11 @@\n")
117
 
        self.makeMalformed("@@ -34,11 +50,6.5 @@\n")
118
 
        self.makeMalformed("@@ -34,11 +50,-6 @@\n")
 
129
        self.makeMalformed(b" -34,11 +50,6 \n")
 
130
        self.makeMalformed(b"@@ +50,6 -34,11 @@\n")
 
131
        self.makeMalformed(b"@@ -34,11 +50,6 @@")
 
132
        self.makeMalformed(b"@@ -34.5,11 +50,6 @@\n")
 
133
        self.makeMalformed(b"@@-34,11 +50,6@@\n")
 
134
        self.makeMalformed(b"@@ 34,11 50,6 @@\n")
 
135
        self.makeMalformed(b"@@ -34,11 @@\n")
 
136
        self.makeMalformed(b"@@ -34,11 +50,6.5 @@\n")
 
137
        self.makeMalformed(b"@@ -34,11 +50,-6 @@\n")
119
138
 
120
 
    def lineThing(self,text, type):
 
139
    def lineThing(self, text, type):
121
140
        line = parse_line(text)
122
141
        self.assertIsInstance(line, type)
123
 
        self.assertEqual(str(line), text)
 
142
        self.assertEqual(line.as_bytes(), text)
124
143
 
125
144
    def makeMalformedLine(self, text):
126
145
        self.assertRaises(MalformedLine, parse_line, text)
127
146
 
128
147
    def testValidLine(self):
129
148
        """Parse a valid hunk line"""
130
 
        self.lineThing(" hello\n", ContextLine)
131
 
        self.lineThing("+hello\n", InsertLine)
132
 
        self.lineThing("-hello\n", RemoveLine)
 
149
        self.lineThing(b" hello\n", ContextLine)
 
150
        self.lineThing(b"+hello\n", InsertLine)
 
151
        self.lineThing(b"-hello\n", RemoveLine)
133
152
 
134
153
    def testMalformedLine(self):
135
154
        """Parse invalid valid hunk lines"""
136
 
        self.makeMalformedLine("hello\n")
 
155
        self.makeMalformedLine(b"hello\n")
137
156
 
138
157
    def testMalformedLineNO_NL(self):
139
 
        """Parse invalid '\ No newline at end of file' in hunk lines"""
 
158
        """Parse invalid '\\ No newline at end of file' in hunk lines"""
140
159
        self.makeMalformedLine(NO_NL)
141
160
 
142
161
    def compare_parsed(self, patchtext):
143
162
        lines = patchtext.splitlines(True)
144
163
        patch = parse_patch(lines.__iter__())
145
 
        pstr = str(patch)
 
164
        pstr = patch.as_bytes()
146
165
        i = difference_index(patchtext, pstr)
147
166
        if i is not None:
148
 
            print "%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i])
149
 
        self.assertEqual (patchtext, str(patch))
 
167
            print("%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i]))
 
168
        self.assertEqual(patchtext, patch.as_bytes())
150
169
 
151
170
    def testAll(self):
152
171
        """Test parsing a whole patch"""
153
 
        patchtext = self.datafile("patchtext.patch").read()
 
172
        with self.datafile("patchtext.patch") as f:
 
173
            patchtext = f.read()
154
174
        self.compare_parsed(patchtext)
155
175
 
156
176
    def test_parse_binary(self):
157
177
        """Test parsing a whole patch"""
158
 
        patches = parse_patches(self.data_lines("binary.patch"))
 
178
        patches = list(parse_patches(self.data_lines("binary.patch")))
159
179
        self.assertIs(BinaryPatch, patches[0].__class__)
160
180
        self.assertIs(Patch, patches[1].__class__)
161
 
        self.assertContainsRe(patches[0].oldname, '^bar\t')
162
 
        self.assertContainsRe(patches[0].newname, '^qux\t')
163
 
        self.assertContainsRe(str(patches[0]),
164
 
                                  'Binary files bar\t.* and qux\t.* differ\n')
 
181
        self.assertContainsRe(patches[0].oldname, b'^bar\t')
 
182
        self.assertContainsRe(patches[0].newname, b'^qux\t')
 
183
        self.assertContainsRe(patches[0].as_bytes(),
 
184
                              b'Binary files bar\t.* and qux\t.* differ\n')
165
185
 
166
186
    def test_parse_binary_after_normal(self):
167
 
        patches = parse_patches(self.data_lines("binary-after-normal.patch"))
 
187
        patches = list(parse_patches(
 
188
            self.data_lines("binary-after-normal.patch")))
168
189
        self.assertIs(BinaryPatch, patches[1].__class__)
169
190
        self.assertIs(Patch, patches[0].__class__)
170
 
        self.assertContainsRe(patches[1].oldname, '^bar\t')
171
 
        self.assertContainsRe(patches[1].newname, '^qux\t')
172
 
        self.assertContainsRe(str(patches[1]),
173
 
                                  'Binary files bar\t.* and qux\t.* differ\n')
 
191
        self.assertContainsRe(patches[1].oldname, b'^bar\t')
 
192
        self.assertContainsRe(patches[1].newname, b'^qux\t')
 
193
        self.assertContainsRe(patches[1].as_bytes(),
 
194
                              b'Binary files bar\t.* and qux\t.* differ\n')
174
195
 
175
196
    def test_roundtrip_binary(self):
176
 
        patchtext = ''.join(self.data_lines("binary.patch"))
 
197
        patchtext = b''.join(self.data_lines("binary.patch"))
177
198
        patches = parse_patches(patchtext.splitlines(True))
178
 
        self.assertEqual(patchtext, ''.join(str(p) for p in patches))
 
199
        self.assertEqual(patchtext, b''.join(p.as_bytes() for p in patches))
179
200
 
180
201
    def testInit(self):
181
202
        """Handle patches missing half the position, range tuple"""
182
203
        patchtext = \
183
 
"""--- orig/__vavg__.cl
 
204
            b"""--- orig/__vavg__.cl
184
205
+++ mod/__vavg__.cl
185
206
@@ -1 +1,2 @@
186
207
 __qbpsbezng__ = "erfgehpgherqgrkg ra"
189
210
        self.compare_parsed(patchtext)
190
211
 
191
212
    def testLineLookup(self):
192
 
        import sys
193
213
        """Make sure we can accurately look up mod line from orig"""
194
214
        patch = parse_patch(self.datafile("diff"))
195
215
        orig = list(self.datafile("orig"))
205
225
        for hunk in patch.hunks:
206
226
            for line in hunk.lines:
207
227
                if isinstance(line, RemoveLine):
208
 
                    next = rem_iter.next()
209
 
                    if line.contents != next:
210
 
                        sys.stdout.write(" orig:%spatch:%s" % (next,
211
 
                                         line.contents))
212
 
                    self.assertEqual(line.contents, next)
213
 
        self.assertRaises(StopIteration, rem_iter.next)
 
228
                    self.assertEqual(line.contents, next(rem_iter))
 
229
        self.assertRaises(StopIteration, next, rem_iter)
214
230
 
215
231
    def testPatching(self):
216
232
        """Test a few patch files, and make sure they work."""
228
244
            mod_lines = list(self.datafile(mod))
229
245
 
230
246
            patched_file = IterableFile(iter_patched(orig_lines, patch))
231
 
            lines = []
232
247
            count = 0
233
248
            for patch_line in patched_file:
234
249
                self.assertEqual(patch_line, mod_lines[count])
239
254
        binary_lines = self.data_lines('binary.patch')
240
255
        e = self.assertRaises(BinaryFiles, iter_patched, [], binary_lines)
241
256
 
242
 
 
243
257
    def test_iter_patched_from_hunks(self):
244
258
        """Test a few patch files, and make sure they work."""
245
259
        files = [
256
270
            mod_lines = list(self.datafile(mod))
257
271
            iter_patched = iter_patched_from_hunks(orig_lines, parsed.hunks)
258
272
            patched_file = IterableFile(iter_patched)
259
 
            lines = []
260
273
            count = 0
261
274
            for patch_line in patched_file:
262
275
                self.assertEqual(patch_line, mod_lines[count])
271
284
    def testParsePatches(self):
272
285
        """Make sure file names can be extracted from tricky unified diffs"""
273
286
        patchtext = \
274
 
"""--- orig-7
 
287
            b"""--- orig-7
275
288
+++ mod-7
276
289
@@ -1,10 +1,10 @@
277
290
 -- a
296
309
--- C
297
310
+++ D
298
311
"""
299
 
        filenames = [('orig-7', 'mod-7'),
300
 
                     ('orig-8', 'mod-8')]
 
312
        filenames = [(b'orig-7', b'mod-7'),
 
313
                     (b'orig-8', b'mod-8')]
301
314
        patches = parse_patches(patchtext.splitlines(True))
302
315
        patch_files = []
303
316
        for patch in patches: