/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: John Arbash Meinel
  • Date: 2007-12-20 12:34:06 UTC
  • mfrom: (3133 +trunk)
  • mto: This revision was merged to the branch mainline in revision 3134.
  • Revision ID: john@arbash-meinel.com-20071220123406-4ijq232s46ecsutz
[merge] bzr.dev 3133

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
import subprocess
21
21
from tempfile import TemporaryFile
22
22
 
23
 
from bzrlib.diff import internal_diff, external_diff, show_diff_trees
 
23
from bzrlib.diff import (
 
24
    internal_diff,
 
25
    external_diff,
 
26
    DiffPath,
 
27
    show_diff_trees,
 
28
    DiffSymlink,
 
29
    DiffTree,
 
30
    DiffText,
 
31
    )
24
32
from bzrlib.errors import BinaryFile, NoDiff
25
33
import bzrlib.osutils as osutils
26
34
import bzrlib.patiencediff
231
239
                          ]
232
240
                          , lines)
233
241
 
 
242
    def test_internal_diff_no_content(self):
 
243
        output = StringIO()
 
244
        internal_diff(u'old', [], u'new', [], output)
 
245
        self.assertEqual('', output.getvalue())
 
246
 
 
247
    def test_internal_diff_no_changes(self):
 
248
        output = StringIO()
 
249
        internal_diff(u'old', ['text\n', 'contents\n'],
 
250
                      u'new', ['text\n', 'contents\n'],
 
251
                      output)
 
252
        self.assertEqual('', output.getvalue())
 
253
 
234
254
    def test_internal_diff_returns_bytes(self):
235
255
        import StringIO
236
256
        output = StringIO.StringIO()
544
564
        self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
545
565
        self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
546
566
 
 
567
 
 
568
class DiffWasIs(DiffPath):
 
569
 
 
570
    def diff(self, file_id, old_path, new_path, old_kind, new_kind):
 
571
        self.to_file.write('was: ')
 
572
        self.to_file.write(self.old_tree.get_file(file_id).read())
 
573
        self.to_file.write('is: ')
 
574
        self.to_file.write(self.new_tree.get_file(file_id).read())
 
575
        pass
 
576
 
 
577
 
 
578
class TestDiffTree(TestCaseWithTransport):
 
579
 
 
580
    def setUp(self):
 
581
        TestCaseWithTransport.setUp(self)
 
582
        self.old_tree = self.make_branch_and_tree('old-tree')
 
583
        self.old_tree.lock_write()
 
584
        self.addCleanup(self.old_tree.unlock)
 
585
        self.new_tree = self.make_branch_and_tree('new-tree')
 
586
        self.new_tree.lock_write()
 
587
        self.addCleanup(self.new_tree.unlock)
 
588
        self.differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
589
 
 
590
    def test_diff_text(self):
 
591
        self.build_tree_contents([('old-tree/olddir/',),
 
592
                                  ('old-tree/olddir/oldfile', 'old\n')])
 
593
        self.old_tree.add('olddir')
 
594
        self.old_tree.add('olddir/oldfile', 'file-id')
 
595
        self.build_tree_contents([('new-tree/newdir/',),
 
596
                                  ('new-tree/newdir/newfile', 'new\n')])
 
597
        self.new_tree.add('newdir')
 
598
        self.new_tree.add('newdir/newfile', 'file-id')
 
599
        differ = DiffText(self.old_tree, self.new_tree, StringIO())
 
600
        differ.diff_text('file-id', None, 'old label', 'new label')
 
601
        self.assertEqual(
 
602
            '--- old label\n+++ new label\n@@ -1,1 +0,0 @@\n-old\n\n',
 
603
            differ.to_file.getvalue())
 
604
        differ.to_file.seek(0)
 
605
        differ.diff_text(None, 'file-id', 'old label', 'new label')
 
606
        self.assertEqual(
 
607
            '--- old label\n+++ new label\n@@ -0,0 +1,1 @@\n+new\n\n',
 
608
            differ.to_file.getvalue())
 
609
        differ.to_file.seek(0)
 
610
        differ.diff_text('file-id', 'file-id', 'old label', 'new label')
 
611
        self.assertEqual(
 
612
            '--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
 
613
            differ.to_file.getvalue())
 
614
 
 
615
    def test_diff_deletion(self):
 
616
        self.build_tree_contents([('old-tree/file', 'contents'),
 
617
                                  ('new-tree/file', 'contents')])
 
618
        self.old_tree.add('file', 'file-id')
 
619
        self.new_tree.add('file', 'file-id')
 
620
        os.unlink('new-tree/file')
 
621
        self.differ.show_diff(None)
 
622
        self.assertContainsRe(self.differ.to_file.getvalue(), '-contents')
 
623
 
 
624
    def test_diff_creation(self):
 
625
        self.build_tree_contents([('old-tree/file', 'contents'),
 
626
                                  ('new-tree/file', 'contents')])
 
627
        self.old_tree.add('file', 'file-id')
 
628
        self.new_tree.add('file', 'file-id')
 
629
        os.unlink('old-tree/file')
 
630
        self.differ.show_diff(None)
 
631
        self.assertContainsRe(self.differ.to_file.getvalue(), '\+contents')
 
632
 
 
633
    def test_diff_symlink(self):
 
634
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
635
        differ.diff_symlink('old target', None)
 
636
        self.assertEqual("=== target was 'old target'\n",
 
637
                         differ.to_file.getvalue())
 
638
 
 
639
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
640
        differ.diff_symlink(None, 'new target')
 
641
        self.assertEqual("=== target is 'new target'\n",
 
642
                         differ.to_file.getvalue())
 
643
 
 
644
        differ = DiffSymlink(self.old_tree, self.new_tree, StringIO())
 
645
        differ.diff_symlink('old target', 'new target')
 
646
        self.assertEqual("=== target changed 'old target' => 'new target'\n",
 
647
                         differ.to_file.getvalue())
 
648
 
 
649
    def test_diff(self):
 
650
        self.build_tree_contents([('old-tree/olddir/',),
 
651
                                  ('old-tree/olddir/oldfile', 'old\n')])
 
652
        self.old_tree.add('olddir')
 
653
        self.old_tree.add('olddir/oldfile', 'file-id')
 
654
        self.build_tree_contents([('new-tree/newdir/',),
 
655
                                  ('new-tree/newdir/newfile', 'new\n')])
 
656
        self.new_tree.add('newdir')
 
657
        self.new_tree.add('newdir/newfile', 'file-id')
 
658
        self.differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
 
659
        self.assertContainsRe(
 
660
            self.differ.to_file.getvalue(),
 
661
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
 
662
             ' \@\@\n-old\n\+new\n\n')
 
663
 
 
664
    def test_diff_kind_change(self):
 
665
        self.build_tree_contents([('old-tree/olddir/',),
 
666
                                  ('old-tree/olddir/oldfile', 'old\n')])
 
667
        self.old_tree.add('olddir')
 
668
        self.old_tree.add('olddir/oldfile', 'file-id')
 
669
        self.build_tree(['new-tree/newdir/'])
 
670
        os.symlink('new', 'new-tree/newdir/newfile')
 
671
        self.new_tree.add('newdir')
 
672
        self.new_tree.add('newdir/newfile', 'file-id')
 
673
        self.differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
 
674
        self.assertContainsRe(
 
675
            self.differ.to_file.getvalue(),
 
676
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+0,0'
 
677
             ' \@\@\n-old\n\n')
 
678
        self.assertContainsRe(self.differ.to_file.getvalue(),
 
679
                              "=== target is 'new'\n")
 
680
 
 
681
    def test_diff_directory(self):
 
682
        self.build_tree(['new-tree/new-dir/'])
 
683
        self.new_tree.add('new-dir', 'new-dir-id')
 
684
        self.differ.diff('new-dir-id', None, 'new-dir')
 
685
        self.assertEqual(self.differ.to_file.getvalue(), '')
 
686
 
 
687
    def create_old_new(self):
 
688
        self.build_tree_contents([('old-tree/olddir/',),
 
689
                                  ('old-tree/olddir/oldfile', 'old\n')])
 
690
        self.old_tree.add('olddir')
 
691
        self.old_tree.add('olddir/oldfile', 'file-id')
 
692
        self.build_tree_contents([('new-tree/newdir/',),
 
693
                                  ('new-tree/newdir/newfile', 'new\n')])
 
694
        self.new_tree.add('newdir')
 
695
        self.new_tree.add('newdir/newfile', 'file-id')
 
696
 
 
697
    def test_register_diff(self):
 
698
        self.create_old_new()
 
699
        old_diff_factories = DiffTree.diff_factories
 
700
        DiffTree.diff_factories=old_diff_factories[:]
 
701
        DiffTree.diff_factories.insert(0, DiffWasIs.from_diff_tree)
 
702
        try:
 
703
            differ = DiffTree(self.old_tree, self.new_tree, StringIO())
 
704
        finally:
 
705
            DiffTree.diff_factories = old_diff_factories
 
706
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
 
707
        self.assertNotContainsRe(
 
708
            differ.to_file.getvalue(),
 
709
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
 
710
             ' \@\@\n-old\n\+new\n\n')
 
711
        self.assertContainsRe(differ.to_file.getvalue(),
 
712
                              'was: old\nis: new\n')
 
713
 
 
714
    def test_extra_factories(self):
 
715
        self.create_old_new()
 
716
        differ = DiffTree(self.old_tree, self.new_tree, StringIO(),
 
717
                            extra_factories=[DiffWasIs.from_diff_tree])
 
718
        differ.diff('file-id', 'olddir/oldfile', 'newdir/newfile')
 
719
        self.assertNotContainsRe(
 
720
            differ.to_file.getvalue(),
 
721
            r'--- olddir/oldfile.*\n\+\+\+ newdir/newfile.*\n\@\@ -1,1 \+1,1'
 
722
             ' \@\@\n-old\n\+new\n\n')
 
723
        self.assertContainsRe(differ.to_file.getvalue(),
 
724
                              'was: old\nis: new\n')
 
725
 
 
726
    def test_alphabetical_order(self):
 
727
        self.build_tree(['new-tree/a-file'])
 
728
        self.new_tree.add('a-file')
 
729
        self.build_tree(['old-tree/b-file'])
 
730
        self.old_tree.add('b-file')
 
731
        self.differ.show_diff(None)
 
732
        self.assertContainsRe(self.differ.to_file.getvalue(),
 
733
            '.*a-file(.|\n)*b-file')
 
734
 
 
735
 
547
736
class TestPatienceDiffLib(TestCase):
548
737
 
549
738
    def setUp(self):
594
783
        # This is what it currently gives:
595
784
        test_one('aBccDe', 'abccde', [(0,0), (5,5)])
596
785
 
 
786
    def assertDiffBlocks(self, a, b, expected_blocks):
 
787
        """Check that the sequence matcher returns the correct blocks.
 
788
 
 
789
        :param a: A sequence to match
 
790
        :param b: Another sequence to match
 
791
        :param expected_blocks: The expected output, not including the final
 
792
            matching block (len(a), len(b), 0)
 
793
        """
 
794
        matcher = self._PatienceSequenceMatcher(None, a, b)
 
795
        blocks = matcher.get_matching_blocks()
 
796
        last = blocks.pop()
 
797
        self.assertEqual((len(a), len(b), 0), last)
 
798
        self.assertEqual(expected_blocks, blocks)
 
799
 
597
800
    def test_matching_blocks(self):
598
 
        def chk_blocks(a, b, expected_blocks):
599
 
            # difflib always adds a signature of the total
600
 
            # length, with no matching entries at the end
601
 
            s = self._PatienceSequenceMatcher(None, a, b)
602
 
            blocks = s.get_matching_blocks()
603
 
            self.assertEquals((len(a), len(b), 0), blocks[-1])
604
 
            self.assertEquals(expected_blocks, blocks[:-1])
605
 
 
606
801
        # Some basic matching tests
607
 
        chk_blocks('', '', [])
608
 
        chk_blocks([], [], [])
609
 
        chk_blocks('abc', '', [])
610
 
        chk_blocks('', 'abc', [])
611
 
        chk_blocks('abcd', 'abcd', [(0, 0, 4)])
612
 
        chk_blocks('abcd', 'abce', [(0, 0, 3)])
613
 
        chk_blocks('eabc', 'abce', [(1, 0, 3)])
614
 
        chk_blocks('eabce', 'abce', [(1, 0, 4)])
615
 
        chk_blocks('abcde', 'abXde', [(0, 0, 2), (3, 3, 2)])
616
 
        chk_blocks('abcde', 'abXYZde', [(0, 0, 2), (3, 5, 2)])
617
 
        chk_blocks('abde', 'abXYZde', [(0, 0, 2), (2, 5, 2)])
618
 
        # This may check too much, but it checks to see that 
 
802
        self.assertDiffBlocks('', '', [])
 
803
        self.assertDiffBlocks([], [], [])
 
804
        self.assertDiffBlocks('abc', '', [])
 
805
        self.assertDiffBlocks('', 'abc', [])
 
806
        self.assertDiffBlocks('abcd', 'abcd', [(0, 0, 4)])
 
807
        self.assertDiffBlocks('abcd', 'abce', [(0, 0, 3)])
 
808
        self.assertDiffBlocks('eabc', 'abce', [(1, 0, 3)])
 
809
        self.assertDiffBlocks('eabce', 'abce', [(1, 0, 4)])
 
810
        self.assertDiffBlocks('abcde', 'abXde', [(0, 0, 2), (3, 3, 2)])
 
811
        self.assertDiffBlocks('abcde', 'abXYZde', [(0, 0, 2), (3, 5, 2)])
 
812
        self.assertDiffBlocks('abde', 'abXYZde', [(0, 0, 2), (2, 5, 2)])
 
813
        # This may check too much, but it checks to see that
619
814
        # a copied block stays attached to the previous section,
620
815
        # not the later one.
621
816
        # difflib would tend to grab the trailing longest match
622
817
        # which would make the diff not look right
623
 
        chk_blocks('abcdefghijklmnop', 'abcdefxydefghijklmnop',
624
 
                   [(0, 0, 6), (6, 11, 10)])
 
818
        self.assertDiffBlocks('abcdefghijklmnop', 'abcdefxydefghijklmnop',
 
819
                              [(0, 0, 6), (6, 11, 10)])
625
820
 
626
821
        # make sure it supports passing in lists
627
 
        chk_blocks(
 
822
        self.assertDiffBlocks(
628
823
                   ['hello there\n',
629
824
                    'world\n',
630
825
                    'how are you today?\n'],
634
829
 
635
830
        # non unique lines surrounded by non-matching lines
636
831
        # won't be found
637
 
        chk_blocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
 
832
        self.assertDiffBlocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
638
833
 
639
834
        # But they only need to be locally unique
640
 
        chk_blocks('aBcDec', 'abcdec', [(0,0,1), (2,2,1), (4,4,2)])
 
835
        self.assertDiffBlocks('aBcDec', 'abcdec', [(0,0,1), (2,2,1), (4,4,2)])
641
836
 
642
837
        # non unique blocks won't be matched
643
 
        chk_blocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (8,8,1)])
 
838
        self.assertDiffBlocks('aBcdEcdFg', 'abcdecdfg', [(0,0,1), (8,8,1)])
644
839
 
645
840
        # but locally unique ones will
646
 
        chk_blocks('aBcdEeXcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
 
841
        self.assertDiffBlocks('aBcdEeXcdFg', 'abcdecdfg', [(0,0,1), (2,2,2),
647
842
                                              (5,4,1), (7,5,2), (10,8,1)])
648
843
 
649
 
        chk_blocks('abbabbXd', 'cabbabxd', [(7,7,1)])
650
 
        chk_blocks('abbabbbb', 'cabbabbc', [])
651
 
        chk_blocks('bbbbbbbb', 'cbbbbbbc', [])
 
844
        self.assertDiffBlocks('abbabbXd', 'cabbabxd', [(7,7,1)])
 
845
        self.assertDiffBlocks('abbabbbb', 'cabbabbc', [])
 
846
        self.assertDiffBlocks('bbbbbbbb', 'cbbbbbbc', [])
 
847
 
 
848
    def test_matching_blocks_tuples(self):
 
849
        # Some basic matching tests
 
850
        self.assertDiffBlocks([], [], [])
 
851
        self.assertDiffBlocks([('a',), ('b',), ('c,')], [], [])
 
852
        self.assertDiffBlocks([], [('a',), ('b',), ('c,')], [])
 
853
        self.assertDiffBlocks([('a',), ('b',), ('c,')],
 
854
                              [('a',), ('b',), ('c,')],
 
855
                              [(0, 0, 3)])
 
856
        self.assertDiffBlocks([('a',), ('b',), ('c,')],
 
857
                              [('a',), ('b',), ('d,')],
 
858
                              [(0, 0, 2)])
 
859
        self.assertDiffBlocks([('d',), ('b',), ('c,')],
 
860
                              [('a',), ('b',), ('c,')],
 
861
                              [(1, 1, 2)])
 
862
        self.assertDiffBlocks([('d',), ('a',), ('b',), ('c,')],
 
863
                              [('a',), ('b',), ('c,')],
 
864
                              [(1, 0, 3)])
 
865
        self.assertDiffBlocks([('a', 'b'), ('c', 'd'), ('e', 'f')],
 
866
                              [('a', 'b'), ('c', 'X'), ('e', 'f')],
 
867
                              [(0, 0, 1), (2, 2, 1)])
 
868
        self.assertDiffBlocks([('a', 'b'), ('c', 'd'), ('e', 'f')],
 
869
                              [('a', 'b'), ('c', 'dX'), ('e', 'f')],
 
870
                              [(0, 0, 1), (2, 2, 1)])
652
871
 
653
872
    def test_opcodes(self):
654
873
        def chk_ops(a, b, expected_codes):
766
985
    def test_multiple_ranges(self):
767
986
        # There was an earlier bug where we used a bad set of ranges,
768
987
        # this triggers that specific bug, to make sure it doesn't regress
769
 
        def chk_blocks(a, b, expected_blocks):
770
 
            # difflib always adds a signature of the total
771
 
            # length, with no matching entries at the end
772
 
            s = self._PatienceSequenceMatcher(None, a, b)
773
 
            blocks = s.get_matching_blocks()
774
 
            x = blocks.pop()
775
 
            self.assertEquals(x, (len(a), len(b), 0))
776
 
            self.assertEquals(expected_blocks, blocks)
777
 
 
778
 
        chk_blocks('abcdefghijklmnop'
779
 
                 , 'abcXghiYZQRSTUVWXYZijklmnop'
780
 
                 , [(0, 0, 3), (6, 4, 3), (9, 20, 7)])
781
 
 
782
 
        chk_blocks('ABCd efghIjk  L'
783
 
                 , 'AxyzBCn mo pqrstuvwI1 2  L'
784
 
                 , [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
 
988
        self.assertDiffBlocks('abcdefghijklmnop',
 
989
                              'abcXghiYZQRSTUVWXYZijklmnop',
 
990
                              [(0, 0, 3), (6, 4, 3), (9, 20, 7)])
 
991
 
 
992
        self.assertDiffBlocks('ABCd efghIjk  L',
 
993
                              'AxyzBCn mo pqrstuvwI1 2  L',
 
994
                              [(0,0,1), (1, 4, 2), (9, 19, 1), (12, 23, 3)])
785
995
 
786
996
        # These are rot13 code snippets.
787
 
        chk_blocks('''\
 
997
        self.assertDiffBlocks('''\
788
998
    trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
789
999
    """
790
1000
    gnxrf_netf = ['svyr*']
897
1107
        self._PatienceSequenceMatcher = \
898
1108
            bzrlib._patiencediff_c.PatienceSequenceMatcher_c
899
1109
 
 
1110
    def test_unhashable(self):
 
1111
        """We should get a proper exception here."""
 
1112
        # We need to be able to hash items in the sequence, lists are
 
1113
        # unhashable, and thus cannot be diffed
 
1114
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
 
1115
                                         None, [[]], [])
 
1116
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
 
1117
                                         None, ['valid', []], [])
 
1118
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
 
1119
                                         None, ['valid'], [[]])
 
1120
        e = self.assertRaises(TypeError, self._PatienceSequenceMatcher,
 
1121
                                         None, ['valid'], ['valid', []])
 
1122
 
900
1123
 
901
1124
class TestPatienceDiffLibFiles(TestCaseInTempDir):
902
1125