~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_patches.py

  • Committer: Alexander Belchenko
  • Date: 2006-07-30 16:43:12 UTC
  • mto: (1711.2.111 jam-integration)
  • mto: This revision was merged to the branch mainline in revision 1906.
  • Revision ID: bialix@ukr.net-20060730164312-b025fd3ff0cee59e
rename  gpl.txt => COPYING.txt

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Aaron Bentley, Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
 
 
17
 
 
 
1
# Copyright (C) 2004 - 2006 Aaron Bentley
 
2
# <aaron.bentley@utoronto.ca>
 
3
#
 
4
#    This program is free software; you can redistribute it and/or modify
 
5
#    it under the terms of the GNU General Public License as published by
 
6
#    the Free Software Foundation; either version 2 of the License, or
 
7
#    (at your option) any later version.
 
8
#
 
9
#    This program is distributed in the hope that it will be useful,
 
10
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
#    GNU General Public License for more details.
 
13
#
 
14
#    You should have received a copy of the GNU General Public License
 
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
18
20
import os.path
19
21
 
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
 
                            BinaryPatch,
27
 
                            BinaryFiles,
28
 
                            Patch,
29
 
                            ContextLine,
 
23
from bzrlib.patches import (MalformedLine, 
 
24
                            MalformedHunkHeader, 
 
25
                            MalformedPatchHeader, 
 
26
                            ContextLine, 
30
27
                            InsertLine,
31
 
                            RemoveLine,
32
 
                            difference_index,
 
28
                            RemoveLine, 
 
29
                            difference_index, 
33
30
                            get_patch_names,
34
 
                            hunk_from_header,
35
 
                            iter_patched,
36
 
                            iter_patched_from_hunks,
 
31
                            hunk_from_header, 
 
32
                            iter_patched, 
37
33
                            parse_line,
38
 
                            parse_patch,
39
 
                            parse_patches,
40
 
                            NO_NL)
41
 
 
42
 
 
43
 
class PatchesTester(TestCase):
44
 
 
 
34
                            parse_patch)
 
35
 
 
36
 
 
37
class PatchesTester(unittest.TestCase):
45
38
    def datafile(self, filename):
46
 
        data_path = os.path.join(os.path.dirname(__file__),
 
39
        data_path = os.path.join(os.path.dirname(__file__), 
47
40
                                 "test_patches_data", filename)
48
41
        return file(data_path, "rb")
49
42
 
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
 
 
65
43
    def testValidPatchHeader(self):
66
44
        """Parse a valid patch header"""
67
45
        lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
68
46
        (orig, mod) = get_patch_names(lines.__iter__())
69
 
        self.assertEqual(orig, "orig/commands.py")
70
 
        self.assertEqual(mod, "mod/dommands.py")
 
47
        assert(orig == "orig/commands.py")
 
48
        assert(mod == "mod/dommands.py")
71
49
 
72
50
    def testInvalidPatchHeader(self):
73
51
        """Parse an invalid patch header"""
79
57
        """Parse a valid hunk header"""
80
58
        header = "@@ -34,11 +50,6 @@\n"
81
59
        hunk = hunk_from_header(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)
 
60
        assert (hunk.orig_pos == 34)
 
61
        assert (hunk.orig_range == 11)
 
62
        assert (hunk.mod_pos == 50)
 
63
        assert (hunk.mod_range == 6)
 
64
        assert (str(hunk) == header)
87
65
 
88
66
    def testValidHunkHeader2(self):
89
67
        """Parse a tricky, valid hunk header"""
90
68
        header = "@@ -1 +0,0 @@\n"
91
69
        hunk = hunk_from_header(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))
 
70
        assert (hunk.orig_pos == 1)
 
71
        assert (hunk.orig_range == 1)
 
72
        assert (hunk.mod_pos == 0)
 
73
        assert (hunk.mod_range == 0)
 
74
        assert (str(hunk) == header)
104
75
 
105
76
    def makeMalformed(self, header):
106
77
        self.assertRaises(MalformedHunkHeader, hunk_from_header, header)
119
90
 
120
91
    def lineThing(self,text, type):
121
92
        line = parse_line(text)
122
 
        self.assertIsInstance(line, type)
123
 
        self.assertEqual(str(line), text)
 
93
        assert(isinstance(line, type))
 
94
        assert(str(line)==text)
124
95
 
125
96
    def makeMalformedLine(self, text):
126
97
        self.assertRaises(MalformedLine, parse_line, text)
130
101
        self.lineThing(" hello\n", ContextLine)
131
102
        self.lineThing("+hello\n", InsertLine)
132
103
        self.lineThing("-hello\n", RemoveLine)
133
 
 
 
104
    
134
105
    def testMalformedLine(self):
135
106
        """Parse invalid valid hunk lines"""
136
107
        self.makeMalformedLine("hello\n")
137
 
 
138
 
    def testMalformedLineNO_NL(self):
139
 
        """Parse invalid '\ No newline at end of file' in hunk lines"""
140
 
        self.makeMalformedLine(NO_NL)
141
 
 
 
108
    
142
109
    def compare_parsed(self, patchtext):
143
110
        lines = patchtext.splitlines(True)
144
111
        patch = parse_patch(lines.__iter__())
153
120
        patchtext = self.datafile("patchtext.patch").read()
154
121
        self.compare_parsed(patchtext)
155
122
 
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
 
 
180
123
    def testInit(self):
181
124
        """Handle patches missing half the position, range tuple"""
182
125
        patchtext = \
200
143
            if mod_pos is None:
201
144
                removals.append(orig[i])
202
145
                continue
203
 
            self.assertEqual(mod[mod_pos], orig[i])
 
146
            assert(mod[mod_pos]==orig[i])
204
147
        rem_iter = removals.__iter__()
205
148
        for hunk in patch.hunks:
206
149
            for line in hunk.lines:
209
152
                    if line.contents != next:
210
153
                        sys.stdout.write(" orig:%spatch:%s" % (next,
211
154
                                         line.contents))
212
 
                    self.assertEqual(line.contents, next)
 
155
                    assert(line.contents == next)
213
156
        self.assertRaises(StopIteration, rem_iter.next)
214
157
 
215
158
    def testPatching(self):
220
163
            ('diff-4', 'orig-4', 'mod-4'),
221
164
            ('diff-5', 'orig-5', 'mod-5'),
222
165
            ('diff-6', 'orig-6', 'mod-6'),
223
 
            ('diff-7', 'orig-7', 'mod-7'),
224
166
        ]
225
167
        for diff, orig, mod in files:
226
168
            patch = self.datafile(diff)
235
177
                count += 1
236
178
            self.assertEqual(count, len(mod_lines))
237
179
 
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
 
 
266
180
    def testFirstLineRenumber(self):
267
181
        """Make sure we handle lines at the beginning of the hunk"""
268
182
        patch = parse_patch(self.datafile("insert_top.patch"))
269
 
        self.assertEqual(patch.pos_in_mod(0), 1)
270
 
 
271
 
    def testParsePatches(self):
272
 
        """Make sure file names can be extracted from tricky unified diffs"""
273
 
        patchtext = \
274
 
"""--- orig-7
275
 
+++ mod-7
276
 
@@ -1,10 +1,10 @@
277
 
 -- a
278
 
--- b
279
 
+++ c
280
 
 xx d
281
 
 xx e
282
 
 ++ f
283
 
-++ g
284
 
+-- h
285
 
 xx i
286
 
 xx j
287
 
 -- k
288
 
--- l
289
 
+++ m
290
 
--- orig-8
291
 
+++ mod-8
292
 
@@ -1 +1 @@
293
 
--- A
294
 
+++ B
295
 
@@ -1 +1 @@
296
 
--- C
297
 
+++ D
298
 
"""
299
 
        filenames = [('orig-7', 'mod-7'),
300
 
                     ('orig-8', 'mod-8')]
301
 
        patches = parse_patches(patchtext.splitlines(True))
302
 
        patch_files = []
303
 
        for patch in patches:
304
 
            patch_files.append((patch.oldname, patch.newname))
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())
 
183
        assert (patch.pos_in_mod(0)==1)
 
184
 
 
185
def test():
 
186
    patchesTestSuite = unittest.makeSuite(PatchesTester,'test')
 
187
    runner = unittest.TextTestRunner(verbosity=0)
 
188
    return runner.run(patchesTestSuite)
 
189
 
 
190
 
 
191
if __name__ == "__main__":
 
192
    test()