43
43
stamp is incremented at each commit.
45
45
if getattr(self, 'timestamp', None) is None:
46
self.timestamp = 1132617600 # Mon 2005-11-22 00:00:00 +0000
46
self.timestamp = 1132617600 # Mon 2005-11-22 00:00:00 +0000
48
self.timestamp += 1 # 1 second between each commit
48
self.timestamp += 1 # 1 second between each commit
49
49
kwargs.setdefault('timestamp', self.timestamp)
50
kwargs.setdefault('timezone', 0) # UTC
50
kwargs.setdefault('timezone', 0) # UTC
51
51
kwargs.setdefault('committer', 'Joe Foo <joe@foo.com>')
53
53
return wt.commit(message, **kwargs)
256
256
wt.commit(message='add file1 and file2')
257
257
self.run_bzr('branch parent child')
258
258
os.unlink('child/file1')
259
with open('child/file2', 'wb') as f: f.write(b'hello\n')
259
with open('child/file2', 'wb') as f:
260
261
self.run_bzr(['commit', '-m', 'remove file1 and modify file2',
262
263
os.chdir('parent')
263
264
self.run_bzr('merge ../child')
264
265
wt.commit('merge child branch')
334
335
# can't sign it without a heavier TestCase and LoopbackGPGStrategy
335
336
# doesn't care anyways.
336
337
self.overrideAttr(repo, 'verify_revision_signature',
337
self.verify_revision_signature)
338
self.verify_revision_signature)
338
339
out = log.format_signature_validity(revid, wt.branch)
339
340
self.assertEqual(
340
u'valid signature from UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>',
341
u'valid signature from UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>',
344
345
class TestShortLogFormatter(TestCaseForLogFormatter):
491
wt.branch, log.ShortLogFormatter,
492
formatter_kwargs=dict(levels=0),
493
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
492
wt.branch, log.ShortLogFormatter,
493
formatter_kwargs=dict(levels=0),
494
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
496
497
class TestLongLogFormatter(TestCaseForLogFormatter):
515
wt.branch, log.LongLogFormatter,
516
show_log_kwargs=dict(verbose=True))
516
wt.branch, log.LongLogFormatter,
517
show_log_kwargs=dict(verbose=True))
518
519
def test_merges_are_indented_by_level(self):
519
520
wt = self.make_branch_and_tree('parent')
520
521
self.wt_commit(wt, 'first post')
521
522
child_wt = wt.controldir.sprout('child').open_workingtree()
522
523
self.wt_commit(child_wt, 'branch 1')
523
smallerchild_wt = wt.controldir.sprout('smallerchild').open_workingtree()
524
smallerchild_wt = wt.controldir.sprout(
525
'smallerchild').open_workingtree()
524
526
self.wt_commit(smallerchild_wt, 'branch 2')
525
527
child_wt.merge_from_branch(smallerchild_wt.branch)
526
528
self.wt_commit(child_wt, 'merge branch 2')
566
wt.branch, log.LongLogFormatter,
567
formatter_kwargs=dict(levels=0),
568
show_log_kwargs=dict(verbose=True))
568
wt.branch, log.LongLogFormatter,
569
formatter_kwargs=dict(levels=0),
570
show_log_kwargs=dict(verbose=True))
570
572
def test_verbose_merge_revisions_contain_deltas(self):
571
573
wt = self.make_branch_and_tree('parent')
615
wt.branch, log.LongLogFormatter,
616
formatter_kwargs=dict(levels=0),
617
show_log_kwargs=dict(verbose=True))
617
wt.branch, log.LongLogFormatter,
618
formatter_kwargs=dict(levels=0),
619
show_log_kwargs=dict(verbose=True))
619
621
def test_trailing_newlines(self):
620
622
wt = self.make_branch_and_tree('.')
645
647
simple log message
647
b, log.LongLogFormatter)
649
b, log.LongLogFormatter)
649
651
def test_author_in_log(self):
650
652
"""Log includes the author name if it's set in
651
653
the revision properties
653
655
wt = self.make_standard_commit('test_author_log',
654
authors=['John Doe <jdoe@example.com>',
655
'Jane Rey <jrey@example.com>'])
656
authors=['John Doe <jdoe@example.com>',
657
'Jane Rey <jrey@example.com>'])
656
658
self.assertFormatterResult(b"""\
657
659
------------------------------------------------------------
666
wt.branch, log.LongLogFormatter)
668
wt.branch, log.LongLogFormatter)
668
670
def test_properties_in_log(self):
669
671
"""Log includes the custom properties returned by the registered
672
674
wt = self.make_standard_commit('test_properties_in_log')
673
676
def trivial_custom_prop_handler(revision):
674
return {'test_prop':'test_value'}
677
return {'test_prop': 'test_value'}
676
679
# Cleaned up in setUp()
677
680
log.properties_handler_registry.register(
691
wt.branch, log.LongLogFormatter)
694
wt.branch, log.LongLogFormatter)
693
696
def test_properties_in_short_log(self):
694
697
"""Log includes the custom properties returned by the registered
697
700
wt = self.make_standard_commit('test_properties_in_short_log')
698
702
def trivial_custom_prop_handler(revision):
699
return {'test_prop':'test_value'}
703
return {'test_prop': 'test_value'}
701
705
log.properties_handler_registry.register(
702
706
'trivial_custom_prop_handler',
710
wt.branch, log.ShortLogFormatter)
714
wt.branch, log.ShortLogFormatter)
712
716
def test_error_in_properties_handler(self):
713
717
"""Log includes the custom properties returned by the registered
716
720
wt = self.make_standard_commit('error_in_properties_handler',
717
revprops={u'first_prop':'first_value'})
721
revprops={u'first_prop': 'first_value'})
718
722
sio = self.make_utf8_encoded_stringio()
719
723
formatter = log.LongLogFormatter(to_file=sio)
720
725
def trivial_custom_prop_handler(revision):
721
726
raise Exception("a test error")
728
733
def test_properties_handler_bad_argument(self):
729
734
wt = self.make_standard_commit('bad_argument',
730
revprops={u'a_prop':'test_value'})
735
revprops={u'a_prop': 'test_value'})
731
736
sio = self.make_utf8_encoded_stringio()
732
737
formatter = log.LongLogFormatter(to_file=sio)
733
739
def bad_argument_prop_handler(revision):
734
return {'custom_prop_name':revision.properties['a_prop']}
740
return {'custom_prop_name': revision.properties['a_prop']}
736
742
log.properties_handler_registry.register(
737
743
'bad_argument_prop_handler',
809
wt.branch, log.LongLogFormatter,
810
formatter_kwargs=dict(levels=1),
811
show_log_kwargs=dict(verbose=True))
815
wt.branch, log.LongLogFormatter,
816
formatter_kwargs=dict(levels=1),
817
show_log_kwargs=dict(verbose=True))
813
819
def test_long_verbose_contain_deltas(self):
814
820
wt = self.make_branch_and_tree('parent')
847
wt.branch, log.LongLogFormatter,
848
formatter_kwargs=dict(levels=1),
849
show_log_kwargs=dict(verbose=True))
853
wt.branch, log.LongLogFormatter,
854
formatter_kwargs=dict(levels=1),
855
show_log_kwargs=dict(verbose=True))
851
857
def test_long_trailing_newlines(self):
852
858
wt = self.make_branch_and_tree('.')
897
wt.branch, log.LongLogFormatter,
898
formatter_kwargs=dict(levels=1))
903
wt.branch, log.LongLogFormatter,
904
formatter_kwargs=dict(levels=1))
900
906
def test_long_properties_in_log(self):
901
907
"""Log includes the custom properties returned by the registered
904
910
wt = self.make_standard_commit('test_properties_in_log')
905
912
def trivial_custom_prop_handler(revision):
906
return {'test_prop':'test_value'}
913
return {'test_prop': 'test_value'}
908
915
log.properties_handler_registry.register(
909
916
'trivial_custom_prop_handler',
933
940
wt = self.make_standard_commit('test-line-log',
934
committer='Line-Log-Formatter Tester <test@line.log>',
941
committer='Line-Log-Formatter Tester <test@line.log>',
936
943
self.assertFormatterResult(b"""\
937
944
1: Line-Log-Formatte... 2005-11-22 add a
939
wt.branch, log.LineLogFormatter)
946
wt.branch, log.LineLogFormatter)
941
948
def test_trailing_newlines(self):
942
949
wt = self.make_branch_and_tree('.')
955
962
self.assertFormatterResult(b"""\
956
963
1.1.1: Joe Foo 2005-11-22 rev-merged
958
wt.branch, log.LineLogFormatter,
959
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
965
wt.branch, log.LineLogFormatter,
966
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
961
968
def test_line_log_with_tags(self):
962
969
wt = self._prepare_tree_with_merges(with_tags=True)
978
985
wt = self.make_standard_commit('test-line-log',
979
committer='Line-Log-Formatter Tester <test@line.log>',
986
committer='Line-Log-Formatter Tester <test@line.log>',
981
988
self.assertFormatterResult(b"""\
982
989
1: Line-Log-Formatte... 2005-11-22 add a
984
wt.branch, log.LineLogFormatter)
991
wt.branch, log.LineLogFormatter)
986
993
def test_line_merge_revs_log_single_merge_revision(self):
987
994
wt = self._prepare_tree_with_merges()
990
997
self.assertFormatterResult(b"""\
991
998
1.1.1: Joe Foo 2005-11-22 rev-merged
993
wt.branch, log.LineLogFormatter,
994
formatter_kwargs=dict(levels=0),
995
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1000
wt.branch, log.LineLogFormatter,
1001
formatter_kwargs=dict(levels=0),
1002
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
997
1004
def test_line_merge_revs_log_with_merges(self):
998
1005
wt = self._prepare_tree_with_merges()
1018
wt.branch, log.GnuChangelogLogFormatter)
1025
wt.branch, log.GnuChangelogLogFormatter)
1020
1027
def test_with_authors(self):
1021
1028
wt = self.make_standard_commit('nicky',
1022
authors=['Fooa Fooz <foo@example.com>',
1023
'Bari Baro <bar@example.com>'])
1029
authors=['Fooa Fooz <foo@example.com>',
1030
'Bari Baro <bar@example.com>'])
1024
1031
self.assertFormatterResult(b'''\
1025
1032
2005-11-22 Fooa Fooz <foo@example.com>
1030
wt.branch, log.GnuChangelogLogFormatter)
1037
wt.branch, log.GnuChangelogLogFormatter)
1032
1039
def test_verbose(self):
1033
1040
wt = self.make_standard_commit('nicky')
1114
1121
Tests use (revno, depth) whil the API expects (revid, revno, depth).
1115
1122
Since the revid is arbitrary, we just duplicate revno
1117
return [ (r, r, d) for r, d in l]
1124
return [(r, r, d) for r, d in l]
1118
1125
forward = complete_revisions(forward)
1119
backward= complete_revisions(backward)
1126
backward = complete_revisions(backward)
1120
1127
self.assertEqual(forward, log.reverse_by_depth(backward))
1123
1129
def test_mainline_revisions(self):
1124
self.assertReversed([( '1', 0), ('2', 0)],
1130
self.assertReversed([('1', 0), ('2', 0)],
1125
1131
[('2', 0), ('1', 0)])
1127
1133
def test_merged_revisions(self):
1128
self.assertReversed([('1', 0), ('2', 0), ('2.2', 1), ('2.1', 1),],
1129
[('2', 0), ('2.1', 1), ('2.2', 1), ('1', 0),])
1134
self.assertReversed([('1', 0), ('2', 0), ('2.2', 1), ('2.1', 1), ],
1135
[('2', 0), ('2.1', 1), ('2.2', 1), ('1', 0), ])
1130
1137
def test_shifted_merged_revisions(self):
1131
1138
"""Test irregular layout.
1133
1140
Requesting revisions touching a file can produce "holes" in the depths.
1135
self.assertReversed([('1', 0), ('2', 0), ('1.1', 2), ('1.2', 2),],
1136
[('2', 0), ('1.2', 2), ('1.1', 2), ('1', 0),])
1142
self.assertReversed([('1', 0), ('2', 0), ('1.1', 2), ('1.2', 2), ],
1143
[('2', 0), ('1.2', 2), ('1.1', 2), ('1', 0), ])
1138
1145
def test_merged_without_child_revisions(self):
1139
1146
"""Test irregular layout.
1143
1150
# When a revision of higher depth doesn't follow one of lower depth, we
1144
1151
# assume a lower depth one is virtually there
1145
1152
self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1146
[('4', 4), ('3', 3), ('2', 2), ('1', 2),])
1153
[('4', 4), ('3', 3), ('2', 2), ('1', 2), ])
1147
1154
# So we get the same order after reversing below even if the original
1148
1155
# revisions are not in the same order.
1149
1156
self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1150
[('3', 3), ('4', 4), ('2', 2), ('1', 2),])
1157
[('3', 3), ('4', 4), ('2', 2), ('1', 2), ])
1153
1160
class TestHistoryChange(tests.TestCaseWithTransport):
1222
1229
log.show_branch_change(tree.branch, s, 3, b'3a')
1223
1230
self.assertContainsRe(s.getvalue(),
1224
'[*]{60}\nRemoved Revisions:\n(.|\n)*2a(.|\n)*3a(.|\n)*'
1225
'[*]{60}\n\nAdded Revisions:\n(.|\n)*2b(.|\n)*3b')
1231
'[*]{60}\nRemoved Revisions:\n(.|\n)*2a(.|\n)*3a(.|\n)*'
1232
'[*]{60}\n\nAdded Revisions:\n(.|\n)*2b(.|\n)*3b')
1227
1234
def test_show_branch_change_no_change(self):
1228
1235
tree = self.setup_ab_tree()
1230
1237
log.show_branch_change(tree.branch, s, 3, b'3b')
1231
1238
self.assertEqual(s.getvalue(),
1232
'Nothing seems to have changed\n')
1239
'Nothing seems to have changed\n')
1234
1241
def test_show_branch_change_no_old(self):
1235
1242
tree = self.setup_ab_tree()
1269
1276
tree.branch.set_last_revision_info(1, b'1a')
1271
1278
'committer': 'Joe Foo <joe@foo.com>',
1272
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1273
'timezone': 0, # UTC
1279
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1280
'timezone': 0, # UTC
1275
1282
tree.commit('commit 2b', rev_id=b'2b', **kwargs)
1276
1283
tree.commit('commit 3b', rev_id=b'3b', **kwargs)
1361
1368
Joe Foo 2005-11-22 commit 2a
1362
1369
1: Joe Foo 2005-11-22 commit 1a
1364
tree.branch, log.LineLogFormatter, show_log_kwargs={
1365
'start_revision': start_rev, 'end_revision': end_rev
1371
tree.branch, log.LineLogFormatter, show_log_kwargs={
1372
'start_revision': start_rev, 'end_revision': end_rev
1369
1376
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1451
1457
def setUp(self):
1452
1458
super(TestLogForAuthors, self).setUp()
1453
1459
self.wt = self.make_standard_commit('nicky',
1454
authors=['John Doe <jdoe@example.com>',
1455
'Jane Rey <jrey@example.com>'])
1460
authors=['John Doe <jdoe@example.com>',
1461
'Jane Rey <jrey@example.com>'])
1457
1463
def assertFormatterResult(self, formatter, who, result):
1458
1464
formatter_kwargs = dict()
1460
1466
author_list_handler = log.author_list_registry.get(who)
1461
1467
formatter_kwargs['author_list_handler'] = author_list_handler
1462
1468
TestCaseForLogFormatter.assertFormatterResult(self, result,
1463
self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1469
self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1465
1471
def test_line_default(self):
1466
1472
self.assertFormatterResult(log.LineLogFormatter, None, b"""\
1615
1620
builder.start_series()
1616
1621
builder.build_snapshot(None, [
1617
('add', ('', b'TREE_ROOT', 'directory', '')),],
1622
('add', ('', b'TREE_ROOT', 'directory', '')), ],
1618
1623
revision_id=b'1')
1619
1624
builder.build_snapshot([b'1'], [], revision_id=b'1.1.1')
1620
1625
builder.build_snapshot([b'1'], [], revision_id=b'2')