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