~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_patches.py

Exclude more files from dumb-rsync upload

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 makeMalformed(self, header):
78
 
        self.assertRaises(MalformedHunkHeader, hunk_from_header, header)
79
 
 
80
 
    def testInvalidHeader(self):
81
 
        """Parse an invalid hunk header"""
82
 
        self.makeMalformed(" -34,11 +50,6 \n")
83
 
        self.makeMalformed("@@ +50,6 -34,11 @@\n")
84
 
        self.makeMalformed("@@ -34,11 +50,6 @@")
85
 
        self.makeMalformed("@@ -34.5,11 +50,6 @@\n")
86
 
        self.makeMalformed("@@-34,11 +50,6@@\n")
87
 
        self.makeMalformed("@@ 34,11 50,6 @@\n")
88
 
        self.makeMalformed("@@ -34,11 @@\n")
89
 
        self.makeMalformed("@@ -34,11 +50,6.5 @@\n")
90
 
        self.makeMalformed("@@ -34,11 +50,-6 @@\n")
91
 
 
92
 
    def lineThing(self,text, type):
93
 
        line = parse_line(text)
94
 
        assert(isinstance(line, type))
95
 
        assert(str(line)==text)
96
 
 
97
 
    def makeMalformedLine(self, text):
98
 
        self.assertRaises(MalformedLine, parse_line, text)
99
 
 
100
 
    def testValidLine(self):
101
 
        """Parse a valid hunk line"""
102
 
        self.lineThing(" hello\n", ContextLine)
103
 
        self.lineThing("+hello\n", InsertLine)
104
 
        self.lineThing("-hello\n", RemoveLine)
105
 
    
106
 
    def testMalformedLine(self):
107
 
        """Parse invalid valid hunk lines"""
108
 
        self.makeMalformedLine("hello\n")
109
 
    
110
 
    def compare_parsed(self, patchtext):
111
 
        lines = patchtext.splitlines(True)
112
 
        patch = parse_patch(lines.__iter__())
113
 
        pstr = str(patch)
114
 
        i = difference_index(patchtext, pstr)
115
 
        if i is not None:
116
 
            print "%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i])
117
 
        self.assertEqual (patchtext, str(patch))
118
 
 
119
 
    def testAll(self):
120
 
        """Test parsing a whole patch"""
121
 
        patchtext = self.datafile("patchtext.patch").read()
122
 
        self.compare_parsed(patchtext)
123
 
 
124
 
    def testInit(self):
125
 
        """Handle patches missing half the position, range tuple"""
126
 
        patchtext = \
127
 
"""--- orig/__vavg__.cl
128
 
+++ mod/__vavg__.cl
129
 
@@ -1 +1,2 @@
130
 
 __qbpsbezng__ = "erfgehpgherqgrkg ra"
131
 
+__qbp__ = Na nygreangr Nepu pbzznaqyvar vagresnpr
132
 
"""
133
 
        self.compare_parsed(patchtext)
134
 
 
135
 
    def testLineLookup(self):
136
 
        import sys
137
 
        """Make sure we can accurately look up mod line from orig"""
138
 
        patch = parse_patch(self.datafile("diff"))
139
 
        orig = list(self.datafile("orig"))
140
 
        mod = list(self.datafile("mod"))
141
 
        removals = []
142
 
        for i in range(len(orig)):
143
 
            mod_pos = patch.pos_in_mod(i)
144
 
            if mod_pos is None:
145
 
                removals.append(orig[i])
146
 
                continue
147
 
            assert(mod[mod_pos]==orig[i])
148
 
        rem_iter = removals.__iter__()
149
 
        for hunk in patch.hunks:
150
 
            for line in hunk.lines:
151
 
                if isinstance(line, RemoveLine):
152
 
                    next = rem_iter.next()
153
 
                    if line.contents != next:
154
 
                        sys.stdout.write(" orig:%spatch:%s" % (next,
155
 
                                         line.contents))
156
 
                    assert(line.contents == next)
157
 
        self.assertRaises(StopIteration, rem_iter.next)
158
 
 
159
 
    def testPatching(self):
160
 
        """Test a few patch files, and make sure they work."""
161
 
        files = [
162
 
            ('diff-2', 'orig-2', 'mod-2'),
163
 
            ('diff-3', 'orig-3', 'mod-3'),
164
 
            ('diff-4', 'orig-4', 'mod-4'),
165
 
            ('diff-5', 'orig-5', 'mod-5'),
166
 
            ('diff-6', 'orig-6', 'mod-6'),
167
 
        ]
168
 
        for diff, orig, mod in files:
169
 
            patch = self.datafile(diff)
170
 
            orig_lines = list(self.datafile(orig))
171
 
            mod_lines = list(self.datafile(mod))
172
 
 
173
 
            patched_file = IterableFile(iter_patched(orig_lines, patch))
174
 
            lines = []
175
 
            count = 0
176
 
            for patch_line in patched_file:
177
 
                self.assertEqual(patch_line, mod_lines[count])
178
 
                count += 1
179
 
            self.assertEqual(count, len(mod_lines))
180
 
 
181
 
    def testFirstLineRenumber(self):
182
 
        """Make sure we handle lines at the beginning of the hunk"""
183
 
        patch = parse_patch(self.datafile("insert_top.patch"))
184
 
        assert (patch.pos_in_mod(0)==1)
185
 
 
186
 
    def testParsePatches(self):
187
 
        """Make sure file names can be extracted from tricky unified diffs"""
188
 
        patchtext = \
189
 
"""--- orig-7
190
 
+++ mod-7
191
 
@@ -1,10 +1,10 @@
192
 
 -- a
193
 
--- b
194
 
+++ c
195
 
 xx d
196
 
 xx e
197
 
 ++ f
198
 
-++ g
199
 
+-- h
200
 
 xx i
201
 
 xx j
202
 
 -- k
203
 
--- l
204
 
+++ m
205
 
--- orig-8
206
 
+++ mod-8
207
 
@@ -1 +1 @@
208
 
--- A
209
 
+++ B
210
 
@@ -1 +1 @@
211
 
--- C
212
 
+++ D
213
 
"""
214
 
        filenames = [('orig-7', 'mod-7'),
215
 
                     ('orig-8', 'mod-8')]
216
 
        patches = parse_patches(patchtext.splitlines(True))
217
 
        patch_files = []
218
 
        for patch in patches:
219
 
            patch_files.append((patch.oldname, patch.newname))
220
 
        assert (patch_files == filenames)
221
 
            
222
 
def test():
223
 
    patchesTestSuite = unittest.makeSuite(PatchesTester,'test')
224
 
    runner = unittest.TextTestRunner(verbosity=0)
225
 
    return runner.run(patchesTestSuite)
226
 
 
227
 
 
228
 
if __name__ == "__main__":
229
 
    test()