~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_patches.py

  • Committer: Martin Pool
  • Date: 2005-05-03 08:00:27 UTC
  • Revision ID: mbp@sourcefrog.net-20050503080027-908edb5b39982198
doc

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