453
wt.branch, log.ShortLogFormatter,
454
formatter_kwargs=dict(levels=0))
446
456
def test_short_merge_revs_log_single_merge_revision(self):
447
wt = self.make_branch_and_memory_tree('.')
449
self.addCleanup(wt.unlock)
451
wt.commit('rev-1', rev_id='rev-1',
452
timestamp=1132586655, timezone=36000,
453
committer='Joe Foo <joe@foo.com>')
454
wt.commit('rev-merged', rev_id='rev-2a',
455
timestamp=1132586700, timezone=36000,
456
committer='Joe Foo <joe@foo.com>')
457
wt.set_parent_ids(['rev-1', 'rev-2a'])
458
wt.branch.set_last_revision_info(1, 'rev-1')
459
wt.commit('rev-2', rev_id='rev-2b',
460
timestamp=1132586800, timezone=36000,
461
committer='Joe Foo <joe@foo.com>')
462
logfile = self.make_utf8_encoded_stringio()
463
formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
457
wt = self._prepare_tree_with_merges()
464
458
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
466
rev = revspec.in_history(wtb)
467
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
468
self.assertEqualDiff("""\
459
rev = revspec.in_history(wt.branch)
460
self.assertFormatterResult("""\
469
461
1.1.1 Joe Foo\t2005-11-22
476
class TestLongLogFormatter(TestCaseWithoutPropsHandler):
465
wt.branch, log.ShortLogFormatter,
466
formatter_kwargs=dict(levels=0),
467
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
470
class TestLongLogFormatter(TestCaseForLogFormatter):
478
472
def test_verbose_log(self):
479
473
"""Verbose log includes changed files
483
wt = self.make_branch_and_tree('.')
485
self.build_tree(['a'])
487
# XXX: why does a longer nick show up?
488
b.nick = 'test_verbose_log'
489
wt.commit(message='add a',
490
timestamp=1132711707,
492
committer='Lorem Ipsum <test@example.com>')
493
logfile = file('out.tmp', 'w+')
494
formatter = log.LongLogFormatter(to_file=logfile)
495
log.show_log(b, formatter, verbose=True)
498
log_contents = logfile.read()
499
self.assertEqualDiff('''\
477
wt = self.make_standard_commit('test_verbose_log', authors=[])
478
self.assertFormatterResult('''\
500
479
------------------------------------------------------------
502
481
committer: Lorem Ipsum <test@example.com>
503
482
branch nick: test_verbose_log
504
timestamp: Wed 2005-11-23 12:08:27 +1000
483
timestamp: Tue 2005-11-22 00:00:00 +0000
489
wt.branch, log.LongLogFormatter,
490
show_log_kwargs=dict(verbose=True))
512
492
def test_merges_are_indented_by_level(self):
513
493
wt = self.make_branch_and_tree('parent')
514
wt.commit('first post')
515
self.run_bzr('branch parent child')
516
self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
517
self.run_bzr('branch child smallerchild')
518
self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
521
self.run_bzr('merge ../smallerchild')
522
self.run_bzr(['commit', '-m', 'merge branch 2'])
523
os.chdir('../parent')
524
self.run_bzr('merge ../child')
525
wt.commit('merge branch 1')
527
sio = self.make_utf8_encoded_stringio()
528
lf = log.LongLogFormatter(to_file=sio, levels=0)
529
log.show_log(b, lf, verbose=True)
530
the_log = normalize_log(sio.getvalue())
531
self.assertEqualDiff("""\
494
self.wt_commit(wt, 'first post')
495
child_wt = wt.bzrdir.sprout('child').open_workingtree()
496
self.wt_commit(child_wt, 'branch 1')
497
smallerchild_wt = wt.bzrdir.sprout('smallerchild').open_workingtree()
498
self.wt_commit(smallerchild_wt, 'branch 2')
499
child_wt.merge_from_branch(smallerchild_wt.branch)
500
self.wt_commit(child_wt, 'merge branch 2')
501
wt.merge_from_branch(child_wt.branch)
502
self.wt_commit(wt, 'merge branch 1')
503
self.assertFormatterResult("""\
532
504
------------------------------------------------------------
534
committer: Lorem Ipsum <test@example.com>
506
committer: Joe Foo <joe@foo.com>
535
507
branch nick: parent
508
timestamp: Tue 2005-11-22 00:00:04 +0000
539
511
------------------------------------------------------------
540
512
revno: 1.1.2 [merge]
541
committer: Lorem Ipsum <test@example.com>
513
committer: Joe Foo <joe@foo.com>
542
514
branch nick: child
515
timestamp: Tue 2005-11-22 00:00:03 +0000
546
518
------------------------------------------------------------
548
committer: Lorem Ipsum <test@example.com>
520
committer: Joe Foo <joe@foo.com>
549
521
branch nick: smallerchild
522
timestamp: Tue 2005-11-22 00:00:02 +0000
553
525
------------------------------------------------------------
555
committer: Lorem Ipsum <test@example.com>
527
committer: Joe Foo <joe@foo.com>
556
528
branch nick: child
529
timestamp: Tue 2005-11-22 00:00:01 +0000
560
532
------------------------------------------------------------
562
committer: Lorem Ipsum <test@example.com>
534
committer: Joe Foo <joe@foo.com>
563
535
branch nick: parent
536
timestamp: Tue 2005-11-22 00:00:00 +0000
540
wt.branch, log.LongLogFormatter,
541
formatter_kwargs=dict(levels=0),
542
show_log_kwargs=dict(verbose=True))
570
544
def test_verbose_merge_revisions_contain_deltas(self):
571
545
wt = self.make_branch_and_tree('parent')
572
546
self.build_tree(['parent/f1', 'parent/f2'])
573
547
wt.add(['f1','f2'])
574
wt.commit('first post')
575
self.run_bzr('branch parent child')
548
self.wt_commit(wt, 'first post')
549
child_wt = wt.bzrdir.sprout('child').open_workingtree()
576
550
os.unlink('child/f1')
577
file('child/f2', 'wb').write('hello\n')
578
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
581
self.run_bzr('merge ../child')
582
wt.commit('merge branch 1')
584
sio = self.make_utf8_encoded_stringio()
585
lf = log.LongLogFormatter(to_file=sio, levels=0)
586
log.show_log(b, lf, verbose=True)
587
the_log = normalize_log(sio.getvalue())
588
self.assertEqualDiff("""\
551
self.build_tree_contents([('child/f2', 'hello\n')])
552
self.wt_commit(child_wt, 'removed f1 and modified f2')
553
wt.merge_from_branch(child_wt.branch)
554
self.wt_commit(wt, 'merge branch 1')
555
self.assertFormatterResult("""\
589
556
------------------------------------------------------------
591
committer: Lorem Ipsum <test@example.com>
558
committer: Joe Foo <joe@foo.com>
592
559
branch nick: parent
560
timestamp: Tue 2005-11-22 00:00:02 +0000
650
615
committer: Joe Foo <joe@foo.com>
651
616
branch nick: test
652
timestamp: Mon 2005-11-21 09:24:15 -0600
617
timestamp: Tue 2005-11-22 00:00:00 +0000
654
619
simple log message
621
b, log.LongLogFormatter)
658
623
def test_author_in_log(self):
659
624
"""Log includes the author name if it's set in
660
625
the revision properties
662
wt = self.make_branch_and_tree('.')
664
self.build_tree(['a'])
666
b.nick = 'test_author_log'
667
wt.commit(message='add a',
668
timestamp=1132711707,
670
committer='Lorem Ipsum <test@example.com>',
671
authors=['John Doe <jdoe@example.com>',
672
'Jane Rey <jrey@example.com>'])
674
formatter = log.LongLogFormatter(to_file=sio)
675
log.show_log(b, formatter)
676
self.assertEqualDiff('''\
627
wt = self.make_standard_commit('test_author_log',
628
authors=['John Doe <jdoe@example.com>',
629
'Jane Rey <jrey@example.com>'])
630
self.assertFormatterResult("""\
677
631
------------------------------------------------------------
679
633
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
680
634
committer: Lorem Ipsum <test@example.com>
681
635
branch nick: test_author_log
682
timestamp: Wed 2005-11-23 12:08:27 +1000
636
timestamp: Tue 2005-11-22 00:00:00 +0000
640
wt.branch, log.LongLogFormatter)
688
642
def test_properties_in_log(self):
689
643
"""Log includes the custom properties returned by the registered
692
wt = self.make_branch_and_tree('.')
694
self.build_tree(['a'])
696
b.nick = 'test_properties_in_log'
697
wt.commit(message='add a',
698
timestamp=1132711707,
700
committer='Lorem Ipsum <test@example.com>',
701
authors=['John Doe <jdoe@example.com>'])
703
formatter = log.LongLogFormatter(to_file=sio)
705
def trivial_custom_prop_handler(revision):
706
return {'test_prop':'test_value'}
646
wt = self.make_standard_commit('test_properties_in_log')
647
def trivial_custom_prop_handler(revision):
648
return {'test_prop':'test_value'}
708
log.properties_handler_registry.register(
709
'trivial_custom_prop_handler',
710
trivial_custom_prop_handler)
711
log.show_log(b, formatter)
713
log.properties_handler_registry.remove(
714
'trivial_custom_prop_handler')
715
self.assertEqualDiff('''\
650
# Cleaned up in setUp()
651
log.properties_handler_registry.register(
652
'trivial_custom_prop_handler',
653
trivial_custom_prop_handler)
654
self.assertFormatterResult("""\
716
655
------------------------------------------------------------
718
657
test_prop: test_value
719
658
author: John Doe <jdoe@example.com>
720
659
committer: Lorem Ipsum <test@example.com>
721
660
branch nick: test_properties_in_log
722
timestamp: Wed 2005-11-23 12:08:27 +1000
661
timestamp: Tue 2005-11-22 00:00:00 +0000
665
wt.branch, log.LongLogFormatter)
728
667
def test_properties_in_short_log(self):
729
668
"""Log includes the custom properties returned by the registered
732
wt = self.make_branch_and_tree('.')
734
self.build_tree(['a'])
736
b.nick = 'test_properties_in_short_log'
737
wt.commit(message='add a',
738
timestamp=1132711707,
740
committer='Lorem Ipsum <test@example.com>',
741
authors=['John Doe <jdoe@example.com>'])
743
formatter = log.ShortLogFormatter(to_file=sio)
745
def trivial_custom_prop_handler(revision):
746
return {'test_prop':'test_value'}
671
wt = self.make_standard_commit('test_properties_in_short_log')
672
def trivial_custom_prop_handler(revision):
673
return {'test_prop':'test_value'}
748
log.properties_handler_registry.register(
749
'trivial_custom_prop_handler',
750
trivial_custom_prop_handler)
751
log.show_log(b, formatter)
753
log.properties_handler_registry.remove(
754
'trivial_custom_prop_handler')
755
self.assertEqualDiff('''\
756
1 John Doe\t2005-11-23
675
log.properties_handler_registry.register(
676
'trivial_custom_prop_handler',
677
trivial_custom_prop_handler)
678
self.assertFormatterResult("""\
679
1 John Doe\t2005-11-22
757
680
test_prop: test_value
684
wt.branch, log.ShortLogFormatter)
763
686
def test_error_in_properties_handler(self):
764
687
"""Log includes the custom properties returned by the registered
767
wt = self.make_branch_and_tree('.')
769
self.build_tree(['a'])
771
b.nick = 'test_author_log'
772
wt.commit(message='add a',
773
timestamp=1132711707,
775
committer='Lorem Ipsum <test@example.com>',
776
authors=['John Doe <jdoe@example.com>'],
777
revprops={'first_prop':'first_value'})
690
wt = self.make_standard_commit('error_in_properties_handler',
691
revprops={'first_prop':'first_value'})
692
sio = self.make_utf8_encoded_stringio()
779
693
formatter = log.LongLogFormatter(to_file=sio)
781
def trivial_custom_prop_handler(revision):
782
raise StandardError("a test error")
694
def trivial_custom_prop_handler(revision):
695
raise StandardError("a test error")
784
log.properties_handler_registry.register(
785
'trivial_custom_prop_handler',
786
trivial_custom_prop_handler)
787
self.assertRaises(StandardError, log.show_log, b, formatter,)
789
log.properties_handler_registry.remove(
790
'trivial_custom_prop_handler')
697
log.properties_handler_registry.register(
698
'trivial_custom_prop_handler',
699
trivial_custom_prop_handler)
700
self.assertRaises(StandardError, log.show_log, wt.branch, formatter,)
792
702
def test_properties_handler_bad_argument(self):
793
wt = self.make_branch_and_tree('.')
795
self.build_tree(['a'])
797
b.nick = 'test_author_log'
798
wt.commit(message='add a',
799
timestamp=1132711707,
801
committer='Lorem Ipsum <test@example.com>',
802
authors=['John Doe <jdoe@example.com>'],
803
revprops={'a_prop':'test_value'})
703
wt = self.make_standard_commit('bad_argument',
704
revprops={'a_prop':'test_value'})
705
sio = self.make_utf8_encoded_stringio()
805
706
formatter = log.LongLogFormatter(to_file=sio)
807
def bad_argument_prop_handler(revision):
808
return {'custom_prop_name':revision.properties['a_prop']}
810
log.properties_handler_registry.register(
811
'bad_argument_prop_handler',
812
bad_argument_prop_handler)
814
self.assertRaises(AttributeError, formatter.show_properties,
817
revision = b.repository.get_revision(b.last_revision())
818
formatter.show_properties(revision, '')
819
self.assertEqualDiff('''custom_prop_name: test_value\n''',
822
log.properties_handler_registry.remove(
823
'bad_argument_prop_handler')
826
class TestLongLogFormatterWithoutMergeRevisions(TestCaseWithoutPropsHandler):
707
def bad_argument_prop_handler(revision):
708
return {'custom_prop_name':revision.properties['a_prop']}
710
log.properties_handler_registry.register(
711
'bad_argument_prop_handler',
712
bad_argument_prop_handler)
714
self.assertRaises(AttributeError, formatter.show_properties,
717
revision = wt.branch.repository.get_revision(wt.branch.last_revision())
718
formatter.show_properties(revision, '')
719
self.assertEqualDiff('''custom_prop_name: test_value\n''',
722
def test_show_ids(self):
723
wt = self.make_branch_and_tree('parent')
724
self.build_tree(['parent/f1', 'parent/f2'])
726
self.wt_commit(wt, 'first post', rev_id='a')
727
child_wt = wt.bzrdir.sprout('child').open_workingtree()
728
self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
729
wt.merge_from_branch(child_wt.branch)
730
self.wt_commit(wt, 'merge branch 1', rev_id='c')
731
self.assertFormatterResult("""\
732
------------------------------------------------------------
737
committer: Joe Foo <joe@foo.com>
739
timestamp: Tue 2005-11-22 00:00:02 +0000
742
------------------------------------------------------------
746
committer: Joe Foo <joe@foo.com>
748
timestamp: Tue 2005-11-22 00:00:01 +0000
751
------------------------------------------------------------
754
committer: Joe Foo <joe@foo.com>
756
timestamp: Tue 2005-11-22 00:00:00 +0000
760
wt.branch, log.LongLogFormatter,
761
formatter_kwargs=dict(levels=0,show_ids=True))
764
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
828
766
def test_long_verbose_log(self):
829
767
"""Verbose log includes changed files
833
wt = self.make_branch_and_tree('.')
835
self.build_tree(['a'])
837
# XXX: why does a longer nick show up?
838
b.nick = 'test_verbose_log'
839
wt.commit(message='add a',
840
timestamp=1132711707,
842
committer='Lorem Ipsum <test@example.com>')
843
logfile = file('out.tmp', 'w+')
844
formatter = log.LongLogFormatter(to_file=logfile, levels=1)
845
log.show_log(b, formatter, verbose=True)
848
log_contents = logfile.read()
849
self.assertEqualDiff('''\
771
wt = self.make_standard_commit('test_long_verbose_log', authors=[])
772
self.assertFormatterResult("""\
850
773
------------------------------------------------------------
852
775
committer: Lorem Ipsum <test@example.com>
853
branch nick: test_verbose_log
854
timestamp: Wed 2005-11-23 12:08:27 +1000
776
branch nick: test_long_verbose_log
777
timestamp: Tue 2005-11-22 00:00:00 +0000
783
wt.branch, log.LongLogFormatter,
784
formatter_kwargs=dict(levels=1),
785
show_log_kwargs=dict(verbose=True))
862
787
def test_long_verbose_contain_deltas(self):
863
788
wt = self.make_branch_and_tree('parent')
864
789
self.build_tree(['parent/f1', 'parent/f2'])
865
790
wt.add(['f1','f2'])
866
wt.commit('first post')
867
self.run_bzr('branch parent child')
791
self.wt_commit(wt, 'first post')
792
child_wt = wt.bzrdir.sprout('child').open_workingtree()
868
793
os.unlink('child/f1')
869
file('child/f2', 'wb').write('hello\n')
870
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
873
self.run_bzr('merge ../child')
874
wt.commit('merge branch 1')
876
sio = self.make_utf8_encoded_stringio()
877
lf = log.LongLogFormatter(to_file=sio, levels=1)
878
log.show_log(b, lf, verbose=True)
879
the_log = normalize_log(sio.getvalue())
880
self.assertEqualDiff("""\
794
self.build_tree_contents([('child/f2', 'hello\n')])
795
self.wt_commit(child_wt, 'removed f1 and modified f2')
796
wt.merge_from_branch(child_wt.branch)
797
self.wt_commit(wt, 'merge branch 1')
798
self.assertFormatterResult("""\
881
799
------------------------------------------------------------
883
committer: Lorem Ipsum <test@example.com>
801
committer: Joe Foo <joe@foo.com>
884
802
branch nick: parent
803
timestamp: Tue 2005-11-22 00:00:02 +0000
931
847
committer: Joe Foo <joe@foo.com>
932
848
branch nick: test
933
timestamp: Mon 2005-11-21 09:24:15 -0600
849
timestamp: Tue 2005-11-22 00:00:00 +0000
935
851
simple log message
853
b, log.LongLogFormatter,
854
formatter_kwargs=dict(levels=1))
939
856
def test_long_author_in_log(self):
940
857
"""Log includes the author name if it's set in
941
858
the revision properties
943
wt = self.make_branch_and_tree('.')
945
self.build_tree(['a'])
947
b.nick = 'test_author_log'
948
wt.commit(message='add a',
949
timestamp=1132711707,
951
committer='Lorem Ipsum <test@example.com>',
952
authors=['John Doe <jdoe@example.com>'])
954
formatter = log.LongLogFormatter(to_file=sio, levels=1)
955
log.show_log(b, formatter)
956
self.assertEqualDiff('''\
860
wt = self.make_standard_commit('test_author_log')
861
self.assertFormatterResult("""\
957
862
------------------------------------------------------------
959
864
author: John Doe <jdoe@example.com>
960
865
committer: Lorem Ipsum <test@example.com>
961
866
branch nick: test_author_log
962
timestamp: Wed 2005-11-23 12:08:27 +1000
867
timestamp: Tue 2005-11-22 00:00:00 +0000
871
wt.branch, log.LongLogFormatter,
872
formatter_kwargs=dict(levels=1))
968
874
def test_long_properties_in_log(self):
969
875
"""Log includes the custom properties returned by the registered
972
wt = self.make_branch_and_tree('.')
974
self.build_tree(['a'])
976
b.nick = 'test_properties_in_log'
977
wt.commit(message='add a',
978
timestamp=1132711707,
980
committer='Lorem Ipsum <test@example.com>',
981
authors=['John Doe <jdoe@example.com>'])
983
formatter = log.LongLogFormatter(to_file=sio, levels=1)
985
def trivial_custom_prop_handler(revision):
986
return {'test_prop':'test_value'}
878
wt = self.make_standard_commit('test_properties_in_log')
879
def trivial_custom_prop_handler(revision):
880
return {'test_prop':'test_value'}
988
log.properties_handler_registry.register(
989
'trivial_custom_prop_handler',
990
trivial_custom_prop_handler)
991
log.show_log(b, formatter)
993
log.properties_handler_registry.remove(
994
'trivial_custom_prop_handler')
995
self.assertEqualDiff('''\
882
log.properties_handler_registry.register(
883
'trivial_custom_prop_handler',
884
trivial_custom_prop_handler)
885
self.assertFormatterResult("""\
996
886
------------------------------------------------------------
998
888
test_prop: test_value
999
889
author: John Doe <jdoe@example.com>
1000
890
committer: Lorem Ipsum <test@example.com>
1001
891
branch nick: test_properties_in_log
1002
timestamp: Wed 2005-11-23 12:08:27 +1000
892
timestamp: Tue 2005-11-22 00:00:00 +0000
1009
class TestLineLogFormatter(tests.TestCaseWithTransport):
896
wt.branch, log.LongLogFormatter,
897
formatter_kwargs=dict(levels=1))
900
class TestLineLogFormatter(TestCaseForLogFormatter):
1011
902
def test_line_log(self):
1012
903
"""Line log should show revno
1016
wt = self.make_branch_and_tree('.')
1018
self.build_tree(['a'])
1020
b.nick = 'test-line-log'
1021
wt.commit(message='add a',
1022
timestamp=1132711707,
1024
committer='Line-Log-Formatter Tester <test@line.log>')
1025
logfile = file('out.tmp', 'w+')
1026
formatter = log.LineLogFormatter(to_file=logfile)
1027
log.show_log(b, formatter)
1030
log_contents = logfile.read()
1031
self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
907
wt = self.make_standard_commit('test-line-log',
908
committer='Line-Log-Formatter Tester <test@line.log>',
910
self.assertFormatterResult("""\
911
1: Line-Log-Formatte... 2005-11-22 add a
913
wt.branch, log.LineLogFormatter)
1034
915
def test_trailing_newlines(self):
1035
916
wt = self.make_branch_and_tree('.')
1036
b = make_commits_with_trailing_newlines(wt)
1037
sio = self.make_utf8_encoded_stringio()
1038
lf = log.LineLogFormatter(to_file=sio)
1040
self.assertEqualDiff("""\
1041
3: Joe Foo 2005-11-21 single line with trailing newline
1042
2: Joe Bar 2005-11-21 multiline
1043
1: Joe Foo 2005-11-21 simple log message
917
b = self.make_commits_with_trailing_newlines(wt)
918
self.assertFormatterResult("""\
919
3: Joe Foo 2005-11-22 single line with trailing newline
920
2: Joe Foo 2005-11-22 multiline
921
1: Joe Foo 2005-11-22 simple log message
1047
def _prepare_tree_with_merges(self, with_tags=False):
1048
wt = self.make_branch_and_memory_tree('.')
1050
self.addCleanup(wt.unlock)
1052
wt.commit('rev-1', rev_id='rev-1',
1053
timestamp=1132586655, timezone=36000,
1054
committer='Joe Foo <joe@foo.com>')
1055
wt.commit('rev-merged', rev_id='rev-2a',
1056
timestamp=1132586700, timezone=36000,
1057
committer='Joe Foo <joe@foo.com>')
1058
wt.set_parent_ids(['rev-1', 'rev-2a'])
1059
wt.branch.set_last_revision_info(1, 'rev-1')
1060
wt.commit('rev-2', rev_id='rev-2b',
1061
timestamp=1132586800, timezone=36000,
1062
committer='Joe Foo <joe@foo.com>')
1065
branch.tags.set_tag('v0.2', 'rev-2b')
1066
wt.commit('rev-3', rev_id='rev-3',
1067
timestamp=1132586900, timezone=36000,
1068
committer='Jane Foo <jane@foo.com>')
1069
branch.tags.set_tag('v1.0rc1', 'rev-3')
1070
branch.tags.set_tag('v1.0', 'rev-3')
923
b, log.LineLogFormatter)
1073
925
def test_line_log_single_merge_revision(self):
1074
926
wt = self._prepare_tree_with_merges()
1075
logfile = self.make_utf8_encoded_stringio()
1076
formatter = log.LineLogFormatter(to_file=logfile)
1077
927
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1079
rev = revspec.in_history(wtb)
1080
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1081
self.assertEqualDiff("""\
928
rev = revspec.in_history(wt.branch)
929
self.assertFormatterResult("""\
1082
930
1.1.1: Joe Foo 2005-11-22 rev-merged
932
wt.branch, log.LineLogFormatter,
933
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1086
935
def test_line_log_with_tags(self):
1087
936
wt = self._prepare_tree_with_merges(with_tags=True)
1088
logfile = self.make_utf8_encoded_stringio()
1089
formatter = log.LineLogFormatter(to_file=logfile)
1090
log.show_log(wt.branch, formatter)
1091
self.assertEqualDiff("""\
1092
3: Jane Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
937
self.assertFormatterResult("""\
938
3: Joe Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
1093
939
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
1094
940
1: Joe Foo 2005-11-22 rev-1
1098
class TestLineLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
942
wt.branch, log.LineLogFormatter)
945
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
1100
947
def test_line_merge_revs_log(self):
1101
948
"""Line log should show revno
1105
wt = self.make_branch_and_tree('.')
1107
self.build_tree(['a'])
1109
b.nick = 'test-line-log'
1110
wt.commit(message='add a',
1111
timestamp=1132711707,
1113
committer='Line-Log-Formatter Tester <test@line.log>')
1114
logfile = file('out.tmp', 'w+')
1115
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1116
log.show_log(b, formatter)
1119
log_contents = logfile.read()
1120
self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
952
wt = self.make_standard_commit('test-line-log',
953
committer='Line-Log-Formatter Tester <test@line.log>',
955
self.assertFormatterResult("""\
956
1: Line-Log-Formatte... 2005-11-22 add a
958
wt.branch, log.LineLogFormatter)
1123
960
def test_line_merge_revs_log_single_merge_revision(self):
1124
wt = self.make_branch_and_memory_tree('.')
1126
self.addCleanup(wt.unlock)
1128
wt.commit('rev-1', rev_id='rev-1',
1129
timestamp=1132586655, timezone=36000,
1130
committer='Joe Foo <joe@foo.com>')
1131
wt.commit('rev-merged', rev_id='rev-2a',
1132
timestamp=1132586700, timezone=36000,
1133
committer='Joe Foo <joe@foo.com>')
1134
wt.set_parent_ids(['rev-1', 'rev-2a'])
1135
wt.branch.set_last_revision_info(1, 'rev-1')
1136
wt.commit('rev-2', rev_id='rev-2b',
1137
timestamp=1132586800, timezone=36000,
1138
committer='Joe Foo <joe@foo.com>')
1139
logfile = self.make_utf8_encoded_stringio()
1140
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
961
wt = self._prepare_tree_with_merges()
1141
962
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1143
rev = revspec.in_history(wtb)
1144
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1145
self.assertEqualDiff("""\
963
rev = revspec.in_history(wt.branch)
964
self.assertFormatterResult("""\
1146
965
1.1.1: Joe Foo 2005-11-22 rev-merged
967
wt.branch, log.LineLogFormatter,
968
formatter_kwargs=dict(levels=0),
969
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1150
971
def test_line_merge_revs_log_with_merges(self):
1151
wt = self.make_branch_and_memory_tree('.')
1153
self.addCleanup(wt.unlock)
1155
wt.commit('rev-1', rev_id='rev-1',
1156
timestamp=1132586655, timezone=36000,
1157
committer='Joe Foo <joe@foo.com>')
1158
wt.commit('rev-merged', rev_id='rev-2a',
1159
timestamp=1132586700, timezone=36000,
1160
committer='Joe Foo <joe@foo.com>')
1161
wt.set_parent_ids(['rev-1', 'rev-2a'])
1162
wt.branch.set_last_revision_info(1, 'rev-1')
1163
wt.commit('rev-2', rev_id='rev-2b',
1164
timestamp=1132586800, timezone=36000,
1165
committer='Joe Foo <joe@foo.com>')
1166
logfile = self.make_utf8_encoded_stringio()
1167
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1168
log.show_log(wt.branch, formatter)
1169
self.assertEqualDiff("""\
972
wt = self._prepare_tree_with_merges()
973
self.assertFormatterResult("""\
1170
974
2: Joe Foo 2005-11-22 [merge] rev-2
1171
975
1.1.1: Joe Foo 2005-11-22 rev-merged
1172
976
1: Joe Foo 2005-11-22 rev-1
1176
class TestGetViewRevisions(tests.TestCaseWithTransport):
1178
def make_tree_with_commits(self):
1179
"""Create a tree with well-known revision ids"""
1180
wt = self.make_branch_and_tree('tree1')
1181
wt.commit('commit one', rev_id='1')
1182
wt.commit('commit two', rev_id='2')
1183
wt.commit('commit three', rev_id='3')
1184
mainline_revs = [None, '1', '2', '3']
1185
rev_nos = {'1': 1, '2': 2, '3': 3}
1186
return mainline_revs, rev_nos, wt
1188
def make_tree_with_merges(self):
1189
"""Create a tree with well-known revision ids and a merge"""
1190
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1191
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1192
tree2.commit('four-a', rev_id='4a')
1193
wt.merge_from_branch(tree2.branch)
1194
wt.commit('four-b', rev_id='4b')
1195
mainline_revs.append('4b')
1198
return mainline_revs, rev_nos, wt
1200
def make_tree_with_many_merges(self):
1201
"""Create a tree with well-known revision ids"""
1202
wt = self.make_branch_and_tree('tree1')
1203
self.build_tree_contents([('tree1/f', '1\n')])
1204
wt.add(['f'], ['f-id'])
1205
wt.commit('commit one', rev_id='1')
1206
wt.commit('commit two', rev_id='2')
1208
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
1209
self.build_tree_contents([('tree3/f', '1\n2\n3a\n')])
1210
tree3.commit('commit three a', rev_id='3a')
1212
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1213
tree2.merge_from_branch(tree3.branch)
1214
tree2.commit('commit three b', rev_id='3b')
1216
wt.merge_from_branch(tree2.branch)
1217
wt.commit('commit three c', rev_id='3c')
1218
tree2.commit('four-a', rev_id='4a')
1220
wt.merge_from_branch(tree2.branch)
1221
wt.commit('four-b', rev_id='4b')
1223
mainline_revs = [None, '1', '2', '3c', '4b']
1224
rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
1225
full_rev_nos_for_reference = {
1228
'3a': '2.1.1', #first commit tree 3
1229
'3b': '2.2.1', # first commit tree 2
1230
'3c': '3', #merges 3b to main
1231
'4a': '2.2.2', # second commit tree 2
1232
'4b': '4', # merges 4a to main
1234
return mainline_revs, rev_nos, wt
1236
def test_get_view_revisions_forward(self):
1237
"""Test the get_view_revisions method"""
1238
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1240
self.addCleanup(wt.unlock)
1241
revisions = list(log.get_view_revisions(
1242
mainline_revs, rev_nos, wt.branch, 'forward'))
1243
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
1245
revisions2 = list(log.get_view_revisions(
1246
mainline_revs, rev_nos, wt.branch, 'forward',
1247
include_merges=False))
1248
self.assertEqual(revisions, revisions2)
1250
def test_get_view_revisions_reverse(self):
1251
"""Test the get_view_revisions with reverse"""
1252
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1254
self.addCleanup(wt.unlock)
1255
revisions = list(log.get_view_revisions(
1256
mainline_revs, rev_nos, wt.branch, 'reverse'))
1257
self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
1259
revisions2 = list(log.get_view_revisions(
1260
mainline_revs, rev_nos, wt.branch, 'reverse',
1261
include_merges=False))
1262
self.assertEqual(revisions, revisions2)
1264
def test_get_view_revisions_merge(self):
1265
"""Test get_view_revisions when there are merges"""
1266
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1268
self.addCleanup(wt.unlock)
1269
revisions = list(log.get_view_revisions(
1270
mainline_revs, rev_nos, wt.branch, 'forward'))
1271
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1272
('4b', '4', 0), ('4a', '3.1.1', 1)],
1274
revisions = list(log.get_view_revisions(
1275
mainline_revs, rev_nos, wt.branch, 'forward',
1276
include_merges=False))
1277
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1281
def test_get_view_revisions_merge_reverse(self):
1282
"""Test get_view_revisions in reverse when there are merges"""
1283
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1285
self.addCleanup(wt.unlock)
1286
revisions = list(log.get_view_revisions(
1287
mainline_revs, rev_nos, wt.branch, 'reverse'))
1288
self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
1289
('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
1291
revisions = list(log.get_view_revisions(
1292
mainline_revs, rev_nos, wt.branch, 'reverse',
1293
include_merges=False))
1294
self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
1298
def test_get_view_revisions_merge2(self):
1299
"""Test get_view_revisions when there are merges"""
1300
mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1302
self.addCleanup(wt.unlock)
1303
revisions = list(log.get_view_revisions(
1304
mainline_revs, rev_nos, wt.branch, 'forward'))
1305
expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1306
('3a', '2.1.1', 1), ('3b', '2.2.1', 1), ('4b', '4', 0),
1308
self.assertEqual(expected, revisions)
1309
revisions = list(log.get_view_revisions(
1310
mainline_revs, rev_nos, wt.branch, 'forward',
1311
include_merges=False))
1312
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1317
def test_file_id_for_range(self):
1318
mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1320
self.addCleanup(wt.unlock)
1322
def rev_from_rev_id(revid, branch):
1323
revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1324
return revspec.in_history(branch)
1326
def view_revs(start_rev, end_rev, file_id, direction):
1327
revs = log.calculate_view_revisions(
1329
start_rev, # start_revision
1330
end_rev, # end_revision
1331
direction, # direction
1332
file_id, # specific_fileid
1333
True, # generate_merge_revisions
1337
rev_3a = rev_from_rev_id('3a', wt.branch)
1338
rev_4b = rev_from_rev_id('4b', wt.branch)
1339
self.assertEqual([('3c', '3', 0), ('3a', '2.1.1', 1)],
1340
view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
1341
# Note: 3c still appears before 3a here because of depth-based sorting
1342
self.assertEqual([('3c', '3', 0), ('3a', '2.1.1', 1)],
1343
view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1346
class TestGetRevisionsTouchingFileID(tests.TestCaseWithTransport):
1348
def create_tree_with_single_merge(self):
1349
"""Create a branch with a moderate layout.
1351
The revision graph looks like:
1359
In this graph, A introduced files f1 and f2 and f3.
1360
B modifies f1 and f3, and C modifies f2 and f3.
1361
D merges the changes from B and C and resolves the conflict for f3.
1363
# TODO: jam 20070218 This seems like it could really be done
1364
# with make_branch_and_memory_tree() if we could just
1365
# create the content of those files.
1366
# TODO: jam 20070218 Another alternative is that we would really
1367
# like to only create this tree 1 time for all tests that
1368
# use it. Since 'log' only uses the tree in a readonly
1369
# fashion, it seems a shame to regenerate an identical
1370
# tree for each test.
1371
tree = self.make_branch_and_tree('tree')
1373
self.addCleanup(tree.unlock)
1375
self.build_tree_contents([('tree/f1', 'A\n'),
1379
tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
1380
tree.commit('A', rev_id='A')
1382
self.build_tree_contents([('tree/f2', 'A\nC\n'),
1383
('tree/f3', 'A\nC\n'),
1385
tree.commit('C', rev_id='C')
1386
# Revert back to A to build the other history.
1387
tree.set_last_revision('A')
1388
tree.branch.set_last_revision_info(1, 'A')
1389
self.build_tree_contents([('tree/f1', 'A\nB\n'),
1391
('tree/f3', 'A\nB\n'),
1393
tree.commit('B', rev_id='B')
1394
tree.set_parent_ids(['B', 'C'])
1395
self.build_tree_contents([('tree/f1', 'A\nB\n'),
1396
('tree/f2', 'A\nC\n'),
1397
('tree/f3', 'A\nB\nC\n'),
1399
tree.commit('D', rev_id='D')
1401
# Switch to a read lock for this tree.
1402
# We still have an addCleanup(tree.unlock) pending
1407
def check_delta(self, delta, **kw):
1408
"""Check the filenames touched by a delta are as expected.
1410
Caller only have to pass in the list of files for each part, all
1411
unspecified parts are considered empty (and checked as such).
1413
for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
1414
# By default we expect an empty list
1415
expected = kw.get(n, [])
1416
# strip out only the path components
1417
got = [x[0] for x in getattr(delta, n)]
1418
self.assertEqual(expected, got)
1420
def test_tree_with_single_merge(self):
1421
"""Make sure the tree layout is correct."""
1422
tree = self.create_tree_with_single_merge()
1423
rev_A_tree = tree.branch.repository.revision_tree('A')
1424
rev_B_tree = tree.branch.repository.revision_tree('B')
1425
rev_C_tree = tree.branch.repository.revision_tree('C')
1426
rev_D_tree = tree.branch.repository.revision_tree('D')
1428
self.check_delta(rev_B_tree.changes_from(rev_A_tree),
1429
modified=['f1', 'f3'])
1431
self.check_delta(rev_C_tree.changes_from(rev_A_tree),
1432
modified=['f2', 'f3'])
1434
self.check_delta(rev_D_tree.changes_from(rev_B_tree),
1435
modified=['f2', 'f3'])
1437
self.check_delta(rev_D_tree.changes_from(rev_C_tree),
1438
modified=['f1', 'f3'])
1440
def assertAllRevisionsForFileID(self, tree, file_id, revisions):
1441
"""Ensure _filter_revisions_touching_file_id returns the right values.
1443
Get the return value from _filter_revisions_touching_file_id and make
1444
sure they are correct.
1446
# The api for _filter_revisions_touching_file_id is a little crazy.
1447
# So we do the setup here.
1448
mainline = tree.branch.revision_history()
1449
mainline.insert(0, None)
1450
revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
1451
view_revs_iter = log.get_view_revisions(mainline, revnos, tree.branch,
1453
actual_revs = log._filter_revisions_touching_file_id(
1456
list(view_revs_iter))
1457
self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
1459
def test_file_id_f1(self):
1460
tree = self.create_tree_with_single_merge()
1461
# f1 should be marked as modified by revisions A and B
1462
self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
1464
def test_file_id_f2(self):
1465
tree = self.create_tree_with_single_merge()
1466
# f2 should be marked as modified by revisions A, C, and D
1467
# because D merged the changes from C.
1468
self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1470
def test_file_id_f3(self):
1471
tree = self.create_tree_with_single_merge()
1472
# f3 should be marked as modified by revisions A, B, C, and D
1473
self.assertAllRevisionsForFileID(tree, 'f3-id', ['D', 'C', 'B', 'A'])
1475
def test_file_id_with_ghosts(self):
1476
# This is testing bug #209948, where having a ghost would cause
1477
# _filter_revisions_touching_file_id() to fail.
1478
tree = self.create_tree_with_single_merge()
1479
# We need to add a revision, so switch back to a write-locked tree
1480
# (still a single addCleanup(tree.unlock) pending).
1483
first_parent = tree.last_revision()
1484
tree.set_parent_ids([first_parent, 'ghost-revision-id'])
1485
self.build_tree_contents([('tree/f1', 'A\nB\nXX\n')])
1486
tree.commit('commit with a ghost', rev_id='XX')
1487
self.assertAllRevisionsForFileID(tree, 'f1-id', ['XX', 'B', 'A'])
1488
self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1490
def test_unknown_file_id(self):
1491
tree = self.create_tree_with_single_merge()
1492
self.assertAllRevisionsForFileID(tree, 'unknown', [])
1494
def test_empty_branch_unknown_file_id(self):
1495
tree = self.make_branch_and_tree('tree')
1496
self.assertAllRevisionsForFileID(tree, 'unknown', [])
978
wt.branch, log.LineLogFormatter,
979
formatter_kwargs=dict(levels=0))
982
class TestGnuChangelogFormatter(TestCaseForLogFormatter):
984
def test_gnu_changelog(self):
985
wt = self.make_standard_commit('nicky', authors=[])
986
self.assertFormatterResult('''\
987
2005-11-22 Lorem Ipsum <test@example.com>
992
wt.branch, log.GnuChangelogLogFormatter)
994
def test_with_authors(self):
995
wt = self.make_standard_commit('nicky',
996
authors=['Fooa Fooz <foo@example.com>',
997
'Bari Baro <bar@example.com>'])
998
self.assertFormatterResult('''\
999
2005-11-22 Fooa Fooz <foo@example.com>
1004
wt.branch, log.GnuChangelogLogFormatter)
1006
def test_verbose(self):
1007
wt = self.make_standard_commit('nicky')
1008
self.assertFormatterResult('''\
1009
2005-11-22 John Doe <jdoe@example.com>
1016
wt.branch, log.GnuChangelogLogFormatter,
1017
show_log_kwargs=dict(verbose=True))
1499
1020
class TestShowChangedRevisions(tests.TestCaseWithTransport):
1697
1219
log.show_branch_change(tree.branch, s, 3, '3b')
1698
1220
self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1699
1221
self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1224
class TestRevisionNotInBranch(TestCaseForLogFormatter):
1226
def setup_a_tree(self):
1227
tree = self.make_branch_and_tree('tree')
1229
self.addCleanup(tree.unlock)
1231
'committer': 'Joe Foo <joe@foo.com>',
1232
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1233
'timezone': 0, # UTC
1235
tree.commit('commit 1a', rev_id='1a', **kwargs)
1236
tree.commit('commit 2a', rev_id='2a', **kwargs)
1237
tree.commit('commit 3a', rev_id='3a', **kwargs)
1240
def setup_ab_tree(self):
1241
tree = self.setup_a_tree()
1242
tree.set_last_revision('1a')
1243
tree.branch.set_last_revision_info(1, '1a')
1245
'committer': 'Joe Foo <joe@foo.com>',
1246
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1247
'timezone': 0, # UTC
1249
tree.commit('commit 2b', rev_id='2b', **kwargs)
1250
tree.commit('commit 3b', rev_id='3b', **kwargs)
1253
def test_one_revision(self):
1254
tree = self.setup_ab_tree()
1256
rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1257
log.show_log(tree.branch, lf, verbose=True, start_revision=rev,
1259
self.assertEqual(1, len(lf.revisions))
1260
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1261
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1263
def test_many_revisions(self):
1264
tree = self.setup_ab_tree()
1266
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1267
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1268
log.show_log(tree.branch, lf, verbose=True, start_revision=start_rev,
1269
end_revision=end_rev)
1270
self.assertEqual(3, len(lf.revisions))
1271
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1272
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1273
self.assertEqual(None, lf.revisions[1].revno) # Out-of-branch
1274
self.assertEqual('2a', lf.revisions[1].rev.revision_id)
1275
self.assertEqual('1', lf.revisions[2].revno) # In-branch
1277
def test_long_format(self):
1278
tree = self.setup_ab_tree()
1279
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1280
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1281
self.assertFormatterResult("""\
1282
------------------------------------------------------------
1284
committer: Joe Foo <joe@foo.com>
1286
timestamp: Tue 2005-11-22 00:00:00 +0000
1289
------------------------------------------------------------
1291
committer: Joe Foo <joe@foo.com>
1293
timestamp: Tue 2005-11-22 00:00:00 +0000
1296
------------------------------------------------------------
1298
committer: Joe Foo <joe@foo.com>
1300
timestamp: Tue 2005-11-22 00:00:00 +0000
1304
tree.branch, log.LongLogFormatter, show_log_kwargs={
1305
'start_revision': start_rev, 'end_revision': end_rev
1308
def test_short_format(self):
1309
tree = self.setup_ab_tree()
1310
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1311
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1312
self.assertFormatterResult("""\
1321
1 Joe Foo\t2005-11-22
1325
tree.branch, log.ShortLogFormatter, show_log_kwargs={
1326
'start_revision': start_rev, 'end_revision': end_rev
1329
def test_line_format(self):
1330
tree = self.setup_ab_tree()
1331
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1332
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1333
self.assertFormatterResult("""\
1334
Joe Foo 2005-11-22 commit 3a
1335
Joe Foo 2005-11-22 commit 2a
1336
1: Joe Foo 2005-11-22 commit 1a
1338
tree.branch, log.LineLogFormatter, show_log_kwargs={
1339
'start_revision': start_rev, 'end_revision': end_rev
1343
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1346
super(TestLogWithBugs, self).setUp()
1347
log.properties_handler_registry.register(
1348
'bugs_properties_handler',
1349
log._bugs_properties_handler)
1351
def make_commits_with_bugs(self):
1352
"""Helper method for LogFormatter tests"""
1353
tree = self.make_branch_and_tree(u'.')
1354
self.build_tree(['a', 'b'])
1356
self.wt_commit(tree, 'simple log message', rev_id='a1',
1357
revprops={'bugs': 'test://bug/id fixed'})
1359
self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id='a2',
1360
authors=['Joe Bar <joe@bar.com>'],
1361
revprops={'bugs': 'test://bug/id fixed\n'
1362
'test://bug/2 fixed'})
1366
def test_long_bugs(self):
1367
tree = self.make_commits_with_bugs()
1368
self.assertFormatterResult("""\
1369
------------------------------------------------------------
1371
fixes bugs: test://bug/id test://bug/2
1372
author: Joe Bar <joe@bar.com>
1373
committer: Joe Foo <joe@foo.com>
1375
timestamp: Tue 2005-11-22 00:00:01 +0000
1380
------------------------------------------------------------
1382
fixes bug: test://bug/id
1383
committer: Joe Foo <joe@foo.com>
1385
timestamp: Tue 2005-11-22 00:00:00 +0000
1389
tree.branch, log.LongLogFormatter)
1391
def test_short_bugs(self):
1392
tree = self.make_commits_with_bugs()
1393
self.assertFormatterResult("""\
1394
2 Joe Bar\t2005-11-22
1395
fixes bugs: test://bug/id test://bug/2
1400
1 Joe Foo\t2005-11-22
1401
fixes bug: test://bug/id
1405
tree.branch, log.ShortLogFormatter)
1407
def test_wrong_bugs_property(self):
1408
tree = self.make_branch_and_tree(u'.')
1409
self.build_tree(['foo'])
1410
self.wt_commit(tree, 'simple log message', rev_id='a1',
1411
revprops={'bugs': 'test://bug/id invalid_value'})
1412
self.assertFormatterResult("""\
1413
1 Joe Foo\t2005-11-22
1417
tree.branch, log.ShortLogFormatter)
1419
def test_bugs_handler_present(self):
1420
self.properties_handler_registry.get('bugs_properties_handler')
1423
class TestLogForAuthors(TestCaseForLogFormatter):
1426
super(TestLogForAuthors, self).setUp()
1427
self.wt = self.make_standard_commit('nicky',
1428
authors=['John Doe <jdoe@example.com>',
1429
'Jane Rey <jrey@example.com>'])
1431
def assertFormatterResult(self, formatter, who, result):
1432
formatter_kwargs = dict()
1434
author_list_handler = log.author_list_registry.get(who)
1435
formatter_kwargs['author_list_handler'] = author_list_handler
1436
TestCaseForLogFormatter.assertFormatterResult(self, result,
1437
self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1439
def test_line_default(self):
1440
self.assertFormatterResult(log.LineLogFormatter, None, """\
1441
1: John Doe 2005-11-22 add a
1444
def test_line_committer(self):
1445
self.assertFormatterResult(log.LineLogFormatter, 'committer', """\
1446
1: Lorem Ipsum 2005-11-22 add a
1449
def test_line_first(self):
1450
self.assertFormatterResult(log.LineLogFormatter, 'first', """\
1451
1: John Doe 2005-11-22 add a
1454
def test_line_all(self):
1455
self.assertFormatterResult(log.LineLogFormatter, 'all', """\
1456
1: John Doe, Jane Rey 2005-11-22 add a
1460
def test_short_default(self):
1461
self.assertFormatterResult(log.ShortLogFormatter, None, """\
1462
1 John Doe\t2005-11-22
1467
def test_short_committer(self):
1468
self.assertFormatterResult(log.ShortLogFormatter, 'committer', """\
1469
1 Lorem Ipsum\t2005-11-22
1474
def test_short_first(self):
1475
self.assertFormatterResult(log.ShortLogFormatter, 'first', """\
1476
1 John Doe\t2005-11-22
1481
def test_short_all(self):
1482
self.assertFormatterResult(log.ShortLogFormatter, 'all', """\
1483
1 John Doe, Jane Rey\t2005-11-22
1488
def test_long_default(self):
1489
self.assertFormatterResult(log.LongLogFormatter, None, """\
1490
------------------------------------------------------------
1492
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1493
committer: Lorem Ipsum <test@example.com>
1495
timestamp: Tue 2005-11-22 00:00:00 +0000
1500
def test_long_committer(self):
1501
self.assertFormatterResult(log.LongLogFormatter, 'committer', """\
1502
------------------------------------------------------------
1504
committer: Lorem Ipsum <test@example.com>
1506
timestamp: Tue 2005-11-22 00:00:00 +0000
1511
def test_long_first(self):
1512
self.assertFormatterResult(log.LongLogFormatter, 'first', """\
1513
------------------------------------------------------------
1515
author: John Doe <jdoe@example.com>
1516
committer: Lorem Ipsum <test@example.com>
1518
timestamp: Tue 2005-11-22 00:00:00 +0000
1523
def test_long_all(self):
1524
self.assertFormatterResult(log.LongLogFormatter, 'all', """\
1525
------------------------------------------------------------
1527
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1528
committer: Lorem Ipsum <test@example.com>
1530
timestamp: Tue 2005-11-22 00:00:00 +0000
1535
def test_gnu_changelog_default(self):
1536
self.assertFormatterResult(log.GnuChangelogLogFormatter, None, """\
1537
2005-11-22 John Doe <jdoe@example.com>
1543
def test_gnu_changelog_committer(self):
1544
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', """\
1545
2005-11-22 Lorem Ipsum <test@example.com>
1551
def test_gnu_changelog_first(self):
1552
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', """\
1553
2005-11-22 John Doe <jdoe@example.com>
1559
def test_gnu_changelog_all(self):
1560
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'all', """\
1561
2005-11-22 John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1568
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1570
def make_branch_with_alternate_ancestries(self, relpath='.'):
1571
# See test_merge_sorted_exclude_ancestry below for the difference with
1572
# bt.per_branch.test_iter_merge_sorted_revision.
1573
# TestIterMergeSortedRevisionsBushyGraph.
1574
# make_branch_with_alternate_ancestries
1575
# and test_merge_sorted_exclude_ancestry
1576
# See the FIXME in assertLogRevnos too.
1577
builder = branchbuilder.BranchBuilder(self.get_transport(relpath))
1589
builder.start_series()
1590
builder.build_snapshot('1', None, [
1591
('add', ('', 'TREE_ROOT', 'directory', '')),])
1592
builder.build_snapshot('1.1.1', ['1'], [])
1593
builder.build_snapshot('2', ['1'], [])
1594
builder.build_snapshot('1.2.1', ['1.1.1'], [])
1595
builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1596
builder.build_snapshot('3', ['2', '1.1.2'], [])
1597
builder.finish_series()
1598
br = builder.get_branch()
1600
self.addCleanup(br.unlock)
1603
def assertLogRevnos(self, expected_revnos, b, start, end,
1604
exclude_common_ancestry, generate_merge_revisions=True):
1605
# FIXME: the layering in log makes it hard to test intermediate levels,
1606
# I wish adding filters with their parameters was easier...
1608
iter_revs = log._calc_view_revisions(
1609
b, start, end, direction='reverse',
1610
generate_merge_revisions=generate_merge_revisions,
1611
exclude_common_ancestry=exclude_common_ancestry)
1612
self.assertEqual(expected_revnos,
1613
[revid for revid, revno, depth in iter_revs])
1615
def test_merge_sorted_exclude_ancestry(self):
1616
b = self.make_branch_with_alternate_ancestries()
1617
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1618
b, '1', '3', exclude_common_ancestry=False)
1619
# '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1620
# it should be mentioned even if merge_sort order will make it appear
1622
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1623
b, '1.1.1', '3', exclude_common_ancestry=True)
1625
def test_merge_sorted_simple_revnos_exclude_ancestry(self):
1626
b = self.make_branch_with_alternate_ancestries()
1627
self.assertLogRevnos(['3', '2'],
1628
b, '1', '3', exclude_common_ancestry=True,
1629
generate_merge_revisions=False)
1630
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2'],
1631
b, '1', '3', exclude_common_ancestry=True,
1632
generate_merge_revisions=True)
1635
class TestLogDefaults(TestCaseForLogFormatter):
1636
def test_default_log_level(self):
1638
Test to ensure that specifying 'levels=1' to make_log_request_dict
1639
doesn't get overwritten when using a LogFormatter that supports more
1643
wt = self._prepare_tree_with_merges()
1646
class CustomLogFormatter(log.LogFormatter):
1647
def __init__(self, *args, **kwargs):
1648
super(CustomLogFormatter, self).__init__(*args, **kwargs)
1650
def get_levels(self):
1651
# log formatter supports all levels:
1653
def log_revision(self, revision):
1654
self.revisions.append(revision)
1656
log_formatter = LogCatcher()
1657
# First request we don't specify number of levels, we should get a
1658
# sensible default (whatever the LogFormatter handles - which in this
1659
# case is 0/everything):
1660
request = log.make_log_request_dict(limit=10)
1661
log.Logger(b, request).show(log_formatter)
1662
# should have all three revisions:
1663
self.assertEqual(len(log_formatter.revisions), 3)
1666
log_formatter = LogCatcher()
1667
# now explicitly request mainline revisions only:
1668
request = log.make_log_request_dict(limit=10, levels=1)
1669
log.Logger(b, request).show(log_formatter)
1670
# should now only have 2 revisions:
1671
self.assertEqual(len(log_formatter.revisions), 2)