~bzr-pqm/bzr/bzr.dev

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