~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_patches.py

  • Committer: Jelmer Vernooij
  • Date: 2012-06-18 11:43:07 UTC
  • mfrom: (6437.54.10 2.5)
  • mto: This revision was merged to the branch mainline in revision 6525.
  • Revision ID: jelmer@samba.org-20120618114307-zeazlym311p38m98
MergeĀ 2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004 - 2006 Aaron Bentley, Canonical Ltd
2
 
# <aaron.bentley@utoronto.ca>
 
1
# Copyright (C) 2005-2010 Aaron Bentley, Canonical Ltd
3
2
#
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
13
12
#
14
13
# You should have received a copy of the GNU General Public License
15
14
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
 
 
18
 
 
19
 
import unittest
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
 
20
18
import os.path
21
19
 
 
20
from bzrlib.tests import TestCase
 
21
 
22
22
from bzrlib.iterablefile import IterableFile
23
 
from bzrlib.patches import (MalformedLine, 
24
 
                            MalformedHunkHeader, 
25
 
                            MalformedPatchHeader, 
26
 
                            ContextLine, 
 
23
from bzrlib.patches import (MalformedLine,
 
24
                            MalformedHunkHeader,
 
25
                            MalformedPatchHeader,
 
26
                            BinaryPatch,
 
27
                            BinaryFiles,
 
28
                            Patch,
 
29
                            ContextLine,
27
30
                            InsertLine,
28
 
                            RemoveLine, 
29
 
                            difference_index, 
 
31
                            RemoveLine,
 
32
                            difference_index,
30
33
                            get_patch_names,
31
 
                            hunk_from_header, 
32
 
                            iter_patched, 
 
34
                            hunk_from_header,
 
35
                            iter_patched,
 
36
                            iter_patched_from_hunks,
33
37
                            parse_line,
34
38
                            parse_patch,
35
 
                            parse_patches)
36
 
 
37
 
 
38
 
class PatchesTester(unittest.TestCase):
 
39
                            parse_patches,
 
40
                            NO_NL)
 
41
 
 
42
 
 
43
class PatchesTester(TestCase):
 
44
 
39
45
    def datafile(self, filename):
40
 
        data_path = os.path.join(os.path.dirname(__file__), 
 
46
        data_path = os.path.join(os.path.dirname(__file__),
41
47
                                 "test_patches_data", filename)
42
48
        return file(data_path, "rb")
43
49
 
 
50
    def data_lines(self, filename):
 
51
        datafile = self.datafile(filename)
 
52
        try:
 
53
            return datafile.readlines()
 
54
        finally:
 
55
            datafile.close()
 
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 = ["diff -pruN commands.py",
 
61
            "--- orig/commands.py",
 
62
            "+++ mod/dommands.py"]
 
63
        bits = parse_patches(iter(lines), allow_dirty=True)
 
64
 
44
65
    def testValidPatchHeader(self):
45
66
        """Parse a valid patch header"""
46
67
        lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
47
68
        (orig, mod) = get_patch_names(lines.__iter__())
48
 
        assert(orig == "orig/commands.py")
49
 
        assert(mod == "mod/dommands.py")
 
69
        self.assertEqual(orig, "orig/commands.py")
 
70
        self.assertEqual(mod, "mod/dommands.py")
50
71
 
51
72
    def testInvalidPatchHeader(self):
52
73
        """Parse an invalid patch header"""
58
79
        """Parse a valid hunk header"""
59
80
        header = "@@ -34,11 +50,6 @@\n"
60
81
        hunk = hunk_from_header(header);
61
 
        assert (hunk.orig_pos == 34)
62
 
        assert (hunk.orig_range == 11)
63
 
        assert (hunk.mod_pos == 50)
64
 
        assert (hunk.mod_range == 6)
65
 
        assert (str(hunk) == header)
 
82
        self.assertEqual(hunk.orig_pos, 34)
 
83
        self.assertEqual(hunk.orig_range, 11)
 
84
        self.assertEqual(hunk.mod_pos, 50)
 
85
        self.assertEqual(hunk.mod_range, 6)
 
86
        self.assertEqual(str(hunk), header)
66
87
 
67
88
    def testValidHunkHeader2(self):
68
89
        """Parse a tricky, valid hunk header"""
69
90
        header = "@@ -1 +0,0 @@\n"
70
91
        hunk = hunk_from_header(header);
71
 
        assert (hunk.orig_pos == 1)
72
 
        assert (hunk.orig_range == 1)
73
 
        assert (hunk.mod_pos == 0)
74
 
        assert (hunk.mod_range == 0)
75
 
        assert (str(hunk) == header)
 
92
        self.assertEqual(hunk.orig_pos, 1)
 
93
        self.assertEqual(hunk.orig_range, 1)
 
94
        self.assertEqual(hunk.mod_pos, 0)
 
95
        self.assertEqual(hunk.mod_range, 0)
 
96
        self.assertEqual(str(hunk), header)
 
97
 
 
98
    def testPDiff(self):
 
99
        """Parse a hunk header produced by diff -p"""
 
100
        header = "@@ -407,7 +292,7 @@ bzr 0.18rc1  2007-07-10\n"
 
101
        hunk = hunk_from_header(header)
 
102
        self.assertEqual('bzr 0.18rc1  2007-07-10', hunk.tail)
 
103
        self.assertEqual(header, str(hunk))
76
104
 
77
105
    def makeMalformed(self, header):
78
106
        self.assertRaises(MalformedHunkHeader, hunk_from_header, header)
91
119
 
92
120
    def lineThing(self,text, type):
93
121
        line = parse_line(text)
94
 
        assert(isinstance(line, type))
95
 
        assert(str(line)==text)
 
122
        self.assertIsInstance(line, type)
 
123
        self.assertEqual(str(line), text)
96
124
 
97
125
    def makeMalformedLine(self, text):
98
126
        self.assertRaises(MalformedLine, parse_line, text)
102
130
        self.lineThing(" hello\n", ContextLine)
103
131
        self.lineThing("+hello\n", InsertLine)
104
132
        self.lineThing("-hello\n", RemoveLine)
105
 
    
 
133
 
106
134
    def testMalformedLine(self):
107
135
        """Parse invalid valid hunk lines"""
108
136
        self.makeMalformedLine("hello\n")
109
 
    
 
137
 
 
138
    def testMalformedLineNO_NL(self):
 
139
        """Parse invalid '\ No newline at end of file' in hunk lines"""
 
140
        self.makeMalformedLine(NO_NL)
 
141
 
110
142
    def compare_parsed(self, patchtext):
111
143
        lines = patchtext.splitlines(True)
112
144
        patch = parse_patch(lines.__iter__())
121
153
        patchtext = self.datafile("patchtext.patch").read()
122
154
        self.compare_parsed(patchtext)
123
155
 
 
156
    def test_parse_binary(self):
 
157
        """Test parsing a whole patch"""
 
158
        patches = parse_patches(self.data_lines("binary.patch"))
 
159
        self.assertIs(BinaryPatch, patches[0].__class__)
 
160
        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')
 
165
 
 
166
    def test_parse_binary_after_normal(self):
 
167
        patches = parse_patches(self.data_lines("binary-after-normal.patch"))
 
168
        self.assertIs(BinaryPatch, patches[1].__class__)
 
169
        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')
 
174
 
 
175
    def test_roundtrip_binary(self):
 
176
        patchtext = ''.join(self.data_lines("binary.patch"))
 
177
        patches = parse_patches(patchtext.splitlines(True))
 
178
        self.assertEqual(patchtext, ''.join(str(p) for p in patches))
 
179
 
124
180
    def testInit(self):
125
181
        """Handle patches missing half the position, range tuple"""
126
182
        patchtext = \
144
200
            if mod_pos is None:
145
201
                removals.append(orig[i])
146
202
                continue
147
 
            assert(mod[mod_pos]==orig[i])
 
203
            self.assertEqual(mod[mod_pos], orig[i])
148
204
        rem_iter = removals.__iter__()
149
205
        for hunk in patch.hunks:
150
206
            for line in hunk.lines:
153
209
                    if line.contents != next:
154
210
                        sys.stdout.write(" orig:%spatch:%s" % (next,
155
211
                                         line.contents))
156
 
                    assert(line.contents == next)
 
212
                    self.assertEqual(line.contents, next)
157
213
        self.assertRaises(StopIteration, rem_iter.next)
158
214
 
159
215
    def testPatching(self):
164
220
            ('diff-4', 'orig-4', 'mod-4'),
165
221
            ('diff-5', 'orig-5', 'mod-5'),
166
222
            ('diff-6', 'orig-6', 'mod-6'),
 
223
            ('diff-7', 'orig-7', 'mod-7'),
167
224
        ]
168
225
        for diff, orig, mod in files:
169
226
            patch = self.datafile(diff)
178
235
                count += 1
179
236
            self.assertEqual(count, len(mod_lines))
180
237
 
 
238
    def test_iter_patched_binary(self):
 
239
        binary_lines = self.data_lines('binary.patch')
 
240
        e = self.assertRaises(BinaryFiles, iter_patched, [], binary_lines)
 
241
 
 
242
 
 
243
    def test_iter_patched_from_hunks(self):
 
244
        """Test a few patch files, and make sure they work."""
 
245
        files = [
 
246
            ('diff-2', 'orig-2', 'mod-2'),
 
247
            ('diff-3', 'orig-3', 'mod-3'),
 
248
            ('diff-4', 'orig-4', 'mod-4'),
 
249
            ('diff-5', 'orig-5', 'mod-5'),
 
250
            ('diff-6', 'orig-6', 'mod-6'),
 
251
            ('diff-7', 'orig-7', 'mod-7'),
 
252
        ]
 
253
        for diff, orig, mod in files:
 
254
            parsed = parse_patch(self.datafile(diff))
 
255
            orig_lines = list(self.datafile(orig))
 
256
            mod_lines = list(self.datafile(mod))
 
257
            iter_patched = iter_patched_from_hunks(orig_lines, parsed.hunks)
 
258
            patched_file = IterableFile(iter_patched)
 
259
            lines = []
 
260
            count = 0
 
261
            for patch_line in patched_file:
 
262
                self.assertEqual(patch_line, mod_lines[count])
 
263
                count += 1
 
264
            self.assertEqual(count, len(mod_lines))
 
265
 
181
266
    def testFirstLineRenumber(self):
182
267
        """Make sure we handle lines at the beginning of the hunk"""
183
268
        patch = parse_patch(self.datafile("insert_top.patch"))
184
 
        assert (patch.pos_in_mod(0)==1)
 
269
        self.assertEqual(patch.pos_in_mod(0), 1)
185
270
 
186
271
    def testParsePatches(self):
187
272
        """Make sure file names can be extracted from tricky unified diffs"""
217
302
        patch_files = []
218
303
        for patch in patches:
219
304
            patch_files.append((patch.oldname, patch.newname))
220
 
        assert (patch_files == filenames)
221
 
            
222
 
def test():
223
 
    patchesTestSuite = unittest.makeSuite(PatchesTester,'test')
224
 
    runner = unittest.TextTestRunner(verbosity=0)
225
 
    return runner.run(patchesTestSuite)
226
 
 
227
 
 
228
 
if __name__ == "__main__":
229
 
    test()
 
305
        self.assertEqual(patch_files, filenames)
 
306
 
 
307
    def testStatsValues(self):
 
308
        """Test the added, removed and hunks values for stats_values."""
 
309
        patch = parse_patch(self.datafile("diff"))
 
310
        self.assertEqual((299, 407, 48), patch.stats_values())