~bzr-pqm/bzr/bzr.dev

1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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
1185.82.127 by Aaron Bentley
PEP8 updates
17
18
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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
1185.82.127 by Aaron Bentley
PEP8 updates
36
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
37
class PatchesTester(unittest.TestCase):
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
38
    def datafile(self, filename):
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
39
        data_path = os.path.join(os.path.dirname(__file__), 
40
                                 "test_patches_data", filename)
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
41
        return file(data_path, "rb")
42
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
43
    def testValidPatchHeader(self):
44
        """Parse a valid patch header"""
45
        lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
46
        (orig, mod) = get_patch_names(lines.__iter__())
47
        assert(orig == "orig/commands.py")
48
        assert(mod == "mod/dommands.py")
49
50
    def testInvalidPatchHeader(self):
51
        """Parse an invalid patch header"""
52
        lines = "-- orig/commands.py\n+++ mod/dommands.py".split('\n')
53
        self.assertRaises(MalformedPatchHeader, get_patch_names,
54
                          lines.__iter__())
55
56
    def testValidHunkHeader(self):
57
        """Parse a valid hunk header"""
58
        header = "@@ -34,11 +50,6 @@\n"
59
        hunk = hunk_from_header(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)
65
66
    def testValidHunkHeader2(self):
67
        """Parse a tricky, valid hunk header"""
68
        header = "@@ -1 +0,0 @@\n"
69
        hunk = hunk_from_header(header);
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)
75
76
    def makeMalformed(self, header):
77
        self.assertRaises(MalformedHunkHeader, hunk_from_header, header)
78
79
    def testInvalidHeader(self):
80
        """Parse an invalid hunk header"""
81
        self.makeMalformed(" -34,11 +50,6 \n")
82
        self.makeMalformed("@@ +50,6 -34,11 @@\n")
83
        self.makeMalformed("@@ -34,11 +50,6 @@")
84
        self.makeMalformed("@@ -34.5,11 +50,6 @@\n")
85
        self.makeMalformed("@@-34,11 +50,6@@\n")
86
        self.makeMalformed("@@ 34,11 50,6 @@\n")
87
        self.makeMalformed("@@ -34,11 @@\n")
88
        self.makeMalformed("@@ -34,11 +50,6.5 @@\n")
89
        self.makeMalformed("@@ -34,11 +50,-6 @@\n")
90
91
    def lineThing(self,text, type):
92
        line = parse_line(text)
93
        assert(isinstance(line, type))
94
        assert(str(line)==text)
95
96
    def makeMalformedLine(self, text):
97
        self.assertRaises(MalformedLine, parse_line, text)
98
99
    def testValidLine(self):
100
        """Parse a valid hunk line"""
101
        self.lineThing(" hello\n", ContextLine)
102
        self.lineThing("+hello\n", InsertLine)
103
        self.lineThing("-hello\n", RemoveLine)
104
    
105
    def testMalformedLine(self):
106
        """Parse invalid valid hunk lines"""
107
        self.makeMalformedLine("hello\n")
108
    
109
    def compare_parsed(self, patchtext):
110
        lines = patchtext.splitlines(True)
111
        patch = parse_patch(lines.__iter__())
112
        pstr = str(patch)
113
        i = difference_index(patchtext, pstr)
114
        if i is not None:
115
            print "%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i])
116
        self.assertEqual (patchtext, str(patch))
117
118
    def testAll(self):
119
        """Test parsing a whole patch"""
1185.82.129 by Aaron Bentley
Removed confusing text from the test module
120
        patchtext = self.datafile("patchtext.patch").read()
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
121
        self.compare_parsed(patchtext)
122
123
    def testInit(self):
124
        """Handle patches missing half the position, range tuple"""
125
        patchtext = \
1185.82.129 by Aaron Bentley
Removed confusing text from the test module
126
"""--- orig/__vavg__.cl
127
+++ mod/__vavg__.cl
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
128
@@ -1 +1,2 @@
1185.82.129 by Aaron Bentley
Removed confusing text from the test module
129
 __qbpsbezng__ = "erfgehpgherqgrkg ra"
130
+__qbp__ = Na nygreangr Nepu pbzznaqyvar vagresnpr
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
131
"""
132
        self.compare_parsed(patchtext)
133
134
    def testLineLookup(self):
135
        import sys
136
        """Make sure we can accurately look up mod line from orig"""
137
        patch = parse_patch(self.datafile("diff"))
138
        orig = list(self.datafile("orig"))
139
        mod = list(self.datafile("mod"))
140
        removals = []
141
        for i in range(len(orig)):
142
            mod_pos = patch.pos_in_mod(i)
143
            if mod_pos is None:
144
                removals.append(orig[i])
145
                continue
146
            assert(mod[mod_pos]==orig[i])
147
        rem_iter = removals.__iter__()
148
        for hunk in patch.hunks:
149
            for line in hunk.lines:
150
                if isinstance(line, RemoveLine):
151
                    next = rem_iter.next()
152
                    if line.contents != next:
153
                        sys.stdout.write(" orig:%spatch:%s" % (next,
154
                                         line.contents))
155
                    assert(line.contents == next)
156
        self.assertRaises(StopIteration, rem_iter.next)
157
158
    def testPatching(self):
159
        """Test a few patch files, and make sure they work."""
160
        files = [
161
            ('diff-2', 'orig-2', 'mod-2'),
162
            ('diff-3', 'orig-3', 'mod-3'),
163
            ('diff-4', 'orig-4', 'mod-4'),
164
            ('diff-5', 'orig-5', 'mod-5'),
165
            ('diff-6', 'orig-6', 'mod-6'),
166
        ]
167
        for diff, orig, mod in files:
168
            patch = self.datafile(diff)
169
            orig_lines = list(self.datafile(orig))
170
            mod_lines = list(self.datafile(mod))
171
172
            patched_file = IterableFile(iter_patched(orig_lines, patch))
173
            lines = []
174
            count = 0
175
            for patch_line in patched_file:
176
                self.assertEqual(patch_line, mod_lines[count])
177
                count += 1
178
            self.assertEqual(count, len(mod_lines))
179
180
    def testFirstLineRenumber(self):
181
        """Make sure we handle lines at the beginning of the hunk"""
182
        patch = parse_patch(self.datafile("insert_top.patch"))
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()