~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Vincent Ladeuil
  • Date: 2012-03-09 16:48:55 UTC
  • mto: (6437.23.24 2.5)
  • mto: This revision was merged to the branch mainline in revision 6499.
  • Revision ID: v.ladeuil+lp@free.fr-20120309164855-htdn25hp7x65mmir
Rely on sphinx for texinfo doc generation

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 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
 
from bzrlib.tests.test_win32utils import BackslashDirSeparatorFeature
49
 
 
50
 
 
51
 
class _AttribFeature(Feature):
52
 
 
53
 
    def _probe(self):
54
 
        if (sys.platform not in ('cygwin', 'win32')):
55
 
            return False
56
 
        try:
57
 
            proc = subprocess.Popen(['attrib', '.'], stdout=subprocess.PIPE)
58
 
        except OSError, e:
59
 
            return False
60
 
        return (0 == proc.wait())
61
 
 
62
 
    def feature_name(self):
63
 
        return 'attrib Windows command-line tool'
64
 
 
65
 
AttribFeature = _AttribFeature()
66
 
 
67
 
 
68
 
compiled_patiencediff_feature = tests.ModuleAvailableFeature(
69
 
                                    '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
    )
70
41
 
71
42
 
72
43
def udiff_lines(old, new, allow_binary=False):
73
44
    output = StringIO()
74
 
    internal_diff('old', old, 'new', new, output, allow_binary)
 
45
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
75
46
    output.seek(0, 0)
76
47
    return output.readlines()
77
48
 
81
52
        # StringIO has no fileno, so it tests a different codepath
82
53
        output = StringIO()
83
54
    else:
84
 
        output = TemporaryFile()
 
55
        output = tempfile.TemporaryFile()
85
56
    try:
86
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
87
 
    except NoDiff:
88
 
        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')
89
60
    output.seek(0, 0)
90
61
    lines = output.readlines()
91
62
    output.close()
92
63
    return lines
93
64
 
94
65
 
95
 
class TestDiff(TestCase):
 
66
class TestDiff(tests.TestCase):
96
67
 
97
68
    def test_add_nl(self):
98
69
        """diff generates a valid diff for patches that add a newline"""
134
105
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
135
106
 
136
107
    def test_binary_lines(self):
137
 
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
138
 
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
139
 
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
140
 
        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)
141
114
 
142
115
    def test_external_diff(self):
143
116
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
153
126
        self.check_patch(lines)
154
127
 
155
128
    def test_external_diff_binary_lang_c(self):
156
 
        old_env = {}
157
129
        for lang in ('LANG', 'LC_ALL', 'LANGUAGE'):
158
 
            old_env[lang] = osutils.set_or_unset_env(lang, 'C')
159
 
        try:
160
 
            lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
161
 
            # Older versions of diffutils say "Binary files", newer
162
 
            # versions just say "Files".
163
 
            self.assertContainsRe(lines[0],
164
 
                                  '(Binary f|F)iles old and new differ\n')
165
 
            self.assertEquals(lines[1:], ['\n'])
166
 
        finally:
167
 
            for lang, old_val in old_env.iteritems():
168
 
                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'])
169
136
 
170
137
    def test_no_external_diff(self):
171
138
        """Check that NoDiff is raised when diff is not available"""
172
 
        # Use os.environ['PATH'] to make sure no 'diff' command is available
173
 
        orig_path = os.environ['PATH']
174
 
        try:
175
 
            os.environ['PATH'] = ''
176
 
            self.assertRaises(NoDiff, external_diff,
177
 
                              'old', ['boo\n'], 'new', ['goo\n'],
178
 
                              StringIO(), diff_opts=['-u'])
179
 
        finally:
180
 
            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'])
181
145
 
182
146
    def test_internal_diff_default(self):
183
147
        # Default internal diff encoding is utf8
184
148
        output = StringIO()
185
 
        internal_diff(u'old_\xb5', ['old_text\n'],
186
 
                    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)
187
151
        lines = output.getvalue().splitlines(True)
188
152
        self.check_patch(lines)
189
153
        self.assertEquals(['--- old_\xc2\xb5\n',
197
161
 
198
162
    def test_internal_diff_utf8(self):
199
163
        output = StringIO()
200
 
        internal_diff(u'old_\xb5', ['old_text\n'],
201
 
                    u'new_\xe5', ['new_text\n'], output,
202
 
                    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')
203
167
        lines = output.getvalue().splitlines(True)
204
168
        self.check_patch(lines)
205
169
        self.assertEquals(['--- old_\xc2\xb5\n',
213
177
 
214
178
    def test_internal_diff_iso_8859_1(self):
215
179
        output = StringIO()
216
 
        internal_diff(u'old_\xb5', ['old_text\n'],
217
 
                    u'new_\xe5', ['new_text\n'], output,
218
 
                    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')
219
183
        lines = output.getvalue().splitlines(True)
220
184
        self.check_patch(lines)
221
185
        self.assertEquals(['--- old_\xb5\n',
229
193
 
230
194
    def test_internal_diff_no_content(self):
231
195
        output = StringIO()
232
 
        internal_diff(u'old', [], u'new', [], output)
 
196
        diff.internal_diff(u'old', [], u'new', [], output)
233
197
        self.assertEqual('', output.getvalue())
234
198
 
235
199
    def test_internal_diff_no_changes(self):
236
200
        output = StringIO()
237
 
        internal_diff(u'old', ['text\n', 'contents\n'],
238
 
                      u'new', ['text\n', 'contents\n'],
239
 
                      output)
 
201
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
 
202
                           u'new', ['text\n', 'contents\n'],
 
203
                           output)
240
204
        self.assertEqual('', output.getvalue())
241
205
 
242
206
    def test_internal_diff_returns_bytes(self):
243
207
        import StringIO
244
208
        output = StringIO.StringIO()
245
 
        internal_diff(u'old_\xb5', ['old_text\n'],
246
 
                    u'new_\xe5', ['new_text\n'], output)
247
 
        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,
248
212
            'internal_diff should return bytestrings')
249
213
 
250
214
 
251
 
class TestDiffFiles(TestCaseInTempDir):
 
215
class TestDiffFiles(tests.TestCaseInTempDir):
252
216
 
253
217
    def test_external_diff_binary(self):
254
218
        """The output when using external diff should use diff's i18n error"""
256
220
        lines = external_udiff_lines(['\x00foobar\n'], ['foo\x00bar\n'])
257
221
 
258
222
        cmd = ['diff', '-u', '--binary', 'old', 'new']
259
 
        open('old', 'wb').write('\x00foobar\n')
260
 
        open('new', 'wb').write('foo\x00bar\n')
 
223
        with open('old', 'wb') as f: f.write('\x00foobar\n')
 
224
        with open('new', 'wb') as f: f.write('foo\x00bar\n')
261
225
        pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE,
262
226
                                     stdin=subprocess.PIPE)
263
227
        out, err = pipe.communicate()
267
231
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
268
232
 
269
233
 
270
 
class TestShowDiffTreesHelper(TestCaseWithTransport):
271
 
    """Has a helper for running show_diff_trees"""
272
 
 
273
 
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
274
 
        output = StringIO()
275
 
        if working_tree is not None:
276
 
            extra_trees = (working_tree,)
277
 
        else:
278
 
            extra_trees = ()
279
 
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
280
 
                        extra_trees=extra_trees, old_label='old/',
281
 
                        new_label='new/')
282
 
        return output.getvalue()
283
 
 
284
 
 
285
 
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):
286
248
 
287
249
    def setUp(self):
288
250
        super(TestDiffDates, self).setUp()
323
285
        os.utime('file1', (1144195200, 1144195200)) # 2006-04-05 00:00:00 UTC
324
286
 
325
287
    def test_diff_rev_tree_working_tree(self):
326
 
        output = self.get_diff(self.wt.basis_tree(), self.wt)
 
288
        output = get_diff_as_string(self.wt.basis_tree(), self.wt)
327
289
        # note that the date for old/file1 is from rev 2 rather than from
328
290
        # the basis revision (rev 4)
329
291
        self.assertEqualDiff(output, '''\
339
301
    def test_diff_rev_tree_rev_tree(self):
340
302
        tree1 = self.b.repository.revision_tree('rev-2')
341
303
        tree2 = self.b.repository.revision_tree('rev-3')
342
 
        output = self.get_diff(tree1, tree2)
 
304
        output = get_diff_as_string(tree1, tree2)
343
305
        self.assertEqualDiff(output, '''\
344
306
=== modified file 'file2'
345
307
--- old/file2\t2006-04-01 00:00:00 +0000
353
315
    def test_diff_add_files(self):
354
316
        tree1 = self.b.repository.revision_tree(_mod_revision.NULL_REVISION)
355
317
        tree2 = self.b.repository.revision_tree('rev-1')
356
 
        output = self.get_diff(tree1, tree2)
 
318
        output = get_diff_as_string(tree1, tree2)
357
319
        # the files have the epoch time stamp for the tree in which
358
320
        # they don't exist.
359
321
        self.assertEqualDiff(output, '''\
374
336
    def test_diff_remove_files(self):
375
337
        tree1 = self.b.repository.revision_tree('rev-3')
376
338
        tree2 = self.b.repository.revision_tree('rev-4')
377
 
        output = self.get_diff(tree1, tree2)
 
339
        output = get_diff_as_string(tree1, tree2)
378
340
        # the file has the epoch time stamp for the tree in which
379
341
        # it doesn't exist.
380
342
        self.assertEqualDiff(output, '''\
391
353
        self.wt.rename_one('file1', 'file1b')
392
354
        old_tree = self.b.repository.revision_tree('rev-1')
393
355
        new_tree = self.b.repository.revision_tree('rev-4')
394
 
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'],
 
356
        out = get_diff_as_string(old_tree, new_tree, specific_files=['file1b'],
395
357
                            working_tree=self.wt)
396
358
        self.assertContainsRe(out, 'file1\t')
397
359
 
403
365
        self.wt.rename_one('file1', 'dir1/file1')
404
366
        old_tree = self.b.repository.revision_tree('rev-1')
405
367
        new_tree = self.b.repository.revision_tree('rev-4')
406
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'],
 
368
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir1'],
407
369
                            working_tree=self.wt)
408
370
        self.assertContainsRe(out, 'file1\t')
409
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'],
 
371
        out = get_diff_as_string(old_tree, new_tree, specific_files=['dir2'],
410
372
                            working_tree=self.wt)
411
373
        self.assertNotContainsRe(out, 'file1\t')
412
374
 
413
375
 
414
 
 
415
 
class TestShowDiffTrees(TestShowDiffTreesHelper):
 
376
class TestShowDiffTrees(tests.TestCaseWithTransport):
416
377
    """Direct tests for show_diff_trees"""
417
378
 
418
379
    def test_modified_file(self):
423
384
        tree.commit('one', rev_id='rev-1')
424
385
 
425
386
        self.build_tree_contents([('tree/file', 'new contents\n')])
426
 
        diff = self.get_diff(tree.basis_tree(), tree)
427
 
        self.assertContainsRe(diff, "=== modified file 'file'\n")
428
 
        self.assertContainsRe(diff, '--- old/file\t')
429
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
430
 
        self.assertContainsRe(diff, '-contents\n'
431
 
                                    '\\+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')
432
393
 
433
394
    def test_modified_file_in_renamed_dir(self):
434
395
        """Test when a file is modified in a renamed directory."""
440
401
 
441
402
        tree.rename_one('dir', 'other')
442
403
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
443
 
        diff = self.get_diff(tree.basis_tree(), tree)
444
 
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
445
 
        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")
446
407
        # XXX: This is technically incorrect, because it used to be at another
447
408
        # location. What to do?
448
 
        self.assertContainsRe(diff, '--- old/dir/file\t')
449
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
450
 
        self.assertContainsRe(diff, '-contents\n'
451
 
                                    '\\+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')
452
413
 
453
414
    def test_renamed_directory(self):
454
415
        """Test when only a directory is only renamed."""
459
420
        tree.commit('one', rev_id='rev-1')
460
421
 
461
422
        tree.rename_one('dir', 'newdir')
462
 
        diff = self.get_diff(tree.basis_tree(), tree)
 
423
        d = get_diff_as_string(tree.basis_tree(), tree)
463
424
        # Renaming a directory should be a single "you renamed this dir" even
464
425
        # when there are files inside.
465
 
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
 
426
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
466
427
 
467
428
    def test_renamed_file(self):
468
429
        """Test when a file is only renamed."""
472
433
        tree.commit('one', rev_id='rev-1')
473
434
 
474
435
        tree.rename_one('file', 'newname')
475
 
        diff = self.get_diff(tree.basis_tree(), tree)
476
 
        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")
477
438
        # We shouldn't have a --- or +++ line, because there is no content
478
439
        # change
479
 
        self.assertNotContainsRe(diff, '---')
 
440
        self.assertNotContainsRe(d, '---')
480
441
 
481
442
    def test_renamed_and_modified_file(self):
482
443
        """Test when a file is only renamed."""
487
448
 
488
449
        tree.rename_one('file', 'newname')
489
450
        self.build_tree_contents([('tree/newname', 'new contents\n')])
490
 
        diff = self.get_diff(tree.basis_tree(), tree)
491
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
492
 
        self.assertContainsRe(diff, '--- old/file\t')
493
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
494
 
        self.assertContainsRe(diff, '-contents\n'
495
 
                                    '\\+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')
496
457
 
497
458
 
498
459
    def test_internal_diff_exec_property(self):
517
478
        tree.rename_one('c', 'new-c')
518
479
        tree.rename_one('d', 'new-d')
519
480
 
520
 
        diff = self.get_diff(tree.basis_tree(), tree)
521
 
 
522
 
        self.assertContainsRe(diff, r"file 'a'.*\(properties changed:.*\+x to -x.*\)")
523
 
        self.assertContainsRe(diff, r"file 'b'.*\(properties changed:.*-x to \+x.*\)")
524
 
        self.assertContainsRe(diff, r"file 'c'.*\(properties changed:.*\+x to -x.*\)")
525
 
        self.assertContainsRe(diff, r"file 'd'.*\(properties changed:.*-x to \+x.*\)")
526
 
        self.assertNotContainsRe(diff, r"file 'e'")
527
 
        self.assertNotContainsRe(diff, r"file 'f'")
528
 
 
 
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'")
529
493
 
530
494
    def test_binary_unicode_filenames(self):
531
495
        """Test that contents of files are *not* encoded in UTF-8 when there
532
496
        is a binary file in the diff.
533
497
        """
534
498
        # See https://bugs.launchpad.net/bugs/110092.
535
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
499
        self.requireFeature(features.UnicodeFilenameFeature)
536
500
 
537
501
        # This bug isn't triggered with cStringIO.
538
502
        from StringIO import StringIO
546
510
        tree.add([alpha], ['file-id'])
547
511
        tree.add([omega], ['file-id-2'])
548
512
        diff_content = StringIO()
549
 
        show_diff_trees(tree.basis_tree(), tree, diff_content)
550
 
        diff = diff_content.getvalue()
551
 
        self.assertContainsRe(diff, r"=== added file '%s'" % alpha_utf8)
552
 
        self.assertContainsRe(
553
 
            diff, "Binary files a/%s.*and b/%s.* differ\n" % (alpha_utf8, alpha_utf8))
554
 
        self.assertContainsRe(diff, r"=== added file '%s'" % omega_utf8)
555
 
        self.assertContainsRe(diff, r"--- a/%s" % (omega_utf8,))
556
 
        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,))
557
521
 
558
522
    def test_unicode_filename(self):
559
523
        """Test when the filename are unicode."""
560
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
524
        self.requireFeature(features.UnicodeFilenameFeature)
561
525
 
562
526
        alpha, omega = u'\u03b1', u'\u03c9'
563
527
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
578
542
        tree.add(['add_'+alpha], ['file-id'])
579
543
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
580
544
 
581
 
        diff = self.get_diff(tree.basis_tree(), tree)
582
 
        self.assertContainsRe(diff,
 
545
        d = get_diff_as_string(tree.basis_tree(), tree)
 
546
        self.assertContainsRe(d,
583
547
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
584
 
        self.assertContainsRe(diff, "=== added file 'add_%s'"%autf8)
585
 
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
586
 
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
587
 
 
588
 
 
589
 
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):
590
597
 
591
598
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
592
599
        self.to_file.write('was: ')
596
603
        pass
597
604
 
598
605
 
599
 
class TestDiffTree(TestCaseWithTransport):
 
606
class TestDiffTree(tests.TestCaseWithTransport):
600
607
 
601
608
    def setUp(self):
602
 
        TestCaseWithTransport.setUp(self)
 
609
        super(TestDiffTree, self).setUp()
603
610
        self.old_tree = self.make_branch_and_tree('old-tree')
604
611
        self.old_tree.lock_write()
605
612
        self.addCleanup(self.old_tree.unlock)
606
613
        self.new_tree = self.make_branch_and_tree('new-tree')
607
614
        self.new_tree.lock_write()
608
615
        self.addCleanup(self.new_tree.unlock)
609
 
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
616
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
610
617
 
611
618
    def test_diff_text(self):
612
619
        self.build_tree_contents([('old-tree/olddir/',),
617
624
                                  ('new-tree/newdir/newfile', 'new\n')])
618
625
        self.new_tree.add('newdir')
619
626
        self.new_tree.add('newdir/newfile', 'file-id')
620
 
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
 
627
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
621
628
        differ.diff_text('file-id', None, 'old label', 'new label')
622
629
        self.assertEqual(
623
630
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
652
659
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
653
660
 
654
661
    def test_diff_symlink(self):
655
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
662
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
656
663
        differ.diff_symlink('old target', None)
657
664
        self.assertEqual("=== target was 'old target'\n",
658
665
                         differ.to_file.getvalue())
659
666
 
660
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
667
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
661
668
        differ.diff_symlink(None, 'new target')
662
669
        self.assertEqual("=== target is 'new target'\n",
663
670
                         differ.to_file.getvalue())
664
671
 
665
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
672
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
666
673
        differ.diff_symlink('old target', 'new target')
667
674
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
668
675
                         differ.to_file.getvalue())
683
690
             ' \@\@\n-old\n\+new\n\n')
684
691
 
685
692
    def test_diff_kind_change(self):
686
 
        self.requireFeature(tests.SymlinkFeature)
 
693
        self.requireFeature(features.SymlinkFeature)
687
694
        self.build_tree_contents([('old-tree/olddir/',),
688
695
                                  ('old-tree/olddir/oldfile', 'old\n')])
689
696
        self.old_tree.add('olddir')
718
725
 
719
726
    def test_register_diff(self):
720
727
        self.create_old_new()
721
 
        old_diff_factories = DiffTree.diff_factories
722
 
        DiffTree.diff_factories=old_diff_factories[:]
723
 
        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)
724
731
        try:
725
 
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
732
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
726
733
        finally:
727
 
            DiffTree.diff_factories = old_diff_factories
 
734
            diff.DiffTree.diff_factories = old_diff_factories
728
735
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
729
736
        self.assertNotContainsRe(
730
737
            differ.to_file.getvalue(),
735
742
 
736
743
    def test_extra_factories(self):
737
744
        self.create_old_new()
738
 
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
739
 
                            extra_factories=[DiffWasIs.from_diff_tree])
 
745
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
 
746
                               extra_factories=[DiffWasIs.from_diff_tree])
740
747
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
741
748
        self.assertNotContainsRe(
742
749
            differ.to_file.getvalue(),
755
762
            '.*a-file(.|\n)*b-file')
756
763
 
757
764
 
758
 
class TestPatienceDiffLib(TestCase):
 
765
class TestPatienceDiffLib(tests.TestCase):
759
766
 
760
767
    def setUp(self):
761
768
        super(TestPatienceDiffLib, self).setUp()
762
 
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
763
 
        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
764
771
        self._PatienceSequenceMatcher = \
765
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
772
            _patiencediff_py.PatienceSequenceMatcher_py
766
773
 
767
774
    def test_diff_unicode_string(self):
768
775
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
1075
1082
                 'how are you today?\n']
1076
1083
        txt_b = ['hello there\n',
1077
1084
                 'how are you today?\n']
1078
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1085
        unified_diff = patiencediff.unified_diff
1079
1086
        psm = self._PatienceSequenceMatcher
1080
1087
        self.assertEquals(['--- \n',
1081
1088
                           '+++ \n',
1129
1136
                 'how are you today?\n']
1130
1137
        txt_b = ['hello there\n',
1131
1138
                 'how are you today?\n']
1132
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1139
        unified_diff = patiencediff.unified_diff
1133
1140
        psm = self._PatienceSequenceMatcher
1134
1141
        self.assertEquals(['--- a\t2008-08-08\n',
1135
1142
                           '+++ b\t2008-09-09\n',
1147
1154
 
1148
1155
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1149
1156
 
1150
 
    _test_needs_features = [compiled_patiencediff_feature]
 
1157
    _test_needs_features = [features.compiled_patiencediff_feature]
1151
1158
 
1152
1159
    def setUp(self):
1153
1160
        super(TestPatienceDiffLib_c, self).setUp()
1154
 
        import bzrlib._patiencediff_c
1155
 
        self._unique_lcs = bzrlib._patiencediff_c.unique_lcs_c
1156
 
        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
1157
1164
        self._PatienceSequenceMatcher = \
1158
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
 
1165
            _patiencediff_c.PatienceSequenceMatcher_c
1159
1166
 
1160
1167
    def test_unhashable(self):
1161
1168
        """We should get a proper exception here."""
1171
1178
                                         None, ['valid'], ['valid', []])
1172
1179
 
1173
1180
 
1174
 
class TestPatienceDiffLibFiles(TestCaseInTempDir):
 
1181
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1175
1182
 
1176
1183
    def setUp(self):
1177
1184
        super(TestPatienceDiffLibFiles, self).setUp()
1178
1185
        self._PatienceSequenceMatcher = \
1179
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
1186
            _patiencediff_py.PatienceSequenceMatcher_py
1180
1187
 
1181
1188
    def test_patience_unified_diff_files(self):
1182
1189
        txt_a = ['hello there\n',
1184
1191
                 'how are you today?\n']
1185
1192
        txt_b = ['hello there\n',
1186
1193
                 'how are you today?\n']
1187
 
        open('a1', 'wb').writelines(txt_a)
1188
 
        open('b1', 'wb').writelines(txt_b)
 
1194
        with open('a1', 'wb') as f: f.writelines(txt_a)
 
1195
        with open('b1', 'wb') as f: f.writelines(txt_b)
1189
1196
 
1190
 
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
 
1197
        unified_diff_files = patiencediff.unified_diff_files
1191
1198
        psm = self._PatienceSequenceMatcher
1192
1199
        self.assertEquals(['--- a1\n',
1193
1200
                           '+++ b1\n',
1201
1208
 
1202
1209
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1203
1210
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1204
 
        open('a2', 'wb').writelines(txt_a)
1205
 
        open('b2', 'wb').writelines(txt_b)
 
1211
        with open('a2', 'wb') as f: f.writelines(txt_a)
 
1212
        with open('b2', 'wb') as f: f.writelines(txt_b)
1206
1213
 
1207
1214
        # This is the result with LongestCommonSubstring matching
1208
1215
        self.assertEquals(['--- a2\n',
1243
1250
 
1244
1251
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1245
1252
 
1246
 
    _test_needs_features = [compiled_patiencediff_feature]
 
1253
    _test_needs_features = [features.compiled_patiencediff_feature]
1247
1254
 
1248
1255
    def setUp(self):
1249
1256
        super(TestPatienceDiffLibFiles_c, self).setUp()
1250
 
        import bzrlib._patiencediff_c
 
1257
        from bzrlib import _patiencediff_c
1251
1258
        self._PatienceSequenceMatcher = \
1252
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
1253
 
 
1254
 
 
1255
 
class TestUsingCompiledIfAvailable(TestCase):
 
1259
            _patiencediff_c.PatienceSequenceMatcher_c
 
1260
 
 
1261
 
 
1262
class TestUsingCompiledIfAvailable(tests.TestCase):
1256
1263
 
1257
1264
    def test_PatienceSequenceMatcher(self):
1258
 
        if compiled_patiencediff_feature.available():
 
1265
        if features.compiled_patiencediff_feature.available():
1259
1266
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1260
1267
            self.assertIs(PatienceSequenceMatcher_c,
1261
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1268
                          patiencediff.PatienceSequenceMatcher)
1262
1269
        else:
1263
1270
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1264
1271
            self.assertIs(PatienceSequenceMatcher_py,
1265
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1272
                          patiencediff.PatienceSequenceMatcher)
1266
1273
 
1267
1274
    def test_unique_lcs(self):
1268
 
        if compiled_patiencediff_feature.available():
 
1275
        if features.compiled_patiencediff_feature.available():
1269
1276
            from bzrlib._patiencediff_c import unique_lcs_c
1270
1277
            self.assertIs(unique_lcs_c,
1271
 
                          bzrlib.patiencediff.unique_lcs)
 
1278
                          patiencediff.unique_lcs)
1272
1279
        else:
1273
1280
            from bzrlib._patiencediff_py import unique_lcs_py
1274
1281
            self.assertIs(unique_lcs_py,
1275
 
                          bzrlib.patiencediff.unique_lcs)
 
1282
                          patiencediff.unique_lcs)
1276
1283
 
1277
1284
    def test_recurse_matches(self):
1278
 
        if compiled_patiencediff_feature.available():
 
1285
        if features.compiled_patiencediff_feature.available():
1279
1286
            from bzrlib._patiencediff_c import recurse_matches_c
1280
1287
            self.assertIs(recurse_matches_c,
1281
 
                          bzrlib.patiencediff.recurse_matches)
 
1288
                          patiencediff.recurse_matches)
1282
1289
        else:
1283
1290
            from bzrlib._patiencediff_py import recurse_matches_py
1284
1291
            self.assertIs(recurse_matches_py,
1285
 
                          bzrlib.patiencediff.recurse_matches)
1286
 
 
1287
 
 
1288
 
class TestDiffFromTool(TestCaseWithTransport):
 
1292
                          patiencediff.recurse_matches)
 
1293
 
 
1294
 
 
1295
class TestDiffFromTool(tests.TestCaseWithTransport):
1289
1296
 
1290
1297
    def test_from_string(self):
1291
 
        diff_obj = DiffFromTool.from_string('diff', None, None, None)
 
1298
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1292
1299
        self.addCleanup(diff_obj.finish)
1293
1300
        self.assertEqual(['diff', '@old_path', '@new_path'],
1294
1301
            diff_obj.command_template)
1295
1302
 
1296
1303
    def test_from_string_u5(self):
1297
 
        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)
1298
1306
        self.addCleanup(diff_obj.finish)
1299
1307
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
1300
1308
                         diff_obj.command_template)
1301
1309
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1302
1310
                         diff_obj._get_command('old-path', 'new-path'))
1303
 
        
 
1311
 
1304
1312
    def test_from_string_path_with_backslashes(self):
1305
 
        self.requireFeature(BackslashDirSeparatorFeature)
 
1313
        self.requireFeature(features.backslashdir_feature)
1306
1314
        tool = 'C:\\Tools\\Diff.exe'
1307
 
        diff_obj = DiffFromTool.from_string(tool, None, None, None)
 
1315
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
1308
1316
        self.addCleanup(diff_obj.finish)
1309
1317
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
1310
1318
                         diff_obj.command_template)
1313
1321
 
1314
1322
    def test_execute(self):
1315
1323
        output = StringIO()
1316
 
        diff_obj = DiffFromTool(['python', '-c',
1317
 
                                 'print "@old_path @new_path"'],
1318
 
                                None, None, output)
 
1324
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1325
                                      'print "@old_path @new_path"'],
 
1326
                                     None, None, output)
1319
1327
        self.addCleanup(diff_obj.finish)
1320
1328
        diff_obj._execute('old', 'new')
1321
1329
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1322
1330
 
1323
1331
    def test_excute_missing(self):
1324
 
        diff_obj = DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1325
 
                                None, None, None)
 
1332
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
 
1333
                                     None, None, None)
1326
1334
        self.addCleanup(diff_obj.finish)
1327
 
        e = self.assertRaises(ExecutableMissing, diff_obj._execute, 'old',
1328
 
                              'new')
 
1335
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
 
1336
                              'old', 'new')
1329
1337
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1330
1338
                         ' on this machine', str(e))
1331
1339
 
1332
1340
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
1333
 
        self.requireFeature(AttribFeature)
 
1341
        self.requireFeature(features.AttribFeature)
1334
1342
        output = StringIO()
1335
1343
        tree = self.make_branch_and_tree('tree')
1336
1344
        self.build_tree_contents([('tree/file', 'content')])
1341
1349
        basis_tree = tree.basis_tree()
1342
1350
        basis_tree.lock_read()
1343
1351
        self.addCleanup(basis_tree.unlock)
1344
 
        diff_obj = DiffFromTool(['python', '-c',
1345
 
                                 'print "@old_path @new_path"'],
1346
 
                                basis_tree, tree, output)
 
1352
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1353
                                      'print "@old_path @new_path"'],
 
1354
                                     basis_tree, tree, output)
1347
1355
        diff_obj._prepare_files('file-id', 'file', 'file')
1348
1356
        # The old content should be readonly
1349
1357
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
1366
1374
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
1367
1375
        tree.add('oldname', 'file-id')
1368
1376
        tree.add('oldname2', 'file2-id')
1369
 
        tree.commit('old tree', timestamp=0)
 
1377
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
1378
        tree.commit('old tree', timestamp=315532800)
1370
1379
        tree.rename_one('oldname', 'newname')
1371
1380
        tree.rename_one('oldname2', 'newname2')
1372
1381
        self.build_tree_contents([('tree/newname', 'newcontent')])
1376
1385
        self.addCleanup(old_tree.unlock)
1377
1386
        tree.lock_read()
1378
1387
        self.addCleanup(tree.unlock)
1379
 
        diff_obj = DiffFromTool(['python', '-c',
1380
 
                                 'print "@old_path @new_path"'],
1381
 
                                old_tree, tree, output)
 
1388
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1389
                                      'print "@old_path @new_path"'],
 
1390
                                     old_tree, tree, output)
1382
1391
        self.addCleanup(diff_obj.finish)
1383
1392
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1384
1393
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1385
1394
                                                     'newname')
1386
1395
        self.assertContainsRe(old_path, 'old/oldname$')
1387
 
        self.assertEqual(0, os.stat(old_path).st_mtime)
 
1396
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1388
1397
        self.assertContainsRe(new_path, 'tree/newname$')
1389
1398
        self.assertFileEqual('oldcontent', old_path)
1390
1399
        self.assertFileEqual('newcontent', new_path)
1394
1403
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1395
1404
 
1396
1405
 
1397
 
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)
1398
1458
 
1399
1459
    def test_basic(self):
1400
1460
        tree = self.make_branch_and_tree('tree')
1401
1461
        (old_tree, new_tree,
1402
1462
         old_branch, new_branch,
1403
 
         specific_files, extra_trees) = \
1404
 
            get_trees_and_branches_to_diff(['tree'], None, None, None)
 
1463
         specific_files, extra_trees) = self.call_gtabtd(
 
1464
             ['tree'], None, None, None)
1405
1465
 
1406
 
        self.assertIsInstance(old_tree, RevisionTree)
1407
 
        #print dir (old_tree)
1408
 
        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())
1409
1469
        self.assertEqual(tree.basedir, new_tree.basedir)
1410
1470
        self.assertEqual(tree.branch.base, old_branch.base)
1411
1471
        self.assertEqual(tree.branch.base, new_branch.base)
1420
1480
        self.build_tree_contents([('tree/file', 'newcontent')])
1421
1481
        tree.commit('new tree', timestamp=0, rev_id="new-id")
1422
1482
 
1423
 
        revisions = [RevisionSpec.from_string('1'),
1424
 
                     RevisionSpec.from_string('2')]
 
1483
        revisions = [revisionspec.RevisionSpec.from_string('1'),
 
1484
                     revisionspec.RevisionSpec.from_string('2')]
1425
1485
        (old_tree, new_tree,
1426
1486
         old_branch, new_branch,
1427
 
         specific_files, extra_trees) = \
1428
 
            get_trees_and_branches_to_diff(['tree'], revisions, None, None)
 
1487
         specific_files, extra_trees) = self.call_gtabtd(
 
1488
            ['tree'], revisions, None, None)
1429
1489
 
1430
 
        self.assertIsInstance(old_tree, RevisionTree)
 
1490
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1431
1491
        self.assertEqual("old-id", old_tree.get_revision_id())
1432
 
        self.assertIsInstance(new_tree, RevisionTree)
 
1492
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
1433
1493
        self.assertEqual("new-id", new_tree.get_revision_id())
1434
1494
        self.assertEqual(tree.branch.base, old_branch.base)
1435
1495
        self.assertEqual(tree.branch.base, new_branch.base)