/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
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
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
20
import subprocess
21
from tempfile import TemporaryFile, mkdtemp
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
22
1692.8.5 by James Henstridge
merge from bzr.dev
23
from bzrlib.diff import internal_diff, external_diff, show_diff_trees
1711.2.56 by John Arbash Meinel
Raise NoDiff if 'diff' not present.
24
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
25
import bzrlib.patiencediff
1711.2.54 by John Arbash Meinel
Use mkstemp instead of NamedTemporary file for external diff.
26
from bzrlib.tests import (TestCase, TestCaseWithTransport,
27
                          TestCaseInTempDir, TestSkipped)
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
28
29
1558.15.11 by Aaron Bentley
Apply merge review suggestions
30
def udiff_lines(old, new, allow_binary=False):
974.1.6 by Aaron Bentley
Added unit tests
31
    output = StringIO()
1558.15.11 by Aaron Bentley
Apply merge review suggestions
32
    internal_diff('old', old, 'new', new, output, allow_binary)
974.1.6 by Aaron Bentley
Added unit tests
33
    output.seek(0, 0)
34
    return output.readlines()
35
1711.2.54 by John Arbash Meinel
Use mkstemp instead of NamedTemporary file for external diff.
36
1711.2.57 by John Arbash Meinel
Allow external diff to write to a file without a fileno.
37
def external_udiff_lines(old, new, use_stringio=False):
38
    if use_stringio:
39
        # StringIO has no fileno, so it tests a different codepath
40
        output = StringIO()
41
    else:
42
        output = TemporaryFile()
1692.8.7 by James Henstridge
changes suggested by John Meinel
43
    try:
44
        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
45
    except NoDiff:
1711.2.56 by John Arbash Meinel
Raise NoDiff if 'diff' not present.
46
        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
47
    output.seek(0, 0)
48
    lines = output.readlines()
49
    output.close()
50
    return lines
51
52
1102 by Martin Pool
- merge test refactoring from robertc
53
class TestDiff(TestCase):
1185.81.25 by Aaron Bentley
Clean up test_diff
54
1102 by Martin Pool
- merge test refactoring from robertc
55
    def test_add_nl(self):
56
        """diff generates a valid diff for patches that add a newline"""
974.1.6 by Aaron Bentley
Added unit tests
57
        lines = udiff_lines(['boo'], ['boo\n'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
58
        self.check_patch(lines)
59
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
60
            ## "expected no-nl, got %r" % lines[4]
974.1.6 by Aaron Bentley
Added unit tests
61
1102 by Martin Pool
- merge test refactoring from robertc
62
    def test_add_nl_2(self):
63
        """diff generates a valid diff for patches that change last line and
64
        add a newline.
65
        """
974.1.6 by Aaron Bentley
Added unit tests
66
        lines = udiff_lines(['boo'], ['goo\n'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
67
        self.check_patch(lines)
68
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
69
            ## "expected no-nl, got %r" % lines[4]
974.1.6 by Aaron Bentley
Added unit tests
70
1102 by Martin Pool
- merge test refactoring from robertc
71
    def test_remove_nl(self):
72
        """diff generates a valid diff for patches that change last line and
73
        add a newline.
74
        """
974.1.6 by Aaron Bentley
Added unit tests
75
        lines = udiff_lines(['boo\n'], ['boo'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
76
        self.check_patch(lines)
77
        self.assertEquals(lines[5], '\\ No newline at end of file\n')
78
            ## "expected no-nl, got %r" % lines[5]
79
80
    def check_patch(self, lines):
81
        self.assert_(len(lines) > 1)
82
            ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
83
        self.assert_(lines[0].startswith ('---'))
84
            ## 'No orig line for patch:\n%s' % "".join(lines)
85
        self.assert_(lines[1].startswith ('+++'))
86
            ## 'No mod line for patch:\n%s' % "".join(lines)
87
        self.assert_(len(lines) > 2)
88
            ## "No hunks for patch:\n%s" % "".join(lines)
89
        self.assert_(lines[2].startswith('@@'))
90
            ## "No hunk header for patch:\n%s" % "".join(lines)
91
        self.assert_('@@' in lines[2][2:])
92
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
93
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
94
    def test_binary_lines(self):
95
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
96
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
1558.15.11 by Aaron Bentley
Apply merge review suggestions
97
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
98
        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
99
100
    def test_external_diff(self):
101
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
102
        self.check_patch(lines)
1899.1.6 by John Arbash Meinel
internal_diff always adds a trailing \n, make sure external_diff does too
103
        self.assertEqual('\n', lines[-1])
1711.2.57 by John Arbash Meinel
Allow external diff to write to a file without a fileno.
104
105
    def test_external_diff_no_fileno(self):
106
        # Make sure that we can handle not having a fileno, even
107
        # if the diff is large
108
        lines = external_udiff_lines(['boo\n']*10000,
109
                                     ['goo\n']*10000,
110
                                     use_stringio=True)
111
        self.check_patch(lines)
1899.1.1 by John Arbash Meinel
Fix the bug in the NoDiff exception class, and add a test
112
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
113
    def test_external_diff_binary_lang_c(self):
114
        orig_lang = os.environ.get('LANG')
115
        try:
116
            os.environ['LANG'] = 'C'
117
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
118
            self.assertEqual(['Binary files old and new differ\n', '\n'], lines)
119
        finally:
120
            if orig_lang is None:
121
                del os.environ['LANG']
122
            else:
123
                os.environ['LANG'] = orig_lang
1899.1.4 by John Arbash Meinel
Just swallow a return code of 2
124
1899.1.1 by John Arbash Meinel
Fix the bug in the NoDiff exception class, and add a test
125
    def test_no_external_diff(self):
126
        """Check that NoDiff is raised when diff is not available"""
127
        # Use os.environ['PATH'] to make sure no 'diff' command is available
128
        orig_path = os.environ['PATH']
129
        try:
130
            os.environ['PATH'] = ''
131
            self.assertRaises(NoDiff, external_diff,
132
                              'old', ['boo\n'], 'new', ['goo\n'],
133
                              StringIO(), diff_opts=['-u'])
134
        finally:
135
            os.environ['PATH'] = orig_path
1692.8.2 by James Henstridge
add a test for sending external diff output to a file
136
        
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
137
    def test_internal_diff_default(self):
138
        # Default internal diff encoding is utf8
139
        output = StringIO()
140
        internal_diff(u'old_\xb5', ['old_text\n'],
141
                    u'new_\xe5', ['new_text\n'], output)
142
        lines = output.getvalue().splitlines(True)
143
        self.check_patch(lines)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
144
        self.assertEquals(['--- old_\xc2\xb5\n',
145
                           '+++ new_\xc3\xa5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
146
                           '@@ -1,1 +1,1 @@\n',
147
                           '-old_text\n',
148
                           '+new_text\n',
149
                           '\n',
150
                          ]
151
                          , lines)
152
153
    def test_internal_diff_utf8(self):
154
        output = StringIO()
155
        internal_diff(u'old_\xb5', ['old_text\n'],
156
                    u'new_\xe5', ['new_text\n'], output,
157
                    path_encoding='utf8')
158
        lines = output.getvalue().splitlines(True)
159
        self.check_patch(lines)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
160
        self.assertEquals(['--- old_\xc2\xb5\n',
161
                           '+++ new_\xc3\xa5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
162
                           '@@ -1,1 +1,1 @@\n',
163
                           '-old_text\n',
164
                           '+new_text\n',
165
                           '\n',
166
                          ]
167
                          , lines)
168
169
    def test_internal_diff_iso_8859_1(self):
170
        output = StringIO()
171
        internal_diff(u'old_\xb5', ['old_text\n'],
172
                    u'new_\xe5', ['new_text\n'], output,
173
                    path_encoding='iso-8859-1')
174
        lines = output.getvalue().splitlines(True)
175
        self.check_patch(lines)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
176
        self.assertEquals(['--- old_\xb5\n',
177
                           '+++ new_\xe5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
178
                           '@@ -1,1 +1,1 @@\n',
179
                           '-old_text\n',
180
                           '+new_text\n',
181
                           '\n',
182
                          ]
183
                          , lines)
184
185
    def test_internal_diff_returns_bytes(self):
186
        import StringIO
187
        output = StringIO.StringIO()
188
        internal_diff(u'old_\xb5', ['old_text\n'],
189
                    u'new_\xe5', ['new_text\n'], output)
190
        self.failUnless(isinstance(output.getvalue(), str),
191
            'internal_diff should return bytestrings')
192
1185.81.25 by Aaron Bentley
Clean up test_diff
193
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
194
class TestDiffFiles(TestCaseInTempDir):
195
196
    def test_external_diff_binary(self):
197
        """The output when using external diff should use diff's i18n error"""
198
        # Make sure external_diff doesn't fail in the current LANG
199
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
200
201
        cmd = ['diff', '-u', 'old', 'new']
202
        open('old', 'wb').write('\x00foobar\n')
203
        open('new', 'wb').write('foo\x00bar\n')
204
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
205
                                     stdin=subprocess.PIPE)
206
        out, err = pipe.communicate()
207
        # Diff returns '2' on Binary files.
208
        self.assertEqual(2, pipe.returncode)
209
        # We should output whatever diff tells us, plus a trailing newline
210
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
211
212
1740.2.5 by Aaron Bentley
Merge from bzr.dev
213
class TestDiffDates(TestCaseWithTransport):
214
215
    def setUp(self):
216
        super(TestDiffDates, self).setUp()
217
        self.wt = self.make_branch_and_tree('.')
218
        self.b = self.wt.branch
219
        self.build_tree_contents([
220
            ('file1', 'file1 contents at rev 1\n'),
221
            ('file2', 'file2 contents at rev 1\n')
222
            ])
223
        self.wt.add(['file1', 'file2'])
224
        self.wt.commit(
225
            message='Revision 1',
226
            timestamp=1143849600, # 2006-04-01 00:00:00 UTC
227
            timezone=0,
228
            rev_id='rev-1')
229
        self.build_tree_contents([('file1', 'file1 contents at rev 2\n')])
230
        self.wt.commit(
231
            message='Revision 2',
232
            timestamp=1143936000, # 2006-04-02 00:00:00 UTC
233
            timezone=28800,
234
            rev_id='rev-2')
235
        self.build_tree_contents([('file2', 'file2 contents at rev 3\n')])
236
        self.wt.commit(
237
            message='Revision 3',
238
            timestamp=1144022400, # 2006-04-03 00:00:00 UTC
239
            timezone=-3600,
240
            rev_id='rev-3')
241
        self.wt.remove(['file2'])
242
        self.wt.commit(
243
            message='Revision 4',
244
            timestamp=1144108800, # 2006-04-04 00:00:00 UTC
245
            timezone=0,
246
            rev_id='rev-4')
247
        self.build_tree_contents([
248
            ('file1', 'file1 contents in working tree\n')
249
            ])
250
        # set the date stamps for files in the working tree to known values
251
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
252
1551.7.22 by Aaron Bentley
Changes from review
253
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
1740.2.5 by Aaron Bentley
Merge from bzr.dev
254
        output = StringIO()
1551.7.22 by Aaron Bentley
Changes from review
255
        if working_tree is not None:
256
            extra_trees = (working_tree,)
257
        else:
258
            extra_trees = ()
259
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
260
                        extra_trees=extra_trees, old_label='old/', 
261
                        new_label='new/')
1740.2.5 by Aaron Bentley
Merge from bzr.dev
262
        return output.getvalue()
263
264
    def test_diff_rev_tree_working_tree(self):
265
        output = self.get_diff(self.wt.basis_tree(), self.wt)
266
        # note that the date for old/file1 is from rev 2 rather than from
267
        # the basis revision (rev 4)
268
        self.assertEqualDiff(output, '''\
269
=== modified file 'file1'
270
--- old/file1\t2006-04-02 00:00:00 +0000
271
+++ new/file1\t2006-04-05 00:00:00 +0000
272
@@ -1,1 +1,1 @@
273
-file1 contents at rev 2
274
+file1 contents in working tree
275
276
''')
277
278
    def test_diff_rev_tree_rev_tree(self):
279
        tree1 = self.b.repository.revision_tree('rev-2')
280
        tree2 = self.b.repository.revision_tree('rev-3')
281
        output = self.get_diff(tree1, tree2)
282
        self.assertEqualDiff(output, '''\
283
=== modified file 'file2'
284
--- old/file2\t2006-04-01 00:00:00 +0000
285
+++ new/file2\t2006-04-03 00:00:00 +0000
286
@@ -1,1 +1,1 @@
287
-file2 contents at rev 1
288
+file2 contents at rev 3
289
290
''')
291
        
292
    def test_diff_add_files(self):
293
        tree1 = self.b.repository.revision_tree(None)
294
        tree2 = self.b.repository.revision_tree('rev-1')
295
        output = self.get_diff(tree1, tree2)
296
        # the files have the epoch time stamp for the tree in which
297
        # they don't exist.
298
        self.assertEqualDiff(output, '''\
299
=== added file 'file1'
300
--- old/file1\t1970-01-01 00:00:00 +0000
301
+++ new/file1\t2006-04-01 00:00:00 +0000
302
@@ -0,0 +1,1 @@
303
+file1 contents at rev 1
304
305
=== added file 'file2'
306
--- old/file2\t1970-01-01 00:00:00 +0000
307
+++ new/file2\t2006-04-01 00:00:00 +0000
308
@@ -0,0 +1,1 @@
309
+file2 contents at rev 1
310
311
''')
312
313
    def test_diff_remove_files(self):
314
        tree1 = self.b.repository.revision_tree('rev-3')
315
        tree2 = self.b.repository.revision_tree('rev-4')
316
        output = self.get_diff(tree1, tree2)
317
        # the file has the epoch time stamp for the tree in which
318
        # it doesn't exist.
319
        self.assertEqualDiff(output, '''\
320
=== removed file 'file2'
321
--- old/file2\t2006-04-03 00:00:00 +0000
322
+++ new/file2\t1970-01-01 00:00:00 +0000
323
@@ -1,1 +0,0 @@
324
-file2 contents at rev 3
325
326
''')
327
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
328
    def test_show_diff_specified(self):
1551.7.22 by Aaron Bentley
Changes from review
329
        """A working tree filename can be used to identify a file"""
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
330
        self.wt.rename_one('file1', 'file1b')
331
        old_tree = self.b.repository.revision_tree('rev-1')
332
        new_tree = self.b.repository.revision_tree('rev-4')
1551.7.22 by Aaron Bentley
Changes from review
333
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'], 
334
                            working_tree=self.wt)
335
        self.assertContainsRe(out, 'file1\t')
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
336
1551.7.22 by Aaron Bentley
Changes from review
337
    def test_recursive_diff(self):
338
        """Children of directories are matched"""
339
        os.mkdir('dir1')
340
        os.mkdir('dir2')
341
        self.wt.add(['dir1', 'dir2'])
342
        self.wt.rename_one('file1', 'dir1/file1')
343
        old_tree = self.b.repository.revision_tree('rev-1')
344
        new_tree = self.b.repository.revision_tree('rev-4')
345
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'], 
346
                            working_tree=self.wt)
347
        self.assertContainsRe(out, 'file1\t')
348
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'], 
349
                            working_tree=self.wt)
350
        self.assertNotContainsRe(out, 'file1\t')
1740.2.5 by Aaron Bentley
Merge from bzr.dev
351
1899.1.1 by John Arbash Meinel
Fix the bug in the NoDiff exception class, and add a test
352
1711.2.15 by John Arbash Meinel
Found a couple CDV left
353
class TestPatienceDiffLib(TestCase):
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
354
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
355
    def test_unique_lcs(self):
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
356
        unique_lcs = bzrlib.patiencediff.unique_lcs
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
357
        self.assertEquals(unique_lcs('', ''), [])
358
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
359
        self.assertEquals(unique_lcs('a', 'b'), [])
360
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
361
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
362
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
363
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1), 
364
                                                         (3,3), (4,4)])
365
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
366
367
    def test_recurse_matches(self):
368
        def test_one(a, b, matches):
369
            test_matches = []
1711.2.22 by John Arbash Meinel
Passing the alo parameter to recurse_matches shaves of 5% of the diff time.
370
            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
371
                test_matches, 10)
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
372
            self.assertEquals(test_matches, matches)
373
1711.2.17 by John Arbash Meinel
Small cleanups to patience_diff code.
374
        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,
375
                 [(0, 0), (2, 2), (4, 4)])
376
        test_one(['a', 'c', 'b', 'a', 'c'], ['a', 'b', 'c'],
377
                 [(0, 0), (2, 1), (4, 2)])
378
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
379
        # recurse_matches doesn't match non-unique 
380
        # lines surrounded by bogus text.
1185.81.24 by Aaron Bentley
Reoganize patience-related code
381
        # 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
382
383
        # This is what it could be
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
384
        #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
385
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
386
        # This is what it currently gives:
387
        test_one('aBccDe', 'abccde', [(0,0), (5,5)])
388
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
389
    def test_matching_blocks(self):
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
390
        def chk_blocks(a, b, expected_blocks):
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
391
            # difflib always adds a signature of the total
392
            # 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
393
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
1185.81.11 by John Arbash Meinel
Found some edge cases that weren't being matched.
394
            blocks = s.get_matching_blocks()
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
395
            self.assertEquals((len(a), len(b), 0), blocks[-1])
396
            self.assertEquals(expected_blocks, blocks[:-1])
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
397
1185.81.2 by John Arbash Meinel
A couple small tests.
398
        # Some basic matching tests
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
399
        chk_blocks('', '', [])
400
        chk_blocks([], [], [])
401
        chk_blocks('abcd', 'abcd', [(0, 0, 4)])
402
        chk_blocks('abcd', 'abce', [(0, 0, 3)])
403
        chk_blocks('eabc', 'abce', [(1, 0, 3)])
404
        chk_blocks('eabce', 'abce', [(1, 0, 4)])
405
        chk_blocks('abcde', 'abXde', [(0, 0, 2), (3, 3, 2)])
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
406
        chk_blocks('abcde', 'abXYZde', [(0, 0, 2), (3, 5, 2)])
407
        chk_blocks('abde', 'abXYZde', [(0, 0, 2), (2, 5, 2)])
408
        # This may check too much, but it checks to see that 
409
        # a copied block stays attached to the previous section,
410
        # not the later one.
411
        # difflib would tend to grab the trailing longest match
412
        # 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,
413
        chk_blocks('abcdefghijklmnop', 'abcdefxydefghijklmnop',
414
                   [(0, 0, 6), (6, 11, 10)])
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
415
1185.81.2 by John Arbash Meinel
A couple small tests.
416
        # make sure it supports passing in lists
417
        chk_blocks(
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
418
                   ['hello there\n',
419
                    'world\n',
420
                    'how are you today?\n'],
421
                   ['hello there\n',
422
                    'how are you today?\n'],
1185.81.2 by John Arbash Meinel
A couple small tests.
423
                [(0, 0, 1), (2, 1, 1)])
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
424
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
425
        # non unique lines surrounded by non-matching lines
426
        # won't be found
427
        chk_blocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
428
429
        # But they only need to be locally unique
430
        chk_blocks('aBcDec', 'abcdec', [(0,0,1), (2,2,1), (4,4,2)])
431
432
        # non unique blocks won't be matched
433
        chk_blocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (8,8,1)])
434
435
        # but locally unique ones will
436
        chk_blocks('aBcdEeXcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
437
                                              (5,4,1), (7,5,2), (10,8,1)])
438
439
        chk_blocks('abbabbXd', 'cabbabxd', [(7,7,1)])
440
        chk_blocks('abbabbbb', 'cabbabbc', [])
441
        chk_blocks('bbbbbbbb', 'cbbbbbbc', [])
1185.81.11 by John Arbash Meinel
Found some edge cases that weren't being matched.
442
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
443
    def test_opcodes(self):
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
444
        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
445
            s = bzrlib.patiencediff.PatienceSequenceMatcher(None, a, b)
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
446
            self.assertEquals(expected_codes, s.get_opcodes())
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
447
448
        chk_ops('', '', [])
449
        chk_ops([], [], [])
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
450
        chk_ops('abcd', 'abcd', [('equal',    0,4, 0,4)])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
451
        chk_ops('abcd', 'abce', [('equal',   0,3, 0,3),
452
                                 ('replace', 3,4, 3,4)
453
                                ])
454
        chk_ops('eabc', 'abce', [('delete', 0,1, 0,0),
455
                                 ('equal',  1,4, 0,3),
456
                                 ('insert', 4,4, 3,4)
457
                                ])
458
        chk_ops('eabce', 'abce', [('delete', 0,1, 0,0),
459
                                  ('equal',  1,5, 0,4)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
460
                                 ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
461
        chk_ops('abcde', 'abXde', [('equal',   0,2, 0,2),
462
                                   ('replace', 2,3, 2,3),
463
                                   ('equal',   3,5, 3,5)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
464
                                  ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
465
        chk_ops('abcde', 'abXYZde', [('equal',   0,2, 0,2),
466
                                     ('replace', 2,3, 2,5),
467
                                     ('equal',   3,5, 5,7)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
468
                                    ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
469
        chk_ops('abde', 'abXYZde', [('equal',  0,2, 0,2),
470
                                    ('insert', 2,2, 2,5),
471
                                    ('equal',  2,4, 5,7)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
472
                                   ])
473
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
474
                [('equal',  0,6,  0,6),
475
                 ('insert', 6,6,  6,11),
476
                 ('equal',  6,16, 11,21)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
477
                ])
478
        chk_ops(
479
                [ 'hello there\n'
480
                , 'world\n'
481
                , 'how are you today?\n'],
482
                [ 'hello there\n'
483
                , 'how are you today?\n'],
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
484
                [('equal',  0,1, 0,1),
485
                 ('delete', 1,2, 1,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
486
                 ('equal',  2,3, 1,2),
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
487
                ])
488
        chk_ops('aBccDe', 'abccde', 
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
489
                [('equal',   0,1, 0,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
490
                 ('replace', 1,5, 1,5),
491
                 ('equal',   5,6, 5,6),
492
                ])
493
        chk_ops('aBcDec', 'abcdec', 
494
                [('equal',   0,1, 0,1),
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
495
                 ('replace', 1,2, 1,2),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
496
                 ('equal',   2,3, 2,3),
497
                 ('replace', 3,4, 3,4),
498
                 ('equal',   4,6, 4,6),
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
499
                ])
1185.81.10 by John Arbash Meinel
Added some more test cases.
500
        chk_ops('aBcdEcdFg', 'abcdecdfg', 
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
501
                [('equal',   0,1, 0,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
502
                 ('replace', 1,8, 1,8),
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
503
                 ('equal',   8,9, 8,9)
1185.81.10 by John Arbash Meinel
Added some more test cases.
504
                ])
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
505
        chk_ops('aBcdEeXcdFg', 'abcdecdfg', 
506
                [('equal',   0,1, 0,1),
507
                 ('replace', 1,2, 1,2),
508
                 ('equal',   2,4, 2,4),
509
                 ('delete', 4,5, 4,4),
510
                 ('equal',   5,6, 4,5),
511
                 ('delete', 6,7, 5,5),
512
                 ('equal',   7,9, 5,7),
513
                 ('replace', 9,10, 7,8),
514
                 ('equal',   10,11, 8,9)
515
                ])
1185.81.10 by John Arbash Meinel
Added some more test cases.
516
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
517
    def test_multiple_ranges(self):
518
        # There was an earlier bug where we used a bad set of ranges,
519
        # 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.
520
        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.
521
            # difflib always adds a signature of the total
522
            # 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
523
            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.
524
            blocks = s.get_matching_blocks()
525
            x = blocks.pop()
526
            self.assertEquals(x, (len(a), len(b), 0))
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
527
            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.
528
529
        chk_blocks('abcdefghijklmnop'
530
                 , 'abcXghiYZQRSTUVWXYZijklmnop'
531
                 , [(0, 0, 3), (6, 4, 3), (9, 20, 7)])
532
533
        chk_blocks('ABCd efghIjk  L'
534
                 , 'AxyzBCn mo pqrstuvwI1 2  L'
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
535
                 , [(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.
536
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
537
        # 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.
538
        chk_blocks('''\
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
539
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
540
    """
541
    gnxrf_netf = ['svyr*']
542
    gnxrf_bcgvbaf = ['ab-erphefr']
543
  
544
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
545
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
546
        vs vf_dhvrg():
547
            ercbegre = nqq_ercbegre_ahyy
548
        ryfr:
549
            ercbegre = nqq_ercbegre_cevag
550
        fzneg_nqq(svyr_yvfg, abg ab_erphefr, ercbegre)
551
552
553
pynff pzq_zxqve(Pbzznaq):
554
'''.splitlines(True), '''\
555
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
556
557
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl 
558
    nqq gurz.
559
    """
560
    gnxrf_netf = ['svyr*']
561
    gnxrf_bcgvbaf = ['ab-erphefr', 'qel-eha']
562
563
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr, qel_eha=Snyfr):
564
        vzcbeg omeyvo.nqq
565
566
        vs qel_eha:
567
            vs vf_dhvrg():
568
                # Guvf vf cbvagyrff, ohg V'q engure abg envfr na reebe
569
                npgvba = omeyvo.nqq.nqq_npgvba_ahyy
570
            ryfr:
571
  npgvba = omeyvo.nqq.nqq_npgvba_cevag
572
        ryvs vf_dhvrg():
573
            npgvba = omeyvo.nqq.nqq_npgvba_nqq
574
        ryfr:
575
       npgvba = omeyvo.nqq.nqq_npgvba_nqq_naq_cevag
576
577
        omeyvo.nqq.fzneg_nqq(svyr_yvfg, abg ab_erphefr, npgvba)
578
579
580
pynff pzq_zxqve(Pbzznaq):
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
581
'''.splitlines(True)
582
, [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
583
1711.2.9 by John Arbash Meinel
Rename cdv => patience
584
    def test_patience_unified_diff(self):
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
585
        txt_a = ['hello there\n',
586
                 'world\n',
587
                 'how are you today?\n']
588
        txt_b = ['hello there\n',
589
                 'how are you today?\n']
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
590
        unified_diff = bzrlib.patiencediff.unified_diff
591
        psm = bzrlib.patiencediff.PatienceSequenceMatcher
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
592
        self.assertEquals([ '---  \n',
593
                           '+++  \n',
594
                           '@@ -1,3 +1,2 @@\n',
595
                           ' hello there\n',
596
                           '-world\n',
597
                           ' 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
598
                          ]
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
599
                          , list(unified_diff(txt_a, txt_b,
600
                                 sequencematcher=psm)))
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
601
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
602
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
603
        # This is the result with LongestCommonSubstring matching
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
604
        self.assertEquals(['---  \n',
605
                           '+++  \n',
606
                           '@@ -1,6 +1,11 @@\n',
607
                           ' a\n',
608
                           ' b\n',
609
                           ' c\n',
610
                           '+d\n',
611
                           '+e\n',
612
                           '+f\n',
613
                           '+x\n',
614
                           '+y\n',
615
                           ' d\n',
616
                           ' e\n',
617
                           ' f\n']
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
618
                          , list(unified_diff(txt_a, txt_b)))
1711.2.9 by John Arbash Meinel
Rename cdv => patience
619
        # And the patience diff
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
620
        self.assertEquals(['---  \n',
621
                           '+++  \n',
622
                           '@@ -4,6 +4,11 @@\n',
623
                           ' d\n',
624
                           ' e\n',
625
                           ' f\n',
626
                           '+x\n',
627
                           '+y\n',
628
                           '+d\n',
629
                           '+e\n',
630
                           '+f\n',
631
                           ' g\n',
632
                           ' h\n',
633
                           ' i\n',
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
634
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
635
                          , 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
636
                                 sequencematcher=psm)))
1185.81.25 by Aaron Bentley
Clean up test_diff
637
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
638
1711.2.15 by John Arbash Meinel
Found a couple CDV left
639
class TestPatienceDiffLibFiles(TestCaseInTempDir):
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
640
1711.2.9 by John Arbash Meinel
Rename cdv => patience
641
    def test_patience_unified_diff_files(self):
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
642
        txt_a = ['hello there\n',
643
                 'world\n',
644
                 'how are you today?\n']
645
        txt_b = ['hello there\n',
646
                 '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
647
        open('a1', 'wb').writelines(txt_a)
648
        open('b1', 'wb').writelines(txt_b)
649
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
650
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
651
        psm = bzrlib.patiencediff.PatienceSequenceMatcher
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
652
        self.assertEquals(['--- a1 \n',
653
                           '+++ b1 \n',
654
                           '@@ -1,3 +1,2 @@\n',
655
                           ' hello there\n',
656
                           '-world\n',
657
                           ' 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
658
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
659
                          , 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
660
                                 sequencematcher=psm)))
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
661
662
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
663
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
664
        open('a2', 'wb').writelines(txt_a)
665
        open('b2', 'wb').writelines(txt_b)
666
667
        # This is the result with LongestCommonSubstring matching
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
668
        self.assertEquals(['--- a2 \n',
669
                           '+++ b2 \n',
670
                           '@@ -1,6 +1,11 @@\n',
671
                           ' a\n',
672
                           ' b\n',
673
                           ' c\n',
674
                           '+d\n',
675
                           '+e\n',
676
                           '+f\n',
677
                           '+x\n',
678
                           '+y\n',
679
                           ' d\n',
680
                           ' e\n',
681
                           ' f\n']
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
682
                          , list(unified_diff_files('a2', 'b2')))
683
1711.2.9 by John Arbash Meinel
Rename cdv => patience
684
        # And the patience diff
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
685
        self.assertEquals(['--- a2 \n',
686
                           '+++ b2 \n',
687
                           '@@ -4,6 +4,11 @@\n',
688
                           ' d\n',
689
                           ' e\n',
690
                           ' f\n',
691
                           '+x\n',
692
                           '+y\n',
693
                           '+d\n',
694
                           '+e\n',
695
                           '+f\n',
696
                           ' g\n',
697
                           ' h\n',
698
                           ' i\n',
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
699
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
700
                          , 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
701
                                 sequencematcher=psm)))