~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Ian Clatworthy
  • Date: 2008-03-27 07:51:10 UTC
  • mto: (3311.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 3312.
  • Revision ID: ian.clatworthy@canonical.com-20080327075110-afgd7x03ybju06ez
Reduce evangelism in the User Guide

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005, 2006 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
import os
 
18
import os.path
18
19
from cStringIO import StringIO
 
20
import errno
19
21
import subprocess
20
 
import sys
21
 
import tempfile
 
22
from tempfile import TemporaryFile
22
23
 
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,
 
24
from bzrlib import tests
 
25
from bzrlib.diff import (
 
26
    DiffFromTool,
 
27
    DiffPath,
 
28
    DiffSymlink,
 
29
    DiffTree,
 
30
    DiffText,
 
31
    external_diff,
 
32
    internal_diff,
 
33
    show_diff_trees,
34
34
    )
35
 
from bzrlib.symbol_versioning import deprecated_in
36
 
from bzrlib.tests import test_win32utils
37
 
 
38
 
 
39
 
class _AttribFeature(tests.Feature):
 
35
from bzrlib.errors import BinaryFile, NoDiff, ExecutableMissing
 
36
import bzrlib.osutils as osutils
 
37
import bzrlib.transform as transform
 
38
import bzrlib.patiencediff
 
39
import bzrlib._patiencediff_py
 
40
from bzrlib.tests import (Feature, TestCase, TestCaseWithTransport,
 
41
                          TestCaseInTempDir, TestSkipped)
 
42
 
 
43
 
 
44
class _CompiledPatienceDiffFeature(Feature):
40
45
 
41
46
    def _probe(self):
42
 
        if (sys.platform not in ('cygwin', 'win32')):
43
 
            return False
44
47
        try:
45
 
            proc = subprocess.Popen(['attrib', '.'], stdout=subprocess.PIPE)
46
 
        except OSError, e:
 
48
            import bzrlib._patiencediff_c
 
49
        except ImportError:
47
50
            return False
48
 
        return (0 == proc.wait())
 
51
        return True
49
52
 
50
53
    def feature_name(self):
51
 
        return 'attrib Windows command-line tool'
52
 
 
53
 
AttribFeature = _AttribFeature()
54
 
 
55
 
 
56
 
compiled_patiencediff_feature = tests.ModuleAvailableFeature(
57
 
                                    'bzrlib._patiencediff_c')
58
 
 
 
54
        return 'bzrlib._patiencediff_c'
 
55
 
 
56
CompiledPatienceDiffFeature = _CompiledPatienceDiffFeature()
 
57
 
 
58
 
 
59
class _UnicodeFilename(Feature):
 
60
    """Does the filesystem support Unicode filenames?"""
 
61
 
 
62
    def _probe(self):
 
63
        try:
 
64
            os.stat(u'\u03b1')
 
65
        except UnicodeEncodeError:
 
66
            return False
 
67
        except (IOError, OSError):
 
68
            # The filesystem allows the Unicode filename but the file doesn't
 
69
            # exist.
 
70
            return True
 
71
        else:
 
72
            # The filesystem allows the Unicode filename and the file exists,
 
73
            # for some reason.
 
74
            return True
 
75
 
 
76
UnicodeFilename = _UnicodeFilename()
 
77
 
 
78
 
 
79
class TestUnicodeFilename(TestCase):
 
80
 
 
81
    def test_probe_passes(self):
 
82
        """UnicodeFilename._probe passes."""
 
83
        # We can't test much more than that because the behaviour depends
 
84
        # on the platform.
 
85
        UnicodeFilename._probe()
 
86
        
59
87
 
60
88
def udiff_lines(old, new, allow_binary=False):
61
89
    output = StringIO()
62
 
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
 
90
    internal_diff('old', old, 'new', new, output, allow_binary)
63
91
    output.seek(0, 0)
64
92
    return output.readlines()
65
93
 
69
97
        # StringIO has no fileno, so it tests a different codepath
70
98
        output = StringIO()
71
99
    else:
72
 
        output = tempfile.TemporaryFile()
 
100
        output = TemporaryFile()
73
101
    try:
74
 
        diff.external_diff('old', old, 'new', new, output, diff_opts=['-u'])
75
 
    except errors.NoDiff:
76
 
        raise tests.TestSkipped('external "diff" not present to test')
 
102
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
 
103
    except NoDiff:
 
104
        raise TestSkipped('external "diff" not present to test')
77
105
    output.seek(0, 0)
78
106
    lines = output.readlines()
79
107
    output.close()
80
108
    return lines
81
109
 
82
110
 
83
 
class TestDiff(tests.TestCase):
 
111
class TestDiff(TestCase):
84
112
 
85
113
    def test_add_nl(self):
86
114
        """diff generates a valid diff for patches that add a newline"""
122
150
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
123
151
 
124
152
    def test_binary_lines(self):
125
 
        empty = []
126
 
        uni_lines = [1023 * 'a' + '\x00']
127
 
        self.assertRaises(errors.BinaryFile, udiff_lines, uni_lines , empty)
128
 
        self.assertRaises(errors.BinaryFile, udiff_lines, empty, uni_lines)
129
 
        udiff_lines(uni_lines , empty, allow_binary=True)
130
 
        udiff_lines(empty, uni_lines, allow_binary=True)
 
153
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
 
154
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
 
155
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
 
156
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
131
157
 
132
158
    def test_external_diff(self):
133
159
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
163
189
        orig_path = os.environ['PATH']
164
190
        try:
165
191
            os.environ['PATH'] = ''
166
 
            self.assertRaises(errors.NoDiff, diff.external_diff,
 
192
            self.assertRaises(NoDiff, external_diff,
167
193
                              'old', ['boo\n'], 'new', ['goo\n'],
168
194
                              StringIO(), diff_opts=['-u'])
169
195
        finally:
170
196
            os.environ['PATH'] = orig_path
171
 
 
 
197
        
172
198
    def test_internal_diff_default(self):
173
199
        # Default internal diff encoding is utf8
174
200
        output = StringIO()
175
 
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
176
 
                           u'new_\xe5', ['new_text\n'], output)
 
201
        internal_diff(u'old_\xb5', ['old_text\n'],
 
202
                    u'new_\xe5', ['new_text\n'], output)
177
203
        lines = output.getvalue().splitlines(True)
178
204
        self.check_patch(lines)
179
205
        self.assertEquals(['--- old_\xc2\xb5\n',
187
213
 
188
214
    def test_internal_diff_utf8(self):
189
215
        output = StringIO()
190
 
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
191
 
                           u'new_\xe5', ['new_text\n'], output,
192
 
                           path_encoding='utf8')
 
216
        internal_diff(u'old_\xb5', ['old_text\n'],
 
217
                    u'new_\xe5', ['new_text\n'], output,
 
218
                    path_encoding='utf8')
193
219
        lines = output.getvalue().splitlines(True)
194
220
        self.check_patch(lines)
195
221
        self.assertEquals(['--- old_\xc2\xb5\n',
203
229
 
204
230
    def test_internal_diff_iso_8859_1(self):
205
231
        output = StringIO()
206
 
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
207
 
                           u'new_\xe5', ['new_text\n'], output,
208
 
                           path_encoding='iso-8859-1')
 
232
        internal_diff(u'old_\xb5', ['old_text\n'],
 
233
                    u'new_\xe5', ['new_text\n'], output,
 
234
                    path_encoding='iso-8859-1')
209
235
        lines = output.getvalue().splitlines(True)
210
236
        self.check_patch(lines)
211
237
        self.assertEquals(['--- old_\xb5\n',
219
245
 
220
246
    def test_internal_diff_no_content(self):
221
247
        output = StringIO()
222
 
        diff.internal_diff(u'old', [], u'new', [], output)
 
248
        internal_diff(u'old', [], u'new', [], output)
223
249
        self.assertEqual('', output.getvalue())
224
250
 
225
251
    def test_internal_diff_no_changes(self):
226
252
        output = StringIO()
227
 
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
228
 
                           u'new', ['text\n', 'contents\n'],
229
 
                           output)
 
253
        internal_diff(u'old', ['text\n', 'contents\n'],
 
254
                      u'new', ['text\n', 'contents\n'],
 
255
                      output)
230
256
        self.assertEqual('', output.getvalue())
231
257
 
232
258
    def test_internal_diff_returns_bytes(self):
233
259
        import StringIO
234
260
        output = StringIO.StringIO()
235
 
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
236
 
                            u'new_\xe5', ['new_text\n'], output)
 
261
        internal_diff(u'old_\xb5', ['old_text\n'],
 
262
                    u'new_\xe5', ['new_text\n'], output)
237
263
        self.failUnless(isinstance(output.getvalue(), str),
238
264
            'internal_diff should return bytestrings')
239
265
 
240
266
 
241
 
class TestDiffFiles(tests.TestCaseInTempDir):
 
267
class TestDiffFiles(TestCaseInTempDir):
242
268
 
243
269
    def test_external_diff_binary(self):
244
270
        """The output when using external diff should use diff's i18n error"""
257
283
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
258
284
 
259
285
 
260
 
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
 
286
class TestShowDiffTreesHelper(TestCaseWithTransport):
261
287
    """Has a helper for running show_diff_trees"""
262
288
 
263
289
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
266
292
            extra_trees = (working_tree,)
267
293
        else:
268
294
            extra_trees = ()
269
 
        diff.show_diff_trees(tree1, tree2, output,
270
 
                             specific_files=specific_files,
271
 
                             extra_trees=extra_trees, old_label='old/',
272
 
                             new_label='new/')
 
295
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
 
296
                        extra_trees=extra_trees, old_label='old/',
 
297
                        new_label='new/')
273
298
        return output.getvalue()
274
299
 
275
300
 
340
365
+file2 contents at rev 3
341
366
 
342
367
''')
343
 
 
 
368
        
344
369
    def test_diff_add_files(self):
345
 
        tree1 = self.b.repository.revision_tree(_mod_revision.NULL_REVISION)
 
370
        tree1 = self.b.repository.revision_tree(None)
346
371
        tree2 = self.b.repository.revision_tree('rev-1')
347
372
        output = self.get_diff(tree1, tree2)
348
373
        # the files have the epoch time stamp for the tree in which
382
407
        self.wt.rename_one('file1', 'file1b')
383
408
        old_tree = self.b.repository.revision_tree('rev-1')
384
409
        new_tree = self.b.repository.revision_tree('rev-4')
385
 
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'],
 
410
        out = self.get_diff(old_tree, new_tree, specific_files=['file1b'], 
386
411
                            working_tree=self.wt)
387
412
        self.assertContainsRe(out, 'file1\t')
388
413
 
394
419
        self.wt.rename_one('file1', 'dir1/file1')
395
420
        old_tree = self.b.repository.revision_tree('rev-1')
396
421
        new_tree = self.b.repository.revision_tree('rev-4')
397
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'],
 
422
        out = self.get_diff(old_tree, new_tree, specific_files=['dir1'], 
398
423
                            working_tree=self.wt)
399
424
        self.assertContainsRe(out, 'file1\t')
400
 
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'],
 
425
        out = self.get_diff(old_tree, new_tree, specific_files=['dir2'], 
401
426
                            working_tree=self.wt)
402
427
        self.assertNotContainsRe(out, 'file1\t')
403
428
 
414
439
        tree.commit('one', rev_id='rev-1')
415
440
 
416
441
        self.build_tree_contents([('tree/file', 'new contents\n')])
417
 
        d = self.get_diff(tree.basis_tree(), tree)
418
 
        self.assertContainsRe(d, "=== modified file 'file'\n")
419
 
        self.assertContainsRe(d, '--- old/file\t')
420
 
        self.assertContainsRe(d, '\\+\\+\\+ new/file\t')
421
 
        self.assertContainsRe(d, '-contents\n'
422
 
                                 '\\+new contents\n')
 
442
        diff = self.get_diff(tree.basis_tree(), tree)
 
443
        self.assertContainsRe(diff, "=== modified file 'file'\n")
 
444
        self.assertContainsRe(diff, '--- old/file\t')
 
445
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
 
446
        self.assertContainsRe(diff, '-contents\n'
 
447
                                    '\\+new contents\n')
423
448
 
424
449
    def test_modified_file_in_renamed_dir(self):
425
450
        """Test when a file is modified in a renamed directory."""
431
456
 
432
457
        tree.rename_one('dir', 'other')
433
458
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
434
 
        d = self.get_diff(tree.basis_tree(), tree)
435
 
        self.assertContainsRe(d, "=== renamed directory 'dir' => 'other'\n")
436
 
        self.assertContainsRe(d, "=== modified file 'other/file'\n")
 
459
        diff = self.get_diff(tree.basis_tree(), tree)
 
460
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
 
461
        self.assertContainsRe(diff, "=== modified file 'other/file'\n")
437
462
        # XXX: This is technically incorrect, because it used to be at another
438
463
        # location. What to do?
439
 
        self.assertContainsRe(d, '--- old/dir/file\t')
440
 
        self.assertContainsRe(d, '\\+\\+\\+ new/other/file\t')
441
 
        self.assertContainsRe(d, '-contents\n'
442
 
                                 '\\+new contents\n')
 
464
        self.assertContainsRe(diff, '--- old/dir/file\t')
 
465
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
 
466
        self.assertContainsRe(diff, '-contents\n'
 
467
                                    '\\+new contents\n')
443
468
 
444
469
    def test_renamed_directory(self):
445
470
        """Test when only a directory is only renamed."""
450
475
        tree.commit('one', rev_id='rev-1')
451
476
 
452
477
        tree.rename_one('dir', 'newdir')
453
 
        d = self.get_diff(tree.basis_tree(), tree)
 
478
        diff = self.get_diff(tree.basis_tree(), tree)
454
479
        # Renaming a directory should be a single "you renamed this dir" even
455
480
        # when there are files inside.
456
 
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
 
481
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
457
482
 
458
483
    def test_renamed_file(self):
459
484
        """Test when a file is only renamed."""
463
488
        tree.commit('one', rev_id='rev-1')
464
489
 
465
490
        tree.rename_one('file', 'newname')
466
 
        d = self.get_diff(tree.basis_tree(), tree)
467
 
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
 
491
        diff = self.get_diff(tree.basis_tree(), tree)
 
492
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
468
493
        # We shouldn't have a --- or +++ line, because there is no content
469
494
        # change
470
 
        self.assertNotContainsRe(d, '---')
 
495
        self.assertNotContainsRe(diff, '---')
471
496
 
472
497
    def test_renamed_and_modified_file(self):
473
498
        """Test when a file is only renamed."""
478
503
 
479
504
        tree.rename_one('file', 'newname')
480
505
        self.build_tree_contents([('tree/newname', 'new contents\n')])
481
 
        d = self.get_diff(tree.basis_tree(), tree)
482
 
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
483
 
        self.assertContainsRe(d, '--- old/file\t')
484
 
        self.assertContainsRe(d, '\\+\\+\\+ new/newname\t')
485
 
        self.assertContainsRe(d, '-contents\n'
486
 
                                 '\\+new contents\n')
 
506
        diff = self.get_diff(tree.basis_tree(), tree)
 
507
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
 
508
        self.assertContainsRe(diff, '--- old/file\t')
 
509
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
 
510
        self.assertContainsRe(diff, '-contents\n'
 
511
                                    '\\+new contents\n')
487
512
 
488
513
 
489
514
    def test_internal_diff_exec_property(self):
508
533
        tree.rename_one('c', 'new-c')
509
534
        tree.rename_one('d', 'new-d')
510
535
 
511
 
        d = self.get_diff(tree.basis_tree(), tree)
 
536
        diff = self.get_diff(tree.basis_tree(), tree)
512
537
 
513
 
        self.assertContainsRe(d, r"file 'a'.*\(properties changed:"
514
 
                                  ".*\+x to -x.*\)")
515
 
        self.assertContainsRe(d, r"file 'b'.*\(properties changed:"
516
 
                                  ".*-x to \+x.*\)")
517
 
        self.assertContainsRe(d, r"file 'c'.*\(properties changed:"
518
 
                                  ".*\+x to -x.*\)")
519
 
        self.assertContainsRe(d, r"file 'd'.*\(properties changed:"
520
 
                                  ".*-x to \+x.*\)")
521
 
        self.assertNotContainsRe(d, r"file 'e'")
522
 
        self.assertNotContainsRe(d, r"file 'f'")
 
538
        self.assertContainsRe(diff, r"file 'a'.*\(properties changed:.*\+x to -x.*\)")
 
539
        self.assertContainsRe(diff, r"file 'b'.*\(properties changed:.*-x to \+x.*\)")
 
540
        self.assertContainsRe(diff, r"file 'c'.*\(properties changed:.*\+x to -x.*\)")
 
541
        self.assertContainsRe(diff, r"file 'd'.*\(properties changed:.*-x to \+x.*\)")
 
542
        self.assertNotContainsRe(diff, r"file 'e'")
 
543
        self.assertNotContainsRe(diff, r"file 'f'")
523
544
 
524
545
 
525
546
    def test_binary_unicode_filenames(self):
527
548
        is a binary file in the diff.
528
549
        """
529
550
        # See https://bugs.launchpad.net/bugs/110092.
530
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
551
        self.requireFeature(UnicodeFilename)
531
552
 
532
553
        # This bug isn't triggered with cStringIO.
533
554
        from StringIO import StringIO
541
562
        tree.add([alpha], ['file-id'])
542
563
        tree.add([omega], ['file-id-2'])
543
564
        diff_content = StringIO()
544
 
        diff.show_diff_trees(tree.basis_tree(), tree, diff_content)
545
 
        d = diff_content.getvalue()
546
 
        self.assertContainsRe(d, r"=== added file '%s'" % alpha_utf8)
547
 
        self.assertContainsRe(d, "Binary files a/%s.*and b/%s.* differ\n"
548
 
                              % (alpha_utf8, alpha_utf8))
549
 
        self.assertContainsRe(d, r"=== added file '%s'" % omega_utf8)
550
 
        self.assertContainsRe(d, r"--- a/%s" % (omega_utf8,))
551
 
        self.assertContainsRe(d, r"\+\+\+ b/%s" % (omega_utf8,))
 
565
        show_diff_trees(tree.basis_tree(), tree, diff_content)
 
566
        diff = diff_content.getvalue()
 
567
        self.assertContainsRe(diff, r"=== added file '%s'" % alpha_utf8)
 
568
        self.assertContainsRe(
 
569
            diff, "Binary files a/%s.*and b/%s.* differ\n" % (alpha_utf8, alpha_utf8))
 
570
        self.assertContainsRe(diff, r"=== added file '%s'" % omega_utf8)
 
571
        self.assertContainsRe(diff, r"--- a/%s" % (omega_utf8,))
 
572
        self.assertContainsRe(diff, r"\+\+\+ b/%s" % (omega_utf8,))
552
573
 
553
574
    def test_unicode_filename(self):
554
575
        """Test when the filename are unicode."""
555
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
576
        self.requireFeature(UnicodeFilename)
556
577
 
557
578
        alpha, omega = u'\u03b1', u'\u03c9'
558
579
        autf8, outf8 = alpha.encode('utf8'), omega.encode('utf8')
573
594
        tree.add(['add_'+alpha], ['file-id'])
574
595
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
575
596
 
576
 
        d = self.get_diff(tree.basis_tree(), tree)
577
 
        self.assertContainsRe(d,
 
597
        diff = self.get_diff(tree.basis_tree(), tree)
 
598
        self.assertContainsRe(diff,
578
599
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
579
 
        self.assertContainsRe(d, "=== added file 'add_%s'"%autf8)
580
 
        self.assertContainsRe(d, "=== modified file 'mod_%s'"%autf8)
581
 
        self.assertContainsRe(d, "=== removed file 'del_%s'"%autf8)
582
 
 
583
 
 
584
 
class DiffWasIs(diff.DiffPath):
 
600
        self.assertContainsRe(diff, "=== added file 'add_%s'"%autf8)
 
601
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
 
602
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
 
603
 
 
604
 
 
605
class DiffWasIs(DiffPath):
585
606
 
586
607
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
587
608
        self.to_file.write('was: ')
591
612
        pass
592
613
 
593
614
 
594
 
class TestDiffTree(tests.TestCaseWithTransport):
 
615
class TestDiffTree(TestCaseWithTransport):
595
616
 
596
617
    def setUp(self):
597
 
        super(TestDiffTree, self).setUp()
 
618
        TestCaseWithTransport.setUp(self)
598
619
        self.old_tree = self.make_branch_and_tree('old-tree')
599
620
        self.old_tree.lock_write()
600
621
        self.addCleanup(self.old_tree.unlock)
601
622
        self.new_tree = self.make_branch_and_tree('new-tree')
602
623
        self.new_tree.lock_write()
603
624
        self.addCleanup(self.new_tree.unlock)
604
 
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
 
625
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
605
626
 
606
627
    def test_diff_text(self):
607
628
        self.build_tree_contents([('old-tree/olddir/',),
612
633
                                  ('new-tree/newdir/newfile', 'new\n')])
613
634
        self.new_tree.add('newdir')
614
635
        self.new_tree.add('newdir/newfile', 'file-id')
615
 
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
 
636
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
616
637
        differ.diff_text('file-id', None, 'old label', 'new label')
617
638
        self.assertEqual(
618
639
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
647
668
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
648
669
 
649
670
    def test_diff_symlink(self):
650
 
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
671
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
651
672
        differ.diff_symlink('old target', None)
652
673
        self.assertEqual("=== target was 'old target'\n",
653
674
                         differ.to_file.getvalue())
654
675
 
655
 
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
676
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
656
677
        differ.diff_symlink(None, 'new target')
657
678
        self.assertEqual("=== target is 'new target'\n",
658
679
                         differ.to_file.getvalue())
659
680
 
660
 
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
681
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
661
682
        differ.diff_symlink('old target', 'new target')
662
683
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
663
684
                         differ.to_file.getvalue())
693
714
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
694
715
             ' \@\@\n-old\n\n')
695
716
        self.assertContainsRe(self.differ.to_file.getvalue(),
696
 
                              "=== target is u'new'\n")
 
717
                              "=== target is 'new'\n")
697
718
 
698
719
    def test_diff_directory(self):
699
720
        self.build_tree(['new-tree/new-dir/'])
713
734
 
714
735
    def test_register_diff(self):
715
736
        self.create_old_new()
716
 
        old_diff_factories = diff.DiffTree.diff_factories
717
 
        diff.DiffTree.diff_factories=old_diff_factories[:]
718
 
        diff.DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
 
737
        old_diff_factories = DiffTree.diff_factories
 
738
        DiffTree.diff_factories=old_diff_factories[:]
 
739
        DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
719
740
        try:
720
 
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
 
741
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
721
742
        finally:
722
 
            diff.DiffTree.diff_factories = old_diff_factories
 
743
            DiffTree.diff_factories = old_diff_factories
723
744
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
724
745
        self.assertNotContainsRe(
725
746
            differ.to_file.getvalue(),
730
751
 
731
752
    def test_extra_factories(self):
732
753
        self.create_old_new()
733
 
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
734
 
                               extra_factories=[DiffWasIs.from_diff_tree])
 
754
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
 
755
                            extra_factories=[DiffWasIs.from_diff_tree])
735
756
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
736
757
        self.assertNotContainsRe(
737
758
            differ.to_file.getvalue(),
750
771
            '.*a-file(.|\n)*b-file')
751
772
 
752
773
 
753
 
class TestPatienceDiffLib(tests.TestCase):
 
774
class TestPatienceDiffLib(TestCase):
754
775
 
755
776
    def setUp(self):
756
777
        super(TestPatienceDiffLib, self).setUp()
757
 
        self._unique_lcs = _patiencediff_py.unique_lcs_py
758
 
        self._recurse_matches = _patiencediff_py.recurse_matches_py
 
778
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
 
779
        self._recurse_matches = bzrlib._patiencediff_py.recurse_matches_py
759
780
        self._PatienceSequenceMatcher = \
760
 
            _patiencediff_py.PatienceSequenceMatcher_py
761
 
 
762
 
    def test_diff_unicode_string(self):
763
 
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
764
 
        b = ''.join([unichr(i) for i in range(4300, 4800, 2)])
765
 
        sm = self._PatienceSequenceMatcher(None, a, b)
766
 
        mb = sm.get_matching_blocks()
767
 
        self.assertEquals(35, len(mb))
 
781
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
768
782
 
769
783
    def test_unique_lcs(self):
770
784
        unique_lcs = self._unique_lcs
776
790
        self.assertEquals(unique_lcs('ab', 'ab'), [(0,0), (1,1)])
777
791
        self.assertEquals(unique_lcs('abcde', 'cdeab'), [(2,0), (3,1), (4,2)])
778
792
        self.assertEquals(unique_lcs('cdeab', 'abcde'), [(0,2), (1,3), (2,4)])
779
 
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1),
 
793
        self.assertEquals(unique_lcs('abXde', 'abYde'), [(0,0), (1,1), 
780
794
                                                         (3,3), (4,4)])
781
795
        self.assertEquals(unique_lcs('acbac', 'abc'), [(2,1)])
782
796
 
797
811
        test_one('abcdbce', 'afbcgdbce', [(0,0), (1, 2), (2, 3), (3, 5),
798
812
                                          (4, 6), (5, 7), (6, 8)])
799
813
 
800
 
        # recurse_matches doesn't match non-unique
 
814
        # recurse_matches doesn't match non-unique 
801
815
        # lines surrounded by bogus text.
802
816
        # The update has been done in patiencediff.SequenceMatcher instead
803
817
 
940
954
                 ('delete', 1,2, 1,1),
941
955
                 ('equal',  2,3, 1,2),
942
956
                ])
943
 
        chk_ops('aBccDe', 'abccde',
 
957
        chk_ops('aBccDe', 'abccde', 
944
958
                [('equal',   0,1, 0,1),
945
959
                 ('replace', 1,5, 1,5),
946
960
                 ('equal',   5,6, 5,6),
947
961
                ])
948
 
        chk_ops('aBcDec', 'abcdec',
 
962
        chk_ops('aBcDec', 'abcdec', 
949
963
                [('equal',   0,1, 0,1),
950
964
                 ('replace', 1,2, 1,2),
951
965
                 ('equal',   2,3, 2,3),
952
966
                 ('replace', 3,4, 3,4),
953
967
                 ('equal',   4,6, 4,6),
954
968
                ])
955
 
        chk_ops('aBcdEcdFg', 'abcdecdfg',
 
969
        chk_ops('aBcdEcdFg', 'abcdecdfg', 
956
970
                [('equal',   0,1, 0,1),
957
971
                 ('replace', 1,8, 1,8),
958
972
                 ('equal',   8,9, 8,9)
959
973
                ])
960
 
        chk_ops('aBcdEeXcdFg', 'abcdecdfg',
 
974
        chk_ops('aBcdEeXcdFg', 'abcdecdfg', 
961
975
                [('equal',   0,1, 0,1),
962
976
                 ('replace', 1,2, 1,2),
963
977
                 ('equal',   2,4, 2,4),
1023
1037
    """
1024
1038
    gnxrf_netf = ['svyr*']
1025
1039
    gnxrf_bcgvbaf = ['ab-erphefr']
1026
 
 
 
1040
  
1027
1041
    qrs eha(frys, svyr_yvfg, ab_erphefr=Snyfr):
1028
1042
        sebz omeyvo.nqq vzcbeg fzneg_nqq, nqq_ercbegre_cevag, nqq_ercbegre_ahyy
1029
1043
        vs vf_dhvrg():
1037
1051
'''.splitlines(True), '''\
1038
1052
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
1039
1053
 
1040
 
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl
 
1054
    --qel-eha jvyy fubj juvpu svyrf jbhyq or nqqrq, ohg abg npghnyyl 
1041
1055
    nqq gurz.
1042
1056
    """
1043
1057
    gnxrf_netf = ['svyr*']
1070
1084
                 'how are you today?\n']
1071
1085
        txt_b = ['hello there\n',
1072
1086
                 'how are you today?\n']
1073
 
        unified_diff = patiencediff.unified_diff
 
1087
        unified_diff = bzrlib.patiencediff.unified_diff
1074
1088
        psm = self._PatienceSequenceMatcher
1075
 
        self.assertEquals(['--- \n',
1076
 
                           '+++ \n',
 
1089
        self.assertEquals([ '---  \n',
 
1090
                           '+++  \n',
1077
1091
                           '@@ -1,3 +1,2 @@\n',
1078
1092
                           ' hello there\n',
1079
1093
                           '-world\n',
1084
1098
        txt_a = map(lambda x: x+'\n', 'abcdefghijklmnop')
1085
1099
        txt_b = map(lambda x: x+'\n', 'abcdefxydefghijklmnop')
1086
1100
        # This is the result with LongestCommonSubstring matching
1087
 
        self.assertEquals(['--- \n',
1088
 
                           '+++ \n',
 
1101
        self.assertEquals(['---  \n',
 
1102
                           '+++  \n',
1089
1103
                           '@@ -1,6 +1,11 @@\n',
1090
1104
                           ' a\n',
1091
1105
                           ' b\n',
1100
1114
                           ' f\n']
1101
1115
                          , list(unified_diff(txt_a, txt_b)))
1102
1116
        # And the patience diff
1103
 
        self.assertEquals(['--- \n',
1104
 
                           '+++ \n',
 
1117
        self.assertEquals(['---  \n',
 
1118
                           '+++  \n',
1105
1119
                           '@@ -4,6 +4,11 @@\n',
1106
1120
                           ' d\n',
1107
1121
                           ' e\n',
1118
1132
                          , list(unified_diff(txt_a, txt_b,
1119
1133
                                 sequencematcher=psm)))
1120
1134
 
1121
 
    def test_patience_unified_diff_with_dates(self):
1122
 
        txt_a = ['hello there\n',
1123
 
                 'world\n',
1124
 
                 'how are you today?\n']
1125
 
        txt_b = ['hello there\n',
1126
 
                 'how are you today?\n']
1127
 
        unified_diff = patiencediff.unified_diff
1128
 
        psm = self._PatienceSequenceMatcher
1129
 
        self.assertEquals(['--- a\t2008-08-08\n',
1130
 
                           '+++ b\t2008-09-09\n',
1131
 
                           '@@ -1,3 +1,2 @@\n',
1132
 
                           ' hello there\n',
1133
 
                           '-world\n',
1134
 
                           ' how are you today?\n'
1135
 
                          ]
1136
 
                          , list(unified_diff(txt_a, txt_b,
1137
 
                                 fromfile='a', tofile='b',
1138
 
                                 fromfiledate='2008-08-08',
1139
 
                                 tofiledate='2008-09-09',
1140
 
                                 sequencematcher=psm)))
1141
 
 
1142
1135
 
1143
1136
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1144
1137
 
1145
 
    _test_needs_features = [compiled_patiencediff_feature]
 
1138
    _test_needs_features = [CompiledPatienceDiffFeature]
1146
1139
 
1147
1140
    def setUp(self):
1148
1141
        super(TestPatienceDiffLib_c, self).setUp()
1149
 
        from bzrlib import _patiencediff_c
1150
 
        self._unique_lcs = _patiencediff_c.unique_lcs_c
1151
 
        self._recurse_matches = _patiencediff_c.recurse_matches_c
 
1142
        import bzrlib._patiencediff_c
 
1143
        self._unique_lcs = bzrlib._patiencediff_c.unique_lcs_c
 
1144
        self._recurse_matches = bzrlib._patiencediff_c.recurse_matches_c
1152
1145
        self._PatienceSequenceMatcher = \
1153
 
            _patiencediff_c.PatienceSequenceMatcher_c
 
1146
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
1154
1147
 
1155
1148
    def test_unhashable(self):
1156
1149
        """We should get a proper exception here."""
1166
1159
                                         None, ['valid'], ['valid', []])
1167
1160
 
1168
1161
 
1169
 
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
 
1162
class TestPatienceDiffLibFiles(TestCaseInTempDir):
1170
1163
 
1171
1164
    def setUp(self):
1172
1165
        super(TestPatienceDiffLibFiles, self).setUp()
1173
1166
        self._PatienceSequenceMatcher = \
1174
 
            _patiencediff_py.PatienceSequenceMatcher_py
 
1167
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
1175
1168
 
1176
1169
    def test_patience_unified_diff_files(self):
1177
1170
        txt_a = ['hello there\n',
1182
1175
        open('a1', 'wb').writelines(txt_a)
1183
1176
        open('b1', 'wb').writelines(txt_b)
1184
1177
 
1185
 
        unified_diff_files = patiencediff.unified_diff_files
 
1178
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
1186
1179
        psm = self._PatienceSequenceMatcher
1187
 
        self.assertEquals(['--- a1\n',
1188
 
                           '+++ b1\n',
 
1180
        self.assertEquals(['--- a1 \n',
 
1181
                           '+++ b1 \n',
1189
1182
                           '@@ -1,3 +1,2 @@\n',
1190
1183
                           ' hello there\n',
1191
1184
                           '-world\n',
1200
1193
        open('b2', 'wb').writelines(txt_b)
1201
1194
 
1202
1195
        # This is the result with LongestCommonSubstring matching
1203
 
        self.assertEquals(['--- a2\n',
1204
 
                           '+++ b2\n',
 
1196
        self.assertEquals(['--- a2 \n',
 
1197
                           '+++ b2 \n',
1205
1198
                           '@@ -1,6 +1,11 @@\n',
1206
1199
                           ' a\n',
1207
1200
                           ' b\n',
1217
1210
                          , list(unified_diff_files('a2', 'b2')))
1218
1211
 
1219
1212
        # And the patience diff
1220
 
        self.assertEquals(['--- a2\n',
1221
 
                           '+++ b2\n',
 
1213
        self.assertEquals(['--- a2 \n',
 
1214
                           '+++ b2 \n',
1222
1215
                           '@@ -4,6 +4,11 @@\n',
1223
1216
                           ' d\n',
1224
1217
                           ' e\n',
1238
1231
 
1239
1232
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1240
1233
 
1241
 
    _test_needs_features = [compiled_patiencediff_feature]
 
1234
    _test_needs_features = [CompiledPatienceDiffFeature]
1242
1235
 
1243
1236
    def setUp(self):
1244
1237
        super(TestPatienceDiffLibFiles_c, self).setUp()
1245
 
        from bzrlib import _patiencediff_c
 
1238
        import bzrlib._patiencediff_c
1246
1239
        self._PatienceSequenceMatcher = \
1247
 
            _patiencediff_c.PatienceSequenceMatcher_c
1248
 
 
1249
 
 
1250
 
class TestUsingCompiledIfAvailable(tests.TestCase):
 
1240
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
 
1241
 
 
1242
 
 
1243
class TestUsingCompiledIfAvailable(TestCase):
1251
1244
 
1252
1245
    def test_PatienceSequenceMatcher(self):
1253
 
        if compiled_patiencediff_feature.available():
 
1246
        if CompiledPatienceDiffFeature.available():
1254
1247
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1255
1248
            self.assertIs(PatienceSequenceMatcher_c,
1256
 
                          patiencediff.PatienceSequenceMatcher)
 
1249
                          bzrlib.patiencediff.PatienceSequenceMatcher)
1257
1250
        else:
1258
1251
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1259
1252
            self.assertIs(PatienceSequenceMatcher_py,
1260
 
                          patiencediff.PatienceSequenceMatcher)
 
1253
                          bzrlib.patiencediff.PatienceSequenceMatcher)
1261
1254
 
1262
1255
    def test_unique_lcs(self):
1263
 
        if compiled_patiencediff_feature.available():
 
1256
        if CompiledPatienceDiffFeature.available():
1264
1257
            from bzrlib._patiencediff_c import unique_lcs_c
1265
1258
            self.assertIs(unique_lcs_c,
1266
 
                          patiencediff.unique_lcs)
 
1259
                          bzrlib.patiencediff.unique_lcs)
1267
1260
        else:
1268
1261
            from bzrlib._patiencediff_py import unique_lcs_py
1269
1262
            self.assertIs(unique_lcs_py,
1270
 
                          patiencediff.unique_lcs)
 
1263
                          bzrlib.patiencediff.unique_lcs)
1271
1264
 
1272
1265
    def test_recurse_matches(self):
1273
 
        if compiled_patiencediff_feature.available():
 
1266
        if CompiledPatienceDiffFeature.available():
1274
1267
            from bzrlib._patiencediff_c import recurse_matches_c
1275
1268
            self.assertIs(recurse_matches_c,
1276
 
                          patiencediff.recurse_matches)
 
1269
                          bzrlib.patiencediff.recurse_matches)
1277
1270
        else:
1278
1271
            from bzrlib._patiencediff_py import recurse_matches_py
1279
1272
            self.assertIs(recurse_matches_py,
1280
 
                          patiencediff.recurse_matches)
1281
 
 
1282
 
 
1283
 
class TestDiffFromTool(tests.TestCaseWithTransport):
 
1273
                          bzrlib.patiencediff.recurse_matches)
 
1274
 
 
1275
 
 
1276
class TestDiffFromTool(TestCaseWithTransport):
1284
1277
 
1285
1278
    def test_from_string(self):
1286
 
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
 
1279
        diff_obj = DiffFromTool.from_string('diff', None, None, None)
1287
1280
        self.addCleanup(diff_obj.finish)
1288
 
        self.assertEqual(['diff', '@old_path', '@new_path'],
 
1281
        self.assertEqual(['diff', '%(old_path)s', '%(new_path)s'],
1289
1282
            diff_obj.command_template)
1290
1283
 
1291
1284
    def test_from_string_u5(self):
1292
 
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
1293
 
                                                 None, None, None)
 
1285
        diff_obj = DiffFromTool.from_string('diff -u\\ 5', None, None, None)
1294
1286
        self.addCleanup(diff_obj.finish)
1295
 
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
 
1287
        self.assertEqual(['diff', '-u 5', '%(old_path)s', '%(new_path)s'],
1296
1288
                         diff_obj.command_template)
1297
1289
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1298
1290
                         diff_obj._get_command('old-path', 'new-path'))
1299
1291
 
1300
 
    def test_from_string_path_with_backslashes(self):
1301
 
        self.requireFeature(test_win32utils.BackslashDirSeparatorFeature)
1302
 
        tool = 'C:\\Tools\\Diff.exe'
1303
 
        diff_obj = diff.DiffFromTool.from_string(tool, None, None, None)
1304
 
        self.addCleanup(diff_obj.finish)
1305
 
        self.assertEqual(['C:\\Tools\\Diff.exe', '@old_path', '@new_path'],
1306
 
                         diff_obj.command_template)
1307
 
        self.assertEqual(['C:\\Tools\\Diff.exe', 'old-path', 'new-path'],
1308
 
                         diff_obj._get_command('old-path', 'new-path'))
1309
 
 
1310
1292
    def test_execute(self):
1311
1293
        output = StringIO()
1312
 
        diff_obj = diff.DiffFromTool(['python', '-c',
1313
 
                                      'print "@old_path @new_path"'],
1314
 
                                     None, None, output)
 
1294
        diff_obj = DiffFromTool(['python', '-c',
 
1295
                                 'print "%(old_path)s %(new_path)s"'],
 
1296
                                None, None, output)
1315
1297
        self.addCleanup(diff_obj.finish)
1316
1298
        diff_obj._execute('old', 'new')
1317
1299
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1318
1300
 
1319
1301
    def test_excute_missing(self):
1320
 
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1321
 
                                     None, None, None)
 
1302
        diff_obj = DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
 
1303
                                None, None, None)
1322
1304
        self.addCleanup(diff_obj.finish)
1323
 
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
1324
 
                              'old', 'new')
 
1305
        e = self.assertRaises(ExecutableMissing, diff_obj._execute, 'old',
 
1306
                              'new')
1325
1307
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1326
1308
                         ' on this machine', str(e))
1327
1309
 
1328
 
    def test_prepare_files_creates_paths_readable_by_windows_tool(self):
1329
 
        self.requireFeature(AttribFeature)
1330
 
        output = StringIO()
1331
 
        tree = self.make_branch_and_tree('tree')
1332
 
        self.build_tree_contents([('tree/file', 'content')])
1333
 
        tree.add('file', 'file-id')
1334
 
        tree.commit('old tree')
1335
 
        tree.lock_read()
1336
 
        self.addCleanup(tree.unlock)
1337
 
        basis_tree = tree.basis_tree()
1338
 
        basis_tree.lock_read()
1339
 
        self.addCleanup(basis_tree.unlock)
1340
 
        diff_obj = diff.DiffFromTool(['python', '-c',
1341
 
                                      'print "@old_path @new_path"'],
1342
 
                                     basis_tree, tree, output)
1343
 
        diff_obj._prepare_files('file-id', 'file', 'file')
1344
 
        # The old content should be readonly
1345
 
        self.assertReadableByAttrib(diff_obj._root, 'old\\file',
1346
 
                                    r'R.*old\\file$')
1347
 
        # The new content should use the tree object, not a 'new' file anymore
1348
 
        self.assertEndsWith(tree.basedir, 'work/tree')
1349
 
        self.assertReadableByAttrib(tree.basedir, 'file', r'work\\tree\\file$')
1350
 
 
1351
 
    def assertReadableByAttrib(self, cwd, relpath, regex):
1352
 
        proc = subprocess.Popen(['attrib', relpath],
1353
 
                                stdout=subprocess.PIPE,
1354
 
                                cwd=cwd)
1355
 
        (result, err) = proc.communicate()
1356
 
        self.assertContainsRe(result.replace('\r\n', '\n'), regex)
1357
 
 
1358
1310
    def test_prepare_files(self):
1359
1311
        output = StringIO()
1360
1312
        tree = self.make_branch_and_tree('tree')
1361
1313
        self.build_tree_contents([('tree/oldname', 'oldcontent')])
1362
 
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
1363
1314
        tree.add('oldname', 'file-id')
1364
 
        tree.add('oldname2', 'file2-id')
1365
 
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
1366
 
        tree.commit('old tree', timestamp=315532800)
 
1315
        tree.commit('old tree', timestamp=0)
1367
1316
        tree.rename_one('oldname', 'newname')
1368
 
        tree.rename_one('oldname2', 'newname2')
1369
1317
        self.build_tree_contents([('tree/newname', 'newcontent')])
1370
 
        self.build_tree_contents([('tree/newname2', 'newcontent2')])
1371
1318
        old_tree = tree.basis_tree()
1372
1319
        old_tree.lock_read()
1373
1320
        self.addCleanup(old_tree.unlock)
1374
1321
        tree.lock_read()
1375
1322
        self.addCleanup(tree.unlock)
1376
 
        diff_obj = diff.DiffFromTool(['python', '-c',
1377
 
                                      'print "@old_path @new_path"'],
1378
 
                                     old_tree, tree, output)
 
1323
        diff_obj = DiffFromTool(['python', '-c',
 
1324
                                 'print "%(old_path)s %(new_path)s"'],
 
1325
                                old_tree, tree, output)
1379
1326
        self.addCleanup(diff_obj.finish)
1380
1327
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1381
1328
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1382
1329
                                                     'newname')
1383
1330
        self.assertContainsRe(old_path, 'old/oldname$')
1384
 
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1385
 
        self.assertContainsRe(new_path, 'tree/newname$')
 
1331
        self.assertEqual(0, os.stat(old_path).st_mtime)
 
1332
        self.assertContainsRe(new_path, 'new/newname$')
1386
1333
        self.assertFileEqual('oldcontent', old_path)
1387
1334
        self.assertFileEqual('newcontent', new_path)
1388
 
        if osutils.host_os_dereferences_symlinks():
 
1335
        if osutils.has_symlinks():
1389
1336
            self.assertTrue(os.path.samefile('tree/newname', new_path))
1390
1337
        # make sure we can create files with the same parent directories
1391
 
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1392
 
 
1393
 
 
1394
 
class TestGetTreesAndBranchesToDiffLocked(tests.TestCaseWithTransport):
1395
 
 
1396
 
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
1397
 
        """Call get_trees_and_branches_to_diff_locked.  Overridden by
1398
 
        TestGetTreesAndBranchesToDiff.
1399
 
        """
1400
 
        return diff.get_trees_and_branches_to_diff_locked(
1401
 
            path_list, revision_specs, old_url, new_url, self.addCleanup)
1402
 
 
1403
 
    def test_basic(self):
1404
 
        tree = self.make_branch_and_tree('tree')
1405
 
        (old_tree, new_tree,
1406
 
         old_branch, new_branch,
1407
 
         specific_files, extra_trees) = self.call_gtabtd(
1408
 
             ['tree'], None, None, None)
1409
 
 
1410
 
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1411
 
        self.assertEqual(_mod_revision.NULL_REVISION,
1412
 
                         old_tree.get_revision_id())
1413
 
        self.assertEqual(tree.basedir, new_tree.basedir)
1414
 
        self.assertEqual(tree.branch.base, old_branch.base)
1415
 
        self.assertEqual(tree.branch.base, new_branch.base)
1416
 
        self.assertIs(None, specific_files)
1417
 
        self.assertIs(None, extra_trees)
1418
 
 
1419
 
    def test_with_rev_specs(self):
1420
 
        tree = self.make_branch_and_tree('tree')
1421
 
        self.build_tree_contents([('tree/file', 'oldcontent')])
1422
 
        tree.add('file', 'file-id')
1423
 
        tree.commit('old tree', timestamp=0, rev_id="old-id")
1424
 
        self.build_tree_contents([('tree/file', 'newcontent')])
1425
 
        tree.commit('new tree', timestamp=0, rev_id="new-id")
1426
 
 
1427
 
        revisions = [revisionspec.RevisionSpec.from_string('1'),
1428
 
                     revisionspec.RevisionSpec.from_string('2')]
1429
 
        (old_tree, new_tree,
1430
 
         old_branch, new_branch,
1431
 
         specific_files, extra_trees) = self.call_gtabtd(
1432
 
            ['tree'], revisions, None, None)
1433
 
 
1434
 
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1435
 
        self.assertEqual("old-id", old_tree.get_revision_id())
1436
 
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
1437
 
        self.assertEqual("new-id", new_tree.get_revision_id())
1438
 
        self.assertEqual(tree.branch.base, old_branch.base)
1439
 
        self.assertEqual(tree.branch.base, new_branch.base)
1440
 
        self.assertIs(None, specific_files)
1441
 
        self.assertEqual(tree.basedir, extra_trees[0].basedir)
1442
 
 
1443
 
 
1444
 
class TestGetTreesAndBranchesToDiff(TestGetTreesAndBranchesToDiffLocked):
1445
 
    """Apply the tests for get_trees_and_branches_to_diff_locked to the
1446
 
    deprecated get_trees_and_branches_to_diff function.
1447
 
    """
1448
 
 
1449
 
    def call_gtabtd(self, path_list, revision_specs, old_url, new_url):
1450
 
        return self.applyDeprecated(
1451
 
            deprecated_in((2, 2, 0)), diff.get_trees_and_branches_to_diff,
1452
 
            path_list, revision_specs, old_url, new_url)
1453
 
 
 
1338
        diff_obj._prepare_files('file-id', 'oldname2', 'newname2')