~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_patches.py

NEWS section template into a separate file

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004 - 2006 Aaron Bentley, Canonical Ltd
 
1
# Copyright (C) 2004 - 2008 Aaron Bentley, Canonical Ltd
2
2
# <aaron.bentley@utoronto.ca>
3
3
#
4
4
# This program is free software; you can redistribute it and/or modify
13
13
#
14
14
# You should have received a copy of the GNU General Public License
15
15
# 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
 
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
17
 
 
18
 
20
19
import os.path
21
20
 
 
21
from bzrlib.tests import TestCase
 
22
 
22
23
from bzrlib.iterablefile import IterableFile
23
 
from bzrlib.patches import (MalformedLine, 
24
 
                            MalformedHunkHeader, 
25
 
                            MalformedPatchHeader, 
26
 
                            ContextLine, 
 
24
from bzrlib.patches import (MalformedLine,
 
25
                            MalformedHunkHeader,
 
26
                            MalformedPatchHeader,
 
27
                            BinaryPatch,
 
28
                            BinaryFiles,
 
29
                            Patch,
 
30
                            ContextLine,
27
31
                            InsertLine,
28
 
                            RemoveLine, 
29
 
                            difference_index, 
 
32
                            RemoveLine,
 
33
                            difference_index,
30
34
                            get_patch_names,
31
 
                            hunk_from_header, 
32
 
                            iter_patched, 
 
35
                            hunk_from_header,
 
36
                            iter_patched,
 
37
                            iter_patched_from_hunks,
33
38
                            parse_line,
34
39
                            parse_patch,
35
 
                            parse_patches)
36
 
 
37
 
 
38
 
class PatchesTester(unittest.TestCase):
 
40
                            parse_patches,
 
41
                            NO_NL)
 
42
 
 
43
 
 
44
class PatchesTester(TestCase):
 
45
 
39
46
    def datafile(self, filename):
40
 
        data_path = os.path.join(os.path.dirname(__file__), 
 
47
        data_path = os.path.join(os.path.dirname(__file__),
41
48
                                 "test_patches_data", filename)
42
49
        return file(data_path, "rb")
43
50
 
 
51
    def data_lines(self, filename):
 
52
        datafile = self.datafile(filename)
 
53
        try:
 
54
            return datafile.readlines()
 
55
        finally:
 
56
            datafile.close()
 
57
 
44
58
    def testValidPatchHeader(self):
45
59
        """Parse a valid patch header"""
46
60
        lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
47
61
        (orig, mod) = get_patch_names(lines.__iter__())
48
 
        assert(orig == "orig/commands.py")
49
 
        assert(mod == "mod/dommands.py")
 
62
        self.assertEqual(orig, "orig/commands.py")
 
63
        self.assertEqual(mod, "mod/dommands.py")
50
64
 
51
65
    def testInvalidPatchHeader(self):
52
66
        """Parse an invalid patch header"""
58
72
        """Parse a valid hunk header"""
59
73
        header = "@@ -34,11 +50,6 @@\n"
60
74
        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)
 
75
        self.assertEqual(hunk.orig_pos, 34)
 
76
        self.assertEqual(hunk.orig_range, 11)
 
77
        self.assertEqual(hunk.mod_pos, 50)
 
78
        self.assertEqual(hunk.mod_range, 6)
 
79
        self.assertEqual(str(hunk), header)
66
80
 
67
81
    def testValidHunkHeader2(self):
68
82
        """Parse a tricky, valid hunk header"""
69
83
        header = "@@ -1 +0,0 @@\n"
70
84
        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)
 
85
        self.assertEqual(hunk.orig_pos, 1)
 
86
        self.assertEqual(hunk.orig_range, 1)
 
87
        self.assertEqual(hunk.mod_pos, 0)
 
88
        self.assertEqual(hunk.mod_range, 0)
 
89
        self.assertEqual(str(hunk), header)
76
90
 
77
91
    def testPDiff(self):
78
92
        """Parse a hunk header produced by diff -p"""
98
112
 
99
113
    def lineThing(self,text, type):
100
114
        line = parse_line(text)
101
 
        assert(isinstance(line, type))
102
 
        assert(str(line)==text)
 
115
        self.assertIsInstance(line, type)
 
116
        self.assertEqual(str(line), text)
103
117
 
104
118
    def makeMalformedLine(self, text):
105
119
        self.assertRaises(MalformedLine, parse_line, text)
109
123
        self.lineThing(" hello\n", ContextLine)
110
124
        self.lineThing("+hello\n", InsertLine)
111
125
        self.lineThing("-hello\n", RemoveLine)
112
 
    
 
126
 
113
127
    def testMalformedLine(self):
114
128
        """Parse invalid valid hunk lines"""
115
129
        self.makeMalformedLine("hello\n")
116
 
    
 
130
 
 
131
    def testMalformedLineNO_NL(self):
 
132
        """Parse invalid '\ No newline at end of file' in hunk lines"""
 
133
        self.makeMalformedLine(NO_NL)
 
134
 
117
135
    def compare_parsed(self, patchtext):
118
136
        lines = patchtext.splitlines(True)
119
137
        patch = parse_patch(lines.__iter__())
128
146
        patchtext = self.datafile("patchtext.patch").read()
129
147
        self.compare_parsed(patchtext)
130
148
 
 
149
    def test_parse_binary(self):
 
150
        """Test parsing a whole patch"""
 
151
        patches = parse_patches(self.data_lines("binary.patch"))
 
152
        self.assertIs(BinaryPatch, patches[0].__class__)
 
153
        self.assertIs(Patch, patches[1].__class__)
 
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')
 
158
 
 
159
    def test_parse_binary_after_normal(self):
 
160
        patches = parse_patches(self.data_lines("binary-after-normal.patch"))
 
161
        self.assertIs(BinaryPatch, patches[1].__class__)
 
162
        self.assertIs(Patch, patches[0].__class__)
 
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')
 
167
 
 
168
    def test_roundtrip_binary(self):
 
169
        patchtext = ''.join(self.data_lines("binary.patch"))
 
170
        patches = parse_patches(patchtext.splitlines(True))
 
171
        self.assertEqual(patchtext, ''.join(str(p) for p in patches))
 
172
 
131
173
    def testInit(self):
132
174
        """Handle patches missing half the position, range tuple"""
133
175
        patchtext = \
151
193
            if mod_pos is None:
152
194
                removals.append(orig[i])
153
195
                continue
154
 
            assert(mod[mod_pos]==orig[i])
 
196
            self.assertEqual(mod[mod_pos], orig[i])
155
197
        rem_iter = removals.__iter__()
156
198
        for hunk in patch.hunks:
157
199
            for line in hunk.lines:
160
202
                    if line.contents != next:
161
203
                        sys.stdout.write(" orig:%spatch:%s" % (next,
162
204
                                         line.contents))
163
 
                    assert(line.contents == next)
 
205
                    self.assertEqual(line.contents, next)
164
206
        self.assertRaises(StopIteration, rem_iter.next)
165
207
 
166
208
    def testPatching(self):
171
213
            ('diff-4', 'orig-4', 'mod-4'),
172
214
            ('diff-5', 'orig-5', 'mod-5'),
173
215
            ('diff-6', 'orig-6', 'mod-6'),
 
216
            ('diff-7', 'orig-7', 'mod-7'),
174
217
        ]
175
218
        for diff, orig, mod in files:
176
219
            patch = self.datafile(diff)
185
228
                count += 1
186
229
            self.assertEqual(count, len(mod_lines))
187
230
 
 
231
    def test_iter_patched_binary(self):
 
232
        binary_lines = self.data_lines('binary.patch')
 
233
        e = self.assertRaises(BinaryFiles, iter_patched, [], binary_lines)
 
234
 
 
235
 
 
236
    def test_iter_patched_from_hunks(self):
 
237
        """Test a few patch files, and make sure they work."""
 
238
        files = [
 
239
            ('diff-2', 'orig-2', 'mod-2'),
 
240
            ('diff-3', 'orig-3', 'mod-3'),
 
241
            ('diff-4', 'orig-4', 'mod-4'),
 
242
            ('diff-5', 'orig-5', 'mod-5'),
 
243
            ('diff-6', 'orig-6', 'mod-6'),
 
244
            ('diff-7', 'orig-7', 'mod-7'),
 
245
        ]
 
246
        for diff, orig, mod in files:
 
247
            parsed = parse_patch(self.datafile(diff))
 
248
            orig_lines = list(self.datafile(orig))
 
249
            mod_lines = list(self.datafile(mod))
 
250
            iter_patched = iter_patched_from_hunks(orig_lines, parsed.hunks)
 
251
            patched_file = IterableFile(iter_patched)
 
252
            lines = []
 
253
            count = 0
 
254
            for patch_line in patched_file:
 
255
                self.assertEqual(patch_line, mod_lines[count])
 
256
                count += 1
 
257
            self.assertEqual(count, len(mod_lines))
 
258
 
188
259
    def testFirstLineRenumber(self):
189
260
        """Make sure we handle lines at the beginning of the hunk"""
190
261
        patch = parse_patch(self.datafile("insert_top.patch"))
191
 
        assert (patch.pos_in_mod(0)==1)
 
262
        self.assertEqual(patch.pos_in_mod(0), 1)
192
263
 
193
264
    def testParsePatches(self):
194
265
        """Make sure file names can be extracted from tricky unified diffs"""
224
295
        patch_files = []
225
296
        for patch in patches:
226
297
            patch_files.append((patch.oldname, patch.newname))
227
 
        assert (patch_files == filenames)
228
 
            
229
 
def test():
230
 
    patchesTestSuite = unittest.makeSuite(PatchesTester,'test')
231
 
    runner = unittest.TextTestRunner(verbosity=0)
232
 
    return runner.run(patchesTestSuite)
233
 
 
234
 
 
235
 
if __name__ == "__main__":
236
 
    test()
 
298
        self.assertEqual(patch_files, filenames)
 
299
 
 
300
    def testStatsValues(self):
 
301
        """Test the added, removed and hunks values for stats_values."""
 
302
        patch = parse_patch(self.datafile("diff"))
 
303
        self.assertEqual((299, 407, 48), patch.stats_values())