18
18
from cStringIO import StringIO
20
20
from bzrlib import (
32
class TestLogMixin(object):
34
def wt_commit(self, wt, message, **kwargs):
35
"""Use some mostly fixed values for commits to simplify tests.
37
Tests can use this function to get some commit attributes. The time
38
stamp is incremented at each commit.
40
if getattr(self, 'timestamp', None) is None:
41
self.timestamp = 1132617600 # Mon 2005-11-22 00:00:00 +0000
43
self.timestamp += 1 # 1 second between each commit
44
kwargs.setdefault('timestamp', self.timestamp)
45
kwargs.setdefault('timezone', 0) # UTC
46
kwargs.setdefault('committer', 'Joe Foo <joe@foo.com>')
48
return wt.commit(message, **kwargs)
51
class TestCaseForLogFormatter(tests.TestCaseWithTransport, TestLogMixin):
30
class TestCaseWithoutPropsHandler(tests.TestCaseWithTransport):
54
super(TestCaseForLogFormatter, self).setUp()
33
super(TestCaseWithoutPropsHandler, self).setUp()
55
34
# keep a reference to the "current" custom prop. handler registry
56
35
self.properties_handler_registry = log.properties_handler_registry
57
# Use a clean registry for log
36
# clean up the registry in log
58
37
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')
40
super(TestCaseWithoutPropsHandler, self)._cleanup()
41
# restore the custom properties handler registry
42
log.properties_handler_registry = self.properties_handler_registry
120
45
class LogCatcher(log.LogFormatter):
121
"""Pull log messages into a list rather than displaying them.
46
"""Pull log messages into list rather than displaying them.
123
To simplify testing we save logged revisions here rather than actually
48
For ease of testing we save logged revisions here rather than actually
124
49
formatting anything, so that we can precisely check the result without
125
being dependent on the formatting.
50
being dependent on the exact formatting.
128
supports_merge_revisions = True
129
53
supports_delta = True
54
# supports_merge_revisions = True
133
def __init__(self, *args, **kwargs):
134
kwargs.update(dict(to_file=None))
135
super(LogCatcher, self).__init__(*args, **kwargs)
57
super(LogCatcher, self).__init__(to_file=None)
138
60
def log_revision(self, revision):
139
self.revisions.append(revision)
61
self.logs.append(revision)
142
64
class TestShowLog(tests.TestCaseWithTransport):
262
180
lf.supports_merge_revisions = True
263
181
log.show_log(b, lf, verbose=True)
266
self.assertEqual(3, len(revs))
183
self.assertEqual(3, len(lf.logs))
185
logentry = lf.logs[0]
269
186
self.assertEqual('2', logentry.revno)
270
187
self.assertEqual('merge child branch', logentry.rev.message)
271
188
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
190
logentry = lf.logs[1]
274
191
self.assertEqual('1.1.1', logentry.revno)
275
192
self.assertEqual('remove file1 and modify file2', logentry.rev.message)
276
193
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
195
logentry = lf.logs[2]
279
196
self.assertEqual('1', logentry.revno)
280
197
self.assertEqual('add file1 and file2', logentry.rev.message)
281
198
self.checkDelta(logentry.delta, added=['file1', 'file2'])
284
class TestShortLogFormatter(TestCaseForLogFormatter):
201
def make_commits_with_trailing_newlines(wt):
202
"""Helper method for LogFormatter tests"""
205
open('a', 'wb').write('hello moto\n')
207
wt.commit('simple log message', rev_id='a1',
208
timestamp=1132586655.459960938, timezone=-6*3600,
209
committer='Joe Foo <joe@foo.com>')
210
open('b', 'wb').write('goodbye\n')
212
wt.commit('multiline\nlog\nmessage\n', rev_id='a2',
213
timestamp=1132586842.411175966, timezone=-6*3600,
214
committer='Joe Foo <joe@foo.com>',
215
authors=['Joe Bar <joe@bar.com>'])
217
open('c', 'wb').write('just another manic monday\n')
219
wt.commit('single line with trailing newline\n', rev_id='a3',
220
timestamp=1132587176.835228920, timezone=-6*3600,
221
committer = 'Joe Foo <joe@foo.com>')
225
def normalize_log(log):
226
"""Replaces the variable lines of logs with fixed lines"""
227
author = 'author: Dolor Sit <test@example.com>'
228
committer = 'committer: Lorem Ipsum <test@example.com>'
229
lines = log.splitlines(True)
230
for idx,line in enumerate(lines):
231
stripped_line = line.lstrip()
232
indent = ' ' * (len(line) - len(stripped_line))
233
if stripped_line.startswith('author:'):
234
lines[idx] = indent + author + '\n'
235
elif stripped_line.startswith('committer:'):
236
lines[idx] = indent + committer + '\n'
237
elif stripped_line.startswith('timestamp:'):
238
lines[idx] = indent + 'timestamp: Just now\n'
239
return ''.join(lines)
242
class TestShortLogFormatter(tests.TestCaseWithTransport):
286
244
def test_trailing_newlines(self):
287
245
wt = self.make_branch_and_tree('.')
288
b = self.make_commits_with_trailing_newlines(wt)
289
self.assertFormatterResult("""\
290
3 Joe Foo\t2005-11-22
246
b = make_commits_with_trailing_newlines(wt)
247
sio = self.make_utf8_encoded_stringio()
248
lf = log.ShortLogFormatter(to_file=sio)
250
self.assertEqualDiff("""\
251
3 Joe Foo\t2005-11-21
291
252
single line with trailing newline
293
2 Joe Foo\t2005-11-22
254
2 Joe Bar\t2005-11-21
298
1 Joe Foo\t2005-11-22
259
1 Joe Foo\t2005-11-21
299
260
simple log message
302
b, log.ShortLogFormatter)
265
def _prepare_tree_with_merges(self, with_tags=False):
266
wt = self.make_branch_and_memory_tree('.')
268
self.addCleanup(wt.unlock)
270
wt.commit('rev-1', rev_id='rev-1',
271
timestamp=1132586655, timezone=36000,
272
committer='Joe Foo <joe@foo.com>')
273
wt.commit('rev-merged', rev_id='rev-2a',
274
timestamp=1132586700, timezone=36000,
275
committer='Joe Foo <joe@foo.com>')
276
wt.set_parent_ids(['rev-1', 'rev-2a'])
277
wt.branch.set_last_revision_info(1, 'rev-1')
278
wt.commit('rev-2', rev_id='rev-2b',
279
timestamp=1132586800, timezone=36000,
280
committer='Joe Foo <joe@foo.com>')
283
branch.tags.set_tag('v0.2', 'rev-2b')
284
wt.commit('rev-3', rev_id='rev-3',
285
timestamp=1132586900, timezone=36000,
286
committer='Jane Foo <jane@foo.com>')
287
branch.tags.set_tag('v1.0rc1', 'rev-3')
288
branch.tags.set_tag('v1.0', 'rev-3')
304
291
def test_short_log_with_merges(self):
305
292
wt = self._prepare_tree_with_merges()
306
self.assertFormatterResult("""\
293
logfile = self.make_utf8_encoded_stringio()
294
formatter = log.ShortLogFormatter(to_file=logfile)
295
log.show_log(wt.branch, formatter)
296
self.assertEqualDiff("""\
307
297
2 Joe Foo\t2005-11-22 [merge]
325
319
Use --include-merges or -n0 to see merged revisions.
327
wt.branch, log.ShortLogFormatter,
328
formatter_kwargs=dict(show_advice=True))
330
323
def test_short_log_with_merges_and_range(self):
331
wt = self._prepare_tree_with_merges()
332
self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
324
wt = self.make_branch_and_memory_tree('.')
326
self.addCleanup(wt.unlock)
328
wt.commit('rev-1', rev_id='rev-1',
329
timestamp=1132586655, timezone=36000,
330
committer='Joe Foo <joe@foo.com>')
331
wt.commit('rev-merged', rev_id='rev-2a',
332
timestamp=1132586700, timezone=36000,
333
committer='Joe Foo <joe@foo.com>')
334
wt.branch.set_last_revision_info(1, 'rev-1')
335
wt.set_parent_ids(['rev-1', 'rev-2a'])
336
wt.commit('rev-2b', rev_id='rev-2b',
337
timestamp=1132586800, timezone=36000,
338
committer='Joe Foo <joe@foo.com>')
339
wt.commit('rev-3a', rev_id='rev-3a',
340
timestamp=1132586800, timezone=36000,
341
committer='Joe Foo <joe@foo.com>')
333
342
wt.branch.set_last_revision_info(2, 'rev-2b')
334
343
wt.set_parent_ids(['rev-2b', 'rev-3a'])
335
self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
336
self.assertFormatterResult("""\
344
wt.commit('rev-3b', rev_id='rev-3b',
345
timestamp=1132586800, timezone=36000,
346
committer='Joe Foo <joe@foo.com>')
347
logfile = self.make_utf8_encoded_stringio()
348
formatter = log.ShortLogFormatter(to_file=logfile)
349
log.show_log(wt.branch, formatter,
350
start_revision=2, end_revision=3)
351
self.assertEqualDiff("""\
337
352
3 Joe Foo\t2005-11-22 [merge]
340
355
2 Joe Foo\t2005-11-22 [merge]
344
wt.branch, log.ShortLogFormatter,
345
show_log_kwargs=dict(start_revision=2, end_revision=3))
347
361
def test_short_log_with_tags(self):
348
362
wt = self._prepare_tree_with_merges(with_tags=True)
349
self.assertFormatterResult("""\
350
3 Joe Foo\t2005-11-22 {v1.0, v1.0rc1}
363
logfile = self.make_utf8_encoded_stringio()
364
formatter = log.ShortLogFormatter(to_file=logfile)
365
log.show_log(wt.branch, formatter)
366
self.assertEqualDiff("""\
367
3 Jane Foo\t2005-11-22 {v1.0, v1.0rc1}
353
370
2 Joe Foo\t2005-11-22 {v0.2} [merge]
360
wt.branch, log.ShortLogFormatter)
362
379
def test_short_log_single_merge_revision(self):
363
wt = self._prepare_tree_with_merges()
380
wt = self.make_branch_and_memory_tree('.')
382
self.addCleanup(wt.unlock)
384
wt.commit('rev-1', rev_id='rev-1',
385
timestamp=1132586655, timezone=36000,
386
committer='Joe Foo <joe@foo.com>')
387
wt.commit('rev-merged', rev_id='rev-2a',
388
timestamp=1132586700, timezone=36000,
389
committer='Joe Foo <joe@foo.com>')
390
wt.set_parent_ids(['rev-1', 'rev-2a'])
391
wt.branch.set_last_revision_info(1, 'rev-1')
392
wt.commit('rev-2', rev_id='rev-2b',
393
timestamp=1132586800, timezone=36000,
394
committer='Joe Foo <joe@foo.com>')
395
logfile = self.make_utf8_encoded_stringio()
396
formatter = log.ShortLogFormatter(to_file=logfile)
364
397
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
365
rev = revspec.in_history(wt.branch)
366
self.assertFormatterResult("""\
399
rev = revspec.in_history(wtb)
400
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
401
self.assertEqualDiff("""\
367
402
1.1.1 Joe Foo\t2005-11-22
371
wt.branch, log.ShortLogFormatter,
372
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
375
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
409
class TestShortLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
377
411
def test_short_merge_revs_log_with_merges(self):
378
wt = self._prepare_tree_with_merges()
412
wt = self.make_branch_and_memory_tree('.')
414
self.addCleanup(wt.unlock)
416
wt.commit('rev-1', rev_id='rev-1',
417
timestamp=1132586655, timezone=36000,
418
committer='Joe Foo <joe@foo.com>')
419
wt.commit('rev-merged', rev_id='rev-2a',
420
timestamp=1132586700, timezone=36000,
421
committer='Joe Foo <joe@foo.com>')
422
wt.set_parent_ids(['rev-1', 'rev-2a'])
423
wt.branch.set_last_revision_info(1, 'rev-1')
424
wt.commit('rev-2', rev_id='rev-2b',
425
timestamp=1132586800, timezone=36000,
426
committer='Joe Foo <joe@foo.com>')
427
logfile = self.make_utf8_encoded_stringio()
428
formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
429
log.show_log(wt.branch, formatter)
379
430
# Note that the 1.1.1 indenting is in fact correct given that
380
431
# the revision numbers are right justified within 5 characters
381
432
# for mainline revnos and 9 characters for dotted revnos.
382
self.assertFormatterResult("""\
433
self.assertEqualDiff("""\
383
434
2 Joe Foo\t2005-11-22 [merge]
393
wt.branch, log.ShortLogFormatter,
394
formatter_kwargs=dict(levels=0))
396
446
def test_short_merge_revs_log_single_merge_revision(self):
397
wt = self._prepare_tree_with_merges()
447
wt = self.make_branch_and_memory_tree('.')
449
self.addCleanup(wt.unlock)
451
wt.commit('rev-1', rev_id='rev-1',
452
timestamp=1132586655, timezone=36000,
453
committer='Joe Foo <joe@foo.com>')
454
wt.commit('rev-merged', rev_id='rev-2a',
455
timestamp=1132586700, timezone=36000,
456
committer='Joe Foo <joe@foo.com>')
457
wt.set_parent_ids(['rev-1', 'rev-2a'])
458
wt.branch.set_last_revision_info(1, 'rev-1')
459
wt.commit('rev-2', rev_id='rev-2b',
460
timestamp=1132586800, timezone=36000,
461
committer='Joe Foo <joe@foo.com>')
462
logfile = self.make_utf8_encoded_stringio()
463
formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
398
464
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
399
rev = revspec.in_history(wt.branch)
400
self.assertFormatterResult("""\
466
rev = revspec.in_history(wtb)
467
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
468
self.assertEqualDiff("""\
401
469
1.1.1 Joe Foo\t2005-11-22
405
wt.branch, log.ShortLogFormatter,
406
formatter_kwargs=dict(levels=0),
407
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
410
class TestLongLogFormatter(TestCaseForLogFormatter):
476
class TestLongLogFormatter(TestCaseWithoutPropsHandler):
412
478
def test_verbose_log(self):
413
479
"""Verbose log includes changed files
417
wt = self.make_standard_commit('test_verbose_log', authors=[])
418
self.assertFormatterResult('''\
483
wt = self.make_branch_and_tree('.')
485
self.build_tree(['a'])
487
# XXX: why does a longer nick show up?
488
b.nick = 'test_verbose_log'
489
wt.commit(message='add a',
490
timestamp=1132711707,
492
committer='Lorem Ipsum <test@example.com>')
493
logfile = file('out.tmp', 'w+')
494
formatter = log.LongLogFormatter(to_file=logfile)
495
log.show_log(b, formatter, verbose=True)
498
log_contents = logfile.read()
499
self.assertEqualDiff('''\
419
500
------------------------------------------------------------
421
502
committer: Lorem Ipsum <test@example.com>
422
503
branch nick: test_verbose_log
423
timestamp: Tue 2005-11-22 00:00:00 +0000
504
timestamp: Wed 2005-11-23 12:08:27 +1000
429
wt.branch, log.LongLogFormatter,
430
show_log_kwargs=dict(verbose=True))
432
512
def test_merges_are_indented_by_level(self):
433
513
wt = self.make_branch_and_tree('parent')
434
self.wt_commit(wt, 'first post')
435
child_wt = wt.bzrdir.sprout('child').open_workingtree()
436
self.wt_commit(child_wt, 'branch 1')
437
smallerchild_wt = wt.bzrdir.sprout('smallerchild').open_workingtree()
438
self.wt_commit(smallerchild_wt, 'branch 2')
439
child_wt.merge_from_branch(smallerchild_wt.branch)
440
self.wt_commit(child_wt, 'merge branch 2')
441
wt.merge_from_branch(child_wt.branch)
442
self.wt_commit(wt, 'merge branch 1')
443
self.assertFormatterResult("""\
514
wt.commit('first post')
515
self.run_bzr('branch parent child')
516
self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
517
self.run_bzr('branch child smallerchild')
518
self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
521
self.run_bzr('merge ../smallerchild')
522
self.run_bzr(['commit', '-m', 'merge branch 2'])
523
os.chdir('../parent')
524
self.run_bzr('merge ../child')
525
wt.commit('merge branch 1')
527
sio = self.make_utf8_encoded_stringio()
528
lf = log.LongLogFormatter(to_file=sio, levels=0)
529
log.show_log(b, lf, verbose=True)
530
the_log = normalize_log(sio.getvalue())
531
self.assertEqualDiff("""\
444
532
------------------------------------------------------------
446
committer: Joe Foo <joe@foo.com>
534
committer: Lorem Ipsum <test@example.com>
447
535
branch nick: parent
448
timestamp: Tue 2005-11-22 00:00:04 +0000
451
539
------------------------------------------------------------
452
540
revno: 1.1.2 [merge]
453
committer: Joe Foo <joe@foo.com>
541
committer: Lorem Ipsum <test@example.com>
454
542
branch nick: child
455
timestamp: Tue 2005-11-22 00:00:03 +0000
458
546
------------------------------------------------------------
460
committer: Joe Foo <joe@foo.com>
548
committer: Lorem Ipsum <test@example.com>
461
549
branch nick: smallerchild
462
timestamp: Tue 2005-11-22 00:00:02 +0000
465
553
------------------------------------------------------------
467
committer: Joe Foo <joe@foo.com>
555
committer: Lorem Ipsum <test@example.com>
468
556
branch nick: child
469
timestamp: Tue 2005-11-22 00:00:01 +0000
472
560
------------------------------------------------------------
474
committer: Joe Foo <joe@foo.com>
562
committer: Lorem Ipsum <test@example.com>
475
563
branch nick: parent
476
timestamp: Tue 2005-11-22 00:00:00 +0000
480
wt.branch, log.LongLogFormatter,
481
formatter_kwargs=dict(levels=0),
482
show_log_kwargs=dict(verbose=True))
484
570
def test_verbose_merge_revisions_contain_deltas(self):
485
571
wt = self.make_branch_and_tree('parent')
486
572
self.build_tree(['parent/f1', 'parent/f2'])
487
573
wt.add(['f1','f2'])
488
self.wt_commit(wt, 'first post')
489
child_wt = wt.bzrdir.sprout('child').open_workingtree()
574
wt.commit('first post')
575
self.run_bzr('branch parent child')
490
576
os.unlink('child/f1')
491
self.build_tree_contents([('child/f2', 'hello\n')])
492
self.wt_commit(child_wt, 'removed f1 and modified f2')
493
wt.merge_from_branch(child_wt.branch)
494
self.wt_commit(wt, 'merge branch 1')
495
self.assertFormatterResult("""\
577
file('child/f2', 'wb').write('hello\n')
578
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
581
self.run_bzr('merge ../child')
582
wt.commit('merge branch 1')
584
sio = self.make_utf8_encoded_stringio()
585
lf = log.LongLogFormatter(to_file=sio, levels=0)
586
log.show_log(b, lf, verbose=True)
587
the_log = normalize_log(sio.getvalue())
588
self.assertEqualDiff("""\
496
589
------------------------------------------------------------
498
committer: Joe Foo <joe@foo.com>
591
committer: Lorem Ipsum <test@example.com>
499
592
branch nick: parent
500
timestamp: Tue 2005-11-22 00:00:02 +0000
555
650
committer: Joe Foo <joe@foo.com>
556
651
branch nick: test
557
timestamp: Tue 2005-11-22 00:00:00 +0000
652
timestamp: Mon 2005-11-21 09:24:15 -0600
559
654
simple log message
561
b, log.LongLogFormatter)
563
658
def test_author_in_log(self):
564
659
"""Log includes the author name if it's set in
565
660
the revision properties
567
wt = self.make_standard_commit('test_author_log',
568
authors=['John Doe <jdoe@example.com>',
569
'Jane Rey <jrey@example.com>'])
570
self.assertFormatterResult("""\
662
wt = self.make_branch_and_tree('.')
664
self.build_tree(['a'])
666
b.nick = 'test_author_log'
667
wt.commit(message='add a',
668
timestamp=1132711707,
670
committer='Lorem Ipsum <test@example.com>',
671
authors=['John Doe <jdoe@example.com>',
672
'Jane Rey <jrey@example.com>'])
674
formatter = log.LongLogFormatter(to_file=sio)
675
log.show_log(b, formatter)
676
self.assertEqualDiff('''\
571
677
------------------------------------------------------------
573
679
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
574
680
committer: Lorem Ipsum <test@example.com>
575
681
branch nick: test_author_log
576
timestamp: Tue 2005-11-22 00:00:00 +0000
682
timestamp: Wed 2005-11-23 12:08:27 +1000
580
wt.branch, log.LongLogFormatter)
582
688
def test_properties_in_log(self):
583
689
"""Log includes the custom properties returned by the registered
586
wt = self.make_standard_commit('test_properties_in_log')
587
def trivial_custom_prop_handler(revision):
588
return {'test_prop':'test_value'}
692
wt = self.make_branch_and_tree('.')
694
self.build_tree(['a'])
696
b.nick = 'test_properties_in_log'
697
wt.commit(message='add a',
698
timestamp=1132711707,
700
committer='Lorem Ipsum <test@example.com>',
701
authors=['John Doe <jdoe@example.com>'])
703
formatter = log.LongLogFormatter(to_file=sio)
705
def trivial_custom_prop_handler(revision):
706
return {'test_prop':'test_value'}
590
# Cleaned up in setUp()
591
log.properties_handler_registry.register(
592
'trivial_custom_prop_handler',
593
trivial_custom_prop_handler)
594
self.assertFormatterResult("""\
708
log.properties_handler_registry.register(
709
'trivial_custom_prop_handler',
710
trivial_custom_prop_handler)
711
log.show_log(b, formatter)
713
log.properties_handler_registry.remove(
714
'trivial_custom_prop_handler')
715
self.assertEqualDiff('''\
595
716
------------------------------------------------------------
597
718
test_prop: test_value
598
719
author: John Doe <jdoe@example.com>
599
720
committer: Lorem Ipsum <test@example.com>
600
721
branch nick: test_properties_in_log
601
timestamp: Tue 2005-11-22 00:00:00 +0000
722
timestamp: Wed 2005-11-23 12:08:27 +1000
605
wt.branch, log.LongLogFormatter)
607
728
def test_properties_in_short_log(self):
608
729
"""Log includes the custom properties returned by the registered
611
wt = self.make_standard_commit('test_properties_in_short_log')
612
def trivial_custom_prop_handler(revision):
613
return {'test_prop':'test_value'}
732
wt = self.make_branch_and_tree('.')
734
self.build_tree(['a'])
736
b.nick = 'test_properties_in_short_log'
737
wt.commit(message='add a',
738
timestamp=1132711707,
740
committer='Lorem Ipsum <test@example.com>',
741
authors=['John Doe <jdoe@example.com>'])
743
formatter = log.ShortLogFormatter(to_file=sio)
745
def trivial_custom_prop_handler(revision):
746
return {'test_prop':'test_value'}
615
log.properties_handler_registry.register(
616
'trivial_custom_prop_handler',
617
trivial_custom_prop_handler)
618
self.assertFormatterResult("""\
619
1 John Doe\t2005-11-22
748
log.properties_handler_registry.register(
749
'trivial_custom_prop_handler',
750
trivial_custom_prop_handler)
751
log.show_log(b, formatter)
753
log.properties_handler_registry.remove(
754
'trivial_custom_prop_handler')
755
self.assertEqualDiff('''\
756
1 John Doe\t2005-11-23
620
757
test_prop: test_value
624
wt.branch, log.ShortLogFormatter)
626
763
def test_error_in_properties_handler(self):
627
764
"""Log includes the custom properties returned by the registered
630
wt = self.make_standard_commit('error_in_properties_handler',
631
revprops={'first_prop':'first_value'})
632
sio = self.make_utf8_encoded_stringio()
767
wt = self.make_branch_and_tree('.')
769
self.build_tree(['a'])
771
b.nick = 'test_author_log'
772
wt.commit(message='add a',
773
timestamp=1132711707,
775
committer='Lorem Ipsum <test@example.com>',
776
authors=['John Doe <jdoe@example.com>'],
777
revprops={'first_prop':'first_value'})
633
779
formatter = log.LongLogFormatter(to_file=sio)
634
def trivial_custom_prop_handler(revision):
635
raise StandardError("a test error")
781
def trivial_custom_prop_handler(revision):
782
raise StandardError("a test error")
637
log.properties_handler_registry.register(
638
'trivial_custom_prop_handler',
639
trivial_custom_prop_handler)
640
self.assertRaises(StandardError, log.show_log, wt.branch, formatter,)
784
log.properties_handler_registry.register(
785
'trivial_custom_prop_handler',
786
trivial_custom_prop_handler)
787
self.assertRaises(StandardError, log.show_log, b, formatter,)
789
log.properties_handler_registry.remove(
790
'trivial_custom_prop_handler')
642
792
def test_properties_handler_bad_argument(self):
643
wt = self.make_standard_commit('bad_argument',
644
revprops={'a_prop':'test_value'})
645
sio = self.make_utf8_encoded_stringio()
793
wt = self.make_branch_and_tree('.')
795
self.build_tree(['a'])
797
b.nick = 'test_author_log'
798
wt.commit(message='add a',
799
timestamp=1132711707,
801
committer='Lorem Ipsum <test@example.com>',
802
authors=['John Doe <jdoe@example.com>'],
803
revprops={'a_prop':'test_value'})
646
805
formatter = log.LongLogFormatter(to_file=sio)
647
def bad_argument_prop_handler(revision):
648
return {'custom_prop_name':revision.properties['a_prop']}
650
log.properties_handler_registry.register(
651
'bad_argument_prop_handler',
652
bad_argument_prop_handler)
654
self.assertRaises(AttributeError, formatter.show_properties,
657
revision = wt.branch.repository.get_revision(wt.branch.last_revision())
658
formatter.show_properties(revision, '')
659
self.assertEqualDiff('''custom_prop_name: test_value\n''',
663
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
807
def bad_argument_prop_handler(revision):
808
return {'custom_prop_name':revision.properties['a_prop']}
810
log.properties_handler_registry.register(
811
'bad_argument_prop_handler',
812
bad_argument_prop_handler)
814
self.assertRaises(AttributeError, formatter.show_properties,
817
revision = b.repository.get_revision(b.last_revision())
818
formatter.show_properties(revision, '')
819
self.assertEqualDiff('''custom_prop_name: test_value\n''',
822
log.properties_handler_registry.remove(
823
'bad_argument_prop_handler')
826
class TestLongLogFormatterWithoutMergeRevisions(TestCaseWithoutPropsHandler):
665
828
def test_long_verbose_log(self):
666
829
"""Verbose log includes changed files
670
wt = self.make_standard_commit('test_long_verbose_log', authors=[])
671
self.assertFormatterResult("""\
833
wt = self.make_branch_and_tree('.')
835
self.build_tree(['a'])
837
# XXX: why does a longer nick show up?
838
b.nick = 'test_verbose_log'
839
wt.commit(message='add a',
840
timestamp=1132711707,
842
committer='Lorem Ipsum <test@example.com>')
843
logfile = file('out.tmp', 'w+')
844
formatter = log.LongLogFormatter(to_file=logfile, levels=1)
845
log.show_log(b, formatter, verbose=True)
848
log_contents = logfile.read()
849
self.assertEqualDiff('''\
672
850
------------------------------------------------------------
674
852
committer: Lorem Ipsum <test@example.com>
675
branch nick: test_long_verbose_log
676
timestamp: Tue 2005-11-22 00:00:00 +0000
853
branch nick: test_verbose_log
854
timestamp: Wed 2005-11-23 12:08:27 +1000
682
wt.branch, log.LongLogFormatter,
683
formatter_kwargs=dict(levels=1),
684
show_log_kwargs=dict(verbose=True))
686
862
def test_long_verbose_contain_deltas(self):
687
863
wt = self.make_branch_and_tree('parent')
688
864
self.build_tree(['parent/f1', 'parent/f2'])
689
865
wt.add(['f1','f2'])
690
self.wt_commit(wt, 'first post')
691
child_wt = wt.bzrdir.sprout('child').open_workingtree()
866
wt.commit('first post')
867
self.run_bzr('branch parent child')
692
868
os.unlink('child/f1')
693
self.build_tree_contents([('child/f2', 'hello\n')])
694
self.wt_commit(child_wt, 'removed f1 and modified f2')
695
wt.merge_from_branch(child_wt.branch)
696
self.wt_commit(wt, 'merge branch 1')
697
self.assertFormatterResult("""\
869
file('child/f2', 'wb').write('hello\n')
870
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
873
self.run_bzr('merge ../child')
874
wt.commit('merge branch 1')
876
sio = self.make_utf8_encoded_stringio()
877
lf = log.LongLogFormatter(to_file=sio, levels=1)
878
log.show_log(b, lf, verbose=True)
879
the_log = normalize_log(sio.getvalue())
880
self.assertEqualDiff("""\
698
881
------------------------------------------------------------
700
committer: Joe Foo <joe@foo.com>
883
committer: Lorem Ipsum <test@example.com>
701
884
branch nick: parent
702
timestamp: Tue 2005-11-22 00:00:02 +0000
746
931
committer: Joe Foo <joe@foo.com>
747
932
branch nick: test
748
timestamp: Tue 2005-11-22 00:00:00 +0000
933
timestamp: Mon 2005-11-21 09:24:15 -0600
750
935
simple log message
752
b, log.LongLogFormatter,
753
formatter_kwargs=dict(levels=1))
755
939
def test_long_author_in_log(self):
756
940
"""Log includes the author name if it's set in
757
941
the revision properties
759
wt = self.make_standard_commit('test_author_log')
760
self.assertFormatterResult("""\
943
wt = self.make_branch_and_tree('.')
945
self.build_tree(['a'])
947
b.nick = 'test_author_log'
948
wt.commit(message='add a',
949
timestamp=1132711707,
951
committer='Lorem Ipsum <test@example.com>',
952
authors=['John Doe <jdoe@example.com>'])
954
formatter = log.LongLogFormatter(to_file=sio, levels=1)
955
log.show_log(b, formatter)
956
self.assertEqualDiff('''\
761
957
------------------------------------------------------------
763
959
author: John Doe <jdoe@example.com>
764
960
committer: Lorem Ipsum <test@example.com>
765
961
branch nick: test_author_log
766
timestamp: Tue 2005-11-22 00:00:00 +0000
962
timestamp: Wed 2005-11-23 12:08:27 +1000
770
wt.branch, log.LongLogFormatter,
771
formatter_kwargs=dict(levels=1))
773
968
def test_long_properties_in_log(self):
774
969
"""Log includes the custom properties returned by the registered
777
wt = self.make_standard_commit('test_properties_in_log')
778
def trivial_custom_prop_handler(revision):
779
return {'test_prop':'test_value'}
972
wt = self.make_branch_and_tree('.')
974
self.build_tree(['a'])
976
b.nick = 'test_properties_in_log'
977
wt.commit(message='add a',
978
timestamp=1132711707,
980
committer='Lorem Ipsum <test@example.com>',
981
authors=['John Doe <jdoe@example.com>'])
983
formatter = log.LongLogFormatter(to_file=sio, levels=1)
985
def trivial_custom_prop_handler(revision):
986
return {'test_prop':'test_value'}
781
log.properties_handler_registry.register(
782
'trivial_custom_prop_handler',
783
trivial_custom_prop_handler)
784
self.assertFormatterResult("""\
988
log.properties_handler_registry.register(
989
'trivial_custom_prop_handler',
990
trivial_custom_prop_handler)
991
log.show_log(b, formatter)
993
log.properties_handler_registry.remove(
994
'trivial_custom_prop_handler')
995
self.assertEqualDiff('''\
785
996
------------------------------------------------------------
787
998
test_prop: test_value
788
999
author: John Doe <jdoe@example.com>
789
1000
committer: Lorem Ipsum <test@example.com>
790
1001
branch nick: test_properties_in_log
791
timestamp: Tue 2005-11-22 00:00:00 +0000
1002
timestamp: Wed 2005-11-23 12:08:27 +1000
795
wt.branch, log.LongLogFormatter,
796
formatter_kwargs=dict(levels=1))
799
class TestLineLogFormatter(TestCaseForLogFormatter):
1009
class TestLineLogFormatter(tests.TestCaseWithTransport):
801
1011
def test_line_log(self):
802
1012
"""Line log should show revno
806
wt = self.make_standard_commit('test-line-log',
807
committer='Line-Log-Formatter Tester <test@line.log>',
809
self.assertFormatterResult("""\
810
1: Line-Log-Formatte... 2005-11-22 add a
812
wt.branch, log.LineLogFormatter)
1016
wt = self.make_branch_and_tree('.')
1018
self.build_tree(['a'])
1020
b.nick = 'test-line-log'
1021
wt.commit(message='add a',
1022
timestamp=1132711707,
1024
committer='Line-Log-Formatter Tester <test@line.log>')
1025
logfile = file('out.tmp', 'w+')
1026
formatter = log.LineLogFormatter(to_file=logfile)
1027
log.show_log(b, formatter)
1030
log_contents = logfile.read()
1031
self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
814
1034
def test_trailing_newlines(self):
815
1035
wt = self.make_branch_and_tree('.')
816
b = self.make_commits_with_trailing_newlines(wt)
817
self.assertFormatterResult("""\
818
3: Joe Foo 2005-11-22 single line with trailing newline
819
2: Joe Foo 2005-11-22 multiline
820
1: Joe Foo 2005-11-22 simple log message
1036
b = make_commits_with_trailing_newlines(wt)
1037
sio = self.make_utf8_encoded_stringio()
1038
lf = log.LineLogFormatter(to_file=sio)
1040
self.assertEqualDiff("""\
1041
3: Joe Foo 2005-11-21 single line with trailing newline
1042
2: Joe Bar 2005-11-21 multiline
1043
1: Joe Foo 2005-11-21 simple log message
822
b, log.LineLogFormatter)
1047
def _prepare_tree_with_merges(self, with_tags=False):
1048
wt = self.make_branch_and_memory_tree('.')
1050
self.addCleanup(wt.unlock)
1052
wt.commit('rev-1', rev_id='rev-1',
1053
timestamp=1132586655, timezone=36000,
1054
committer='Joe Foo <joe@foo.com>')
1055
wt.commit('rev-merged', rev_id='rev-2a',
1056
timestamp=1132586700, timezone=36000,
1057
committer='Joe Foo <joe@foo.com>')
1058
wt.set_parent_ids(['rev-1', 'rev-2a'])
1059
wt.branch.set_last_revision_info(1, 'rev-1')
1060
wt.commit('rev-2', rev_id='rev-2b',
1061
timestamp=1132586800, timezone=36000,
1062
committer='Joe Foo <joe@foo.com>')
1065
branch.tags.set_tag('v0.2', 'rev-2b')
1066
wt.commit('rev-3', rev_id='rev-3',
1067
timestamp=1132586900, timezone=36000,
1068
committer='Jane Foo <jane@foo.com>')
1069
branch.tags.set_tag('v1.0rc1', 'rev-3')
1070
branch.tags.set_tag('v1.0', 'rev-3')
824
1073
def test_line_log_single_merge_revision(self):
825
1074
wt = self._prepare_tree_with_merges()
1075
logfile = self.make_utf8_encoded_stringio()
1076
formatter = log.LineLogFormatter(to_file=logfile)
826
1077
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
827
rev = revspec.in_history(wt.branch)
828
self.assertFormatterResult("""\
1079
rev = revspec.in_history(wtb)
1080
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1081
self.assertEqualDiff("""\
829
1082
1.1.1: Joe Foo 2005-11-22 rev-merged
831
wt.branch, log.LineLogFormatter,
832
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
834
1086
def test_line_log_with_tags(self):
835
1087
wt = self._prepare_tree_with_merges(with_tags=True)
836
self.assertFormatterResult("""\
837
3: Joe Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
1088
logfile = self.make_utf8_encoded_stringio()
1089
formatter = log.LineLogFormatter(to_file=logfile)
1090
log.show_log(wt.branch, formatter)
1091
self.assertEqualDiff("""\
1092
3: Jane Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
838
1093
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
839
1094
1: Joe Foo 2005-11-22 rev-1
841
wt.branch, log.LineLogFormatter)
844
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
1098
class TestLineLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
846
1100
def test_line_merge_revs_log(self):
847
1101
"""Line log should show revno
851
wt = self.make_standard_commit('test-line-log',
852
committer='Line-Log-Formatter Tester <test@line.log>',
854
self.assertFormatterResult("""\
855
1: Line-Log-Formatte... 2005-11-22 add a
857
wt.branch, log.LineLogFormatter)
1105
wt = self.make_branch_and_tree('.')
1107
self.build_tree(['a'])
1109
b.nick = 'test-line-log'
1110
wt.commit(message='add a',
1111
timestamp=1132711707,
1113
committer='Line-Log-Formatter Tester <test@line.log>')
1114
logfile = file('out.tmp', 'w+')
1115
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1116
log.show_log(b, formatter)
1119
log_contents = logfile.read()
1120
self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
859
1123
def test_line_merge_revs_log_single_merge_revision(self):
860
wt = self._prepare_tree_with_merges()
1124
wt = self.make_branch_and_memory_tree('.')
1126
self.addCleanup(wt.unlock)
1128
wt.commit('rev-1', rev_id='rev-1',
1129
timestamp=1132586655, timezone=36000,
1130
committer='Joe Foo <joe@foo.com>')
1131
wt.commit('rev-merged', rev_id='rev-2a',
1132
timestamp=1132586700, timezone=36000,
1133
committer='Joe Foo <joe@foo.com>')
1134
wt.set_parent_ids(['rev-1', 'rev-2a'])
1135
wt.branch.set_last_revision_info(1, 'rev-1')
1136
wt.commit('rev-2', rev_id='rev-2b',
1137
timestamp=1132586800, timezone=36000,
1138
committer='Joe Foo <joe@foo.com>')
1139
logfile = self.make_utf8_encoded_stringio()
1140
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
861
1141
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
862
rev = revspec.in_history(wt.branch)
863
self.assertFormatterResult("""\
1143
rev = revspec.in_history(wtb)
1144
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1145
self.assertEqualDiff("""\
864
1146
1.1.1: Joe Foo 2005-11-22 rev-merged
866
wt.branch, log.LineLogFormatter,
867
formatter_kwargs=dict(levels=0),
868
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
870
1150
def test_line_merge_revs_log_with_merges(self):
871
wt = self._prepare_tree_with_merges()
872
self.assertFormatterResult("""\
1151
wt = self.make_branch_and_memory_tree('.')
1153
self.addCleanup(wt.unlock)
1155
wt.commit('rev-1', rev_id='rev-1',
1156
timestamp=1132586655, timezone=36000,
1157
committer='Joe Foo <joe@foo.com>')
1158
wt.commit('rev-merged', rev_id='rev-2a',
1159
timestamp=1132586700, timezone=36000,
1160
committer='Joe Foo <joe@foo.com>')
1161
wt.set_parent_ids(['rev-1', 'rev-2a'])
1162
wt.branch.set_last_revision_info(1, 'rev-1')
1163
wt.commit('rev-2', rev_id='rev-2b',
1164
timestamp=1132586800, timezone=36000,
1165
committer='Joe Foo <joe@foo.com>')
1166
logfile = self.make_utf8_encoded_stringio()
1167
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1168
log.show_log(wt.branch, formatter)
1169
self.assertEqualDiff("""\
873
1170
2: Joe Foo 2005-11-22 [merge] rev-2
874
1171
1.1.1: Joe Foo 2005-11-22 rev-merged
875
1172
1: Joe Foo 2005-11-22 rev-1
877
wt.branch, log.LineLogFormatter,
878
formatter_kwargs=dict(levels=0))
881
class TestGnuChangelogFormatter(TestCaseForLogFormatter):
883
def test_gnu_changelog(self):
884
wt = self.make_standard_commit('nicky', authors=[])
885
self.assertFormatterResult('''\
886
2005-11-22 Lorem Ipsum <test@example.com>
891
wt.branch, log.GnuChangelogLogFormatter)
893
def test_with_authors(self):
894
wt = self.make_standard_commit('nicky',
895
authors=['Fooa Fooz <foo@example.com>',
896
'Bari Baro <bar@example.com>'])
897
self.assertFormatterResult('''\
898
2005-11-22 Fooa Fooz <foo@example.com>
903
wt.branch, log.GnuChangelogLogFormatter)
905
def test_verbose(self):
906
wt = self.make_standard_commit('nicky')
907
self.assertFormatterResult('''\
908
2005-11-22 John Doe <jdoe@example.com>
915
wt.branch, log.GnuChangelogLogFormatter,
916
show_log_kwargs=dict(verbose=True))
918
class TestGetViewRevisions(tests.TestCaseWithTransport, TestLogMixin):
920
def _get_view_revisions(self, *args, **kwargs):
921
return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
922
log.get_view_revisions, *args, **kwargs)
1176
class TestGetViewRevisions(tests.TestCaseWithTransport):
924
1178
def make_tree_with_commits(self):
925
1179
"""Create a tree with well-known revision ids"""
926
1180
wt = self.make_branch_and_tree('tree1')
927
self.wt_commit(wt, 'commit one', rev_id='1')
928
self.wt_commit(wt, 'commit two', rev_id='2')
929
self.wt_commit(wt, 'commit three', rev_id='3')
1181
wt.commit('commit one', rev_id='1')
1182
wt.commit('commit two', rev_id='2')
1183
wt.commit('commit three', rev_id='3')
930
1184
mainline_revs = [None, '1', '2', '3']
931
1185
rev_nos = {'1': 1, '2': 2, '3': 3}
932
1186
return mainline_revs, rev_nos, wt
935
1189
"""Create a tree with well-known revision ids and a merge"""
936
1190
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
937
1191
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
938
self.wt_commit(tree2, 'four-a', rev_id='4a')
1192
tree2.commit('four-a', rev_id='4a')
939
1193
wt.merge_from_branch(tree2.branch)
940
self.wt_commit(wt, 'four-b', rev_id='4b')
1194
wt.commit('four-b', rev_id='4b')
941
1195
mainline_revs.append('4b')
942
1196
rev_nos['4b'] = 4
944
1198
return mainline_revs, rev_nos, wt
946
def make_branch_with_many_merges(self):
1200
def make_tree_with_many_merges(self):
947
1201
"""Create a tree with well-known revision ids"""
948
builder = self.make_branch_builder('tree1')
949
builder.start_series()
950
builder.build_snapshot('1', None, [
951
('add', ('', 'TREE_ROOT', 'directory', '')),
952
('add', ('f', 'f-id', 'file', '1\n'))])
953
builder.build_snapshot('2', ['1'], [])
954
builder.build_snapshot('3a', ['2'], [
955
('modify', ('f-id', '1\n2\n3a\n'))])
956
builder.build_snapshot('3b', ['2', '3a'], [
957
('modify', ('f-id', '1\n2\n3a\n'))])
958
builder.build_snapshot('3c', ['2', '3b'], [
959
('modify', ('f-id', '1\n2\n3a\n'))])
960
builder.build_snapshot('4a', ['3b'], [])
961
builder.build_snapshot('4b', ['3c', '4a'], [])
962
builder.finish_series()
1202
wt = self.make_branch_and_tree('tree1')
1203
self.build_tree_contents([('tree1/f', '1\n')])
1204
wt.add(['f'], ['f-id'])
1205
wt.commit('commit one', rev_id='1')
1206
wt.commit('commit two', rev_id='2')
1208
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
1209
self.build_tree_contents([('tree3/f', '1\n2\n3a\n')])
1210
tree3.commit('commit three a', rev_id='3a')
1212
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1213
tree2.merge_from_branch(tree3.branch)
1214
tree2.commit('commit three b', rev_id='3b')
1216
wt.merge_from_branch(tree2.branch)
1217
wt.commit('commit three c', rev_id='3c')
1218
tree2.commit('four-a', rev_id='4a')
1220
wt.merge_from_branch(tree2.branch)
1221
wt.commit('four-b', rev_id='4b')
976
1223
mainline_revs = [None, '1', '2', '3c', '4b']
977
1224
rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
1051
1298
def test_get_view_revisions_merge2(self):
1052
1299
"""Test get_view_revisions when there are merges"""
1053
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1055
self.addCleanup(b.unlock)
1056
revisions = list(self._get_view_revisions(
1057
mainline_revs, rev_nos, b, 'forward'))
1300
mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1302
self.addCleanup(wt.unlock)
1303
revisions = list(log.get_view_revisions(
1304
mainline_revs, rev_nos, wt.branch, 'forward'))
1058
1305
expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1059
('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1306
('3a', '2.1.1', 1), ('3b', '2.2.1', 1), ('4b', '4', 0),
1060
1307
('4a', '2.2.2', 1)]
1061
1308
self.assertEqual(expected, revisions)
1062
revisions = list(self._get_view_revisions(
1063
mainline_revs, rev_nos, b, 'forward',
1309
revisions = list(log.get_view_revisions(
1310
mainline_revs, rev_nos, wt.branch, 'forward',
1064
1311
include_merges=False))
1065
1312
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1066
1313
('4b', '4', 0)],
1069
1317
def test_file_id_for_range(self):
1070
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1072
self.addCleanup(b.unlock)
1318
mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1320
self.addCleanup(wt.unlock)
1074
1322
def rev_from_rev_id(revid, branch):
1075
1323
revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1076
1324
return revspec.in_history(branch)
1078
1326
def view_revs(start_rev, end_rev, file_id, direction):
1079
revs = self.applyDeprecated(
1080
symbol_versioning.deprecated_in((2, 2, 0)),
1081
log.calculate_view_revisions,
1327
revs = log.calculate_view_revisions(
1083
1329
start_rev, # start_revision
1084
1330
end_rev, # end_revision
1085
1331
direction, # direction
1275
1512
class TestLogFormatter(tests.TestCase):
1278
super(TestLogFormatter, self).setUp()
1279
self.rev = revision.Revision('a-id')
1280
self.lf = log.LogFormatter(None)
1282
1514
def test_short_committer(self):
1283
def assertCommitter(expected, committer):
1284
self.rev.committer = committer
1285
self.assertEqual(expected, self.lf.short_committer(self.rev))
1287
assertCommitter('John Doe', 'John Doe <jdoe@example.com>')
1288
assertCommitter('John Smith', 'John Smith <jsmith@example.com>')
1289
assertCommitter('John Smith', 'John Smith')
1290
assertCommitter('jsmith@example.com', 'jsmith@example.com')
1291
assertCommitter('jsmith@example.com', '<jsmith@example.com>')
1292
assertCommitter('John Smith', 'John Smith jsmith@example.com')
1515
rev = revision.Revision('a-id')
1516
rev.committer = 'John Doe <jdoe@example.com>'
1517
lf = log.LogFormatter(None)
1518
self.assertEqual('John Doe', lf.short_committer(rev))
1519
rev.committer = 'John Smith <jsmith@example.com>'
1520
self.assertEqual('John Smith', lf.short_committer(rev))
1521
rev.committer = 'John Smith'
1522
self.assertEqual('John Smith', lf.short_committer(rev))
1523
rev.committer = 'jsmith@example.com'
1524
self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1525
rev.committer = '<jsmith@example.com>'
1526
self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1527
rev.committer = 'John Smith jsmith@example.com'
1528
self.assertEqual('John Smith', lf.short_committer(rev))
1294
1530
def test_short_author(self):
1295
def assertAuthor(expected, author):
1296
self.rev.properties['author'] = author
1297
self.assertEqual(expected, self.lf.short_author(self.rev))
1299
assertAuthor('John Smith', 'John Smith <jsmith@example.com>')
1300
assertAuthor('John Smith', 'John Smith')
1301
assertAuthor('jsmith@example.com', 'jsmith@example.com')
1302
assertAuthor('jsmith@example.com', '<jsmith@example.com>')
1303
assertAuthor('John Smith', 'John Smith jsmith@example.com')
1305
def test_short_author_from_committer(self):
1306
self.rev.committer = 'John Doe <jdoe@example.com>'
1307
self.assertEqual('John Doe', self.lf.short_author(self.rev))
1309
def test_short_author_from_authors(self):
1310
self.rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1311
'Jane Rey <jrey@example.com>')
1312
self.assertEqual('John Smith', self.lf.short_author(self.rev))
1531
rev = revision.Revision('a-id')
1532
rev.committer = 'John Doe <jdoe@example.com>'
1533
lf = log.LogFormatter(None)
1534
self.assertEqual('John Doe', lf.short_author(rev))
1535
rev.properties['author'] = 'John Smith <jsmith@example.com>'
1536
self.assertEqual('John Smith', lf.short_author(rev))
1537
rev.properties['author'] = 'John Smith'
1538
self.assertEqual('John Smith', lf.short_author(rev))
1539
rev.properties['author'] = 'jsmith@example.com'
1540
self.assertEqual('jsmith@example.com', lf.short_author(rev))
1541
rev.properties['author'] = '<jsmith@example.com>'
1542
self.assertEqual('jsmith@example.com', lf.short_author(rev))
1543
rev.properties['author'] = 'John Smith jsmith@example.com'
1544
self.assertEqual('John Smith', lf.short_author(rev))
1545
del rev.properties['author']
1546
rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1547
'Jane Rey <jrey@example.com>')
1548
self.assertEqual('John Smith', lf.short_author(rev))
1315
1551
class TestReverseByDepth(tests.TestCase):
1461
1697
log.show_branch_change(tree.branch, s, 3, '3b')
1462
1698
self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1463
1699
self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1467
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1470
TestCaseForLogFormatter.setUp(self)
1471
log.properties_handler_registry.register(
1472
'bugs_properties_handler',
1473
log._bugs_properties_handler)
1475
def make_commits_with_bugs(self):
1476
"""Helper method for LogFormatter tests"""
1477
tree = self.make_branch_and_tree(u'.')
1478
self.build_tree(['a', 'b'])
1480
self.wt_commit(tree, 'simple log message', rev_id='a1',
1481
revprops={'bugs': 'test://bug/id fixed'})
1483
self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id='a2',
1484
authors=['Joe Bar <joe@bar.com>'],
1485
revprops={'bugs': 'test://bug/id fixed\n'
1486
'test://bug/2 fixed'})
1490
def test_long_bugs(self):
1491
tree = self.make_commits_with_bugs()
1492
self.assertFormatterResult("""\
1493
------------------------------------------------------------
1495
fixes bug(s): test://bug/id test://bug/2
1496
author: Joe Bar <joe@bar.com>
1497
committer: Joe Foo <joe@foo.com>
1499
timestamp: Tue 2005-11-22 00:00:01 +0000
1504
------------------------------------------------------------
1506
fixes bug(s): test://bug/id
1507
committer: Joe Foo <joe@foo.com>
1509
timestamp: Tue 2005-11-22 00:00:00 +0000
1513
tree.branch, log.LongLogFormatter)
1515
def test_short_bugs(self):
1516
tree = self.make_commits_with_bugs()
1517
self.assertFormatterResult("""\
1518
2 Joe Bar\t2005-11-22
1519
fixes bug(s): test://bug/id test://bug/2
1524
1 Joe Foo\t2005-11-22
1525
fixes bug(s): test://bug/id
1529
tree.branch, log.ShortLogFormatter)
1531
def test_wrong_bugs_property(self):
1532
tree = self.make_branch_and_tree(u'.')
1533
self.build_tree(['foo'])
1534
self.wt_commit(tree, 'simple log message', rev_id='a1',
1535
revprops={'bugs': 'test://bug/id invalid_value'})
1536
self.assertFormatterResult("""\
1537
1 Joe Foo\t2005-11-22
1541
tree.branch, log.ShortLogFormatter)
1543
def test_bugs_handler_present(self):
1544
self.properties_handler_registry.get('bugs_properties_handler')
1546
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1548
def make_branch_with_alternate_ancestries(self, relpath='.'):
1549
# See test_merge_sorted_exclude_ancestry below for the difference with
1550
# bt.per_branch.test_iter_merge_sorted_revision.
1551
# TestIterMergeSortedRevisionsBushyGraph.
1552
# make_branch_with_alternate_ancestries
1553
# and test_merge_sorted_exclude_ancestry
1554
# See the FIXME in assertLogRevnos too.
1555
builder = branchbuilder.BranchBuilder(self.get_transport(relpath))
1567
builder.start_series()
1568
builder.build_snapshot('1', None, [
1569
('add', ('', 'TREE_ROOT', 'directory', '')),])
1570
builder.build_snapshot('1.1.1', ['1'], [])
1571
builder.build_snapshot('2', ['1'], [])
1572
builder.build_snapshot('1.2.1', ['1.1.1'], [])
1573
builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1574
builder.build_snapshot('3', ['2', '1.1.2'], [])
1575
builder.finish_series()
1576
br = builder.get_branch()
1578
self.addCleanup(br.unlock)
1581
def assertLogRevnos(self, expected_revnos, b, start, end,
1582
exclude_common_ancestry):
1583
# FIXME: the layering in log makes it hard to test intermediate levels,
1584
# I wish adding filters with their parameters were easier...
1586
iter_revs = log._calc_view_revisions(
1587
b, start, end, direction='reverse',
1588
generate_merge_revisions=True,
1589
exclude_common_ancestry=exclude_common_ancestry)
1590
self.assertEqual(expected_revnos,
1591
[revid for revid, revno, depth in iter_revs])
1593
def test_merge_sorted_exclude_ancestry(self):
1594
b = self.make_branch_with_alternate_ancestries()
1595
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1597
# '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1598
# it should be mentioned even if merge_sort order will make it appear
1600
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1601
b, '1.1.1', '3', True)