/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 bzrlib/tests/test_patches.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-02-11 04:02:41 UTC
  • mfrom: (5017.2.2 tariff)
  • Revision ID: pqm@pqm.ubuntu.com-20100211040241-w6n021dz0uus341n
(mbp) add import-tariff tests

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Aaron Bentley, Canonical Ltd
 
1
# Copyright (C) 2004 - 2008 Aaron Bentley, Canonical Ltd
 
2
# <aaron.bentley@utoronto.ca>
2
3
#
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
17
18
 
18
19
import os.path
19
20
 
20
 
from breezy.tests import TestCase, TestCaseWithTransport
 
21
from bzrlib.tests import TestCase
21
22
 
22
 
from breezy.iterablefile import IterableFile
23
 
from breezy.patches import (
24
 
    AppliedPatches,
25
 
    MalformedLine,
26
 
    MalformedHunkHeader,
27
 
    MalformedPatchHeader,
28
 
    BinaryPatch,
29
 
    BinaryFiles,
30
 
    Patch,
31
 
    ContextLine,
32
 
    InsertLine,
33
 
    RemoveLine,
34
 
    difference_index,
35
 
    get_patch_names,
36
 
    hunk_from_header,
37
 
    iter_patched,
38
 
    iter_patched_from_hunks,
39
 
    parse_line,
40
 
    parse_patch,
41
 
    parse_patches,
42
 
    NO_NL,
43
 
    )
 
23
from bzrlib.iterablefile import IterableFile
 
24
from bzrlib.patches import (MalformedLine,
 
25
                            MalformedHunkHeader,
 
26
                            MalformedPatchHeader,
 
27
                            BinaryPatch,
 
28
                            BinaryFiles,
 
29
                            Patch,
 
30
                            ContextLine,
 
31
                            InsertLine,
 
32
                            RemoveLine,
 
33
                            difference_index,
 
34
                            get_patch_names,
 
35
                            hunk_from_header,
 
36
                            iter_patched,
 
37
                            iter_patched_from_hunks,
 
38
                            parse_line,
 
39
                            parse_patch,
 
40
                            parse_patches,
 
41
                            NO_NL)
44
42
 
45
43
 
46
44
class PatchesTester(TestCase):
48
46
    def datafile(self, filename):
49
47
        data_path = os.path.join(os.path.dirname(__file__),
50
48
                                 "test_patches_data", filename)
51
 
        return open(data_path, "rb")
 
49
        return file(data_path, "rb")
52
50
 
53
51
    def data_lines(self, filename):
54
 
        with self.datafile(filename) as datafile:
 
52
        datafile = self.datafile(filename)
 
53
        try:
55
54
            return datafile.readlines()
56
 
 
57
 
    def test_parse_patches_leading_noise(self):
58
 
        # https://bugs.launchpad.net/bzr/+bug/502076
59
 
        # https://code.launchpad.net/~toshio/bzr/allow-dirty-patches/+merge/18854
60
 
        lines = [b"diff -pruN commands.py",
61
 
                 b"--- orig/commands.py",
62
 
                 b"+++ mod/dommands.py"]
63
 
        bits = list(parse_patches(iter(lines), allow_dirty=True))
64
 
 
65
 
    def test_preserve_dirty_head(self):
66
 
        """Parse a patch containing a dirty header, and preserve lines"""
67
 
        lines = [b"=== added directory 'foo/bar'\n",
68
 
                 b"=== modified file 'orig/commands.py'\n",
69
 
                 b"--- orig/commands.py\n",
70
 
                 b"+++ mod/dommands.py\n",
71
 
                 b"=== modified file 'orig/another.py'\n",
72
 
                 b"--- orig/another.py\n",
73
 
                 b"+++ mod/another.py\n"]
74
 
        patches = list(parse_patches(
75
 
            lines.__iter__(), allow_dirty=True, keep_dirty=True))
76
 
        self.assertLength(2, patches)
77
 
        self.assertEqual(patches[0]['dirty_head'],
78
 
                         [b"=== added directory 'foo/bar'\n",
79
 
                          b"=== modified file 'orig/commands.py'\n"])
80
 
        self.assertEqual(patches[0]['patch'].get_header().splitlines(True),
81
 
                         [b"--- orig/commands.py\n", b"+++ mod/dommands.py\n"])
82
 
        self.assertEqual(patches[1]['dirty_head'],
83
 
                         [b"=== modified file 'orig/another.py'\n"])
84
 
        self.assertEqual(patches[1]['patch'].get_header().splitlines(True),
85
 
                         [b"--- orig/another.py\n", b"+++ mod/another.py\n"])
 
55
        finally:
 
56
            datafile.close()
86
57
 
87
58
    def testValidPatchHeader(self):
88
59
        """Parse a valid patch header"""
89
 
        lines = b"--- orig/commands.py\n+++ mod/dommands.py\n".split(b'\n')
 
60
        lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
90
61
        (orig, mod) = get_patch_names(lines.__iter__())
91
 
        self.assertEqual(orig, b"orig/commands.py")
92
 
        self.assertEqual(mod, b"mod/dommands.py")
 
62
        self.assertEqual(orig, "orig/commands.py")
 
63
        self.assertEqual(mod, "mod/dommands.py")
93
64
 
94
65
    def testInvalidPatchHeader(self):
95
66
        """Parse an invalid patch header"""
96
 
        lines = b"-- orig/commands.py\n+++ mod/dommands.py".split(b'\n')
 
67
        lines = "-- orig/commands.py\n+++ mod/dommands.py".split('\n')
97
68
        self.assertRaises(MalformedPatchHeader, get_patch_names,
98
69
                          lines.__iter__())
99
70
 
100
71
    def testValidHunkHeader(self):
101
72
        """Parse a valid hunk header"""
102
 
        header = b"@@ -34,11 +50,6 @@\n"
103
 
        hunk = hunk_from_header(header)
 
73
        header = "@@ -34,11 +50,6 @@\n"
 
74
        hunk = hunk_from_header(header);
104
75
        self.assertEqual(hunk.orig_pos, 34)
105
76
        self.assertEqual(hunk.orig_range, 11)
106
77
        self.assertEqual(hunk.mod_pos, 50)
107
78
        self.assertEqual(hunk.mod_range, 6)
108
 
        self.assertEqual(hunk.as_bytes(), header)
 
79
        self.assertEqual(str(hunk), header)
109
80
 
110
81
    def testValidHunkHeader2(self):
111
82
        """Parse a tricky, valid hunk header"""
112
 
        header = b"@@ -1 +0,0 @@\n"
113
 
        hunk = hunk_from_header(header)
 
83
        header = "@@ -1 +0,0 @@\n"
 
84
        hunk = hunk_from_header(header);
114
85
        self.assertEqual(hunk.orig_pos, 1)
115
86
        self.assertEqual(hunk.orig_range, 1)
116
87
        self.assertEqual(hunk.mod_pos, 0)
117
88
        self.assertEqual(hunk.mod_range, 0)
118
 
        self.assertEqual(hunk.as_bytes(), header)
 
89
        self.assertEqual(str(hunk), header)
119
90
 
120
91
    def testPDiff(self):
121
92
        """Parse a hunk header produced by diff -p"""
122
 
        header = b"@@ -407,7 +292,7 @@ bzr 0.18rc1  2007-07-10\n"
 
93
        header = "@@ -407,7 +292,7 @@ bzr 0.18rc1  2007-07-10\n"
123
94
        hunk = hunk_from_header(header)
124
 
        self.assertEqual(b'bzr 0.18rc1  2007-07-10', hunk.tail)
125
 
        self.assertEqual(header, hunk.as_bytes())
 
95
        self.assertEqual('bzr 0.18rc1  2007-07-10', hunk.tail)
 
96
        self.assertEqual(header, str(hunk))
126
97
 
127
98
    def makeMalformed(self, header):
128
99
        self.assertRaises(MalformedHunkHeader, hunk_from_header, header)
129
100
 
130
101
    def testInvalidHeader(self):
131
102
        """Parse an invalid hunk header"""
132
 
        self.makeMalformed(b" -34,11 +50,6 \n")
133
 
        self.makeMalformed(b"@@ +50,6 -34,11 @@\n")
134
 
        self.makeMalformed(b"@@ -34,11 +50,6 @@")
135
 
        self.makeMalformed(b"@@ -34.5,11 +50,6 @@\n")
136
 
        self.makeMalformed(b"@@-34,11 +50,6@@\n")
137
 
        self.makeMalformed(b"@@ 34,11 50,6 @@\n")
138
 
        self.makeMalformed(b"@@ -34,11 @@\n")
139
 
        self.makeMalformed(b"@@ -34,11 +50,6.5 @@\n")
140
 
        self.makeMalformed(b"@@ -34,11 +50,-6 @@\n")
 
103
        self.makeMalformed(" -34,11 +50,6 \n")
 
104
        self.makeMalformed("@@ +50,6 -34,11 @@\n")
 
105
        self.makeMalformed("@@ -34,11 +50,6 @@")
 
106
        self.makeMalformed("@@ -34.5,11 +50,6 @@\n")
 
107
        self.makeMalformed("@@-34,11 +50,6@@\n")
 
108
        self.makeMalformed("@@ 34,11 50,6 @@\n")
 
109
        self.makeMalformed("@@ -34,11 @@\n")
 
110
        self.makeMalformed("@@ -34,11 +50,6.5 @@\n")
 
111
        self.makeMalformed("@@ -34,11 +50,-6 @@\n")
141
112
 
142
 
    def lineThing(self, text, type):
 
113
    def lineThing(self,text, type):
143
114
        line = parse_line(text)
144
115
        self.assertIsInstance(line, type)
145
 
        self.assertEqual(line.as_bytes(), text)
 
116
        self.assertEqual(str(line), text)
146
117
 
147
118
    def makeMalformedLine(self, text):
148
119
        self.assertRaises(MalformedLine, parse_line, text)
149
120
 
150
121
    def testValidLine(self):
151
122
        """Parse a valid hunk line"""
152
 
        self.lineThing(b" hello\n", ContextLine)
153
 
        self.lineThing(b"+hello\n", InsertLine)
154
 
        self.lineThing(b"-hello\n", RemoveLine)
 
123
        self.lineThing(" hello\n", ContextLine)
 
124
        self.lineThing("+hello\n", InsertLine)
 
125
        self.lineThing("-hello\n", RemoveLine)
155
126
 
156
127
    def testMalformedLine(self):
157
128
        """Parse invalid valid hunk lines"""
158
 
        self.makeMalformedLine(b"hello\n")
 
129
        self.makeMalformedLine("hello\n")
159
130
 
160
131
    def testMalformedLineNO_NL(self):
161
 
        """Parse invalid '\\ No newline at end of file' in hunk lines"""
 
132
        """Parse invalid '\ No newline at end of file' in hunk lines"""
162
133
        self.makeMalformedLine(NO_NL)
163
134
 
164
135
    def compare_parsed(self, patchtext):
165
136
        lines = patchtext.splitlines(True)
166
137
        patch = parse_patch(lines.__iter__())
167
 
        pstr = patch.as_bytes()
 
138
        pstr = str(patch)
168
139
        i = difference_index(patchtext, pstr)
169
140
        if i is not None:
170
 
            print("%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i]))
171
 
        self.assertEqual(patchtext, patch.as_bytes())
 
141
            print "%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i])
 
142
        self.assertEqual (patchtext, str(patch))
172
143
 
173
144
    def testAll(self):
174
145
        """Test parsing a whole patch"""
175
 
        with self.datafile("patchtext.patch") as f:
176
 
            patchtext = f.read()
 
146
        patchtext = self.datafile("patchtext.patch").read()
177
147
        self.compare_parsed(patchtext)
178
148
 
179
149
    def test_parse_binary(self):
180
150
        """Test parsing a whole patch"""
181
 
        patches = list(parse_patches(self.data_lines("binary.patch")))
 
151
        patches = parse_patches(self.data_lines("binary.patch"))
182
152
        self.assertIs(BinaryPatch, patches[0].__class__)
183
153
        self.assertIs(Patch, patches[1].__class__)
184
 
        self.assertContainsRe(patches[0].oldname, b'^bar\t')
185
 
        self.assertContainsRe(patches[0].newname, b'^qux\t')
186
 
        self.assertContainsRe(patches[0].as_bytes(),
187
 
                              b'Binary files bar\t.* and qux\t.* differ\n')
 
154
        self.assertContainsRe(patches[0].oldname, '^bar\t')
 
155
        self.assertContainsRe(patches[0].newname, '^qux\t')
 
156
        self.assertContainsRe(str(patches[0]),
 
157
                                  'Binary files bar\t.* and qux\t.* differ\n')
188
158
 
189
159
    def test_parse_binary_after_normal(self):
190
 
        patches = list(parse_patches(
191
 
            self.data_lines("binary-after-normal.patch")))
 
160
        patches = parse_patches(self.data_lines("binary-after-normal.patch"))
192
161
        self.assertIs(BinaryPatch, patches[1].__class__)
193
162
        self.assertIs(Patch, patches[0].__class__)
194
 
        self.assertContainsRe(patches[1].oldname, b'^bar\t')
195
 
        self.assertContainsRe(patches[1].newname, b'^qux\t')
196
 
        self.assertContainsRe(patches[1].as_bytes(),
197
 
                              b'Binary files bar\t.* and qux\t.* differ\n')
 
163
        self.assertContainsRe(patches[1].oldname, '^bar\t')
 
164
        self.assertContainsRe(patches[1].newname, '^qux\t')
 
165
        self.assertContainsRe(str(patches[1]),
 
166
                                  'Binary files bar\t.* and qux\t.* differ\n')
198
167
 
199
168
    def test_roundtrip_binary(self):
200
 
        patchtext = b''.join(self.data_lines("binary.patch"))
 
169
        patchtext = ''.join(self.data_lines("binary.patch"))
201
170
        patches = parse_patches(patchtext.splitlines(True))
202
 
        self.assertEqual(patchtext, b''.join(p.as_bytes() for p in patches))
 
171
        self.assertEqual(patchtext, ''.join(str(p) for p in patches))
203
172
 
204
173
    def testInit(self):
205
174
        """Handle patches missing half the position, range tuple"""
206
175
        patchtext = \
207
 
            b"""--- orig/__vavg__.cl
 
176
"""--- orig/__vavg__.cl
208
177
+++ mod/__vavg__.cl
209
178
@@ -1 +1,2 @@
210
179
 __qbpsbezng__ = "erfgehpgherqgrkg ra"
213
182
        self.compare_parsed(patchtext)
214
183
 
215
184
    def testLineLookup(self):
 
185
        import sys
216
186
        """Make sure we can accurately look up mod line from orig"""
217
187
        patch = parse_patch(self.datafile("diff"))
218
188
        orig = list(self.datafile("orig"))
228
198
        for hunk in patch.hunks:
229
199
            for line in hunk.lines:
230
200
                if isinstance(line, RemoveLine):
231
 
                    self.assertEqual(line.contents, next(rem_iter))
232
 
        self.assertRaises(StopIteration, next, rem_iter)
 
201
                    next = rem_iter.next()
 
202
                    if line.contents != next:
 
203
                        sys.stdout.write(" orig:%spatch:%s" % (next,
 
204
                                         line.contents))
 
205
                    self.assertEqual(line.contents, next)
 
206
        self.assertRaises(StopIteration, rem_iter.next)
233
207
 
234
208
    def testPatching(self):
235
209
        """Test a few patch files, and make sure they work."""
247
221
            mod_lines = list(self.datafile(mod))
248
222
 
249
223
            patched_file = IterableFile(iter_patched(orig_lines, patch))
 
224
            lines = []
250
225
            count = 0
251
226
            for patch_line in patched_file:
252
227
                self.assertEqual(patch_line, mod_lines[count])
257
232
        binary_lines = self.data_lines('binary.patch')
258
233
        e = self.assertRaises(BinaryFiles, iter_patched, [], binary_lines)
259
234
 
 
235
 
260
236
    def test_iter_patched_from_hunks(self):
261
237
        """Test a few patch files, and make sure they work."""
262
238
        files = [
273
249
            mod_lines = list(self.datafile(mod))
274
250
            iter_patched = iter_patched_from_hunks(orig_lines, parsed.hunks)
275
251
            patched_file = IterableFile(iter_patched)
 
252
            lines = []
276
253
            count = 0
277
254
            for patch_line in patched_file:
278
255
                self.assertEqual(patch_line, mod_lines[count])
287
264
    def testParsePatches(self):
288
265
        """Make sure file names can be extracted from tricky unified diffs"""
289
266
        patchtext = \
290
 
            b"""--- orig-7
 
267
"""--- orig-7
291
268
+++ mod-7
292
269
@@ -1,10 +1,10 @@
293
270
 -- a
312
289
--- C
313
290
+++ D
314
291
"""
315
 
        filenames = [(b'orig-7', b'mod-7'),
316
 
                     (b'orig-8', b'mod-8')]
 
292
        filenames = [('orig-7', 'mod-7'),
 
293
                     ('orig-8', 'mod-8')]
317
294
        patches = parse_patches(patchtext.splitlines(True))
318
295
        patch_files = []
319
296
        for patch in patches:
324
301
        """Test the added, removed and hunks values for stats_values."""
325
302
        patch = parse_patch(self.datafile("diff"))
326
303
        self.assertEqual((299, 407, 48), patch.stats_values())
327
 
 
328
 
 
329
 
class AppliedPatchesTests(TestCaseWithTransport):
330
 
 
331
 
    def test_apply_simple(self):
332
 
        tree = self.make_branch_and_tree('.')
333
 
        self.build_tree_contents([('a', 'a\n')])
334
 
        tree.add('a')
335
 
        tree.commit('Add a')
336
 
        patch = parse_patch(b"""\
337
 
--- a/a
338
 
+++ a/a
339
 
@@ -1 +1 @@
340
 
-a
341
 
+b
342
 
""".splitlines(True))
343
 
        with AppliedPatches(tree, [patch]) as newtree:
344
 
            self.assertEqual(b'b\n', newtree.get_file_text('a'))
345
 
 
346
 
    def test_apply_delete(self):
347
 
        tree = self.make_branch_and_tree('.')
348
 
        self.build_tree_contents([('a', 'a\n')])
349
 
        tree.add('a')
350
 
        tree.commit('Add a')
351
 
        patch = parse_patch(b"""\
352
 
--- a/a
353
 
+++ /dev/null
354
 
@@ -1 +0,0 @@
355
 
-a
356
 
""".splitlines(True))
357
 
        with AppliedPatches(tree, [patch]) as newtree:
358
 
            self.assertFalse(newtree.has_filename('a'))
359
 
 
360
 
    def test_apply_add(self):
361
 
        tree = self.make_branch_and_tree('.')
362
 
        self.build_tree_contents([('a', 'a\n')])
363
 
        tree.add('a')
364
 
        tree.commit('Add a')
365
 
        patch = parse_patch(b"""\
366
 
--- /dev/null
367
 
+++ a/b
368
 
@@ -0,0 +1 @@
369
 
+b
370
 
""".splitlines(True))
371
 
        with AppliedPatches(tree, [patch]) as newtree:
372
 
            self.assertEqual(b'b\n', newtree.get_file_text('b'))