/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_diff.py

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
 
21
import tempfile
24
22
 
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,
 
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,
36
34
    )
37
 
from bzrlib.errors import BinaryFile, NoDiff, ExecutableMissing
38
 
import bzrlib.osutils as osutils
39
 
import bzrlib.revision as _mod_revision
40
 
import bzrlib.transform as transform
41
 
import bzrlib.patiencediff
42
 
import bzrlib._patiencediff_py
43
 
from bzrlib.tests import (Feature, TestCase, TestCaseWithTransport,
44
 
                          TestCaseInTempDir, TestSkipped)
45
 
from bzrlib.revisiontree import RevisionTree
46
 
from bzrlib.revisionspec import RevisionSpec
47
 
 
48
 
 
49
 
class _AttribFeature(Feature):
 
35
from bzrlib.symbol_versioning import deprecated_in
 
36
from bzrlib.tests import test_win32utils
 
37
 
 
38
 
 
39
class _AttribFeature(tests.Feature):
50
40
 
51
41
    def _probe(self):
52
42
        if (sys.platform not in ('cygwin', 'win32')):
63
53
AttribFeature = _AttribFeature()
64
54
 
65
55
 
66
 
class _CompiledPatienceDiffFeature(Feature):
67
 
 
68
 
    def _probe(self):
69
 
        try:
70
 
            import bzrlib._patiencediff_c
71
 
        except ImportError:
72
 
            return False
73
 
        return True
74
 
 
75
 
    def feature_name(self):
76
 
        return 'bzrlib._patiencediff_c'
77
 
 
78
 
CompiledPatienceDiffFeature = _CompiledPatienceDiffFeature()
 
56
compiled_patiencediff_feature = tests.ModuleAvailableFeature(
 
57
                                    'bzrlib._patiencediff_c')
79
58
 
80
59
 
81
60
def udiff_lines(old, new, allow_binary=False):
82
61
    output = StringIO()
83
 
    internal_diff('old', old, 'new', new, output, allow_binary)
 
62
    diff.internal_diff('old', old, 'new', new, output, allow_binary)
84
63
    output.seek(0, 0)
85
64
    return output.readlines()
86
65
 
90
69
        # StringIO has no fileno, so it tests a different codepath
91
70
        output = StringIO()
92
71
    else:
93
 
        output = TemporaryFile()
 
72
        output = tempfile.TemporaryFile()
94
73
    try:
95
 
        external_diff('old', old, 'new', new, output, diff_opts=['-u'])
96
 
    except NoDiff:
97
 
        raise TestSkipped('external "diff" not present to test')
 
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')
98
77
    output.seek(0, 0)
99
78
    lines = output.readlines()
100
79
    output.close()
101
80
    return lines
102
81
 
103
82
 
104
 
class TestDiff(TestCase):
 
83
class TestDiff(tests.TestCase):
105
84
 
106
85
    def test_add_nl(self):
107
86
        """diff generates a valid diff for patches that add a newline"""
143
122
            ## "Unterminated hunk header for patch:\n%s" % "".join(lines)
144
123
 
145
124
    def test_binary_lines(self):
146
 
        self.assertRaises(BinaryFile, udiff_lines, [1023 * 'a' + '\x00'], [])
147
 
        self.assertRaises(BinaryFile, udiff_lines, [], [1023 * 'a' + '\x00'])
148
 
        udiff_lines([1023 * 'a' + '\x00'], [], allow_binary=True)
149
 
        udiff_lines([], [1023 * 'a' + '\x00'], allow_binary=True)
 
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)
150
131
 
151
132
    def test_external_diff(self):
152
133
        lines = external_udiff_lines(['boo\n'], ['goo\n'])
182
163
        orig_path = os.environ['PATH']
183
164
        try:
184
165
            os.environ['PATH'] = ''
185
 
            self.assertRaises(NoDiff, external_diff,
 
166
            self.assertRaises(errors.NoDiff, diff.external_diff,
186
167
                              'old', ['boo\n'], 'new', ['goo\n'],
187
168
                              StringIO(), diff_opts=['-u'])
188
169
        finally:
191
172
    def test_internal_diff_default(self):
192
173
        # Default internal diff encoding is utf8
193
174
        output = StringIO()
194
 
        internal_diff(u'old_\xb5', ['old_text\n'],
195
 
                    u'new_\xe5', ['new_text\n'], output)
 
175
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
176
                           u'new_\xe5', ['new_text\n'], output)
196
177
        lines = output.getvalue().splitlines(True)
197
178
        self.check_patch(lines)
198
179
        self.assertEquals(['--- old_\xc2\xb5\n',
206
187
 
207
188
    def test_internal_diff_utf8(self):
208
189
        output = StringIO()
209
 
        internal_diff(u'old_\xb5', ['old_text\n'],
210
 
                    u'new_\xe5', ['new_text\n'], output,
211
 
                    path_encoding='utf8')
 
190
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
191
                           u'new_\xe5', ['new_text\n'], output,
 
192
                           path_encoding='utf8')
212
193
        lines = output.getvalue().splitlines(True)
213
194
        self.check_patch(lines)
214
195
        self.assertEquals(['--- old_\xc2\xb5\n',
222
203
 
223
204
    def test_internal_diff_iso_8859_1(self):
224
205
        output = StringIO()
225
 
        internal_diff(u'old_\xb5', ['old_text\n'],
226
 
                    u'new_\xe5', ['new_text\n'], output,
227
 
                    path_encoding='iso-8859-1')
 
206
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
207
                           u'new_\xe5', ['new_text\n'], output,
 
208
                           path_encoding='iso-8859-1')
228
209
        lines = output.getvalue().splitlines(True)
229
210
        self.check_patch(lines)
230
211
        self.assertEquals(['--- old_\xb5\n',
238
219
 
239
220
    def test_internal_diff_no_content(self):
240
221
        output = StringIO()
241
 
        internal_diff(u'old', [], u'new', [], output)
 
222
        diff.internal_diff(u'old', [], u'new', [], output)
242
223
        self.assertEqual('', output.getvalue())
243
224
 
244
225
    def test_internal_diff_no_changes(self):
245
226
        output = StringIO()
246
 
        internal_diff(u'old', ['text\n', 'contents\n'],
247
 
                      u'new', ['text\n', 'contents\n'],
248
 
                      output)
 
227
        diff.internal_diff(u'old', ['text\n', 'contents\n'],
 
228
                           u'new', ['text\n', 'contents\n'],
 
229
                           output)
249
230
        self.assertEqual('', output.getvalue())
250
231
 
251
232
    def test_internal_diff_returns_bytes(self):
252
233
        import StringIO
253
234
        output = StringIO.StringIO()
254
 
        internal_diff(u'old_\xb5', ['old_text\n'],
255
 
                    u'new_\xe5', ['new_text\n'], output)
 
235
        diff.internal_diff(u'old_\xb5', ['old_text\n'],
 
236
                            u'new_\xe5', ['new_text\n'], output)
256
237
        self.failUnless(isinstance(output.getvalue(), str),
257
238
            'internal_diff should return bytestrings')
258
239
 
259
240
 
260
 
class TestDiffFiles(TestCaseInTempDir):
 
241
class TestDiffFiles(tests.TestCaseInTempDir):
261
242
 
262
243
    def test_external_diff_binary(self):
263
244
        """The output when using external diff should use diff's i18n error"""
276
257
        self.assertEqual(out.splitlines(True) + ['\n'], lines)
277
258
 
278
259
 
279
 
class TestShowDiffTreesHelper(TestCaseWithTransport):
 
260
class TestShowDiffTreesHelper(tests.TestCaseWithTransport):
280
261
    """Has a helper for running show_diff_trees"""
281
262
 
282
263
    def get_diff(self, tree1, tree2, specific_files=None, working_tree=None):
285
266
            extra_trees = (working_tree,)
286
267
        else:
287
268
            extra_trees = ()
288
 
        show_diff_trees(tree1, tree2, output, specific_files=specific_files,
289
 
                        extra_trees=extra_trees, old_label='old/',
290
 
                        new_label='new/')
 
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/')
291
273
        return output.getvalue()
292
274
 
293
275
 
432
414
        tree.commit('one', rev_id='rev-1')
433
415
 
434
416
        self.build_tree_contents([('tree/file', 'new contents\n')])
435
 
        diff = self.get_diff(tree.basis_tree(), tree)
436
 
        self.assertContainsRe(diff, "=== modified file 'file'\n")
437
 
        self.assertContainsRe(diff, '--- old/file\t')
438
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/file\t')
439
 
        self.assertContainsRe(diff, '-contents\n'
440
 
                                    '\\+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')
441
423
 
442
424
    def test_modified_file_in_renamed_dir(self):
443
425
        """Test when a file is modified in a renamed directory."""
449
431
 
450
432
        tree.rename_one('dir', 'other')
451
433
        self.build_tree_contents([('tree/other/file', 'new contents\n')])
452
 
        diff = self.get_diff(tree.basis_tree(), tree)
453
 
        self.assertContainsRe(diff, "=== renamed directory 'dir' => 'other'\n")
454
 
        self.assertContainsRe(diff, "=== modified file 'other/file'\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")
455
437
        # XXX: This is technically incorrect, because it used to be at another
456
438
        # location. What to do?
457
 
        self.assertContainsRe(diff, '--- old/dir/file\t')
458
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/other/file\t')
459
 
        self.assertContainsRe(diff, '-contents\n'
460
 
                                    '\\+new contents\n')
 
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')
461
443
 
462
444
    def test_renamed_directory(self):
463
445
        """Test when only a directory is only renamed."""
468
450
        tree.commit('one', rev_id='rev-1')
469
451
 
470
452
        tree.rename_one('dir', 'newdir')
471
 
        diff = self.get_diff(tree.basis_tree(), tree)
 
453
        d = self.get_diff(tree.basis_tree(), tree)
472
454
        # Renaming a directory should be a single "you renamed this dir" even
473
455
        # when there are files inside.
474
 
        self.assertEqual("=== renamed directory 'dir' => 'newdir'\n", diff)
 
456
        self.assertEqual(d, "=== renamed directory 'dir' => 'newdir'\n")
475
457
 
476
458
    def test_renamed_file(self):
477
459
        """Test when a file is only renamed."""
481
463
        tree.commit('one', rev_id='rev-1')
482
464
 
483
465
        tree.rename_one('file', 'newname')
484
 
        diff = self.get_diff(tree.basis_tree(), tree)
485
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
 
466
        d = self.get_diff(tree.basis_tree(), tree)
 
467
        self.assertContainsRe(d, "=== renamed file 'file' => 'newname'\n")
486
468
        # We shouldn't have a --- or +++ line, because there is no content
487
469
        # change
488
 
        self.assertNotContainsRe(diff, '---')
 
470
        self.assertNotContainsRe(d, '---')
489
471
 
490
472
    def test_renamed_and_modified_file(self):
491
473
        """Test when a file is only renamed."""
496
478
 
497
479
        tree.rename_one('file', 'newname')
498
480
        self.build_tree_contents([('tree/newname', 'new contents\n')])
499
 
        diff = self.get_diff(tree.basis_tree(), tree)
500
 
        self.assertContainsRe(diff, "=== renamed file 'file' => 'newname'\n")
501
 
        self.assertContainsRe(diff, '--- old/file\t')
502
 
        self.assertContainsRe(diff, '\\+\\+\\+ new/newname\t')
503
 
        self.assertContainsRe(diff, '-contents\n'
504
 
                                    '\\+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')
505
487
 
506
488
 
507
489
    def test_internal_diff_exec_property(self):
526
508
        tree.rename_one('c', 'new-c')
527
509
        tree.rename_one('d', 'new-d')
528
510
 
529
 
        diff = self.get_diff(tree.basis_tree(), tree)
 
511
        d = self.get_diff(tree.basis_tree(), tree)
530
512
 
531
 
        self.assertContainsRe(diff, r"file 'a'.*\(properties changed:.*\+x to -x.*\)")
532
 
        self.assertContainsRe(diff, r"file 'b'.*\(properties changed:.*-x to \+x.*\)")
533
 
        self.assertContainsRe(diff, r"file 'c'.*\(properties changed:.*\+x to -x.*\)")
534
 
        self.assertContainsRe(diff, r"file 'd'.*\(properties changed:.*-x to \+x.*\)")
535
 
        self.assertNotContainsRe(diff, r"file 'e'")
536
 
        self.assertNotContainsRe(diff, r"file 'f'")
 
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'")
537
523
 
538
524
 
539
525
    def test_binary_unicode_filenames(self):
555
541
        tree.add([alpha], ['file-id'])
556
542
        tree.add([omega], ['file-id-2'])
557
543
        diff_content = StringIO()
558
 
        show_diff_trees(tree.basis_tree(), tree, diff_content)
559
 
        diff = diff_content.getvalue()
560
 
        self.assertContainsRe(diff, r"=== added file '%s'" % alpha_utf8)
561
 
        self.assertContainsRe(
562
 
            diff, "Binary files a/%s.*and b/%s.* differ\n" % (alpha_utf8, alpha_utf8))
563
 
        self.assertContainsRe(diff, r"=== added file '%s'" % omega_utf8)
564
 
        self.assertContainsRe(diff, r"--- a/%s" % (omega_utf8,))
565
 
        self.assertContainsRe(diff, r"\+\+\+ b/%s" % (omega_utf8,))
 
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,))
566
552
 
567
553
    def test_unicode_filename(self):
568
554
        """Test when the filename are unicode."""
587
573
        tree.add(['add_'+alpha], ['file-id'])
588
574
        self.build_tree_contents([('tree/mod_'+alpha, 'contents_mod\n')])
589
575
 
590
 
        diff = self.get_diff(tree.basis_tree(), tree)
591
 
        self.assertContainsRe(diff,
 
576
        d = self.get_diff(tree.basis_tree(), tree)
 
577
        self.assertContainsRe(d,
592
578
                "=== renamed file 'ren_%s' => 'ren_%s'\n"%(autf8, outf8))
593
 
        self.assertContainsRe(diff, "=== added file 'add_%s'"%autf8)
594
 
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
595
 
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
596
 
 
597
 
 
598
 
class DiffWasIs(DiffPath):
 
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):
599
585
 
600
586
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
601
587
        self.to_file.write('was: ')
605
591
        pass
606
592
 
607
593
 
608
 
class TestDiffTree(TestCaseWithTransport):
 
594
class TestDiffTree(tests.TestCaseWithTransport):
609
595
 
610
596
    def setUp(self):
611
 
        TestCaseWithTransport.setUp(self)
 
597
        super(TestDiffTree, self).setUp()
612
598
        self.old_tree = self.make_branch_and_tree('old-tree')
613
599
        self.old_tree.lock_write()
614
600
        self.addCleanup(self.old_tree.unlock)
615
601
        self.new_tree = self.make_branch_and_tree('new-tree')
616
602
        self.new_tree.lock_write()
617
603
        self.addCleanup(self.new_tree.unlock)
618
 
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
604
        self.differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
619
605
 
620
606
    def test_diff_text(self):
621
607
        self.build_tree_contents([('old-tree/olddir/',),
626
612
                                  ('new-tree/newdir/newfile', 'new\n')])
627
613
        self.new_tree.add('newdir')
628
614
        self.new_tree.add('newdir/newfile', 'file-id')
629
 
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
 
615
        differ = diff.DiffText(self.old_tree, self.new_tree, StringIO())
630
616
        differ.diff_text('file-id', None, 'old label', 'new label')
631
617
        self.assertEqual(
632
618
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
661
647
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
662
648
 
663
649
    def test_diff_symlink(self):
664
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
650
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
665
651
        differ.diff_symlink('old target', None)
666
652
        self.assertEqual("=== target was 'old target'\n",
667
653
                         differ.to_file.getvalue())
668
654
 
669
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
655
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
670
656
        differ.diff_symlink(None, 'new target')
671
657
        self.assertEqual("=== target is 'new target'\n",
672
658
                         differ.to_file.getvalue())
673
659
 
674
 
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
660
        differ = diff.DiffSymlink(self.old_tree, self.new_tree, StringIO())
675
661
        differ.diff_symlink('old target', 'new target')
676
662
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
677
663
                         differ.to_file.getvalue())
727
713
 
728
714
    def test_register_diff(self):
729
715
        self.create_old_new()
730
 
        old_diff_factories = DiffTree.diff_factories
731
 
        DiffTree.diff_factories=old_diff_factories[:]
732
 
        DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
 
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)
733
719
        try:
734
 
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
720
            differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO())
735
721
        finally:
736
 
            DiffTree.diff_factories = old_diff_factories
 
722
            diff.DiffTree.diff_factories = old_diff_factories
737
723
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
738
724
        self.assertNotContainsRe(
739
725
            differ.to_file.getvalue(),
744
730
 
745
731
    def test_extra_factories(self):
746
732
        self.create_old_new()
747
 
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
748
 
                            extra_factories=[DiffWasIs.from_diff_tree])
 
733
        differ = diff.DiffTree(self.old_tree, self.new_tree, StringIO(),
 
734
                               extra_factories=[DiffWasIs.from_diff_tree])
749
735
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
750
736
        self.assertNotContainsRe(
751
737
            differ.to_file.getvalue(),
764
750
            '.*a-file(.|\n)*b-file')
765
751
 
766
752
 
767
 
class TestPatienceDiffLib(TestCase):
 
753
class TestPatienceDiffLib(tests.TestCase):
768
754
 
769
755
    def setUp(self):
770
756
        super(TestPatienceDiffLib, self).setUp()
771
 
        self._unique_lcs = bzrlib._patiencediff_py.unique_lcs_py
772
 
        self._recurse_matches = bzrlib._patiencediff_py.recurse_matches_py
 
757
        self._unique_lcs = _patiencediff_py.unique_lcs_py
 
758
        self._recurse_matches = _patiencediff_py.recurse_matches_py
773
759
        self._PatienceSequenceMatcher = \
774
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
760
            _patiencediff_py.PatienceSequenceMatcher_py
775
761
 
776
762
    def test_diff_unicode_string(self):
777
763
        a = ''.join([unichr(i) for i in range(4000, 4500, 3)])
1084
1070
                 'how are you today?\n']
1085
1071
        txt_b = ['hello there\n',
1086
1072
                 'how are you today?\n']
1087
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1073
        unified_diff = patiencediff.unified_diff
1088
1074
        psm = self._PatienceSequenceMatcher
1089
1075
        self.assertEquals(['--- \n',
1090
1076
                           '+++ \n',
1138
1124
                 'how are you today?\n']
1139
1125
        txt_b = ['hello there\n',
1140
1126
                 'how are you today?\n']
1141
 
        unified_diff = bzrlib.patiencediff.unified_diff
 
1127
        unified_diff = patiencediff.unified_diff
1142
1128
        psm = self._PatienceSequenceMatcher
1143
1129
        self.assertEquals(['--- a\t2008-08-08\n',
1144
1130
                           '+++ b\t2008-09-09\n',
1156
1142
 
1157
1143
class TestPatienceDiffLib_c(TestPatienceDiffLib):
1158
1144
 
1159
 
    _test_needs_features = [CompiledPatienceDiffFeature]
 
1145
    _test_needs_features = [compiled_patiencediff_feature]
1160
1146
 
1161
1147
    def setUp(self):
1162
1148
        super(TestPatienceDiffLib_c, self).setUp()
1163
 
        import bzrlib._patiencediff_c
1164
 
        self._unique_lcs = bzrlib._patiencediff_c.unique_lcs_c
1165
 
        self._recurse_matches = bzrlib._patiencediff_c.recurse_matches_c
 
1149
        from bzrlib import _patiencediff_c
 
1150
        self._unique_lcs = _patiencediff_c.unique_lcs_c
 
1151
        self._recurse_matches = _patiencediff_c.recurse_matches_c
1166
1152
        self._PatienceSequenceMatcher = \
1167
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
 
1153
            _patiencediff_c.PatienceSequenceMatcher_c
1168
1154
 
1169
1155
    def test_unhashable(self):
1170
1156
        """We should get a proper exception here."""
1180
1166
                                         None, ['valid'], ['valid', []])
1181
1167
 
1182
1168
 
1183
 
class TestPatienceDiffLibFiles(TestCaseInTempDir):
 
1169
class TestPatienceDiffLibFiles(tests.TestCaseInTempDir):
1184
1170
 
1185
1171
    def setUp(self):
1186
1172
        super(TestPatienceDiffLibFiles, self).setUp()
1187
1173
        self._PatienceSequenceMatcher = \
1188
 
            bzrlib._patiencediff_py.PatienceSequenceMatcher_py
 
1174
            _patiencediff_py.PatienceSequenceMatcher_py
1189
1175
 
1190
1176
    def test_patience_unified_diff_files(self):
1191
1177
        txt_a = ['hello there\n',
1196
1182
        open('a1', 'wb').writelines(txt_a)
1197
1183
        open('b1', 'wb').writelines(txt_b)
1198
1184
 
1199
 
        unified_diff_files = bzrlib.patiencediff.unified_diff_files
 
1185
        unified_diff_files = patiencediff.unified_diff_files
1200
1186
        psm = self._PatienceSequenceMatcher
1201
1187
        self.assertEquals(['--- a1\n',
1202
1188
                           '+++ b1\n',
1252
1238
 
1253
1239
class TestPatienceDiffLibFiles_c(TestPatienceDiffLibFiles):
1254
1240
 
1255
 
    _test_needs_features = [CompiledPatienceDiffFeature]
 
1241
    _test_needs_features = [compiled_patiencediff_feature]
1256
1242
 
1257
1243
    def setUp(self):
1258
1244
        super(TestPatienceDiffLibFiles_c, self).setUp()
1259
 
        import bzrlib._patiencediff_c
 
1245
        from bzrlib import _patiencediff_c
1260
1246
        self._PatienceSequenceMatcher = \
1261
 
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
1262
 
 
1263
 
 
1264
 
class TestUsingCompiledIfAvailable(TestCase):
 
1247
            _patiencediff_c.PatienceSequenceMatcher_c
 
1248
 
 
1249
 
 
1250
class TestUsingCompiledIfAvailable(tests.TestCase):
1265
1251
 
1266
1252
    def test_PatienceSequenceMatcher(self):
1267
 
        if CompiledPatienceDiffFeature.available():
 
1253
        if compiled_patiencediff_feature.available():
1268
1254
            from bzrlib._patiencediff_c import PatienceSequenceMatcher_c
1269
1255
            self.assertIs(PatienceSequenceMatcher_c,
1270
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1256
                          patiencediff.PatienceSequenceMatcher)
1271
1257
        else:
1272
1258
            from bzrlib._patiencediff_py import PatienceSequenceMatcher_py
1273
1259
            self.assertIs(PatienceSequenceMatcher_py,
1274
 
                          bzrlib.patiencediff.PatienceSequenceMatcher)
 
1260
                          patiencediff.PatienceSequenceMatcher)
1275
1261
 
1276
1262
    def test_unique_lcs(self):
1277
 
        if CompiledPatienceDiffFeature.available():
 
1263
        if compiled_patiencediff_feature.available():
1278
1264
            from bzrlib._patiencediff_c import unique_lcs_c
1279
1265
            self.assertIs(unique_lcs_c,
1280
 
                          bzrlib.patiencediff.unique_lcs)
 
1266
                          patiencediff.unique_lcs)
1281
1267
        else:
1282
1268
            from bzrlib._patiencediff_py import unique_lcs_py
1283
1269
            self.assertIs(unique_lcs_py,
1284
 
                          bzrlib.patiencediff.unique_lcs)
 
1270
                          patiencediff.unique_lcs)
1285
1271
 
1286
1272
    def test_recurse_matches(self):
1287
 
        if CompiledPatienceDiffFeature.available():
 
1273
        if compiled_patiencediff_feature.available():
1288
1274
            from bzrlib._patiencediff_c import recurse_matches_c
1289
1275
            self.assertIs(recurse_matches_c,
1290
 
                          bzrlib.patiencediff.recurse_matches)
 
1276
                          patiencediff.recurse_matches)
1291
1277
        else:
1292
1278
            from bzrlib._patiencediff_py import recurse_matches_py
1293
1279
            self.assertIs(recurse_matches_py,
1294
 
                          bzrlib.patiencediff.recurse_matches)
1295
 
 
1296
 
 
1297
 
class TestDiffFromTool(TestCaseWithTransport):
 
1280
                          patiencediff.recurse_matches)
 
1281
 
 
1282
 
 
1283
class TestDiffFromTool(tests.TestCaseWithTransport):
1298
1284
 
1299
1285
    def test_from_string(self):
1300
 
        diff_obj = DiffFromTool.from_string('diff', None, None, None)
 
1286
        diff_obj = diff.DiffFromTool.from_string('diff', None, None, None)
1301
1287
        self.addCleanup(diff_obj.finish)
1302
1288
        self.assertEqual(['diff', '@old_path', '@new_path'],
1303
1289
            diff_obj.command_template)
1304
1290
 
1305
1291
    def test_from_string_u5(self):
1306
 
        diff_obj = DiffFromTool.from_string('diff -u\\ 5', None, None, None)
 
1292
        diff_obj = diff.DiffFromTool.from_string('diff "-u 5"',
 
1293
                                                 None, None, None)
1307
1294
        self.addCleanup(diff_obj.finish)
1308
1295
        self.assertEqual(['diff', '-u 5', '@old_path', '@new_path'],
1309
1296
                         diff_obj.command_template)
1310
1297
        self.assertEqual(['diff', '-u 5', 'old-path', 'new-path'],
1311
1298
                         diff_obj._get_command('old-path', 'new-path'))
1312
1299
 
 
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
 
1313
1310
    def test_execute(self):
1314
1311
        output = StringIO()
1315
 
        diff_obj = DiffFromTool(['python', '-c',
1316
 
                                 'print "@old_path @new_path"'],
1317
 
                                None, None, output)
 
1312
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1313
                                      'print "@old_path @new_path"'],
 
1314
                                     None, None, output)
1318
1315
        self.addCleanup(diff_obj.finish)
1319
1316
        diff_obj._execute('old', 'new')
1320
1317
        self.assertEqual(output.getvalue().rstrip(), 'old new')
1321
1318
 
1322
1319
    def test_excute_missing(self):
1323
 
        diff_obj = DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
1324
 
                                None, None, None)
 
1320
        diff_obj = diff.DiffFromTool(['a-tool-which-is-unlikely-to-exist'],
 
1321
                                     None, None, None)
1325
1322
        self.addCleanup(diff_obj.finish)
1326
 
        e = self.assertRaises(ExecutableMissing, diff_obj._execute, 'old',
1327
 
                              'new')
 
1323
        e = self.assertRaises(errors.ExecutableMissing, diff_obj._execute,
 
1324
                              'old', 'new')
1328
1325
        self.assertEqual('a-tool-which-is-unlikely-to-exist could not be found'
1329
1326
                         ' on this machine', str(e))
1330
1327
 
1337
1334
        tree.commit('old tree')
1338
1335
        tree.lock_read()
1339
1336
        self.addCleanup(tree.unlock)
1340
 
        diff_obj = DiffFromTool(['python', '-c',
1341
 
                                 'print "@old_path @new_path"'],
1342
 
                                tree, tree, output)
 
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
1343
        diff_obj._prepare_files('file-id', 'file', 'file')
1344
 
        self.assertReadableByAttrib(diff_obj._root, 'old\\file', r'old\\file')
1345
 
        self.assertReadableByAttrib(diff_obj._root, 'new\\file', r'new\\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$')
1346
1350
 
1347
1351
    def assertReadableByAttrib(self, cwd, relpath, regex):
1348
1352
        proc = subprocess.Popen(['attrib', relpath],
1349
1353
                                stdout=subprocess.PIPE,
1350
1354
                                cwd=cwd)
1351
 
        proc.wait()
1352
 
        result = proc.stdout.read()
1353
 
        self.assertContainsRe(result, regex)
 
1355
        (result, err) = proc.communicate()
 
1356
        self.assertContainsRe(result.replace('\r\n', '\n'), regex)
1354
1357
 
1355
1358
    def test_prepare_files(self):
1356
1359
        output = StringIO()
1359
1362
        self.build_tree_contents([('tree/oldname2', 'oldcontent2')])
1360
1363
        tree.add('oldname', 'file-id')
1361
1364
        tree.add('oldname2', 'file2-id')
1362
 
        tree.commit('old tree', timestamp=0)
 
1365
        # Earliest allowable date on FAT32 filesystems is 1980-01-01
 
1366
        tree.commit('old tree', timestamp=315532800)
1363
1367
        tree.rename_one('oldname', 'newname')
1364
1368
        tree.rename_one('oldname2', 'newname2')
1365
1369
        self.build_tree_contents([('tree/newname', 'newcontent')])
1369
1373
        self.addCleanup(old_tree.unlock)
1370
1374
        tree.lock_read()
1371
1375
        self.addCleanup(tree.unlock)
1372
 
        diff_obj = DiffFromTool(['python', '-c',
1373
 
                                 'print "@old_path @new_path"'],
1374
 
                                old_tree, tree, output)
 
1376
        diff_obj = diff.DiffFromTool(['python', '-c',
 
1377
                                      'print "@old_path @new_path"'],
 
1378
                                     old_tree, tree, output)
1375
1379
        self.addCleanup(diff_obj.finish)
1376
1380
        self.assertContainsRe(diff_obj._root, 'bzr-diff-[^/]*')
1377
1381
        old_path, new_path = diff_obj._prepare_files('file-id', 'oldname',
1378
1382
                                                     'newname')
1379
1383
        self.assertContainsRe(old_path, 'old/oldname$')
1380
 
        self.assertEqual(0, os.stat(old_path).st_mtime)
 
1384
        self.assertEqual(315532800, os.stat(old_path).st_mtime)
1381
1385
        self.assertContainsRe(new_path, 'tree/newname$')
1382
1386
        self.assertFileEqual('oldcontent', old_path)
1383
1387
        self.assertFileEqual('newcontent', new_path)
1387
1391
        diff_obj._prepare_files('file2-id', 'oldname2', 'newname2')
1388
1392
 
1389
1393
 
1390
 
class TestGetTreesAndBranchesToDiff(TestCaseWithTransport):
 
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)
1391
1402
 
1392
1403
    def test_basic(self):
1393
1404
        tree = self.make_branch_and_tree('tree')
1394
1405
        (old_tree, new_tree,
1395
1406
         old_branch, new_branch,
1396
 
         specific_files, extra_trees) = \
1397
 
            get_trees_and_branches_to_diff(['tree'], None, None, None)
 
1407
         specific_files, extra_trees) = self.call_gtabtd(
 
1408
             ['tree'], None, None, None)
1398
1409
 
1399
 
        self.assertIsInstance(old_tree, RevisionTree)
1400
 
        #print dir (old_tree)
1401
 
        self.assertEqual(_mod_revision.NULL_REVISION, old_tree.get_revision_id())
 
1410
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
 
1411
        self.assertEqual(_mod_revision.NULL_REVISION,
 
1412
                         old_tree.get_revision_id())
1402
1413
        self.assertEqual(tree.basedir, new_tree.basedir)
1403
1414
        self.assertEqual(tree.branch.base, old_branch.base)
1404
1415
        self.assertEqual(tree.branch.base, new_branch.base)
1413
1424
        self.build_tree_contents([('tree/file', 'newcontent')])
1414
1425
        tree.commit('new tree', timestamp=0, rev_id="new-id")
1415
1426
 
1416
 
        revisions = [RevisionSpec.from_string('1'),
1417
 
                     RevisionSpec.from_string('2')]
 
1427
        revisions = [revisionspec.RevisionSpec.from_string('1'),
 
1428
                     revisionspec.RevisionSpec.from_string('2')]
1418
1429
        (old_tree, new_tree,
1419
1430
         old_branch, new_branch,
1420
 
         specific_files, extra_trees) = \
1421
 
            get_trees_and_branches_to_diff(['tree'], revisions, None, None)
 
1431
         specific_files, extra_trees) = self.call_gtabtd(
 
1432
            ['tree'], revisions, None, None)
1422
1433
 
1423
 
        self.assertIsInstance(old_tree, RevisionTree)
 
1434
        self.assertIsInstance(old_tree, revisiontree.RevisionTree)
1424
1435
        self.assertEqual("old-id", old_tree.get_revision_id())
1425
 
        self.assertIsInstance(new_tree, RevisionTree)
 
1436
        self.assertIsInstance(new_tree, revisiontree.RevisionTree)
1426
1437
        self.assertEqual("new-id", new_tree.get_revision_id())
1427
1438
        self.assertEqual(tree.branch.base, old_branch.base)
1428
1439
        self.assertEqual(tree.branch.base, new_branch.base)
1429
1440
        self.assertIs(None, specific_files)
1430
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