~bzr/ubuntu/lucid/bzr/beta-ppa

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_patches_data/diff-6

  • Committer: Martin Pool
  • Date: 2010-07-02 07:29:40 UTC
  • mfrom: (129.1.7 packaging-karmic)
  • Revision ID: mbp@sourcefrog.net-20100702072940-hpzq5elg8wjve8rh
* PPA rebuild.
* PPA rebuild for Karmic.
* PPA rebuild for Jaunty.
* PPA rebuild for Hardy.
* From postinst, actually remove the example bash completion scripts.
  (LP: #249452)
* New upstream release.
* New upstream release.
* New upstream release.
* Revert change to Build-depends: Dapper does not have python-central.
  Should be python-support..
* Target ppa..
* Target ppa..
* Target ppa..
* Target ppa..
* New upstream release.
* Switch to dpkg-source 3.0 (quilt) format.
* Bump standards version to 3.8.4.
* Remove embedded copy of python-configobj. Closes: #555336
* Remove embedded copy of python-elementtree. Closes: #555343
* Change section from 'Devel' to 'Vcs'..
* Change section from 'Devel' to 'Vcs'..
* Change section from 'Devel' to 'Vcs'..
* Change section from 'Devel' to 'Vcs'..
* Change section from 'Devel' to 'Vcs'..
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* debian/control: Fix obsolete-relation-form-in-source
  lintian warning. 
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Split out docs into bzr-doc package.
* New upstream release.
* Added John Francesco Ferlito to Uploaders.
* Fix install path to quick-reference guide
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Fix FTBFS due to path changes, again.
* Fix FTBFS due to doc paths changing
* New upstream release.
* Fix FTBFS due to path changes, again.
* Fix FTBFS due to doc paths changing
* New upstream release.
* Fix FTBFS due to path changes, again.
* Fix FTBFS due to doc paths changing
* New upstream release.
* Fix FTBFS due to path changes, again, again.
* Fix FTBFS due to path changes, again.
* Fix FTBFS due to path changes.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Bump standards version to 3.8.3.
* Remove unused patch system.
* New upstream release.
* New upstream release.
* New upstream release.
* Fix copy and paste tab error in .install file
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
 + Fixes compatibility with Python 2.4. Closes: #537708
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream version.
* Bump standards version to 3.8.2.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Add python-pyrex to build-deps to ensure C extensions are always build.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Split documentation into bzr-doc package. ((LP: #385074)
* Multiple packaging changes to make us more linitan clean.
* New upstream release.
* Split documentation into bzr-doc package. ((LP: #385074)
* Multiple packaging changes to make us more linitan clean.
* New upstream release.
* Split documentation into bzr-doc package. ((LP: #385074)
* Multiple packaging changes to make us more linitan clean.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Fix API compatibility version. (Closes: #526233)
* New upstream release.
  + Fixes default format for upgrade command. (Closes: #464688)
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Add missing dependency on zlib development library. (Closes:
  #523595)
* Add zlib build-depends.
* Add zlib build-depends.
* Add zlib build-depends.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Move to section vcs.
* Bump standards version to 3.8.1.
* New upstream release.
* Remove temporary patch for missing .c files from distribution
* New upstream release.
* Remove temporary patch for missing .c files from distribution
* New upstream release.
* Remove temporary patch for missing .c files from distribution
* Add temporary patch for missing .c files from distribution
* Add temporary patch for missing .c files from distribution
* Add temporary patch for missing .c files from distribution
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Recommend ca-certificates. (Closes: #452024)
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Update watch file. bazaar now uses launchpad to host its sources.
* Remove patch for inventory root revision copy, applied upstream.
* New upstream release.
* New upstream release.
* New upstream release
* Force removal of files installed in error to /etc/bash_completion.d/
  (LP: #249452)
* New upstream release.
* New upstream release
* New upstream release.
* Bump standards version.
* Include patch for inventory root revision copy, required for bzr-svn.
* New upstream release.
* Remove unused lintian overrides.
* Correct the package version not to be native.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* New upstream release.
* Final 1.5 release.
* New upstream release.
* New upstream release.
* New upstream release.
* Add myself as a co-maintainer.
* Add a Dm-Upload-Allowed: yes header.
* New upstream bugfix release.
* New upstream release.
* Final 1.3 release.
* New upstream release.
* First release candidate of the upcoming 1.3 release.
* Rebuild to fix the problem caused by a build with a broken python-central.
* New upstream release.
* Rebuild for dapper PPA.
* Apply Lamont's patches to fix build-dependencies on dapper.
  (See: https://bugs.launchpad.net/bzr/+bug/189915)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
--- orig-6      2005-09-23 16:27:16.000000000 -0500
 
2
+++ mod-6       2005-09-23 16:27:32.000000000 -0500
 
3
@@ -1,558 +1 @@
 
4
-# Copyright (C) 2004, 2005 Aaron Bentley
 
5
-# <aaron.bentley@utoronto.ca>
 
6
-#
 
7
-#    This program is free software; you can redistribute it and/or modify
 
8
-#    it under the terms of the GNU General Public License as published by
 
9
-#    the Free Software Foundation; either version 2 of the License, or
 
10
-#    (at your option) any later version.
 
11
-#
 
12
-#    This program is distributed in the hope that it will be useful,
 
13
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
-#    GNU General Public License for more details.
 
16
-#
 
17
-#    You should have received a copy of the GNU General Public License
 
18
-#    along with this program; if not, write to the Free Software
 
19
-#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
20
-
 
21
-class PatchSyntax(Exception):
 
22
-    def __init__(self, msg):
 
23
-        Exception.__init__(self, msg)
 
24
-
 
25
-
 
26
-class MalformedPatchHeader(PatchSyntax):
 
27
-    def __init__(self, desc, line):
 
28
-        self.desc = desc
 
29
-        self.line = line
 
30
-        msg = "Malformed patch header.  %s\n%r" % (self.desc, self.line)
 
31
-        PatchSyntax.__init__(self, msg)
 
32
-
 
33
-class MalformedHunkHeader(PatchSyntax):
 
34
-    def __init__(self, desc, line):
 
35
-        self.desc = desc
 
36
-        self.line = line
 
37
-        msg = "Malformed hunk header.  %s\n%r" % (self.desc, self.line)
 
38
-        PatchSyntax.__init__(self, msg)
 
39
-
 
40
-class MalformedLine(PatchSyntax):
 
41
-    def __init__(self, desc, line):
 
42
-        self.desc = desc
 
43
-        self.line = line
 
44
-        msg = "Malformed line.  %s\n%s" % (self.desc, self.line)
 
45
-        PatchSyntax.__init__(self, msg)
 
46
-
 
47
-def get_patch_names(iter_lines):
 
48
-    try:
 
49
-        line = iter_lines.next()
 
50
-        if not line.startswith("--- "):
 
51
-            raise MalformedPatchHeader("No orig name", line)
 
52
-        else:
 
53
-            orig_name = line[4:].rstrip("\n")
 
54
-    except StopIteration:
 
55
-        raise MalformedPatchHeader("No orig line", "")
 
56
-    try:
 
57
-        line = iter_lines.next()
 
58
-        if not line.startswith("+++ "):
 
59
-            raise PatchSyntax("No mod name")
 
60
-        else:
 
61
-            mod_name = line[4:].rstrip("\n")
 
62
-    except StopIteration:
 
63
-        raise MalformedPatchHeader("No mod line", "")
 
64
-    return (orig_name, mod_name)
 
65
-
 
66
-def parse_range(textrange):
 
67
-    """Parse a patch range, handling the "1" special-case
 
68
-
 
69
-    :param textrange: The text to parse
 
70
-    :type textrange: str
 
71
-    :return: the position and range, as a tuple
 
72
-    :rtype: (int, int)
 
73
-    """
 
74
-    tmp = textrange.split(',')
 
75
-    if len(tmp) == 1:
 
76
-        pos = tmp[0]
 
77
-        range = "1"
 
78
-    else:
 
79
-        (pos, range) = tmp
 
80
-    pos = int(pos)
 
81
-    range = int(range)
 
82
-    return (pos, range)
 
83
-
 
84
 
85
-def hunk_from_header(line):
 
86
-    if not line.startswith("@@") or not line.endswith("@@\n") \
 
87
-        or not len(line) > 4:
 
88
-        raise MalformedHunkHeader("Does not start and end with @@.", line)
 
89
-    try:
 
90
-        (orig, mod) = line[3:-4].split(" ")
 
91
-    except Exception, e:
 
92
-        raise MalformedHunkHeader(str(e), line)
 
93
-    if not orig.startswith('-') or not mod.startswith('+'):
 
94
-        raise MalformedHunkHeader("Positions don't start with + or -.", line)
 
95
-    try:
 
96
-        (orig_pos, orig_range) = parse_range(orig[1:])
 
97
-        (mod_pos, mod_range) = parse_range(mod[1:])
 
98
-    except Exception, e:
 
99
-        raise MalformedHunkHeader(str(e), line)
 
100
-    if mod_range < 0 or orig_range < 0:
 
101
-        raise MalformedHunkHeader("Hunk range is negative", line)
 
102
-    return Hunk(orig_pos, orig_range, mod_pos, mod_range)
 
103
-
 
104
-
 
105
-class HunkLine:
 
106
-    def __init__(self, contents):
 
107
-        self.contents = contents
 
108
-
 
109
-    def get_str(self, leadchar):
 
110
-        if self.contents == "\n" and leadchar == " " and False:
 
111
-            return "\n"
 
112
-        if not self.contents.endswith('\n'):
 
113
-            terminator = '\n' + NO_NL
 
114
-        else:
 
115
-            terminator = ''
 
116
-        return leadchar + self.contents + terminator
 
117
-
 
118
-
 
119
-class ContextLine(HunkLine):
 
120
-    def __init__(self, contents):
 
121
-        HunkLine.__init__(self, contents)
 
122
-
 
123
-    def __str__(self):
 
124
-        return self.get_str(" ")
 
125
-
 
126
-
 
127
-class InsertLine(HunkLine):
 
128
-    def __init__(self, contents):
 
129
-        HunkLine.__init__(self, contents)
 
130
-
 
131
-    def __str__(self):
 
132
-        return self.get_str("+")
 
133
-
 
134
-
 
135
-class RemoveLine(HunkLine):
 
136
-    def __init__(self, contents):
 
137
-        HunkLine.__init__(self, contents)
 
138
-
 
139
-    def __str__(self):
 
140
-        return self.get_str("-")
 
141
-
 
142
-NO_NL = '\\ No newline at end of file\n'
 
143
-__pychecker__="no-returnvalues"
 
144
-
 
145
-def parse_line(line):
 
146
-    if line.startswith("\n"):
 
147
-        return ContextLine(line)
 
148
-    elif line.startswith(" "):
 
149
-        return ContextLine(line[1:])
 
150
-    elif line.startswith("+"):
 
151
-        return InsertLine(line[1:])
 
152
-    elif line.startswith("-"):
 
153
-        return RemoveLine(line[1:])
 
154
-    elif line == NO_NL:
 
155
-        return NO_NL
 
156
-    else:
 
157
-        raise MalformedLine("Unknown line type", line)
 
158
-__pychecker__=""
 
159
-
 
160
-
 
161
-class Hunk:
 
162
-    def __init__(self, orig_pos, orig_range, mod_pos, mod_range):
 
163
-        self.orig_pos = orig_pos
 
164
-        self.orig_range = orig_range
 
165
-        self.mod_pos = mod_pos
 
166
-        self.mod_range = mod_range
 
167
-        self.lines = []
 
168
-
 
169
-    def get_header(self):
 
170
-        return "@@ -%s +%s @@\n" % (self.range_str(self.orig_pos, 
 
171
-                                                   self.orig_range),
 
172
-                                    self.range_str(self.mod_pos, 
 
173
-                                                   self.mod_range))
 
174
-
 
175
-    def range_str(self, pos, range):
 
176
-        """Return a file range, special-casing for 1-line files.
 
177
-
 
178
-        :param pos: The position in the file
 
179
-        :type pos: int
 
180
-        :range: The range in the file
 
181
-        :type range: int
 
182
-        :return: a string in the format 1,4 except when range == pos == 1
 
183
-        """
 
184
-        if range == 1:
 
185
-            return "%i" % pos
 
186
-        else:
 
187
-            return "%i,%i" % (pos, range)
 
188
-
 
189
-    def __str__(self):
 
190
-        lines = [self.get_header()]
 
191
-        for line in self.lines:
 
192
-            lines.append(str(line))
 
193
-        return "".join(lines)
 
194
-
 
195
-    def shift_to_mod(self, pos):
 
196
-        if pos < self.orig_pos-1:
 
197
-            return 0
 
198
-        elif pos > self.orig_pos+self.orig_range:
 
199
-            return self.mod_range - self.orig_range
 
200
-        else:
 
201
-            return self.shift_to_mod_lines(pos)
 
202
-
 
203
-    def shift_to_mod_lines(self, pos):
 
204
-        assert (pos >= self.orig_pos-1 and pos <= self.orig_pos+self.orig_range)
 
205
-        position = self.orig_pos-1
 
206
-        shift = 0
 
207
-        for line in self.lines:
 
208
-            if isinstance(line, InsertLine):
 
209
-                shift += 1
 
210
-            elif isinstance(line, RemoveLine):
 
211
-                if position == pos:
 
212
-                    return None
 
213
-                shift -= 1
 
214
-                position += 1
 
215
-            elif isinstance(line, ContextLine):
 
216
-                position += 1
 
217
-            if position > pos:
 
218
-                break
 
219
-        return shift
 
220
-
 
221
-def iter_hunks(iter_lines):
 
222
-    hunk = None
 
223
-    for line in iter_lines:
 
224
-        if line == "\n":
 
225
-            if hunk is not None:
 
226
-                yield hunk
 
227
-                hunk = None
 
228
-            continue
 
229
-        if hunk is not None:
 
230
-            yield hunk
 
231
-        hunk = hunk_from_header(line)
 
232
-        orig_size = 0
 
233
-        mod_size = 0
 
234
-        while orig_size < hunk.orig_range or mod_size < hunk.mod_range:
 
235
-            hunk_line = parse_line(iter_lines.next())
 
236
-            hunk.lines.append(hunk_line)
 
237
-            if isinstance(hunk_line, (RemoveLine, ContextLine)):
 
238
-                orig_size += 1
 
239
-            if isinstance(hunk_line, (InsertLine, ContextLine)):
 
240
-                mod_size += 1
 
241
-    if hunk is not None:
 
242
-        yield hunk
 
243
-
 
244
-class Patch:
 
245
-    def __init__(self, oldname, newname):
 
246
-        self.oldname = oldname
 
247
-        self.newname = newname
 
248
-        self.hunks = []
 
249
-
 
250
-    def __str__(self):
 
251
-        ret = self.get_header() 
 
252
-        ret += "".join([str(h) for h in self.hunks])
 
253
-        return ret
 
254
-
 
255
-    def get_header(self):
 
256
-        return "--- %s\n+++ %s\n" % (self.oldname, self.newname)
 
257
-
 
258
-    def stats_str(self):
 
259
-        """Return a string of patch statistics"""
 
260
-        removes = 0
 
261
-        inserts = 0
 
262
-        for hunk in self.hunks:
 
263
-            for line in hunk.lines:
 
264
-                if isinstance(line, InsertLine):
 
265
-                     inserts+=1;
 
266
-                elif isinstance(line, RemoveLine):
 
267
-                     removes+=1;
 
268
-        return "%i inserts, %i removes in %i hunks" % \
 
269
-            (inserts, removes, len(self.hunks))
 
270
-
 
271
-    def pos_in_mod(self, position):
 
272
-        newpos = position
 
273
-        for hunk in self.hunks:
 
274
-            shift = hunk.shift_to_mod(position)
 
275
-            if shift is None:
 
276
-                return None
 
277
-            newpos += shift
 
278
-        return newpos
 
279
-            
 
280
-    def iter_inserted(self):
 
281
-        """Iteraties through inserted lines
 
282
-        
 
283
-        :return: Pair of line number, line
 
284
-        :rtype: iterator of (int, InsertLine)
 
285
-        """
 
286
-        for hunk in self.hunks:
 
287
-            pos = hunk.mod_pos - 1;
 
288
-            for line in hunk.lines:
 
289
-                if isinstance(line, InsertLine):
 
290
-                    yield (pos, line)
 
291
-                    pos += 1
 
292
-                if isinstance(line, ContextLine):
 
293
-                    pos += 1
 
294
-
 
295
-def parse_patch(iter_lines):
 
296
-    (orig_name, mod_name) = get_patch_names(iter_lines)
 
297
-    patch = Patch(orig_name, mod_name)
 
298
-    for hunk in iter_hunks(iter_lines):
 
299
-        patch.hunks.append(hunk)
 
300
-    return patch
 
301
-
 
302
-
 
303
-def iter_file_patch(iter_lines):
 
304
-    saved_lines = []
 
305
-    for line in iter_lines:
 
306
-        if line.startswith('=== '):
 
307
-            continue
 
308
-        elif line.startswith('--- '):
 
309
-            if len(saved_lines) > 0:
 
310
-                yield saved_lines
 
311
-            saved_lines = []
 
312
-        saved_lines.append(line)
 
313
-    if len(saved_lines) > 0:
 
314
-        yield saved_lines
 
315
-
 
316
-
 
317
-def iter_lines_handle_nl(iter_lines):
 
318
-    """
 
319
-    Iterates through lines, ensuring that lines that originally had no
 
320
-    terminating \n are produced without one.  This transformation may be
 
321
-    applied at any point up until hunk line parsing, and is safe to apply
 
322
-    repeatedly.
 
323
-    """
 
324
-    last_line = None
 
325
-    for line in iter_lines:
 
326
-        if line == NO_NL:
 
327
-            assert last_line.endswith('\n')
 
328
-            last_line = last_line[:-1]
 
329
-            line = None
 
330
-        if last_line is not None:
 
331
-            yield last_line
 
332
-        last_line = line
 
333
-    if last_line is not None:
 
334
-        yield last_line
 
335
-
 
336
-
 
337
-def parse_patches(iter_lines):
 
338
-    iter_lines = iter_lines_handle_nl(iter_lines)
 
339
-    return [parse_patch(f.__iter__()) for f in iter_file_patch(iter_lines)]
 
340
-
 
341
-
 
342
-def difference_index(atext, btext):
 
343
-    """Find the indext of the first character that differs betweeen two texts
 
344
-
 
345
-    :param atext: The first text
 
346
-    :type atext: str
 
347
-    :param btext: The second text
 
348
-    :type str: str
 
349
-    :return: The index, or None if there are no differences within the range
 
350
-    :rtype: int or NoneType
 
351
-    """
 
352
-    length = len(atext)
 
353
-    if len(btext) < length:
 
354
-        length = len(btext)
 
355
-    for i in range(length):
 
356
-        if atext[i] != btext[i]:
 
357
-            return i;
 
358
-    return None
 
359
-
 
360
-class PatchConflict(Exception):
 
361
-    def __init__(self, line_no, orig_line, patch_line):
 
362
-        orig = orig_line.rstrip('\n')
 
363
-        patch = str(patch_line).rstrip('\n')
 
364
-        msg = 'Text contents mismatch at line %d.  Original has "%s",'\
 
365
-            ' but patch says it should be "%s"' % (line_no, orig, patch)
 
366
-        Exception.__init__(self, msg)
 
367
-
 
368
-
 
369
-def iter_patched(orig_lines, patch_lines):
 
370
-    """Iterate through a series of lines with a patch applied.
 
371
-    This handles a single file, and does exact, not fuzzy patching.
 
372
-    """
 
373
-    if orig_lines is not None:
 
374
-        orig_lines = orig_lines.__iter__()
 
375
-    seen_patch = []
 
376
-    patch_lines = iter_lines_handle_nl(patch_lines.__iter__())
 
377
-    get_patch_names(patch_lines)
 
378
-    line_no = 1
 
379
-    for hunk in iter_hunks(patch_lines):
 
380
-        while line_no < hunk.orig_pos:
 
381
-            orig_line = orig_lines.next()
 
382
-            yield orig_line
 
383
-            line_no += 1
 
384
-        for hunk_line in hunk.lines:
 
385
-            seen_patch.append(str(hunk_line))
 
386
-            if isinstance(hunk_line, InsertLine):
 
387
-                yield hunk_line.contents
 
388
-            elif isinstance(hunk_line, (ContextLine, RemoveLine)):
 
389
-                orig_line = orig_lines.next()
 
390
-                if orig_line != hunk_line.contents:
 
391
-                    raise PatchConflict(line_no, orig_line, "".join(seen_patch))
 
392
-                if isinstance(hunk_line, ContextLine):
 
393
-                    yield orig_line
 
394
-                else:
 
395
-                    assert isinstance(hunk_line, RemoveLine)
 
396
-                line_no += 1
 
397
-                    
 
398
-import unittest
 
399
-import os.path
 
400
-class PatchesTester(unittest.TestCase):
 
401
-    def datafile(self, filename):
 
402
-        data_path = os.path.join(os.path.dirname(__file__), "testdata", 
 
403
-                                 filename)
 
404
-        return file(data_path, "rb")
 
405
-
 
406
-    def testValidPatchHeader(self):
 
407
-        """Parse a valid patch header"""
 
408
-        lines = "--- orig/commands.py\n+++ mod/dommands.py\n".split('\n')
 
409
-        (orig, mod) = get_patch_names(lines.__iter__())
 
410
-        assert(orig == "orig/commands.py")
 
411
-        assert(mod == "mod/dommands.py")
 
412
-
 
413
-    def testInvalidPatchHeader(self):
 
414
-        """Parse an invalid patch header"""
 
415
-        lines = "-- orig/commands.py\n+++ mod/dommands.py".split('\n')
 
416
-        self.assertRaises(MalformedPatchHeader, get_patch_names,
 
417
-                          lines.__iter__())
 
418
-
 
419
-    def testValidHunkHeader(self):
 
420
-        """Parse a valid hunk header"""
 
421
-        header = "@@ -34,11 +50,6 @@\n"
 
422
-        hunk = hunk_from_header(header);
 
423
-        assert (hunk.orig_pos == 34)
 
424
-        assert (hunk.orig_range == 11)
 
425
-        assert (hunk.mod_pos == 50)
 
426
-        assert (hunk.mod_range == 6)
 
427
-        assert (str(hunk) == header)
 
428
-
 
429
-    def testValidHunkHeader2(self):
 
430
-        """Parse a tricky, valid hunk header"""
 
431
-        header = "@@ -1 +0,0 @@\n"
 
432
-        hunk = hunk_from_header(header);
 
433
-        assert (hunk.orig_pos == 1)
 
434
-        assert (hunk.orig_range == 1)
 
435
-        assert (hunk.mod_pos == 0)
 
436
-        assert (hunk.mod_range == 0)
 
437
-        assert (str(hunk) == header)
 
438
-
 
439
-    def makeMalformed(self, header):
 
440
-        self.assertRaises(MalformedHunkHeader, hunk_from_header, header)
 
441
-
 
442
-    def testInvalidHeader(self):
 
443
-        """Parse an invalid hunk header"""
 
444
-        self.makeMalformed(" -34,11 +50,6 \n")
 
445
-        self.makeMalformed("@@ +50,6 -34,11 @@\n")
 
446
-        self.makeMalformed("@@ -34,11 +50,6 @@")
 
447
-        self.makeMalformed("@@ -34.5,11 +50,6 @@\n")
 
448
-        self.makeMalformed("@@-34,11 +50,6@@\n")
 
449
-        self.makeMalformed("@@ 34,11 50,6 @@\n")
 
450
-        self.makeMalformed("@@ -34,11 @@\n")
 
451
-        self.makeMalformed("@@ -34,11 +50,6.5 @@\n")
 
452
-        self.makeMalformed("@@ -34,11 +50,-6 @@\n")
 
453
-
 
454
-    def lineThing(self,text, type):
 
455
-        line = parse_line(text)
 
456
-        assert(isinstance(line, type))
 
457
-        assert(str(line)==text)
 
458
-
 
459
-    def makeMalformedLine(self, text):
 
460
-        self.assertRaises(MalformedLine, parse_line, text)
 
461
-
 
462
-    def testValidLine(self):
 
463
-        """Parse a valid hunk line"""
 
464
-        self.lineThing(" hello\n", ContextLine)
 
465
-        self.lineThing("+hello\n", InsertLine)
 
466
-        self.lineThing("-hello\n", RemoveLine)
 
467
-    
 
468
-    def testMalformedLine(self):
 
469
-        """Parse invalid valid hunk lines"""
 
470
-        self.makeMalformedLine("hello\n")
 
471
-    
 
472
-    def compare_parsed(self, patchtext):
 
473
-        lines = patchtext.splitlines(True)
 
474
-        patch = parse_patch(lines.__iter__())
 
475
-        pstr = str(patch)
 
476
-        i = difference_index(patchtext, pstr)
 
477
-        if i is not None:
 
478
-            print "%i: \"%s\" != \"%s\"" % (i, patchtext[i], pstr[i])
 
479
-        self.assertEqual (patchtext, str(patch))
 
480
-
 
481
-    def testAll(self):
 
482
-        """Test parsing a whole patch"""
 
483
-        patchtext = """--- orig/commands.py
 
484
-+++ mod/commands.py
 
485
-@@ -1337,7 +1337,8 @@
 
486
 
487
-     def set_title(self, command=None):
 
488
-         try:
 
489
--            version = self.tree.tree_version.nonarch
 
490
-+            version = pylon.alias_or_version(self.tree.tree_version, self.tree,
 
491
-+                                             full=False)
 
492
-         except:
 
493
-             version = "[no version]"
 
494
-         if command is None:
 
495
-@@ -1983,7 +1984,11 @@
 
496
-                                          version)
 
497
-         if len(new_merges) > 0:
 
498
-             if cmdutil.prompt("Log for merge"):
 
499
--                mergestuff = cmdutil.log_for_merge(tree, comp_version)
 
500
-+                if cmdutil.prompt("changelog for merge"):
 
501
-+                    mergestuff = "Patches applied:\\n"
 
502
-+                    mergestuff += pylon.changelog_for_merge(new_merges)
 
503
-+                else:
 
504
-+                    mergestuff = cmdutil.log_for_merge(tree, comp_version)
 
505
-                 log.description += mergestuff
 
506
-         log.save()
 
507
-     try:
 
508
-"""
 
509
-        self.compare_parsed(patchtext)
 
510
-
 
511
-    def testInit(self):
 
512
-        """Handle patches missing half the position, range tuple"""
 
513
-        patchtext = \
 
514
-"""--- orig/__init__.py
 
515
-+++ mod/__init__.py
 
516
-@@ -1 +1,2 @@
 
517
- __docformat__ = "restructuredtext en"
 
518
-+__doc__ = An alternate Arch commandline interface
 
519
-"""
 
520
-        self.compare_parsed(patchtext)
 
521
-        
 
522
-
 
523
-
 
524
-    def testLineLookup(self):
 
525
-        import sys
 
526
-        """Make sure we can accurately look up mod line from orig"""
 
527
-        patch = parse_patch(self.datafile("diff"))
 
528
-        orig = list(self.datafile("orig"))
 
529
-        mod = list(self.datafile("mod"))
 
530
-        removals = []
 
531
-        for i in range(len(orig)):
 
532
-            mod_pos = patch.pos_in_mod(i)
 
533
-            if mod_pos is None:
 
534
-                removals.append(orig[i])
 
535
-                continue
 
536
-            assert(mod[mod_pos]==orig[i])
 
537
-        rem_iter = removals.__iter__()
 
538
-        for hunk in patch.hunks:
 
539
-            for line in hunk.lines:
 
540
-                if isinstance(line, RemoveLine):
 
541
-                    next = rem_iter.next()
 
542
-                    if line.contents != next:
 
543
-                        sys.stdout.write(" orig:%spatch:%s" % (next,
 
544
-                                         line.contents))
 
545
-                    assert(line.contents == next)
 
546
-        self.assertRaises(StopIteration, rem_iter.next)
 
547
-
 
548
-    def testFirstLineRenumber(self):
 
549
-        """Make sure we handle lines at the beginning of the hunk"""
 
550
-        patch = parse_patch(self.datafile("insert_top.patch"))
 
551
-        assert (patch.pos_in_mod(0)==1)
 
552
-
 
553
-def test():
 
554
-    patchesTestSuite = unittest.makeSuite(PatchesTester,'test')
 
555
-    runner = unittest.TextTestRunner(verbosity=0)
 
556
-    return runner.run(patchesTestSuite)
 
557
-    
 
558
-
 
559
-if __name__ == "__main__":
 
560
-    test()
 
561
-# arch-tag: d1541a25-eac5-4de9-a476-08a7cecd5683
 
562
+Total contents change