419
wt.branch, log.ShortLogFormatter,
420
formatter_kwargs=dict(levels=0))
449
422
def test_short_merge_revs_log_single_merge_revision(self):
450
wt = self.make_branch_and_memory_tree('.')
452
self.addCleanup(wt.unlock)
454
wt.commit('rev-1', rev_id='rev-1',
455
timestamp=1132586655, timezone=36000,
456
committer='Joe Foo <joe@foo.com>')
457
wt.commit('rev-merged', rev_id='rev-2a',
458
timestamp=1132586700, timezone=36000,
459
committer='Joe Foo <joe@foo.com>')
460
wt.set_parent_ids(['rev-1', 'rev-2a'])
461
wt.branch.set_last_revision_info(1, 'rev-1')
462
wt.commit('rev-2', rev_id='rev-2b',
463
timestamp=1132586800, timezone=36000,
464
committer='Joe Foo <joe@foo.com>')
465
logfile = self.make_utf8_encoded_stringio()
466
formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
423
wt = self._prepare_tree_with_merges()
467
424
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
469
rev = revspec.in_history(wtb)
470
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
471
self.assertEqualDiff("""\
425
rev = revspec.in_history(wt.branch)
426
self.assertFormatterResult("""\
472
427
1.1.1 Joe Foo\t2005-11-22
479
class TestLongLogFormatter(TestCaseWithoutPropsHandler):
431
wt.branch, log.ShortLogFormatter,
432
formatter_kwargs=dict(levels=0),
433
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
436
class TestLongLogFormatter(TestCaseForLogFormatter):
481
438
def test_verbose_log(self):
482
439
"""Verbose log includes changed files
486
wt = self.make_branch_and_tree('.')
488
self.build_tree(['a'])
490
# XXX: why does a longer nick show up?
491
b.nick = 'test_verbose_log'
492
wt.commit(message='add a',
493
timestamp=1132711707,
495
committer='Lorem Ipsum <test@example.com>')
496
logfile = file('out.tmp', 'w+')
497
formatter = log.LongLogFormatter(to_file=logfile)
498
log.show_log(b, formatter, verbose=True)
501
log_contents = logfile.read()
502
self.assertEqualDiff('''\
443
wt = self.make_standard_commit('test_verbose_log', authors=[])
444
self.assertFormatterResult('''\
503
445
------------------------------------------------------------
505
447
committer: Lorem Ipsum <test@example.com>
506
448
branch nick: test_verbose_log
507
timestamp: Wed 2005-11-23 12:08:27 +1000
449
timestamp: Tue 2005-11-22 00:00:00 +0000
455
wt.branch, log.LongLogFormatter,
456
show_log_kwargs=dict(verbose=True))
515
458
def test_merges_are_indented_by_level(self):
516
459
wt = self.make_branch_and_tree('parent')
517
wt.commit('first post')
518
self.run_bzr('branch parent child')
519
self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
520
self.run_bzr('branch child smallerchild')
521
self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
524
self.run_bzr('merge ../smallerchild')
525
self.run_bzr(['commit', '-m', 'merge branch 2'])
526
os.chdir('../parent')
527
self.run_bzr('merge ../child')
528
wt.commit('merge branch 1')
530
sio = self.make_utf8_encoded_stringio()
531
lf = log.LongLogFormatter(to_file=sio, levels=0)
532
log.show_log(b, lf, verbose=True)
533
the_log = normalize_log(sio.getvalue())
534
self.assertEqualDiff("""\
460
self.wt_commit(wt, 'first post')
461
child_wt = wt.bzrdir.sprout('child').open_workingtree()
462
self.wt_commit(child_wt, 'branch 1')
463
smallerchild_wt = wt.bzrdir.sprout('smallerchild').open_workingtree()
464
self.wt_commit(smallerchild_wt, 'branch 2')
465
child_wt.merge_from_branch(smallerchild_wt.branch)
466
self.wt_commit(child_wt, 'merge branch 2')
467
wt.merge_from_branch(child_wt.branch)
468
self.wt_commit(wt, 'merge branch 1')
469
self.assertFormatterResult("""\
535
470
------------------------------------------------------------
537
committer: Lorem Ipsum <test@example.com>
472
committer: Joe Foo <joe@foo.com>
538
473
branch nick: parent
474
timestamp: Tue 2005-11-22 00:00:04 +0000
542
477
------------------------------------------------------------
543
478
revno: 1.1.2 [merge]
544
committer: Lorem Ipsum <test@example.com>
479
committer: Joe Foo <joe@foo.com>
545
480
branch nick: child
481
timestamp: Tue 2005-11-22 00:00:03 +0000
549
484
------------------------------------------------------------
551
committer: Lorem Ipsum <test@example.com>
486
committer: Joe Foo <joe@foo.com>
552
487
branch nick: smallerchild
488
timestamp: Tue 2005-11-22 00:00:02 +0000
556
491
------------------------------------------------------------
558
committer: Lorem Ipsum <test@example.com>
493
committer: Joe Foo <joe@foo.com>
559
494
branch nick: child
495
timestamp: Tue 2005-11-22 00:00:01 +0000
563
498
------------------------------------------------------------
565
committer: Lorem Ipsum <test@example.com>
500
committer: Joe Foo <joe@foo.com>
566
501
branch nick: parent
502
timestamp: Tue 2005-11-22 00:00:00 +0000
506
wt.branch, log.LongLogFormatter,
507
formatter_kwargs=dict(levels=0),
508
show_log_kwargs=dict(verbose=True))
573
510
def test_verbose_merge_revisions_contain_deltas(self):
574
511
wt = self.make_branch_and_tree('parent')
575
512
self.build_tree(['parent/f1', 'parent/f2'])
576
513
wt.add(['f1','f2'])
577
wt.commit('first post')
578
self.run_bzr('branch parent child')
514
self.wt_commit(wt, 'first post')
515
child_wt = wt.bzrdir.sprout('child').open_workingtree()
579
516
os.unlink('child/f1')
580
file('child/f2', 'wb').write('hello\n')
581
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
584
self.run_bzr('merge ../child')
585
wt.commit('merge branch 1')
587
sio = self.make_utf8_encoded_stringio()
588
lf = log.LongLogFormatter(to_file=sio, levels=0)
589
log.show_log(b, lf, verbose=True)
590
the_log = normalize_log(sio.getvalue())
591
self.assertEqualDiff("""\
517
self.build_tree_contents([('child/f2', 'hello\n')])
518
self.wt_commit(child_wt, 'removed f1 and modified f2')
519
wt.merge_from_branch(child_wt.branch)
520
self.wt_commit(wt, 'merge branch 1')
521
self.assertFormatterResult("""\
592
522
------------------------------------------------------------
594
committer: Lorem Ipsum <test@example.com>
524
committer: Joe Foo <joe@foo.com>
595
525
branch nick: parent
526
timestamp: Tue 2005-11-22 00:00:02 +0000
653
581
committer: Joe Foo <joe@foo.com>
654
582
branch nick: test
655
timestamp: Mon 2005-11-21 09:24:15 -0600
583
timestamp: Tue 2005-11-22 00:00:00 +0000
657
585
simple log message
587
b, log.LongLogFormatter)
661
589
def test_author_in_log(self):
662
590
"""Log includes the author name if it's set in
663
591
the revision properties
665
wt = self.make_branch_and_tree('.')
667
self.build_tree(['a'])
669
b.nick = 'test_author_log'
670
wt.commit(message='add a',
671
timestamp=1132711707,
673
committer='Lorem Ipsum <test@example.com>',
674
authors=['John Doe <jdoe@example.com>',
675
'Jane Rey <jrey@example.com>'])
677
formatter = log.LongLogFormatter(to_file=sio)
678
log.show_log(b, formatter)
679
self.assertEqualDiff('''\
593
wt = self.make_standard_commit('test_author_log',
594
authors=['John Doe <jdoe@example.com>',
595
'Jane Rey <jrey@example.com>'])
596
self.assertFormatterResult("""\
680
597
------------------------------------------------------------
682
599
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
683
600
committer: Lorem Ipsum <test@example.com>
684
601
branch nick: test_author_log
685
timestamp: Wed 2005-11-23 12:08:27 +1000
602
timestamp: Tue 2005-11-22 00:00:00 +0000
606
wt.branch, log.LongLogFormatter)
691
608
def test_properties_in_log(self):
692
609
"""Log includes the custom properties returned by the registered
695
wt = self.make_branch_and_tree('.')
697
self.build_tree(['a'])
699
b.nick = 'test_properties_in_log'
700
wt.commit(message='add a',
701
timestamp=1132711707,
703
committer='Lorem Ipsum <test@example.com>',
704
authors=['John Doe <jdoe@example.com>'])
706
formatter = log.LongLogFormatter(to_file=sio)
708
def trivial_custom_prop_handler(revision):
709
return {'test_prop':'test_value'}
612
wt = self.make_standard_commit('test_properties_in_log')
613
def trivial_custom_prop_handler(revision):
614
return {'test_prop':'test_value'}
711
log.properties_handler_registry.register(
712
'trivial_custom_prop_handler',
713
trivial_custom_prop_handler)
714
log.show_log(b, formatter)
716
log.properties_handler_registry.remove(
717
'trivial_custom_prop_handler')
718
self.assertEqualDiff('''\
616
# Cleaned up in setUp()
617
log.properties_handler_registry.register(
618
'trivial_custom_prop_handler',
619
trivial_custom_prop_handler)
620
self.assertFormatterResult("""\
719
621
------------------------------------------------------------
721
623
test_prop: test_value
722
624
author: John Doe <jdoe@example.com>
723
625
committer: Lorem Ipsum <test@example.com>
724
626
branch nick: test_properties_in_log
725
timestamp: Wed 2005-11-23 12:08:27 +1000
627
timestamp: Tue 2005-11-22 00:00:00 +0000
631
wt.branch, log.LongLogFormatter)
731
633
def test_properties_in_short_log(self):
732
634
"""Log includes the custom properties returned by the registered
735
wt = self.make_branch_and_tree('.')
737
self.build_tree(['a'])
739
b.nick = 'test_properties_in_short_log'
740
wt.commit(message='add a',
741
timestamp=1132711707,
743
committer='Lorem Ipsum <test@example.com>',
744
authors=['John Doe <jdoe@example.com>'])
746
formatter = log.ShortLogFormatter(to_file=sio)
748
def trivial_custom_prop_handler(revision):
749
return {'test_prop':'test_value'}
637
wt = self.make_standard_commit('test_properties_in_short_log')
638
def trivial_custom_prop_handler(revision):
639
return {'test_prop':'test_value'}
751
log.properties_handler_registry.register(
752
'trivial_custom_prop_handler',
753
trivial_custom_prop_handler)
754
log.show_log(b, formatter)
756
log.properties_handler_registry.remove(
757
'trivial_custom_prop_handler')
758
self.assertEqualDiff('''\
759
1 John Doe\t2005-11-23
641
log.properties_handler_registry.register(
642
'trivial_custom_prop_handler',
643
trivial_custom_prop_handler)
644
self.assertFormatterResult("""\
645
1 John Doe\t2005-11-22
760
646
test_prop: test_value
650
wt.branch, log.ShortLogFormatter)
766
652
def test_error_in_properties_handler(self):
767
653
"""Log includes the custom properties returned by the registered
770
wt = self.make_branch_and_tree('.')
772
self.build_tree(['a'])
774
b.nick = 'test_author_log'
775
wt.commit(message='add a',
776
timestamp=1132711707,
778
committer='Lorem Ipsum <test@example.com>',
779
authors=['John Doe <jdoe@example.com>'],
780
revprops={'first_prop':'first_value'})
656
wt = self.make_standard_commit('error_in_properties_handler',
657
revprops={'first_prop':'first_value'})
658
sio = self.make_utf8_encoded_stringio()
782
659
formatter = log.LongLogFormatter(to_file=sio)
784
def trivial_custom_prop_handler(revision):
785
raise StandardError("a test error")
660
def trivial_custom_prop_handler(revision):
661
raise StandardError("a test error")
787
log.properties_handler_registry.register(
788
'trivial_custom_prop_handler',
789
trivial_custom_prop_handler)
790
self.assertRaises(StandardError, log.show_log, b, formatter,)
792
log.properties_handler_registry.remove(
793
'trivial_custom_prop_handler')
663
log.properties_handler_registry.register(
664
'trivial_custom_prop_handler',
665
trivial_custom_prop_handler)
666
self.assertRaises(StandardError, log.show_log, wt.branch, formatter,)
795
668
def test_properties_handler_bad_argument(self):
796
wt = self.make_branch_and_tree('.')
798
self.build_tree(['a'])
800
b.nick = 'test_author_log'
801
wt.commit(message='add a',
802
timestamp=1132711707,
804
committer='Lorem Ipsum <test@example.com>',
805
authors=['John Doe <jdoe@example.com>'],
806
revprops={'a_prop':'test_value'})
669
wt = self.make_standard_commit('bad_argument',
670
revprops={'a_prop':'test_value'})
671
sio = self.make_utf8_encoded_stringio()
808
672
formatter = log.LongLogFormatter(to_file=sio)
810
def bad_argument_prop_handler(revision):
811
return {'custom_prop_name':revision.properties['a_prop']}
813
log.properties_handler_registry.register(
814
'bad_argument_prop_handler',
815
bad_argument_prop_handler)
817
self.assertRaises(AttributeError, formatter.show_properties,
820
revision = b.repository.get_revision(b.last_revision())
821
formatter.show_properties(revision, '')
822
self.assertEqualDiff('''custom_prop_name: test_value\n''',
825
log.properties_handler_registry.remove(
826
'bad_argument_prop_handler')
829
class TestLongLogFormatterWithoutMergeRevisions(TestCaseWithoutPropsHandler):
673
def bad_argument_prop_handler(revision):
674
return {'custom_prop_name':revision.properties['a_prop']}
676
log.properties_handler_registry.register(
677
'bad_argument_prop_handler',
678
bad_argument_prop_handler)
680
self.assertRaises(AttributeError, formatter.show_properties,
683
revision = wt.branch.repository.get_revision(wt.branch.last_revision())
684
formatter.show_properties(revision, '')
685
self.assertEqualDiff('''custom_prop_name: test_value\n''',
688
def test_show_ids(self):
689
wt = self.make_branch_and_tree('parent')
690
self.build_tree(['parent/f1', 'parent/f2'])
692
self.wt_commit(wt, 'first post', rev_id='a')
693
child_wt = wt.bzrdir.sprout('child').open_workingtree()
694
self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
695
wt.merge_from_branch(child_wt.branch)
696
self.wt_commit(wt, 'merge branch 1', rev_id='c')
697
self.assertFormatterResult("""\
698
------------------------------------------------------------
703
committer: Joe Foo <joe@foo.com>
705
timestamp: Tue 2005-11-22 00:00:02 +0000
708
------------------------------------------------------------
712
committer: Joe Foo <joe@foo.com>
714
timestamp: Tue 2005-11-22 00:00:01 +0000
717
------------------------------------------------------------
720
committer: Joe Foo <joe@foo.com>
722
timestamp: Tue 2005-11-22 00:00:00 +0000
726
wt.branch, log.LongLogFormatter,
727
formatter_kwargs=dict(levels=0,show_ids=True))
730
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
831
732
def test_long_verbose_log(self):
832
733
"""Verbose log includes changed files
836
wt = self.make_branch_and_tree('.')
838
self.build_tree(['a'])
840
# XXX: why does a longer nick show up?
841
b.nick = 'test_verbose_log'
842
wt.commit(message='add a',
843
timestamp=1132711707,
845
committer='Lorem Ipsum <test@example.com>')
846
logfile = file('out.tmp', 'w+')
847
formatter = log.LongLogFormatter(to_file=logfile, levels=1)
848
log.show_log(b, formatter, verbose=True)
851
log_contents = logfile.read()
852
self.assertEqualDiff('''\
737
wt = self.make_standard_commit('test_long_verbose_log', authors=[])
738
self.assertFormatterResult("""\
853
739
------------------------------------------------------------
855
741
committer: Lorem Ipsum <test@example.com>
856
branch nick: test_verbose_log
857
timestamp: Wed 2005-11-23 12:08:27 +1000
742
branch nick: test_long_verbose_log
743
timestamp: Tue 2005-11-22 00:00:00 +0000
749
wt.branch, log.LongLogFormatter,
750
formatter_kwargs=dict(levels=1),
751
show_log_kwargs=dict(verbose=True))
865
753
def test_long_verbose_contain_deltas(self):
866
754
wt = self.make_branch_and_tree('parent')
867
755
self.build_tree(['parent/f1', 'parent/f2'])
868
756
wt.add(['f1','f2'])
869
wt.commit('first post')
870
self.run_bzr('branch parent child')
757
self.wt_commit(wt, 'first post')
758
child_wt = wt.bzrdir.sprout('child').open_workingtree()
871
759
os.unlink('child/f1')
872
file('child/f2', 'wb').write('hello\n')
873
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
876
self.run_bzr('merge ../child')
877
wt.commit('merge branch 1')
879
sio = self.make_utf8_encoded_stringio()
880
lf = log.LongLogFormatter(to_file=sio, levels=1)
881
log.show_log(b, lf, verbose=True)
882
the_log = normalize_log(sio.getvalue())
883
self.assertEqualDiff("""\
760
self.build_tree_contents([('child/f2', 'hello\n')])
761
self.wt_commit(child_wt, 'removed f1 and modified f2')
762
wt.merge_from_branch(child_wt.branch)
763
self.wt_commit(wt, 'merge branch 1')
764
self.assertFormatterResult("""\
884
765
------------------------------------------------------------
886
committer: Lorem Ipsum <test@example.com>
767
committer: Joe Foo <joe@foo.com>
887
768
branch nick: parent
769
timestamp: Tue 2005-11-22 00:00:02 +0000
934
813
committer: Joe Foo <joe@foo.com>
935
814
branch nick: test
936
timestamp: Mon 2005-11-21 09:24:15 -0600
815
timestamp: Tue 2005-11-22 00:00:00 +0000
938
817
simple log message
819
b, log.LongLogFormatter,
820
formatter_kwargs=dict(levels=1))
942
822
def test_long_author_in_log(self):
943
823
"""Log includes the author name if it's set in
944
824
the revision properties
946
wt = self.make_branch_and_tree('.')
948
self.build_tree(['a'])
950
b.nick = 'test_author_log'
951
wt.commit(message='add a',
952
timestamp=1132711707,
954
committer='Lorem Ipsum <test@example.com>',
955
authors=['John Doe <jdoe@example.com>'])
957
formatter = log.LongLogFormatter(to_file=sio, levels=1)
958
log.show_log(b, formatter)
959
self.assertEqualDiff('''\
826
wt = self.make_standard_commit('test_author_log')
827
self.assertFormatterResult("""\
960
828
------------------------------------------------------------
962
830
author: John Doe <jdoe@example.com>
963
831
committer: Lorem Ipsum <test@example.com>
964
832
branch nick: test_author_log
965
timestamp: Wed 2005-11-23 12:08:27 +1000
833
timestamp: Tue 2005-11-22 00:00:00 +0000
837
wt.branch, log.LongLogFormatter,
838
formatter_kwargs=dict(levels=1))
971
840
def test_long_properties_in_log(self):
972
841
"""Log includes the custom properties returned by the registered
975
wt = self.make_branch_and_tree('.')
977
self.build_tree(['a'])
979
b.nick = 'test_properties_in_log'
980
wt.commit(message='add a',
981
timestamp=1132711707,
983
committer='Lorem Ipsum <test@example.com>',
984
authors=['John Doe <jdoe@example.com>'])
986
formatter = log.LongLogFormatter(to_file=sio, levels=1)
988
def trivial_custom_prop_handler(revision):
989
return {'test_prop':'test_value'}
844
wt = self.make_standard_commit('test_properties_in_log')
845
def trivial_custom_prop_handler(revision):
846
return {'test_prop':'test_value'}
991
log.properties_handler_registry.register(
992
'trivial_custom_prop_handler',
993
trivial_custom_prop_handler)
994
log.show_log(b, formatter)
996
log.properties_handler_registry.remove(
997
'trivial_custom_prop_handler')
998
self.assertEqualDiff('''\
848
log.properties_handler_registry.register(
849
'trivial_custom_prop_handler',
850
trivial_custom_prop_handler)
851
self.assertFormatterResult("""\
999
852
------------------------------------------------------------
1001
854
test_prop: test_value
1002
855
author: John Doe <jdoe@example.com>
1003
856
committer: Lorem Ipsum <test@example.com>
1004
857
branch nick: test_properties_in_log
1005
timestamp: Wed 2005-11-23 12:08:27 +1000
858
timestamp: Tue 2005-11-22 00:00:00 +0000
1012
class TestLineLogFormatter(tests.TestCaseWithTransport):
862
wt.branch, log.LongLogFormatter,
863
formatter_kwargs=dict(levels=1))
866
class TestLineLogFormatter(TestCaseForLogFormatter):
1014
868
def test_line_log(self):
1015
869
"""Line log should show revno
1019
wt = self.make_branch_and_tree('.')
1021
self.build_tree(['a'])
1023
b.nick = 'test-line-log'
1024
wt.commit(message='add a',
1025
timestamp=1132711707,
1027
committer='Line-Log-Formatter Tester <test@line.log>')
1028
logfile = file('out.tmp', 'w+')
1029
formatter = log.LineLogFormatter(to_file=logfile)
1030
log.show_log(b, formatter)
1033
log_contents = logfile.read()
1034
self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
873
wt = self.make_standard_commit('test-line-log',
874
committer='Line-Log-Formatter Tester <test@line.log>',
876
self.assertFormatterResult("""\
877
1: Line-Log-Formatte... 2005-11-22 add a
879
wt.branch, log.LineLogFormatter)
1037
881
def test_trailing_newlines(self):
1038
882
wt = self.make_branch_and_tree('.')
1039
b = make_commits_with_trailing_newlines(wt)
1040
sio = self.make_utf8_encoded_stringio()
1041
lf = log.LineLogFormatter(to_file=sio)
1043
self.assertEqualDiff("""\
1044
3: Joe Foo 2005-11-21 single line with trailing newline
1045
2: Joe Bar 2005-11-21 multiline
1046
1: Joe Foo 2005-11-21 simple log message
883
b = self.make_commits_with_trailing_newlines(wt)
884
self.assertFormatterResult("""\
885
3: Joe Foo 2005-11-22 single line with trailing newline
886
2: Joe Foo 2005-11-22 multiline
887
1: Joe Foo 2005-11-22 simple log message
1050
def _prepare_tree_with_merges(self, with_tags=False):
1051
wt = self.make_branch_and_memory_tree('.')
1053
self.addCleanup(wt.unlock)
1055
wt.commit('rev-1', rev_id='rev-1',
1056
timestamp=1132586655, timezone=36000,
1057
committer='Joe Foo <joe@foo.com>')
1058
wt.commit('rev-merged', rev_id='rev-2a',
1059
timestamp=1132586700, timezone=36000,
1060
committer='Joe Foo <joe@foo.com>')
1061
wt.set_parent_ids(['rev-1', 'rev-2a'])
1062
wt.branch.set_last_revision_info(1, 'rev-1')
1063
wt.commit('rev-2', rev_id='rev-2b',
1064
timestamp=1132586800, timezone=36000,
1065
committer='Joe Foo <joe@foo.com>')
1068
branch.tags.set_tag('v0.2', 'rev-2b')
1069
wt.commit('rev-3', rev_id='rev-3',
1070
timestamp=1132586900, timezone=36000,
1071
committer='Jane Foo <jane@foo.com>')
1072
branch.tags.set_tag('v1.0rc1', 'rev-3')
1073
branch.tags.set_tag('v1.0', 'rev-3')
889
b, log.LineLogFormatter)
1076
891
def test_line_log_single_merge_revision(self):
1077
892
wt = self._prepare_tree_with_merges()
1078
logfile = self.make_utf8_encoded_stringio()
1079
formatter = log.LineLogFormatter(to_file=logfile)
1080
893
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1082
rev = revspec.in_history(wtb)
1083
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1084
self.assertEqualDiff("""\
894
rev = revspec.in_history(wt.branch)
895
self.assertFormatterResult("""\
1085
896
1.1.1: Joe Foo 2005-11-22 rev-merged
898
wt.branch, log.LineLogFormatter,
899
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1089
901
def test_line_log_with_tags(self):
1090
902
wt = self._prepare_tree_with_merges(with_tags=True)
1091
logfile = self.make_utf8_encoded_stringio()
1092
formatter = log.LineLogFormatter(to_file=logfile)
1093
log.show_log(wt.branch, formatter)
1094
self.assertEqualDiff("""\
1095
3: Jane Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
903
self.assertFormatterResult("""\
904
3: Joe Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
1096
905
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
1097
906
1: Joe Foo 2005-11-22 rev-1
1101
class TestLineLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
908
wt.branch, log.LineLogFormatter)
911
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
1103
913
def test_line_merge_revs_log(self):
1104
914
"""Line log should show revno
1108
wt = self.make_branch_and_tree('.')
1110
self.build_tree(['a'])
1112
b.nick = 'test-line-log'
1113
wt.commit(message='add a',
1114
timestamp=1132711707,
1116
committer='Line-Log-Formatter Tester <test@line.log>')
1117
logfile = file('out.tmp', 'w+')
1118
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1119
log.show_log(b, formatter)
1122
log_contents = logfile.read()
1123
self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
918
wt = self.make_standard_commit('test-line-log',
919
committer='Line-Log-Formatter Tester <test@line.log>',
921
self.assertFormatterResult("""\
922
1: Line-Log-Formatte... 2005-11-22 add a
924
wt.branch, log.LineLogFormatter)
1126
926
def test_line_merge_revs_log_single_merge_revision(self):
1127
wt = self.make_branch_and_memory_tree('.')
1129
self.addCleanup(wt.unlock)
1131
wt.commit('rev-1', rev_id='rev-1',
1132
timestamp=1132586655, timezone=36000,
1133
committer='Joe Foo <joe@foo.com>')
1134
wt.commit('rev-merged', rev_id='rev-2a',
1135
timestamp=1132586700, timezone=36000,
1136
committer='Joe Foo <joe@foo.com>')
1137
wt.set_parent_ids(['rev-1', 'rev-2a'])
1138
wt.branch.set_last_revision_info(1, 'rev-1')
1139
wt.commit('rev-2', rev_id='rev-2b',
1140
timestamp=1132586800, timezone=36000,
1141
committer='Joe Foo <joe@foo.com>')
1142
logfile = self.make_utf8_encoded_stringio()
1143
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
927
wt = self._prepare_tree_with_merges()
1144
928
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1146
rev = revspec.in_history(wtb)
1147
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1148
self.assertEqualDiff("""\
929
rev = revspec.in_history(wt.branch)
930
self.assertFormatterResult("""\
1149
931
1.1.1: Joe Foo 2005-11-22 rev-merged
933
wt.branch, log.LineLogFormatter,
934
formatter_kwargs=dict(levels=0),
935
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1153
937
def test_line_merge_revs_log_with_merges(self):
1154
wt = self.make_branch_and_memory_tree('.')
1156
self.addCleanup(wt.unlock)
1158
wt.commit('rev-1', rev_id='rev-1',
1159
timestamp=1132586655, timezone=36000,
1160
committer='Joe Foo <joe@foo.com>')
1161
wt.commit('rev-merged', rev_id='rev-2a',
1162
timestamp=1132586700, timezone=36000,
1163
committer='Joe Foo <joe@foo.com>')
1164
wt.set_parent_ids(['rev-1', 'rev-2a'])
1165
wt.branch.set_last_revision_info(1, 'rev-1')
1166
wt.commit('rev-2', rev_id='rev-2b',
1167
timestamp=1132586800, timezone=36000,
1168
committer='Joe Foo <joe@foo.com>')
1169
logfile = self.make_utf8_encoded_stringio()
1170
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1171
log.show_log(wt.branch, formatter)
1172
self.assertEqualDiff("""\
938
wt = self._prepare_tree_with_merges()
939
self.assertFormatterResult("""\
1173
940
2: Joe Foo 2005-11-22 [merge] rev-2
1174
941
1.1.1: Joe Foo 2005-11-22 rev-merged
1175
942
1: Joe Foo 2005-11-22 rev-1
1179
class TestGetViewRevisions(tests.TestCaseWithTransport):
1181
def make_tree_with_commits(self):
1182
"""Create a tree with well-known revision ids"""
1183
wt = self.make_branch_and_tree('tree1')
1184
wt.commit('commit one', rev_id='1')
1185
wt.commit('commit two', rev_id='2')
1186
wt.commit('commit three', rev_id='3')
1187
mainline_revs = [None, '1', '2', '3']
1188
rev_nos = {'1': 1, '2': 2, '3': 3}
1189
return mainline_revs, rev_nos, wt
1191
def make_tree_with_merges(self):
1192
"""Create a tree with well-known revision ids and a merge"""
1193
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1194
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1195
tree2.commit('four-a', rev_id='4a')
1196
wt.merge_from_branch(tree2.branch)
1197
wt.commit('four-b', rev_id='4b')
1198
mainline_revs.append('4b')
1201
return mainline_revs, rev_nos, wt
1203
def make_branch_with_many_merges(self):
1204
"""Create a tree with well-known revision ids"""
1205
builder = self.make_branch_builder('tree1')
1206
builder.start_series()
1207
builder.build_snapshot('1', None, [
1208
('add', ('', 'TREE_ROOT', 'directory', '')),
1209
('add', ('f', 'f-id', 'file', '1\n'))])
1210
builder.build_snapshot('2', ['1'], [])
1211
builder.build_snapshot('3a', ['2'], [
1212
('modify', ('f-id', '1\n2\n3a\n'))])
1213
builder.build_snapshot('3b', ['2', '3a'], [
1214
('modify', ('f-id', '1\n2\n3a\n'))])
1215
builder.build_snapshot('3c', ['2', '3b'], [
1216
('modify', ('f-id', '1\n2\n3a\n'))])
1217
builder.build_snapshot('4a', ['3b'], [])
1218
builder.build_snapshot('4b', ['3c', '4a'], [])
1219
builder.finish_series()
1233
mainline_revs = [None, '1', '2', '3c', '4b']
1234
rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
1235
full_rev_nos_for_reference = {
1238
'3a': '2.1.1', #first commit tree 3
1239
'3b': '2.2.1', # first commit tree 2
1240
'3c': '3', #merges 3b to main
1241
'4a': '2.2.2', # second commit tree 2
1242
'4b': '4', # merges 4a to main
1244
return mainline_revs, rev_nos, builder.get_branch()
1246
def test_get_view_revisions_forward(self):
1247
"""Test the get_view_revisions method"""
1248
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1250
self.addCleanup(wt.unlock)
1251
revisions = list(log.get_view_revisions(
1252
mainline_revs, rev_nos, wt.branch, 'forward'))
1253
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
1255
revisions2 = list(log.get_view_revisions(
1256
mainline_revs, rev_nos, wt.branch, 'forward',
1257
include_merges=False))
1258
self.assertEqual(revisions, revisions2)
1260
def test_get_view_revisions_reverse(self):
1261
"""Test the get_view_revisions with reverse"""
1262
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1264
self.addCleanup(wt.unlock)
1265
revisions = list(log.get_view_revisions(
1266
mainline_revs, rev_nos, wt.branch, 'reverse'))
1267
self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
1269
revisions2 = list(log.get_view_revisions(
1270
mainline_revs, rev_nos, wt.branch, 'reverse',
1271
include_merges=False))
1272
self.assertEqual(revisions, revisions2)
1274
def test_get_view_revisions_merge(self):
1275
"""Test get_view_revisions when there are merges"""
1276
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1278
self.addCleanup(wt.unlock)
1279
revisions = list(log.get_view_revisions(
1280
mainline_revs, rev_nos, wt.branch, 'forward'))
1281
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1282
('4b', '4', 0), ('4a', '3.1.1', 1)],
1284
revisions = list(log.get_view_revisions(
1285
mainline_revs, rev_nos, wt.branch, 'forward',
1286
include_merges=False))
1287
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1291
def test_get_view_revisions_merge_reverse(self):
1292
"""Test get_view_revisions in reverse when there are merges"""
1293
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1295
self.addCleanup(wt.unlock)
1296
revisions = list(log.get_view_revisions(
1297
mainline_revs, rev_nos, wt.branch, 'reverse'))
1298
self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
1299
('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
1301
revisions = list(log.get_view_revisions(
1302
mainline_revs, rev_nos, wt.branch, 'reverse',
1303
include_merges=False))
1304
self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
1308
def test_get_view_revisions_merge2(self):
1309
"""Test get_view_revisions when there are merges"""
1310
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1312
self.addCleanup(b.unlock)
1313
revisions = list(log.get_view_revisions(
1314
mainline_revs, rev_nos, b, 'forward'))
1315
expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1316
('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1318
self.assertEqual(expected, revisions)
1319
revisions = list(log.get_view_revisions(
1320
mainline_revs, rev_nos, b, 'forward',
1321
include_merges=False))
1322
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1327
def test_file_id_for_range(self):
1328
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1330
self.addCleanup(b.unlock)
1332
def rev_from_rev_id(revid, branch):
1333
revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1334
return revspec.in_history(branch)
1336
def view_revs(start_rev, end_rev, file_id, direction):
1337
revs = log.calculate_view_revisions(
1339
start_rev, # start_revision
1340
end_rev, # end_revision
1341
direction, # direction
1342
file_id, # specific_fileid
1343
True, # generate_merge_revisions
1347
rev_3a = rev_from_rev_id('3a', b)
1348
rev_4b = rev_from_rev_id('4b', b)
1349
self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1), ('3a', '2.1.1', 2)],
1350
view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
1351
# Note: 3c still appears before 3a here because of depth-based sorting
1352
self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1), ('3a', '2.1.1', 2)],
1353
view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1356
class TestGetRevisionsTouchingFileID(tests.TestCaseWithTransport):
1358
def create_tree_with_single_merge(self):
1359
"""Create a branch with a moderate layout.
1361
The revision graph looks like:
1369
In this graph, A introduced files f1 and f2 and f3.
1370
B modifies f1 and f3, and C modifies f2 and f3.
1371
D merges the changes from B and C and resolves the conflict for f3.
1373
# TODO: jam 20070218 This seems like it could really be done
1374
# with make_branch_and_memory_tree() if we could just
1375
# create the content of those files.
1376
# TODO: jam 20070218 Another alternative is that we would really
1377
# like to only create this tree 1 time for all tests that
1378
# use it. Since 'log' only uses the tree in a readonly
1379
# fashion, it seems a shame to regenerate an identical
1380
# tree for each test.
1381
tree = self.make_branch_and_tree('tree')
1383
self.addCleanup(tree.unlock)
1385
self.build_tree_contents([('tree/f1', 'A\n'),
1389
tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
1390
tree.commit('A', rev_id='A')
1392
self.build_tree_contents([('tree/f2', 'A\nC\n'),
1393
('tree/f3', 'A\nC\n'),
1395
tree.commit('C', rev_id='C')
1396
# Revert back to A to build the other history.
1397
tree.set_last_revision('A')
1398
tree.branch.set_last_revision_info(1, 'A')
1399
self.build_tree_contents([('tree/f1', 'A\nB\n'),
1401
('tree/f3', 'A\nB\n'),
1403
tree.commit('B', rev_id='B')
1404
tree.set_parent_ids(['B', 'C'])
1405
self.build_tree_contents([('tree/f1', 'A\nB\n'),
1406
('tree/f2', 'A\nC\n'),
1407
('tree/f3', 'A\nB\nC\n'),
1409
tree.commit('D', rev_id='D')
1411
# Switch to a read lock for this tree.
1412
# We still have an addCleanup(tree.unlock) pending
1417
def check_delta(self, delta, **kw):
1418
"""Check the filenames touched by a delta are as expected.
1420
Caller only have to pass in the list of files for each part, all
1421
unspecified parts are considered empty (and checked as such).
1423
for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
1424
# By default we expect an empty list
1425
expected = kw.get(n, [])
1426
# strip out only the path components
1427
got = [x[0] for x in getattr(delta, n)]
1428
self.assertEqual(expected, got)
1430
def test_tree_with_single_merge(self):
1431
"""Make sure the tree layout is correct."""
1432
tree = self.create_tree_with_single_merge()
1433
rev_A_tree = tree.branch.repository.revision_tree('A')
1434
rev_B_tree = tree.branch.repository.revision_tree('B')
1435
rev_C_tree = tree.branch.repository.revision_tree('C')
1436
rev_D_tree = tree.branch.repository.revision_tree('D')
1438
self.check_delta(rev_B_tree.changes_from(rev_A_tree),
1439
modified=['f1', 'f3'])
1441
self.check_delta(rev_C_tree.changes_from(rev_A_tree),
1442
modified=['f2', 'f3'])
1444
self.check_delta(rev_D_tree.changes_from(rev_B_tree),
1445
modified=['f2', 'f3'])
1447
self.check_delta(rev_D_tree.changes_from(rev_C_tree),
1448
modified=['f1', 'f3'])
1450
def assertAllRevisionsForFileID(self, tree, file_id, revisions):
1451
"""Ensure _filter_revisions_touching_file_id returns the right values.
1453
Get the return value from _filter_revisions_touching_file_id and make
1454
sure they are correct.
1456
# The api for _filter_revisions_touching_file_id is a little crazy.
1457
# So we do the setup here.
1458
mainline = tree.branch.revision_history()
1459
mainline.insert(0, None)
1460
revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
1461
view_revs_iter = log.get_view_revisions(mainline, revnos, tree.branch,
1463
actual_revs = log._filter_revisions_touching_file_id(
1466
list(view_revs_iter))
1467
self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
1469
def test_file_id_f1(self):
1470
tree = self.create_tree_with_single_merge()
1471
# f1 should be marked as modified by revisions A and B
1472
self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
1474
def test_file_id_f2(self):
1475
tree = self.create_tree_with_single_merge()
1476
# f2 should be marked as modified by revisions A, C, and D
1477
# because D merged the changes from C.
1478
self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1480
def test_file_id_f3(self):
1481
tree = self.create_tree_with_single_merge()
1482
# f3 should be marked as modified by revisions A, B, C, and D
1483
self.assertAllRevisionsForFileID(tree, 'f3-id', ['D', 'C', 'B', 'A'])
1485
def test_file_id_with_ghosts(self):
1486
# This is testing bug #209948, where having a ghost would cause
1487
# _filter_revisions_touching_file_id() to fail.
1488
tree = self.create_tree_with_single_merge()
1489
# We need to add a revision, so switch back to a write-locked tree
1490
# (still a single addCleanup(tree.unlock) pending).
1493
first_parent = tree.last_revision()
1494
tree.set_parent_ids([first_parent, 'ghost-revision-id'])
1495
self.build_tree_contents([('tree/f1', 'A\nB\nXX\n')])
1496
tree.commit('commit with a ghost', rev_id='XX')
1497
self.assertAllRevisionsForFileID(tree, 'f1-id', ['XX', 'B', 'A'])
1498
self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1500
def test_unknown_file_id(self):
1501
tree = self.create_tree_with_single_merge()
1502
self.assertAllRevisionsForFileID(tree, 'unknown', [])
1504
def test_empty_branch_unknown_file_id(self):
1505
tree = self.make_branch_and_tree('tree')
1506
self.assertAllRevisionsForFileID(tree, 'unknown', [])
944
wt.branch, log.LineLogFormatter,
945
formatter_kwargs=dict(levels=0))
948
class TestGnuChangelogFormatter(TestCaseForLogFormatter):
950
def test_gnu_changelog(self):
951
wt = self.make_standard_commit('nicky', authors=[])
952
self.assertFormatterResult('''\
953
2005-11-22 Lorem Ipsum <test@example.com>
958
wt.branch, log.GnuChangelogLogFormatter)
960
def test_with_authors(self):
961
wt = self.make_standard_commit('nicky',
962
authors=['Fooa Fooz <foo@example.com>',
963
'Bari Baro <bar@example.com>'])
964
self.assertFormatterResult('''\
965
2005-11-22 Fooa Fooz <foo@example.com>
970
wt.branch, log.GnuChangelogLogFormatter)
972
def test_verbose(self):
973
wt = self.make_standard_commit('nicky')
974
self.assertFormatterResult('''\
975
2005-11-22 John Doe <jdoe@example.com>
982
wt.branch, log.GnuChangelogLogFormatter,
983
show_log_kwargs=dict(verbose=True))
1509
986
class TestShowChangedRevisions(tests.TestCaseWithTransport):
1707
1185
log.show_branch_change(tree.branch, s, 3, '3b')
1708
1186
self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1709
1187
self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1190
class TestRevisionNotInBranch(TestCaseForLogFormatter):
1192
def setup_a_tree(self):
1193
tree = self.make_branch_and_tree('tree')
1195
self.addCleanup(tree.unlock)
1197
'committer': 'Joe Foo <joe@foo.com>',
1198
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1199
'timezone': 0, # UTC
1201
tree.commit('commit 1a', rev_id='1a', **kwargs)
1202
tree.commit('commit 2a', rev_id='2a', **kwargs)
1203
tree.commit('commit 3a', rev_id='3a', **kwargs)
1206
def setup_ab_tree(self):
1207
tree = self.setup_a_tree()
1208
tree.set_last_revision('1a')
1209
tree.branch.set_last_revision_info(1, '1a')
1211
'committer': 'Joe Foo <joe@foo.com>',
1212
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1213
'timezone': 0, # UTC
1215
tree.commit('commit 2b', rev_id='2b', **kwargs)
1216
tree.commit('commit 3b', rev_id='3b', **kwargs)
1219
def test_one_revision(self):
1220
tree = self.setup_ab_tree()
1222
rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1223
log.show_log(tree.branch, lf, verbose=True, start_revision=rev,
1225
self.assertEqual(1, len(lf.revisions))
1226
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1227
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1229
def test_many_revisions(self):
1230
tree = self.setup_ab_tree()
1232
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1233
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1234
log.show_log(tree.branch, lf, verbose=True, start_revision=start_rev,
1235
end_revision=end_rev)
1236
self.assertEqual(3, len(lf.revisions))
1237
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1238
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1239
self.assertEqual(None, lf.revisions[1].revno) # Out-of-branch
1240
self.assertEqual('2a', lf.revisions[1].rev.revision_id)
1241
self.assertEqual('1', lf.revisions[2].revno) # In-branch
1243
def test_long_format(self):
1244
tree = self.setup_ab_tree()
1245
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1246
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1247
self.assertFormatterResult("""\
1248
------------------------------------------------------------
1250
committer: Joe Foo <joe@foo.com>
1252
timestamp: Tue 2005-11-22 00:00:00 +0000
1255
------------------------------------------------------------
1257
committer: Joe Foo <joe@foo.com>
1259
timestamp: Tue 2005-11-22 00:00:00 +0000
1262
------------------------------------------------------------
1264
committer: Joe Foo <joe@foo.com>
1266
timestamp: Tue 2005-11-22 00:00:00 +0000
1270
tree.branch, log.LongLogFormatter, show_log_kwargs={
1271
'start_revision': start_rev, 'end_revision': end_rev
1274
def test_short_format(self):
1275
tree = self.setup_ab_tree()
1276
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1277
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1278
self.assertFormatterResult("""\
1287
1 Joe Foo\t2005-11-22
1291
tree.branch, log.ShortLogFormatter, show_log_kwargs={
1292
'start_revision': start_rev, 'end_revision': end_rev
1295
def test_line_format(self):
1296
tree = self.setup_ab_tree()
1297
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1298
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1299
self.assertFormatterResult("""\
1300
Joe Foo 2005-11-22 commit 3a
1301
Joe Foo 2005-11-22 commit 2a
1302
1: Joe Foo 2005-11-22 commit 1a
1304
tree.branch, log.LineLogFormatter, show_log_kwargs={
1305
'start_revision': start_rev, 'end_revision': end_rev
1309
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1312
TestCaseForLogFormatter.setUp(self)
1313
log.properties_handler_registry.register(
1314
'bugs_properties_handler',
1315
log._bugs_properties_handler)
1317
def make_commits_with_bugs(self):
1318
"""Helper method for LogFormatter tests"""
1319
tree = self.make_branch_and_tree(u'.')
1320
self.build_tree(['a', 'b'])
1322
self.wt_commit(tree, 'simple log message', rev_id='a1',
1323
revprops={'bugs': 'test://bug/id fixed'})
1325
self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id='a2',
1326
authors=['Joe Bar <joe@bar.com>'],
1327
revprops={'bugs': 'test://bug/id fixed\n'
1328
'test://bug/2 fixed'})
1332
def test_long_bugs(self):
1333
tree = self.make_commits_with_bugs()
1334
self.assertFormatterResult("""\
1335
------------------------------------------------------------
1337
fixes bugs: test://bug/id test://bug/2
1338
author: Joe Bar <joe@bar.com>
1339
committer: Joe Foo <joe@foo.com>
1341
timestamp: Tue 2005-11-22 00:00:01 +0000
1346
------------------------------------------------------------
1348
fixes bug: test://bug/id
1349
committer: Joe Foo <joe@foo.com>
1351
timestamp: Tue 2005-11-22 00:00:00 +0000
1355
tree.branch, log.LongLogFormatter)
1357
def test_short_bugs(self):
1358
tree = self.make_commits_with_bugs()
1359
self.assertFormatterResult("""\
1360
2 Joe Bar\t2005-11-22
1361
fixes bugs: test://bug/id test://bug/2
1366
1 Joe Foo\t2005-11-22
1367
fixes bug: test://bug/id
1371
tree.branch, log.ShortLogFormatter)
1373
def test_wrong_bugs_property(self):
1374
tree = self.make_branch_and_tree(u'.')
1375
self.build_tree(['foo'])
1376
self.wt_commit(tree, 'simple log message', rev_id='a1',
1377
revprops={'bugs': 'test://bug/id invalid_value'})
1378
self.assertFormatterResult("""\
1379
1 Joe Foo\t2005-11-22
1383
tree.branch, log.ShortLogFormatter)
1385
def test_bugs_handler_present(self):
1386
self.properties_handler_registry.get('bugs_properties_handler')
1389
class TestLogForAuthors(TestCaseForLogFormatter):
1392
TestCaseForLogFormatter.setUp(self)
1393
self.wt = self.make_standard_commit('nicky',
1394
authors=['John Doe <jdoe@example.com>',
1395
'Jane Rey <jrey@example.com>'])
1397
def assertFormatterResult(self, formatter, who, result):
1398
formatter_kwargs = dict()
1400
author_list_handler = log.author_list_registry.get(who)
1401
formatter_kwargs['author_list_handler'] = author_list_handler
1402
TestCaseForLogFormatter.assertFormatterResult(self, result,
1403
self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1405
def test_line_default(self):
1406
self.assertFormatterResult(log.LineLogFormatter, None, """\
1407
1: John Doe 2005-11-22 add a
1410
def test_line_committer(self):
1411
self.assertFormatterResult(log.LineLogFormatter, 'committer', """\
1412
1: Lorem Ipsum 2005-11-22 add a
1415
def test_line_first(self):
1416
self.assertFormatterResult(log.LineLogFormatter, 'first', """\
1417
1: John Doe 2005-11-22 add a
1420
def test_line_all(self):
1421
self.assertFormatterResult(log.LineLogFormatter, 'all', """\
1422
1: John Doe, Jane Rey 2005-11-22 add a
1426
def test_short_default(self):
1427
self.assertFormatterResult(log.ShortLogFormatter, None, """\
1428
1 John Doe\t2005-11-22
1433
def test_short_committer(self):
1434
self.assertFormatterResult(log.ShortLogFormatter, 'committer', """\
1435
1 Lorem Ipsum\t2005-11-22
1440
def test_short_first(self):
1441
self.assertFormatterResult(log.ShortLogFormatter, 'first', """\
1442
1 John Doe\t2005-11-22
1447
def test_short_all(self):
1448
self.assertFormatterResult(log.ShortLogFormatter, 'all', """\
1449
1 John Doe, Jane Rey\t2005-11-22
1454
def test_long_default(self):
1455
self.assertFormatterResult(log.LongLogFormatter, None, """\
1456
------------------------------------------------------------
1458
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1459
committer: Lorem Ipsum <test@example.com>
1461
timestamp: Tue 2005-11-22 00:00:00 +0000
1466
def test_long_committer(self):
1467
self.assertFormatterResult(log.LongLogFormatter, 'committer', """\
1468
------------------------------------------------------------
1470
committer: Lorem Ipsum <test@example.com>
1472
timestamp: Tue 2005-11-22 00:00:00 +0000
1477
def test_long_first(self):
1478
self.assertFormatterResult(log.LongLogFormatter, 'first', """\
1479
------------------------------------------------------------
1481
author: John Doe <jdoe@example.com>
1482
committer: Lorem Ipsum <test@example.com>
1484
timestamp: Tue 2005-11-22 00:00:00 +0000
1489
def test_long_all(self):
1490
self.assertFormatterResult(log.LongLogFormatter, 'all', """\
1491
------------------------------------------------------------
1493
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1494
committer: Lorem Ipsum <test@example.com>
1496
timestamp: Tue 2005-11-22 00:00:00 +0000
1501
def test_gnu_changelog_default(self):
1502
self.assertFormatterResult(log.GnuChangelogLogFormatter, None, """\
1503
2005-11-22 John Doe <jdoe@example.com>
1509
def test_gnu_changelog_committer(self):
1510
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', """\
1511
2005-11-22 Lorem Ipsum <test@example.com>
1517
def test_gnu_changelog_first(self):
1518
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', """\
1519
2005-11-22 John Doe <jdoe@example.com>
1525
def test_gnu_changelog_all(self):
1526
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'all', """\
1527
2005-11-22 John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1534
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1536
def make_branch_with_alternate_ancestries(self, relpath='.'):
1537
# See test_merge_sorted_exclude_ancestry below for the difference with
1538
# bt.per_branch.test_iter_merge_sorted_revision.
1539
# TestIterMergeSortedRevisionsBushyGraph.
1540
# make_branch_with_alternate_ancestries
1541
# and test_merge_sorted_exclude_ancestry
1542
# See the FIXME in assertLogRevnos too.
1543
builder = branchbuilder.BranchBuilder(self.get_transport(relpath))
1555
builder.start_series()
1556
builder.build_snapshot('1', None, [
1557
('add', ('', 'TREE_ROOT', 'directory', '')),])
1558
builder.build_snapshot('1.1.1', ['1'], [])
1559
builder.build_snapshot('2', ['1'], [])
1560
builder.build_snapshot('1.2.1', ['1.1.1'], [])
1561
builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1562
builder.build_snapshot('3', ['2', '1.1.2'], [])
1563
builder.finish_series()
1564
br = builder.get_branch()
1566
self.addCleanup(br.unlock)
1569
def assertLogRevnos(self, expected_revnos, b, start, end,
1570
exclude_common_ancestry, generate_merge_revisions=True):
1571
# FIXME: the layering in log makes it hard to test intermediate levels,
1572
# I wish adding filters with their parameters was easier...
1574
iter_revs = log._calc_view_revisions(
1575
b, start, end, direction='reverse',
1576
generate_merge_revisions=generate_merge_revisions,
1577
exclude_common_ancestry=exclude_common_ancestry)
1578
self.assertEqual(expected_revnos,
1579
[revid for revid, revno, depth in iter_revs])
1581
def test_merge_sorted_exclude_ancestry(self):
1582
b = self.make_branch_with_alternate_ancestries()
1583
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1584
b, '1', '3', exclude_common_ancestry=False)
1585
# '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1586
# it should be mentioned even if merge_sort order will make it appear
1588
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1589
b, '1.1.1', '3', exclude_common_ancestry=True)
1591
def test_merge_sorted_simple_revnos_exclude_ancestry(self):
1592
b = self.make_branch_with_alternate_ancestries()
1593
self.assertLogRevnos(['3', '2'],
1594
b, '1', '3', exclude_common_ancestry=True,
1595
generate_merge_revisions=False)
1596
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2'],
1597
b, '1', '3', exclude_common_ancestry=True,
1598
generate_merge_revisions=True)
1601
class TestLogDefaults(TestCaseForLogFormatter):
1602
def test_default_log_level(self):
1604
Test to ensure that specifying 'levels=1' to make_log_request_dict
1605
doesn't get overwritten when using a LogFormatter that supports more
1609
wt = self._prepare_tree_with_merges()
1612
class CustomLogFormatter(log.LogFormatter):
1613
def __init__(self, *args, **kwargs):
1614
super(CustomLogFormatter, self).__init__(*args, **kwargs)
1616
def get_levels(self):
1617
# log formatter supports all levels:
1619
def log_revision(self, revision):
1620
self.revisions.append(revision)
1622
log_formatter = LogCatcher()
1623
# First request we don't specify number of levels, we should get a
1624
# sensible default (whatever the LogFormatter handles - which in this
1625
# case is 0/everything):
1626
request = log.make_log_request_dict(limit=10)
1627
log.Logger(b, request).show(log_formatter)
1628
# should have all three revisions:
1629
self.assertEquals(len(log_formatter.revisions), 3)
1632
log_formatter = LogCatcher()
1633
# now explicitly request mainline revisions only:
1634
request = log.make_log_request_dict(limit=10, levels=1)
1635
log.Logger(b, request).show(log_formatter)
1636
# should now only have 2 revisions:
1637
self.assertEquals(len(log_formatter.revisions), 2)