1
# Copyright (C) 2005-2010 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
from cStringIO import StringIO
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):
54
super(TestCaseForLogFormatter, self).setUp()
55
# keep a reference to the "current" custom prop. handler registry
56
self.properties_handler_registry = log.properties_handler_registry
57
# Use a clean registry for log
58
log.properties_handler_registry = registry.Registry()
61
log.properties_handler_registry = self.properties_handler_registry
62
self.addCleanup(restore)
64
def assertFormatterResult(self, result, branch, formatter_class,
65
formatter_kwargs=None, show_log_kwargs=None):
66
logfile = self.make_utf8_encoded_stringio()
67
if formatter_kwargs is None:
69
formatter = formatter_class(to_file=logfile, **formatter_kwargs)
70
if show_log_kwargs is None:
72
log.show_log(branch, formatter, **show_log_kwargs)
73
self.assertEqualDiff(result, logfile.getvalue())
75
def make_standard_commit(self, branch_nick, **kwargs):
76
wt = self.make_branch_and_tree('.')
78
self.addCleanup(wt.unlock)
79
self.build_tree(['a'])
81
wt.branch.nick = branch_nick
82
kwargs.setdefault('committer', 'Lorem Ipsum <test@example.com>')
83
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
def _prepare_tree_with_merges(self, with_tags=False):
103
wt = self.make_branch_and_memory_tree('.')
105
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')
109
wt.set_parent_ids(['rev-1', 'rev-2a'])
110
wt.branch.set_last_revision_info(1, 'rev-1')
111
self.wt_commit(wt, 'rev-2', rev_id='rev-2b')
114
branch.tags.set_tag('v0.2', 'rev-2b')
115
self.wt_commit(wt, 'rev-3', rev_id='rev-3')
116
branch.tags.set_tag('v1.0rc1', 'rev-3')
117
branch.tags.set_tag('v1.0', 'rev-3')
121
class LogCatcher(log.LogFormatter):
122
"""Pull log messages into a list rather than displaying them.
124
To simplify testing we save logged revisions here rather than actually
125
formatting anything, so that we can precisely check the result without
126
being dependent on the formatting.
129
supports_merge_revisions = True
130
supports_delta = True
134
def __init__(self, *args, **kwargs):
135
kwargs.update(dict(to_file=None))
136
super(LogCatcher, self).__init__(*args, **kwargs)
139
def log_revision(self, revision):
140
self.revisions.append(revision)
143
class TestShowLog(tests.TestCaseWithTransport):
145
def checkDelta(self, delta, **kw):
146
"""Check the filenames touched by a delta are as expected.
148
Caller only have to pass in the list of files for each part, all
149
unspecified parts are considered empty (and checked as such).
151
for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
152
# By default we expect an empty list
153
expected = kw.get(n, [])
154
# strip out only the path components
155
got = [x[0] for x in getattr(delta, n)]
156
self.assertEqual(expected, got)
158
def assertInvalidRevisonNumber(self, br, start, end):
160
self.assertRaises(errors.InvalidRevisionNumber,
161
log.show_log, br, lf,
162
start_revision=start, end_revision=end)
164
def test_cur_revno(self):
165
wt = self.make_branch_and_tree('.')
169
wt.commit('empty commit')
170
log.show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
172
# Since there is a single revision in the branch all the combinations
174
self.assertInvalidRevisonNumber(b, 2, 1)
175
self.assertInvalidRevisonNumber(b, 1, 2)
176
self.assertInvalidRevisonNumber(b, 0, 2)
177
self.assertInvalidRevisonNumber(b, 1, 0)
178
self.assertInvalidRevisonNumber(b, -1, 1)
179
self.assertInvalidRevisonNumber(b, 1, -1)
181
def test_empty_branch(self):
182
wt = self.make_branch_and_tree('.')
185
log.show_log(wt.branch, lf)
187
self.assertEqual([], lf.revisions)
189
def test_empty_commit(self):
190
wt = self.make_branch_and_tree('.')
192
wt.commit('empty commit')
194
log.show_log(wt.branch, lf, verbose=True)
196
self.assertEqual(1, len(revs))
197
self.assertEqual('1', revs[0].revno)
198
self.assertEqual('empty commit', revs[0].rev.message)
199
self.checkDelta(revs[0].delta)
201
def test_simple_commit(self):
202
wt = self.make_branch_and_tree('.')
203
wt.commit('empty commit')
204
self.build_tree(['hello'])
206
wt.commit('add one file',
207
committer=u'\u013d\xf3r\xe9m \xcdp\u0161\xfam '
208
u'<test@example.com>')
210
log.show_log(wt.branch, lf, verbose=True)
211
self.assertEqual(2, len(lf.revisions))
212
# first one is most recent
213
log_entry = lf.revisions[0]
214
self.assertEqual('2', log_entry.revno)
215
self.assertEqual('add one file', log_entry.rev.message)
216
self.checkDelta(log_entry.delta, added=['hello'])
218
def test_commit_message_with_control_chars(self):
219
wt = self.make_branch_and_tree('.')
220
msg = u"All 8-bit chars: " + ''.join([unichr(x) for x in range(256)])
221
msg = msg.replace(u'\r', u'\n')
224
log.show_log(wt.branch, lf, verbose=True)
225
committed_msg = lf.revisions[0].rev.message
226
if wt.branch.repository._serializer.squashes_xml_invalid_characters:
227
self.assertNotEqual(msg, committed_msg)
228
self.assertTrue(len(committed_msg) > len(msg))
230
self.assertEqual(msg, committed_msg)
232
def test_commit_message_without_control_chars(self):
233
wt = self.make_branch_and_tree('.')
234
# escaped. As ElementTree apparently does some kind of
235
# newline conversion, neither LF (\x0A) nor CR (\x0D) are
236
# included in the test commit message, even though they are
237
# valid XML 1.0 characters.
238
msg = "\x09" + ''.join([unichr(x) for x in range(0x20, 256)])
241
log.show_log(wt.branch, lf, verbose=True)
242
committed_msg = lf.revisions[0].rev.message
243
self.assertEqual(msg, committed_msg)
245
def test_deltas_in_merge_revisions(self):
246
"""Check deltas created for both mainline and merge revisions"""
247
wt = self.make_branch_and_tree('parent')
248
self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
251
wt.commit(message='add file1 and file2')
252
self.run_bzr('branch parent child')
253
os.unlink('child/file1')
254
file('child/file2', 'wb').write('hello\n')
255
self.run_bzr(['commit', '-m', 'remove file1 and modify file2',
258
self.run_bzr('merge ../child')
259
wt.commit('merge child branch')
263
lf.supports_merge_revisions = True
264
log.show_log(b, lf, verbose=True)
267
self.assertEqual(3, len(revs))
270
self.assertEqual('2', logentry.revno)
271
self.assertEqual('merge child branch', logentry.rev.message)
272
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
275
self.assertEqual('1.1.1', logentry.revno)
276
self.assertEqual('remove file1 and modify file2', logentry.rev.message)
277
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
280
self.assertEqual('1', logentry.revno)
281
self.assertEqual('add file1 and file2', logentry.rev.message)
282
self.checkDelta(logentry.delta, added=['file1', 'file2'])
285
class TestShortLogFormatter(TestCaseForLogFormatter):
287
def test_trailing_newlines(self):
288
wt = self.make_branch_and_tree('.')
289
b = self.make_commits_with_trailing_newlines(wt)
290
self.assertFormatterResult("""\
291
3 Joe Foo\t2005-11-22
292
single line with trailing newline
294
2 Joe Foo\t2005-11-22
299
1 Joe Foo\t2005-11-22
303
b, log.ShortLogFormatter)
305
def test_short_log_with_merges(self):
306
wt = self._prepare_tree_with_merges()
307
self.assertFormatterResult("""\
308
2 Joe Foo\t2005-11-22 [merge]
311
1 Joe Foo\t2005-11-22
315
wt.branch, log.ShortLogFormatter)
317
def test_short_log_with_merges_and_advice(self):
318
wt = self._prepare_tree_with_merges()
319
self.assertFormatterResult("""\
320
2 Joe Foo\t2005-11-22 [merge]
323
1 Joe Foo\t2005-11-22
326
Use --include-merged or -n0 to see merged revisions.
328
wt.branch, log.ShortLogFormatter,
329
formatter_kwargs=dict(show_advice=True))
331
def test_short_log_with_merges_and_range(self):
332
wt = self._prepare_tree_with_merges()
333
self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
334
wt.branch.set_last_revision_info(2, 'rev-2b')
335
wt.set_parent_ids(['rev-2b', 'rev-3a'])
336
self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
337
self.assertFormatterResult("""\
338
3 Joe Foo\t2005-11-22 [merge]
341
2 Joe Foo\t2005-11-22 [merge]
345
wt.branch, log.ShortLogFormatter,
346
show_log_kwargs=dict(start_revision=2, end_revision=3))
348
def test_short_log_with_tags(self):
349
wt = self._prepare_tree_with_merges(with_tags=True)
350
self.assertFormatterResult("""\
351
3 Joe Foo\t2005-11-22 {v1.0, v1.0rc1}
354
2 Joe Foo\t2005-11-22 {v0.2} [merge]
357
1 Joe Foo\t2005-11-22
361
wt.branch, log.ShortLogFormatter)
363
def test_short_log_single_merge_revision(self):
364
wt = self._prepare_tree_with_merges()
365
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
366
rev = revspec.in_history(wt.branch)
367
self.assertFormatterResult("""\
368
1.1.1 Joe Foo\t2005-11-22
372
wt.branch, log.ShortLogFormatter,
373
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
375
def test_show_ids(self):
376
wt = self.make_branch_and_tree('parent')
377
self.build_tree(['parent/f1', 'parent/f2'])
379
self.wt_commit(wt, 'first post', rev_id='a')
380
child_wt = wt.bzrdir.sprout('child').open_workingtree()
381
self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
382
wt.merge_from_branch(child_wt.branch)
383
self.wt_commit(wt, 'merge branch 1', rev_id='c')
384
self.assertFormatterResult("""\
385
2 Joe Foo\t2005-11-22 [merge]
389
1.1.1 Joe Foo\t2005-11-22
393
1 Joe Foo\t2005-11-22
398
wt.branch, log.ShortLogFormatter,
399
formatter_kwargs=dict(levels=0,show_ids=True))
402
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
404
def test_short_merge_revs_log_with_merges(self):
405
wt = self._prepare_tree_with_merges()
406
# Note that the 1.1.1 indenting is in fact correct given that
407
# the revision numbers are right justified within 5 characters
408
# for mainline revnos and 9 characters for dotted revnos.
409
self.assertFormatterResult("""\
410
2 Joe Foo\t2005-11-22 [merge]
413
1.1.1 Joe Foo\t2005-11-22
416
1 Joe Foo\t2005-11-22
420
wt.branch, log.ShortLogFormatter,
421
formatter_kwargs=dict(levels=0))
423
def test_short_merge_revs_log_single_merge_revision(self):
424
wt = self._prepare_tree_with_merges()
425
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
426
rev = revspec.in_history(wt.branch)
427
self.assertFormatterResult("""\
428
1.1.1 Joe Foo\t2005-11-22
432
wt.branch, log.ShortLogFormatter,
433
formatter_kwargs=dict(levels=0),
434
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
437
class TestLongLogFormatter(TestCaseForLogFormatter):
439
def test_verbose_log(self):
440
"""Verbose log includes changed files
444
wt = self.make_standard_commit('test_verbose_log', authors=[])
445
self.assertFormatterResult('''\
446
------------------------------------------------------------
448
committer: Lorem Ipsum <test@example.com>
449
branch nick: test_verbose_log
450
timestamp: Tue 2005-11-22 00:00:00 +0000
456
wt.branch, log.LongLogFormatter,
457
show_log_kwargs=dict(verbose=True))
459
def test_merges_are_indented_by_level(self):
460
wt = self.make_branch_and_tree('parent')
461
self.wt_commit(wt, 'first post')
462
child_wt = wt.bzrdir.sprout('child').open_workingtree()
463
self.wt_commit(child_wt, 'branch 1')
464
smallerchild_wt = wt.bzrdir.sprout('smallerchild').open_workingtree()
465
self.wt_commit(smallerchild_wt, 'branch 2')
466
child_wt.merge_from_branch(smallerchild_wt.branch)
467
self.wt_commit(child_wt, 'merge branch 2')
468
wt.merge_from_branch(child_wt.branch)
469
self.wt_commit(wt, 'merge branch 1')
470
self.assertFormatterResult("""\
471
------------------------------------------------------------
473
committer: Joe Foo <joe@foo.com>
475
timestamp: Tue 2005-11-22 00:00:04 +0000
478
------------------------------------------------------------
480
committer: Joe Foo <joe@foo.com>
482
timestamp: Tue 2005-11-22 00:00:03 +0000
485
------------------------------------------------------------
487
committer: Joe Foo <joe@foo.com>
488
branch nick: smallerchild
489
timestamp: Tue 2005-11-22 00:00:02 +0000
492
------------------------------------------------------------
494
committer: Joe Foo <joe@foo.com>
496
timestamp: Tue 2005-11-22 00:00:01 +0000
499
------------------------------------------------------------
501
committer: Joe Foo <joe@foo.com>
503
timestamp: Tue 2005-11-22 00:00:00 +0000
507
wt.branch, log.LongLogFormatter,
508
formatter_kwargs=dict(levels=0),
509
show_log_kwargs=dict(verbose=True))
511
def test_verbose_merge_revisions_contain_deltas(self):
512
wt = self.make_branch_and_tree('parent')
513
self.build_tree(['parent/f1', 'parent/f2'])
515
self.wt_commit(wt, 'first post')
516
child_wt = wt.bzrdir.sprout('child').open_workingtree()
517
os.unlink('child/f1')
518
self.build_tree_contents([('child/f2', 'hello\n')])
519
self.wt_commit(child_wt, 'removed f1 and modified f2')
520
wt.merge_from_branch(child_wt.branch)
521
self.wt_commit(wt, 'merge branch 1')
522
self.assertFormatterResult("""\
523
------------------------------------------------------------
525
committer: Joe Foo <joe@foo.com>
527
timestamp: Tue 2005-11-22 00:00:02 +0000
534
------------------------------------------------------------
536
committer: Joe Foo <joe@foo.com>
538
timestamp: Tue 2005-11-22 00:00:01 +0000
540
removed f1 and modified f2
545
------------------------------------------------------------
547
committer: Joe Foo <joe@foo.com>
549
timestamp: Tue 2005-11-22 00:00:00 +0000
556
wt.branch, log.LongLogFormatter,
557
formatter_kwargs=dict(levels=0),
558
show_log_kwargs=dict(verbose=True))
560
def test_trailing_newlines(self):
561
wt = self.make_branch_and_tree('.')
562
b = self.make_commits_with_trailing_newlines(wt)
563
self.assertFormatterResult("""\
564
------------------------------------------------------------
566
committer: Joe Foo <joe@foo.com>
568
timestamp: Tue 2005-11-22 00:00:02 +0000
570
single line with trailing newline
571
------------------------------------------------------------
573
committer: Joe Foo <joe@foo.com>
575
timestamp: Tue 2005-11-22 00:00:01 +0000
580
------------------------------------------------------------
582
committer: Joe Foo <joe@foo.com>
584
timestamp: Tue 2005-11-22 00:00:00 +0000
588
b, log.LongLogFormatter)
590
def test_author_in_log(self):
591
"""Log includes the author name if it's set in
592
the revision properties
594
wt = self.make_standard_commit('test_author_log',
595
authors=['John Doe <jdoe@example.com>',
596
'Jane Rey <jrey@example.com>'])
597
self.assertFormatterResult("""\
598
------------------------------------------------------------
600
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
601
committer: Lorem Ipsum <test@example.com>
602
branch nick: test_author_log
603
timestamp: Tue 2005-11-22 00:00:00 +0000
607
wt.branch, log.LongLogFormatter)
609
def test_properties_in_log(self):
610
"""Log includes the custom properties returned by the registered
613
wt = self.make_standard_commit('test_properties_in_log')
614
def trivial_custom_prop_handler(revision):
615
return {'test_prop':'test_value'}
617
# Cleaned up in setUp()
618
log.properties_handler_registry.register(
619
'trivial_custom_prop_handler',
620
trivial_custom_prop_handler)
621
self.assertFormatterResult("""\
622
------------------------------------------------------------
624
test_prop: test_value
625
author: John Doe <jdoe@example.com>
626
committer: Lorem Ipsum <test@example.com>
627
branch nick: test_properties_in_log
628
timestamp: Tue 2005-11-22 00:00:00 +0000
632
wt.branch, log.LongLogFormatter)
634
def test_properties_in_short_log(self):
635
"""Log includes the custom properties returned by the registered
638
wt = self.make_standard_commit('test_properties_in_short_log')
639
def trivial_custom_prop_handler(revision):
640
return {'test_prop':'test_value'}
642
log.properties_handler_registry.register(
643
'trivial_custom_prop_handler',
644
trivial_custom_prop_handler)
645
self.assertFormatterResult("""\
646
1 John Doe\t2005-11-22
647
test_prop: test_value
651
wt.branch, log.ShortLogFormatter)
653
def test_error_in_properties_handler(self):
654
"""Log includes the custom properties returned by the registered
657
wt = self.make_standard_commit('error_in_properties_handler',
658
revprops={'first_prop':'first_value'})
659
sio = self.make_utf8_encoded_stringio()
660
formatter = log.LongLogFormatter(to_file=sio)
661
def trivial_custom_prop_handler(revision):
662
raise StandardError("a test error")
664
log.properties_handler_registry.register(
665
'trivial_custom_prop_handler',
666
trivial_custom_prop_handler)
667
self.assertRaises(StandardError, log.show_log, wt.branch, formatter,)
669
def test_properties_handler_bad_argument(self):
670
wt = self.make_standard_commit('bad_argument',
671
revprops={'a_prop':'test_value'})
672
sio = self.make_utf8_encoded_stringio()
673
formatter = log.LongLogFormatter(to_file=sio)
674
def bad_argument_prop_handler(revision):
675
return {'custom_prop_name':revision.properties['a_prop']}
677
log.properties_handler_registry.register(
678
'bad_argument_prop_handler',
679
bad_argument_prop_handler)
681
self.assertRaises(AttributeError, formatter.show_properties,
684
revision = wt.branch.repository.get_revision(wt.branch.last_revision())
685
formatter.show_properties(revision, '')
686
self.assertEqualDiff('''custom_prop_name: test_value\n''',
689
def test_show_ids(self):
690
wt = self.make_branch_and_tree('parent')
691
self.build_tree(['parent/f1', 'parent/f2'])
693
self.wt_commit(wt, 'first post', rev_id='a')
694
child_wt = wt.bzrdir.sprout('child').open_workingtree()
695
self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
696
wt.merge_from_branch(child_wt.branch)
697
self.wt_commit(wt, 'merge branch 1', rev_id='c')
698
self.assertFormatterResult("""\
699
------------------------------------------------------------
704
committer: Joe Foo <joe@foo.com>
706
timestamp: Tue 2005-11-22 00:00:02 +0000
709
------------------------------------------------------------
713
committer: Joe Foo <joe@foo.com>
715
timestamp: Tue 2005-11-22 00:00:01 +0000
718
------------------------------------------------------------
721
committer: Joe Foo <joe@foo.com>
723
timestamp: Tue 2005-11-22 00:00:00 +0000
727
wt.branch, log.LongLogFormatter,
728
formatter_kwargs=dict(levels=0,show_ids=True))
731
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
733
def test_long_verbose_log(self):
734
"""Verbose log includes changed files
738
wt = self.make_standard_commit('test_long_verbose_log', authors=[])
739
self.assertFormatterResult("""\
740
------------------------------------------------------------
742
committer: Lorem Ipsum <test@example.com>
743
branch nick: test_long_verbose_log
744
timestamp: Tue 2005-11-22 00:00:00 +0000
750
wt.branch, log.LongLogFormatter,
751
formatter_kwargs=dict(levels=1),
752
show_log_kwargs=dict(verbose=True))
754
def test_long_verbose_contain_deltas(self):
755
wt = self.make_branch_and_tree('parent')
756
self.build_tree(['parent/f1', 'parent/f2'])
758
self.wt_commit(wt, 'first post')
759
child_wt = wt.bzrdir.sprout('child').open_workingtree()
760
os.unlink('child/f1')
761
self.build_tree_contents([('child/f2', 'hello\n')])
762
self.wt_commit(child_wt, 'removed f1 and modified f2')
763
wt.merge_from_branch(child_wt.branch)
764
self.wt_commit(wt, 'merge branch 1')
765
self.assertFormatterResult("""\
766
------------------------------------------------------------
768
committer: Joe Foo <joe@foo.com>
770
timestamp: Tue 2005-11-22 00:00:02 +0000
777
------------------------------------------------------------
779
committer: Joe Foo <joe@foo.com>
781
timestamp: Tue 2005-11-22 00:00:00 +0000
788
wt.branch, log.LongLogFormatter,
789
formatter_kwargs=dict(levels=1),
790
show_log_kwargs=dict(verbose=True))
792
def test_long_trailing_newlines(self):
793
wt = self.make_branch_and_tree('.')
794
b = self.make_commits_with_trailing_newlines(wt)
795
self.assertFormatterResult("""\
796
------------------------------------------------------------
798
committer: Joe Foo <joe@foo.com>
800
timestamp: Tue 2005-11-22 00:00:02 +0000
802
single line with trailing newline
803
------------------------------------------------------------
805
committer: Joe Foo <joe@foo.com>
807
timestamp: Tue 2005-11-22 00:00:01 +0000
812
------------------------------------------------------------
814
committer: Joe Foo <joe@foo.com>
816
timestamp: Tue 2005-11-22 00:00:00 +0000
820
b, log.LongLogFormatter,
821
formatter_kwargs=dict(levels=1))
823
def test_long_author_in_log(self):
824
"""Log includes the author name if it's set in
825
the revision properties
827
wt = self.make_standard_commit('test_author_log')
828
self.assertFormatterResult("""\
829
------------------------------------------------------------
831
author: John Doe <jdoe@example.com>
832
committer: Lorem Ipsum <test@example.com>
833
branch nick: test_author_log
834
timestamp: Tue 2005-11-22 00:00:00 +0000
838
wt.branch, log.LongLogFormatter,
839
formatter_kwargs=dict(levels=1))
841
def test_long_properties_in_log(self):
842
"""Log includes the custom properties returned by the registered
845
wt = self.make_standard_commit('test_properties_in_log')
846
def trivial_custom_prop_handler(revision):
847
return {'test_prop':'test_value'}
849
log.properties_handler_registry.register(
850
'trivial_custom_prop_handler',
851
trivial_custom_prop_handler)
852
self.assertFormatterResult("""\
853
------------------------------------------------------------
855
test_prop: test_value
856
author: John Doe <jdoe@example.com>
857
committer: Lorem Ipsum <test@example.com>
858
branch nick: test_properties_in_log
859
timestamp: Tue 2005-11-22 00:00:00 +0000
863
wt.branch, log.LongLogFormatter,
864
formatter_kwargs=dict(levels=1))
867
class TestLineLogFormatter(TestCaseForLogFormatter):
869
def test_line_log(self):
870
"""Line log should show revno
874
wt = self.make_standard_commit('test-line-log',
875
committer='Line-Log-Formatter Tester <test@line.log>',
877
self.assertFormatterResult("""\
878
1: Line-Log-Formatte... 2005-11-22 add a
880
wt.branch, log.LineLogFormatter)
882
def test_trailing_newlines(self):
883
wt = self.make_branch_and_tree('.')
884
b = self.make_commits_with_trailing_newlines(wt)
885
self.assertFormatterResult("""\
886
3: Joe Foo 2005-11-22 single line with trailing newline
887
2: Joe Foo 2005-11-22 multiline
888
1: Joe Foo 2005-11-22 simple log message
890
b, log.LineLogFormatter)
892
def test_line_log_single_merge_revision(self):
893
wt = self._prepare_tree_with_merges()
894
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
895
rev = revspec.in_history(wt.branch)
896
self.assertFormatterResult("""\
897
1.1.1: Joe Foo 2005-11-22 rev-merged
899
wt.branch, log.LineLogFormatter,
900
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
902
def test_line_log_with_tags(self):
903
wt = self._prepare_tree_with_merges(with_tags=True)
904
self.assertFormatterResult("""\
905
3: Joe Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
906
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
907
1: Joe Foo 2005-11-22 rev-1
909
wt.branch, log.LineLogFormatter)
912
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
914
def test_line_merge_revs_log(self):
915
"""Line log should show revno
919
wt = self.make_standard_commit('test-line-log',
920
committer='Line-Log-Formatter Tester <test@line.log>',
922
self.assertFormatterResult("""\
923
1: Line-Log-Formatte... 2005-11-22 add a
925
wt.branch, log.LineLogFormatter)
927
def test_line_merge_revs_log_single_merge_revision(self):
928
wt = self._prepare_tree_with_merges()
929
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
930
rev = revspec.in_history(wt.branch)
931
self.assertFormatterResult("""\
932
1.1.1: Joe Foo 2005-11-22 rev-merged
934
wt.branch, log.LineLogFormatter,
935
formatter_kwargs=dict(levels=0),
936
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
938
def test_line_merge_revs_log_with_merges(self):
939
wt = self._prepare_tree_with_merges()
940
self.assertFormatterResult("""\
941
2: Joe Foo 2005-11-22 [merge] rev-2
942
1.1.1: Joe Foo 2005-11-22 rev-merged
943
1: Joe Foo 2005-11-22 rev-1
945
wt.branch, log.LineLogFormatter,
946
formatter_kwargs=dict(levels=0))
949
class TestGnuChangelogFormatter(TestCaseForLogFormatter):
951
def test_gnu_changelog(self):
952
wt = self.make_standard_commit('nicky', authors=[])
953
self.assertFormatterResult('''\
954
2005-11-22 Lorem Ipsum <test@example.com>
959
wt.branch, log.GnuChangelogLogFormatter)
961
def test_with_authors(self):
962
wt = self.make_standard_commit('nicky',
963
authors=['Fooa Fooz <foo@example.com>',
964
'Bari Baro <bar@example.com>'])
965
self.assertFormatterResult('''\
966
2005-11-22 Fooa Fooz <foo@example.com>
971
wt.branch, log.GnuChangelogLogFormatter)
973
def test_verbose(self):
974
wt = self.make_standard_commit('nicky')
975
self.assertFormatterResult('''\
976
2005-11-22 John Doe <jdoe@example.com>
983
wt.branch, log.GnuChangelogLogFormatter,
984
show_log_kwargs=dict(verbose=True))
987
class TestShowChangedRevisions(tests.TestCaseWithTransport):
989
def test_show_changed_revisions_verbose(self):
990
tree = self.make_branch_and_tree('tree_a')
991
self.build_tree(['tree_a/foo'])
993
tree.commit('bar', rev_id='bar-id')
994
s = self.make_utf8_encoded_stringio()
995
log.show_changed_revisions(tree.branch, [], ['bar-id'], s)
996
self.assertContainsRe(s.getvalue(), 'bar')
997
self.assertNotContainsRe(s.getvalue(), 'foo')
1000
class TestLogFormatter(tests.TestCase):
1003
super(TestLogFormatter, self).setUp()
1004
self.rev = revision.Revision('a-id')
1005
self.lf = log.LogFormatter(None)
1007
def test_short_committer(self):
1008
def assertCommitter(expected, committer):
1009
self.rev.committer = committer
1010
self.assertEqual(expected, self.lf.short_committer(self.rev))
1012
assertCommitter('John Doe', 'John Doe <jdoe@example.com>')
1013
assertCommitter('John Smith', 'John Smith <jsmith@example.com>')
1014
assertCommitter('John Smith', 'John Smith')
1015
assertCommitter('jsmith@example.com', 'jsmith@example.com')
1016
assertCommitter('jsmith@example.com', '<jsmith@example.com>')
1017
assertCommitter('John Smith', 'John Smith jsmith@example.com')
1019
def test_short_author(self):
1020
def assertAuthor(expected, author):
1021
self.rev.properties['author'] = author
1022
self.assertEqual(expected, self.lf.short_author(self.rev))
1024
assertAuthor('John Smith', 'John Smith <jsmith@example.com>')
1025
assertAuthor('John Smith', 'John Smith')
1026
assertAuthor('jsmith@example.com', 'jsmith@example.com')
1027
assertAuthor('jsmith@example.com', '<jsmith@example.com>')
1028
assertAuthor('John Smith', 'John Smith jsmith@example.com')
1030
def test_short_author_from_committer(self):
1031
self.rev.committer = 'John Doe <jdoe@example.com>'
1032
self.assertEqual('John Doe', self.lf.short_author(self.rev))
1034
def test_short_author_from_authors(self):
1035
self.rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1036
'Jane Rey <jrey@example.com>')
1037
self.assertEqual('John Smith', self.lf.short_author(self.rev))
1040
class TestReverseByDepth(tests.TestCase):
1041
"""Test reverse_by_depth behavior.
1043
This is used to present revisions in forward (oldest first) order in a nice
1046
The tests use lighter revision description to ease reading.
1049
def assertReversed(self, forward, backward):
1050
# Transform the descriptions to suit the API: tests use (revno, depth),
1051
# while the API expects (revid, revno, depth)
1052
def complete_revisions(l):
1053
"""Transform the description to suit the API.
1055
Tests use (revno, depth) whil the API expects (revid, revno, depth).
1056
Since the revid is arbitrary, we just duplicate revno
1058
return [ (r, r, d) for r, d in l]
1059
forward = complete_revisions(forward)
1060
backward= complete_revisions(backward)
1061
self.assertEqual(forward, log.reverse_by_depth(backward))
1064
def test_mainline_revisions(self):
1065
self.assertReversed([( '1', 0), ('2', 0)],
1066
[('2', 0), ('1', 0)])
1068
def test_merged_revisions(self):
1069
self.assertReversed([('1', 0), ('2', 0), ('2.2', 1), ('2.1', 1),],
1070
[('2', 0), ('2.1', 1), ('2.2', 1), ('1', 0),])
1071
def test_shifted_merged_revisions(self):
1072
"""Test irregular layout.
1074
Requesting revisions touching a file can produce "holes" in the depths.
1076
self.assertReversed([('1', 0), ('2', 0), ('1.1', 2), ('1.2', 2),],
1077
[('2', 0), ('1.2', 2), ('1.1', 2), ('1', 0),])
1079
def test_merged_without_child_revisions(self):
1080
"""Test irregular layout.
1082
Revision ranges can produce "holes" in the depths.
1084
# When a revision of higher depth doesn't follow one of lower depth, we
1085
# assume a lower depth one is virtually there
1086
self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1087
[('4', 4), ('3', 3), ('2', 2), ('1', 2),])
1088
# So we get the same order after reversing below even if the original
1089
# revisions are not in the same order.
1090
self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1091
[('3', 3), ('4', 4), ('2', 2), ('1', 2),])
1094
class TestHistoryChange(tests.TestCaseWithTransport):
1096
def setup_a_tree(self):
1097
tree = self.make_branch_and_tree('tree')
1099
self.addCleanup(tree.unlock)
1100
tree.commit('1a', rev_id='1a')
1101
tree.commit('2a', rev_id='2a')
1102
tree.commit('3a', rev_id='3a')
1105
def setup_ab_tree(self):
1106
tree = self.setup_a_tree()
1107
tree.set_last_revision('1a')
1108
tree.branch.set_last_revision_info(1, '1a')
1109
tree.commit('2b', rev_id='2b')
1110
tree.commit('3b', rev_id='3b')
1113
def setup_ac_tree(self):
1114
tree = self.setup_a_tree()
1115
tree.set_last_revision(revision.NULL_REVISION)
1116
tree.branch.set_last_revision_info(0, revision.NULL_REVISION)
1117
tree.commit('1c', rev_id='1c')
1118
tree.commit('2c', rev_id='2c')
1119
tree.commit('3c', rev_id='3c')
1122
def test_all_new(self):
1123
tree = self.setup_ab_tree()
1124
old, new = log.get_history_change('1a', '3a', tree.branch.repository)
1125
self.assertEqual([], old)
1126
self.assertEqual(['2a', '3a'], new)
1128
def test_all_old(self):
1129
tree = self.setup_ab_tree()
1130
old, new = log.get_history_change('3a', '1a', tree.branch.repository)
1131
self.assertEqual([], new)
1132
self.assertEqual(['2a', '3a'], old)
1134
def test_null_old(self):
1135
tree = self.setup_ab_tree()
1136
old, new = log.get_history_change(revision.NULL_REVISION,
1137
'3a', tree.branch.repository)
1138
self.assertEqual([], old)
1139
self.assertEqual(['1a', '2a', '3a'], new)
1141
def test_null_new(self):
1142
tree = self.setup_ab_tree()
1143
old, new = log.get_history_change('3a', revision.NULL_REVISION,
1144
tree.branch.repository)
1145
self.assertEqual([], new)
1146
self.assertEqual(['1a', '2a', '3a'], old)
1148
def test_diverged(self):
1149
tree = self.setup_ab_tree()
1150
old, new = log.get_history_change('3a', '3b', tree.branch.repository)
1151
self.assertEqual(old, ['2a', '3a'])
1152
self.assertEqual(new, ['2b', '3b'])
1154
def test_unrelated(self):
1155
tree = self.setup_ac_tree()
1156
old, new = log.get_history_change('3a', '3c', tree.branch.repository)
1157
self.assertEqual(old, ['1a', '2a', '3a'])
1158
self.assertEqual(new, ['1c', '2c', '3c'])
1160
def test_show_branch_change(self):
1161
tree = self.setup_ab_tree()
1163
log.show_branch_change(tree.branch, s, 3, '3a')
1164
self.assertContainsRe(s.getvalue(),
1165
'[*]{60}\nRemoved Revisions:\n(.|\n)*2a(.|\n)*3a(.|\n)*'
1166
'[*]{60}\n\nAdded Revisions:\n(.|\n)*2b(.|\n)*3b')
1168
def test_show_branch_change_no_change(self):
1169
tree = self.setup_ab_tree()
1171
log.show_branch_change(tree.branch, s, 3, '3b')
1172
self.assertEqual(s.getvalue(),
1173
'Nothing seems to have changed\n')
1175
def test_show_branch_change_no_old(self):
1176
tree = self.setup_ab_tree()
1178
log.show_branch_change(tree.branch, s, 2, '2b')
1179
self.assertContainsRe(s.getvalue(), 'Added Revisions:')
1180
self.assertNotContainsRe(s.getvalue(), 'Removed Revisions:')
1182
def test_show_branch_change_no_new(self):
1183
tree = self.setup_ab_tree()
1184
tree.branch.set_last_revision_info(2, '2b')
1186
log.show_branch_change(tree.branch, s, 3, '3b')
1187
self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1188
self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1191
class TestRevisionNotInBranch(TestCaseForLogFormatter):
1193
def setup_a_tree(self):
1194
tree = self.make_branch_and_tree('tree')
1196
self.addCleanup(tree.unlock)
1198
'committer': 'Joe Foo <joe@foo.com>',
1199
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1200
'timezone': 0, # UTC
1202
tree.commit('commit 1a', rev_id='1a', **kwargs)
1203
tree.commit('commit 2a', rev_id='2a', **kwargs)
1204
tree.commit('commit 3a', rev_id='3a', **kwargs)
1207
def setup_ab_tree(self):
1208
tree = self.setup_a_tree()
1209
tree.set_last_revision('1a')
1210
tree.branch.set_last_revision_info(1, '1a')
1212
'committer': 'Joe Foo <joe@foo.com>',
1213
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1214
'timezone': 0, # UTC
1216
tree.commit('commit 2b', rev_id='2b', **kwargs)
1217
tree.commit('commit 3b', rev_id='3b', **kwargs)
1220
def test_one_revision(self):
1221
tree = self.setup_ab_tree()
1223
rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1224
log.show_log(tree.branch, lf, verbose=True, start_revision=rev,
1226
self.assertEqual(1, len(lf.revisions))
1227
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1228
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1230
def test_many_revisions(self):
1231
tree = self.setup_ab_tree()
1233
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1234
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1235
log.show_log(tree.branch, lf, verbose=True, start_revision=start_rev,
1236
end_revision=end_rev)
1237
self.assertEqual(3, len(lf.revisions))
1238
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1239
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1240
self.assertEqual(None, lf.revisions[1].revno) # Out-of-branch
1241
self.assertEqual('2a', lf.revisions[1].rev.revision_id)
1242
self.assertEqual('1', lf.revisions[2].revno) # In-branch
1244
def test_long_format(self):
1245
tree = self.setup_ab_tree()
1246
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1247
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1248
self.assertFormatterResult("""\
1249
------------------------------------------------------------
1251
committer: Joe Foo <joe@foo.com>
1253
timestamp: Tue 2005-11-22 00:00:00 +0000
1256
------------------------------------------------------------
1258
committer: Joe Foo <joe@foo.com>
1260
timestamp: Tue 2005-11-22 00:00:00 +0000
1263
------------------------------------------------------------
1265
committer: Joe Foo <joe@foo.com>
1267
timestamp: Tue 2005-11-22 00:00:00 +0000
1271
tree.branch, log.LongLogFormatter, show_log_kwargs={
1272
'start_revision': start_rev, 'end_revision': end_rev
1275
def test_short_format(self):
1276
tree = self.setup_ab_tree()
1277
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1278
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1279
self.assertFormatterResult("""\
1288
1 Joe Foo\t2005-11-22
1292
tree.branch, log.ShortLogFormatter, show_log_kwargs={
1293
'start_revision': start_rev, 'end_revision': end_rev
1296
def test_line_format(self):
1297
tree = self.setup_ab_tree()
1298
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1299
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1300
self.assertFormatterResult("""\
1301
Joe Foo 2005-11-22 commit 3a
1302
Joe Foo 2005-11-22 commit 2a
1303
1: Joe Foo 2005-11-22 commit 1a
1305
tree.branch, log.LineLogFormatter, show_log_kwargs={
1306
'start_revision': start_rev, 'end_revision': end_rev
1310
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1313
TestCaseForLogFormatter.setUp(self)
1314
log.properties_handler_registry.register(
1315
'bugs_properties_handler',
1316
log._bugs_properties_handler)
1318
def make_commits_with_bugs(self):
1319
"""Helper method for LogFormatter tests"""
1320
tree = self.make_branch_and_tree(u'.')
1321
self.build_tree(['a', 'b'])
1323
self.wt_commit(tree, 'simple log message', rev_id='a1',
1324
revprops={'bugs': 'test://bug/id fixed'})
1326
self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id='a2',
1327
authors=['Joe Bar <joe@bar.com>'],
1328
revprops={'bugs': 'test://bug/id fixed\n'
1329
'test://bug/2 fixed'})
1333
def test_long_bugs(self):
1334
tree = self.make_commits_with_bugs()
1335
self.assertFormatterResult("""\
1336
------------------------------------------------------------
1338
fixes bugs: test://bug/id test://bug/2
1339
author: Joe Bar <joe@bar.com>
1340
committer: Joe Foo <joe@foo.com>
1342
timestamp: Tue 2005-11-22 00:00:01 +0000
1347
------------------------------------------------------------
1349
fixes bug: test://bug/id
1350
committer: Joe Foo <joe@foo.com>
1352
timestamp: Tue 2005-11-22 00:00:00 +0000
1356
tree.branch, log.LongLogFormatter)
1358
def test_short_bugs(self):
1359
tree = self.make_commits_with_bugs()
1360
self.assertFormatterResult("""\
1361
2 Joe Bar\t2005-11-22
1362
fixes bugs: test://bug/id test://bug/2
1367
1 Joe Foo\t2005-11-22
1368
fixes bug: test://bug/id
1372
tree.branch, log.ShortLogFormatter)
1374
def test_wrong_bugs_property(self):
1375
tree = self.make_branch_and_tree(u'.')
1376
self.build_tree(['foo'])
1377
self.wt_commit(tree, 'simple log message', rev_id='a1',
1378
revprops={'bugs': 'test://bug/id invalid_value'})
1379
self.assertFormatterResult("""\
1380
1 Joe Foo\t2005-11-22
1384
tree.branch, log.ShortLogFormatter)
1386
def test_bugs_handler_present(self):
1387
self.properties_handler_registry.get('bugs_properties_handler')
1390
class TestLogForAuthors(TestCaseForLogFormatter):
1393
TestCaseForLogFormatter.setUp(self)
1394
self.wt = self.make_standard_commit('nicky',
1395
authors=['John Doe <jdoe@example.com>',
1396
'Jane Rey <jrey@example.com>'])
1398
def assertFormatterResult(self, formatter, who, result):
1399
formatter_kwargs = dict()
1401
author_list_handler = log.author_list_registry.get(who)
1402
formatter_kwargs['author_list_handler'] = author_list_handler
1403
TestCaseForLogFormatter.assertFormatterResult(self, result,
1404
self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1406
def test_line_default(self):
1407
self.assertFormatterResult(log.LineLogFormatter, None, """\
1408
1: John Doe 2005-11-22 add a
1411
def test_line_committer(self):
1412
self.assertFormatterResult(log.LineLogFormatter, 'committer', """\
1413
1: Lorem Ipsum 2005-11-22 add a
1416
def test_line_first(self):
1417
self.assertFormatterResult(log.LineLogFormatter, 'first', """\
1418
1: John Doe 2005-11-22 add a
1421
def test_line_all(self):
1422
self.assertFormatterResult(log.LineLogFormatter, 'all', """\
1423
1: John Doe, Jane Rey 2005-11-22 add a
1427
def test_short_default(self):
1428
self.assertFormatterResult(log.ShortLogFormatter, None, """\
1429
1 John Doe\t2005-11-22
1434
def test_short_committer(self):
1435
self.assertFormatterResult(log.ShortLogFormatter, 'committer', """\
1436
1 Lorem Ipsum\t2005-11-22
1441
def test_short_first(self):
1442
self.assertFormatterResult(log.ShortLogFormatter, 'first', """\
1443
1 John Doe\t2005-11-22
1448
def test_short_all(self):
1449
self.assertFormatterResult(log.ShortLogFormatter, 'all', """\
1450
1 John Doe, Jane Rey\t2005-11-22
1455
def test_long_default(self):
1456
self.assertFormatterResult(log.LongLogFormatter, None, """\
1457
------------------------------------------------------------
1459
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1460
committer: Lorem Ipsum <test@example.com>
1462
timestamp: Tue 2005-11-22 00:00:00 +0000
1467
def test_long_committer(self):
1468
self.assertFormatterResult(log.LongLogFormatter, 'committer', """\
1469
------------------------------------------------------------
1471
committer: Lorem Ipsum <test@example.com>
1473
timestamp: Tue 2005-11-22 00:00:00 +0000
1478
def test_long_first(self):
1479
self.assertFormatterResult(log.LongLogFormatter, 'first', """\
1480
------------------------------------------------------------
1482
author: John Doe <jdoe@example.com>
1483
committer: Lorem Ipsum <test@example.com>
1485
timestamp: Tue 2005-11-22 00:00:00 +0000
1490
def test_long_all(self):
1491
self.assertFormatterResult(log.LongLogFormatter, 'all', """\
1492
------------------------------------------------------------
1494
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1495
committer: Lorem Ipsum <test@example.com>
1497
timestamp: Tue 2005-11-22 00:00:00 +0000
1502
def test_gnu_changelog_default(self):
1503
self.assertFormatterResult(log.GnuChangelogLogFormatter, None, """\
1504
2005-11-22 John Doe <jdoe@example.com>
1510
def test_gnu_changelog_committer(self):
1511
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', """\
1512
2005-11-22 Lorem Ipsum <test@example.com>
1518
def test_gnu_changelog_first(self):
1519
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', """\
1520
2005-11-22 John Doe <jdoe@example.com>
1526
def test_gnu_changelog_all(self):
1527
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'all', """\
1528
2005-11-22 John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1535
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1537
def make_branch_with_alternate_ancestries(self, relpath='.'):
1538
# See test_merge_sorted_exclude_ancestry below for the difference with
1539
# bt.per_branch.test_iter_merge_sorted_revision.
1540
# TestIterMergeSortedRevisionsBushyGraph.
1541
# make_branch_with_alternate_ancestries
1542
# and test_merge_sorted_exclude_ancestry
1543
# See the FIXME in assertLogRevnos too.
1544
builder = branchbuilder.BranchBuilder(self.get_transport(relpath))
1556
builder.start_series()
1557
builder.build_snapshot('1', None, [
1558
('add', ('', 'TREE_ROOT', 'directory', '')),])
1559
builder.build_snapshot('1.1.1', ['1'], [])
1560
builder.build_snapshot('2', ['1'], [])
1561
builder.build_snapshot('1.2.1', ['1.1.1'], [])
1562
builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1563
builder.build_snapshot('3', ['2', '1.1.2'], [])
1564
builder.finish_series()
1565
br = builder.get_branch()
1567
self.addCleanup(br.unlock)
1570
def assertLogRevnos(self, expected_revnos, b, start, end,
1571
exclude_common_ancestry, generate_merge_revisions=True):
1572
# FIXME: the layering in log makes it hard to test intermediate levels,
1573
# I wish adding filters with their parameters were easier...
1575
iter_revs = log._calc_view_revisions(
1576
b, start, end, direction='reverse',
1577
generate_merge_revisions=generate_merge_revisions,
1578
exclude_common_ancestry=exclude_common_ancestry)
1579
self.assertEqual(expected_revnos,
1580
[revid for revid, revno, depth in iter_revs])
1582
def test_merge_sorted_exclude_ancestry(self):
1583
b = self.make_branch_with_alternate_ancestries()
1584
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1585
b, '1', '3', exclude_common_ancestry=False)
1586
# '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1587
# it should be mentioned even if merge_sort order will make it appear
1589
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1590
b, '1.1.1', '3', exclude_common_ancestry=True)
1592
def test_merge_sorted_simple_revnos_exclude_ancestry(self):
1593
b = self.make_branch_with_alternate_ancestries()
1594
self.assertLogRevnos(['3', '2'],
1595
b, '1', '3', exclude_common_ancestry=True,
1596
generate_merge_revisions=False)
1597
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2'],
1598
b, '1', '3', exclude_common_ancestry=True,
1599
generate_merge_revisions=True)
1602
class TestLogDefaults(TestCaseForLogFormatter):
1603
def test_default_log_level(self):
1605
Test to ensure that specifying 'levels=1' to make_log_request_dict
1606
doesn't get overwritten when using a LogFormatter that supports more
1610
wt = self._prepare_tree_with_merges()
1613
class CustomLogFormatter(log.LogFormatter):
1614
def __init__(self, *args, **kwargs):
1615
super(CustomLogFormatter, self).__init__(*args, **kwargs)
1617
def get_levels(self):
1618
# log formatter supports all levels:
1620
def log_revision(self, revision):
1621
self.revisions.append(revision)
1623
log_formatter = LogCatcher()
1624
# First request we don't specify number of levels, we should get a
1625
# sensible default (whatever the LogFormatter handles - which in this
1626
# case is 0/everything):
1627
request = log.make_log_request_dict(limit=10)
1628
log.Logger(b, request).show(log_formatter)
1629
# should have all three revisions:
1630
self.assertEquals(len(log_formatter.revisions), 3)
1633
log_formatter = LogCatcher()
1634
# now explicitly request mainline revisions only:
1635
request = log.make_log_request_dict(limit=10, levels=1)
1636
log.Logger(b, request).show(log_formatter)
1637
# should now only have 2 revisions:
1638
self.assertEquals(len(log_formatter.revisions), 2)