79
170
wt.commit('empty commit')
80
show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
81
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
82
start_revision=2, end_revision=1)
83
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
84
start_revision=1, end_revision=2)
85
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
86
start_revision=0, end_revision=2)
87
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
88
start_revision=1, end_revision=0)
89
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
90
start_revision=-1, end_revision=1)
91
self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
92
start_revision=1, end_revision=-1)
94
def test_simple_log(self):
95
eq = self.assertEquals
171
log.show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
173
# Since there is a single revision in the branch all the combinations
175
self.assertInvalidRevisonNumber(b, 2, 1)
176
self.assertInvalidRevisonNumber(b, 1, 2)
177
self.assertInvalidRevisonNumber(b, 0, 2)
178
self.assertInvalidRevisonNumber(b, 1, 0)
179
self.assertInvalidRevisonNumber(b, -1, 1)
180
self.assertInvalidRevisonNumber(b, 1, -1)
182
def test_empty_branch(self):
97
183
wt = self.make_branch_and_tree('.')
100
185
lf = LogCatcher()
186
log.show_log(wt.branch, lf)
188
self.assertEqual([], lf.revisions)
190
def test_empty_commit(self):
191
wt = self.make_branch_and_tree('.')
105
193
wt.commit('empty commit')
106
194
lf = LogCatcher()
107
show_log(b, lf, verbose=True)
109
eq(lf.logs[0].revno, '1')
110
eq(lf.logs[0].rev.message, 'empty commit')
112
self.log('log delta: %r' % d)
195
log.show_log(wt.branch, lf, verbose=True)
197
self.assertEqual(1, len(revs))
198
self.assertEqual('1', revs[0].revno)
199
self.assertEqual('empty commit', revs[0].rev.message)
200
self.checkDelta(revs[0].delta)
202
def test_simple_commit(self):
203
wt = self.make_branch_and_tree('.')
204
wt.commit('empty commit')
115
205
self.build_tree(['hello'])
117
wt.commit('add one file')
120
# log using regular thing
121
show_log(b, LongLogFormatter(lf))
123
for l in lf.readlines():
126
# get log as data structure
207
wt.commit('add one file',
208
committer=u'\u013d\xf3r\xe9m \xcdp\u0161\xfam '
209
u'<test@example.com>')
127
210
lf = LogCatcher()
128
show_log(b, lf, verbose=True)
130
self.log('log entries:')
131
for logentry in lf.logs:
132
self.log('%4s %s' % (logentry.revno, logentry.rev.message))
211
log.show_log(wt.branch, lf, verbose=True)
212
self.assertEqual(2, len(lf.revisions))
134
213
# first one is most recent
135
logentry = lf.logs[0]
136
eq(logentry.revno, '2')
137
eq(logentry.rev.message, 'add one file')
139
self.log('log 2 delta: %r' % d)
140
# self.checkDelta(d, added=['hello'])
142
# commit a log message with control characters
143
msg = "All 8-bit chars: " + ''.join([unichr(x) for x in range(256)])
144
self.log("original commit message: %r", msg)
214
log_entry = lf.revisions[0]
215
self.assertEqual('2', log_entry.revno)
216
self.assertEqual('add one file', log_entry.rev.message)
217
self.checkDelta(log_entry.delta, added=['hello'])
219
def test_commit_message_with_control_chars(self):
220
wt = self.make_branch_and_tree('.')
221
msg = u"All 8-bit chars: " + ''.join([unichr(x) for x in range(256)])
222
msg = msg.replace(u'\r', u'\n')
146
224
lf = LogCatcher()
147
show_log(b, lf, verbose=True)
148
committed_msg = lf.logs[0].rev.message
149
self.log("escaped commit message: %r", committed_msg)
150
self.assert_(msg != committed_msg)
151
self.assert_(len(committed_msg) > len(msg))
225
log.show_log(wt.branch, lf, verbose=True)
226
committed_msg = lf.revisions[0].rev.message
227
if wt.branch.repository._serializer.squashes_xml_invalid_characters:
228
self.assertNotEqual(msg, committed_msg)
229
self.assertTrue(len(committed_msg) > len(msg))
231
self.assertEqual(msg, committed_msg)
153
# Check that log message with only XML-valid characters isn't
233
def test_commit_message_without_control_chars(self):
234
wt = self.make_branch_and_tree('.')
154
235
# escaped. As ElementTree apparently does some kind of
155
236
# newline conversion, neither LF (\x0A) nor CR (\x0D) are
156
237
# included in the test commit message, even though they are
157
238
# valid XML 1.0 characters.
158
239
msg = "\x09" + ''.join([unichr(x) for x in range(0x20, 256)])
159
self.log("original commit message: %r", msg)
161
241
lf = LogCatcher()
162
show_log(b, lf, verbose=True)
163
committed_msg = lf.logs[0].rev.message
164
self.log("escaped commit message: %r", committed_msg)
165
self.assert_(msg == committed_msg)
242
log.show_log(wt.branch, lf, verbose=True)
243
committed_msg = lf.revisions[0].rev.message
244
self.assertEqual(msg, committed_msg)
246
def test_deltas_in_merge_revisions(self):
247
"""Check deltas created for both mainline and merge revisions"""
248
wt = self.make_branch_and_tree('parent')
249
self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
252
wt.commit(message='add file1 and file2')
253
self.run_bzr('branch parent child')
254
os.unlink('child/file1')
255
with file('child/file2', 'wb') as f: f.write('hello\n')
256
self.run_bzr(['commit', '-m', 'remove file1 and modify file2',
259
self.run_bzr('merge ../child')
260
wt.commit('merge child branch')
264
lf.supports_merge_revisions = True
265
log.show_log(b, lf, verbose=True)
268
self.assertEqual(3, len(revs))
271
self.assertEqual('2', logentry.revno)
272
self.assertEqual('merge child branch', logentry.rev.message)
273
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
276
self.assertEqual('1.1.1', logentry.revno)
277
self.assertEqual('remove file1 and modify file2', logentry.rev.message)
278
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
281
self.assertEqual('1', logentry.revno)
282
self.assertEqual('add file1 and file2', logentry.rev.message)
283
self.checkDelta(logentry.delta, added=['file1', 'file2'])
286
class TestFormatSignatureValidity(tests.TestCaseWithTransport):
287
class UTFLoopbackGPGStrategy(gpg.LoopbackGPGStrategy):
288
def verify(self, content, testament):
289
return (gpg.SIGNATURE_VALID,
290
u'UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>')
292
def has_signature_for_revision_id(self, revision_id):
295
def get_signature_text(self, revision_id):
298
def test_format_signature_validity_utf(self):
299
"""Check that GPG signatures containing UTF-8 names are formatted
301
# Monkey patch to use our UTF-8 generating GPGStrategy
302
self.overrideAttr(gpg, 'GPGStrategy', self.UTFLoopbackGPGStrategy)
303
wt = self.make_branch_and_tree('.')
304
revid = wt.commit('empty commit')
305
repo = wt.branch.repository
306
# Monkey patch out checking if this rev is actually signed, since we
307
# can't sign it without a heavier TestCase and LoopbackGPGStrategy
308
# doesn't care anyways.
309
self.overrideAttr(repo, 'has_signature_for_revision_id',
310
self.has_signature_for_revision_id)
311
self.overrideAttr(repo, 'get_signature_text', self.get_signature_text)
312
out = log.format_signature_validity(revid, repo)
314
u'valid signature from UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>',
318
class TestShortLogFormatter(TestCaseForLogFormatter):
167
320
def test_trailing_newlines(self):
168
321
wt = self.make_branch_and_tree('.')
171
open('a', 'wb').write('hello moto\n')
173
wt.commit('simple log message', rev_id='a1'
174
, timestamp=1132586655.459960938, timezone=-6*3600
175
, committer='Joe Foo <joe@foo.com>')
176
open('b', 'wb').write('goodbye\n')
178
wt.commit('multiline\nlog\nmessage\n', rev_id='a2'
179
, timestamp=1132586842.411175966, timezone=-6*3600
180
, committer='Joe Foo <joe@foo.com>')
182
open('c', 'wb').write('just another manic monday\n')
184
wt.commit('single line with trailing newline\n', rev_id='a3'
185
, timestamp=1132587176.835228920, timezone=-6*3600
186
, committer = 'Joe Foo <joe@foo.com>')
189
lf = ShortLogFormatter(to_file=sio)
191
self.assertEquals(sio.getvalue(), """\
192
3 Joe Foo\t2005-11-21
322
b = self.make_commits_with_trailing_newlines(wt)
323
self.assertFormatterResult("""\
324
3 Joe Foo\t2005-11-22
193
325
single line with trailing newline
195
2 Joe Foo\t2005-11-21
327
2 Joe Foo\t2005-11-22
200
1 Joe Foo\t2005-11-21
332
1 Joe Foo\t2005-11-22
201
333
simple log message
206
lf = LongLogFormatter(to_file=sio)
208
self.assertEquals(sio.getvalue(), """\
209
------------------------------------------------------------
211
committer: Joe Foo <joe@foo.com>
213
timestamp: Mon 2005-11-21 09:32:56 -0600
215
single line with trailing newline
216
------------------------------------------------------------
218
committer: Joe Foo <joe@foo.com>
220
timestamp: Mon 2005-11-21 09:27:22 -0600
225
------------------------------------------------------------
227
committer: Joe Foo <joe@foo.com>
229
timestamp: Mon 2005-11-21 09:24:15 -0600
336
b, log.ShortLogFormatter)
338
def test_short_log_with_merges(self):
339
wt = self._prepare_tree_with_merges()
340
self.assertFormatterResult("""\
341
2 Joe Foo\t2005-11-22 [merge]
344
1 Joe Foo\t2005-11-22
348
wt.branch, log.ShortLogFormatter)
350
def test_short_log_with_merges_and_advice(self):
351
wt = self._prepare_tree_with_merges()
352
self.assertFormatterResult("""\
353
2 Joe Foo\t2005-11-22 [merge]
356
1 Joe Foo\t2005-11-22
359
Use --include-merged or -n0 to see merged revisions.
361
wt.branch, log.ShortLogFormatter,
362
formatter_kwargs=dict(show_advice=True))
364
def test_short_log_with_merges_and_range(self):
365
wt = self._prepare_tree_with_merges()
366
self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
367
wt.branch.set_last_revision_info(2, 'rev-2b')
368
wt.set_parent_ids(['rev-2b', 'rev-3a'])
369
self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
370
self.assertFormatterResult("""\
371
3 Joe Foo\t2005-11-22 [merge]
374
2 Joe Foo\t2005-11-22 [merge]
378
wt.branch, log.ShortLogFormatter,
379
show_log_kwargs=dict(start_revision=2, end_revision=3))
381
def test_short_log_with_tags(self):
382
wt = self._prepare_tree_with_merges(with_tags=True)
383
self.assertFormatterResult("""\
384
3 Joe Foo\t2005-11-22 {v1.0, v1.0rc1}
387
2 Joe Foo\t2005-11-22 {v0.2} [merge]
390
1 Joe Foo\t2005-11-22
394
wt.branch, log.ShortLogFormatter)
396
def test_short_log_single_merge_revision(self):
397
wt = self._prepare_tree_with_merges()
398
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
399
rev = revspec.in_history(wt.branch)
400
self.assertFormatterResult("""\
401
1.1.1 Joe Foo\t2005-11-22
405
wt.branch, log.ShortLogFormatter,
406
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
408
def test_show_ids(self):
409
wt = self.make_branch_and_tree('parent')
410
self.build_tree(['parent/f1', 'parent/f2'])
412
self.wt_commit(wt, 'first post', rev_id='a')
413
child_wt = wt.bzrdir.sprout('child').open_workingtree()
414
self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
415
wt.merge_from_branch(child_wt.branch)
416
self.wt_commit(wt, 'merge branch 1', rev_id='c')
417
self.assertFormatterResult("""\
418
2 Joe Foo\t2005-11-22 [merge]
422
1.1.1 Joe Foo\t2005-11-22
426
1 Joe Foo\t2005-11-22
431
wt.branch, log.ShortLogFormatter,
432
formatter_kwargs=dict(levels=0,show_ids=True))
435
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
437
def test_short_merge_revs_log_with_merges(self):
438
wt = self._prepare_tree_with_merges()
439
# Note that the 1.1.1 indenting is in fact correct given that
440
# the revision numbers are right justified within 5 characters
441
# for mainline revnos and 9 characters for dotted revnos.
442
self.assertFormatterResult("""\
443
2 Joe Foo\t2005-11-22 [merge]
446
1.1.1 Joe Foo\t2005-11-22
449
1 Joe Foo\t2005-11-22
453
wt.branch, log.ShortLogFormatter,
454
formatter_kwargs=dict(levels=0))
456
def test_short_merge_revs_log_single_merge_revision(self):
457
wt = self._prepare_tree_with_merges()
458
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
459
rev = revspec.in_history(wt.branch)
460
self.assertFormatterResult("""\
461
1.1.1 Joe Foo\t2005-11-22
465
wt.branch, log.ShortLogFormatter,
466
formatter_kwargs=dict(levels=0),
467
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
470
class TestLongLogFormatter(TestCaseForLogFormatter):
234
472
def test_verbose_log(self):
235
473
"""Verbose log includes changed files
239
wt = self.make_branch_and_tree('.')
241
self.build_tree(['a'])
243
# XXX: why does a longer nick show up?
244
b.nick = 'test_verbose_log'
245
wt.commit(message='add a',
246
timestamp=1132711707,
248
committer='Lorem Ipsum <test@example.com>')
249
logfile = file('out.tmp', 'w+')
250
formatter = LongLogFormatter(to_file=logfile)
251
show_log(b, formatter, verbose=True)
254
log_contents = logfile.read()
255
self.assertEqualDiff(log_contents, '''\
477
wt = self.make_standard_commit('test_verbose_log', authors=[])
478
self.assertFormatterResult('''\
256
479
------------------------------------------------------------
258
481
committer: Lorem Ipsum <test@example.com>
259
482
branch nick: test_verbose_log
260
timestamp: Wed 2005-11-23 12:08:27 +1000
483
timestamp: Tue 2005-11-22 00:00:00 +0000
489
wt.branch, log.LongLogFormatter,
490
show_log_kwargs=dict(verbose=True))
492
def test_merges_are_indented_by_level(self):
493
wt = self.make_branch_and_tree('parent')
494
self.wt_commit(wt, 'first post')
495
child_wt = wt.bzrdir.sprout('child').open_workingtree()
496
self.wt_commit(child_wt, 'branch 1')
497
smallerchild_wt = wt.bzrdir.sprout('smallerchild').open_workingtree()
498
self.wt_commit(smallerchild_wt, 'branch 2')
499
child_wt.merge_from_branch(smallerchild_wt.branch)
500
self.wt_commit(child_wt, 'merge branch 2')
501
wt.merge_from_branch(child_wt.branch)
502
self.wt_commit(wt, 'merge branch 1')
503
self.assertFormatterResult("""\
504
------------------------------------------------------------
506
committer: Joe Foo <joe@foo.com>
508
timestamp: Tue 2005-11-22 00:00:04 +0000
511
------------------------------------------------------------
513
committer: Joe Foo <joe@foo.com>
515
timestamp: Tue 2005-11-22 00:00:03 +0000
518
------------------------------------------------------------
520
committer: Joe Foo <joe@foo.com>
521
branch nick: smallerchild
522
timestamp: Tue 2005-11-22 00:00:02 +0000
525
------------------------------------------------------------
527
committer: Joe Foo <joe@foo.com>
529
timestamp: Tue 2005-11-22 00:00:01 +0000
532
------------------------------------------------------------
534
committer: Joe Foo <joe@foo.com>
536
timestamp: Tue 2005-11-22 00:00:00 +0000
540
wt.branch, log.LongLogFormatter,
541
formatter_kwargs=dict(levels=0),
542
show_log_kwargs=dict(verbose=True))
544
def test_verbose_merge_revisions_contain_deltas(self):
545
wt = self.make_branch_and_tree('parent')
546
self.build_tree(['parent/f1', 'parent/f2'])
548
self.wt_commit(wt, 'first post')
549
child_wt = wt.bzrdir.sprout('child').open_workingtree()
550
os.unlink('child/f1')
551
self.build_tree_contents([('child/f2', 'hello\n')])
552
self.wt_commit(child_wt, 'removed f1 and modified f2')
553
wt.merge_from_branch(child_wt.branch)
554
self.wt_commit(wt, 'merge branch 1')
555
self.assertFormatterResult("""\
556
------------------------------------------------------------
558
committer: Joe Foo <joe@foo.com>
560
timestamp: Tue 2005-11-22 00:00:02 +0000
567
------------------------------------------------------------
569
committer: Joe Foo <joe@foo.com>
571
timestamp: Tue 2005-11-22 00:00:01 +0000
573
removed f1 and modified f2
578
------------------------------------------------------------
580
committer: Joe Foo <joe@foo.com>
582
timestamp: Tue 2005-11-22 00:00:00 +0000
589
wt.branch, log.LongLogFormatter,
590
formatter_kwargs=dict(levels=0),
591
show_log_kwargs=dict(verbose=True))
593
def test_trailing_newlines(self):
594
wt = self.make_branch_and_tree('.')
595
b = self.make_commits_with_trailing_newlines(wt)
596
self.assertFormatterResult("""\
597
------------------------------------------------------------
599
committer: Joe Foo <joe@foo.com>
601
timestamp: Tue 2005-11-22 00:00:02 +0000
603
single line with trailing newline
604
------------------------------------------------------------
606
committer: Joe Foo <joe@foo.com>
608
timestamp: Tue 2005-11-22 00:00:01 +0000
613
------------------------------------------------------------
615
committer: Joe Foo <joe@foo.com>
617
timestamp: Tue 2005-11-22 00:00:00 +0000
621
b, log.LongLogFormatter)
623
def test_author_in_log(self):
624
"""Log includes the author name if it's set in
625
the revision properties
627
wt = self.make_standard_commit('test_author_log',
628
authors=['John Doe <jdoe@example.com>',
629
'Jane Rey <jrey@example.com>'])
630
self.assertFormatterResult("""\
631
------------------------------------------------------------
633
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
634
committer: Lorem Ipsum <test@example.com>
635
branch nick: test_author_log
636
timestamp: Tue 2005-11-22 00:00:00 +0000
640
wt.branch, log.LongLogFormatter)
642
def test_properties_in_log(self):
643
"""Log includes the custom properties returned by the registered
646
wt = self.make_standard_commit('test_properties_in_log')
647
def trivial_custom_prop_handler(revision):
648
return {'test_prop':'test_value'}
650
# Cleaned up in setUp()
651
log.properties_handler_registry.register(
652
'trivial_custom_prop_handler',
653
trivial_custom_prop_handler)
654
self.assertFormatterResult("""\
655
------------------------------------------------------------
657
test_prop: test_value
658
author: John Doe <jdoe@example.com>
659
committer: Lorem Ipsum <test@example.com>
660
branch nick: test_properties_in_log
661
timestamp: Tue 2005-11-22 00:00:00 +0000
665
wt.branch, log.LongLogFormatter)
667
def test_properties_in_short_log(self):
668
"""Log includes the custom properties returned by the registered
671
wt = self.make_standard_commit('test_properties_in_short_log')
672
def trivial_custom_prop_handler(revision):
673
return {'test_prop':'test_value'}
675
log.properties_handler_registry.register(
676
'trivial_custom_prop_handler',
677
trivial_custom_prop_handler)
678
self.assertFormatterResult("""\
679
1 John Doe\t2005-11-22
680
test_prop: test_value
684
wt.branch, log.ShortLogFormatter)
686
def test_error_in_properties_handler(self):
687
"""Log includes the custom properties returned by the registered
690
wt = self.make_standard_commit('error_in_properties_handler',
691
revprops={'first_prop':'first_value'})
692
sio = self.make_utf8_encoded_stringio()
693
formatter = log.LongLogFormatter(to_file=sio)
694
def trivial_custom_prop_handler(revision):
695
raise StandardError("a test error")
697
log.properties_handler_registry.register(
698
'trivial_custom_prop_handler',
699
trivial_custom_prop_handler)
700
self.assertRaises(StandardError, log.show_log, wt.branch, formatter,)
702
def test_properties_handler_bad_argument(self):
703
wt = self.make_standard_commit('bad_argument',
704
revprops={'a_prop':'test_value'})
705
sio = self.make_utf8_encoded_stringio()
706
formatter = log.LongLogFormatter(to_file=sio)
707
def bad_argument_prop_handler(revision):
708
return {'custom_prop_name':revision.properties['a_prop']}
710
log.properties_handler_registry.register(
711
'bad_argument_prop_handler',
712
bad_argument_prop_handler)
714
self.assertRaises(AttributeError, formatter.show_properties,
717
revision = wt.branch.repository.get_revision(wt.branch.last_revision())
718
formatter.show_properties(revision, '')
719
self.assertEqualDiff('''custom_prop_name: test_value\n''',
722
def test_show_ids(self):
723
wt = self.make_branch_and_tree('parent')
724
self.build_tree(['parent/f1', 'parent/f2'])
726
self.wt_commit(wt, 'first post', rev_id='a')
727
child_wt = wt.bzrdir.sprout('child').open_workingtree()
728
self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
729
wt.merge_from_branch(child_wt.branch)
730
self.wt_commit(wt, 'merge branch 1', rev_id='c')
731
self.assertFormatterResult("""\
732
------------------------------------------------------------
737
committer: Joe Foo <joe@foo.com>
739
timestamp: Tue 2005-11-22 00:00:02 +0000
742
------------------------------------------------------------
746
committer: Joe Foo <joe@foo.com>
748
timestamp: Tue 2005-11-22 00:00:01 +0000
751
------------------------------------------------------------
754
committer: Joe Foo <joe@foo.com>
756
timestamp: Tue 2005-11-22 00:00:00 +0000
760
wt.branch, log.LongLogFormatter,
761
formatter_kwargs=dict(levels=0,show_ids=True))
764
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
766
def test_long_verbose_log(self):
767
"""Verbose log includes changed files
771
wt = self.make_standard_commit('test_long_verbose_log', authors=[])
772
self.assertFormatterResult("""\
773
------------------------------------------------------------
775
committer: Lorem Ipsum <test@example.com>
776
branch nick: test_long_verbose_log
777
timestamp: Tue 2005-11-22 00:00:00 +0000
783
wt.branch, log.LongLogFormatter,
784
formatter_kwargs=dict(levels=1),
785
show_log_kwargs=dict(verbose=True))
787
def test_long_verbose_contain_deltas(self):
788
wt = self.make_branch_and_tree('parent')
789
self.build_tree(['parent/f1', 'parent/f2'])
791
self.wt_commit(wt, 'first post')
792
child_wt = wt.bzrdir.sprout('child').open_workingtree()
793
os.unlink('child/f1')
794
self.build_tree_contents([('child/f2', 'hello\n')])
795
self.wt_commit(child_wt, 'removed f1 and modified f2')
796
wt.merge_from_branch(child_wt.branch)
797
self.wt_commit(wt, 'merge branch 1')
798
self.assertFormatterResult("""\
799
------------------------------------------------------------
801
committer: Joe Foo <joe@foo.com>
803
timestamp: Tue 2005-11-22 00:00:02 +0000
810
------------------------------------------------------------
812
committer: Joe Foo <joe@foo.com>
814
timestamp: Tue 2005-11-22 00:00:00 +0000
821
wt.branch, log.LongLogFormatter,
822
formatter_kwargs=dict(levels=1),
823
show_log_kwargs=dict(verbose=True))
825
def test_long_trailing_newlines(self):
826
wt = self.make_branch_and_tree('.')
827
b = self.make_commits_with_trailing_newlines(wt)
828
self.assertFormatterResult("""\
829
------------------------------------------------------------
831
committer: Joe Foo <joe@foo.com>
833
timestamp: Tue 2005-11-22 00:00:02 +0000
835
single line with trailing newline
836
------------------------------------------------------------
838
committer: Joe Foo <joe@foo.com>
840
timestamp: Tue 2005-11-22 00:00:01 +0000
845
------------------------------------------------------------
847
committer: Joe Foo <joe@foo.com>
849
timestamp: Tue 2005-11-22 00:00:00 +0000
853
b, log.LongLogFormatter,
854
formatter_kwargs=dict(levels=1))
856
def test_long_author_in_log(self):
857
"""Log includes the author name if it's set in
858
the revision properties
860
wt = self.make_standard_commit('test_author_log')
861
self.assertFormatterResult("""\
862
------------------------------------------------------------
864
author: John Doe <jdoe@example.com>
865
committer: Lorem Ipsum <test@example.com>
866
branch nick: test_author_log
867
timestamp: Tue 2005-11-22 00:00:00 +0000
871
wt.branch, log.LongLogFormatter,
872
formatter_kwargs=dict(levels=1))
874
def test_long_properties_in_log(self):
875
"""Log includes the custom properties returned by the registered
878
wt = self.make_standard_commit('test_properties_in_log')
879
def trivial_custom_prop_handler(revision):
880
return {'test_prop':'test_value'}
882
log.properties_handler_registry.register(
883
'trivial_custom_prop_handler',
884
trivial_custom_prop_handler)
885
self.assertFormatterResult("""\
886
------------------------------------------------------------
888
test_prop: test_value
889
author: John Doe <jdoe@example.com>
890
committer: Lorem Ipsum <test@example.com>
891
branch nick: test_properties_in_log
892
timestamp: Tue 2005-11-22 00:00:00 +0000
896
wt.branch, log.LongLogFormatter,
897
formatter_kwargs=dict(levels=1))
900
class TestLineLogFormatter(TestCaseForLogFormatter):
267
902
def test_line_log(self):
268
903
"""Line log should show revno
907
wt = self.make_standard_commit('test-line-log',
908
committer='Line-Log-Formatter Tester <test@line.log>',
910
self.assertFormatterResult("""\
911
1: Line-Log-Formatte... 2005-11-22 add a
913
wt.branch, log.LineLogFormatter)
915
def test_trailing_newlines(self):
272
916
wt = self.make_branch_and_tree('.')
917
b = self.make_commits_with_trailing_newlines(wt)
918
self.assertFormatterResult("""\
919
3: Joe Foo 2005-11-22 single line with trailing newline
920
2: Joe Foo 2005-11-22 multiline
921
1: Joe Foo 2005-11-22 simple log message
923
b, log.LineLogFormatter)
925
def test_line_log_single_merge_revision(self):
926
wt = self._prepare_tree_with_merges()
927
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
928
rev = revspec.in_history(wt.branch)
929
self.assertFormatterResult("""\
930
1.1.1: Joe Foo 2005-11-22 rev-merged
932
wt.branch, log.LineLogFormatter,
933
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
935
def test_line_log_with_tags(self):
936
wt = self._prepare_tree_with_merges(with_tags=True)
937
self.assertFormatterResult("""\
938
3: Joe Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
939
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
940
1: Joe Foo 2005-11-22 rev-1
942
wt.branch, log.LineLogFormatter)
945
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
947
def test_line_merge_revs_log(self):
948
"""Line log should show revno
952
wt = self.make_standard_commit('test-line-log',
953
committer='Line-Log-Formatter Tester <test@line.log>',
955
self.assertFormatterResult("""\
956
1: Line-Log-Formatte... 2005-11-22 add a
958
wt.branch, log.LineLogFormatter)
960
def test_line_merge_revs_log_single_merge_revision(self):
961
wt = self._prepare_tree_with_merges()
962
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
963
rev = revspec.in_history(wt.branch)
964
self.assertFormatterResult("""\
965
1.1.1: Joe Foo 2005-11-22 rev-merged
967
wt.branch, log.LineLogFormatter,
968
formatter_kwargs=dict(levels=0),
969
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
971
def test_line_merge_revs_log_with_merges(self):
972
wt = self._prepare_tree_with_merges()
973
self.assertFormatterResult("""\
974
2: Joe Foo 2005-11-22 [merge] rev-2
975
1.1.1: Joe Foo 2005-11-22 rev-merged
976
1: Joe Foo 2005-11-22 rev-1
978
wt.branch, log.LineLogFormatter,
979
formatter_kwargs=dict(levels=0))
982
class TestGnuChangelogFormatter(TestCaseForLogFormatter):
984
def test_gnu_changelog(self):
985
wt = self.make_standard_commit('nicky', authors=[])
986
self.assertFormatterResult('''\
987
2005-11-22 Lorem Ipsum <test@example.com>
992
wt.branch, log.GnuChangelogLogFormatter)
994
def test_with_authors(self):
995
wt = self.make_standard_commit('nicky',
996
authors=['Fooa Fooz <foo@example.com>',
997
'Bari Baro <bar@example.com>'])
998
self.assertFormatterResult('''\
999
2005-11-22 Fooa Fooz <foo@example.com>
1004
wt.branch, log.GnuChangelogLogFormatter)
1006
def test_verbose(self):
1007
wt = self.make_standard_commit('nicky')
1008
self.assertFormatterResult('''\
1009
2005-11-22 John Doe <jdoe@example.com>
1016
wt.branch, log.GnuChangelogLogFormatter,
1017
show_log_kwargs=dict(verbose=True))
1020
class TestShowChangedRevisions(tests.TestCaseWithTransport):
1022
def test_show_changed_revisions_verbose(self):
1023
tree = self.make_branch_and_tree('tree_a')
1024
self.build_tree(['tree_a/foo'])
1026
tree.commit('bar', rev_id='bar-id')
1027
s = self.make_utf8_encoded_stringio()
1028
log.show_changed_revisions(tree.branch, [], ['bar-id'], s)
1029
self.assertContainsRe(s.getvalue(), 'bar')
1030
self.assertNotContainsRe(s.getvalue(), 'foo')
1033
class TestLogFormatter(tests.TestCase):
1036
super(TestLogFormatter, self).setUp()
1037
self.rev = revision.Revision('a-id')
1038
self.lf = log.LogFormatter(None)
1040
def test_short_committer(self):
1041
def assertCommitter(expected, committer):
1042
self.rev.committer = committer
1043
self.assertEqual(expected, self.lf.short_committer(self.rev))
1045
assertCommitter('John Doe', 'John Doe <jdoe@example.com>')
1046
assertCommitter('John Smith', 'John Smith <jsmith@example.com>')
1047
assertCommitter('John Smith', 'John Smith')
1048
assertCommitter('jsmith@example.com', 'jsmith@example.com')
1049
assertCommitter('jsmith@example.com', '<jsmith@example.com>')
1050
assertCommitter('John Smith', 'John Smith jsmith@example.com')
1052
def test_short_author(self):
1053
def assertAuthor(expected, author):
1054
self.rev.properties['author'] = author
1055
self.assertEqual(expected, self.lf.short_author(self.rev))
1057
assertAuthor('John Smith', 'John Smith <jsmith@example.com>')
1058
assertAuthor('John Smith', 'John Smith')
1059
assertAuthor('jsmith@example.com', 'jsmith@example.com')
1060
assertAuthor('jsmith@example.com', '<jsmith@example.com>')
1061
assertAuthor('John Smith', 'John Smith jsmith@example.com')
1063
def test_short_author_from_committer(self):
1064
self.rev.committer = 'John Doe <jdoe@example.com>'
1065
self.assertEqual('John Doe', self.lf.short_author(self.rev))
1067
def test_short_author_from_authors(self):
1068
self.rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1069
'Jane Rey <jrey@example.com>')
1070
self.assertEqual('John Smith', self.lf.short_author(self.rev))
1073
class TestReverseByDepth(tests.TestCase):
1074
"""Test reverse_by_depth behavior.
1076
This is used to present revisions in forward (oldest first) order in a nice
1079
The tests use lighter revision description to ease reading.
1082
def assertReversed(self, forward, backward):
1083
# Transform the descriptions to suit the API: tests use (revno, depth),
1084
# while the API expects (revid, revno, depth)
1085
def complete_revisions(l):
1086
"""Transform the description to suit the API.
1088
Tests use (revno, depth) whil the API expects (revid, revno, depth).
1089
Since the revid is arbitrary, we just duplicate revno
1091
return [ (r, r, d) for r, d in l]
1092
forward = complete_revisions(forward)
1093
backward= complete_revisions(backward)
1094
self.assertEqual(forward, log.reverse_by_depth(backward))
1097
def test_mainline_revisions(self):
1098
self.assertReversed([( '1', 0), ('2', 0)],
1099
[('2', 0), ('1', 0)])
1101
def test_merged_revisions(self):
1102
self.assertReversed([('1', 0), ('2', 0), ('2.2', 1), ('2.1', 1),],
1103
[('2', 0), ('2.1', 1), ('2.2', 1), ('1', 0),])
1104
def test_shifted_merged_revisions(self):
1105
"""Test irregular layout.
1107
Requesting revisions touching a file can produce "holes" in the depths.
1109
self.assertReversed([('1', 0), ('2', 0), ('1.1', 2), ('1.2', 2),],
1110
[('2', 0), ('1.2', 2), ('1.1', 2), ('1', 0),])
1112
def test_merged_without_child_revisions(self):
1113
"""Test irregular layout.
1115
Revision ranges can produce "holes" in the depths.
1117
# When a revision of higher depth doesn't follow one of lower depth, we
1118
# assume a lower depth one is virtually there
1119
self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1120
[('4', 4), ('3', 3), ('2', 2), ('1', 2),])
1121
# So we get the same order after reversing below even if the original
1122
# revisions are not in the same order.
1123
self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1124
[('3', 3), ('4', 4), ('2', 2), ('1', 2),])
1127
class TestHistoryChange(tests.TestCaseWithTransport):
1129
def setup_a_tree(self):
1130
tree = self.make_branch_and_tree('tree')
1132
self.addCleanup(tree.unlock)
1133
tree.commit('1a', rev_id='1a')
1134
tree.commit('2a', rev_id='2a')
1135
tree.commit('3a', rev_id='3a')
1138
def setup_ab_tree(self):
1139
tree = self.setup_a_tree()
1140
tree.set_last_revision('1a')
1141
tree.branch.set_last_revision_info(1, '1a')
1142
tree.commit('2b', rev_id='2b')
1143
tree.commit('3b', rev_id='3b')
1146
def setup_ac_tree(self):
1147
tree = self.setup_a_tree()
1148
tree.set_last_revision(revision.NULL_REVISION)
1149
tree.branch.set_last_revision_info(0, revision.NULL_REVISION)
1150
tree.commit('1c', rev_id='1c')
1151
tree.commit('2c', rev_id='2c')
1152
tree.commit('3c', rev_id='3c')
1155
def test_all_new(self):
1156
tree = self.setup_ab_tree()
1157
old, new = log.get_history_change('1a', '3a', tree.branch.repository)
1158
self.assertEqual([], old)
1159
self.assertEqual(['2a', '3a'], new)
1161
def test_all_old(self):
1162
tree = self.setup_ab_tree()
1163
old, new = log.get_history_change('3a', '1a', tree.branch.repository)
1164
self.assertEqual([], new)
1165
self.assertEqual(['2a', '3a'], old)
1167
def test_null_old(self):
1168
tree = self.setup_ab_tree()
1169
old, new = log.get_history_change(revision.NULL_REVISION,
1170
'3a', tree.branch.repository)
1171
self.assertEqual([], old)
1172
self.assertEqual(['1a', '2a', '3a'], new)
1174
def test_null_new(self):
1175
tree = self.setup_ab_tree()
1176
old, new = log.get_history_change('3a', revision.NULL_REVISION,
1177
tree.branch.repository)
1178
self.assertEqual([], new)
1179
self.assertEqual(['1a', '2a', '3a'], old)
1181
def test_diverged(self):
1182
tree = self.setup_ab_tree()
1183
old, new = log.get_history_change('3a', '3b', tree.branch.repository)
1184
self.assertEqual(old, ['2a', '3a'])
1185
self.assertEqual(new, ['2b', '3b'])
1187
def test_unrelated(self):
1188
tree = self.setup_ac_tree()
1189
old, new = log.get_history_change('3a', '3c', tree.branch.repository)
1190
self.assertEqual(old, ['1a', '2a', '3a'])
1191
self.assertEqual(new, ['1c', '2c', '3c'])
1193
def test_show_branch_change(self):
1194
tree = self.setup_ab_tree()
1196
log.show_branch_change(tree.branch, s, 3, '3a')
1197
self.assertContainsRe(s.getvalue(),
1198
'[*]{60}\nRemoved Revisions:\n(.|\n)*2a(.|\n)*3a(.|\n)*'
1199
'[*]{60}\n\nAdded Revisions:\n(.|\n)*2b(.|\n)*3b')
1201
def test_show_branch_change_no_change(self):
1202
tree = self.setup_ab_tree()
1204
log.show_branch_change(tree.branch, s, 3, '3b')
1205
self.assertEqual(s.getvalue(),
1206
'Nothing seems to have changed\n')
1208
def test_show_branch_change_no_old(self):
1209
tree = self.setup_ab_tree()
1211
log.show_branch_change(tree.branch, s, 2, '2b')
1212
self.assertContainsRe(s.getvalue(), 'Added Revisions:')
1213
self.assertNotContainsRe(s.getvalue(), 'Removed Revisions:')
1215
def test_show_branch_change_no_new(self):
1216
tree = self.setup_ab_tree()
1217
tree.branch.set_last_revision_info(2, '2b')
1219
log.show_branch_change(tree.branch, s, 3, '3b')
1220
self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1221
self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1224
class TestRevisionNotInBranch(TestCaseForLogFormatter):
1226
def setup_a_tree(self):
1227
tree = self.make_branch_and_tree('tree')
1229
self.addCleanup(tree.unlock)
1231
'committer': 'Joe Foo <joe@foo.com>',
1232
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1233
'timezone': 0, # UTC
1235
tree.commit('commit 1a', rev_id='1a', **kwargs)
1236
tree.commit('commit 2a', rev_id='2a', **kwargs)
1237
tree.commit('commit 3a', rev_id='3a', **kwargs)
1240
def setup_ab_tree(self):
1241
tree = self.setup_a_tree()
1242
tree.set_last_revision('1a')
1243
tree.branch.set_last_revision_info(1, '1a')
1245
'committer': 'Joe Foo <joe@foo.com>',
1246
'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1247
'timezone': 0, # UTC
1249
tree.commit('commit 2b', rev_id='2b', **kwargs)
1250
tree.commit('commit 3b', rev_id='3b', **kwargs)
1253
def test_one_revision(self):
1254
tree = self.setup_ab_tree()
1256
rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1257
log.show_log(tree.branch, lf, verbose=True, start_revision=rev,
1259
self.assertEqual(1, len(lf.revisions))
1260
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1261
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1263
def test_many_revisions(self):
1264
tree = self.setup_ab_tree()
1266
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1267
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1268
log.show_log(tree.branch, lf, verbose=True, start_revision=start_rev,
1269
end_revision=end_rev)
1270
self.assertEqual(3, len(lf.revisions))
1271
self.assertEqual(None, lf.revisions[0].revno) # Out-of-branch
1272
self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1273
self.assertEqual(None, lf.revisions[1].revno) # Out-of-branch
1274
self.assertEqual('2a', lf.revisions[1].rev.revision_id)
1275
self.assertEqual('1', lf.revisions[2].revno) # In-branch
1277
def test_long_format(self):
1278
tree = self.setup_ab_tree()
1279
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1280
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1281
self.assertFormatterResult("""\
1282
------------------------------------------------------------
1284
committer: Joe Foo <joe@foo.com>
1286
timestamp: Tue 2005-11-22 00:00:00 +0000
1289
------------------------------------------------------------
1291
committer: Joe Foo <joe@foo.com>
1293
timestamp: Tue 2005-11-22 00:00:00 +0000
1296
------------------------------------------------------------
1298
committer: Joe Foo <joe@foo.com>
1300
timestamp: Tue 2005-11-22 00:00:00 +0000
1304
tree.branch, log.LongLogFormatter, show_log_kwargs={
1305
'start_revision': start_rev, 'end_revision': end_rev
1308
def test_short_format(self):
1309
tree = self.setup_ab_tree()
1310
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1311
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1312
self.assertFormatterResult("""\
1321
1 Joe Foo\t2005-11-22
1325
tree.branch, log.ShortLogFormatter, show_log_kwargs={
1326
'start_revision': start_rev, 'end_revision': end_rev
1329
def test_line_format(self):
1330
tree = self.setup_ab_tree()
1331
start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1332
end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1333
self.assertFormatterResult("""\
1334
Joe Foo 2005-11-22 commit 3a
1335
Joe Foo 2005-11-22 commit 2a
1336
1: Joe Foo 2005-11-22 commit 1a
1338
tree.branch, log.LineLogFormatter, show_log_kwargs={
1339
'start_revision': start_rev, 'end_revision': end_rev
1343
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1346
super(TestLogWithBugs, self).setUp()
1347
log.properties_handler_registry.register(
1348
'bugs_properties_handler',
1349
log._bugs_properties_handler)
1351
def make_commits_with_bugs(self):
1352
"""Helper method for LogFormatter tests"""
1353
tree = self.make_branch_and_tree(u'.')
1354
self.build_tree(['a', 'b'])
1356
self.wt_commit(tree, 'simple log message', rev_id='a1',
1357
revprops={'bugs': 'test://bug/id fixed'})
1359
self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id='a2',
1360
authors=['Joe Bar <joe@bar.com>'],
1361
revprops={'bugs': 'test://bug/id fixed\n'
1362
'test://bug/2 fixed'})
1366
def test_long_bugs(self):
1367
tree = self.make_commits_with_bugs()
1368
self.assertFormatterResult("""\
1369
------------------------------------------------------------
1371
fixes bugs: test://bug/id test://bug/2
1372
author: Joe Bar <joe@bar.com>
1373
committer: Joe Foo <joe@foo.com>
1375
timestamp: Tue 2005-11-22 00:00:01 +0000
1380
------------------------------------------------------------
1382
fixes bug: test://bug/id
1383
committer: Joe Foo <joe@foo.com>
1385
timestamp: Tue 2005-11-22 00:00:00 +0000
1389
tree.branch, log.LongLogFormatter)
1391
def test_short_bugs(self):
1392
tree = self.make_commits_with_bugs()
1393
self.assertFormatterResult("""\
1394
2 Joe Bar\t2005-11-22
1395
fixes bugs: test://bug/id test://bug/2
1400
1 Joe Foo\t2005-11-22
1401
fixes bug: test://bug/id
1405
tree.branch, log.ShortLogFormatter)
1407
def test_wrong_bugs_property(self):
1408
tree = self.make_branch_and_tree(u'.')
1409
self.build_tree(['foo'])
1410
self.wt_commit(tree, 'simple log message', rev_id='a1',
1411
revprops={'bugs': 'test://bug/id invalid_value'})
1412
self.assertFormatterResult("""\
1413
1 Joe Foo\t2005-11-22
1417
tree.branch, log.ShortLogFormatter)
1419
def test_bugs_handler_present(self):
1420
self.properties_handler_registry.get('bugs_properties_handler')
1423
class TestLogForAuthors(TestCaseForLogFormatter):
1426
super(TestLogForAuthors, self).setUp()
1427
self.wt = self.make_standard_commit('nicky',
1428
authors=['John Doe <jdoe@example.com>',
1429
'Jane Rey <jrey@example.com>'])
1431
def assertFormatterResult(self, formatter, who, result):
1432
formatter_kwargs = dict()
1434
author_list_handler = log.author_list_registry.get(who)
1435
formatter_kwargs['author_list_handler'] = author_list_handler
1436
TestCaseForLogFormatter.assertFormatterResult(self, result,
1437
self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1439
def test_line_default(self):
1440
self.assertFormatterResult(log.LineLogFormatter, None, """\
1441
1: John Doe 2005-11-22 add a
1444
def test_line_committer(self):
1445
self.assertFormatterResult(log.LineLogFormatter, 'committer', """\
1446
1: Lorem Ipsum 2005-11-22 add a
1449
def test_line_first(self):
1450
self.assertFormatterResult(log.LineLogFormatter, 'first', """\
1451
1: John Doe 2005-11-22 add a
1454
def test_line_all(self):
1455
self.assertFormatterResult(log.LineLogFormatter, 'all', """\
1456
1: John Doe, Jane Rey 2005-11-22 add a
1460
def test_short_default(self):
1461
self.assertFormatterResult(log.ShortLogFormatter, None, """\
1462
1 John Doe\t2005-11-22
1467
def test_short_committer(self):
1468
self.assertFormatterResult(log.ShortLogFormatter, 'committer', """\
1469
1 Lorem Ipsum\t2005-11-22
1474
def test_short_first(self):
1475
self.assertFormatterResult(log.ShortLogFormatter, 'first', """\
1476
1 John Doe\t2005-11-22
1481
def test_short_all(self):
1482
self.assertFormatterResult(log.ShortLogFormatter, 'all', """\
1483
1 John Doe, Jane Rey\t2005-11-22
1488
def test_long_default(self):
1489
self.assertFormatterResult(log.LongLogFormatter, None, """\
1490
------------------------------------------------------------
1492
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1493
committer: Lorem Ipsum <test@example.com>
1495
timestamp: Tue 2005-11-22 00:00:00 +0000
1500
def test_long_committer(self):
1501
self.assertFormatterResult(log.LongLogFormatter, 'committer', """\
1502
------------------------------------------------------------
1504
committer: Lorem Ipsum <test@example.com>
1506
timestamp: Tue 2005-11-22 00:00:00 +0000
1511
def test_long_first(self):
1512
self.assertFormatterResult(log.LongLogFormatter, 'first', """\
1513
------------------------------------------------------------
1515
author: John Doe <jdoe@example.com>
1516
committer: Lorem Ipsum <test@example.com>
1518
timestamp: Tue 2005-11-22 00:00:00 +0000
1523
def test_long_all(self):
1524
self.assertFormatterResult(log.LongLogFormatter, 'all', """\
1525
------------------------------------------------------------
1527
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1528
committer: Lorem Ipsum <test@example.com>
1530
timestamp: Tue 2005-11-22 00:00:00 +0000
1535
def test_gnu_changelog_default(self):
1536
self.assertFormatterResult(log.GnuChangelogLogFormatter, None, """\
1537
2005-11-22 John Doe <jdoe@example.com>
1543
def test_gnu_changelog_committer(self):
1544
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', """\
1545
2005-11-22 Lorem Ipsum <test@example.com>
1551
def test_gnu_changelog_first(self):
1552
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', """\
1553
2005-11-22 John Doe <jdoe@example.com>
1559
def test_gnu_changelog_all(self):
1560
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'all', """\
1561
2005-11-22 John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1568
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1570
def make_branch_with_alternate_ancestries(self, relpath='.'):
1571
# See test_merge_sorted_exclude_ancestry below for the difference with
1572
# bt.per_branch.test_iter_merge_sorted_revision.
1573
# TestIterMergeSortedRevisionsBushyGraph.
1574
# make_branch_with_alternate_ancestries
1575
# and test_merge_sorted_exclude_ancestry
1576
# See the FIXME in assertLogRevnos too.
1577
builder = branchbuilder.BranchBuilder(self.get_transport(relpath))
1589
builder.start_series()
1590
builder.build_snapshot('1', None, [
1591
('add', ('', 'TREE_ROOT', 'directory', '')),])
1592
builder.build_snapshot('1.1.1', ['1'], [])
1593
builder.build_snapshot('2', ['1'], [])
1594
builder.build_snapshot('1.2.1', ['1.1.1'], [])
1595
builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1596
builder.build_snapshot('3', ['2', '1.1.2'], [])
1597
builder.finish_series()
1598
br = builder.get_branch()
1600
self.addCleanup(br.unlock)
1603
def assertLogRevnos(self, expected_revnos, b, start, end,
1604
exclude_common_ancestry, generate_merge_revisions=True):
1605
# FIXME: the layering in log makes it hard to test intermediate levels,
1606
# I wish adding filters with their parameters was easier...
1608
iter_revs = log._calc_view_revisions(
1609
b, start, end, direction='reverse',
1610
generate_merge_revisions=generate_merge_revisions,
1611
exclude_common_ancestry=exclude_common_ancestry)
1612
self.assertEqual(expected_revnos,
1613
[revid for revid, revno, depth in iter_revs])
1615
def test_merge_sorted_exclude_ancestry(self):
1616
b = self.make_branch_with_alternate_ancestries()
1617
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1618
b, '1', '3', exclude_common_ancestry=False)
1619
# '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1620
# it should be mentioned even if merge_sort order will make it appear
1622
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1623
b, '1.1.1', '3', exclude_common_ancestry=True)
1625
def test_merge_sorted_simple_revnos_exclude_ancestry(self):
1626
b = self.make_branch_with_alternate_ancestries()
1627
self.assertLogRevnos(['3', '2'],
1628
b, '1', '3', exclude_common_ancestry=True,
1629
generate_merge_revisions=False)
1630
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2'],
1631
b, '1', '3', exclude_common_ancestry=True,
1632
generate_merge_revisions=True)
1635
class TestLogDefaults(TestCaseForLogFormatter):
1636
def test_default_log_level(self):
1638
Test to ensure that specifying 'levels=1' to make_log_request_dict
1639
doesn't get overwritten when using a LogFormatter that supports more
1643
wt = self._prepare_tree_with_merges()
274
self.build_tree(['a'])
276
b.nick = 'test-line-log'
277
wt.commit(message='add a',
278
timestamp=1132711707,
280
committer='Line-Log-Formatter Tester <test@line.log>')
281
logfile = file('out.tmp', 'w+')
282
formatter = LineLogFormatter(to_file=logfile)
283
show_log(b, formatter)
286
log_contents = logfile.read()
287
self.assertEqualDiff(log_contents, '1: Line-Log-Formatte... 2005-11-23 add a\n')
289
def make_tree_with_commits(self):
290
"""Create a tree with well-known revision ids"""
291
wt = self.make_branch_and_tree('tree1')
292
wt.commit('commit one', rev_id='1')
293
wt.commit('commit two', rev_id='2')
294
wt.commit('commit three', rev_id='3')
295
mainline_revs = [None, '1', '2', '3']
296
rev_nos = {'1': 1, '2': 2, '3': 3}
297
return mainline_revs, rev_nos, wt
299
def make_tree_with_merges(self):
300
"""Create a tree with well-known revision ids and a merge"""
301
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
302
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
303
tree2.commit('four-a', rev_id='4a')
304
wt.merge_from_branch(tree2.branch)
305
wt.commit('four-b', rev_id='4b')
306
mainline_revs.append('4b')
309
return mainline_revs, rev_nos, wt
311
def make_tree_with_many_merges(self):
312
"""Create a tree with well-known revision ids"""
313
wt = self.make_branch_and_tree('tree1')
314
wt.commit('commit one', rev_id='1')
315
wt.commit('commit two', rev_id='2')
316
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
317
tree3.commit('commit three a', rev_id='3a')
318
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
319
tree2.merge_from_branch(tree3.branch)
320
tree2.commit('commit three b', rev_id='3b')
321
wt.merge_from_branch(tree2.branch)
322
wt.commit('commit three c', rev_id='3c')
323
tree2.commit('four-a', rev_id='4a')
324
wt.merge_from_branch(tree2.branch)
325
wt.commit('four-b', rev_id='4b')
326
mainline_revs = [None, '1', '2', '3c', '4b']
327
rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
328
full_rev_nos_for_reference = {
331
'3a': '2.2.1', #first commit tree 3
332
'3b': '2.1.1', # first commit tree 2
333
'3c': '3', #merges 3b to main
334
'4a': '2.1.2', # second commit tree 2
335
'4b': '4', # merges 4a to main
337
return mainline_revs, rev_nos, wt
339
def test_get_view_revisions_forward(self):
340
"""Test the get_view_revisions method"""
341
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
342
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
344
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
346
revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
347
'forward', include_merges=False))
348
self.assertEqual(revisions, revisions2)
350
def test_get_view_revisions_reverse(self):
351
"""Test the get_view_revisions with reverse"""
352
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
353
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
355
self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
357
revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
358
'reverse', include_merges=False))
359
self.assertEqual(revisions, revisions2)
361
def test_get_view_revisions_merge(self):
362
"""Test get_view_revisions when there are merges"""
363
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
364
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
366
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
367
('4b', '4', 0), ('4a', '3.1.1', 1)],
369
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
370
'forward', include_merges=False))
371
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
375
def test_get_view_revisions_merge_reverse(self):
376
"""Test get_view_revisions in reverse when there are merges"""
377
mainline_revs, rev_nos, wt = self.make_tree_with_merges()
378
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
380
self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
381
('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
383
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
384
'reverse', include_merges=False))
385
self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
389
def test_get_view_revisions_merge2(self):
390
"""Test get_view_revisions when there are merges"""
391
mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
392
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
394
expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
395
('3a', '2.2.1', 1), ('3b', '2.1.1', 1), ('4b', '4', 0),
397
self.assertEqual(expected, revisions)
398
revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
399
'forward', include_merges=False))
400
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1646
class CustomLogFormatter(log.LogFormatter):
1647
def __init__(self, *args, **kwargs):
1648
super(CustomLogFormatter, self).__init__(*args, **kwargs)
1650
def get_levels(self):
1651
# log formatter supports all levels:
1653
def log_revision(self, revision):
1654
self.revisions.append(revision)
1656
log_formatter = LogCatcher()
1657
# First request we don't specify number of levels, we should get a
1658
# sensible default (whatever the LogFormatter handles - which in this
1659
# case is 0/everything):
1660
request = log.make_log_request_dict(limit=10)
1661
log.Logger(b, request).show(log_formatter)
1662
# should have all three revisions:
1663
self.assertEquals(len(log_formatter.revisions), 3)
1666
log_formatter = LogCatcher()
1667
# now explicitly request mainline revisions only:
1668
request = log.make_log_request_dict(limit=10, levels=1)
1669
log.Logger(b, request).show(log_formatter)
1670
# should now only have 2 revisions:
1671
self.assertEquals(len(log_formatter.revisions), 2)