915
wt.branch, log.GnuChangelogLogFormatter,
916
show_log_kwargs=dict(verbose=True))
918
class TestGetViewRevisions(tests.TestCaseWithTransport, TestLogMixin):
920
def _get_view_revisions(self, *args, **kwargs):
921
return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
922
log.get_view_revisions, *args, **kwargs)
924
def make_tree_with_commits(self):
925
"""Create a tree with well-known revision ids"""
926
wt = self.make_branch_and_tree('tree1')
927
self.wt_commit(wt, 'commit one', rev_id='1')
928
self.wt_commit(wt, 'commit two', rev_id='2')
929
self.wt_commit(wt, 'commit three', rev_id='3')
930
mainline_revs = [None, '1', '2', '3']
931
rev_nos = {'1': 1, '2': 2, '3': 3}
932
return mainline_revs, rev_nos, wt
934
def make_tree_with_merges(self):
935
"""Create a tree with well-known revision ids and a merge"""
936
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
937
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
938
self.wt_commit(tree2, 'four-a', rev_id='4a')
939
wt.merge_from_branch(tree2.branch)
940
self.wt_commit(wt, 'four-b', rev_id='4b')
941
mainline_revs.append('4b')
944
return mainline_revs, rev_nos, wt
946
def make_branch_with_many_merges(self):
947
"""Create a tree with well-known revision ids"""
948
builder = self.make_branch_builder('tree1')
949
builder.start_series()
950
builder.build_snapshot('1', None, [
951
('add', ('', 'TREE_ROOT', 'directory', '')),
952
('add', ('f', 'f-id', 'file', '1\n'))])
953
builder.build_snapshot('2', ['1'], [])
954
builder.build_snapshot('3a', ['2'], [
955
('modify', ('f-id', '1\n2\n3a\n'))])
956
builder.build_snapshot('3b', ['2', '3a'], [
957
('modify', ('f-id', '1\n2\n3a\n'))])
958
builder.build_snapshot('3c', ['2', '3b'], [
959
('modify', ('f-id', '1\n2\n3a\n'))])
960
builder.build_snapshot('4a', ['3b'], [])
961
builder.build_snapshot('4b', ['3c', '4a'], [])
962
builder.finish_series()
976
mainline_revs = [None, '1', '2', '3c', '4b']
977
rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
978
full_rev_nos_for_reference = {
981
'3a': '2.1.1', #first commit tree 3
982
'3b': '2.2.1', # first commit tree 2
983
'3c': '3', #merges 3b to main
984
'4a': '2.2.2', # second commit tree 2
985
'4b': '4', # merges 4a to main
987
return mainline_revs, rev_nos, builder.get_branch()
989
def test_get_view_revisions_forward(self):
990
"""Test the get_view_revisions method"""
991
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
993
self.addCleanup(wt.unlock)
994
revisions = list(self._get_view_revisions(
995
mainline_revs, rev_nos, wt.branch, 'forward'))
996
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
998
revisions2 = list(self._get_view_revisions(
999
mainline_revs, rev_nos, wt.branch, 'forward',
1000
include_merges=False))
1001
self.assertEqual(revisions, revisions2)
1003
def test_get_view_revisions_reverse(self):
1004
"""Test the get_view_revisions with reverse"""
1005
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1007
self.addCleanup(wt.unlock)
1008
revisions = list(self._get_view_revisions(
1009
mainline_revs, rev_nos, wt.branch, 'reverse'))
1010
self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
1012
revisions2 = list(self._get_view_revisions(
1013
mainline_revs, rev_nos, wt.branch, 'reverse',
1014
include_merges=False))
1015
self.assertEqual(revisions, revisions2)
1017
def test_get_view_revisions_merge(self):
1018
"""Test get_view_revisions when there are merges"""
1019
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1021
self.addCleanup(wt.unlock)
1022
revisions = list(self._get_view_revisions(
1023
mainline_revs, rev_nos, wt.branch, 'forward'))
1024
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1025
('4b', '4', 0), ('4a', '3.1.1', 1)],
1027
revisions = list(self._get_view_revisions(
1028
mainline_revs, rev_nos, wt.branch, 'forward',
1029
include_merges=False))
1030
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1034
def test_get_view_revisions_merge_reverse(self):
1035
"""Test get_view_revisions in reverse when there are merges"""
1036
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1038
self.addCleanup(wt.unlock)
1039
revisions = list(self._get_view_revisions(
1040
mainline_revs, rev_nos, wt.branch, 'reverse'))
1041
self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
1042
('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
1044
revisions = list(self._get_view_revisions(
1045
mainline_revs, rev_nos, wt.branch, 'reverse',
1046
include_merges=False))
1047
self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
1051
def test_get_view_revisions_merge2(self):
1052
"""Test get_view_revisions when there are merges"""
1053
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1055
self.addCleanup(b.unlock)
1056
revisions = list(self._get_view_revisions(
1057
mainline_revs, rev_nos, b, 'forward'))
1058
expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1059
('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1061
self.assertEqual(expected, revisions)
1062
revisions = list(self._get_view_revisions(
1063
mainline_revs, rev_nos, b, 'forward',
1064
include_merges=False))
1065
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1069
def test_file_id_for_range(self):
1070
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1072
self.addCleanup(b.unlock)
1074
def rev_from_rev_id(revid, branch):
1075
revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1076
return revspec.in_history(branch)
1078
def view_revs(start_rev, end_rev, file_id, direction):
1079
revs = self.applyDeprecated(
1080
symbol_versioning.deprecated_in((2, 2, 0)),
1081
log.calculate_view_revisions,
1083
start_rev, # start_revision
1084
end_rev, # end_revision
1085
direction, # direction
1086
file_id, # specific_fileid
1087
True, # generate_merge_revisions
1091
rev_3a = rev_from_rev_id('3a', b)
1092
rev_4b = rev_from_rev_id('4b', b)
1093
self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
1094
('3a', '2.1.1', 2)],
1095
view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
1096
# Note: 3c still appears before 3a here because of depth-based sorting
1097
self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
1098
('3a', '2.1.1', 2)],
1099
view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1102
class TestGetRevisionsTouchingFileID(tests.TestCaseWithTransport):
1104
def get_view_revisions(self, *args):
1105
return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
1106
log.get_view_revisions, *args)
1108
def create_tree_with_single_merge(self):
1109
"""Create a branch with a moderate layout.
1111
The revision graph looks like:
1119
In this graph, A introduced files f1 and f2 and f3.
1120
B modifies f1 and f3, and C modifies f2 and f3.
1121
D merges the changes from B and C and resolves the conflict for f3.
1123
# TODO: jam 20070218 This seems like it could really be done
1124
# with make_branch_and_memory_tree() if we could just
1125
# create the content of those files.
1126
# TODO: jam 20070218 Another alternative is that we would really
1127
# like to only create this tree 1 time for all tests that
1128
# use it. Since 'log' only uses the tree in a readonly
1129
# fashion, it seems a shame to regenerate an identical
1130
# tree for each test.
1131
# TODO: vila 20100122 One way to address the shame above will be to
1132
# create a memory tree during test parametrization and give a
1133
# *copy* of this tree to each test. Copying a memory tree ought
1134
# to be cheap, at least cheaper than creating them with such
1136
tree = self.make_branch_and_tree('tree')
1138
self.addCleanup(tree.unlock)
1140
self.build_tree_contents([('tree/f1', 'A\n'),
1144
tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
1145
tree.commit('A', rev_id='A')
1147
self.build_tree_contents([('tree/f2', 'A\nC\n'),
1148
('tree/f3', 'A\nC\n'),
1150
tree.commit('C', rev_id='C')
1151
# Revert back to A to build the other history.
1152
tree.set_last_revision('A')
1153
tree.branch.set_last_revision_info(1, 'A')
1154
self.build_tree_contents([('tree/f1', 'A\nB\n'),
1156
('tree/f3', 'A\nB\n'),
1158
tree.commit('B', rev_id='B')
1159
tree.set_parent_ids(['B', 'C'])
1160
self.build_tree_contents([('tree/f1', 'A\nB\n'),
1161
('tree/f2', 'A\nC\n'),
1162
('tree/f3', 'A\nB\nC\n'),
1164
tree.commit('D', rev_id='D')
1166
# Switch to a read lock for this tree.
1167
# We still have an addCleanup(tree.unlock) pending
1172
def check_delta(self, delta, **kw):
1173
"""Check the filenames touched by a delta are as expected.
1175
Caller only have to pass in the list of files for each part, all
1176
unspecified parts are considered empty (and checked as such).
1178
for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
1179
# By default we expect an empty list
1180
expected = kw.get(n, [])
1181
# strip out only the path components
1182
got = [x[0] for x in getattr(delta, n)]
1183
self.assertEqual(expected, got)
1185
def test_tree_with_single_merge(self):
1186
"""Make sure the tree layout is correct."""
1187
tree = self.create_tree_with_single_merge()
1188
rev_A_tree = tree.branch.repository.revision_tree('A')
1189
rev_B_tree = tree.branch.repository.revision_tree('B')
1190
rev_C_tree = tree.branch.repository.revision_tree('C')
1191
rev_D_tree = tree.branch.repository.revision_tree('D')
1193
self.check_delta(rev_B_tree.changes_from(rev_A_tree),
1194
modified=['f1', 'f3'])
1196
self.check_delta(rev_C_tree.changes_from(rev_A_tree),
1197
modified=['f2', 'f3'])
1199
self.check_delta(rev_D_tree.changes_from(rev_B_tree),
1200
modified=['f2', 'f3'])
1202
self.check_delta(rev_D_tree.changes_from(rev_C_tree),
1203
modified=['f1', 'f3'])
1205
def assertAllRevisionsForFileID(self, tree, file_id, revisions):
1206
"""Ensure _filter_revisions_touching_file_id returns the right values.
1208
Get the return value from _filter_revisions_touching_file_id and make
1209
sure they are correct.
1211
# The api for _filter_revisions_touching_file_id is a little crazy.
1212
# So we do the setup here.
1213
mainline = tree.branch.revision_history()
1214
mainline.insert(0, None)
1215
revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
1216
view_revs_iter = self.get_view_revisions(
1217
mainline, revnos, tree.branch, 'reverse', True)
1218
actual_revs = log._filter_revisions_touching_file_id(
1219
tree.branch, file_id, list(view_revs_iter))
1220
self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
1222
def test_file_id_f1(self):
1223
tree = self.create_tree_with_single_merge()
1224
# f1 should be marked as modified by revisions A and B
1225
self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
1227
def test_file_id_f2(self):
1228
tree = self.create_tree_with_single_merge()
1229
# f2 should be marked as modified by revisions A, C, and D
1230
# because D merged the changes from C.
1231
self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1233
def test_file_id_f3(self):
1234
tree = self.create_tree_with_single_merge()
1235
# f3 should be marked as modified by revisions A, B, C, and D
1236
self.assertAllRevisionsForFileID(tree, 'f3-id', ['D', 'C', 'B', 'A'])
1238
def test_file_id_with_ghosts(self):
1239
# This is testing bug #209948, where having a ghost would cause
1240
# _filter_revisions_touching_file_id() to fail.
1241
tree = self.create_tree_with_single_merge()
1242
# We need to add a revision, so switch back to a write-locked tree
1243
# (still a single addCleanup(tree.unlock) pending).
1246
first_parent = tree.last_revision()
1247
tree.set_parent_ids([first_parent, 'ghost-revision-id'])
1248
self.build_tree_contents([('tree/f1', 'A\nB\nXX\n')])
1249
tree.commit('commit with a ghost', rev_id='XX')
1250
self.assertAllRevisionsForFileID(tree, 'f1-id', ['XX', 'B', 'A'])
1251
self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1253
def test_unknown_file_id(self):
1254
tree = self.create_tree_with_single_merge()
1255
self.assertAllRevisionsForFileID(tree, 'unknown', [])
1257
def test_empty_branch_unknown_file_id(self):
1258
tree = self.make_branch_and_tree('tree')
1259
self.assertAllRevisionsForFileID(tree, 'unknown', [])
1049
wt.branch, log.GnuChangelogLogFormatter,
1050
show_log_kwargs=dict(verbose=True))
1262
1053
class TestShowChangedRevisions(tests.TestCaseWithTransport):
1372
1163
tree = self.make_branch_and_tree('tree')
1373
1164
tree.lock_write()
1374
1165
self.addCleanup(tree.unlock)
1375
tree.commit('1a', rev_id='1a')
1376
tree.commit('2a', rev_id='2a')
1377
tree.commit('3a', rev_id='3a')
1166
tree.commit('1a', rev_id=b'1a')
1167
tree.commit('2a', rev_id=b'2a')
1168
tree.commit('3a', rev_id=b'3a')
1380
1171
def setup_ab_tree(self):
1381
1172
tree = self.setup_a_tree()
1382
tree.set_last_revision('1a')
1383
tree.branch.set_last_revision_info(1, '1a')
1384
tree.commit('2b', rev_id='2b')
1385
tree.commit('3b', rev_id='3b')
1173
tree.set_last_revision(b'1a')
1174
tree.branch.set_last_revision_info(1, b'1a')
1175
tree.commit('2b', rev_id=b'2b')
1176
tree.commit('3b', rev_id=b'3b')
1388
1179
def setup_ac_tree(self):
1389
1180
tree = self.setup_a_tree()
1390
1181
tree.set_last_revision(revision.NULL_REVISION)
1391
1182
tree.branch.set_last_revision_info(0, revision.NULL_REVISION)
1392
tree.commit('1c', rev_id='1c')
1393
tree.commit('2c', rev_id='2c')
1394
tree.commit('3c', rev_id='3c')
1183
tree.commit('1c', rev_id=b'1c')
1184
tree.commit('2c', rev_id=b'2c')
1185
tree.commit('3c', rev_id=b'3c')
1397
1188
def test_all_new(self):
1398
1189
tree = self.setup_ab_tree()
1399
old, new = log.get_history_change('1a', '3a', tree.branch.repository)
1190
old, new = log.get_history_change(b'1a', b'3a', tree.branch.repository)
1400
1191
self.assertEqual([], old)
1401
self.assertEqual(['2a', '3a'], new)
1192
self.assertEqual([b'2a', b'3a'], new)
1403
1194
def test_all_old(self):
1404
1195
tree = self.setup_ab_tree()
1405
old, new = log.get_history_change('3a', '1a', tree.branch.repository)
1196
old, new = log.get_history_change(b'3a', b'1a', tree.branch.repository)
1406
1197
self.assertEqual([], new)
1407
self.assertEqual(['2a', '3a'], old)
1198
self.assertEqual([b'2a', b'3a'], old)
1409
1200
def test_null_old(self):
1410
1201
tree = self.setup_ab_tree()
1411
1202
old, new = log.get_history_change(revision.NULL_REVISION,
1412
'3a', tree.branch.repository)
1203
b'3a', tree.branch.repository)
1413
1204
self.assertEqual([], old)
1414
self.assertEqual(['1a', '2a', '3a'], new)
1205
self.assertEqual([b'1a', b'2a', b'3a'], new)
1416
1207
def test_null_new(self):
1417
1208
tree = self.setup_ab_tree()
1418
old, new = log.get_history_change('3a', revision.NULL_REVISION,
1209
old, new = log.get_history_change(b'3a', revision.NULL_REVISION,
1419
1210
tree.branch.repository)
1420
1211
self.assertEqual([], new)
1421
self.assertEqual(['1a', '2a', '3a'], old)
1212
self.assertEqual([b'1a', b'2a', b'3a'], old)
1423
1214
def test_diverged(self):
1424
1215
tree = self.setup_ab_tree()
1425
old, new = log.get_history_change('3a', '3b', tree.branch.repository)
1426
self.assertEqual(old, ['2a', '3a'])
1427
self.assertEqual(new, ['2b', '3b'])
1216
old, new = log.get_history_change(b'3a', b'3b', tree.branch.repository)
1217
self.assertEqual(old, [b'2a', b'3a'])
1218
self.assertEqual(new, [b'2b', b'3b'])
1429
1220
def test_unrelated(self):
1430
1221
tree = self.setup_ac_tree()
1431
old, new = log.get_history_change('3a', '3c', tree.branch.repository)
1432
self.assertEqual(old, ['1a', '2a', '3a'])
1433
self.assertEqual(new, ['1c', '2c', '3c'])
1222
old, new = log.get_history_change(b'3a', b'3c', tree.branch.repository)
1223
self.assertEqual(old, [b'1a', b'2a', b'3a'])
1224
self.assertEqual(new, [b'1c', b'2c', b'3c'])
1435
1226
def test_show_branch_change(self):
1436
1227
tree = self.setup_ab_tree()
1438
log.show_branch_change(tree.branch, s, 3, '3a')
1229
log.show_branch_change(tree.branch, s, 3, b'3a')
1439
1230
self.assertContainsRe(s.getvalue(),
1440
'[*]{60}\nRemoved Revisions:\n(.|\n)*2a(.|\n)*3a(.|\n)*'
1441
'[*]{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')
1443
1234
def test_show_branch_change_no_change(self):
1444
1235
tree = self.setup_ab_tree()
1446
log.show_branch_change(tree.branch, s, 3, '3b')
1237
log.show_branch_change(tree.branch, s, 3, b'3b')
1447
1238
self.assertEqual(s.getvalue(),
1448
'Nothing seems to have changed\n')
1239
'Nothing seems to have changed\n')
1450
1241
def test_show_branch_change_no_old(self):
1451
1242
tree = self.setup_ab_tree()
1453
log.show_branch_change(tree.branch, s, 2, '2b')
1244
log.show_branch_change(tree.branch, s, 2, b'2b')
1454
1245
self.assertContainsRe(s.getvalue(), 'Added Revisions:')
1455
1246
self.assertNotContainsRe(s.getvalue(), 'Removed Revisions:')
1457
1248
def test_show_branch_change_no_new(self):
1458
1249
tree = self.setup_ab_tree()
1459
tree.branch.set_last_revision_info(2, '2b')
1250
tree.branch.set_last_revision_info(2, b'2b')
1461
log.show_branch_change(tree.branch, s, 3, '3b')
1252
log.show_branch_change(tree.branch, s, 3, b'3b')
1462
1253
self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1463
1254
self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1257
class TestRevisionNotInBranch(TestCaseForLogFormatter):
1259
def setup_a_tree(self):
1260
tree = self.make_branch_and_tree('tree')
1262
self.addCleanup(tree.unlock)
1264
'committer': 'Joe Foo <joe@foo.com>',
1265
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1266
'timezone': 0, # UTC
1268
tree.commit('commit 1a', rev_id=b'1a', **kwargs)
1269
tree.commit('commit 2a', rev_id=b'2a', **kwargs)
1270
tree.commit('commit 3a', rev_id=b'3a', **kwargs)
1273
def setup_ab_tree(self):
1274
tree = self.setup_a_tree()
1275
tree.set_last_revision(b'1a')
1276
tree.branch.set_last_revision_info(1, b'1a')
1278
'committer': 'Joe Foo <joe@foo.com>',
1279
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1280
'timezone': 0, # UTC
1282
tree.commit('commit 2b', rev_id=b'2b', **kwargs)
1283
tree.commit('commit 3b', rev_id=b'3b', **kwargs)
1286
def test_one_revision(self):
1287
tree = self.setup_ab_tree()
1289
rev = revisionspec.RevisionInfo(tree.branch, None, b'3a')
1290
log.show_log(tree.branch, lf, verbose=True, start_revision=rev,
1292
self.assertEqual(1, len(lf.revisions))
1293
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1294
self.assertEqual(b'3a', lf.revisions[0].rev.revision_id)
1296
def test_many_revisions(self):
1297
tree = self.setup_ab_tree()
1299
start_rev = revisionspec.RevisionInfo(tree.branch, None, b'1a')
1300
end_rev = revisionspec.RevisionInfo(tree.branch, None, b'3a')
1301
log.show_log(tree.branch, lf, verbose=True, start_revision=start_rev,
1302
end_revision=end_rev)
1303
self.assertEqual(3, len(lf.revisions))
1304
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1305
self.assertEqual(b'3a', lf.revisions[0].rev.revision_id)
1306
self.assertEqual(None, lf.revisions[1].revno) # Out-of-branch
1307
self.assertEqual(b'2a', lf.revisions[1].rev.revision_id)
1308
self.assertEqual('1', lf.revisions[2].revno) # In-branch
1310
def test_long_format(self):
1311
tree = self.setup_ab_tree()
1312
start_rev = revisionspec.RevisionInfo(tree.branch, None, b'1a')
1313
end_rev = revisionspec.RevisionInfo(tree.branch, None, b'3a')
1314
self.assertFormatterResult(b"""\
1315
------------------------------------------------------------
1317
committer: Joe Foo <joe@foo.com>
1319
timestamp: Tue 2005-11-22 00:00:00 +0000
1322
------------------------------------------------------------
1324
committer: Joe Foo <joe@foo.com>
1326
timestamp: Tue 2005-11-22 00:00:00 +0000
1329
------------------------------------------------------------
1331
committer: Joe Foo <joe@foo.com>
1333
timestamp: Tue 2005-11-22 00:00:00 +0000
1337
tree.branch, log.LongLogFormatter, show_log_kwargs={
1338
'start_revision': start_rev, 'end_revision': end_rev
1341
def test_short_format(self):
1342
tree = self.setup_ab_tree()
1343
start_rev = revisionspec.RevisionInfo(tree.branch, None, b'1a')
1344
end_rev = revisionspec.RevisionInfo(tree.branch, None, b'3a')
1345
self.assertFormatterResult(b"""\
1354
1 Joe Foo\t2005-11-22
1358
tree.branch, log.ShortLogFormatter, show_log_kwargs={
1359
'start_revision': start_rev, 'end_revision': end_rev
1362
def test_line_format(self):
1363
tree = self.setup_ab_tree()
1364
start_rev = revisionspec.RevisionInfo(tree.branch, None, b'1a')
1365
end_rev = revisionspec.RevisionInfo(tree.branch, None, b'3a')
1366
self.assertFormatterResult(b"""\
1367
Joe Foo 2005-11-22 commit 3a
1368
Joe Foo 2005-11-22 commit 2a
1369
1: Joe Foo 2005-11-22 commit 1a
1371
tree.branch, log.LineLogFormatter, show_log_kwargs={
1372
'start_revision': start_rev, 'end_revision': end_rev
1467
1376
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1469
1378
def setUp(self):
1470
TestCaseForLogFormatter.setUp(self)
1379
super(TestLogWithBugs, self).setUp()
1471
1380
log.properties_handler_registry.register(
1472
1381
'bugs_properties_handler',
1473
1382
log._bugs_properties_handler)
1504
1412
------------------------------------------------------------
1506
fixes bug(s): test://bug/id
1414
fixes bug: test://bug/id
1507
1415
committer: Joe Foo <joe@foo.com>
1508
1416
branch nick: work
1509
1417
timestamp: Tue 2005-11-22 00:00:00 +0000
1511
1419
simple log message
1513
tree.branch, log.LongLogFormatter)
1421
tree.branch, log.LongLogFormatter)
1515
1423
def test_short_bugs(self):
1516
1424
tree = self.make_commits_with_bugs()
1517
self.assertFormatterResult("""\
1425
self.assertFormatterResult(b"""\
1518
1426
2 Joe Bar\t2005-11-22
1519
fixes bug(s): test://bug/id test://bug/2
1427
fixes bugs: test://bug/id test://bug/2
1524
1432
1 Joe Foo\t2005-11-22
1525
fixes bug(s): test://bug/id
1433
fixes bug: test://bug/id
1526
1434
simple log message
1529
tree.branch, log.ShortLogFormatter)
1437
tree.branch, log.ShortLogFormatter)
1531
1439
def test_wrong_bugs_property(self):
1532
1440
tree = self.make_branch_and_tree(u'.')
1533
1441
self.build_tree(['foo'])
1534
self.wt_commit(tree, 'simple log message', rev_id='a1',
1535
revprops={'bugs': 'test://bug/id invalid_value'})
1536
self.assertFormatterResult("""\
1442
self.wt_commit(tree, 'simple log message', rev_id=b'a1',
1443
revprops={u'bugs': 'test://bug/id invalid_value'})
1444
self.assertFormatterResult(b"""\
1537
1445
1 Joe Foo\t2005-11-22
1538
1446
simple log message
1541
tree.branch, log.ShortLogFormatter)
1449
tree.branch, log.ShortLogFormatter)
1543
1451
def test_bugs_handler_present(self):
1544
1452
self.properties_handler_registry.get('bugs_properties_handler')
1455
class TestLogForAuthors(TestCaseForLogFormatter):
1458
super(TestLogForAuthors, self).setUp()
1459
self.wt = self.make_standard_commit('nicky',
1460
authors=['John Doe <jdoe@example.com>',
1461
'Jane Rey <jrey@example.com>'])
1463
def assertFormatterResult(self, formatter, who, result):
1464
formatter_kwargs = dict()
1466
author_list_handler = log.author_list_registry.get(who)
1467
formatter_kwargs['author_list_handler'] = author_list_handler
1468
TestCaseForLogFormatter.assertFormatterResult(self, result,
1469
self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1471
def test_line_default(self):
1472
self.assertFormatterResult(log.LineLogFormatter, None, b"""\
1473
1: John Doe 2005-11-22 add a
1476
def test_line_committer(self):
1477
self.assertFormatterResult(log.LineLogFormatter, 'committer', b"""\
1478
1: Lorem Ipsum 2005-11-22 add a
1481
def test_line_first(self):
1482
self.assertFormatterResult(log.LineLogFormatter, 'first', b"""\
1483
1: John Doe 2005-11-22 add a
1486
def test_line_all(self):
1487
self.assertFormatterResult(log.LineLogFormatter, 'all', b"""\
1488
1: John Doe, Jane Rey 2005-11-22 add a
1491
def test_short_default(self):
1492
self.assertFormatterResult(log.ShortLogFormatter, None, b"""\
1493
1 John Doe\t2005-11-22
1498
def test_short_committer(self):
1499
self.assertFormatterResult(log.ShortLogFormatter, 'committer', b"""\
1500
1 Lorem Ipsum\t2005-11-22
1505
def test_short_first(self):
1506
self.assertFormatterResult(log.ShortLogFormatter, 'first', b"""\
1507
1 John Doe\t2005-11-22
1512
def test_short_all(self):
1513
self.assertFormatterResult(log.ShortLogFormatter, 'all', b"""\
1514
1 John Doe, Jane Rey\t2005-11-22
1519
def test_long_default(self):
1520
self.assertFormatterResult(log.LongLogFormatter, None, b"""\
1521
------------------------------------------------------------
1523
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1524
committer: Lorem Ipsum <test@example.com>
1526
timestamp: Tue 2005-11-22 00:00:00 +0000
1531
def test_long_committer(self):
1532
self.assertFormatterResult(log.LongLogFormatter, 'committer', b"""\
1533
------------------------------------------------------------
1535
committer: Lorem Ipsum <test@example.com>
1537
timestamp: Tue 2005-11-22 00:00:00 +0000
1542
def test_long_first(self):
1543
self.assertFormatterResult(log.LongLogFormatter, 'first', b"""\
1544
------------------------------------------------------------
1546
author: John Doe <jdoe@example.com>
1547
committer: Lorem Ipsum <test@example.com>
1549
timestamp: Tue 2005-11-22 00:00:00 +0000
1554
def test_long_all(self):
1555
self.assertFormatterResult(log.LongLogFormatter, 'all', b"""\
1556
------------------------------------------------------------
1558
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1559
committer: Lorem Ipsum <test@example.com>
1561
timestamp: Tue 2005-11-22 00:00:00 +0000
1566
def test_gnu_changelog_default(self):
1567
self.assertFormatterResult(log.GnuChangelogLogFormatter, None, b"""\
1568
2005-11-22 John Doe <jdoe@example.com>
1574
def test_gnu_changelog_committer(self):
1575
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', b"""\
1576
2005-11-22 Lorem Ipsum <test@example.com>
1582
def test_gnu_changelog_first(self):
1583
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', b"""\
1584
2005-11-22 John Doe <jdoe@example.com>
1590
def test_gnu_changelog_all(self):
1591
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'all', b"""\
1592
2005-11-22 John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1546
1599
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1548
1601
def make_branch_with_alternate_ancestries(self, relpath='.'):
1549
1602
# See test_merge_sorted_exclude_ancestry below for the difference with
1550
1603
# bt.per_branch.test_iter_merge_sorted_revision.
1551
# TestIterMergeSortedRevisionsBushyGraph.
1604
# TestIterMergeSortedRevisionsBushyGraph.
1552
1605
# make_branch_with_alternate_ancestries
1553
1606
# and test_merge_sorted_exclude_ancestry
1554
1607
# See the FIXME in assertLogRevnos too.
1581
1635
def assertLogRevnos(self, expected_revnos, b, start, end,
1582
exclude_common_ancestry):
1636
exclude_common_ancestry, generate_merge_revisions=True):
1583
1637
# FIXME: the layering in log makes it hard to test intermediate levels,
1584
# I wish adding filters with their parameters were easier...
1638
# I wish adding filters with their parameters was easier...
1585
1639
# -- vila 20100413
1586
1640
iter_revs = log._calc_view_revisions(
1587
1641
b, start, end, direction='reverse',
1588
generate_merge_revisions=True,
1642
generate_merge_revisions=generate_merge_revisions,
1589
1643
exclude_common_ancestry=exclude_common_ancestry)
1590
1644
self.assertEqual(expected_revnos,
1591
1645
[revid for revid, revno, depth in iter_revs])
1593
1647
def test_merge_sorted_exclude_ancestry(self):
1594
1648
b = self.make_branch_with_alternate_ancestries()
1595
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1649
self.assertLogRevnos([b'3', b'1.1.2', b'1.2.1', b'1.1.1', b'2', b'1'],
1650
b, b'1', b'3', exclude_common_ancestry=False)
1597
1651
# '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1598
1652
# it should be mentioned even if merge_sort order will make it appear
1600
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1601
b, '1.1.1', '3', True)
1654
self.assertLogRevnos([b'3', b'1.1.2', b'1.2.1', b'2'],
1655
b, b'1.1.1', b'3', exclude_common_ancestry=True)
1657
def test_merge_sorted_simple_revnos_exclude_ancestry(self):
1658
b = self.make_branch_with_alternate_ancestries()
1659
self.assertLogRevnos([b'3', b'2'],
1660
b, b'1', b'3', exclude_common_ancestry=True,
1661
generate_merge_revisions=False)
1662
self.assertLogRevnos([b'3', b'1.1.2', b'1.2.1', b'1.1.1', b'2'],
1663
b, b'1', b'3', exclude_common_ancestry=True,
1664
generate_merge_revisions=True)
1667
class TestLogDefaults(TestCaseForLogFormatter):
1668
def test_default_log_level(self):
1670
Test to ensure that specifying 'levels=1' to make_log_request_dict
1671
doesn't get overwritten when using a LogFormatter that supports more
1675
wt = self._prepare_tree_with_merges()
1678
class CustomLogFormatter(log.LogFormatter):
1679
def __init__(self, *args, **kwargs):
1680
super(CustomLogFormatter, self).__init__(*args, **kwargs)
1683
def get_levels(self):
1684
# log formatter supports all levels:
1687
def log_revision(self, revision):
1688
self.revisions.append(revision)
1690
log_formatter = LogCatcher()
1691
# First request we don't specify number of levels, we should get a
1692
# sensible default (whatever the LogFormatter handles - which in this
1693
# case is 0/everything):
1694
request = log.make_log_request_dict(limit=10)
1695
log.Logger(b, request).show(log_formatter)
1696
# should have all three revisions:
1697
self.assertEqual(len(log_formatter.revisions), 3)
1700
log_formatter = LogCatcher()
1701
# now explicitly request mainline revisions only:
1702
request = log.make_log_request_dict(limit=10, levels=1)
1703
log.Logger(b, request).show(log_formatter)
1704
# should now only have 2 revisions:
1705
self.assertEqual(len(log_formatter.revisions), 2)