~bzr-pqm/bzr/bzr.dev

1711.2.16 by John Arbash Meinel
test_diff needs a copyright statement
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
1740.2.5 by Aaron Bentley
Merge from bzr.dev
17
import os
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
18
from cStringIO import StringIO
1692.8.7 by James Henstridge
changes suggested by John Meinel
19
import errno
1692.8.5 by James Henstridge
merge from bzr.dev
20
from tempfile import TemporaryFile
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
21
1692.8.5 by James Henstridge
merge from bzr.dev
22
from bzrlib.diff import internal_diff, external_diff, show_diff_trees
1711.2.56 by John Arbash Meinel
Raise NoDiff if 'diff' not present.
23
from bzrlib.errors import BinaryFile, NoDiff
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
24
import bzrlib.patiencediff
1711.2.54 by John Arbash Meinel
Use mkstemp instead of NamedTemporary file for external diff.
25
from bzrlib.tests import (TestCase, TestCaseWithTransport,
26
                          TestCaseInTempDir, TestSkipped)
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
27
28
1558.15.11 by Aaron Bentley
Apply merge review suggestions
29
def udiff_lines(old, new, allow_binary=False):
974.1.6 by Aaron Bentley
Added unit tests
30
    output = StringIO()
1558.15.11 by Aaron Bentley
Apply merge review suggestions
31
    internal_diff('old', old, 'new', new, output, allow_binary)
974.1.6 by Aaron Bentley
Added unit tests
32
    output.seek(0, 0)
33
    return output.readlines()
34
1711.2.54 by John Arbash Meinel
Use mkstemp instead of NamedTemporary file for external diff.
35
1711.2.57 by John Arbash Meinel
Allow external diff to write to a file without a fileno.
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()
1692.8.7 by James Henstridge
changes suggested by John Meinel
42
    try:
43
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
1711.2.58 by John Arbash Meinel
Use osutils.pumpfile so we don't have to buffer everything in ram
44
    except NoDiff:
1711.2.56 by John Arbash Meinel
Raise NoDiff if 'diff' not present.
45
        raise TestSkipped('external "diff" not present to test')
1692.8.2 by James Henstridge
add a test for sending external diff output to a file
46
    output.seek(0, 0)
47
    lines = output.readlines()
48
    output.close()
49
    return lines
50
51
1102 by Martin Pool
- merge test refactoring from robertc
52
class TestDiff(TestCase):
1185.81.25 by Aaron Bentley
Clean up test_diff
53
1102 by Martin Pool
- merge test refactoring from robertc
54
    def test_add_nl(self):
55
        """diff generates a valid diff for patches that add a newline"""
974.1.6 by Aaron Bentley
Added unit tests
56
        lines = udiff_lines(['boo'], ['boo\n'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
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]
974.1.6 by Aaron Bentley
Added unit tests
60
1102 by Martin Pool
- merge test refactoring from robertc
61
    def test_add_nl_2(self):
62
        """diff generates a valid diff for patches that change last line and
63
        add a newline.
64
        """
974.1.6 by Aaron Bentley
Added unit tests
65
        lines = udiff_lines(['boo'], ['goo\n'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
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]
974.1.6 by Aaron Bentley
Added unit tests
69
1102 by Martin Pool
- merge test refactoring from robertc
70
    def test_remove_nl(self):
71
        """diff generates a valid diff for patches that change last line and
72
        add a newline.
73
        """
974.1.6 by Aaron Bentley
Added unit tests
74
        lines = udiff_lines(['boo\n'], ['boo'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
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
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
93
    def test_binary_lines(self):
94
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
95
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
1558.15.11 by Aaron Bentley
Apply merge review suggestions
96
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
97
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
1692.8.2 by James Henstridge
add a test for sending external diff output to a file
98
99
    def test_external_diff(self):
100
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
101
        self.check_patch(lines)
1711.2.57 by John Arbash Meinel
Allow external diff to write to a file without a fileno.
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)
1692.8.2 by James Henstridge
add a test for sending external diff output to a file
110
        
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
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)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
118
        self.assertEquals(['--- old_\xc2\xb5\n',
119
                           '+++ new_\xc3\xa5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
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)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
134
        self.assertEquals(['--- old_\xc2\xb5\n',
135
                           '+++ new_\xc3\xa5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
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)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
150
        self.assertEquals(['--- old_\xb5\n',
151
                           '+++ new_\xe5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
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
1185.81.25 by Aaron Bentley
Clean up test_diff
167
1740.2.5 by Aaron Bentley
Merge from bzr.dev
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
1551.7.22 by Aaron Bentley
Changes from review
208
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
1740.2.5 by Aaron Bentley
Merge from bzr.dev
209
        output = StringIO()
1551.7.22 by Aaron Bentley
Changes from review
210
        if working_tree is not None:
211
            extra_trees = (working_tree,)
212
        else:
213
            extra_trees = ()
214
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
215
                        extra_trees=extra_trees, old_label='old/', 
216
                        new_label='new/')
1740.2.5 by Aaron Bentley
Merge from bzr.dev
217
        return output.getvalue()
218
219
    def test_diff_rev_tree_working_tree(self):
220
        output = self.get_diff(self.wt.basis_tree(), self.wt)
221
        # note that the date for old/file1 is from rev 2 rather than from
222
        # the basis revision (rev 4)
223
        self.assertEqualDiff(output, '''\
224
=== modified file 'file1'
225
--- old/file1\t2006-04-02 00:00:00 +0000
226
+++ new/file1\t2006-04-05 00:00:00 +0000
227
@@ -1,1 +1,1 @@
228
-file1 contents at rev 2
229
+file1 contents in working tree
230
231
''')
232
233
    def test_diff_rev_tree_rev_tree(self):
234
        tree1 = self.b.repository.revision_tree('rev-2')
235
        tree2 = self.b.repository.revision_tree('rev-3')
236
        output = self.get_diff(tree1, tree2)
237
        self.assertEqualDiff(output, '''\
238
=== modified file 'file2'
239
--- old/file2\t2006-04-01 00:00:00 +0000
240
+++ new/file2\t2006-04-03 00:00:00 +0000
241
@@ -1,1 +1,1 @@
242
-file2 contents at rev 1
243
+file2 contents at rev 3
244
245
''')
246
        
247
    def test_diff_add_files(self):
248
        tree1 = self.b.repository.revision_tree(None)
249
        tree2 = self.b.repository.revision_tree('rev-1')
250
        output = self.get_diff(tree1, tree2)
251
        # the files have the epoch time stamp for the tree in which
252
        # they don't exist.
253
        self.assertEqualDiff(output, '''\
254
=== added file 'file1'
255
--- old/file1\t1970-01-01 00:00:00 +0000
256
+++ new/file1\t2006-04-01 00:00:00 +0000
257
@@ -0,0 +1,1 @@
258
+file1 contents at rev 1
259
260
=== added file 'file2'
261
--- old/file2\t1970-01-01 00:00:00 +0000
262
+++ new/file2\t2006-04-01 00:00:00 +0000
263
@@ -0,0 +1,1 @@
264
+file2 contents at rev 1
265
266
''')
267
268
    def test_diff_remove_files(self):
269
        tree1 = self.b.repository.revision_tree('rev-3')
270
        tree2 = self.b.repository.revision_tree('rev-4')
271
        output = self.get_diff(tree1, tree2)
272
        # the file has the epoch time stamp for the tree in which
273
        # it doesn't exist.
274
        self.assertEqualDiff(output, '''\
275
=== removed file 'file2'
276
--- old/file2\t2006-04-03 00:00:00 +0000
277
+++ new/file2\t1970-01-01 00:00:00 +0000
278
@@ -1,1 +0,0 @@
279
-file2 contents at rev 3
280
281
''')
282
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
283
    def test_show_diff_specified(self):
1551.7.22 by Aaron Bentley
Changes from review
284
        """A working tree filename can be used to identify a file"""
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
285
        self.wt.rename_one('file1', 'file1b')
286
        old_tree = self.b.repository.revision_tree('rev-1')
287
        new_tree = self.b.repository.revision_tree('rev-4')
1551.7.22 by Aaron Bentley
Changes from review
288
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'], 
289
                            working_tree=self.wt)
290
        self.assertContainsRe(out, 'file1\t')
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
291
1551.7.22 by Aaron Bentley
Changes from review
292
    def test_recursive_diff(self):
293
        """Children of directories are matched"""
294
        os.mkdir('dir1')
295
        os.mkdir('dir2')
296
        self.wt.add(['dir1', 'dir2'])
297
        self.wt.rename_one('file1', 'dir1/file1')
298
        old_tree = self.b.repository.revision_tree('rev-1')
299
        new_tree = self.b.repository.revision_tree('rev-4')
300
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'], 
301
                            working_tree=self.wt)
302
        self.assertContainsRe(out, 'file1\t')
303
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'], 
304
                            working_tree=self.wt)
305
        self.assertNotContainsRe(out, 'file1\t')
1740.2.5 by Aaron Bentley
Merge from bzr.dev
306
1711.2.15 by John Arbash Meinel
Found a couple CDV left
307
class TestPatienceDiffLib(TestCase):
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
308
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
309
    def test_unique_lcs(self):
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
310
        unique_lcs = bzrlib.patiencediff.unique_lcs
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
311
        self.assertEquals(unique_lcs('', ''), [])
312
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
313
        self.assertEquals(unique_lcs('a', 'b'), [])
314
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
315
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
316
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
317
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1), 
318
                                                         (3,3), (4,4)])
319
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
320
321
    def test_recurse_matches(self):
322
        def test_one(a, b, matches):
323
            test_matches = []
1711.2.22 by John Arbash Meinel
Passing the alo parameter to recurse_matches shaves of 5% of the diff time.
324
            bzrlib.patiencediff.recurse_matches(a, b, 0, 0, len(a), len(b),
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
325
                test_matches, 10)
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
326
            self.assertEquals(test_matches, matches)
327
1711.2.17 by John Arbash Meinel
Small cleanups to patience_diff code.
328
        test_one(['a', '', 'b', '', 'c'], ['a', 'a', 'b', 'c', 'c'],
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
329
                 [(0, 0), (2, 2), (4, 4)])
330
        test_one(['a', 'c', 'b', 'a', 'c'], ['a', 'b', 'c'],
331
                 [(0, 0), (2, 1), (4, 2)])
332
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
333
        # recurse_matches doesn't match non-unique 
334
        # lines surrounded by bogus text.
1185.81.24 by Aaron Bentley
Reoganize patience-related code
335
        # The update has been done in patiencediff.SequenceMatcher instead
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
336
337
        # This is what it could be
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
338
        #test_one('aBccDe', 'abccde', [(0,0), (2,2), (3,3), (5,5)])
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
339
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
340
        # This is what it currently gives:
341
        test_one('aBccDe', 'abccde', [(0,0), (5,5)])
342
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
343
    def test_matching_blocks(self):
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
344
        def chk_blocks(a, b, expected_blocks):
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
345
            # difflib always adds a signature of the total
346
            # length, with no matching entries at the end
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
347
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
1185.81.11 by John Arbash Meinel
Found some edge cases that weren't being matched.
348
            blocks = s.get_matching_blocks()
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
349
            self.assertEquals((len(a), len(b), 0), blocks[-1])
350
            self.assertEquals(expected_blocks, blocks[:-1])
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
351
1185.81.2 by John Arbash Meinel
A couple small tests.
352
        # Some basic matching tests
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
353
        chk_blocks('', '', [])
354
        chk_blocks([], [], [])
355
        chk_blocks('abcd', 'abcd', [(0, 0, 4)])
356
        chk_blocks('abcd', 'abce', [(0, 0, 3)])
357
        chk_blocks('eabc', 'abce', [(1, 0, 3)])
358
        chk_blocks('eabce', 'abce', [(1, 0, 4)])
359
        chk_blocks('abcde', 'abXde', [(0, 0, 2), (3, 3, 2)])
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
360
        chk_blocks('abcde', 'abXYZde', [(0, 0, 2), (3, 5, 2)])
361
        chk_blocks('abde', 'abXYZde', [(0, 0, 2), (2, 5, 2)])
362
        # This may check too much, but it checks to see that 
363
        # a copied block stays attached to the previous section,
364
        # not the later one.
365
        # difflib would tend to grab the trailing longest match
366
        # which would make the diff not look right
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
367
        chk_blocks('abcdefghijklmnop', 'abcdefxydefghijklmnop',
368
                   [(0, 0, 6), (6, 11, 10)])
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
369
1185.81.2 by John Arbash Meinel
A couple small tests.
370
        # make sure it supports passing in lists
371
        chk_blocks(
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
372
                   ['hello there\n',
373
                    'world\n',
374
                    'how are you today?\n'],
375
                   ['hello there\n',
376
                    'how are you today?\n'],
1185.81.2 by John Arbash Meinel
A couple small tests.
377
                [(0, 0, 1), (2, 1, 1)])
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
378
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
379
        # non unique lines surrounded by non-matching lines
380
        # won't be found
381
        chk_blocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
382
383
        # But they only need to be locally unique
384
        chk_blocks('aBcDec', 'abcdec', [(0,0,1), (2,2,1), (4,4,2)])
385
386
        # non unique blocks won't be matched
387
        chk_blocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (8,8,1)])
388
389
        # but locally unique ones will
390
        chk_blocks('aBcdEeXcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
391
                                              (5,4,1), (7,5,2), (10,8,1)])
392
393
        chk_blocks('abbabbXd', 'cabbabxd', [(7,7,1)])
394
        chk_blocks('abbabbbb', 'cabbabbc', [])
395
        chk_blocks('bbbbbbbb', 'cbbbbbbc', [])
1185.81.11 by John Arbash Meinel
Found some edge cases that weren't being matched.
396
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
397
    def test_opcodes(self):
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
398
        def chk_ops(a, b, expected_codes):
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
399
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
400
            self.assertEquals(expected_codes, s.get_opcodes())
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
401
402
        chk_ops('', '', [])
403
        chk_ops([], [], [])
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
404
        chk_ops('abcd', 'abcd', [('equal',    0,4, 0,4)])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
405
        chk_ops('abcd', 'abce', [('equal',   0,3, 0,3),
406
                                 ('replace', 3,4, 3,4)
407
                                ])
408
        chk_ops('eabc', 'abce', [('delete', 0,1, 0,0),
409
                                 ('equal',  1,4, 0,3),
410
                                 ('insert', 4,4, 3,4)
411
                                ])
412
        chk_ops('eabce', 'abce', [('delete', 0,1, 0,0),
413
                                  ('equal',  1,5, 0,4)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
414
                                 ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
415
        chk_ops('abcde', 'abXde', [('equal',   0,2, 0,2),
416
                                   ('replace', 2,3, 2,3),
417
                                   ('equal',   3,5, 3,5)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
418
                                  ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
419
        chk_ops('abcde', 'abXYZde', [('equal',   0,2, 0,2),
420
                                     ('replace', 2,3, 2,5),
421
                                     ('equal',   3,5, 5,7)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
422
                                    ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
423
        chk_ops('abde', 'abXYZde', [('equal',  0,2, 0,2),
424
                                    ('insert', 2,2, 2,5),
425
                                    ('equal',  2,4, 5,7)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
426
                                   ])
427
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
428
                [('equal',  0,6,  0,6),
429
                 ('insert', 6,6,  6,11),
430
                 ('equal',  6,16, 11,21)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
431
                ])
432
        chk_ops(
433
                [ 'hello there\n'
434
                , 'world\n'
435
                , 'how are you today?\n'],
436
                [ 'hello there\n'
437
                , 'how are you today?\n'],
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
438
                [('equal',  0,1, 0,1),
439
                 ('delete', 1,2, 1,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
440
                 ('equal',  2,3, 1,2),
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
441
                ])
442
        chk_ops('aBccDe', 'abccde', 
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
443
                [('equal',   0,1, 0,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
444
                 ('replace', 1,5, 1,5),
445
                 ('equal',   5,6, 5,6),
446
                ])
447
        chk_ops('aBcDec', 'abcdec', 
448
                [('equal',   0,1, 0,1),
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
449
                 ('replace', 1,2, 1,2),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
450
                 ('equal',   2,3, 2,3),
451
                 ('replace', 3,4, 3,4),
452
                 ('equal',   4,6, 4,6),
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
453
                ])
1185.81.10 by John Arbash Meinel
Added some more test cases.
454
        chk_ops('aBcdEcdFg', 'abcdecdfg', 
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
455
                [('equal',   0,1, 0,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
456
                 ('replace', 1,8, 1,8),
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
457
                 ('equal',   8,9, 8,9)
1185.81.10 by John Arbash Meinel
Added some more test cases.
458
                ])
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
459
        chk_ops('aBcdEeXcdFg', 'abcdecdfg', 
460
                [('equal',   0,1, 0,1),
461
                 ('replace', 1,2, 1,2),
462
                 ('equal',   2,4, 2,4),
463
                 ('delete', 4,5, 4,4),
464
                 ('equal',   5,6, 4,5),
465
                 ('delete', 6,7, 5,5),
466
                 ('equal',   7,9, 5,7),
467
                 ('replace', 9,10, 7,8),
468
                 ('equal',   10,11, 8,9)
469
                ])
1185.81.10 by John Arbash Meinel
Added some more test cases.
470
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
471
    def test_multiple_ranges(self):
472
        # There was an earlier bug where we used a bad set of ranges,
473
        # this triggers that specific bug, to make sure it doesn't regress
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
474
        def chk_blocks(a, b, expected_blocks):
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
475
            # difflib always adds a signature of the total
476
            # length, with no matching entries at the end
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
477
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
478
            blocks = s.get_matching_blocks()
479
            x = blocks.pop()
480
            self.assertEquals(x, (len(a), len(b), 0))
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
481
            self.assertEquals(expected_blocks, blocks)
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
482
483
        chk_blocks('abcdefghijklmnop'
484
                 , 'abcXghiYZQRSTUVWXYZijklmnop'
485
                 , [(0, 0, 3), (6, 4, 3), (9, 20, 7)])
486
487
        chk_blocks('ABCd efghIjk  L'
488
                 , 'AxyzBCn mo pqrstuvwI1 2  L'
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
489
                 , [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
490
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
491
        # These are rot13 code snippets.
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
492
        chk_blocks('''\
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
493
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
494
    """
495
    gnxrf_netf = ['svyr*']
496
    gnxrf_bcgvbaf = ['ab-erphefr']
497
  
498
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
499
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
500
        vs vf_dhvrg():
501
            ercbegre = nqq_ercbegre_ahyy
502
        ryfr:
503
            ercbegre = nqq_ercbegre_cevag
504
        fzneg_nqq(svyr_yvfg, abg ab_erphefr, ercbegre)
505
506
507
pynff pzq_zxqve(Pbzznaq):
508
'''.splitlines(True), '''\
509
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
510
511
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl 
512
    nqq gurz.
513
    """
514
    gnxrf_netf = ['svyr*']
515
    gnxrf_bcgvbaf = ['ab-erphefr', 'qel-eha']
516
517
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr, qel_eha=Snyfr):
518
        vzcbeg omeyvo.nqq
519
520
        vs qel_eha:
521
            vs vf_dhvrg():
522
                # Guvf vf cbvagyrff, ohg V'q engure abg envfr na reebe
523
                npgvba = omeyvo.nqq.nqq_npgvba_ahyy
524
            ryfr:
525
  npgvba = omeyvo.nqq.nqq_npgvba_cevag
526
        ryvs vf_dhvrg():
527
            npgvba = omeyvo.nqq.nqq_npgvba_nqq
528
        ryfr:
529
       npgvba = omeyvo.nqq.nqq_npgvba_nqq_naq_cevag
530
531
        omeyvo.nqq.fzneg_nqq(svyr_yvfg, abg ab_erphefr, npgvba)
532
533
534
pynff pzq_zxqve(Pbzznaq):
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
535
'''.splitlines(True)
536
, [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
537
1711.2.9 by John Arbash Meinel
Rename cdv => patience
538
    def test_patience_unified_diff(self):
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
539
        txt_a = ['hello there\n',
540
                 'world\n',
541
                 'how are you today?\n']
542
        txt_b = ['hello there\n',
543
                 'how are you today?\n']
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
544
        unified_diff = bzrlib.patiencediff.unified_diff
545
        psm = bzrlib.patiencediff.PatienceSequenceMatcher
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
546
        self.assertEquals([ '---  \n',
547
                           '+++  \n',
548
                           '@@ -1,3 +1,2 @@\n',
549
                           ' hello there\n',
550
                           '-world\n',
551
                           ' how are you today?\n'
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
552
                          ]
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
553
                          , list(unified_diff(txt_a, txt_b,
554
                                 sequencematcher=psm)))
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
555
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
556
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
557
        # This is the result with LongestCommonSubstring matching
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
558
        self.assertEquals(['---  \n',
559
                           '+++  \n',
560
                           '@@ -1,6 +1,11 @@\n',
561
                           ' a\n',
562
                           ' b\n',
563
                           ' c\n',
564
                           '+d\n',
565
                           '+e\n',
566
                           '+f\n',
567
                           '+x\n',
568
                           '+y\n',
569
                           ' d\n',
570
                           ' e\n',
571
                           ' f\n']
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
572
                          , list(unified_diff(txt_a, txt_b)))
1711.2.9 by John Arbash Meinel
Rename cdv => patience
573
        # And the patience diff
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
574
        self.assertEquals(['---  \n',
575
                           '+++  \n',
576
                           '@@ -4,6 +4,11 @@\n',
577
                           ' d\n',
578
                           ' e\n',
579
                           ' f\n',
580
                           '+x\n',
581
                           '+y\n',
582
                           '+d\n',
583
                           '+e\n',
584
                           '+f\n',
585
                           ' g\n',
586
                           ' h\n',
587
                           ' i\n',
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
588
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
589
                          , list(unified_diff(txt_a, txt_b,
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
590
                                 sequencematcher=psm)))
1185.81.25 by Aaron Bentley
Clean up test_diff
591
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
592
1711.2.15 by John Arbash Meinel
Found a couple CDV left
593
class TestPatienceDiffLibFiles(TestCaseInTempDir):
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
594
1711.2.9 by John Arbash Meinel
Rename cdv => patience
595
    def test_patience_unified_diff_files(self):
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
596
        txt_a = ['hello there\n',
597
                 'world\n',
598
                 'how are you today?\n']
599
        txt_b = ['hello there\n',
600
                 'how are you today?\n']
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
601
        open('a1', 'wb').writelines(txt_a)
602
        open('b1', 'wb').writelines(txt_b)
603
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
604
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
605
        psm = bzrlib.patiencediff.PatienceSequenceMatcher
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
606
        self.assertEquals(['--- a1 \n',
607
                           '+++ b1 \n',
608
                           '@@ -1,3 +1,2 @@\n',
609
                           ' hello there\n',
610
                           '-world\n',
611
                           ' how are you today?\n',
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
612
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
613
                          , list(unified_diff_files('a1', 'b1',
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
614
                                 sequencematcher=psm)))
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
615
616
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
617
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
618
        open('a2', 'wb').writelines(txt_a)
619
        open('b2', 'wb').writelines(txt_b)
620
621
        # This is the result with LongestCommonSubstring matching
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
622
        self.assertEquals(['--- a2 \n',
623
                           '+++ b2 \n',
624
                           '@@ -1,6 +1,11 @@\n',
625
                           ' a\n',
626
                           ' b\n',
627
                           ' c\n',
628
                           '+d\n',
629
                           '+e\n',
630
                           '+f\n',
631
                           '+x\n',
632
                           '+y\n',
633
                           ' d\n',
634
                           ' e\n',
635
                           ' f\n']
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
636
                          , list(unified_diff_files('a2', 'b2')))
637
1711.2.9 by John Arbash Meinel
Rename cdv => patience
638
        # And the patience diff
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
639
        self.assertEquals(['--- a2 \n',
640
                           '+++ b2 \n',
641
                           '@@ -4,6 +4,11 @@\n',
642
                           ' d\n',
643
                           ' e\n',
644
                           ' f\n',
645
                           '+x\n',
646
                           '+y\n',
647
                           '+d\n',
648
                           '+e\n',
649
                           '+f\n',
650
                           ' g\n',
651
                           ' h\n',
652
                           ' i\n',
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
653
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
654
                          , list(unified_diff_files('a2', 'b2',
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
655
                                 sequencematcher=psm)))