~bzr-pqm/bzr/bzr.dev

4763.2.4 by John Arbash Meinel
merge bzr.2.1 in preparation for NEWS entry.
1
# Copyright (C) 2005-2010 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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1711.2.16 by John Arbash Meinel
test_diff needs a copyright statement
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
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
19
import subprocess
3287.18.6 by Matt McClure
Snapshot of unfinished work.
20
import sys
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
21
import tempfile
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
22
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
23
from bzrlib import (
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
24
    diff,
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
25
    errors,
26
    osutils,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
27
    patiencediff,
28
    _patiencediff_py,
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
29
    revision as _mod_revision,
30
    revisionspec,
31
    revisiontree,
32
    tests,
33
    transform,
34
    )
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
35
from bzrlib.symbol_versioning import deprecated_in
5241.2.2 by Robert Collins
Missed one test.
36
from bzrlib.tests import features
4797.57.6 by Alexander Belchenko
added whitebox test for path_encoding in diff.
37
from bzrlib.tests.blackbox.test_diff import subst_dates
4913.5.9 by Gordon Tyler
Use test_win32utils' BackslashDirSeparatorFeature instead of checking sys.platform for win32.
38
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
39
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
40
class _AttribFeature(tests.Feature):
3287.18.20 by Matt McClure
Introduces a Feature subclass to encapsulate the availability of 'attrib'.
41
42
    def _probe(self):
43
        if (sys.platform not in ('cygwin', 'win32')):
3287.18.21 by Matt McClure
Fixes capitalization of False.
44
            return False
3287.18.20 by Matt McClure
Introduces a Feature subclass to encapsulate the availability of 'attrib'.
45
        try:
46
            proc = subprocess.Popen(['attrib', '.'], stdout=subprocess.PIPE)
47
        except OSError, e:
3287.18.21 by Matt McClure
Fixes capitalization of False.
48
            return False
3287.18.20 by Matt McClure
Introduces a Feature subclass to encapsulate the availability of 'attrib'.
49
        return (0 == proc.wait())
3287.18.24 by Matt McClure
Cleans up for submission. Removes comments.
50
3287.18.20 by Matt McClure
Introduces a Feature subclass to encapsulate the availability of 'attrib'.
51
    def feature_name(self):
52
        return 'attrib Windows command-line tool'
53
54
AttribFeature = _AttribFeature()
55
56
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
57
compiled_patiencediff_feature = tests.ModuleAvailableFeature(
58
                                    'bzrlib._patiencediff_c')
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
59
60
1558.15.11 by Aaron Bentley
Apply merge review suggestions
61
def udiff_lines(old, new, allow_binary=False):
974.1.6 by Aaron Bentley
Added unit tests
62
    output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
63
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
974.1.6 by Aaron Bentley
Added unit tests
64
    output.seek(0, 0)
65
    return output.readlines()
66
1711.2.54 by John Arbash Meinel
Use mkstemp instead of NamedTemporary file for external diff.
67
1711.2.57 by John Arbash Meinel
Allow external diff to write to a file without a fileno.
68
def external_udiff_lines(old, new, use_stringio=False):
69
    if use_stringio:
70
        # StringIO has no fileno, so it tests a different codepath
71
        output = StringIO()
72
    else:
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
73
        output = tempfile.TemporaryFile()
1692.8.7 by James Henstridge
changes suggested by John Meinel
74
    try:
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
75
        diff.external_diff('old', old, 'new', new, output, diff_opts=['-u'])
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
76
    except errors.NoDiff:
77
        raise tests.TestSkipped('external "diff" not present to test')
1692.8.2 by James Henstridge
add a test for sending external diff output to a file
78
    output.seek(0, 0)
79
    lines = output.readlines()
80
    output.close()
81
    return lines
82
83
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
84
class TestDiff(tests.TestCase):
1185.81.25 by Aaron Bentley
Clean up test_diff
85
1102 by Martin Pool
- merge test refactoring from robertc
86
    def test_add_nl(self):
87
        """diff generates a valid diff for patches that add a newline"""
974.1.6 by Aaron Bentley
Added unit tests
88
        lines = udiff_lines(['boo'], ['boo\n'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
89
        self.check_patch(lines)
90
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
91
            ## "expected no-nl, got %r" % lines[4]
974.1.6 by Aaron Bentley
Added unit tests
92
1102 by Martin Pool
- merge test refactoring from robertc
93
    def test_add_nl_2(self):
94
        """diff generates a valid diff for patches that change last line and
95
        add a newline.
96
        """
974.1.6 by Aaron Bentley
Added unit tests
97
        lines = udiff_lines(['boo'], ['goo\n'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
98
        self.check_patch(lines)
99
        self.assertEquals(lines[4], '\\ No newline at end of file\n')
100
            ## "expected no-nl, got %r" % lines[4]
974.1.6 by Aaron Bentley
Added unit tests
101
1102 by Martin Pool
- merge test refactoring from robertc
102
    def test_remove_nl(self):
103
        """diff generates a valid diff for patches that change last line and
104
        add a newline.
105
        """
974.1.6 by Aaron Bentley
Added unit tests
106
        lines = udiff_lines(['boo\n'], ['boo'])
1185.16.145 by Martin Pool
Remove all assert statements from test cases.
107
        self.check_patch(lines)
108
        self.assertEquals(lines[5], '\\ No newline at end of file\n')
109
            ## "expected no-nl, got %r" % lines[5]
110
111
    def check_patch(self, lines):
112
        self.assert_(len(lines) > 1)
113
            ## "Not enough lines for a file header for patch:\n%s" % "".join(lines)
114
        self.assert_(lines[0].startswith ('---'))
115
            ## 'No orig line for patch:\n%s' % "".join(lines)
116
        self.assert_(lines[1].startswith ('+++'))
117
            ## 'No mod line for patch:\n%s' % "".join(lines)
118
        self.assert_(len(lines) > 2)
119
            ## "No hunks for patch:\n%s" % "".join(lines)
120
        self.assert_(lines[2].startswith('@@'))
121
            ## "No hunk header for patch:\n%s" % "".join(lines)
122
        self.assert_('@@' in lines[2][2:])
123
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
124
1558.15.2 by Aaron Bentley
Implemented binary file handling for diff
125
    def test_binary_lines(self):
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
126
        empty = []
127
        uni_lines = [1023 * 'a' + '\x00']
128
        self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines , empty)
129
        self.assertRaises(errors.BinaryFile, udiff_lines, empty, uni_lines)
130
        udiff_lines(uni_lines , empty, allow_binary=True)
131
        udiff_lines(empty, uni_lines, allow_binary=True)
1692.8.2 by James Henstridge
add a test for sending external diff output to a file
132
133
    def test_external_diff(self):
134
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
135
        self.check_patch(lines)
1899.1.6 by John Arbash Meinel
internal_diff always adds a trailing \n, make sure external_diff does too
136
        self.assertEqual('\n', lines[-1])
1711.2.57 by John Arbash Meinel
Allow external diff to write to a file without a fileno.
137
138
    def test_external_diff_no_fileno(self):
139
        # Make sure that we can handle not having a fileno, even
140
        # if the diff is large
141
        lines = external_udiff_lines(['boo\n']*10000,
142
                                     ['goo\n']*10000,
143
                                     use_stringio=True)
144
        self.check_patch(lines)
1899.1.1 by John Arbash Meinel
Fix the bug in the NoDiff exception class, and add a test
145
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
146
    def test_external_diff_binary_lang_c(self):
2321.2.5 by Alexander Belchenko
external diff: no need for special code path for win32 (suggested by John Meinel)
147
        old_env = {}
148
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
149
            old_env[lang] = osutils.set_or_unset_env(lang, 'C')
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
150
        try:
151
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
1959.1.1 by Marien Zwart
merge.
152
            # Older versions of diffutils say "Binary files", newer
153
            # versions just say "Files".
154
            self.assertContainsRe(lines[0],
155
                                  '(Binary f|F)iles old and new differ\n')
156
            self.assertEquals(lines[1:], ['\n'])
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
157
        finally:
2321.2.5 by Alexander Belchenko
external diff: no need for special code path for win32 (suggested by John Meinel)
158
            for lang, old_val in old_env.iteritems():
159
                osutils.set_or_unset_env(lang, old_val)
1899.1.4 by John Arbash Meinel
Just swallow a return code of 2
160
1899.1.1 by John Arbash Meinel
Fix the bug in the NoDiff exception class, and add a test
161
    def test_no_external_diff(self):
162
        """Check that NoDiff is raised when diff is not available"""
163
        # Use os.environ['PATH'] to make sure no 'diff' command is available
164
        orig_path = os.environ['PATH']
165
        try:
166
            os.environ['PATH'] = ''
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
167
            self.assertRaises(errors.NoDiff, diff.external_diff,
1899.1.1 by John Arbash Meinel
Fix the bug in the NoDiff exception class, and add a test
168
                              'old', ['boo\n'], 'new', ['goo\n'],
169
                              StringIO(), diff_opts=['-u'])
170
        finally:
171
            os.environ['PATH'] = orig_path
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
172
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
173
    def test_internal_diff_default(self):
174
        # Default internal diff encoding is utf8
175
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
176
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
177
                           u'new_\xe5', ['new_text\n'], output)
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
178
        lines = output.getvalue().splitlines(True)
179
        self.check_patch(lines)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
180
        self.assertEquals(['--- old_\xc2\xb5\n',
181
                           '+++ new_\xc3\xa5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
182
                           '@@ -1,1 +1,1 @@\n',
183
                           '-old_text\n',
184
                           '+new_text\n',
185
                           '\n',
186
                          ]
187
                          , lines)
188
189
    def test_internal_diff_utf8(self):
190
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
191
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
192
                           u'new_\xe5', ['new_text\n'], output,
193
                           path_encoding='utf8')
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
194
        lines = output.getvalue().splitlines(True)
195
        self.check_patch(lines)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
196
        self.assertEquals(['--- old_\xc2\xb5\n',
197
                           '+++ new_\xc3\xa5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
198
                           '@@ -1,1 +1,1 @@\n',
199
                           '-old_text\n',
200
                           '+new_text\n',
201
                           '\n',
202
                          ]
203
                          , lines)
204
205
    def test_internal_diff_iso_8859_1(self):
206
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
207
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
208
                           u'new_\xe5', ['new_text\n'], output,
209
                           path_encoding='iso-8859-1')
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
210
        lines = output.getvalue().splitlines(True)
211
        self.check_patch(lines)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
212
        self.assertEquals(['--- old_\xb5\n',
213
                           '+++ new_\xe5\n',
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
214
                           '@@ -1,1 +1,1 @@\n',
215
                           '-old_text\n',
216
                           '+new_text\n',
217
                           '\n',
218
                          ]
219
                          , lines)
220
3085.1.1 by John Arbash Meinel
Fix internal_diff to not fail when the texts are identical.
221
    def test_internal_diff_no_content(self):
222
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
223
        diff.internal_diff(u'old', [], u'new', [], output)
3085.1.1 by John Arbash Meinel
Fix internal_diff to not fail when the texts are identical.
224
        self.assertEqual('', output.getvalue())
225
226
    def test_internal_diff_no_changes(self):
227
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
228
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
229
                           u'new', ['text\n', 'contents\n'],
230
                           output)
3085.1.1 by John Arbash Meinel
Fix internal_diff to not fail when the texts are identical.
231
        self.assertEqual('', output.getvalue())
232
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
233
    def test_internal_diff_returns_bytes(self):
234
        import StringIO
235
        output = StringIO.StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
236
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
237
                            u'new_\xe5', ['new_text\n'], output)
1711.2.30 by John Arbash Meinel
Fix bug in internal_diff handling of unicode paths
238
        self.failUnless(isinstance(output.getvalue(), str),
239
            'internal_diff should return bytestrings')
240
1185.81.25 by Aaron Bentley
Clean up test_diff
241
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
242
class TestDiffFiles(tests.TestCaseInTempDir):
1920.1.1 by John Arbash Meinel
fix bug #56307, handle binary files even when LANG is not english
243
244
    def test_external_diff_binary(self):
245
        """The output when using external diff should use diff's i18n error"""
246
        # Make sure external_diff doesn't fail in the current LANG
247
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
248
2240.1.1 by Alexander Belchenko
test_external_diff_binary: run external diff with --binary flag
249
        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
250
        open('old', 'wb').write('\x00foobar\n')
251
        open('new', 'wb').write('foo\x00bar\n')
252
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
253
                                     stdin=subprocess.PIPE)
254
        out, err = pipe.communicate()
255
        # Diff returns '2' on Binary files.
256
        self.assertEqual(2, pipe.returncode)
257
        # We should output whatever diff tells us, plus a trailing newline
258
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
259
260
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
261
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
262
    """Has a helper for running show_diff_trees"""
263
264
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
265
        output = StringIO()
266
        if working_tree is not None:
267
            extra_trees = (working_tree,)
268
        else:
269
            extra_trees = ()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
270
        diff.show_diff_trees(tree1, tree2, output,
271
                             specific_files=specific_files,
272
                             extra_trees=extra_trees, old_label='old/',
273
                             new_label='new/')
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
274
        return output.getvalue()
275
276
277
class TestDiffDates(TestShowDiffTreesHelper):
1740.2.5 by Aaron Bentley
Merge from bzr.dev
278
279
    def setUp(self):
280
        super(TestDiffDates, self).setUp()
281
        self.wt = self.make_branch_and_tree('.')
282
        self.b = self.wt.branch
283
        self.build_tree_contents([
284
            ('file1', 'file1 contents at rev 1\n'),
285
            ('file2', 'file2 contents at rev 1\n')
286
            ])
287
        self.wt.add(['file1', 'file2'])
288
        self.wt.commit(
289
            message='Revision 1',
290
            timestamp=1143849600, # 2006-04-01 00:00:00 UTC
291
            timezone=0,
292
            rev_id='rev-1')
293
        self.build_tree_contents([('file1', 'file1 contents at rev 2\n')])
294
        self.wt.commit(
295
            message='Revision 2',
296
            timestamp=1143936000, # 2006-04-02 00:00:00 UTC
297
            timezone=28800,
298
            rev_id='rev-2')
299
        self.build_tree_contents([('file2', 'file2 contents at rev 3\n')])
300
        self.wt.commit(
301
            message='Revision 3',
302
            timestamp=1144022400, # 2006-04-03 00:00:00 UTC
303
            timezone=-3600,
304
            rev_id='rev-3')
305
        self.wt.remove(['file2'])
306
        self.wt.commit(
307
            message='Revision 4',
308
            timestamp=1144108800, # 2006-04-04 00:00:00 UTC
309
            timezone=0,
310
            rev_id='rev-4')
311
        self.build_tree_contents([
312
            ('file1', 'file1 contents in working tree\n')
313
            ])
314
        # set the date stamps for files in the working tree to known values
315
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
316
317
    def test_diff_rev_tree_working_tree(self):
318
        output = self.get_diff(self.wt.basis_tree(), self.wt)
319
        # note that the date for old/file1 is from rev 2 rather than from
320
        # the basis revision (rev 4)
321
        self.assertEqualDiff(output, '''\
322
=== modified file 'file1'
323
--- old/file1\t2006-04-02 00:00:00 +0000
324
+++ new/file1\t2006-04-05 00:00:00 +0000
325
@@ -1,1 +1,1 @@
326
-file1 contents at rev 2
327
+file1 contents in working tree
328
329
''')
330
331
    def test_diff_rev_tree_rev_tree(self):
332
        tree1 = self.b.repository.revision_tree('rev-2')
333
        tree2 = self.b.repository.revision_tree('rev-3')
334
        output = self.get_diff(tree1, tree2)
335
        self.assertEqualDiff(output, '''\
336
=== modified file 'file2'
337
--- old/file2\t2006-04-01 00:00:00 +0000
338
+++ new/file2\t2006-04-03 00:00:00 +0000
339
@@ -1,1 +1,1 @@
340
-file2 contents at rev 1
341
+file2 contents at rev 3
342
343
''')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
344
1740.2.5 by Aaron Bentley
Merge from bzr.dev
345
    def test_diff_add_files(self):
3668.5.1 by Jelmer Vernooij
Use NULL_REVISION rather than None for Repository.revision_tree().
346
        tree1 = self.b.repository.revision_tree(_mod_revision.NULL_REVISION)
1740.2.5 by Aaron Bentley
Merge from bzr.dev
347
        tree2 = self.b.repository.revision_tree('rev-1')
348
        output = self.get_diff(tree1, tree2)
349
        # the files have the epoch time stamp for the tree in which
350
        # they don't exist.
351
        self.assertEqualDiff(output, '''\
352
=== added file 'file1'
353
--- old/file1\t1970-01-01 00:00:00 +0000
354
+++ new/file1\t2006-04-01 00:00:00 +0000
355
@@ -0,0 +1,1 @@
356
+file1 contents at rev 1
357
358
=== added file 'file2'
359
--- old/file2\t1970-01-01 00:00:00 +0000
360
+++ new/file2\t2006-04-01 00:00:00 +0000
361
@@ -0,0 +1,1 @@
362
+file2 contents at rev 1
363
364
''')
365
366
    def test_diff_remove_files(self):
367
        tree1 = self.b.repository.revision_tree('rev-3')
368
        tree2 = self.b.repository.revision_tree('rev-4')
369
        output = self.get_diff(tree1, tree2)
370
        # the file has the epoch time stamp for the tree in which
371
        # it doesn't exist.
372
        self.assertEqualDiff(output, '''\
373
=== removed file 'file2'
374
--- old/file2\t2006-04-03 00:00:00 +0000
375
+++ new/file2\t1970-01-01 00:00:00 +0000
376
@@ -1,1 +0,0 @@
377
-file2 contents at rev 3
378
379
''')
380
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
381
    def test_show_diff_specified(self):
1551.7.22 by Aaron Bentley
Changes from review
382
        """A working tree filename can be used to identify a file"""
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
383
        self.wt.rename_one('file1', 'file1b')
384
        old_tree = self.b.repository.revision_tree('rev-1')
385
        new_tree = self.b.repository.revision_tree('rev-4')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
386
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'],
1551.7.22 by Aaron Bentley
Changes from review
387
                            working_tree=self.wt)
388
        self.assertContainsRe(out, 'file1\t')
1551.7.17 by Aaron Bentley
Switch to PathsNotVersioned, accept extra_trees
389
1551.7.22 by Aaron Bentley
Changes from review
390
    def test_recursive_diff(self):
391
        """Children of directories are matched"""
392
        os.mkdir('dir1')
393
        os.mkdir('dir2')
394
        self.wt.add(['dir1', 'dir2'])
395
        self.wt.rename_one('file1', 'dir1/file1')
396
        old_tree = self.b.repository.revision_tree('rev-1')
397
        new_tree = self.b.repository.revision_tree('rev-4')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
398
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'],
1551.7.22 by Aaron Bentley
Changes from review
399
                            working_tree=self.wt)
400
        self.assertContainsRe(out, 'file1\t')
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
401
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'],
1551.7.22 by Aaron Bentley
Changes from review
402
                            working_tree=self.wt)
403
        self.assertNotContainsRe(out, 'file1\t')
1740.2.5 by Aaron Bentley
Merge from bzr.dev
404
1899.1.1 by John Arbash Meinel
Fix the bug in the NoDiff exception class, and add a test
405
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
406
407
class TestShowDiffTrees(TestShowDiffTreesHelper):
408
    """Direct tests for show_diff_trees"""
409
410
    def test_modified_file(self):
411
        """Test when a file is modified."""
412
        tree = self.make_branch_and_tree('tree')
413
        self.build_tree_contents([('tree/file', 'contents\n')])
414
        tree.add(['file'], ['file-id'])
415
        tree.commit('one', rev_id='rev-1')
416
417
        self.build_tree_contents([('tree/file', 'new contents\n')])
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
418
        d = self.get_diff(tree.basis_tree(), tree)
419
        self.assertContainsRe(d, "=== modified file 'file'\n")
420
        self.assertContainsRe(d, '--- old/file\t')
421
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
422
        self.assertContainsRe(d, '-contents\n'
423
                                 '\\+new contents\n')
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
424
2405.1.2 by John Arbash Meinel
Fix bug #103870 by passing None instead of a (sometimes wrong) path
425
    def test_modified_file_in_renamed_dir(self):
426
        """Test when a file is modified in a renamed directory."""
427
        tree = self.make_branch_and_tree('tree')
428
        self.build_tree(['tree/dir/'])
429
        self.build_tree_contents([('tree/dir/file', 'contents\n')])
430
        tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
431
        tree.commit('one', rev_id='rev-1')
432
433
        tree.rename_one('dir', 'other')
434
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
435
        d = self.get_diff(tree.basis_tree(), tree)
436
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
437
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
2405.1.2 by John Arbash Meinel
Fix bug #103870 by passing None instead of a (sometimes wrong) path
438
        # XXX: This is technically incorrect, because it used to be at another
439
        # location. What to do?
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
440
        self.assertContainsRe(d, '--- old/dir/file\t')
441
        self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
442
        self.assertContainsRe(d, '-contents\n'
443
                                 '\\+new contents\n')
2405.1.2 by John Arbash Meinel
Fix bug #103870 by passing None instead of a (sometimes wrong) path
444
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
445
    def test_renamed_directory(self):
446
        """Test when only a directory is only renamed."""
447
        tree = self.make_branch_and_tree('tree')
448
        self.build_tree(['tree/dir/'])
449
        self.build_tree_contents([('tree/dir/file', 'contents\n')])
450
        tree.add(['dir', 'dir/file'], ['dir-id', 'file-id'])
451
        tree.commit('one', rev_id='rev-1')
452
453
        tree.rename_one('dir', 'newdir')
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
454
        d = self.get_diff(tree.basis_tree(), tree)
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
455
        # Renaming a directory should be a single "you renamed this dir" even
456
        # when there are files inside.
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
457
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
458
459
    def test_renamed_file(self):
460
        """Test when a file is only renamed."""
461
        tree = self.make_branch_and_tree('tree')
462
        self.build_tree_contents([('tree/file', 'contents\n')])
463
        tree.add(['file'], ['file-id'])
464
        tree.commit('one', rev_id='rev-1')
465
466
        tree.rename_one('file', 'newname')
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
467
        d = self.get_diff(tree.basis_tree(), tree)
468
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
469
        # We shouldn't have a --- or +++ line, because there is no content
470
        # change
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
471
        self.assertNotContainsRe(d, '---')
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
472
473
    def test_renamed_and_modified_file(self):
474
        """Test when a file is only renamed."""
475
        tree = self.make_branch_and_tree('tree')
476
        self.build_tree_contents([('tree/file', 'contents\n')])
477
        tree.add(['file'], ['file-id'])
478
        tree.commit('one', rev_id='rev-1')
479
480
        tree.rename_one('file', 'newname')
481
        self.build_tree_contents([('tree/newname', 'new contents\n')])
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
482
        d = self.get_diff(tree.basis_tree(), tree)
483
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
484
        self.assertContainsRe(d, '--- old/file\t')
485
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
486
        self.assertContainsRe(d, '-contents\n'
487
                                 '\\+new contents\n')
2405.1.1 by John Arbash Meinel
Add a bunch of direct tests for 'show_diff_trees'
488
3268.1.1 by C Miller
Describe the property changes in diffs. Currently, this is the executable-bit
489
490
    def test_internal_diff_exec_property(self):
491
        tree = self.make_branch_and_tree('tree')
492
493
        tt = transform.TreeTransform(tree)
494
        tt.new_file('a', tt.root, 'contents\n', 'a-id', True)
495
        tt.new_file('b', tt.root, 'contents\n', 'b-id', False)
496
        tt.new_file('c', tt.root, 'contents\n', 'c-id', True)
497
        tt.new_file('d', tt.root, 'contents\n', 'd-id', False)
498
        tt.new_file('e', tt.root, 'contents\n', 'control-e-id', True)
499
        tt.new_file('f', tt.root, 'contents\n', 'control-f-id', False)
500
        tt.apply()
501
        tree.commit('one', rev_id='rev-1')
502
503
        tt = transform.TreeTransform(tree)
504
        tt.set_executability(False, tt.trans_id_file_id('a-id'))
505
        tt.set_executability(True, tt.trans_id_file_id('b-id'))
506
        tt.set_executability(False, tt.trans_id_file_id('c-id'))
507
        tt.set_executability(True, tt.trans_id_file_id('d-id'))
508
        tt.apply()
509
        tree.rename_one('c', 'new-c')
510
        tree.rename_one('d', 'new-d')
511
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
512
        d = self.get_diff(tree.basis_tree(), tree)
3268.1.1 by C Miller
Describe the property changes in diffs. Currently, this is the executable-bit
513
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
514
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
515
                                  ".*\+x to -x.*\)")
516
        self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
517
                                  ".*-x to \+x.*\)")
518
        self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
519
                                  ".*\+x to -x.*\)")
520
        self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
521
                                  ".*-x to \+x.*\)")
522
        self.assertNotContainsRe(d, r"file 'e'")
523
        self.assertNotContainsRe(d, r"file 'f'")
3268.1.1 by C Miller
Describe the property changes in diffs. Currently, this is the executable-bit
524
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
525
    def test_binary_unicode_filenames(self):
2592.2.2 by Jonathan Lange
Apply jam's comments to test_binary_unicode_filenames. Change the
526
        """Test that contents of files are *not* encoded in UTF-8 when there
527
        is a binary file in the diff.
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
528
        """
529
        # See https://bugs.launchpad.net/bugs/110092.
3477.1.2 by John Arbash Meinel
Rename UnicodeFilename => UnicodeFilenameFeature
530
        self.requireFeature(tests.UnicodeFilenameFeature)
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
531
532
        # This bug isn't triggered with cStringIO.
533
        from StringIO import StringIO
534
        tree = self.make_branch_and_tree('tree')
2592.2.2 by Jonathan Lange
Apply jam's comments to test_binary_unicode_filenames. Change the
535
        alpha, omega = u'\u03b1', u'\u03c9'
536
        alpha_utf8, omega_utf8 = alpha.encode('utf8'), omega.encode('utf8')
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
537
        self.build_tree_contents(
2592.2.2 by Jonathan Lange
Apply jam's comments to test_binary_unicode_filenames. Change the
538
            [('tree/' + alpha, chr(0)),
539
             ('tree/' + omega,
540
              ('The %s and the %s\n' % (alpha_utf8, omega_utf8)))])
541
        tree.add([alpha], ['file-id'])
542
        tree.add([omega], ['file-id-2'])
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
543
        diff_content = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
544
        diff.show_diff_trees(tree.basis_tree(), tree, diff_content)
545
        d = diff_content.getvalue()
546
        self.assertContainsRe(d, r"=== added file '%s'" % alpha_utf8)
547
        self.assertContainsRe(d, "Binary files a/%s.*and b/%s.* differ\n"
548
                              % (alpha_utf8, alpha_utf8))
549
        self.assertContainsRe(d, r"=== added file '%s'" % omega_utf8)
550
        self.assertContainsRe(d, r"--- a/%s" % (omega_utf8,))
551
        self.assertContainsRe(d, r"\+\+\+ b/%s" % (omega_utf8,))
2592.2.1 by Jonathan Lange
Reproduce and fix bug 110092.
552
2725.2.1 by ghigo
When a unicode filename is renamed, in the diff is showed a wrong result
553
    def test_unicode_filename(self):
554
        """Test when the filename are unicode."""
3477.1.2 by John Arbash Meinel
Rename UnicodeFilename => UnicodeFilenameFeature
555
        self.requireFeature(tests.UnicodeFilenameFeature)
2725.2.1 by ghigo
When a unicode filename is renamed, in the diff is showed a wrong result
556
557
        alpha, omega = u'\u03b1', u'\u03c9'
558
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
559
560
        tree = self.make_branch_and_tree('tree')
561
        self.build_tree_contents([('tree/ren_'+alpha, 'contents\n')])
562
        tree.add(['ren_'+alpha], ['file-id-2'])
563
        self.build_tree_contents([('tree/del_'+alpha, 'contents\n')])
564
        tree.add(['del_'+alpha], ['file-id-3'])
565
        self.build_tree_contents([('tree/mod_'+alpha, 'contents\n')])
566
        tree.add(['mod_'+alpha], ['file-id-4'])
567
568
        tree.commit('one', rev_id='rev-1')
569
570
        tree.rename_one('ren_'+alpha, 'ren_'+omega)
571
        tree.remove('del_'+alpha)
572
        self.build_tree_contents([('tree/add_'+alpha, 'contents\n')])
573
        tree.add(['add_'+alpha], ['file-id'])
574
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
575
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
576
        d = self.get_diff(tree.basis_tree(), tree)
577
        self.assertContainsRe(d,
2725.2.1 by ghigo
When a unicode filename is renamed, in the diff is showed a wrong result
578
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
579
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
580
        self.assertContainsRe(d, "=== modified file 'mod_%s'"%autf8)
581
        self.assertContainsRe(d, "=== removed file 'del_%s'"%autf8)
582
4797.57.6 by Alexander Belchenko
added whitebox test for path_encoding in diff.
583
    def test_unicode_filename_path_encoding(self):
584
        """Test for bug #382699: unicode filenames on Windows should be shown
585
        in user encoding.
586
        """
587
        self.requireFeature(tests.UnicodeFilenameFeature)
588
        # The word 'test' in Russian
589
        _russian_test = u'\u0422\u0435\u0441\u0442'
590
        directory = _russian_test + u'/'
591
        test_txt = _russian_test + u'.txt'
592
        u1234 = u'\u1234.txt'
593
594
        tree = self.make_branch_and_tree('.')
595
        self.build_tree_contents([
596
            (test_txt, 'foo\n'),
597
            (u1234, 'foo\n'),
598
            (directory, None),
599
            ])
600
        tree.add([test_txt, u1234, directory])
601
602
        sio = StringIO()
5258.1.1 by Alexander Belchenko
merge diff header work from my 2.1 branch
603
        diff.show_diff_trees(tree.basis_tree(), tree, sio,
4797.57.6 by Alexander Belchenko
added whitebox test for path_encoding in diff.
604
            path_encoding='cp1251')
605
606
        output = subst_dates(sio.getvalue())
607
        shouldbe = ('''\
608
=== added directory '%(directory)s'
609
=== added file '%(test_txt)s'
610
--- a/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
611
+++ b/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
612
@@ -0,0 +1,1 @@
613
+foo
614
615
=== added file '?.txt'
616
--- a/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
617
+++ b/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
618
@@ -0,0 +1,1 @@
619
+foo
620
621
''' % {'directory': _russian_test.encode('cp1251'),
622
       'test_txt': test_txt.encode('cp1251'),
623
      })
624
        self.assertEqualDiff(output, shouldbe)
625
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
626
627
class DiffWasIs(diff.DiffPath):
3009.2.15 by Aaron Bentley
Test differ registration
628
629
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
630
        self.to_file.write('was: ')
631
        self.to_file.write(self.old_tree.get_file(file_id).read())
632
        self.to_file.write('is: ')
633
        self.to_file.write(self.new_tree.get_file(file_id).read())
634
        pass
635
636
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
637
class TestDiffTree(tests.TestCaseWithTransport):
3009.2.9 by Aaron Bentley
Add tests for Differ
638
639
    def setUp(self):
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
640
        super(TestDiffTree, self).setUp()
3009.2.9 by Aaron Bentley
Add tests for Differ
641
        self.old_tree = self.make_branch_and_tree('old-tree')
642
        self.old_tree.lock_write()
643
        self.addCleanup(self.old_tree.unlock)
644
        self.new_tree = self.make_branch_and_tree('new-tree')
645
        self.new_tree.lock_write()
646
        self.addCleanup(self.new_tree.unlock)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
647
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
3009.2.9 by Aaron Bentley
Add tests for Differ
648
649
    def test_diff_text(self):
650
        self.build_tree_contents([('old-tree/olddir/',),
651
                                  ('old-tree/olddir/oldfile', 'old\n')])
652
        self.old_tree.add('olddir')
653
        self.old_tree.add('olddir/oldfile', 'file-id')
654
        self.build_tree_contents([('new-tree/newdir/',),
655
                                  ('new-tree/newdir/newfile', 'new\n')])
656
        self.new_tree.add('newdir')
657
        self.new_tree.add('newdir/newfile', 'file-id')
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
658
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
659
        differ.diff_text('file-id', None, 'old label', 'new label')
3009.2.9 by Aaron Bentley
Add tests for Differ
660
        self.assertEqual(
661
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
662
            differ.to_file.getvalue())
663
        differ.to_file.seek(0)
664
        differ.diff_text(None, 'file-id', 'old label', 'new label')
3009.2.9 by Aaron Bentley
Add tests for Differ
665
        self.assertEqual(
666
            '--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
667
            differ.to_file.getvalue())
668
        differ.to_file.seek(0)
669
        differ.diff_text('file-id', 'file-id', 'old label', 'new label')
3009.2.9 by Aaron Bentley
Add tests for Differ
670
        self.assertEqual(
671
            '--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
672
            differ.to_file.getvalue())
3009.2.9 by Aaron Bentley
Add tests for Differ
673
3087.1.1 by Aaron Bentley
Diff handles missing files correctly, with no tracebacks
674
    def test_diff_deletion(self):
675
        self.build_tree_contents([('old-tree/file', 'contents'),
676
                                  ('new-tree/file', 'contents')])
677
        self.old_tree.add('file', 'file-id')
678
        self.new_tree.add('file', 'file-id')
679
        os.unlink('new-tree/file')
680
        self.differ.show_diff(None)
681
        self.assertContainsRe(self.differ.to_file.getvalue(), '-contents')
682
683
    def test_diff_creation(self):
684
        self.build_tree_contents([('old-tree/file', 'contents'),
685
                                  ('new-tree/file', 'contents')])
686
        self.old_tree.add('file', 'file-id')
687
        self.new_tree.add('file', 'file-id')
688
        os.unlink('old-tree/file')
689
        self.differ.show_diff(None)
690
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
691
3009.2.9 by Aaron Bentley
Add tests for Differ
692
    def test_diff_symlink(self):
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
693
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
694
        differ.diff_symlink('old target', None)
3009.2.9 by Aaron Bentley
Add tests for Differ
695
        self.assertEqual("=== target was 'old target'\n",
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
696
                         differ.to_file.getvalue())
3009.2.9 by Aaron Bentley
Add tests for Differ
697
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
698
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
699
        differ.diff_symlink(None, 'new target')
3009.2.9 by Aaron Bentley
Add tests for Differ
700
        self.assertEqual("=== target is 'new target'\n",
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
701
                         differ.to_file.getvalue())
702
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
703
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
704
        differ.diff_symlink('old target', 'new target')
3009.2.9 by Aaron Bentley
Add tests for Differ
705
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
3009.2.11 by Aaron Bentley
Refactor diff to be more pluggable
706
                         differ.to_file.getvalue())
3009.2.9 by Aaron Bentley
Add tests for Differ
707
708
    def test_diff(self):
709
        self.build_tree_contents([('old-tree/olddir/',),
710
                                  ('old-tree/olddir/oldfile', 'old\n')])
711
        self.old_tree.add('olddir')
712
        self.old_tree.add('olddir/oldfile', 'file-id')
713
        self.build_tree_contents([('new-tree/newdir/',),
714
                                  ('new-tree/newdir/newfile', 'new\n')])
715
        self.new_tree.add('newdir')
716
        self.new_tree.add('newdir/newfile', 'file-id')
3009.2.12 by Aaron Bentley
Associate labels with text diffing only
717
        self.differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
3009.2.9 by Aaron Bentley
Add tests for Differ
718
        self.assertContainsRe(
719
            self.differ.to_file.getvalue(),
720
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
721
             ' \@\@\n-old\n\+new\n\n')
722
723
    def test_diff_kind_change(self):
3146.4.3 by Aaron Bentley
Add missing Symlink requirement
724
        self.requireFeature(tests.SymlinkFeature)
3009.2.9 by Aaron Bentley
Add tests for Differ
725
        self.build_tree_contents([('old-tree/olddir/',),
726
                                  ('old-tree/olddir/oldfile', 'old\n')])
727
        self.old_tree.add('olddir')
728
        self.old_tree.add('olddir/oldfile', 'file-id')
729
        self.build_tree(['new-tree/newdir/'])
730
        os.symlink('new', 'new-tree/newdir/newfile')
731
        self.new_tree.add('newdir')
732
        self.new_tree.add('newdir/newfile', 'file-id')
3009.2.12 by Aaron Bentley
Associate labels with text diffing only
733
        self.differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
3009.2.9 by Aaron Bentley
Add tests for Differ
734
        self.assertContainsRe(
735
            self.differ.to_file.getvalue(),
736
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
737
             ' \@\@\n-old\n\n')
738
        self.assertContainsRe(self.differ.to_file.getvalue(),
4216.3.1 by Robert Collins
Fix Tree.get_symlink_target to decode from the disk encoding to get a unicode encoded string.
739
                              "=== target is u'new'\n")
3009.2.9 by Aaron Bentley
Add tests for Differ
740
3009.2.19 by Aaron Bentley
Implement directory diffing
741
    def test_diff_directory(self):
742
        self.build_tree(['new-tree/new-dir/'])
743
        self.new_tree.add('new-dir', 'new-dir-id')
744
        self.differ.diff('new-dir-id', None, 'new-dir')
745
        self.assertEqual(self.differ.to_file.getvalue(), '')
746
3009.2.16 by Aaron Bentley
Test support for extra differs
747
    def create_old_new(self):
748
        self.build_tree_contents([('old-tree/olddir/',),
749
                                  ('old-tree/olddir/oldfile', 'old\n')])
750
        self.old_tree.add('olddir')
751
        self.old_tree.add('olddir/oldfile', 'file-id')
752
        self.build_tree_contents([('new-tree/newdir/',),
753
                                  ('new-tree/newdir/newfile', 'new\n')])
754
        self.new_tree.add('newdir')
755
        self.new_tree.add('newdir/newfile', 'file-id')
756
3009.2.27 by Aaron Bentley
Use extra_factories instead of extra_diffs
757
    def test_register_diff(self):
3009.2.16 by Aaron Bentley
Test support for extra differs
758
        self.create_old_new()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
759
        old_diff_factories = diff.DiffTree.diff_factories
760
        diff.DiffTree.diff_factories=old_diff_factories[:]
761
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
3009.2.16 by Aaron Bentley
Test support for extra differs
762
        try:
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
763
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
3009.2.16 by Aaron Bentley
Test support for extra differs
764
        finally:
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
765
            diff.DiffTree.diff_factories = old_diff_factories
3009.2.16 by Aaron Bentley
Test support for extra differs
766
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
767
        self.assertNotContainsRe(
768
            differ.to_file.getvalue(),
769
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
770
             ' \@\@\n-old\n\+new\n\n')
771
        self.assertContainsRe(differ.to_file.getvalue(),
772
                              'was: old\nis: new\n')
773
3009.2.27 by Aaron Bentley
Use extra_factories instead of extra_diffs
774
    def test_extra_factories(self):
3009.2.16 by Aaron Bentley
Test support for extra differs
775
        self.create_old_new()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
776
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
777
                               extra_factories=[DiffWasIs.from_diff_tree])
3009.2.16 by Aaron Bentley
Test support for extra differs
778
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
779
        self.assertNotContainsRe(
780
            differ.to_file.getvalue(),
781
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
782
             ' \@\@\n-old\n\+new\n\n')
783
        self.assertContainsRe(differ.to_file.getvalue(),
784
                              'was: old\nis: new\n')
785
3123.4.1 by Aaron Bentley
Diff sorts files in alphabetical order
786
    def test_alphabetical_order(self):
787
        self.build_tree(['new-tree/a-file'])
788
        self.new_tree.add('a-file')
789
        self.build_tree(['old-tree/b-file'])
790
        self.old_tree.add('b-file')
791
        self.differ.show_diff(None)
792
        self.assertContainsRe(self.differ.to_file.getvalue(),
793
            '.*a-file(.|\n)*b-file')
794
3009.2.9 by Aaron Bentley
Add tests for Differ
795
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
796
class TestPatienceDiffLib(tests.TestCase):
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
797
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
798
    def setUp(self):
799
        super(TestPatienceDiffLib, self).setUp()
5168.1.3 by Vincent Ladeuil
Even more import fixes.
800
        self._unique_lcs = _patiencediff_py.unique_lcs_py
801
        self._recurse_matches = _patiencediff_py.recurse_matches_py
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
802
        self._PatienceSequenceMatcher = \
5168.1.3 by Vincent Ladeuil
Even more import fixes.
803
            _patiencediff_py.PatienceSequenceMatcher_py
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
804
3628.1.3 by Lukáš Lalinský
Add a test
805
    def test_diff_unicode_string(self):
806
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
807
        b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
808
        sm = self._PatienceSequenceMatcher(None, a, b)
809
        mb = sm.get_matching_blocks()
810
        self.assertEquals(35, len(mb))
811
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
812
    def test_unique_lcs(self):
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
813
        unique_lcs = self._unique_lcs
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
814
        self.assertEquals(unique_lcs('', ''), [])
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
815
        self.assertEquals(unique_lcs('', 'a'), [])
816
        self.assertEquals(unique_lcs('a', ''), [])
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
817
        self.assertEquals(unique_lcs('a', 'a'), [(0,0)])
818
        self.assertEquals(unique_lcs('a', 'b'), [])
819
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
820
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
821
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
822
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
823
                                                         (3,3), (4,4)])
824
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
825
826
    def test_recurse_matches(self):
827
        def test_one(a, b, matches):
828
            test_matches = []
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
829
            self._recurse_matches(
830
                a, b, 0, 0, len(a), len(b), test_matches, 10)
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
831
            self.assertEquals(test_matches, matches)
832
1711.2.17 by John Arbash Meinel
Small cleanups to patience_diff code.
833
        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,
834
                 [(0, 0), (2, 2), (4, 4)])
835
        test_one(['a', 'c', 'b', 'a', 'c'], ['a', 'b', 'c'],
836
                 [(0, 0), (2, 1), (4, 2)])
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
837
        # Even though 'bc' is not unique globally, and is surrounded by
838
        # non-matching lines, we should still match, because they are locally
839
        # unique
840
        test_one('abcdbce', 'afbcgdbce', [(0,0), (1, 2), (2, 3), (3, 5),
841
                                          (4, 6), (5, 7), (6, 8)])
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
842
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
843
        # recurse_matches doesn't match non-unique
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
844
        # lines surrounded by bogus text.
1185.81.24 by Aaron Bentley
Reoganize patience-related code
845
        # 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
846
847
        # This is what it could be
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
848
        #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
849
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
850
        # This is what it currently gives:
851
        test_one('aBccDe', 'abccde', [(0,0), (5,5)])
852
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
853
    def assertDiffBlocks(self, a, b, expected_blocks):
854
        """Check that the sequence matcher returns the correct blocks.
855
856
        :param a: A sequence to match
857
        :param b: Another sequence to match
858
        :param expected_blocks: The expected output, not including the final
859
            matching block (len(a), len(b), 0)
860
        """
861
        matcher = self._PatienceSequenceMatcher(None, a, b)
862
        blocks = matcher.get_matching_blocks()
863
        last = blocks.pop()
864
        self.assertEqual((len(a), len(b), 0), last)
865
        self.assertEqual(expected_blocks, blocks)
866
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
867
    def test_matching_blocks(self):
1185.81.2 by John Arbash Meinel
A couple small tests.
868
        # Some basic matching tests
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
869
        self.assertDiffBlocks('', '', [])
870
        self.assertDiffBlocks([], [], [])
871
        self.assertDiffBlocks('abc', '', [])
872
        self.assertDiffBlocks('', 'abc', [])
873
        self.assertDiffBlocks('abcd', 'abcd', [(0, 0, 4)])
874
        self.assertDiffBlocks('abcd', 'abce', [(0, 0, 3)])
875
        self.assertDiffBlocks('eabc', 'abce', [(1, 0, 3)])
876
        self.assertDiffBlocks('eabce', 'abce', [(1, 0, 4)])
877
        self.assertDiffBlocks('abcde', 'abXde', [(0, 0, 2), (3, 3, 2)])
878
        self.assertDiffBlocks('abcde', 'abXYZde', [(0, 0, 2), (3, 5, 2)])
879
        self.assertDiffBlocks('abde', 'abXYZde', [(0, 0, 2), (2, 5, 2)])
880
        # This may check too much, but it checks to see that
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
881
        # a copied block stays attached to the previous section,
882
        # not the later one.
883
        # difflib would tend to grab the trailing longest match
884
        # which would make the diff not look right
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
885
        self.assertDiffBlocks('abcdefghijklmnop', 'abcdefxydefghijklmnop',
886
                              [(0, 0, 6), (6, 11, 10)])
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
887
1185.81.2 by John Arbash Meinel
A couple small tests.
888
        # make sure it supports passing in lists
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
889
        self.assertDiffBlocks(
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
890
                   ['hello there\n',
891
                    'world\n',
892
                    'how are you today?\n'],
893
                   ['hello there\n',
894
                    'how are you today?\n'],
1185.81.2 by John Arbash Meinel
A couple small tests.
895
                [(0, 0, 1), (2, 1, 1)])
1185.81.1 by John Arbash Meinel
Adding nofrillsprecisemerge's diff algorithm, wrapped in difflib.
896
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
897
        # non unique lines surrounded by non-matching lines
898
        # won't be found
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
899
        self.assertDiffBlocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
900
901
        # But they only need to be locally unique
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
902
        self.assertDiffBlocks('aBcDec', 'abcdec', [(0,0,1), (2,2,1), (4,4,2)])
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
903
904
        # non unique blocks won't be matched
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
905
        self.assertDiffBlocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (8,8,1)])
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
906
907
        # but locally unique ones will
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
908
        self.assertDiffBlocks('aBcdEeXcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
909
                                              (5,4,1), (7,5,2), (10,8,1)])
910
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
911
        self.assertDiffBlocks('abbabbXd', 'cabbabxd', [(7,7,1)])
912
        self.assertDiffBlocks('abbabbbb', 'cabbabbc', [])
913
        self.assertDiffBlocks('bbbbbbbb', 'cbbbbbbc', [])
1185.81.11 by John Arbash Meinel
Found some edge cases that weren't being matched.
914
3074.2.1 by John Arbash Meinel
Change the C PatienceDiff implementation to support arbitrary objects.
915
    def test_matching_blocks_tuples(self):
916
        # Some basic matching tests
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
917
        self.assertDiffBlocks([], [], [])
918
        self.assertDiffBlocks([('a',), ('b',), ('c,')], [], [])
919
        self.assertDiffBlocks([], [('a',), ('b',), ('c,')], [])
920
        self.assertDiffBlocks([('a',), ('b',), ('c,')],
921
                              [('a',), ('b',), ('c,')],
922
                              [(0, 0, 3)])
923
        self.assertDiffBlocks([('a',), ('b',), ('c,')],
924
                              [('a',), ('b',), ('d,')],
925
                              [(0, 0, 2)])
926
        self.assertDiffBlocks([('d',), ('b',), ('c,')],
927
                              [('a',), ('b',), ('c,')],
928
                              [(1, 1, 2)])
929
        self.assertDiffBlocks([('d',), ('a',), ('b',), ('c,')],
930
                              [('a',), ('b',), ('c,')],
931
                              [(1, 0, 3)])
932
        self.assertDiffBlocks([('a', 'b'), ('c', 'd'), ('e', 'f')],
933
                              [('a', 'b'), ('c', 'X'), ('e', 'f')],
934
                              [(0, 0, 1), (2, 2, 1)])
935
        self.assertDiffBlocks([('a', 'b'), ('c', 'd'), ('e', 'f')],
936
                              [('a', 'b'), ('c', 'dX'), ('e', 'f')],
937
                              [(0, 0, 1), (2, 2, 1)])
3074.2.1 by John Arbash Meinel
Change the C PatienceDiff implementation to support arbitrary objects.
938
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
939
    def test_opcodes(self):
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
940
        def chk_ops(a, b, expected_codes):
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
941
            s = self._PatienceSequenceMatcher(None, a, b)
1711.2.10 by John Arbash Meinel
Clarify the patience tests a little bit.
942
            self.assertEquals(expected_codes, s.get_opcodes())
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
943
944
        chk_ops('', '', [])
945
        chk_ops([], [], [])
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
946
        chk_ops('abc', '', [('delete', 0,3, 0,0)])
947
        chk_ops('', 'abc', [('insert', 0,0, 0,3)])
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
948
        chk_ops('abcd', 'abcd', [('equal',    0,4, 0,4)])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
949
        chk_ops('abcd', 'abce', [('equal',   0,3, 0,3),
950
                                 ('replace', 3,4, 3,4)
951
                                ])
952
        chk_ops('eabc', 'abce', [('delete', 0,1, 0,0),
953
                                 ('equal',  1,4, 0,3),
954
                                 ('insert', 4,4, 3,4)
955
                                ])
956
        chk_ops('eabce', 'abce', [('delete', 0,1, 0,0),
957
                                  ('equal',  1,5, 0,4)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
958
                                 ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
959
        chk_ops('abcde', 'abXde', [('equal',   0,2, 0,2),
960
                                   ('replace', 2,3, 2,3),
961
                                   ('equal',   3,5, 3,5)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
962
                                  ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
963
        chk_ops('abcde', 'abXYZde', [('equal',   0,2, 0,2),
964
                                     ('replace', 2,3, 2,5),
965
                                     ('equal',   3,5, 5,7)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
966
                                    ])
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
967
        chk_ops('abde', 'abXYZde', [('equal',  0,2, 0,2),
968
                                    ('insert', 2,2, 2,5),
969
                                    ('equal',  2,4, 5,7)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
970
                                   ])
971
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
972
                [('equal',  0,6,  0,6),
973
                 ('insert', 6,6,  6,11),
974
                 ('equal',  6,16, 11,21)
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
975
                ])
976
        chk_ops(
977
                [ 'hello there\n'
978
                , 'world\n'
979
                , 'how are you today?\n'],
980
                [ 'hello there\n'
981
                , 'how are you today?\n'],
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
982
                [('equal',  0,1, 0,1),
983
                 ('delete', 1,2, 1,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
984
                 ('equal',  2,3, 1,2),
1185.81.9 by John Arbash Meinel
Added (failing) tests for cdv.recurse_matches with common sections,
985
                ])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
986
        chk_ops('aBccDe', 'abccde',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
987
                [('equal',   0,1, 0,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
988
                 ('replace', 1,5, 1,5),
989
                 ('equal',   5,6, 5,6),
990
                ])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
991
        chk_ops('aBcDec', 'abcdec',
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
992
                [('equal',   0,1, 0,1),
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
993
                 ('replace', 1,2, 1,2),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
994
                 ('equal',   2,3, 2,3),
995
                 ('replace', 3,4, 3,4),
996
                 ('equal',   4,6, 4,6),
1185.81.3 by John Arbash Meinel
Adding tests for checking opcodes.
997
                ])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
998
        chk_ops('aBcdEcdFg', 'abcdecdfg',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
999
                [('equal',   0,1, 0,1),
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
1000
                 ('replace', 1,8, 1,8),
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1001
                 ('equal',   8,9, 8,9)
1185.81.10 by John Arbash Meinel
Added some more test cases.
1002
                ])
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1003
        chk_ops('aBcdEeXcdFg', 'abcdecdfg',
1711.2.21 by John Arbash Meinel
Cleanup patiencediff, remove the use of difflib.SequenceMatcher.
1004
                [('equal',   0,1, 0,1),
1005
                 ('replace', 1,2, 1,2),
1006
                 ('equal',   2,4, 2,4),
1007
                 ('delete', 4,5, 4,4),
1008
                 ('equal',   5,6, 4,5),
1009
                 ('delete', 6,7, 5,5),
1010
                 ('equal',   7,9, 5,7),
1011
                 ('replace', 9,10, 7,8),
1012
                 ('equal',   10,11, 8,9)
1013
                ])
1185.81.10 by John Arbash Meinel
Added some more test cases.
1014
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1015
    def test_grouped_opcodes(self):
1016
        def chk_ops(a, b, expected_codes, n=3):
1017
            s = self._PatienceSequenceMatcher(None, a, b)
1018
            self.assertEquals(expected_codes, list(s.get_grouped_opcodes(n)))
1019
1020
        chk_ops('', '', [])
1021
        chk_ops([], [], [])
1022
        chk_ops('abc', '', [[('delete', 0,3, 0,0)]])
1023
        chk_ops('', 'abc', [[('insert', 0,0, 0,3)]])
1024
        chk_ops('abcd', 'abcd', [])
1025
        chk_ops('abcd', 'abce', [[('equal',   0,3, 0,3),
1026
                                  ('replace', 3,4, 3,4)
1027
                                 ]])
1028
        chk_ops('eabc', 'abce', [[('delete', 0,1, 0,0),
1029
                                 ('equal',  1,4, 0,3),
1030
                                 ('insert', 4,4, 3,4)
1031
                                ]])
1032
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1033
                [[('equal',  3,6, 3,6),
1034
                  ('insert', 6,6, 6,11),
1035
                  ('equal',  6,9, 11,14)
1036
                  ]])
1037
        chk_ops('abcdefghijklmnop', 'abcdefxydefghijklmnop',
1038
                [[('equal',  2,6, 2,6),
1039
                  ('insert', 6,6, 6,11),
1040
                  ('equal',  6,10, 11,15)
1041
                  ]], 4)
1042
        chk_ops('Xabcdef', 'abcdef',
1043
                [[('delete', 0,1, 0,0),
1044
                  ('equal',  1,4, 0,3)
1045
                  ]])
1046
        chk_ops('abcdef', 'abcdefX',
1047
                [[('equal',  3,6, 3,6),
1048
                  ('insert', 6,6, 6,7)
1049
                  ]])
1050
1051
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
1052
    def test_multiple_ranges(self):
1053
        # There was an earlier bug where we used a bad set of ranges,
1054
        # this triggers that specific bug, to make sure it doesn't regress
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
1055
        self.assertDiffBlocks('abcdefghijklmnop',
1056
                              'abcXghiYZQRSTUVWXYZijklmnop',
1057
                              [(0, 0, 3), (6, 4, 3), (9, 20, 7)])
1058
1059
        self.assertDiffBlocks('ABCd efghIjk  L',
1060
                              'AxyzBCn mo pqrstuvwI1 2  L',
1061
                              [(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.
1062
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
1063
        # These are rot13 code snippets.
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
1064
        self.assertDiffBlocks('''\
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
1065
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1066
    """
1067
    gnxrf_netf = ['svyr*']
1068
    gnxrf_bcgvbaf = ['ab-erphefr']
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1069
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
1070
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
1071
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
1072
        vs vf_dhvrg():
1073
            ercbegre = nqq_ercbegre_ahyy
1074
        ryfr:
1075
            ercbegre = nqq_ercbegre_cevag
1076
        fzneg_nqq(svyr_yvfg, abg ab_erphefr, ercbegre)
1077
1078
1079
pynff pzq_zxqve(Pbzznaq):
1080
'''.splitlines(True), '''\
1081
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1082
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1083
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl
1711.2.8 by John Arbash Meinel
rot13 the code snippet to help with clarity.
1084
    nqq gurz.
1085
    """
1086
    gnxrf_netf = ['svyr*']
1087
    gnxrf_bcgvbaf = ['ab-erphefr', 'qel-eha']
1088
1089
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr, qel_eha=Snyfr):
1090
        vzcbeg omeyvo.nqq
1091
1092
        vs qel_eha:
1093
            vs vf_dhvrg():
1094
                # Guvf vf cbvagyrff, ohg V'q engure abg envfr na reebe
1095
                npgvba = omeyvo.nqq.nqq_npgvba_ahyy
1096
            ryfr:
1097
  npgvba = omeyvo.nqq.nqq_npgvba_cevag
1098
        ryvs vf_dhvrg():
1099
            npgvba = omeyvo.nqq.nqq_npgvba_nqq
1100
        ryfr:
1101
       npgvba = omeyvo.nqq.nqq_npgvba_nqq_naq_cevag
1102
1103
        omeyvo.nqq.fzneg_nqq(svyr_yvfg, abg ab_erphefr, npgvba)
1104
1105
1106
pynff pzq_zxqve(Pbzznaq):
1185.81.16 by John Arbash Meinel
Added tests, and an assert check to make sure ranges are always increasing.
1107
'''.splitlines(True)
1108
, [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
1109
1711.2.9 by John Arbash Meinel
Rename cdv => patience
1110
    def test_patience_unified_diff(self):
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1111
        txt_a = ['hello there\n',
1112
                 'world\n',
1113
                 'how are you today?\n']
1114
        txt_b = ['hello there\n',
1115
                 'how are you today?\n']
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1116
        unified_diff = patiencediff.unified_diff
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1117
        psm = self._PatienceSequenceMatcher
3922.1.3 by John Arbash Meinel
fix some odd spacing.
1118
        self.assertEquals(['--- \n',
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1119
                           '+++ \n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1120
                           '@@ -1,3 +1,2 @@\n',
1121
                           ' hello there\n',
1122
                           '-world\n',
1123
                           ' 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
1124
                          ]
1711.2.20 by John Arbash Meinel
Late bind to patiencediff objects to make it easier to plug-in
1125
                          , list(unified_diff(txt_a, txt_b,
1126
                                 sequencematcher=psm)))
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1127
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1128
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1129
        # This is the result with LongestCommonSubstring matching
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1130
        self.assertEquals(['--- \n',
1131
                           '+++ \n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1132
                           '@@ -1,6 +1,11 @@\n',
1133
                           ' a\n',
1134
                           ' b\n',
1135
                           ' c\n',
1136
                           '+d\n',
1137
                           '+e\n',
1138
                           '+f\n',
1139
                           '+x\n',
1140
                           '+y\n',
1141
                           ' d\n',
1142
                           ' e\n',
1143
                           ' f\n']
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1144
                          , list(unified_diff(txt_a, txt_b)))
1711.2.9 by John Arbash Meinel
Rename cdv => patience
1145
        # And the patience diff
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1146
        self.assertEquals(['--- \n',
1147
                           '+++ \n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1148
                           '@@ -4,6 +4,11 @@\n',
1149
                           ' d\n',
1150
                           ' e\n',
1151
                           ' f\n',
1152
                           '+x\n',
1153
                           '+y\n',
1154
                           '+d\n',
1155
                           '+e\n',
1156
                           '+f\n',
1157
                           ' g\n',
1158
                           ' h\n',
1159
                           ' i\n',
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1160
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
1161
                          , 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
1162
                                 sequencematcher=psm)))
1185.81.25 by Aaron Bentley
Clean up test_diff
1163
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1164
    def test_patience_unified_diff_with_dates(self):
1165
        txt_a = ['hello there\n',
1166
                 'world\n',
1167
                 'how are you today?\n']
1168
        txt_b = ['hello there\n',
1169
                 'how are you today?\n']
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1170
        unified_diff = patiencediff.unified_diff
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1171
        psm = self._PatienceSequenceMatcher
3922.1.4 by John Arbash Meinel
It turns out that internal_diff worked around the trailing whitespace problem
1172
        self.assertEquals(['--- a\t2008-08-08\n',
1173
                           '+++ b\t2008-09-09\n',
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1174
                           '@@ -1,3 +1,2 @@\n',
1175
                           ' hello there\n',
1176
                           '-world\n',
1177
                           ' how are you today?\n'
1178
                          ]
1179
                          , list(unified_diff(txt_a, txt_b,
1180
                                 fromfile='a', tofile='b',
1181
                                 fromfiledate='2008-08-08',
1182
                                 tofiledate='2008-09-09',
1183
                                 sequencematcher=psm)))
1184
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1185
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1186
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1187
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
1188
    _test_needs_features = [compiled_patiencediff_feature]
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1189
1190
    def setUp(self):
1191
        super(TestPatienceDiffLib_c, self).setUp()
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1192
        from bzrlib import _patiencediff_c
1193
        self._unique_lcs = _patiencediff_c.unique_lcs_c
1194
        self._recurse_matches = _patiencediff_c.recurse_matches_c
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1195
        self._PatienceSequenceMatcher = \
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1196
            _patiencediff_c.PatienceSequenceMatcher_c
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1197
3074.2.3 by John Arbash Meinel
Enable some error checking, and small amount of code cleanup.
1198
    def test_unhashable(self):
1199
        """We should get a proper exception here."""
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
1200
        # We need to be able to hash items in the sequence, lists are
1201
        # unhashable, and thus cannot be diffed
3074.2.3 by John Arbash Meinel
Enable some error checking, and small amount of code cleanup.
1202
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1203
                                         None, [[]], [])
3074.2.10 by John Arbash Meinel
Cleanup the test cases (Andrew)
1204
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1205
                                         None, ['valid', []], [])
1206
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1207
                                         None, ['valid'], [[]])
1208
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
1209
                                         None, ['valid'], ['valid', []])
3074.2.3 by John Arbash Meinel
Enable some error checking, and small amount of code cleanup.
1210
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1211
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1212
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1213
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1214
    def setUp(self):
1215
        super(TestPatienceDiffLibFiles, self).setUp()
1216
        self._PatienceSequenceMatcher = \
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1217
            _patiencediff_py.PatienceSequenceMatcher_py
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1218
1711.2.9 by John Arbash Meinel
Rename cdv => patience
1219
    def test_patience_unified_diff_files(self):
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1220
        txt_a = ['hello there\n',
1221
                 'world\n',
1222
                 'how are you today?\n']
1223
        txt_b = ['hello there\n',
1224
                 '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
1225
        open('a1', 'wb').writelines(txt_a)
1226
        open('b1', 'wb').writelines(txt_b)
1227
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1228
        unified_diff_files = patiencediff.unified_diff_files
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1229
        psm = self._PatienceSequenceMatcher
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1230
        self.assertEquals(['--- a1\n',
1231
                           '+++ b1\n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1232
                           '@@ -1,3 +1,2 @@\n',
1233
                           ' hello there\n',
1234
                           '-world\n',
1235
                           ' 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
1236
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
1237
                          , 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
1238
                                 sequencematcher=psm)))
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1239
1240
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1241
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1242
        open('a2', 'wb').writelines(txt_a)
1243
        open('b2', 'wb').writelines(txt_b)
1244
1245
        # This is the result with LongestCommonSubstring matching
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1246
        self.assertEquals(['--- a2\n',
1247
                           '+++ b2\n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1248
                           '@@ -1,6 +1,11 @@\n',
1249
                           ' a\n',
1250
                           ' b\n',
1251
                           ' c\n',
1252
                           '+d\n',
1253
                           '+e\n',
1254
                           '+f\n',
1255
                           '+x\n',
1256
                           '+y\n',
1257
                           ' d\n',
1258
                           ' e\n',
1259
                           ' f\n']
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1260
                          , list(unified_diff_files('a2', 'b2')))
1261
1711.2.9 by John Arbash Meinel
Rename cdv => patience
1262
        # And the patience diff
3922.1.2 by John Arbash Meinel
Update the test cases for the new patience diff code.
1263
        self.assertEquals(['--- a2\n',
1264
                           '+++ b2\n',
1185.81.29 by Aaron Bentley
Fix style issues and duplicated tests
1265
                           '@@ -4,6 +4,11 @@\n',
1266
                           ' d\n',
1267
                           ' e\n',
1268
                           ' f\n',
1269
                           '+x\n',
1270
                           '+y\n',
1271
                           '+d\n',
1272
                           '+e\n',
1273
                           '+f\n',
1274
                           ' g\n',
1275
                           ' h\n',
1276
                           ' i\n',
1185.81.14 by John Arbash Meinel
Added a main function for running cdvdifflib manually, included tests for unified_diff interfaces
1277
                          ]
1185.81.25 by Aaron Bentley
Clean up test_diff
1278
                          , 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
1279
                                 sequencematcher=psm)))
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1280
1281
1282
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1283
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
1284
    _test_needs_features = [compiled_patiencediff_feature]
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1285
1286
    def setUp(self):
1287
        super(TestPatienceDiffLibFiles_c, self).setUp()
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1288
        from bzrlib import _patiencediff_c
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1289
        self._PatienceSequenceMatcher = \
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1290
            _patiencediff_c.PatienceSequenceMatcher_c
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1291
1292
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1293
class TestUsingCompiledIfAvailable(tests.TestCase):
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1294
1295
    def test_PatienceSequenceMatcher(self):
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
1296
        if compiled_patiencediff_feature.available():
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1297
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1298
            self.assertIs(PatienceSequenceMatcher_c,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1299
                          patiencediff.PatienceSequenceMatcher)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1300
        else:
1301
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1302
            self.assertIs(PatienceSequenceMatcher_py,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1303
                          patiencediff.PatienceSequenceMatcher)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1304
1305
    def test_unique_lcs(self):
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
1306
        if compiled_patiencediff_feature.available():
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1307
            from bzrlib._patiencediff_c import unique_lcs_c
1308
            self.assertIs(unique_lcs_c,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1309
                          patiencediff.unique_lcs)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1310
        else:
1311
            from bzrlib._patiencediff_py import unique_lcs_py
1312
            self.assertIs(unique_lcs_py,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1313
                          patiencediff.unique_lcs)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1314
1315
    def test_recurse_matches(self):
4913.2.20 by John Arbash Meinel
Change all of the compiled_foo to compiled_foo_feature
1316
        if compiled_patiencediff_feature.available():
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1317
            from bzrlib._patiencediff_c import recurse_matches_c
1318
            self.assertIs(recurse_matches_c,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1319
                          patiencediff.recurse_matches)
2781.1.1 by Martin Pool
merge cpatiencediff from Lukas
1320
        else:
1321
            from bzrlib._patiencediff_py import recurse_matches_py
1322
            self.assertIs(recurse_matches_py,
5168.1.3 by Vincent Ladeuil
Even more import fixes.
1323
                          patiencediff.recurse_matches)
3123.6.2 by Aaron Bentley
Implement diff --using natively
1324
1325
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1326
class TestDiffFromTool(tests.TestCaseWithTransport):
3123.6.2 by Aaron Bentley
Implement diff --using natively
1327
1328
    def test_from_string(self):
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1329
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
3123.6.2 by Aaron Bentley
Implement diff --using natively
1330
        self.addCleanup(diff_obj.finish)
4603.1.20 by Aaron Bentley
Use string.Template substitution with @ as delimiter.
1331
        self.assertEqual(['diff', '@old_path', '@new_path'],
3123.6.2 by Aaron Bentley
Implement diff --using natively
1332
            diff_obj.command_template)
3199.1.6 by Vincent Ladeuil
Fiz last leaking tmp dir.
1333
1334
    def test_from_string_u5(self):
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1335
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
1336
                                                 None, None, None)
3199.1.6 by Vincent Ladeuil
Fiz last leaking tmp dir.
1337
        self.addCleanup(diff_obj.finish)
4603.1.20 by Aaron Bentley
Use string.Template substitution with @ as delimiter.
1338
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
3123.6.2 by Aaron Bentley
Implement diff --using natively
1339
                         diff_obj.command_template)
1340
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1341
                         diff_obj._get_command('old-path', 'new-path'))
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1342
4913.5.8 by Gordon Tyler
Added test_from_string_path_with_backslashes, which tests the actual scenario in bug 392428.
1343
    def test_from_string_path_with_backslashes(self):
5241.2.2 by Robert Collins
Missed one test.
1344
        self.requireFeature(features.backslashdir_feature)
4913.5.8 by Gordon Tyler
Added test_from_string_path_with_backslashes, which tests the actual scenario in bug 392428.
1345
        tool = 'C:\\Tools\\Diff.exe'
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1346
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
4913.5.8 by Gordon Tyler
Added test_from_string_path_with_backslashes, which tests the actual scenario in bug 392428.
1347
        self.addCleanup(diff_obj.finish)
1348
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
1349
                         diff_obj.command_template)
1350
        self.assertEqual(['C:\\Tools\\Diff.exe', 'old-path', 'new-path'],
1351
                         diff_obj._get_command('old-path', 'new-path'))
3123.6.2 by Aaron Bentley
Implement diff --using natively
1352
1353
    def test_execute(self):
1354
        output = StringIO()
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1355
        diff_obj = diff.DiffFromTool(['python', '-c',
1356
                                      'print "@old_path @new_path"'],
1357
                                     None, None, output)
3123.6.2 by Aaron Bentley
Implement diff --using natively
1358
        self.addCleanup(diff_obj.finish)
1359
        diff_obj._execute('old', 'new')
3146.4.2 by Aaron Bentley
Avoid assuming unix newline on output
1360
        self.assertEqual(output.getvalue().rstrip(), 'old new')
3123.6.2 by Aaron Bentley
Implement diff --using natively
1361
3145.1.1 by Aaron Bentley
Handle missing tools gracefully in diff --using
1362
    def test_excute_missing(self):
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1363
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1364
                                     None, None, None)
3145.1.1 by Aaron Bentley
Handle missing tools gracefully in diff --using
1365
        self.addCleanup(diff_obj.finish)
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1366
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
1367
                              'old', 'new')
3145.1.1 by Aaron Bentley
Handle missing tools gracefully in diff --using
1368
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1369
                         ' on this machine', str(e))
1370
3287.18.22 by Matt McClure
Reverts to prior decomposition of exercise and verification, as suggested
1371
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
3287.18.20 by Matt McClure
Introduces a Feature subclass to encapsulate the availability of 'attrib'.
1372
        self.requireFeature(AttribFeature)
3287.18.10 by Matt McClure
Uses TestSkipped for test_execute_windows_tool on non-Windows platforms.
1373
        output = StringIO()
1374
        tree = self.make_branch_and_tree('tree')
1375
        self.build_tree_contents([('tree/file', 'content')])
1376
        tree.add('file', 'file-id')
3287.18.11 by Matt McClure
Removed unnecessary timestamp parameter.
1377
        tree.commit('old tree')
3287.18.10 by Matt McClure
Uses TestSkipped for test_execute_windows_tool on non-Windows platforms.
1378
        tree.lock_read()
1379
        self.addCleanup(tree.unlock)
4873.3.1 by John Arbash Meinel
Now that we return files directly from the working tree
1380
        basis_tree = tree.basis_tree()
1381
        basis_tree.lock_read()
1382
        self.addCleanup(basis_tree.unlock)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1383
        diff_obj = diff.DiffFromTool(['python', '-c',
1384
                                      'print "@old_path @new_path"'],
1385
                                     basis_tree, tree, output)
3287.18.22 by Matt McClure
Reverts to prior decomposition of exercise and verification, as suggested
1386
        diff_obj._prepare_files('file-id', 'file', 'file')
4873.3.1 by John Arbash Meinel
Now that we return files directly from the working tree
1387
        # The old content should be readonly
1388
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
1389
                                    r'R.*old\\file$')
1390
        # The new content should use the tree object, not a 'new' file anymore
1391
        self.assertEndsWith(tree.basedir, 'work/tree')
1392
        self.assertReadableByAttrib(tree.basedir, 'file', r'work\\tree\\file$')
3287.18.22 by Matt McClure
Reverts to prior decomposition of exercise and verification, as suggested
1393
1394
    def assertReadableByAttrib(self, cwd, relpath, regex):
1395
        proc = subprocess.Popen(['attrib', relpath],
1396
                                stdout=subprocess.PIPE,
1397
                                cwd=cwd)
4873.3.1 by John Arbash Meinel
Now that we return files directly from the working tree
1398
        (result, err) = proc.communicate()
1399
        self.assertContainsRe(result.replace('\r\n', '\n'), regex)
3287.18.9 by Matt McClure
Adds a test asserting that a Windows tool that understands forward slashes
1400
3123.6.2 by Aaron Bentley
Implement diff --using natively
1401
    def test_prepare_files(self):
1402
        output = StringIO()
1403
        tree = self.make_branch_and_tree('tree')
3123.6.5 by Aaron Bentley
Symlink to real files if possible
1404
        self.build_tree_contents([('tree/oldname', 'oldcontent')])
3287.18.23 by Matt McClure
Adds comments that document my understanding of
1405
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
3123.6.5 by Aaron Bentley
Symlink to real files if possible
1406
        tree.add('oldname', 'file-id')
3287.18.23 by Matt McClure
Adds comments that document my understanding of
1407
        tree.add('oldname2', 'file2-id')
5151.3.1 by Martin
Fix os.utime test failures, three on FAT filesystems and one with readonly files
1408
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
1409
        tree.commit('old tree', timestamp=315532800)
3123.6.5 by Aaron Bentley
Symlink to real files if possible
1410
        tree.rename_one('oldname', 'newname')
3287.18.23 by Matt McClure
Adds comments that document my understanding of
1411
        tree.rename_one('oldname2', 'newname2')
3123.6.5 by Aaron Bentley
Symlink to real files if possible
1412
        self.build_tree_contents([('tree/newname', 'newcontent')])
3287.19.1 by Matt McClure
Fixes https://bugs.launchpad.net/bzr/+bug/212289. I submitted this patch.
1413
        self.build_tree_contents([('tree/newname2', 'newcontent2')])
3123.6.2 by Aaron Bentley
Implement diff --using natively
1414
        old_tree = tree.basis_tree()
1415
        old_tree.lock_read()
1416
        self.addCleanup(old_tree.unlock)
3123.6.4 by Aaron Bentley
Set mtime (and atime) on files for --using
1417
        tree.lock_read()
1418
        self.addCleanup(tree.unlock)
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1419
        diff_obj = diff.DiffFromTool(['python', '-c',
1420
                                      'print "@old_path @new_path"'],
1421
                                     old_tree, tree, output)
3123.6.2 by Aaron Bentley
Implement diff --using natively
1422
        self.addCleanup(diff_obj.finish)
1423
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1424
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1425
                                                     'newname')
1426
        self.assertContainsRe(old_path, 'old/oldname$')
5151.3.1 by Martin
Fix os.utime test failures, three on FAT filesystems and one with readonly files
1427
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
4845.2.1 by Gary van der Merwe
When launching an external diff app, don't write temporary files for a working tree.
1428
        self.assertContainsRe(new_path, 'tree/newname$')
3123.6.2 by Aaron Bentley
Implement diff --using natively
1429
        self.assertFileEqual('oldcontent', old_path)
1430
        self.assertFileEqual('newcontent', new_path)
3287.18.14 by Matt McClure
Extracted a host_os_dereferences_symlinks method.
1431
        if osutils.host_os_dereferences_symlinks():
3123.6.5 by Aaron Bentley
Symlink to real files if possible
1432
            self.assertTrue(os.path.samefile('tree/newname', new_path))
3123.6.2 by Aaron Bentley
Implement diff --using natively
1433
        # make sure we can create files with the same parent directories
3287.18.25 by Matt McClure
Uses the correct file_id as the argument to _prepare_files.
1434
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1435
1436
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1437
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
1438
1439
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
1440
        """Call get_trees_and_branches_to_diff_locked.  Overridden by
1441
        TestGetTreesAndBranchesToDiff.
1442
        """
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1443
        return diff.get_trees_and_branches_to_diff_locked(
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
1444
            path_list, revision_specs, old_url, new_url, self.addCleanup)
4732.1.2 by Vincent Ladeuil
(trivial) Fix some PEP8 issues
1445
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1446
    def test_basic(self):
1447
        tree = self.make_branch_and_tree('tree')
1448
        (old_tree, new_tree,
1449
         old_branch, new_branch,
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
1450
         specific_files, extra_trees) = self.call_gtabtd(
1451
             ['tree'], None, None, None)
4732.1.2 by Vincent Ladeuil
(trivial) Fix some PEP8 issues
1452
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1453
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1454
        self.assertEqual(_mod_revision.NULL_REVISION,
1455
                         old_tree.get_revision_id())
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1456
        self.assertEqual(tree.basedir, new_tree.basedir)
1457
        self.assertEqual(tree.branch.base, old_branch.base)
1458
        self.assertEqual(tree.branch.base, new_branch.base)
1459
        self.assertIs(None, specific_files)
1460
        self.assertIs(None, extra_trees)
1461
1462
    def test_with_rev_specs(self):
1463
        tree = self.make_branch_and_tree('tree')
1464
        self.build_tree_contents([('tree/file', 'oldcontent')])
1465
        tree.add('file', 'file-id')
1466
        tree.commit('old tree', timestamp=0, rev_id="old-id")
1467
        self.build_tree_contents([('tree/file', 'newcontent')])
1468
        tree.commit('new tree', timestamp=0, rev_id="new-id")
4732.1.2 by Vincent Ladeuil
(trivial) Fix some PEP8 issues
1469
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1470
        revisions = [revisionspec.RevisionSpec.from_string('1'),
1471
                     revisionspec.RevisionSpec.from_string('2')]
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1472
        (old_tree, new_tree,
1473
         old_branch, new_branch,
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
1474
         specific_files, extra_trees) = self.call_gtabtd(
1475
            ['tree'], revisions, None, None)
4732.1.2 by Vincent Ladeuil
(trivial) Fix some PEP8 issues
1476
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1477
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1478
        self.assertEqual("old-id", old_tree.get_revision_id())
5168.1.2 by Vincent Ladeuil
Ckeanup some more imports.
1479
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
4705.1.2 by Gary van der Merwe
Start on tests for get_trees_and_branches_to_diff.
1480
        self.assertEqual("new-id", new_tree.get_revision_id())
1481
        self.assertEqual(tree.branch.base, old_branch.base)
1482
        self.assertEqual(tree.branch.base, new_branch.base)
1483
        self.assertIs(None, specific_files)
4705.1.4 by Gary van der Merwe
Add newline to end of test_diff.py
1484
        self.assertEqual(tree.basedir, extra_trees[0].basedir)
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
1485
1486
1487
class TestGetTreesAndBranchesToDiff(TestGetTreesAndBranchesToDiffLocked):
1488
    """Apply the tests for get_trees_and_branches_to_diff_locked to the
1489
    deprecated get_trees_and_branches_to_diff function.
1490
    """
1491
1492
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
1493
        return self.applyDeprecated(
5168.1.4 by Vincent Ladeuil
Final import fixes for bt.test_diff.
1494
            deprecated_in((2, 2, 0)), diff.get_trees_and_branches_to_diff,
5147.3.7 by Andrew Bennetts
Expect DeprecationWarnings for get_trees_and_branches_to_diff in test_diff, and add corresponding test coverage for get_trees_and_branches_to_diff_locked.
1495
            path_list, revision_specs, old_url, new_url)
1496