18
18
from cStringIO import StringIO
20
20
from bzrlib import (
32
class TestLogMixin(object):
34
def wt_commit(self, wt, message, **kwargs):
35
"""Use some mostly fixed values for commits to simplify tests.
37
Tests can use this function to get some commit attributes. The time
38
stamp is incremented at each commit.
40
if getattr(self, 'timestamp', None) is None:
41
self.timestamp = 1132617600 # Mon 2005-11-22 00:00:00 +0000
43
self.timestamp += 1 # 1 second between each commit
44
kwargs.setdefault('timestamp', self.timestamp)
45
kwargs.setdefault('timezone', 0) # UTC
46
kwargs.setdefault('committer', 'Joe Foo <joe@foo.com>')
48
return wt.commit(message, **kwargs)
51
class TestCaseForLogFormatter(tests.TestCaseWithTransport, TestLogMixin):
30
class TestCaseForLogFormatter(tests.TestCaseWithTransport):
54
33
super(TestCaseForLogFormatter, self).setUp()
79
62
self.build_tree(['a'])
81
64
wt.branch.nick = branch_nick
66
kwargs.setdefault('message', 'add a')
67
kwargs.setdefault('timestamp', 1132711707)
68
kwargs.setdefault('timezone', 36000)
82
69
kwargs.setdefault('committer', 'Lorem Ipsum <test@example.com>')
83
70
kwargs.setdefault('authors', ['John Doe <jdoe@example.com>'])
84
self.wt_commit(wt, 'add a', **kwargs)
87
def make_commits_with_trailing_newlines(self, wt):
88
"""Helper method for LogFormatter tests"""
91
self.build_tree_contents([('a', 'hello moto\n')])
92
self.wt_commit(wt, 'simple log message', rev_id='a1')
93
self.build_tree_contents([('b', 'goodbye\n')])
95
self.wt_commit(wt, 'multiline\nlog\nmessage\n', rev_id='a2')
97
self.build_tree_contents([('c', 'just another manic monday\n')])
99
self.wt_commit(wt, 'single line with trailing newline\n', rev_id='a3')
102
74
def _prepare_tree_with_merges(self, with_tags=False):
103
75
wt = self.make_branch_and_memory_tree('.')
105
77
self.addCleanup(wt.unlock)
107
self.wt_commit(wt, 'rev-1', rev_id='rev-1')
108
self.wt_commit(wt, 'rev-merged', rev_id='rev-2a')
79
wt.commit('rev-1', rev_id='rev-1',
80
timestamp=1132586655, timezone=36000,
81
committer='Joe Foo <joe@foo.com>')
82
wt.commit('rev-merged', rev_id='rev-2a',
83
timestamp=1132586700, timezone=36000,
84
committer='Joe Foo <joe@foo.com>')
109
85
wt.set_parent_ids(['rev-1', 'rev-2a'])
110
86
wt.branch.set_last_revision_info(1, 'rev-1')
111
self.wt_commit(wt, 'rev-2', rev_id='rev-2b')
87
wt.commit('rev-2', rev_id='rev-2b',
88
timestamp=1132586800, timezone=36000,
89
committer='Joe Foo <joe@foo.com>')
113
91
branch = wt.branch
114
92
branch.tags.set_tag('v0.2', 'rev-2b')
115
self.wt_commit(wt, 'rev-3', rev_id='rev-3')
93
wt.commit('rev-3', rev_id='rev-3',
94
timestamp=1132586900, timezone=36000,
95
committer='Jane Foo <jane@foo.com>')
116
96
branch.tags.set_tag('v1.0rc1', 'rev-3')
117
97
branch.tags.set_tag('v1.0', 'rev-3')
120
103
class LogCatcher(log.LogFormatter):
121
104
"""Pull log messages into a list rather than displaying them.
281
260
self.checkDelta(logentry.delta, added=['file1', 'file2'])
263
def make_commits_with_trailing_newlines(wt):
264
"""Helper method for LogFormatter tests"""
267
open('a', 'wb').write('hello moto\n')
269
wt.commit('simple log message', rev_id='a1',
270
timestamp=1132586655.459960938, timezone=-6*3600,
271
committer='Joe Foo <joe@foo.com>')
272
open('b', 'wb').write('goodbye\n')
274
wt.commit('multiline\nlog\nmessage\n', rev_id='a2',
275
timestamp=1132586842.411175966, timezone=-6*3600,
276
committer='Joe Foo <joe@foo.com>',
277
authors=['Joe Bar <joe@bar.com>'])
279
open('c', 'wb').write('just another manic monday\n')
281
wt.commit('single line with trailing newline\n', rev_id='a3',
282
timestamp=1132587176.835228920, timezone=-6*3600,
283
committer = 'Joe Foo <joe@foo.com>')
287
def normalize_log(log):
288
"""Replaces the variable lines of logs with fixed lines"""
289
author = 'author: Dolor Sit <test@example.com>'
290
committer = 'committer: Lorem Ipsum <test@example.com>'
291
lines = log.splitlines(True)
292
for idx,line in enumerate(lines):
293
stripped_line = line.lstrip()
294
indent = ' ' * (len(line) - len(stripped_line))
295
if stripped_line.startswith('author:'):
296
lines[idx] = indent + author + '\n'
297
elif stripped_line.startswith('committer:'):
298
lines[idx] = indent + committer + '\n'
299
elif stripped_line.startswith('timestamp:'):
300
lines[idx] = indent + 'timestamp: Just now\n'
301
return ''.join(lines)
284
304
class TestShortLogFormatter(TestCaseForLogFormatter):
286
306
def test_trailing_newlines(self):
287
307
wt = self.make_branch_and_tree('.')
288
b = self.make_commits_with_trailing_newlines(wt)
308
b = make_commits_with_trailing_newlines(wt)
289
309
self.assertFormatterResult("""\
290
3 Joe Foo\t2005-11-22
310
3 Joe Foo\t2005-11-21
291
311
single line with trailing newline
293
2 Joe Foo\t2005-11-22
313
2 Joe Bar\t2005-11-21
298
1 Joe Foo\t2005-11-22
318
1 Joe Foo\t2005-11-21
299
319
simple log message
328
348
formatter_kwargs=dict(show_advice=True))
330
350
def test_short_log_with_merges_and_range(self):
331
wt = self._prepare_tree_with_merges()
332
self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
351
wt = self.make_branch_and_memory_tree('.')
353
self.addCleanup(wt.unlock)
355
wt.commit('rev-1', rev_id='rev-1',
356
timestamp=1132586655, timezone=36000,
357
committer='Joe Foo <joe@foo.com>')
358
wt.commit('rev-merged', rev_id='rev-2a',
359
timestamp=1132586700, timezone=36000,
360
committer='Joe Foo <joe@foo.com>')
361
wt.branch.set_last_revision_info(1, 'rev-1')
362
wt.set_parent_ids(['rev-1', 'rev-2a'])
363
wt.commit('rev-2b', rev_id='rev-2b',
364
timestamp=1132586800, timezone=36000,
365
committer='Joe Foo <joe@foo.com>')
366
wt.commit('rev-3a', rev_id='rev-3a',
367
timestamp=1132586800, timezone=36000,
368
committer='Joe Foo <joe@foo.com>')
333
369
wt.branch.set_last_revision_info(2, 'rev-2b')
334
370
wt.set_parent_ids(['rev-2b', 'rev-3a'])
335
self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
371
wt.commit('rev-3b', rev_id='rev-3b',
372
timestamp=1132586800, timezone=36000,
373
committer='Joe Foo <joe@foo.com>')
336
374
self.assertFormatterResult("""\
337
375
3 Joe Foo\t2005-11-22 [merge]
340
378
2 Joe Foo\t2005-11-22 [merge]
344
382
wt.branch, log.ShortLogFormatter,
360
398
wt.branch, log.ShortLogFormatter)
362
400
def test_short_log_single_merge_revision(self):
363
wt = self._prepare_tree_with_merges()
401
wt = self.make_branch_and_memory_tree('.')
403
self.addCleanup(wt.unlock)
405
wt.commit('rev-1', rev_id='rev-1',
406
timestamp=1132586655, timezone=36000,
407
committer='Joe Foo <joe@foo.com>')
408
wt.commit('rev-merged', rev_id='rev-2a',
409
timestamp=1132586700, timezone=36000,
410
committer='Joe Foo <joe@foo.com>')
411
wt.set_parent_ids(['rev-1', 'rev-2a'])
412
wt.branch.set_last_revision_info(1, 'rev-1')
413
wt.commit('rev-2', rev_id='rev-2b',
414
timestamp=1132586800, timezone=36000,
415
committer='Joe Foo <joe@foo.com>')
364
416
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
365
417
rev = revspec.in_history(wt.branch)
366
418
self.assertFormatterResult("""\
375
427
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
377
429
def test_short_merge_revs_log_with_merges(self):
378
wt = self._prepare_tree_with_merges()
430
wt = self.make_branch_and_memory_tree('.')
432
self.addCleanup(wt.unlock)
434
wt.commit('rev-1', rev_id='rev-1',
435
timestamp=1132586655, timezone=36000,
436
committer='Joe Foo <joe@foo.com>')
437
wt.commit('rev-merged', rev_id='rev-2a',
438
timestamp=1132586700, timezone=36000,
439
committer='Joe Foo <joe@foo.com>')
440
wt.set_parent_ids(['rev-1', 'rev-2a'])
441
wt.branch.set_last_revision_info(1, 'rev-1')
442
wt.commit('rev-2', rev_id='rev-2b',
443
timestamp=1132586800, timezone=36000,
444
committer='Joe Foo <joe@foo.com>')
379
445
# Note that the 1.1.1 indenting is in fact correct given that
380
446
# the revision numbers are right justified within 5 characters
381
447
# for mainline revnos and 9 characters for dotted revnos.
394
460
formatter_kwargs=dict(levels=0))
396
462
def test_short_merge_revs_log_single_merge_revision(self):
397
wt = self._prepare_tree_with_merges()
463
wt = self.make_branch_and_memory_tree('.')
465
self.addCleanup(wt.unlock)
467
wt.commit('rev-1', rev_id='rev-1',
468
timestamp=1132586655, timezone=36000,
469
committer='Joe Foo <joe@foo.com>')
470
wt.commit('rev-merged', rev_id='rev-2a',
471
timestamp=1132586700, timezone=36000,
472
committer='Joe Foo <joe@foo.com>')
473
wt.set_parent_ids(['rev-1', 'rev-2a'])
474
wt.branch.set_last_revision_info(1, 'rev-1')
475
wt.commit('rev-2', rev_id='rev-2b',
476
timestamp=1132586800, timezone=36000,
477
committer='Joe Foo <joe@foo.com>')
398
478
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
399
479
rev = revspec.in_history(wt.branch)
400
480
self.assertFormatterResult("""\
432
512
def test_merges_are_indented_by_level(self):
433
513
wt = self.make_branch_and_tree('parent')
434
self.wt_commit(wt, 'first post')
435
child_wt = wt.bzrdir.sprout('child').open_workingtree()
436
self.wt_commit(child_wt, 'branch 1')
437
smallerchild_wt = wt.bzrdir.sprout('smallerchild').open_workingtree()
438
self.wt_commit(smallerchild_wt, 'branch 2')
439
child_wt.merge_from_branch(smallerchild_wt.branch)
440
self.wt_commit(child_wt, 'merge branch 2')
441
wt.merge_from_branch(child_wt.branch)
442
self.wt_commit(wt, 'merge branch 1')
514
wt.commit('first post')
515
self.run_bzr('branch parent child')
516
self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
517
self.run_bzr('branch child smallerchild')
518
self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
521
self.run_bzr('merge ../smallerchild')
522
self.run_bzr(['commit', '-m', 'merge branch 2'])
523
os.chdir('../parent')
524
self.run_bzr('merge ../child')
525
wt.commit('merge branch 1')
443
526
self.assertFormatterResult("""\
444
527
------------------------------------------------------------
446
committer: Joe Foo <joe@foo.com>
529
committer: Lorem Ipsum <test@example.com>
447
530
branch nick: parent
448
timestamp: Tue 2005-11-22 00:00:04 +0000
451
534
------------------------------------------------------------
452
535
revno: 1.1.2 [merge]
453
committer: Joe Foo <joe@foo.com>
536
committer: Lorem Ipsum <test@example.com>
454
537
branch nick: child
455
timestamp: Tue 2005-11-22 00:00:03 +0000
458
541
------------------------------------------------------------
460
committer: Joe Foo <joe@foo.com>
543
committer: Lorem Ipsum <test@example.com>
461
544
branch nick: smallerchild
462
timestamp: Tue 2005-11-22 00:00:02 +0000
465
548
------------------------------------------------------------
467
committer: Joe Foo <joe@foo.com>
550
committer: Lorem Ipsum <test@example.com>
468
551
branch nick: child
469
timestamp: Tue 2005-11-22 00:00:01 +0000
472
555
------------------------------------------------------------
474
committer: Joe Foo <joe@foo.com>
557
committer: Lorem Ipsum <test@example.com>
475
558
branch nick: parent
476
timestamp: Tue 2005-11-22 00:00:00 +0000
480
563
wt.branch, log.LongLogFormatter,
481
564
formatter_kwargs=dict(levels=0),
482
show_log_kwargs=dict(verbose=True))
565
show_log_kwargs=dict(verbose=True),
484
568
def test_verbose_merge_revisions_contain_deltas(self):
485
569
wt = self.make_branch_and_tree('parent')
486
570
self.build_tree(['parent/f1', 'parent/f2'])
487
571
wt.add(['f1','f2'])
488
self.wt_commit(wt, 'first post')
489
child_wt = wt.bzrdir.sprout('child').open_workingtree()
572
wt.commit('first post')
573
self.run_bzr('branch parent child')
490
574
os.unlink('child/f1')
491
self.build_tree_contents([('child/f2', 'hello\n')])
492
self.wt_commit(child_wt, 'removed f1 and modified f2')
493
wt.merge_from_branch(child_wt.branch)
494
self.wt_commit(wt, 'merge branch 1')
575
file('child/f2', 'wb').write('hello\n')
576
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
579
self.run_bzr('merge ../child')
580
wt.commit('merge branch 1')
495
581
self.assertFormatterResult("""\
496
582
------------------------------------------------------------
498
committer: Joe Foo <joe@foo.com>
584
committer: Lorem Ipsum <test@example.com>
499
585
branch nick: parent
500
timestamp: Tue 2005-11-22 00:00:02 +0000
529
615
wt.branch, log.LongLogFormatter,
530
616
formatter_kwargs=dict(levels=0),
531
show_log_kwargs=dict(verbose=True))
617
show_log_kwargs=dict(verbose=True),
533
620
def test_trailing_newlines(self):
534
621
wt = self.make_branch_and_tree('.')
535
b = self.make_commits_with_trailing_newlines(wt)
622
b = make_commits_with_trailing_newlines(wt)
536
623
self.assertFormatterResult("""\
537
624
------------------------------------------------------------
539
626
committer: Joe Foo <joe@foo.com>
540
627
branch nick: test
541
timestamp: Tue 2005-11-22 00:00:02 +0000
628
timestamp: Mon 2005-11-21 09:32:56 -0600
543
630
single line with trailing newline
544
631
------------------------------------------------------------
633
author: Joe Bar <joe@bar.com>
546
634
committer: Joe Foo <joe@foo.com>
547
635
branch nick: test
548
timestamp: Tue 2005-11-22 00:00:01 +0000
636
timestamp: Mon 2005-11-21 09:27:22 -0600
720
808
wt.branch, log.LongLogFormatter,
721
809
formatter_kwargs=dict(levels=1),
722
show_log_kwargs=dict(verbose=True))
810
show_log_kwargs=dict(verbose=True),
724
813
def test_long_trailing_newlines(self):
725
814
wt = self.make_branch_and_tree('.')
726
b = self.make_commits_with_trailing_newlines(wt)
815
b = make_commits_with_trailing_newlines(wt)
727
816
self.assertFormatterResult("""\
728
817
------------------------------------------------------------
730
819
committer: Joe Foo <joe@foo.com>
731
820
branch nick: test
732
timestamp: Tue 2005-11-22 00:00:02 +0000
821
timestamp: Mon 2005-11-21 09:32:56 -0600
734
823
single line with trailing newline
735
824
------------------------------------------------------------
826
author: Joe Bar <joe@bar.com>
737
827
committer: Joe Foo <joe@foo.com>
738
828
branch nick: test
739
timestamp: Tue 2005-11-22 00:00:01 +0000
829
timestamp: Mon 2005-11-21 09:27:22 -0600
852
942
committer='Line-Log-Formatter Tester <test@line.log>',
854
944
self.assertFormatterResult("""\
855
1: Line-Log-Formatte... 2005-11-22 add a
945
1: Line-Log-Formatte... 2005-11-23 add a
857
947
wt.branch, log.LineLogFormatter)
859
949
def test_line_merge_revs_log_single_merge_revision(self):
860
wt = self._prepare_tree_with_merges()
950
wt = self.make_branch_and_memory_tree('.')
952
self.addCleanup(wt.unlock)
954
wt.commit('rev-1', rev_id='rev-1',
955
timestamp=1132586655, timezone=36000,
956
committer='Joe Foo <joe@foo.com>')
957
wt.commit('rev-merged', rev_id='rev-2a',
958
timestamp=1132586700, timezone=36000,
959
committer='Joe Foo <joe@foo.com>')
960
wt.set_parent_ids(['rev-1', 'rev-2a'])
961
wt.branch.set_last_revision_info(1, 'rev-1')
962
wt.commit('rev-2', rev_id='rev-2b',
963
timestamp=1132586800, timezone=36000,
964
committer='Joe Foo <joe@foo.com>')
861
965
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
862
966
rev = revspec.in_history(wt.branch)
863
967
self.assertFormatterResult("""\
868
972
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
870
974
def test_line_merge_revs_log_with_merges(self):
871
wt = self._prepare_tree_with_merges()
975
wt = self.make_branch_and_memory_tree('.')
977
self.addCleanup(wt.unlock)
979
wt.commit('rev-1', rev_id='rev-1',
980
timestamp=1132586655, timezone=36000,
981
committer='Joe Foo <joe@foo.com>')
982
wt.commit('rev-merged', rev_id='rev-2a',
983
timestamp=1132586700, timezone=36000,
984
committer='Joe Foo <joe@foo.com>')
985
wt.set_parent_ids(['rev-1', 'rev-2a'])
986
wt.branch.set_last_revision_info(1, 'rev-1')
987
wt.commit('rev-2', rev_id='rev-2b',
988
timestamp=1132586800, timezone=36000,
989
committer='Joe Foo <joe@foo.com>')
872
990
self.assertFormatterResult("""\
873
991
2: Joe Foo 2005-11-22 [merge] rev-2
874
992
1.1.1: Joe Foo 2005-11-22 rev-merged
878
996
formatter_kwargs=dict(levels=0))
881
class TestGnuChangelogFormatter(TestCaseForLogFormatter):
883
def test_gnu_changelog(self):
884
wt = self.make_standard_commit('nicky', authors=[])
885
self.assertFormatterResult('''\
886
2005-11-22 Lorem Ipsum <test@example.com>
891
wt.branch, log.GnuChangelogLogFormatter)
893
def test_with_authors(self):
894
wt = self.make_standard_commit('nicky',
895
authors=['Fooa Fooz <foo@example.com>',
896
'Bari Baro <bar@example.com>'])
897
self.assertFormatterResult('''\
898
2005-11-22 Fooa Fooz <foo@example.com>
903
wt.branch, log.GnuChangelogLogFormatter)
905
def test_verbose(self):
906
wt = self.make_standard_commit('nicky')
907
self.assertFormatterResult('''\
908
2005-11-22 John Doe <jdoe@example.com>
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)
999
class TestGetViewRevisions(tests.TestCaseWithTransport):
924
1001
def make_tree_with_commits(self):
925
1002
"""Create a tree with well-known revision ids"""
926
1003
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')
1004
wt.commit('commit one', rev_id='1')
1005
wt.commit('commit two', rev_id='2')
1006
wt.commit('commit three', rev_id='3')
930
1007
mainline_revs = [None, '1', '2', '3']
931
1008
rev_nos = {'1': 1, '2': 2, '3': 3}
932
1009
return mainline_revs, rev_nos, wt
991
1068
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
993
1070
self.addCleanup(wt.unlock)
994
revisions = list(self._get_view_revisions(
1071
revisions = list(log.get_view_revisions(
995
1072
mainline_revs, rev_nos, wt.branch, 'forward'))
996
1073
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
998
revisions2 = list(self._get_view_revisions(
1075
revisions2 = list(log.get_view_revisions(
999
1076
mainline_revs, rev_nos, wt.branch, 'forward',
1000
1077
include_merges=False))
1001
1078
self.assertEqual(revisions, revisions2)
1005
1082
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1007
1084
self.addCleanup(wt.unlock)
1008
revisions = list(self._get_view_revisions(
1085
revisions = list(log.get_view_revisions(
1009
1086
mainline_revs, rev_nos, wt.branch, 'reverse'))
1010
1087
self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
1012
revisions2 = list(self._get_view_revisions(
1089
revisions2 = list(log.get_view_revisions(
1013
1090
mainline_revs, rev_nos, wt.branch, 'reverse',
1014
1091
include_merges=False))
1015
1092
self.assertEqual(revisions, revisions2)
1019
1096
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1021
1098
self.addCleanup(wt.unlock)
1022
revisions = list(self._get_view_revisions(
1099
revisions = list(log.get_view_revisions(
1023
1100
mainline_revs, rev_nos, wt.branch, 'forward'))
1024
1101
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1025
1102
('4b', '4', 0), ('4a', '3.1.1', 1)],
1027
revisions = list(self._get_view_revisions(
1104
revisions = list(log.get_view_revisions(
1028
1105
mainline_revs, rev_nos, wt.branch, 'forward',
1029
1106
include_merges=False))
1030
1107
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1036
1113
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1038
1115
self.addCleanup(wt.unlock)
1039
revisions = list(self._get_view_revisions(
1116
revisions = list(log.get_view_revisions(
1040
1117
mainline_revs, rev_nos, wt.branch, 'reverse'))
1041
1118
self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
1042
1119
('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
1044
revisions = list(self._get_view_revisions(
1121
revisions = list(log.get_view_revisions(
1045
1122
mainline_revs, rev_nos, wt.branch, 'reverse',
1046
1123
include_merges=False))
1047
1124
self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
1053
1130
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1055
1132
self.addCleanup(b.unlock)
1056
revisions = list(self._get_view_revisions(
1133
revisions = list(log.get_view_revisions(
1057
1134
mainline_revs, rev_nos, b, 'forward'))
1058
1135
expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1059
1136
('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1060
1137
('4a', '2.2.2', 1)]
1061
1138
self.assertEqual(expected, revisions)
1062
revisions = list(self._get_view_revisions(
1139
revisions = list(log.get_view_revisions(
1063
1140
mainline_revs, rev_nos, b, 'forward',
1064
1141
include_merges=False))
1065
1142
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1066
1143
('4b', '4', 0)],
1069
1147
def test_file_id_for_range(self):
1070
1148
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1091
1167
rev_3a = rev_from_rev_id('3a', b)
1092
1168
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)],
1169
self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1), ('3a', '2.1.1', 2)],
1095
1170
view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
1096
1171
# 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)],
1172
self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1), ('3a', '2.1.1', 2)],
1099
1173
view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1102
1176
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
1178
def create_tree_with_single_merge(self):
1109
1179
"""Create a branch with a moderate layout.
1275
1342
class TestLogFormatter(tests.TestCase):
1278
super(TestLogFormatter, self).setUp()
1279
self.rev = revision.Revision('a-id')
1280
self.lf = log.LogFormatter(None)
1282
1344
def test_short_committer(self):
1283
def assertCommitter(expected, committer):
1284
self.rev.committer = committer
1285
self.assertEqual(expected, self.lf.short_committer(self.rev))
1287
assertCommitter('John Doe', 'John Doe <jdoe@example.com>')
1288
assertCommitter('John Smith', 'John Smith <jsmith@example.com>')
1289
assertCommitter('John Smith', 'John Smith')
1290
assertCommitter('jsmith@example.com', 'jsmith@example.com')
1291
assertCommitter('jsmith@example.com', '<jsmith@example.com>')
1292
assertCommitter('John Smith', 'John Smith jsmith@example.com')
1345
rev = revision.Revision('a-id')
1346
rev.committer = 'John Doe <jdoe@example.com>'
1347
lf = log.LogFormatter(None)
1348
self.assertEqual('John Doe', lf.short_committer(rev))
1349
rev.committer = 'John Smith <jsmith@example.com>'
1350
self.assertEqual('John Smith', lf.short_committer(rev))
1351
rev.committer = 'John Smith'
1352
self.assertEqual('John Smith', lf.short_committer(rev))
1353
rev.committer = 'jsmith@example.com'
1354
self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1355
rev.committer = '<jsmith@example.com>'
1356
self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1357
rev.committer = 'John Smith jsmith@example.com'
1358
self.assertEqual('John Smith', lf.short_committer(rev))
1294
1360
def test_short_author(self):
1295
def assertAuthor(expected, author):
1296
self.rev.properties['author'] = author
1297
self.assertEqual(expected, self.lf.short_author(self.rev))
1299
assertAuthor('John Smith', 'John Smith <jsmith@example.com>')
1300
assertAuthor('John Smith', 'John Smith')
1301
assertAuthor('jsmith@example.com', 'jsmith@example.com')
1302
assertAuthor('jsmith@example.com', '<jsmith@example.com>')
1303
assertAuthor('John Smith', 'John Smith jsmith@example.com')
1305
def test_short_author_from_committer(self):
1306
self.rev.committer = 'John Doe <jdoe@example.com>'
1307
self.assertEqual('John Doe', self.lf.short_author(self.rev))
1309
def test_short_author_from_authors(self):
1310
self.rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1311
'Jane Rey <jrey@example.com>')
1312
self.assertEqual('John Smith', self.lf.short_author(self.rev))
1361
rev = revision.Revision('a-id')
1362
rev.committer = 'John Doe <jdoe@example.com>'
1363
lf = log.LogFormatter(None)
1364
self.assertEqual('John Doe', lf.short_author(rev))
1365
rev.properties['author'] = 'John Smith <jsmith@example.com>'
1366
self.assertEqual('John Smith', lf.short_author(rev))
1367
rev.properties['author'] = 'John Smith'
1368
self.assertEqual('John Smith', lf.short_author(rev))
1369
rev.properties['author'] = 'jsmith@example.com'
1370
self.assertEqual('jsmith@example.com', lf.short_author(rev))
1371
rev.properties['author'] = '<jsmith@example.com>'
1372
self.assertEqual('jsmith@example.com', lf.short_author(rev))
1373
rev.properties['author'] = 'John Smith jsmith@example.com'
1374
self.assertEqual('John Smith', lf.short_author(rev))
1375
del rev.properties['author']
1376
rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1377
'Jane Rey <jrey@example.com>')
1378
self.assertEqual('John Smith', lf.short_author(rev))
1315
1381
class TestReverseByDepth(tests.TestCase):
1461
1527
log.show_branch_change(tree.branch, s, 3, '3b')
1462
1528
self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1463
1529
self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1467
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1470
TestCaseForLogFormatter.setUp(self)
1471
log.properties_handler_registry.register(
1472
'bugs_properties_handler',
1473
log._bugs_properties_handler)
1475
def make_commits_with_bugs(self):
1476
"""Helper method for LogFormatter tests"""
1477
tree = self.make_branch_and_tree(u'.')
1478
self.build_tree(['a', 'b'])
1480
self.wt_commit(tree, 'simple log message', rev_id='a1',
1481
revprops={'bugs': 'test://bug/id fixed'})
1483
self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id='a2',
1484
authors=['Joe Bar <joe@bar.com>'],
1485
revprops={'bugs': 'test://bug/id fixed\n'
1486
'test://bug/2 fixed'})
1490
def test_long_bugs(self):
1491
tree = self.make_commits_with_bugs()
1492
self.assertFormatterResult("""\
1493
------------------------------------------------------------
1495
fixes bug(s): test://bug/id test://bug/2
1496
author: Joe Bar <joe@bar.com>
1497
committer: Joe Foo <joe@foo.com>
1499
timestamp: Tue 2005-11-22 00:00:01 +0000
1504
------------------------------------------------------------
1506
fixes bug(s): test://bug/id
1507
committer: Joe Foo <joe@foo.com>
1509
timestamp: Tue 2005-11-22 00:00:00 +0000
1513
tree.branch, log.LongLogFormatter)
1515
def test_short_bugs(self):
1516
tree = self.make_commits_with_bugs()
1517
self.assertFormatterResult("""\
1518
2 Joe Bar\t2005-11-22
1519
fixes bug(s): test://bug/id test://bug/2
1524
1 Joe Foo\t2005-11-22
1525
fixes bug(s): test://bug/id
1529
tree.branch, log.ShortLogFormatter)
1531
def test_wrong_bugs_property(self):
1532
tree = self.make_branch_and_tree(u'.')
1533
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("""\
1537
1 Joe Foo\t2005-11-22
1541
tree.branch, log.ShortLogFormatter)
1543
def test_bugs_handler_present(self):
1544
self.properties_handler_registry.get('bugs_properties_handler')
1546
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1548
def make_branch_with_alternate_ancestries(self, relpath='.'):
1549
# See test_merge_sorted_exclude_ancestry below for the difference with
1550
# bt.per_branch.test_iter_merge_sorted_revision.
1551
# TestIterMergeSortedRevisionsBushyGraph.
1552
# make_branch_with_alternate_ancestries
1553
# and test_merge_sorted_exclude_ancestry
1554
# See the FIXME in assertLogRevnos too.
1555
builder = branchbuilder.BranchBuilder(self.get_transport(relpath))
1567
builder.start_series()
1568
builder.build_snapshot('1', None, [
1569
('add', ('', 'TREE_ROOT', 'directory', '')),])
1570
builder.build_snapshot('1.1.1', ['1'], [])
1571
builder.build_snapshot('2', ['1'], [])
1572
builder.build_snapshot('1.2.1', ['1.1.1'], [])
1573
builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1574
builder.build_snapshot('3', ['2', '1.1.2'], [])
1575
builder.finish_series()
1576
br = builder.get_branch()
1578
self.addCleanup(br.unlock)
1581
def assertLogRevnos(self, expected_revnos, b, start, end,
1582
exclude_common_ancestry):
1583
# FIXME: the layering in log makes it hard to test intermediate levels,
1584
# I wish adding filters with their parameters were easier...
1586
iter_revs = log._calc_view_revisions(
1587
b, start, end, direction='reverse',
1588
generate_merge_revisions=True,
1589
exclude_common_ancestry=exclude_common_ancestry)
1590
self.assertEqual(expected_revnos,
1591
[revid for revid, revno, depth in iter_revs])
1593
def test_merge_sorted_exclude_ancestry(self):
1594
b = self.make_branch_with_alternate_ancestries()
1595
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1597
# '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1598
# 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)