544
564
self.assertContainsRe(diff, "=== modified file 'mod_%s'"%autf8)
545
565
self.assertContainsRe(diff, "=== removed file 'del_%s'"%autf8)
568
class DiffWasIs(DiffPath):
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())
578
class TestDiffTree(TestCaseWithTransport):
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())
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')
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')
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')
612
'--- old label\n+++ new label\n@@ -1,1 +1,1 @@\n-old\n+new\n\n',
613
differ.to_file.getvalue())
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')
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')
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())
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())
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())
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')
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'
678
self.assertContainsRe(self.differ.to_file.getvalue(),
679
"=== target is 'new'\n")
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(), '')
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')
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)
703
differ = DiffTree(self.old_tree, self.new_tree, StringIO())
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')
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')
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')
547
736
class TestPatienceDiffLib(TestCase):
594
783
# This is what it currently gives:
595
784
test_one('aBccDe', 'abccde', [(0,0), (5,5)])
786
def assertDiffBlocks(self, a, b, expected_blocks):
787
"""Check that the sequence matcher returns the correct blocks.
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)
794
matcher = self._PatienceSequenceMatcher(None, a, b)
795
blocks = matcher.get_matching_blocks()
797
self.assertEqual((len(a), len(b), 0), last)
798
self.assertEqual(expected_blocks, blocks)
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])
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)])
626
821
# make sure it supports passing in lists
822
self.assertDiffBlocks(
628
823
['hello there\n',
630
825
'how are you today?\n'],
635
830
# non unique lines surrounded by non-matching lines
637
chk_blocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
832
self.assertDiffBlocks('aBccDe', 'abccde', [(0,0,1), (5,5,1)])
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)])
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)])
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)])
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', [])
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,')],
856
self.assertDiffBlocks([('a',), ('b',), ('c,')],
857
[('a',), ('b',), ('d,')],
859
self.assertDiffBlocks([('d',), ('b',), ('c,')],
860
[('a',), ('b',), ('c,')],
862
self.assertDiffBlocks([('d',), ('a',), ('b',), ('c,')],
863
[('a',), ('b',), ('c,')],
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)])
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()
775
self.assertEquals(x, (len(a), len(b), 0))
776
self.assertEquals(expected_blocks, blocks)
778
chk_blocks('abcdefghijklmnop'
779
, 'abcXghiYZQRSTUVWXYZijklmnop'
780
, [(0, 0, 3), (6, 4, 3), (9, 20, 7)])
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)])
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)])
786
996
# These are rot13 code snippets.
997
self.assertDiffBlocks('''\
788
998
trg nqqrq jura lbh nqq n svyr va gur qverpgbel.
790
1000
gnxrf_netf = ['svyr*']