~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_patches.py

  • Committer: Robert Collins
  • Date: 2005-08-23 06:52:09 UTC
  • mto: (974.1.50) (1185.1.10) (1092.3.1)
  • mto: This revision was merged to the branch mainline in revision 1139.
  • Revision ID: robertc@robertcollins.net-20050823065209-81cd5962c401751b
move io redirection into each test case from the global runner

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2004 - 2008 Aaron Bentley, Canonical Ltd
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 os.path
20
 
 
21
 
from bzrlib.tests import TestCase
22
 
 
23
 
from bzrlib.iterablefile import IterableFile
24
 
from bzrlib.patches import (MalformedLine, 
25
 
                            MalformedHunkHeader, 
26
 
                            MalformedPatchHeader, 
27
 
                            ContextLine, 
28
 
                            InsertLine,
29
 
                            RemoveLine, 
30
 
                            difference_index, 
31
 
                            get_patch_names,
32
 
                            hunk_from_header, 
33
 
                            iter_patched, 
34
 
                            iter_patched_from_hunks,
35
 
                            parse_line,
36
 
                            parse_patch,
37
 
                            parse_patches)
38
 
 
39
 
 
40
 
class PatchesTester(TestCase):
41
 
 
42
 
    def datafile(self, filename):
43
 
        data_path = os.path.join(os.path.dirname(__file__), 
44
 
                                 "test_patches_data", filename)
45
 
        return file(data_path, "rb")
46
 
 
47
 
    def testValidPatchHeader(self):
48
 
        """Parse a valid patch header"""
49
 
        lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
50
 
        (orig, mod) = get_patch_names(lines.__iter__())
51
 
        self.assertEqual(orig, "orig/commands.py")
52
 
        self.assertEqual(mod, "mod/dommands.py")
53
 
 
54
 
    def testInvalidPatchHeader(self):
55
 
        """Parse an invalid patch header"""
56
 
        lines = "-- orig/commands.py\n+++ mod/dommands.py".split('\n')
57
 
        self.assertRaises(MalformedPatchHeader, get_patch_names,
58
 
                          lines.__iter__())
59
 
 
60
 
    def testValidHunkHeader(self):
61
 
        """Parse a valid hunk header"""
62
 
        header = "@@ -34,11 +50,6 @@\n"
63
 
        hunk = hunk_from_header(header);
64
 
        self.assertEqual(hunk.orig_pos, 34)
65
 
        self.assertEqual(hunk.orig_range, 11)
66
 
        self.assertEqual(hunk.mod_pos, 50)
67
 
        self.assertEqual(hunk.mod_range, 6)
68
 
        self.assertEqual(str(hunk), header)
69
 
 
70
 
    def testValidHunkHeader2(self):
71
 
        """Parse a tricky, valid hunk header"""
72
 
        header = "@@ -1 +0,0 @@\n"
73
 
        hunk = hunk_from_header(header);
74
 
        self.assertEqual(hunk.orig_pos, 1)
75
 
        self.assertEqual(hunk.orig_range, 1)
76
 
        self.assertEqual(hunk.mod_pos, 0)
77
 
        self.assertEqual(hunk.mod_range, 0)
78
 
        self.assertEqual(str(hunk), header)
79
 
 
80
 
    def testPDiff(self):
81
 
        """Parse a hunk header produced by diff -p"""
82
 
        header = "@@ -407,7 +292,7 @@ bzr 0.18rc1  2007-07-10\n"
83
 
        hunk = hunk_from_header(header)
84
 
        self.assertEqual('bzr 0.18rc1  2007-07-10', hunk.tail)
85
 
        self.assertEqual(header, str(hunk))
86
 
 
87
 
    def makeMalformed(self, header):
88
 
        self.assertRaises(MalformedHunkHeader, hunk_from_header, header)
89
 
 
90
 
    def testInvalidHeader(self):
91
 
        """Parse an invalid hunk header"""
92
 
        self.makeMalformed(" -34,11 +50,6 \n")
93
 
        self.makeMalformed("@@ +50,6 -34,11 @@\n")
94
 
        self.makeMalformed("@@ -34,11 +50,6 @@")
95
 
        self.makeMalformed("@@ -34.5,11 +50,6 @@\n")
96
 
        self.makeMalformed("@@-34,11 +50,6@@\n")
97
 
        self.makeMalformed("@@ 34,11 50,6 @@\n")
98
 
        self.makeMalformed("@@ -34,11 @@\n")
99
 
        self.makeMalformed("@@ -34,11 +50,6.5 @@\n")
100
 
        self.makeMalformed("@@ -34,11 +50,-6 @@\n")
101
 
 
102
 
    def lineThing(self,text, type):
103
 
        line = parse_line(text)
104
 
        self.assertIsInstance(line, type)
105
 
        self.assertEqual(str(line), text)
106
 
 
107
 
    def makeMalformedLine(self, text):
108
 
        self.assertRaises(MalformedLine, parse_line, text)
109
 
 
110
 
    def testValidLine(self):
111
 
        """Parse a valid hunk line"""
112
 
        self.lineThing(" hello\n", ContextLine)
113
 
        self.lineThing("+hello\n", InsertLine)
114
 
        self.lineThing("-hello\n", RemoveLine)
115
 
    
116
 
    def testMalformedLine(self):
117
 
        """Parse invalid valid hunk lines"""
118
 
        self.makeMalformedLine("hello\n")
119
 
    
120
 
    def compare_parsed(self, patchtext):
121
 
        lines = patchtext.splitlines(True)
122
 
        patch = parse_patch(lines.__iter__())
123
 
        pstr = str(patch)
124
 
        i = difference_index(patchtext, pstr)
125
 
        if i is not None:
126
 
            print "%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i])
127
 
        self.assertEqual (patchtext, str(patch))
128
 
 
129
 
    def testAll(self):
130
 
        """Test parsing a whole patch"""
131
 
        patchtext = self.datafile("patchtext.patch").read()
132
 
        self.compare_parsed(patchtext)
133
 
 
134
 
    def testInit(self):
135
 
        """Handle patches missing half the position, range tuple"""
136
 
        patchtext = \
137
 
"""--- orig/__vavg__.cl
138
 
+++ mod/__vavg__.cl
139
 
@@ -1 +1,2 @@
140
 
 __qbpsbezng__ = "erfgehpgherqgrkg ra"
141
 
+__qbp__ = Na nygreangr Nepu pbzznaqyvar vagresnpr
142
 
"""
143
 
        self.compare_parsed(patchtext)
144
 
 
145
 
    def testLineLookup(self):
146
 
        import sys
147
 
        """Make sure we can accurately look up mod line from orig"""
148
 
        patch = parse_patch(self.datafile("diff"))
149
 
        orig = list(self.datafile("orig"))
150
 
        mod = list(self.datafile("mod"))
151
 
        removals = []
152
 
        for i in range(len(orig)):
153
 
            mod_pos = patch.pos_in_mod(i)
154
 
            if mod_pos is None:
155
 
                removals.append(orig[i])
156
 
                continue
157
 
            self.assertEqual(mod[mod_pos], orig[i])
158
 
        rem_iter = removals.__iter__()
159
 
        for hunk in patch.hunks:
160
 
            for line in hunk.lines:
161
 
                if isinstance(line, RemoveLine):
162
 
                    next = rem_iter.next()
163
 
                    if line.contents != next:
164
 
                        sys.stdout.write(" orig:%spatch:%s" % (next,
165
 
                                         line.contents))
166
 
                    self.assertEqual(line.contents, next)
167
 
        self.assertRaises(StopIteration, rem_iter.next)
168
 
 
169
 
    def testPatching(self):
170
 
        """Test a few patch files, and make sure they work."""
171
 
        files = [
172
 
            ('diff-2', 'orig-2', 'mod-2'),
173
 
            ('diff-3', 'orig-3', 'mod-3'),
174
 
            ('diff-4', 'orig-4', 'mod-4'),
175
 
            ('diff-5', 'orig-5', 'mod-5'),
176
 
            ('diff-6', 'orig-6', 'mod-6'),
177
 
        ]
178
 
        for diff, orig, mod in files:
179
 
            patch = self.datafile(diff)
180
 
            orig_lines = list(self.datafile(orig))
181
 
            mod_lines = list(self.datafile(mod))
182
 
 
183
 
            patched_file = IterableFile(iter_patched(orig_lines, patch))
184
 
            lines = []
185
 
            count = 0
186
 
            for patch_line in patched_file:
187
 
                self.assertEqual(patch_line, mod_lines[count])
188
 
                count += 1
189
 
            self.assertEqual(count, len(mod_lines))
190
 
 
191
 
    def test_iter_patched_from_hunks(self):
192
 
        """Test a few patch files, and make sure they work."""
193
 
        files = [
194
 
            ('diff-2', 'orig-2', 'mod-2'),
195
 
            ('diff-3', 'orig-3', 'mod-3'),
196
 
            ('diff-4', 'orig-4', 'mod-4'),
197
 
            ('diff-5', 'orig-5', 'mod-5'),
198
 
            ('diff-6', 'orig-6', 'mod-6'),
199
 
        ]
200
 
        for diff, orig, mod in files:
201
 
            parsed = parse_patch(self.datafile(diff))
202
 
            orig_lines = list(self.datafile(orig))
203
 
            mod_lines = list(self.datafile(mod))
204
 
            iter_patched = iter_patched_from_hunks(orig_lines, parsed.hunks)
205
 
            patched_file = IterableFile(iter_patched)
206
 
            lines = []
207
 
            count = 0
208
 
            for patch_line in patched_file:
209
 
                self.assertEqual(patch_line, mod_lines[count])
210
 
                count += 1
211
 
            self.assertEqual(count, len(mod_lines))
212
 
 
213
 
    def testFirstLineRenumber(self):
214
 
        """Make sure we handle lines at the beginning of the hunk"""
215
 
        patch = parse_patch(self.datafile("insert_top.patch"))
216
 
        self.assertEqual(patch.pos_in_mod(0), 1)
217
 
 
218
 
    def testParsePatches(self):
219
 
        """Make sure file names can be extracted from tricky unified diffs"""
220
 
        patchtext = \
221
 
"""--- orig-7
222
 
+++ mod-7
223
 
@@ -1,10 +1,10 @@
224
 
 -- a
225
 
--- b
226
 
+++ c
227
 
 xx d
228
 
 xx e
229
 
 ++ f
230
 
-++ g
231
 
+-- h
232
 
 xx i
233
 
 xx j
234
 
 -- k
235
 
--- l
236
 
+++ m
237
 
--- orig-8
238
 
+++ mod-8
239
 
@@ -1 +1 @@
240
 
--- A
241
 
+++ B
242
 
@@ -1 +1 @@
243
 
--- C
244
 
+++ D
245
 
"""
246
 
        filenames = [('orig-7', 'mod-7'),
247
 
                     ('orig-8', 'mod-8')]
248
 
        patches = parse_patches(patchtext.splitlines(True))
249
 
        patch_files = []
250
 
        for patch in patches:
251
 
            patch_files.append((patch.oldname, patch.newname))
252
 
        self.assertEqual(patch_files, filenames)