~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/selftest/testdiff.py

- trim imports

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Development Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
 
13
 
# You should have received a copy of the GNU General Public License
14
 
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
 
 
17
 
import os
 
1
from bzrlib.selftest import TestCase
 
2
from bzrlib.diff import internal_diff
18
3
from cStringIO import StringIO
19
 
import errno
20
 
from tempfile import TemporaryFile
21
 
 
22
 
from bzrlib.diff import internal_diff, external_diff, show_diff_trees
23
 
from bzrlib.errors import BinaryFile, NoDiff
24
 
import bzrlib.patiencediff
25
 
from bzrlib.tests import (TestCase, TestCaseWithTransport,
26
 
                          TestCaseInTempDir, TestSkipped)
27
 
 
28
 
 
29
 
def udiff_lines(old, new, allow_binary=False):
 
4
def udiff_lines(old, new):
30
5
    output = StringIO()
31
 
    internal_diff('old', old, 'new', new, output, allow_binary)
 
6
    internal_diff('old', old, 'new', new, output)
32
7
    output.seek(0, 0)
33
8
    return output.readlines()
34
9
 
35
 
 
36
 
def external_udiff_lines(old, new, use_stringio=False):
37
 
    if use_stringio:
38
 
        # StringIO has no fileno, so it tests a different codepath
39
 
        output = StringIO()
40
 
    else:
41
 
        output = TemporaryFile()
42
 
    try:
43
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
44
 
    except NoDiff:
45
 
        raise TestSkipped('external "diff" not present to test')
46
 
    output.seek(0, 0)
47
 
    lines = output.readlines()
48
 
    output.close()
49
 
    return lines
50
 
 
 
10
def check_patch(lines):
 
11
    assert len(lines) > 1, \
 
12
        "Not enough lines for a file header for patch:\n%s" % "".join(lines)
 
13
    assert lines[0].startswith ('---'), \
 
14
        'No orig line for patch:\n%s' % "".join(lines)
 
15
    assert lines[1].startswith ('+++'), \
 
16
        'No mod line for patch:\n%s' % "".join(lines)
 
17
    assert len(lines) > 2, \
 
18
        "No hunks for patch:\n%s" % "".join(lines)
 
19
    assert lines[2].startswith('@@'),\
 
20
        "No hunk header for patch:\n%s" % "".join(lines)
 
21
    assert '@@' in lines[2][2:], \
 
22
        "Unterminated hunk header for patch:\n%s" % "".join(lines)
51
23
 
52
24
class TestDiff(TestCase):
53
 
 
54
25
    def test_add_nl(self):
55
26
        """diff generates a valid diff for patches that add a newline"""
56
27
        lines = udiff_lines(['boo'], ['boo\n'])
57
 
        self.check_patch(lines)
58
 
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
59
 
            ## "expected no-nl, got %r" % lines[4]
 
28
        check_patch(lines)
 
29
        assert lines[4] == '\\ No newline at end of file\n', \
 
30
            "expected no-nl, got %r" % lines[4]
60
31
 
61
32
    def test_add_nl_2(self):
62
33
        """diff generates a valid diff for patches that change last line and
63
34
        add a newline.
64
35
        """
65
36
        lines = udiff_lines(['boo'], ['goo\n'])
66
 
        self.check_patch(lines)
67
 
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
68
 
            ## "expected no-nl, got %r" % lines[4]
 
37
        check_patch(lines)
 
38
        assert lines[4] == '\\ No newline at end of file\n', \
 
39
            "expected no-nl, got %r" % lines[4]
69
40
 
70
41
    def test_remove_nl(self):
71
42
        """diff generates a valid diff for patches that change last line and
72
43
        add a newline.
73
44
        """
74
45
        lines = udiff_lines(['boo\n'], ['boo'])
75
 
        self.check_patch(lines)
76
 
        self.assertEquals(lines[5], '\\ No newline at end of file\n')
77
 
            ## "expected no-nl, got %r" % lines[5]
78
 
 
79
 
    def check_patch(self, lines):
80
 
        self.assert_(len(lines) > 1)
81
 
            ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
82
 
        self.assert_(lines[0].startswith ('---'))
83
 
            ## 'No orig line for patch:\n%s' % "".join(lines)
84
 
        self.assert_(lines[1].startswith ('+++'))
85
 
            ## 'No mod line for patch:\n%s' % "".join(lines)
86
 
        self.assert_(len(lines) > 2)
87
 
            ## "No hunks for patch:\n%s" % "".join(lines)
88
 
        self.assert_(lines[2].startswith('@@'))
89
 
            ## "No hunk header for patch:\n%s" % "".join(lines)
90
 
        self.assert_('@@' in lines[2][2:])
91
 
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
92
 
 
93
 
    def test_binary_lines(self):
94
 
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
95
 
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
96
 
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
97
 
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
98
 
 
99
 
    def test_external_diff(self):
100
 
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
101
 
        self.check_patch(lines)
102
 
 
103
 
    def test_external_diff_no_fileno(self):
104
 
        # Make sure that we can handle not having a fileno, even
105
 
        # if the diff is large
106
 
        lines = external_udiff_lines(['boo\n']*10000,
107
 
                                     ['goo\n']*10000,
108
 
                                     use_stringio=True)
109
 
        self.check_patch(lines)
110
 
        
111
 
    def test_internal_diff_default(self):
112
 
        # Default internal diff encoding is utf8
113
 
        output = StringIO()
114
 
        internal_diff(u'old_\xb5', ['old_text\n'],
115
 
                    u'new_\xe5', ['new_text\n'], output)
116
 
        lines = output.getvalue().splitlines(True)
117
 
        self.check_patch(lines)
118
 
        self.assertEquals(['--- old_\xc2\xb5\n',
119
 
                           '+++ new_\xc3\xa5\n',
120
 
                           '@@ -1,1 +1,1 @@\n',
121
 
                           '-old_text\n',
122
 
                           '+new_text\n',
123
 
                           '\n',
124
 
                          ]
125
 
                          , lines)
126
 
 
127
 
    def test_internal_diff_utf8(self):
128
 
        output = StringIO()
129
 
        internal_diff(u'old_\xb5', ['old_text\n'],
130
 
                    u'new_\xe5', ['new_text\n'], output,
131
 
                    path_encoding='utf8')
132
 
        lines = output.getvalue().splitlines(True)
133
 
        self.check_patch(lines)
134
 
        self.assertEquals(['--- old_\xc2\xb5\n',
135
 
                           '+++ new_\xc3\xa5\n',
136
 
                           '@@ -1,1 +1,1 @@\n',
137
 
                           '-old_text\n',
138
 
                           '+new_text\n',
139
 
                           '\n',
140
 
                          ]
141
 
                          , lines)
142
 
 
143
 
    def test_internal_diff_iso_8859_1(self):
144
 
        output = StringIO()
145
 
        internal_diff(u'old_\xb5', ['old_text\n'],
146
 
                    u'new_\xe5', ['new_text\n'], output,
147
 
                    path_encoding='iso-8859-1')
148
 
        lines = output.getvalue().splitlines(True)
149
 
        self.check_patch(lines)
150
 
        self.assertEquals(['--- old_\xb5\n',
151
 
                           '+++ new_\xe5\n',
152
 
                           '@@ -1,1 +1,1 @@\n',
153
 
                           '-old_text\n',
154
 
                           '+new_text\n',
155
 
                           '\n',
156
 
                          ]
157
 
                          , lines)
158
 
 
159
 
    def test_internal_diff_returns_bytes(self):
160
 
        import StringIO
161
 
        output = StringIO.StringIO()
162
 
        internal_diff(u'old_\xb5', ['old_text\n'],
163
 
                    u'new_\xe5', ['new_text\n'], output)
164
 
        self.failUnless(isinstance(output.getvalue(), str),
165
 
            'internal_diff should return bytestrings')
166
 
 
167
 
 
168
 
class TestDiffDates(TestCaseWithTransport):
169
 
 
170
 
    def setUp(self):
171
 
        super(TestDiffDates, self).setUp()
172
 
        self.wt = self.make_branch_and_tree('.')
173
 
        self.b = self.wt.branch
174
 
        self.build_tree_contents([
175
 
            ('file1', 'file1 contents at rev 1\n'),
176
 
            ('file2', 'file2 contents at rev 1\n')
177
 
            ])
178
 
        self.wt.add(['file1', 'file2'])
179
 
        self.wt.commit(
180
 
            message='Revision 1',
181
 
            timestamp=1143849600, # 2006-04-01 00:00:00 UTC
182
 
            timezone=0,
183
 
            rev_id='rev-1')
184
 
        self.build_tree_contents([('file1', 'file1 contents at rev 2\n')])
185
 
        self.wt.commit(
186
 
            message='Revision 2',
187
 
            timestamp=1143936000, # 2006-04-02 00:00:00 UTC
188
 
            timezone=28800,
189
 
            rev_id='rev-2')
190
 
        self.build_tree_contents([('file2', 'file2 contents at rev 3\n')])
191
 
        self.wt.commit(
192
 
            message='Revision 3',
193
 
            timestamp=1144022400, # 2006-04-03 00:00:00 UTC
194
 
            timezone=-3600,
195
 
            rev_id='rev-3')
196
 
        self.wt.remove(['file2'])
197
 
        self.wt.commit(
198
 
            message='Revision 4',
199
 
            timestamp=1144108800, # 2006-04-04 00:00:00 UTC
200
 
            timezone=0,
201
 
            rev_id='rev-4')
202
 
        self.build_tree_contents([
203
 
            ('file1', 'file1 contents in working tree\n')
204
 
            ])
205
 
        # set the date stamps for files in the working tree to known values
206
 
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
207
 
 
208
 
    def get_diff(self, tree1, tree2):
209
 
        output = StringIO()
210
 
        show_diff_trees(tree1, tree2, output,
211
 
                        old_label='old/', new_label='new/')
212
 
        return output.getvalue()
213
 
 
214
 
    def test_diff_rev_tree_working_tree(self):
215
 
        output = self.get_diff(self.wt.basis_tree(), self.wt)
216
 
        # note that the date for old/file1 is from rev 2 rather than from
217
 
        # the basis revision (rev 4)
218
 
        self.assertEqualDiff(output, '''\
219
 
=== modified file 'file1'
220
 
--- old/file1\t2006-04-02 00:00:00 +0000
221
 
+++ new/file1\t2006-04-05 00:00:00 +0000
222
 
@@ -1,1 +1,1 @@
223
 
-file1 contents at rev 2
224
 
+file1 contents in working tree
225
 
 
226
 
''')
227
 
 
228
 
    def test_diff_rev_tree_rev_tree(self):
229
 
        tree1 = self.b.repository.revision_tree('rev-2')
230
 
        tree2 = self.b.repository.revision_tree('rev-3')
231
 
        output = self.get_diff(tree1, tree2)
232
 
        self.assertEqualDiff(output, '''\
233
 
=== modified file 'file2'
234
 
--- old/file2\t2006-04-01 00:00:00 +0000
235
 
+++ new/file2\t2006-04-03 00:00:00 +0000
236
 
@@ -1,1 +1,1 @@
237
 
-file2 contents at rev 1
238
 
+file2 contents at rev 3
239
 
 
240
 
''')
241
 
        
242
 
    def test_diff_add_files(self):
243
 
        tree1 = self.b.repository.revision_tree(None)
244
 
        tree2 = self.b.repository.revision_tree('rev-1')
245
 
        output = self.get_diff(tree1, tree2)
246
 
        # the files have the epoch time stamp for the tree in which
247
 
        # they don't exist.
248
 
        self.assertEqualDiff(output, '''\
249
 
=== added file 'file1'
250
 
--- old/file1\t1970-01-01 00:00:00 +0000
251
 
+++ new/file1\t2006-04-01 00:00:00 +0000
252
 
@@ -0,0 +1,1 @@
253
 
+file1 contents at rev 1
254
 
 
255
 
=== added file 'file2'
256
 
--- old/file2\t1970-01-01 00:00:00 +0000
257
 
+++ new/file2\t2006-04-01 00:00:00 +0000
258
 
@@ -0,0 +1,1 @@
259
 
+file2 contents at rev 1
260
 
 
261
 
''')
262
 
 
263
 
    def test_diff_remove_files(self):
264
 
        tree1 = self.b.repository.revision_tree('rev-3')
265
 
        tree2 = self.b.repository.revision_tree('rev-4')
266
 
        output = self.get_diff(tree1, tree2)
267
 
        # the file has the epoch time stamp for the tree in which
268
 
        # it doesn't exist.
269
 
        self.assertEqualDiff(output, '''\
270
 
=== removed file 'file2'
271
 
--- old/file2\t2006-04-03 00:00:00 +0000
272
 
+++ new/file2\t1970-01-01 00:00:00 +0000
273
 
@@ -1,1 +0,0 @@
274
 
-file2 contents at rev 3
275
 
 
276
 
''')
277
 
 
278
 
 
279
 
class TestPatienceDiffLib(TestCase):
280
 
 
281
 
    def test_unique_lcs(self):
282
 
        unique_lcs = bzrlib.patiencediff.unique_lcs
283
 
        self.assertEquals(unique_lcs('', ''), [])
284
 
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
285
 
        self.assertEquals(unique_lcs('a', 'b'), [])
286
 
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
287
 
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
288
 
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
289
 
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1), 
290
 
                                                         (3,3), (4,4)])
291
 
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
292
 
 
293
 
    def test_recurse_matches(self):
294
 
        def test_one(a, b, matches):
295
 
            test_matches = []
296
 
            bzrlib.patiencediff.recurse_matches(a, b, 0, 0, len(a), len(b),
297
 
                test_matches, 10)
298
 
            self.assertEquals(test_matches, matches)
299
 
 
300
 
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
301
 
                 [(0, 0), (2, 2), (4, 4)])
302
 
        test_one(['a', 'c', 'b', 'a', 'c'], ['a', 'b', 'c'],
303
 
                 [(0, 0), (2, 1), (4, 2)])
304
 
 
305
 
        # recurse_matches doesn't match non-unique 
306
 
        # lines surrounded by bogus text.
307
 
        # The update has been done in patiencediff.SequenceMatcher instead
308
 
 
309
 
        # This is what it could be
310
 
        #test_one('aBccDe', 'abccde', [(0,0), (2,2), (3,3), (5,5)])
311
 
 
312
 
        # This is what it currently gives:
313
 
        test_one('aBccDe', 'abccde', [(0,0), (5,5)])
314
 
 
315
 
    def test_matching_blocks(self):
316
 
        def chk_blocks(a, b, expected_blocks):
317
 
            # difflib always adds a signature of the total
318
 
            # length, with no matching entries at the end
319
 
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
320
 
            blocks = s.get_matching_blocks()
321
 
            self.assertEquals((len(a), len(b), 0), blocks[-1])
322
 
            self.assertEquals(expected_blocks, blocks[:-1])
323
 
 
324
 
        # Some basic matching tests
325
 
        chk_blocks('', '', [])
326
 
        chk_blocks([], [], [])
327
 
        chk_blocks('abcd', 'abcd', [(0, 0, 4)])
328
 
        chk_blocks('abcd', 'abce', [(0, 0, 3)])
329
 
        chk_blocks('eabc', 'abce', [(1, 0, 3)])
330
 
        chk_blocks('eabce', 'abce', [(1, 0, 4)])
331
 
        chk_blocks('abcde', 'abXde', [(0, 0, 2), (3, 3, 2)])
332
 
        chk_blocks('abcde', 'abXYZde', [(0, 0, 2), (3, 5, 2)])
333
 
        chk_blocks('abde', 'abXYZde', [(0, 0, 2), (2, 5, 2)])
334
 
        # This may check too much, but it checks to see that 
335
 
        # a copied block stays attached to the previous section,
336
 
        # not the later one.
337
 
        # difflib would tend to grab the trailing longest match
338
 
        # which would make the diff not look right
339
 
        chk_blocks('abcdefghijklmnop', 'abcdefxydefghijklmnop',
340
 
                   [(0, 0, 6), (6, 11, 10)])
341
 
 
342
 
        # make sure it supports passing in lists
343
 
        chk_blocks(
344
 
                   ['hello there\n',
345
 
                    'world\n',
346
 
                    'how are you today?\n'],
347
 
                   ['hello there\n',
348
 
                    'how are you today?\n'],
349
 
                [(0, 0, 1), (2, 1, 1)])
350
 
 
351
 
        # non unique lines surrounded by non-matching lines
352
 
        # won't be found
353
 
        chk_blocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
354
 
 
355
 
        # But they only need to be locally unique
356
 
        chk_blocks('aBcDec', 'abcdec', [(0,0,1), (2,2,1), (4,4,2)])
357
 
 
358
 
        # non unique blocks won't be matched
359
 
        chk_blocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (8,8,1)])
360
 
 
361
 
        # but locally unique ones will
362
 
        chk_blocks('aBcdEeXcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
363
 
                                              (5,4,1), (7,5,2), (10,8,1)])
364
 
 
365
 
        chk_blocks('abbabbXd', 'cabbabxd', [(7,7,1)])
366
 
        chk_blocks('abbabbbb', 'cabbabbc', [])
367
 
        chk_blocks('bbbbbbbb', 'cbbbbbbc', [])
368
 
 
369
 
    def test_opcodes(self):
370
 
        def chk_ops(a, b, expected_codes):
371
 
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
372
 
            self.assertEquals(expected_codes, s.get_opcodes())
373
 
 
374
 
        chk_ops('', '', [])
375
 
        chk_ops([], [], [])
376
 
        chk_ops('abcd', 'abcd', [('equal',    0,4, 0,4)])
377
 
        chk_ops('abcd', 'abce', [('equal',   0,3, 0,3),
378
 
                                 ('replace', 3,4, 3,4)
379
 
                                ])
380
 
        chk_ops('eabc', 'abce', [('delete', 0,1, 0,0),
381
 
                                 ('equal',  1,4, 0,3),
382
 
                                 ('insert', 4,4, 3,4)
383
 
                                ])
384
 
        chk_ops('eabce', 'abce', [('delete', 0,1, 0,0),
385
 
                                  ('equal',  1,5, 0,4)
386
 
                                 ])
387
 
        chk_ops('abcde', 'abXde', [('equal',   0,2, 0,2),
388
 
                                   ('replace', 2,3, 2,3),
389
 
                                   ('equal',   3,5, 3,5)
390
 
                                  ])
391
 
        chk_ops('abcde', 'abXYZde', [('equal',   0,2, 0,2),
392
 
                                     ('replace', 2,3, 2,5),
393
 
                                     ('equal',   3,5, 5,7)
394
 
                                    ])
395
 
        chk_ops('abde', 'abXYZde', [('equal',  0,2, 0,2),
396
 
                                    ('insert', 2,2, 2,5),
397
 
                                    ('equal',  2,4, 5,7)
398
 
                                   ])
399
 
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
400
 
                [('equal',  0,6,  0,6),
401
 
                 ('insert', 6,6,  6,11),
402
 
                 ('equal',  6,16, 11,21)
403
 
                ])
404
 
        chk_ops(
405
 
                [ 'hello there\n'
406
 
                , 'world\n'
407
 
                , 'how are you today?\n'],
408
 
                [ 'hello there\n'
409
 
                , 'how are you today?\n'],
410
 
                [('equal',  0,1, 0,1),
411
 
                 ('delete', 1,2, 1,1),
412
 
                 ('equal',  2,3, 1,2),
413
 
                ])
414
 
        chk_ops('aBccDe', 'abccde', 
415
 
                [('equal',   0,1, 0,1),
416
 
                 ('replace', 1,5, 1,5),
417
 
                 ('equal',   5,6, 5,6),
418
 
                ])
419
 
        chk_ops('aBcDec', 'abcdec', 
420
 
                [('equal',   0,1, 0,1),
421
 
                 ('replace', 1,2, 1,2),
422
 
                 ('equal',   2,3, 2,3),
423
 
                 ('replace', 3,4, 3,4),
424
 
                 ('equal',   4,6, 4,6),
425
 
                ])
426
 
        chk_ops('aBcdEcdFg', 'abcdecdfg', 
427
 
                [('equal',   0,1, 0,1),
428
 
                 ('replace', 1,8, 1,8),
429
 
                 ('equal',   8,9, 8,9)
430
 
                ])
431
 
        chk_ops('aBcdEeXcdFg', 'abcdecdfg', 
432
 
                [('equal',   0,1, 0,1),
433
 
                 ('replace', 1,2, 1,2),
434
 
                 ('equal',   2,4, 2,4),
435
 
                 ('delete', 4,5, 4,4),
436
 
                 ('equal',   5,6, 4,5),
437
 
                 ('delete', 6,7, 5,5),
438
 
                 ('equal',   7,9, 5,7),
439
 
                 ('replace', 9,10, 7,8),
440
 
                 ('equal',   10,11, 8,9)
441
 
                ])
442
 
 
443
 
    def test_multiple_ranges(self):
444
 
        # There was an earlier bug where we used a bad set of ranges,
445
 
        # this triggers that specific bug, to make sure it doesn't regress
446
 
        def chk_blocks(a, b, expected_blocks):
447
 
            # difflib always adds a signature of the total
448
 
            # length, with no matching entries at the end
449
 
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
450
 
            blocks = s.get_matching_blocks()
451
 
            x = blocks.pop()
452
 
            self.assertEquals(x, (len(a), len(b), 0))
453
 
            self.assertEquals(expected_blocks, blocks)
454
 
 
455
 
        chk_blocks('abcdefghijklmnop'
456
 
                 , 'abcXghiYZQRSTUVWXYZijklmnop'
457
 
                 , [(0, 0, 3), (6, 4, 3), (9, 20, 7)])
458
 
 
459
 
        chk_blocks('ABCd efghIjk  L'
460
 
                 , 'AxyzBCn mo pqrstuvwI1 2  L'
461
 
                 , [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
462
 
 
463
 
        # These are rot13 code snippets.
464
 
        chk_blocks('''\
465
 
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
466
 
    """
467
 
    gnxrf_netf = ['svyr*']
468
 
    gnxrf_bcgvbaf = ['ab-erphefr']
469
 
  
470
 
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
471
 
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
472
 
        vs vf_dhvrg():
473
 
            ercbegre = nqq_ercbegre_ahyy
474
 
        ryfr:
475
 
            ercbegre = nqq_ercbegre_cevag
476
 
        fzneg_nqq(svyr_yvfg, abg ab_erphefr, ercbegre)
477
 
 
478
 
 
479
 
pynff pzq_zxqve(Pbzznaq):
480
 
'''.splitlines(True), '''\
481
 
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
482
 
 
483
 
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl 
484
 
    nqq gurz.
485
 
    """
486
 
    gnxrf_netf = ['svyr*']
487
 
    gnxrf_bcgvbaf = ['ab-erphefr', 'qel-eha']
488
 
 
489
 
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr, qel_eha=Snyfr):
490
 
        vzcbeg omeyvo.nqq
491
 
 
492
 
        vs qel_eha:
493
 
            vs vf_dhvrg():
494
 
                # Guvf vf cbvagyrff, ohg V'q engure abg envfr na reebe
495
 
                npgvba = omeyvo.nqq.nqq_npgvba_ahyy
496
 
            ryfr:
497
 
  npgvba = omeyvo.nqq.nqq_npgvba_cevag
498
 
        ryvs vf_dhvrg():
499
 
            npgvba = omeyvo.nqq.nqq_npgvba_nqq
500
 
        ryfr:
501
 
       npgvba = omeyvo.nqq.nqq_npgvba_nqq_naq_cevag
502
 
 
503
 
        omeyvo.nqq.fzneg_nqq(svyr_yvfg, abg ab_erphefr, npgvba)
504
 
 
505
 
 
506
 
pynff pzq_zxqve(Pbzznaq):
507
 
'''.splitlines(True)
508
 
, [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
509
 
 
510
 
    def test_patience_unified_diff(self):
511
 
        txt_a = ['hello there\n',
512
 
                 'world\n',
513
 
                 'how are you today?\n']
514
 
        txt_b = ['hello there\n',
515
 
                 'how are you today?\n']
516
 
        unified_diff = bzrlib.patiencediff.unified_diff
517
 
        psm = bzrlib.patiencediff.PatienceSequenceMatcher
518
 
        self.assertEquals([ '---  \n',
519
 
                           '+++  \n',
520
 
                           '@@ -1,3 +1,2 @@\n',
521
 
                           ' hello there\n',
522
 
                           '-world\n',
523
 
                           ' how are you today?\n'
524
 
                          ]
525
 
                          , list(unified_diff(txt_a, txt_b,
526
 
                                 sequencematcher=psm)))
527
 
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
528
 
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
529
 
        # This is the result with LongestCommonSubstring matching
530
 
        self.assertEquals(['---  \n',
531
 
                           '+++  \n',
532
 
                           '@@ -1,6 +1,11 @@\n',
533
 
                           ' a\n',
534
 
                           ' b\n',
535
 
                           ' c\n',
536
 
                           '+d\n',
537
 
                           '+e\n',
538
 
                           '+f\n',
539
 
                           '+x\n',
540
 
                           '+y\n',
541
 
                           ' d\n',
542
 
                           ' e\n',
543
 
                           ' f\n']
544
 
                          , list(unified_diff(txt_a, txt_b)))
545
 
        # And the patience diff
546
 
        self.assertEquals(['---  \n',
547
 
                           '+++  \n',
548
 
                           '@@ -4,6 +4,11 @@\n',
549
 
                           ' d\n',
550
 
                           ' e\n',
551
 
                           ' f\n',
552
 
                           '+x\n',
553
 
                           '+y\n',
554
 
                           '+d\n',
555
 
                           '+e\n',
556
 
                           '+f\n',
557
 
                           ' g\n',
558
 
                           ' h\n',
559
 
                           ' i\n',
560
 
                          ]
561
 
                          , list(unified_diff(txt_a, txt_b,
562
 
                                 sequencematcher=psm)))
563
 
 
564
 
 
565
 
class TestPatienceDiffLibFiles(TestCaseInTempDir):
566
 
 
567
 
    def test_patience_unified_diff_files(self):
568
 
        txt_a = ['hello there\n',
569
 
                 'world\n',
570
 
                 'how are you today?\n']
571
 
        txt_b = ['hello there\n',
572
 
                 'how are you today?\n']
573
 
        open('a1', 'wb').writelines(txt_a)
574
 
        open('b1', 'wb').writelines(txt_b)
575
 
 
576
 
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
577
 
        psm = bzrlib.patiencediff.PatienceSequenceMatcher
578
 
        self.assertEquals(['--- a1 \n',
579
 
                           '+++ b1 \n',
580
 
                           '@@ -1,3 +1,2 @@\n',
581
 
                           ' hello there\n',
582
 
                           '-world\n',
583
 
                           ' how are you today?\n',
584
 
                          ]
585
 
                          , list(unified_diff_files('a1', 'b1',
586
 
                                 sequencematcher=psm)))
587
 
 
588
 
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
589
 
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
590
 
        open('a2', 'wb').writelines(txt_a)
591
 
        open('b2', 'wb').writelines(txt_b)
592
 
 
593
 
        # This is the result with LongestCommonSubstring matching
594
 
        self.assertEquals(['--- a2 \n',
595
 
                           '+++ b2 \n',
596
 
                           '@@ -1,6 +1,11 @@\n',
597
 
                           ' a\n',
598
 
                           ' b\n',
599
 
                           ' c\n',
600
 
                           '+d\n',
601
 
                           '+e\n',
602
 
                           '+f\n',
603
 
                           '+x\n',
604
 
                           '+y\n',
605
 
                           ' d\n',
606
 
                           ' e\n',
607
 
                           ' f\n']
608
 
                          , list(unified_diff_files('a2', 'b2')))
609
 
 
610
 
        # And the patience diff
611
 
        self.assertEquals(['--- a2 \n',
612
 
                           '+++ b2 \n',
613
 
                           '@@ -4,6 +4,11 @@\n',
614
 
                           ' d\n',
615
 
                           ' e\n',
616
 
                           ' f\n',
617
 
                           '+x\n',
618
 
                           '+y\n',
619
 
                           '+d\n',
620
 
                           '+e\n',
621
 
                           '+f\n',
622
 
                           ' g\n',
623
 
                           ' h\n',
624
 
                           ' i\n',
625
 
                          ]
626
 
                          , list(unified_diff_files('a2', 'b2',
627
 
                                 sequencematcher=psm)))
 
46
        check_patch(lines)
 
47
        assert lines[5] == '\\ No newline at end of file\n', \
 
48
            "expected no-nl, got %r" % lines[5]