~bzr-pqm/bzr/bzr.dev

3376.2.6 by Martin Pool
Make PatchesTester use bzrlib TestCase base
1
# Copyright (C) 2004 - 2008 Aaron Bentley, Canonical Ltd
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
2
# <aaron.bentley@utoronto.ca>
3
#
2052.3.1 by John Arbash Meinel
Add tests to cleanup the copyright of all source files
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
4183.7.1 by Sabin Iacob
update FSF mailing address
16
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 os.path
20
3376.2.6 by Martin Pool
Make PatchesTester use bzrlib TestCase base
21
from bzrlib.tests import TestCase
22
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
23
from bzrlib.iterablefile import IterableFile
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
24
from bzrlib.patches import (MalformedLine,
25
                            MalformedHunkHeader,
26
                            MalformedPatchHeader,
27
                            ContextLine,
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
28
                            InsertLine,
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
29
                            RemoveLine,
30
                            difference_index,
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
31
                            get_patch_names,
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
32
                            hunk_from_header,
33
                            iter_patched,
3363.18.3 by Aaron Bentley
Add tests for iter_patched_from_hunks
34
                            iter_patched_from_hunks,
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
35
                            parse_line,
2298.6.1 by Johan Dahlberg
Fix bzrtools shelve command for removed lines beginning with "--"
36
                            parse_patch,
3873.1.2 by Benoît Pierre
Add patches test for 'No newline at end of file' in the middle of hunk lines.
37
                            parse_patches,
38
                            NO_NL)
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
39
1185.82.127 by Aaron Bentley
PEP8 updates
40
3376.2.6 by Martin Pool
Make PatchesTester use bzrlib TestCase base
41
class PatchesTester(TestCase):
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
42
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
43
    def datafile(self, filename):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
44
        data_path = os.path.join(os.path.dirname(__file__),
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
45
                                 "test_patches_data", filename)
1185.82.7 by John Arbash Meinel
Adding patches.py into bzrlib, including the tests into the test suite.
46
        return file(data_path, "rb")
47
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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__())
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
52
        self.assertEqual(orig, "orig/commands.py")
53
        self.assertEqual(mod, "mod/dommands.py")
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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);
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
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)
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
70
71
    def testValidHunkHeader2(self):
72
        """Parse a tricky, valid hunk header"""
73
        header = "@@ -1 +0,0 @@\n"
74
        hunk = hunk_from_header(header);
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
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)
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
80
1551.18.6 by Aaron Bentley
Add support for diff -p-style diffs to patch parser
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
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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)
3376.2.5 by Martin Pool
Remove a few more elusive assert statements
105
        self.assertIsInstance(line, type)
106
        self.assertEqual(str(line), text)
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
116
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
117
    def testMalformedLine(self):
118
        """Parse invalid valid hunk lines"""
119
        self.makeMalformedLine("hello\n")
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
120
3873.1.2 by Benoît Pierre
Add patches test for 'No newline at end of file' in the middle of hunk lines.
121
    def testMalformedLineNO_NL(self):
3873.1.4 by Benoît Pierre
Add another test for patches to check we correctly handle '\ No newline
122
        """Parse invalid '\ No newline at end of file' in hunk lines"""
3873.1.2 by Benoît Pierre
Add patches test for 'No newline at end of file' in the middle of hunk lines.
123
        self.makeMalformedLine(NO_NL)
124
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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"""
1185.82.129 by Aaron Bentley
Removed confusing text from the test module
136
        patchtext = self.datafile("patchtext.patch").read()
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
137
        self.compare_parsed(patchtext)
138
139
    def testInit(self):
140
        """Handle patches missing half the position, range tuple"""
141
        patchtext = \
1185.82.129 by Aaron Bentley
Removed confusing text from the test module
142
"""--- orig/__vavg__.cl
143
+++ mod/__vavg__.cl
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
144
@@ -1 +1,2 @@
1185.82.129 by Aaron Bentley
Removed confusing text from the test module
145
 __qbpsbezng__ = "erfgehpgherqgrkg ra"
146
+__qbp__ = Na nygreangr Nepu pbzznaqyvar vagresnpr
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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
3376.2.5 by Martin Pool
Remove a few more elusive assert statements
162
            self.assertEqual(mod[mod_pos], orig[i])
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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))
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
171
                    self.assertEqual(line.contents, next)
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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'),
3873.1.4 by Benoît Pierre
Add another test for patches to check we correctly handle '\ No newline
182
            ('diff-7', 'orig-7', 'mod-7'),
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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
3363.18.3 by Aaron Bentley
Add tests for iter_patched_from_hunks
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'),
3873.1.4 by Benoît Pierre
Add another test for patches to check we correctly handle '\ No newline
205
            ('diff-7', 'orig-7', 'mod-7'),
3363.18.3 by Aaron Bentley
Add tests for iter_patched_from_hunks
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
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
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"))
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
223
        self.assertEqual(patch.pos_in_mod(0), 1)
1185.82.126 by Aaron Bentley
Split the patch testing out into a separate file
224
2298.6.1 by Johan Dahlberg
Fix bzrtools shelve command for removed lines beginning with "--"
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))
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
259
        self.assertEqual(patch_files, filenames)
3946.4.1 by Tim Penhey
Extract out the counting of the stats values.
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())