/brz/remove-bazaar

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