/brz/remove-bazaar

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