~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2011-08-17 18:13:57 UTC
  • mfrom: (5268.7.29 transport-segments)
  • Revision ID: pqm@pqm.ubuntu.com-20110817181357-y5q5eth1hk8bl3om
(jelmer) Allow specifying the colocated branch to use in the branch URL,
 and retrieving the branch name using ControlDir._get_selected_branch.
 (Jelmer Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
 
import os.path
19
18
from cStringIO import StringIO
20
 
import errno
21
19
import subprocess
22
20
import sys
23
 
from tempfile import TemporaryFile
24
 
 
25
 
from bzrlib import tests
26
 
from bzrlib.diff import (
27
 
    DiffFromTool,
28
 
    DiffPath,
29
 
    DiffSymlink,
30
 
    DiffTree,
31
 
    DiffText,
32
 
    external_diff,
33
 
    internal_diff,
34
 
    show_diff_trees,
35
 
    get_trees_and_branches_to_diff,
36
 
    )
37
 
from bzrlib.errors import BinaryFile, NoDiff, ExecutableMissing
38
 
import bzrlib.osutils as osutils
39
 
import bzrlib.revision as _mod_revision
40
 
import bzrlib.transform as transform
41
 
import bzrlib.patiencediff
42
 
import bzrlib._patiencediff_py
43
 
from bzrlib.tests import (Feature, TestCase, TestCaseWithTransport,
44
 
                          TestCaseInTempDir, TestSkipped)
45
 
from bzrlib.revisiontree import RevisionTree
46
 
from bzrlib.revisionspec import RevisionSpec
47
 
 
48
 
 
49
 
class _AttribFeature(Feature):
50
 
 
51
 
    def _probe(self):
52
 
        if (sys.platform not in ('cygwin', 'win32')):
53
 
            return False
54
 
        try:
55
 
            proc = subprocess.Popen(['attrib', '.'], stdout=subprocess.PIPE)
56
 
        except OSError, e:
57
 
            return False
58
 
        return (0 == proc.wait())
59
 
 
60
 
    def feature_name(self):
61
 
        return 'attrib Windows command-line tool'
62
 
 
63
 
AttribFeature = _AttribFeature()
64
 
 
65
 
 
66
 
compiled_patiencediff_feature = tests.ModuleAvailableFeature(
67
 
                                    'bzrlib._patiencediff_c')
 
21
import tempfile
 
22
 
 
23
from bzrlib import (
 
24
    diff,
 
25
    errors,
 
26
    osutils,
 
27
    patiencediff,
 
28
    _patiencediff_py,
 
29
    revision as _mod_revision,
 
30
    revisionspec,
 
31
    revisiontree,
 
32
    tests,
 
33
    transform,
 
34
    )
 
35
from bzrlib.symbol_versioning import deprecated_in
 
36
from bzrlib.tests import features, EncodingAdapter
 
37
from bzrlib.tests.blackbox.test_diff import subst_dates
 
38
from bzrlib.tests import (
 
39
    features,
 
40
    )
68
41
 
69
42
 
70
43
def udiff_lines(old, new, allow_binary=False):
71
44
    output = StringIO()
72
 
    internal_diff('old', old, 'new', new, output, allow_binary)
 
45
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
73
46
    output.seek(0, 0)
74
47
    return output.readlines()
75
48
 
79
52
        # StringIO has no fileno, so it tests a different codepath
80
53
        output = StringIO()
81
54
    else:
82
 
        output = TemporaryFile()
 
55
        output = tempfile.TemporaryFile()
83
56
    try:
84
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
85
 
    except NoDiff:
86
 
        raise TestSkipped('external "diff" not present to test')
 
57
        diff.external_diff('old', old, 'new', new, output, diff_opts=['-u'])
 
58
    except errors.NoDiff:
 
59
        raise tests.TestSkipped('external "diff" not present to test')
87
60
    output.seek(0, 0)
88
61
    lines = output.readlines()
89
62
    output.close()
90
63
    return lines
91
64
 
92
65
 
93
 
class TestDiff(TestCase):
 
66
class TestDiff(tests.TestCase):
94
67
 
95
68
    def test_add_nl(self):
96
69
        """diff generates a valid diff for patches that add a newline"""
132
105
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
133
106
 
134
107
    def test_binary_lines(self):
135
 
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
136
 
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
137
 
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
138
 
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
 
108
        empty = []
 
109
        uni_lines = [1023 * 'a' + '\x00']
 
110
        self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines , empty)
 
111
        self.assertRaises(errors.BinaryFile, udiff_lines, empty, uni_lines)
 
112
        udiff_lines(uni_lines , empty, allow_binary=True)
 
113
        udiff_lines(empty, uni_lines, allow_binary=True)
139
114
 
140
115
    def test_external_diff(self):
141
116
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
151
126
        self.check_patch(lines)
152
127
 
153
128
    def test_external_diff_binary_lang_c(self):
154
 
        old_env = {}
155
129
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
156
 
            old_env[lang] = osutils.set_or_unset_env(lang, 'C')
157
 
        try:
158
 
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
159
 
            # Older versions of diffutils say "Binary files", newer
160
 
            # versions just say "Files".
161
 
            self.assertContainsRe(lines[0],
162
 
                                  '(Binary f|F)iles old and new differ\n')
163
 
            self.assertEquals(lines[1:], ['\n'])
164
 
        finally:
165
 
            for lang, old_val in old_env.iteritems():
166
 
                osutils.set_or_unset_env(lang, old_val)
 
130
            self.overrideEnv(lang, 'C')
 
131
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
 
132
        # Older versions of diffutils say "Binary files", newer
 
133
        # versions just say "Files".
 
134
        self.assertContainsRe(lines[0], '(Binary f|F)iles old and new differ\n')
 
135
        self.assertEquals(lines[1:], ['\n'])
167
136
 
168
137
    def test_no_external_diff(self):
169
138
        """Check that NoDiff is raised when diff is not available"""
170
 
        # Use os.environ['PATH'] to make sure no 'diff' command is available
171
 
        orig_path = os.environ['PATH']
172
 
        try:
173
 
            os.environ['PATH'] = ''
174
 
            self.assertRaises(NoDiff, external_diff,
175
 
                              'old', ['boo\n'], 'new', ['goo\n'],
176
 
                              StringIO(), diff_opts=['-u'])
177
 
        finally:
178
 
            os.environ['PATH'] = orig_path
 
139
        # Make sure no 'diff' command is available
 
140
        # XXX: Weird, using None instead of '' breaks the test -- vila 20101216
 
141
        self.overrideEnv('PATH', '')
 
142
        self.assertRaises(errors.NoDiff, diff.external_diff,
 
143
                          'old', ['boo\n'], 'new', ['goo\n'],
 
144
                          StringIO(), diff_opts=['-u'])
179
145
 
180
146
    def test_internal_diff_default(self):
181
147
        # Default internal diff encoding is utf8
182
148
        output = StringIO()
183
 
        internal_diff(u'old_\xb5', ['old_text\n'],
184
 
                    u'new_\xe5', ['new_text\n'], output)
 
149
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
150
                           u'new_\xe5', ['new_text\n'], output)
185
151
        lines = output.getvalue().splitlines(True)
186
152
        self.check_patch(lines)
187
153
        self.assertEquals(['--- old_\xc2\xb5\n',
195
161
 
196
162
    def test_internal_diff_utf8(self):
197
163
        output = StringIO()
198
 
        internal_diff(u'old_\xb5', ['old_text\n'],
199
 
                    u'new_\xe5', ['new_text\n'], output,
200
 
                    path_encoding='utf8')
 
164
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
165
                           u'new_\xe5', ['new_text\n'], output,
 
166
                           path_encoding='utf8')
201
167
        lines = output.getvalue().splitlines(True)
202
168
        self.check_patch(lines)
203
169
        self.assertEquals(['--- old_\xc2\xb5\n',
211
177
 
212
178
    def test_internal_diff_iso_8859_1(self):
213
179
        output = StringIO()
214
 
        internal_diff(u'old_\xb5', ['old_text\n'],
215
 
                    u'new_\xe5', ['new_text\n'], output,
216
 
                    path_encoding='iso-8859-1')
 
180
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
181
                           u'new_\xe5', ['new_text\n'], output,
 
182
                           path_encoding='iso-8859-1')
217
183
        lines = output.getvalue().splitlines(True)
218
184
        self.check_patch(lines)
219
185
        self.assertEquals(['--- old_\xb5\n',
227
193
 
228
194
    def test_internal_diff_no_content(self):
229
195
        output = StringIO()
230
 
        internal_diff(u'old', [], u'new', [], output)
 
196
        diff.internal_diff(u'old', [], u'new', [], output)
231
197
        self.assertEqual('', output.getvalue())
232
198
 
233
199
    def test_internal_diff_no_changes(self):
234
200
        output = StringIO()
235
 
        internal_diff(u'old', ['text\n', 'contents\n'],
236
 
                      u'new', ['text\n', 'contents\n'],
237
 
                      output)
 
201
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
 
202
                           u'new', ['text\n', 'contents\n'],
 
203
                           output)
238
204
        self.assertEqual('', output.getvalue())
239
205
 
240
206
    def test_internal_diff_returns_bytes(self):
241
207
        import StringIO
242
208
        output = StringIO.StringIO()
243
 
        internal_diff(u'old_\xb5', ['old_text\n'],
244
 
                    u'new_\xe5', ['new_text\n'], output)
245
 
        self.failUnless(isinstance(output.getvalue(), str),
 
209
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
210
                            u'new_\xe5', ['new_text\n'], output)
 
211
        self.assertIsInstance(output.getvalue(), str,
246
212
            'internal_diff should return bytestrings')
247
213
 
248
214
 
249
 
class TestDiffFiles(TestCaseInTempDir):
 
215
class TestDiffFiles(tests.TestCaseInTempDir):
250
216
 
251
217
    def test_external_diff_binary(self):
252
218
        """The output when using external diff should use diff's i18n error"""
265
231
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
266
232
 
267
233
 
268
 
class TestShowDiffTreesHelper(TestCaseWithTransport):
269
 
    """Has a helper for running show_diff_trees"""
270
 
 
271
 
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
272
 
        output = StringIO()
273
 
        if working_tree is not None:
274
 
            extra_trees = (working_tree,)
275
 
        else:
276
 
            extra_trees = ()
277
 
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
278
 
                        extra_trees=extra_trees, old_label='old/',
279
 
                        new_label='new/')
280
 
        return output.getvalue()
281
 
 
282
 
 
283
 
class TestDiffDates(TestShowDiffTreesHelper):
 
234
def get_diff_as_string(tree1, tree2, specific_files=None, working_tree=None):
 
235
    output = StringIO()
 
236
    if working_tree is not None:
 
237
        extra_trees = (working_tree,)
 
238
    else:
 
239
        extra_trees = ()
 
240
    diff.show_diff_trees(tree1, tree2, output,
 
241
        specific_files=specific_files,
 
242
        extra_trees=extra_trees, old_label='old/',
 
243
        new_label='new/')
 
244
    return output.getvalue()
 
245
 
 
246
 
 
247
class TestDiffDates(tests.TestCaseWithTransport):
284
248
 
285
249
    def setUp(self):
286
250
        super(TestDiffDates, self).setUp()
321
285
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
322
286
 
323
287
    def test_diff_rev_tree_working_tree(self):
324
 
        output = self.get_diff(self.wt.basis_tree(), self.wt)
 
288
        output = get_diff_as_string(self.wt.basis_tree(), self.wt)
325
289
        # note that the date for old/file1 is from rev 2 rather than from
326
290
        # the basis revision (rev 4)
327
291
        self.assertEqualDiff(output, '''\
337
301
    def test_diff_rev_tree_rev_tree(self):
338
302
        tree1 = self.b.repository.revision_tree('rev-2')
339
303
        tree2 = self.b.repository.revision_tree('rev-3')
340
 
        output = self.get_diff(tree1, tree2)
 
304
        output = get_diff_as_string(tree1, tree2)
341
305
        self.assertEqualDiff(output, '''\
342
306
=== modified file 'file2'
343
307
--- old/file2\t2006-04-01 00:00:00 +0000
351
315
    def test_diff_add_files(self):
352
316
        tree1 = self.b.repository.revision_tree(_mod_revision.NULL_REVISION)
353
317
        tree2 = self.b.repository.revision_tree('rev-1')
354
 
        output = self.get_diff(tree1, tree2)
 
318
        output = get_diff_as_string(tree1, tree2)
355
319
        # the files have the epoch time stamp for the tree in which
356
320
        # they don't exist.
357
321
        self.assertEqualDiff(output, '''\
372
336
    def test_diff_remove_files(self):
373
337
        tree1 = self.b.repository.revision_tree('rev-3')
374
338
        tree2 = self.b.repository.revision_tree('rev-4')
375
 
        output = self.get_diff(tree1, tree2)
 
339
        output = get_diff_as_string(tree1, tree2)
376
340
        # the file has the epoch time stamp for the tree in which
377
341
        # it doesn't exist.
378
342
        self.assertEqualDiff(output, '''\
389
353
        self.wt.rename_one('file1', 'file1b')
390
354
        old_tree = self.b.repository.revision_tree('rev-1')
391
355
        new_tree = self.b.repository.revision_tree('rev-4')
392
 
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'],
 
356
        out = get_diff_as_string(old_tree, new_tree, specific_files=['file1b'],
393
357
                            working_tree=self.wt)
394
358
        self.assertContainsRe(out, 'file1\t')
395
359
 
401
365
        self.wt.rename_one('file1', 'dir1/file1')
402
366
        old_tree = self.b.repository.revision_tree('rev-1')
403
367
        new_tree = self.b.repository.revision_tree('rev-4')
404
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'],
 
368
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir1'],
405
369
                            working_tree=self.wt)
406
370
        self.assertContainsRe(out, 'file1\t')
407
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'],
 
371
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir2'],
408
372
                            working_tree=self.wt)
409
373
        self.assertNotContainsRe(out, 'file1\t')
410
374
 
411
375
 
412
 
 
413
 
class TestShowDiffTrees(TestShowDiffTreesHelper):
 
376
class TestShowDiffTrees(tests.TestCaseWithTransport):
414
377
    """Direct tests for show_diff_trees"""
415
378
 
416
379
    def test_modified_file(self):
421
384
        tree.commit('one', rev_id='rev-1')
422
385
 
423
386
        self.build_tree_contents([('tree/file', 'new contents\n')])
424
 
        diff = self.get_diff(tree.basis_tree(), tree)
425
 
        self.assertContainsRe(diff, "=== modified file 'file'\n")
426
 
        self.assertContainsRe(diff, '--- old/file\t')
427
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
428
 
        self.assertContainsRe(diff, '-contents\n'
429
 
                                    '\\+new contents\n')
 
387
        d = get_diff_as_string(tree.basis_tree(), tree)
 
388
        self.assertContainsRe(d, "=== modified file 'file'\n")
 
389
        self.assertContainsRe(d, '--- old/file\t')
 
390
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
 
391
        self.assertContainsRe(d, '-contents\n'
 
392
                                 '\\+new contents\n')
430
393
 
431
394
    def test_modified_file_in_renamed_dir(self):
432
395
        """Test when a file is modified in a renamed directory."""
438
401
 
439
402
        tree.rename_one('dir', 'other')
440
403
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
441
 
        diff = self.get_diff(tree.basis_tree(), tree)
442
 
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
443
 
        self.assertContainsRe(diff, "=== modified file 'other/file'\n")
 
404
        d = get_diff_as_string(tree.basis_tree(), tree)
 
405
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
 
406
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
444
407
        # XXX: This is technically incorrect, because it used to be at another
445
408
        # location. What to do?
446
 
        self.assertContainsRe(diff, '--- old/dir/file\t')
447
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
448
 
        self.assertContainsRe(diff, '-contents\n'
449
 
                                    '\\+new contents\n')
 
409
        self.assertContainsRe(d, '--- old/dir/file\t')
 
410
        self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
 
411
        self.assertContainsRe(d, '-contents\n'
 
412
                                 '\\+new contents\n')
450
413
 
451
414
    def test_renamed_directory(self):
452
415
        """Test when only a directory is only renamed."""
457
420
        tree.commit('one', rev_id='rev-1')
458
421
 
459
422
        tree.rename_one('dir', 'newdir')
460
 
        diff = self.get_diff(tree.basis_tree(), tree)
 
423
        d = get_diff_as_string(tree.basis_tree(), tree)
461
424
        # Renaming a directory should be a single "you renamed this dir" even
462
425
        # when there are files inside.
463
 
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
 
426
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
464
427
 
465
428
    def test_renamed_file(self):
466
429
        """Test when a file is only renamed."""
470
433
        tree.commit('one', rev_id='rev-1')
471
434
 
472
435
        tree.rename_one('file', 'newname')
473
 
        diff = self.get_diff(tree.basis_tree(), tree)
474
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
 
436
        d = get_diff_as_string(tree.basis_tree(), tree)
 
437
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
475
438
        # We shouldn't have a --- or +++ line, because there is no content
476
439
        # change
477
 
        self.assertNotContainsRe(diff, '---')
 
440
        self.assertNotContainsRe(d, '---')
478
441
 
479
442
    def test_renamed_and_modified_file(self):
480
443
        """Test when a file is only renamed."""
485
448
 
486
449
        tree.rename_one('file', 'newname')
487
450
        self.build_tree_contents([('tree/newname', 'new contents\n')])
488
 
        diff = self.get_diff(tree.basis_tree(), tree)
489
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
490
 
        self.assertContainsRe(diff, '--- old/file\t')
491
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
492
 
        self.assertContainsRe(diff, '-contents\n'
493
 
                                    '\\+new contents\n')
 
451
        d = get_diff_as_string(tree.basis_tree(), tree)
 
452
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
 
453
        self.assertContainsRe(d, '--- old/file\t')
 
454
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
 
455
        self.assertContainsRe(d, '-contents\n'
 
456
                                 '\\+new contents\n')
494
457
 
495
458
 
496
459
    def test_internal_diff_exec_property(self):
515
478
        tree.rename_one('c', 'new-c')
516
479
        tree.rename_one('d', 'new-d')
517
480
 
518
 
        diff = self.get_diff(tree.basis_tree(), tree)
519
 
 
520
 
        self.assertContainsRe(diff, r"file 'a'.*\(properties changed:.*\+x to -x.*\)")
521
 
        self.assertContainsRe(diff, r"file 'b'.*\(properties changed:.*-x to \+x.*\)")
522
 
        self.assertContainsRe(diff, r"file 'c'.*\(properties changed:.*\+x to -x.*\)")
523
 
        self.assertContainsRe(diff, r"file 'd'.*\(properties changed:.*-x to \+x.*\)")
524
 
        self.assertNotContainsRe(diff, r"file 'e'")
525
 
        self.assertNotContainsRe(diff, r"file 'f'")
526
 
 
 
481
        d = get_diff_as_string(tree.basis_tree(), tree)
 
482
 
 
483
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
 
484
                                  ".*\+x to -x.*\)")
 
485
        self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
 
486
                                  ".*-x to \+x.*\)")
 
487
        self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
 
488
                                  ".*\+x to -x.*\)")
 
489
        self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
 
490
                                  ".*-x to \+x.*\)")
 
491
        self.assertNotContainsRe(d, r"file 'e'")
 
492
        self.assertNotContainsRe(d, r"file 'f'")
527
493
 
528
494
    def test_binary_unicode_filenames(self):
529
495
        """Test that contents of files are *not* encoded in UTF-8 when there
530
496
        is a binary file in the diff.
531
497
        """
532
498
        # See https://bugs.launchpad.net/bugs/110092.
533
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
499
        self.requireFeature(features.UnicodeFilenameFeature)
534
500
 
535
501
        # This bug isn't triggered with cStringIO.
536
502
        from StringIO import StringIO
544
510
        tree.add([alpha], ['file-id'])
545
511
        tree.add([omega], ['file-id-2'])
546
512
        diff_content = StringIO()
547
 
        show_diff_trees(tree.basis_tree(), tree, diff_content)
548
 
        diff = diff_content.getvalue()
549
 
        self.assertContainsRe(diff, r"=== added file '%s'" % alpha_utf8)
550
 
        self.assertContainsRe(
551
 
            diff, "Binary files a/%s.*and b/%s.* differ\n" % (alpha_utf8, alpha_utf8))
552
 
        self.assertContainsRe(diff, r"=== added file '%s'" % omega_utf8)
553
 
        self.assertContainsRe(diff, r"--- a/%s" % (omega_utf8,))
554
 
        self.assertContainsRe(diff, r"\+\+\+ b/%s" % (omega_utf8,))
 
513
        diff.show_diff_trees(tree.basis_tree(), tree, diff_content)
 
514
        d = diff_content.getvalue()
 
515
        self.assertContainsRe(d, r"=== added file '%s'" % alpha_utf8)
 
516
        self.assertContainsRe(d, "Binary files a/%s.*and b/%s.* differ\n"
 
517
                              % (alpha_utf8, alpha_utf8))
 
518
        self.assertContainsRe(d, r"=== added file '%s'" % omega_utf8)
 
519
        self.assertContainsRe(d, r"--- a/%s" % (omega_utf8,))
 
520
        self.assertContainsRe(d, r"\+\+\+ b/%s" % (omega_utf8,))
555
521
 
556
522
    def test_unicode_filename(self):
557
523
        """Test when the filename are unicode."""
558
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
524
        self.requireFeature(features.UnicodeFilenameFeature)
559
525
 
560
526
        alpha, omega = u'\u03b1', u'\u03c9'
561
527
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
576
542
        tree.add(['add_'+alpha], ['file-id'])
577
543
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
578
544
 
579
 
        diff = self.get_diff(tree.basis_tree(), tree)
580
 
        self.assertContainsRe(diff,
 
545
        d = get_diff_as_string(tree.basis_tree(), tree)
 
546
        self.assertContainsRe(d,
581
547
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
582
 
        self.assertContainsRe(diff, "=== added file 'add_%s'"%autf8)
583
 
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
584
 
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
585
 
 
586
 
 
587
 
class DiffWasIs(DiffPath):
 
548
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
 
549
        self.assertContainsRe(d, "=== modified file 'mod_%s'"%autf8)
 
550
        self.assertContainsRe(d, "=== removed file 'del_%s'"%autf8)
 
551
 
 
552
    def test_unicode_filename_path_encoding(self):
 
553
        """Test for bug #382699: unicode filenames on Windows should be shown
 
554
        in user encoding.
 
555
        """
 
556
        self.requireFeature(features.UnicodeFilenameFeature)
 
557
        # The word 'test' in Russian
 
558
        _russian_test = u'\u0422\u0435\u0441\u0442'
 
559
        directory = _russian_test + u'/'
 
560
        test_txt = _russian_test + u'.txt'
 
561
        u1234 = u'\u1234.txt'
 
562
 
 
563
        tree = self.make_branch_and_tree('.')
 
564
        self.build_tree_contents([
 
565
            (test_txt, 'foo\n'),
 
566
            (u1234, 'foo\n'),
 
567
            (directory, None),
 
568
            ])
 
569
        tree.add([test_txt, u1234, directory])
 
570
 
 
571
        sio = StringIO()
 
572
        diff.show_diff_trees(tree.basis_tree(), tree, sio,
 
573
            path_encoding='cp1251')
 
574
 
 
575
        output = subst_dates(sio.getvalue())
 
576
        shouldbe = ('''\
 
577
=== added directory '%(directory)s'
 
578
=== added file '%(test_txt)s'
 
579
--- a/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
580
+++ b/%(test_txt)s\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
581
@@ -0,0 +1,1 @@
 
582
+foo
 
583
 
 
584
=== added file '?.txt'
 
585
--- a/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
586
+++ b/?.txt\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
587
@@ -0,0 +1,1 @@
 
588
+foo
 
589
 
 
590
''' % {'directory': _russian_test.encode('cp1251'),
 
591
       'test_txt': test_txt.encode('cp1251'),
 
592
      })
 
593
        self.assertEqualDiff(output, shouldbe)
 
594
 
 
595
 
 
596
class DiffWasIs(diff.DiffPath):
588
597
 
589
598
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
590
599
        self.to_file.write('was: ')
594
603
        pass
595
604
 
596
605
 
597
 
class TestDiffTree(TestCaseWithTransport):
 
606
class TestDiffTree(tests.TestCaseWithTransport):
598
607
 
599
608
    def setUp(self):
600
 
        TestCaseWithTransport.setUp(self)
 
609
        super(TestDiffTree, self).setUp()
601
610
        self.old_tree = self.make_branch_and_tree('old-tree')
602
611
        self.old_tree.lock_write()
603
612
        self.addCleanup(self.old_tree.unlock)
604
613
        self.new_tree = self.make_branch_and_tree('new-tree')
605
614
        self.new_tree.lock_write()
606
615
        self.addCleanup(self.new_tree.unlock)
607
 
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
616
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
608
617
 
609
618
    def test_diff_text(self):
610
619
        self.build_tree_contents([('old-tree/olddir/',),
615
624
                                  ('new-tree/newdir/newfile', 'new\n')])
616
625
        self.new_tree.add('newdir')
617
626
        self.new_tree.add('newdir/newfile', 'file-id')
618
 
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
 
627
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
619
628
        differ.diff_text('file-id', None, 'old label', 'new label')
620
629
        self.assertEqual(
621
630
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
650
659
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
651
660
 
652
661
    def test_diff_symlink(self):
653
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
662
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
654
663
        differ.diff_symlink('old target', None)
655
664
        self.assertEqual("=== target was 'old target'\n",
656
665
                         differ.to_file.getvalue())
657
666
 
658
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
667
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
659
668
        differ.diff_symlink(None, 'new target')
660
669
        self.assertEqual("=== target is 'new target'\n",
661
670
                         differ.to_file.getvalue())
662
671
 
663
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
672
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
664
673
        differ.diff_symlink('old target', 'new target')
665
674
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
666
675
                         differ.to_file.getvalue())
681
690
             ' \@\@\n-old\n\+new\n\n')
682
691
 
683
692
    def test_diff_kind_change(self):
684
 
        self.requireFeature(tests.SymlinkFeature)
 
693
        self.requireFeature(features.SymlinkFeature)
685
694
        self.build_tree_contents([('old-tree/olddir/',),
686
695
                                  ('old-tree/olddir/oldfile', 'old\n')])
687
696
        self.old_tree.add('olddir')
716
725
 
717
726
    def test_register_diff(self):
718
727
        self.create_old_new()
719
 
        old_diff_factories = DiffTree.diff_factories
720
 
        DiffTree.diff_factories=old_diff_factories[:]
721
 
        DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
 
728
        old_diff_factories = diff.DiffTree.diff_factories
 
729
        diff.DiffTree.diff_factories=old_diff_factories[:]
 
730
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
722
731
        try:
723
 
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
732
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
724
733
        finally:
725
 
            DiffTree.diff_factories = old_diff_factories
 
734
            diff.DiffTree.diff_factories = old_diff_factories
726
735
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
727
736
        self.assertNotContainsRe(
728
737
            differ.to_file.getvalue(),
733
742
 
734
743
    def test_extra_factories(self):
735
744
        self.create_old_new()
736
 
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
737
 
                            extra_factories=[DiffWasIs.from_diff_tree])
 
745
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
 
746
                               extra_factories=[DiffWasIs.from_diff_tree])
738
747
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
739
748
        self.assertNotContainsRe(
740
749
            differ.to_file.getvalue(),
753
762
            '.*a-file(.|\n)*b-file')
754
763
 
755
764
 
756
 
class TestPatienceDiffLib(TestCase):
 
765
class TestPatienceDiffLib(tests.TestCase):
757
766
 
758
767
    def setUp(self):
759
768
        super(TestPatienceDiffLib, self).setUp()
760
 
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
761
 
        self._recurse_matches = bzrlib._patiencediff_py.recurse_matches_py
 
769
        self._unique_lcs = _patiencediff_py.unique_lcs_py
 
770
        self._recurse_matches = _patiencediff_py.recurse_matches_py
762
771
        self._PatienceSequenceMatcher = \
763
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
772
            _patiencediff_py.PatienceSequenceMatcher_py
764
773
 
765
774
    def test_diff_unicode_string(self):
766
775
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
1073
1082
                 'how are you today?\n']
1074
1083
        txt_b = ['hello there\n',
1075
1084
                 'how are you today?\n']
1076
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1085
        unified_diff = patiencediff.unified_diff
1077
1086
        psm = self._PatienceSequenceMatcher
1078
1087
        self.assertEquals(['--- \n',
1079
1088
                           '+++ \n',
1127
1136
                 'how are you today?\n']
1128
1137
        txt_b = ['hello there\n',
1129
1138
                 'how are you today?\n']
1130
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1139
        unified_diff = patiencediff.unified_diff
1131
1140
        psm = self._PatienceSequenceMatcher
1132
1141
        self.assertEquals(['--- a\t2008-08-08\n',
1133
1142
                           '+++ b\t2008-09-09\n',
1145
1154
 
1146
1155
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1147
1156
 
1148
 
    _test_needs_features = [compiled_patiencediff_feature]
 
1157
    _test_needs_features = [features.compiled_patiencediff_feature]
1149
1158
 
1150
1159
    def setUp(self):
1151
1160
        super(TestPatienceDiffLib_c, self).setUp()
1152
 
        import bzrlib._patiencediff_c
1153
 
        self._unique_lcs = bzrlib._patiencediff_c.unique_lcs_c
1154
 
        self._recurse_matches = bzrlib._patiencediff_c.recurse_matches_c
 
1161
        from bzrlib import _patiencediff_c
 
1162
        self._unique_lcs = _patiencediff_c.unique_lcs_c
 
1163
        self._recurse_matches = _patiencediff_c.recurse_matches_c
1155
1164
        self._PatienceSequenceMatcher = \
1156
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
 
1165
            _patiencediff_c.PatienceSequenceMatcher_c
1157
1166
 
1158
1167
    def test_unhashable(self):
1159
1168
        """We should get a proper exception here."""
1169
1178
                                         None, ['valid'], ['valid', []])
1170
1179
 
1171
1180
 
1172
 
class TestPatienceDiffLibFiles(TestCaseInTempDir):
 
1181
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1173
1182
 
1174
1183
    def setUp(self):
1175
1184
        super(TestPatienceDiffLibFiles, self).setUp()
1176
1185
        self._PatienceSequenceMatcher = \
1177
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
1186
            _patiencediff_py.PatienceSequenceMatcher_py
1178
1187
 
1179
1188
    def test_patience_unified_diff_files(self):
1180
1189
        txt_a = ['hello there\n',
1185
1194
        open('a1', 'wb').writelines(txt_a)
1186
1195
        open('b1', 'wb').writelines(txt_b)
1187
1196
 
1188
 
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
 
1197
        unified_diff_files = patiencediff.unified_diff_files
1189
1198
        psm = self._PatienceSequenceMatcher
1190
1199
        self.assertEquals(['--- a1\n',
1191
1200
                           '+++ b1\n',
1241
1250
 
1242
1251
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1243
1252
 
1244
 
    _test_needs_features = [compiled_patiencediff_feature]
 
1253
    _test_needs_features = [features.compiled_patiencediff_feature]
1245
1254
 
1246
1255
    def setUp(self):
1247
1256
        super(TestPatienceDiffLibFiles_c, self).setUp()
1248
 
        import bzrlib._patiencediff_c
 
1257
        from bzrlib import _patiencediff_c
1249
1258
        self._PatienceSequenceMatcher = \
1250
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
1251
 
 
1252
 
 
1253
 
class TestUsingCompiledIfAvailable(TestCase):
 
1259
            _patiencediff_c.PatienceSequenceMatcher_c
 
1260
 
 
1261
 
 
1262
class TestUsingCompiledIfAvailable(tests.TestCase):
1254
1263
 
1255
1264
    def test_PatienceSequenceMatcher(self):
1256
 
        if compiled_patiencediff_feature.available():
 
1265
        if features.compiled_patiencediff_feature.available():
1257
1266
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1258
1267
            self.assertIs(PatienceSequenceMatcher_c,
1259
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1268
                          patiencediff.PatienceSequenceMatcher)
1260
1269
        else:
1261
1270
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1262
1271
            self.assertIs(PatienceSequenceMatcher_py,
1263
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1272
                          patiencediff.PatienceSequenceMatcher)
1264
1273
 
1265
1274
    def test_unique_lcs(self):
1266
 
        if compiled_patiencediff_feature.available():
 
1275
        if features.compiled_patiencediff_feature.available():
1267
1276
            from bzrlib._patiencediff_c import unique_lcs_c
1268
1277
            self.assertIs(unique_lcs_c,
1269
 
                          bzrlib.patiencediff.unique_lcs)
 
1278
                          patiencediff.unique_lcs)
1270
1279
        else:
1271
1280
            from bzrlib._patiencediff_py import unique_lcs_py
1272
1281
            self.assertIs(unique_lcs_py,
1273
 
                          bzrlib.patiencediff.unique_lcs)
 
1282
                          patiencediff.unique_lcs)
1274
1283
 
1275
1284
    def test_recurse_matches(self):
1276
 
        if compiled_patiencediff_feature.available():
 
1285
        if features.compiled_patiencediff_feature.available():
1277
1286
            from bzrlib._patiencediff_c import recurse_matches_c
1278
1287
            self.assertIs(recurse_matches_c,
1279
 
                          bzrlib.patiencediff.recurse_matches)
 
1288
                          patiencediff.recurse_matches)
1280
1289
        else:
1281
1290
            from bzrlib._patiencediff_py import recurse_matches_py
1282
1291
            self.assertIs(recurse_matches_py,
1283
 
                          bzrlib.patiencediff.recurse_matches)
1284
 
 
1285
 
 
1286
 
class TestDiffFromTool(TestCaseWithTransport):
 
1292
                          patiencediff.recurse_matches)
 
1293
 
 
1294
 
 
1295
class TestDiffFromTool(tests.TestCaseWithTransport):
1287
1296
 
1288
1297
    def test_from_string(self):
1289
 
        diff_obj = DiffFromTool.from_string('diff', None, None, None)
 
1298
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1290
1299
        self.addCleanup(diff_obj.finish)
1291
1300
        self.assertEqual(['diff', '@old_path', '@new_path'],
1292
1301
            diff_obj.command_template)
1293
1302
 
1294
1303
    def test_from_string_u5(self):
1295
 
        diff_obj = DiffFromTool.from_string('diff -u\\ 5', None, None, None)
 
1304
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
 
1305
                                                 None, None, None)
1296
1306
        self.addCleanup(diff_obj.finish)
1297
1307
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
1298
1308
                         diff_obj.command_template)
1299
1309
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1300
1310
                         diff_obj._get_command('old-path', 'new-path'))
1301
1311
 
 
1312
    def test_from_string_path_with_backslashes(self):
 
1313
        self.requireFeature(features.backslashdir_feature)
 
1314
        tool = 'C:\\Tools\\Diff.exe'
 
1315
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
 
1316
        self.addCleanup(diff_obj.finish)
 
1317
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
 
1318
                         diff_obj.command_template)
 
1319
        self.assertEqual(['C:\\Tools\\Diff.exe', 'old-path', 'new-path'],
 
1320
                         diff_obj._get_command('old-path', 'new-path'))
 
1321
 
1302
1322
    def test_execute(self):
1303
1323
        output = StringIO()
1304
 
        diff_obj = DiffFromTool(['python', '-c',
1305
 
                                 'print "@old_path @new_path"'],
1306
 
                                None, None, output)
 
1324
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1325
                                      'print "@old_path @new_path"'],
 
1326
                                     None, None, output)
1307
1327
        self.addCleanup(diff_obj.finish)
1308
1328
        diff_obj._execute('old', 'new')
1309
1329
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1310
1330
 
1311
1331
    def test_excute_missing(self):
1312
 
        diff_obj = DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1313
 
                                None, None, None)
 
1332
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
 
1333
                                     None, None, None)
1314
1334
        self.addCleanup(diff_obj.finish)
1315
 
        e = self.assertRaises(ExecutableMissing, diff_obj._execute, 'old',
1316
 
                              'new')
 
1335
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
 
1336
                              'old', 'new')
1317
1337
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1318
1338
                         ' on this machine', str(e))
1319
1339
 
1320
1340
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
1321
 
        self.requireFeature(AttribFeature)
 
1341
        self.requireFeature(features.AttribFeature)
1322
1342
        output = StringIO()
1323
1343
        tree = self.make_branch_and_tree('tree')
1324
1344
        self.build_tree_contents([('tree/file', 'content')])
1329
1349
        basis_tree = tree.basis_tree()
1330
1350
        basis_tree.lock_read()
1331
1351
        self.addCleanup(basis_tree.unlock)
1332
 
        diff_obj = DiffFromTool(['python', '-c',
1333
 
                                 'print "@old_path @new_path"'],
1334
 
                                basis_tree, tree, output)
 
1352
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1353
                                      'print "@old_path @new_path"'],
 
1354
                                     basis_tree, tree, output)
1335
1355
        diff_obj._prepare_files('file-id', 'file', 'file')
1336
1356
        # The old content should be readonly
1337
1357
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
1354
1374
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
1355
1375
        tree.add('oldname', 'file-id')
1356
1376
        tree.add('oldname2', 'file2-id')
1357
 
        tree.commit('old tree', timestamp=0)
 
1377
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
1378
        tree.commit('old tree', timestamp=315532800)
1358
1379
        tree.rename_one('oldname', 'newname')
1359
1380
        tree.rename_one('oldname2', 'newname2')
1360
1381
        self.build_tree_contents([('tree/newname', 'newcontent')])
1364
1385
        self.addCleanup(old_tree.unlock)
1365
1386
        tree.lock_read()
1366
1387
        self.addCleanup(tree.unlock)
1367
 
        diff_obj = DiffFromTool(['python', '-c',
1368
 
                                 'print "@old_path @new_path"'],
1369
 
                                old_tree, tree, output)
 
1388
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1389
                                      'print "@old_path @new_path"'],
 
1390
                                     old_tree, tree, output)
1370
1391
        self.addCleanup(diff_obj.finish)
1371
1392
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1372
1393
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1373
1394
                                                     'newname')
1374
1395
        self.assertContainsRe(old_path, 'old/oldname$')
1375
 
        self.assertEqual(0, os.stat(old_path).st_mtime)
 
1396
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1376
1397
        self.assertContainsRe(new_path, 'tree/newname$')
1377
1398
        self.assertFileEqual('oldcontent', old_path)
1378
1399
        self.assertFileEqual('newcontent', new_path)
1382
1403
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1383
1404
 
1384
1405
 
1385
 
class TestGetTreesAndBranchesToDiff(TestCaseWithTransport):
 
1406
class TestDiffFromToolEncodedFilename(tests.TestCaseWithTransport):
 
1407
 
 
1408
    def test_encodable_filename(self):
 
1409
        # Just checks file path for external diff tool.
 
1410
        # We cannot change CPython's internal encoding used by os.exec*.
 
1411
        import sys
 
1412
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
 
1413
                                    None, None, None)
 
1414
        for _, scenario in EncodingAdapter.encoding_scenarios:
 
1415
            encoding = scenario['encoding']
 
1416
            dirname  = scenario['info']['directory']
 
1417
            filename = scenario['info']['filename']
 
1418
 
 
1419
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
 
1420
            relpath = dirname + u'/' + filename
 
1421
            fullpath = diffobj._safe_filename('safe', relpath)
 
1422
            self.assertEqual(
 
1423
                    fullpath,
 
1424
                    fullpath.encode(encoding).decode(encoding)
 
1425
                    )
 
1426
            self.assert_(fullpath.startswith(diffobj._root + '/safe'))
 
1427
 
 
1428
    def test_unencodable_filename(self):
 
1429
        import sys
 
1430
        diffobj = diff.DiffFromTool(['dummy', '@old_path', '@new_path'],
 
1431
                                    None, None, None)
 
1432
        for _, scenario in EncodingAdapter.encoding_scenarios:
 
1433
            encoding = scenario['encoding']
 
1434
            dirname  = scenario['info']['directory']
 
1435
            filename = scenario['info']['filename']
 
1436
 
 
1437
            if encoding == 'iso-8859-1':
 
1438
                encoding = 'iso-8859-2'
 
1439
            else:
 
1440
                encoding = 'iso-8859-1'
 
1441
 
 
1442
            self.overrideAttr(diffobj, '_fenc', lambda: encoding)
 
1443
            relpath = dirname + u'/' + filename
 
1444
            fullpath = diffobj._safe_filename('safe', relpath)
 
1445
            self.assertEqual(
 
1446
                    fullpath,
 
1447
                    fullpath.encode(encoding).decode(encoding)
 
1448
                    )
 
1449
            self.assert_(fullpath.startswith(diffobj._root + '/safe'))
 
1450
 
 
1451
 
 
1452
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
 
1453
 
 
1454
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
 
1455
        """Call get_trees_and_branches_to_diff_locked."""
 
1456
        return diff.get_trees_and_branches_to_diff_locked(
 
1457
            path_list, revision_specs, old_url, new_url, self.addCleanup)
1386
1458
 
1387
1459
    def test_basic(self):
1388
1460
        tree = self.make_branch_and_tree('tree')
1389
1461
        (old_tree, new_tree,
1390
1462
         old_branch, new_branch,
1391
 
         specific_files, extra_trees) = \
1392
 
            get_trees_and_branches_to_diff(['tree'], None, None, None)
 
1463
         specific_files, extra_trees) = self.call_gtabtd(
 
1464
             ['tree'], None, None, None)
1393
1465
 
1394
 
        self.assertIsInstance(old_tree, RevisionTree)
1395
 
        #print dir (old_tree)
1396
 
        self.assertEqual(_mod_revision.NULL_REVISION, old_tree.get_revision_id())
 
1466
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
 
1467
        self.assertEqual(_mod_revision.NULL_REVISION,
 
1468
                         old_tree.get_revision_id())
1397
1469
        self.assertEqual(tree.basedir, new_tree.basedir)
1398
1470
        self.assertEqual(tree.branch.base, old_branch.base)
1399
1471
        self.assertEqual(tree.branch.base, new_branch.base)
1408
1480
        self.build_tree_contents([('tree/file', 'newcontent')])
1409
1481
        tree.commit('new tree', timestamp=0, rev_id="new-id")
1410
1482
 
1411
 
        revisions = [RevisionSpec.from_string('1'),
1412
 
                     RevisionSpec.from_string('2')]
 
1483
        revisions = [revisionspec.RevisionSpec.from_string('1'),
 
1484
                     revisionspec.RevisionSpec.from_string('2')]
1413
1485
        (old_tree, new_tree,
1414
1486
         old_branch, new_branch,
1415
 
         specific_files, extra_trees) = \
1416
 
            get_trees_and_branches_to_diff(['tree'], revisions, None, None)
 
1487
         specific_files, extra_trees) = self.call_gtabtd(
 
1488
            ['tree'], revisions, None, None)
1417
1489
 
1418
 
        self.assertIsInstance(old_tree, RevisionTree)
 
1490
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1419
1491
        self.assertEqual("old-id", old_tree.get_revision_id())
1420
 
        self.assertIsInstance(new_tree, RevisionTree)
 
1492
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
1421
1493
        self.assertEqual("new-id", new_tree.get_revision_id())
1422
1494
        self.assertEqual(tree.branch.base, old_branch.base)
1423
1495
        self.assertEqual(tree.branch.base, new_branch.base)