877
945
formatter_kwargs=dict(levels=0))
880
class TestGetViewRevisions(tests.TestCaseWithTransport, TestLogMixin):
882
def _get_view_revisions(self, *args, **kwargs):
883
return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
884
log.get_view_revisions, *args, **kwargs)
886
def make_tree_with_commits(self):
887
"""Create a tree with well-known revision ids"""
888
wt = self.make_branch_and_tree('tree1')
889
self.wt_commit(wt, 'commit one', rev_id='1')
890
self.wt_commit(wt, 'commit two', rev_id='2')
891
self.wt_commit(wt, 'commit three', rev_id='3')
892
mainline_revs = [None, '1', '2', '3']
893
rev_nos = {'1': 1, '2': 2, '3': 3}
894
return mainline_revs, rev_nos, wt
896
def make_tree_with_merges(self):
897
"""Create a tree with well-known revision ids and a merge"""
898
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
899
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
900
self.wt_commit(tree2, 'four-a', rev_id='4a')
901
wt.merge_from_branch(tree2.branch)
902
self.wt_commit(wt, 'four-b', rev_id='4b')
903
mainline_revs.append('4b')
906
return mainline_revs, rev_nos, wt
908
def make_branch_with_many_merges(self):
909
"""Create a tree with well-known revision ids"""
910
builder = self.make_branch_builder('tree1')
911
builder.start_series()
912
builder.build_snapshot('1', None, [
913
('add', ('', 'TREE_ROOT', 'directory', '')),
914
('add', ('f', 'f-id', 'file', '1\n'))])
915
builder.build_snapshot('2', ['1'], [])
916
builder.build_snapshot('3a', ['2'], [
917
('modify', ('f-id', '1\n2\n3a\n'))])
918
builder.build_snapshot('3b', ['2', '3a'], [
919
('modify', ('f-id', '1\n2\n3a\n'))])
920
builder.build_snapshot('3c', ['2', '3b'], [
921
('modify', ('f-id', '1\n2\n3a\n'))])
922
builder.build_snapshot('4a', ['3b'], [])
923
builder.build_snapshot('4b', ['3c', '4a'], [])
924
builder.finish_series()
938
mainline_revs = [None, '1', '2', '3c', '4b']
939
rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
940
full_rev_nos_for_reference = {
943
'3a': '2.1.1', #first commit tree 3
944
'3b': '2.2.1', # first commit tree 2
945
'3c': '3', #merges 3b to main
946
'4a': '2.2.2', # second commit tree 2
947
'4b': '4', # merges 4a to main
949
return mainline_revs, rev_nos, builder.get_branch()
951
def test_get_view_revisions_forward(self):
952
"""Test the get_view_revisions method"""
953
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
955
self.addCleanup(wt.unlock)
956
revisions = list(self._get_view_revisions(
957
mainline_revs, rev_nos, wt.branch, 'forward'))
958
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
960
revisions2 = list(self._get_view_revisions(
961
mainline_revs, rev_nos, wt.branch, 'forward',
962
include_merges=False))
963
self.assertEqual(revisions, revisions2)
965
def test_get_view_revisions_reverse(self):
966
"""Test the get_view_revisions with reverse"""
967
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
969
self.addCleanup(wt.unlock)
970
revisions = list(self._get_view_revisions(
971
mainline_revs, rev_nos, wt.branch, 'reverse'))
972
self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
974
revisions2 = list(self._get_view_revisions(
975
mainline_revs, rev_nos, wt.branch, 'reverse',
976
include_merges=False))
977
self.assertEqual(revisions, revisions2)
979
def test_get_view_revisions_merge(self):
980
"""Test get_view_revisions when there are merges"""
981
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
983
self.addCleanup(wt.unlock)
984
revisions = list(self._get_view_revisions(
985
mainline_revs, rev_nos, wt.branch, 'forward'))
986
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
987
('4b', '4', 0), ('4a', '3.1.1', 1)],
989
revisions = list(self._get_view_revisions(
990
mainline_revs, rev_nos, wt.branch, 'forward',
991
include_merges=False))
992
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
996
def test_get_view_revisions_merge_reverse(self):
997
"""Test get_view_revisions in reverse when there are merges"""
998
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1000
self.addCleanup(wt.unlock)
1001
revisions = list(self._get_view_revisions(
1002
mainline_revs, rev_nos, wt.branch, 'reverse'))
1003
self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
1004
('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
1006
revisions = list(self._get_view_revisions(
1007
mainline_revs, rev_nos, wt.branch, 'reverse',
1008
include_merges=False))
1009
self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
1013
def test_get_view_revisions_merge2(self):
1014
"""Test get_view_revisions when there are merges"""
1015
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1017
self.addCleanup(b.unlock)
1018
revisions = list(self._get_view_revisions(
1019
mainline_revs, rev_nos, b, 'forward'))
1020
expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1021
('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1023
self.assertEqual(expected, revisions)
1024
revisions = list(self._get_view_revisions(
1025
mainline_revs, rev_nos, b, 'forward',
1026
include_merges=False))
1027
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1031
def test_file_id_for_range(self):
1032
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1034
self.addCleanup(b.unlock)
1036
def rev_from_rev_id(revid, branch):
1037
revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1038
return revspec.in_history(branch)
1040
def view_revs(start_rev, end_rev, file_id, direction):
1041
revs = self.applyDeprecated(
1042
symbol_versioning.deprecated_in((2, 2, 0)),
1043
log.calculate_view_revisions,
1045
start_rev, # start_revision
1046
end_rev, # end_revision
1047
direction, # direction
1048
file_id, # specific_fileid
1049
True, # generate_merge_revisions
1053
rev_3a = rev_from_rev_id('3a', b)
1054
rev_4b = rev_from_rev_id('4b', b)
1055
self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
1056
('3a', '2.1.1', 2)],
1057
view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
1058
# Note: 3c still appears before 3a here because of depth-based sorting
1059
self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
1060
('3a', '2.1.1', 2)],
1061
view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1064
class TestGetRevisionsTouchingFileID(tests.TestCaseWithTransport):
1066
def get_view_revisions(self, *args):
1067
return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
1068
log.get_view_revisions, *args)
1070
def create_tree_with_single_merge(self):
1071
"""Create a branch with a moderate layout.
1073
The revision graph looks like:
1081
In this graph, A introduced files f1 and f2 and f3.
1082
B modifies f1 and f3, and C modifies f2 and f3.
1083
D merges the changes from B and C and resolves the conflict for f3.
1085
# TODO: jam 20070218 This seems like it could really be done
1086
# with make_branch_and_memory_tree() if we could just
1087
# create the content of those files.
1088
# TODO: jam 20070218 Another alternative is that we would really
1089
# like to only create this tree 1 time for all tests that
1090
# use it. Since 'log' only uses the tree in a readonly
1091
# fashion, it seems a shame to regenerate an identical
1092
# tree for each test.
1093
# TODO: vila 20100122 One way to address the shame above will be to
1094
# create a memory tree during test parametrization and give a
1095
# *copy* of this tree to each test. Copying a memory tree ought
1096
# to be cheap, at least cheaper than creating them with such
1098
tree = self.make_branch_and_tree('tree')
1100
self.addCleanup(tree.unlock)
1102
self.build_tree_contents([('tree/f1', 'A\n'),
1106
tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
1107
tree.commit('A', rev_id='A')
1109
self.build_tree_contents([('tree/f2', 'A\nC\n'),
1110
('tree/f3', 'A\nC\n'),
1112
tree.commit('C', rev_id='C')
1113
# Revert back to A to build the other history.
1114
tree.set_last_revision('A')
1115
tree.branch.set_last_revision_info(1, 'A')
1116
self.build_tree_contents([('tree/f1', 'A\nB\n'),
1118
('tree/f3', 'A\nB\n'),
1120
tree.commit('B', rev_id='B')
1121
tree.set_parent_ids(['B', 'C'])
1122
self.build_tree_contents([('tree/f1', 'A\nB\n'),
1123
('tree/f2', 'A\nC\n'),
1124
('tree/f3', 'A\nB\nC\n'),
1126
tree.commit('D', rev_id='D')
1128
# Switch to a read lock for this tree.
1129
# We still have an addCleanup(tree.unlock) pending
1134
def check_delta(self, delta, **kw):
1135
"""Check the filenames touched by a delta are as expected.
1137
Caller only have to pass in the list of files for each part, all
1138
unspecified parts are considered empty (and checked as such).
1140
for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
1141
# By default we expect an empty list
1142
expected = kw.get(n, [])
1143
# strip out only the path components
1144
got = [x[0] for x in getattr(delta, n)]
1145
self.assertEqual(expected, got)
1147
def test_tree_with_single_merge(self):
1148
"""Make sure the tree layout is correct."""
1149
tree = self.create_tree_with_single_merge()
1150
rev_A_tree = tree.branch.repository.revision_tree('A')
1151
rev_B_tree = tree.branch.repository.revision_tree('B')
1152
rev_C_tree = tree.branch.repository.revision_tree('C')
1153
rev_D_tree = tree.branch.repository.revision_tree('D')
1155
self.check_delta(rev_B_tree.changes_from(rev_A_tree),
1156
modified=['f1', 'f3'])
1158
self.check_delta(rev_C_tree.changes_from(rev_A_tree),
1159
modified=['f2', 'f3'])
1161
self.check_delta(rev_D_tree.changes_from(rev_B_tree),
1162
modified=['f2', 'f3'])
1164
self.check_delta(rev_D_tree.changes_from(rev_C_tree),
1165
modified=['f1', 'f3'])
1167
def assertAllRevisionsForFileID(self, tree, file_id, revisions):
1168
"""Ensure _filter_revisions_touching_file_id returns the right values.
1170
Get the return value from _filter_revisions_touching_file_id and make
1171
sure they are correct.
1173
# The api for _filter_revisions_touching_file_id is a little crazy.
1174
# So we do the setup here.
1175
mainline = tree.branch.revision_history()
1176
mainline.insert(0, None)
1177
revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
1178
view_revs_iter = self.get_view_revisions(
1179
mainline, revnos, tree.branch, 'reverse', True)
1180
actual_revs = log._filter_revisions_touching_file_id(
1181
tree.branch, file_id, list(view_revs_iter))
1182
self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
1184
def test_file_id_f1(self):
1185
tree = self.create_tree_with_single_merge()
1186
# f1 should be marked as modified by revisions A and B
1187
self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
1189
def test_file_id_f2(self):
1190
tree = self.create_tree_with_single_merge()
1191
# f2 should be marked as modified by revisions A, C, and D
1192
# because D merged the changes from C.
1193
self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1195
def test_file_id_f3(self):
1196
tree = self.create_tree_with_single_merge()
1197
# f3 should be marked as modified by revisions A, B, C, and D
1198
self.assertAllRevisionsForFileID(tree, 'f3-id', ['D', 'C', 'B', 'A'])
1200
def test_file_id_with_ghosts(self):
1201
# This is testing bug #209948, where having a ghost would cause
1202
# _filter_revisions_touching_file_id() to fail.
1203
tree = self.create_tree_with_single_merge()
1204
# We need to add a revision, so switch back to a write-locked tree
1205
# (still a single addCleanup(tree.unlock) pending).
1208
first_parent = tree.last_revision()
1209
tree.set_parent_ids([first_parent, 'ghost-revision-id'])
1210
self.build_tree_contents([('tree/f1', 'A\nB\nXX\n')])
1211
tree.commit('commit with a ghost', rev_id='XX')
1212
self.assertAllRevisionsForFileID(tree, 'f1-id', ['XX', 'B', 'A'])
1213
self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1215
def test_unknown_file_id(self):
1216
tree = self.create_tree_with_single_merge()
1217
self.assertAllRevisionsForFileID(tree, 'unknown', [])
1219
def test_empty_branch_unknown_file_id(self):
1220
tree = self.make_branch_and_tree('tree')
1221
self.assertAllRevisionsForFileID(tree, 'unknown', [])
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))
1224
986
class TestShowChangedRevisions(tests.TestCaseWithTransport):
1425
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
1429
1309
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1505
1385
def test_bugs_handler_present(self):
1506
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 were 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)