18
18
from cStringIO import StringIO
20
20
from bzrlib import (
30
class TestCaseWithoutPropsHandler(tests.TestCaseWithTransport):
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):
33
super(TestCaseWithoutPropsHandler, self).setUp()
54
super(TestCaseForLogFormatter, self).setUp()
34
55
# keep a reference to the "current" custom prop. handler registry
35
56
self.properties_handler_registry = log.properties_handler_registry
36
# clean up the registry in log
57
# Use a clean registry for log
37
58
log.properties_handler_registry = registry.Registry()
40
super(TestCaseWithoutPropsHandler, self)._cleanup()
41
# restore the custom properties handler registry
42
log.properties_handler_registry = self.properties_handler_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')
45
120
class LogCatcher(log.LogFormatter):
46
"""Pull log messages into list rather than displaying them.
48
For ease of testing we save log messages here rather than actually
49
formatting them, so that we can precisely check the result without
50
being too dependent on the exact formatting.
52
We should also test the LogFormatter.
121
"""Pull log messages into a list rather than displaying them.
123
To simplify testing we save logged revisions here rather than actually
124
formatting anything, so that we can precisely check the result without
125
being dependent on the formatting.
128
supports_merge_revisions = True
55
129
supports_delta = True
58
super(LogCatcher, self).__init__(to_file=None)
133
def __init__(self, *args, **kwargs):
134
kwargs.update(dict(to_file=None))
135
super(LogCatcher, self).__init__(*args, **kwargs)
61
138
def log_revision(self, revision):
62
self.logs.append(revision)
139
self.revisions.append(revision)
65
142
class TestShowLog(tests.TestCaseWithTransport):
181
262
lf.supports_merge_revisions = True
182
263
log.show_log(b, lf, verbose=True)
184
self.assertEqual(3, len(lf.logs))
266
self.assertEqual(3, len(revs))
186
logentry = lf.logs[0]
187
269
self.assertEqual('2', logentry.revno)
188
270
self.assertEqual('merge child branch', logentry.rev.message)
189
271
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
191
logentry = lf.logs[1]
192
274
self.assertEqual('1.1.1', logentry.revno)
193
275
self.assertEqual('remove file1 and modify file2', logentry.rev.message)
194
276
self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
196
logentry = lf.logs[2]
197
279
self.assertEqual('1', logentry.revno)
198
280
self.assertEqual('add file1 and file2', logentry.rev.message)
199
281
self.checkDelta(logentry.delta, added=['file1', 'file2'])
202
def make_commits_with_trailing_newlines(wt):
203
"""Helper method for LogFormatter tests"""
206
open('a', 'wb').write('hello moto\n')
208
wt.commit('simple log message', rev_id='a1',
209
timestamp=1132586655.459960938, timezone=-6*3600,
210
committer='Joe Foo <joe@foo.com>')
211
open('b', 'wb').write('goodbye\n')
213
wt.commit('multiline\nlog\nmessage\n', rev_id='a2',
214
timestamp=1132586842.411175966, timezone=-6*3600,
215
committer='Joe Foo <joe@foo.com>',
216
authors=['Joe Bar <joe@bar.com>'])
218
open('c', 'wb').write('just another manic monday\n')
220
wt.commit('single line with trailing newline\n', rev_id='a3',
221
timestamp=1132587176.835228920, timezone=-6*3600,
222
committer = 'Joe Foo <joe@foo.com>')
226
def normalize_log(log):
227
"""Replaces the variable lines of logs with fixed lines"""
228
author = 'author: Dolor Sit <test@example.com>'
229
committer = 'committer: Lorem Ipsum <test@example.com>'
230
lines = log.splitlines(True)
231
for idx,line in enumerate(lines):
232
stripped_line = line.lstrip()
233
indent = ' ' * (len(line) - len(stripped_line))
234
if stripped_line.startswith('author:'):
235
lines[idx] = indent + author + '\n'
236
elif stripped_line.startswith('committer:'):
237
lines[idx] = indent + committer + '\n'
238
elif stripped_line.startswith('timestamp:'):
239
lines[idx] = indent + 'timestamp: Just now\n'
240
return ''.join(lines)
243
class TestShortLogFormatter(tests.TestCaseWithTransport):
284
class TestShortLogFormatter(TestCaseForLogFormatter):
245
286
def test_trailing_newlines(self):
246
287
wt = self.make_branch_and_tree('.')
247
b = make_commits_with_trailing_newlines(wt)
248
sio = self.make_utf8_encoded_stringio()
249
lf = log.ShortLogFormatter(to_file=sio)
251
self.assertEqualDiff("""\
252
3 Joe Foo\t2005-11-21
288
b = self.make_commits_with_trailing_newlines(wt)
289
self.assertFormatterResult("""\
290
3 Joe Foo\t2005-11-22
253
291
single line with trailing newline
255
2 Joe Bar\t2005-11-21
293
2 Joe Foo\t2005-11-22
260
1 Joe Foo\t2005-11-21
298
1 Joe Foo\t2005-11-22
261
299
simple log message
266
def _prepare_tree_with_merges(self, with_tags=False):
267
wt = self.make_branch_and_memory_tree('.')
269
self.addCleanup(wt.unlock)
271
wt.commit('rev-1', rev_id='rev-1',
272
timestamp=1132586655, timezone=36000,
273
committer='Joe Foo <joe@foo.com>')
274
wt.commit('rev-merged', rev_id='rev-2a',
275
timestamp=1132586700, timezone=36000,
276
committer='Joe Foo <joe@foo.com>')
277
wt.set_parent_ids(['rev-1', 'rev-2a'])
278
wt.branch.set_last_revision_info(1, 'rev-1')
279
wt.commit('rev-2', rev_id='rev-2b',
280
timestamp=1132586800, timezone=36000,
281
committer='Joe Foo <joe@foo.com>')
284
branch.tags.set_tag('v0.2', 'rev-2b')
285
wt.commit('rev-3', rev_id='rev-3',
286
timestamp=1132586900, timezone=36000,
287
committer='Jane Foo <jane@foo.com>')
288
branch.tags.set_tag('v1.0rc1', 'rev-3')
289
branch.tags.set_tag('v1.0', 'rev-3')
302
b, log.ShortLogFormatter)
292
304
def test_short_log_with_merges(self):
293
305
wt = self._prepare_tree_with_merges()
294
logfile = self.make_utf8_encoded_stringio()
295
formatter = log.ShortLogFormatter(to_file=logfile)
296
log.show_log(wt.branch, formatter)
297
self.assertEqualDiff("""\
298
2 Joe Foo\t2005-11-22 [merge]
301
1 Joe Foo\t2005-11-22
304
Use --levels 0 (or -n0) to see merged revisions.
306
self.assertFormatterResult("""\
307
2 Joe Foo\t2005-11-22 [merge]
310
1 Joe Foo\t2005-11-22
314
wt.branch, log.ShortLogFormatter)
316
def test_short_log_with_merges_and_advice(self):
317
wt = self._prepare_tree_with_merges()
318
self.assertFormatterResult("""\
319
2 Joe Foo\t2005-11-22 [merge]
322
1 Joe Foo\t2005-11-22
325
Use --include-merges or -n0 to see merged revisions.
327
wt.branch, log.ShortLogFormatter,
328
formatter_kwargs=dict(show_advice=True))
308
330
def test_short_log_with_merges_and_range(self):
309
wt = self.make_branch_and_memory_tree('.')
311
self.addCleanup(wt.unlock)
313
wt.commit('rev-1', rev_id='rev-1',
314
timestamp=1132586655, timezone=36000,
315
committer='Joe Foo <joe@foo.com>')
316
wt.commit('rev-merged', rev_id='rev-2a',
317
timestamp=1132586700, timezone=36000,
318
committer='Joe Foo <joe@foo.com>')
319
wt.branch.set_last_revision_info(1, 'rev-1')
320
wt.set_parent_ids(['rev-1', 'rev-2a'])
321
wt.commit('rev-2b', rev_id='rev-2b',
322
timestamp=1132586800, timezone=36000,
323
committer='Joe Foo <joe@foo.com>')
324
wt.commit('rev-3a', rev_id='rev-3a',
325
timestamp=1132586800, timezone=36000,
326
committer='Joe Foo <joe@foo.com>')
331
wt = self._prepare_tree_with_merges()
332
self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
327
333
wt.branch.set_last_revision_info(2, 'rev-2b')
328
334
wt.set_parent_ids(['rev-2b', 'rev-3a'])
329
wt.commit('rev-3b', rev_id='rev-3b',
330
timestamp=1132586800, timezone=36000,
331
committer='Joe Foo <joe@foo.com>')
332
logfile = self.make_utf8_encoded_stringio()
333
formatter = log.ShortLogFormatter(to_file=logfile)
334
log.show_log(wt.branch, formatter,
335
start_revision=2, end_revision=3)
336
self.assertEqualDiff("""\
335
self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
336
self.assertFormatterResult("""\
337
337
3 Joe Foo\t2005-11-22 [merge]
340
340
2 Joe Foo\t2005-11-22 [merge]
343
Use --levels 0 (or -n0) to see merged revisions.
344
wt.branch, log.ShortLogFormatter,
345
show_log_kwargs=dict(start_revision=2, end_revision=3))
347
347
def test_short_log_with_tags(self):
348
348
wt = self._prepare_tree_with_merges(with_tags=True)
349
logfile = self.make_utf8_encoded_stringio()
350
formatter = log.ShortLogFormatter(to_file=logfile)
351
log.show_log(wt.branch, formatter)
352
self.assertEqualDiff("""\
353
3 Jane Foo\t2005-11-22 {v1.0, v1.0rc1}
349
self.assertFormatterResult("""\
350
3 Joe Foo\t2005-11-22 {v1.0, v1.0rc1}
356
353
2 Joe Foo\t2005-11-22 {v0.2} [merge]
359
356
1 Joe Foo\t2005-11-22
362
Use --levels 0 (or -n0) to see merged revisions.
360
wt.branch, log.ShortLogFormatter)
366
362
def test_short_log_single_merge_revision(self):
367
wt = self.make_branch_and_memory_tree('.')
369
self.addCleanup(wt.unlock)
371
wt.commit('rev-1', rev_id='rev-1',
372
timestamp=1132586655, timezone=36000,
373
committer='Joe Foo <joe@foo.com>')
374
wt.commit('rev-merged', rev_id='rev-2a',
375
timestamp=1132586700, timezone=36000,
376
committer='Joe Foo <joe@foo.com>')
377
wt.set_parent_ids(['rev-1', 'rev-2a'])
378
wt.branch.set_last_revision_info(1, 'rev-1')
379
wt.commit('rev-2', rev_id='rev-2b',
380
timestamp=1132586800, timezone=36000,
381
committer='Joe Foo <joe@foo.com>')
382
logfile = self.make_utf8_encoded_stringio()
383
formatter = log.ShortLogFormatter(to_file=logfile)
363
wt = self._prepare_tree_with_merges()
384
364
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
386
rev = revspec.in_history(wtb)
387
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
388
self.assertEqualDiff("""\
365
rev = revspec.in_history(wt.branch)
366
self.assertFormatterResult("""\
389
367
1.1.1 Joe Foo\t2005-11-22
396
class TestShortLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
371
wt.branch, log.ShortLogFormatter,
372
show_log_kwargs=dict(start_revision=rev, end_revision=rev))
375
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
398
377
def test_short_merge_revs_log_with_merges(self):
399
wt = self.make_branch_and_memory_tree('.')
401
self.addCleanup(wt.unlock)
403
wt.commit('rev-1', rev_id='rev-1',
404
timestamp=1132586655, timezone=36000,
405
committer='Joe Foo <joe@foo.com>')
406
wt.commit('rev-merged', rev_id='rev-2a',
407
timestamp=1132586700, timezone=36000,
408
committer='Joe Foo <joe@foo.com>')
409
wt.set_parent_ids(['rev-1', 'rev-2a'])
410
wt.branch.set_last_revision_info(1, 'rev-1')
411
wt.commit('rev-2', rev_id='rev-2b',
412
timestamp=1132586800, timezone=36000,
413
committer='Joe Foo <joe@foo.com>')
414
logfile = self.make_utf8_encoded_stringio()
415
formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
416
log.show_log(wt.branch, formatter)
378
wt = self._prepare_tree_with_merges()
417
379
# Note that the 1.1.1 indenting is in fact correct given that
418
380
# the revision numbers are right justified within 5 characters
419
381
# for mainline revnos and 9 characters for dotted revnos.
420
self.assertEqualDiff("""\
382
self.assertFormatterResult("""\
421
383
2 Joe Foo\t2005-11-22 [merge]
393
wt.branch, log.ShortLogFormatter,
394
formatter_kwargs=dict(levels=0))
433
396
def test_short_merge_revs_log_single_merge_revision(self):
434
wt = self.make_branch_and_memory_tree('.')
436
self.addCleanup(wt.unlock)
438
wt.commit('rev-1', rev_id='rev-1',
439
timestamp=1132586655, timezone=36000,
440
committer='Joe Foo <joe@foo.com>')
441
wt.commit('rev-merged', rev_id='rev-2a',
442
timestamp=1132586700, timezone=36000,
443
committer='Joe Foo <joe@foo.com>')
444
wt.set_parent_ids(['rev-1', 'rev-2a'])
445
wt.branch.set_last_revision_info(1, 'rev-1')
446
wt.commit('rev-2', rev_id='rev-2b',
447
timestamp=1132586800, timezone=36000,
448
committer='Joe Foo <joe@foo.com>')
449
logfile = self.make_utf8_encoded_stringio()
450
formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
397
wt = self._prepare_tree_with_merges()
451
398
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
453
rev = revspec.in_history(wtb)
454
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
455
self.assertEqualDiff("""\
399
rev = revspec.in_history(wt.branch)
400
self.assertFormatterResult("""\
456
401
1.1.1 Joe Foo\t2005-11-22
463
class TestLongLogFormatter(TestCaseWithoutPropsHandler):
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):
465
412
def test_verbose_log(self):
466
413
"""Verbose log includes changed files
470
wt = self.make_branch_and_tree('.')
472
self.build_tree(['a'])
474
# XXX: why does a longer nick show up?
475
b.nick = 'test_verbose_log'
476
wt.commit(message='add a',
477
timestamp=1132711707,
479
committer='Lorem Ipsum <test@example.com>')
480
logfile = file('out.tmp', 'w+')
481
formatter = log.LongLogFormatter(to_file=logfile)
482
log.show_log(b, formatter, verbose=True)
485
log_contents = logfile.read()
486
self.assertEqualDiff('''\
417
wt = self.make_standard_commit('test_verbose_log', authors=[])
418
self.assertFormatterResult('''\
487
419
------------------------------------------------------------
489
421
committer: Lorem Ipsum <test@example.com>
490
422
branch nick: test_verbose_log
491
timestamp: Wed 2005-11-23 12:08:27 +1000
423
timestamp: Tue 2005-11-22 00:00:00 +0000
429
wt.branch, log.LongLogFormatter,
430
show_log_kwargs=dict(verbose=True))
499
432
def test_merges_are_indented_by_level(self):
500
433
wt = self.make_branch_and_tree('parent')
501
wt.commit('first post')
502
self.run_bzr('branch parent child')
503
self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
504
self.run_bzr('branch child smallerchild')
505
self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
508
self.run_bzr('merge ../smallerchild')
509
self.run_bzr(['commit', '-m', 'merge branch 2'])
510
os.chdir('../parent')
511
self.run_bzr('merge ../child')
512
wt.commit('merge branch 1')
514
sio = self.make_utf8_encoded_stringio()
515
lf = log.LongLogFormatter(to_file=sio, levels=0)
516
log.show_log(b, lf, verbose=True)
517
the_log = normalize_log(sio.getvalue())
518
self.assertEqualDiff("""\
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("""\
519
444
------------------------------------------------------------
521
committer: Lorem Ipsum <test@example.com>
446
committer: Joe Foo <joe@foo.com>
522
447
branch nick: parent
448
timestamp: Tue 2005-11-22 00:00:04 +0000
526
451
------------------------------------------------------------
527
452
revno: 1.1.2 [merge]
528
committer: Lorem Ipsum <test@example.com>
453
committer: Joe Foo <joe@foo.com>
529
454
branch nick: child
455
timestamp: Tue 2005-11-22 00:00:03 +0000
533
458
------------------------------------------------------------
535
committer: Lorem Ipsum <test@example.com>
460
committer: Joe Foo <joe@foo.com>
536
461
branch nick: smallerchild
462
timestamp: Tue 2005-11-22 00:00:02 +0000
540
465
------------------------------------------------------------
542
committer: Lorem Ipsum <test@example.com>
467
committer: Joe Foo <joe@foo.com>
543
468
branch nick: child
469
timestamp: Tue 2005-11-22 00:00:01 +0000
547
472
------------------------------------------------------------
549
committer: Lorem Ipsum <test@example.com>
474
committer: Joe Foo <joe@foo.com>
550
475
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))
557
484
def test_verbose_merge_revisions_contain_deltas(self):
558
485
wt = self.make_branch_and_tree('parent')
559
486
self.build_tree(['parent/f1', 'parent/f2'])
560
487
wt.add(['f1','f2'])
561
wt.commit('first post')
562
self.run_bzr('branch parent child')
488
self.wt_commit(wt, 'first post')
489
child_wt = wt.bzrdir.sprout('child').open_workingtree()
563
490
os.unlink('child/f1')
564
file('child/f2', 'wb').write('hello\n')
565
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
568
self.run_bzr('merge ../child')
569
wt.commit('merge branch 1')
571
sio = self.make_utf8_encoded_stringio()
572
lf = log.LongLogFormatter(to_file=sio, levels=0)
573
log.show_log(b, lf, verbose=True)
574
the_log = normalize_log(sio.getvalue())
575
self.assertEqualDiff("""\
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("""\
576
496
------------------------------------------------------------
578
committer: Lorem Ipsum <test@example.com>
498
committer: Joe Foo <joe@foo.com>
579
499
branch nick: parent
500
timestamp: Tue 2005-11-22 00:00:02 +0000
637
555
committer: Joe Foo <joe@foo.com>
638
556
branch nick: test
639
timestamp: Mon 2005-11-21 09:24:15 -0600
557
timestamp: Tue 2005-11-22 00:00:00 +0000
641
559
simple log message
561
b, log.LongLogFormatter)
645
563
def test_author_in_log(self):
646
564
"""Log includes the author name if it's set in
647
565
the revision properties
649
wt = self.make_branch_and_tree('.')
651
self.build_tree(['a'])
653
b.nick = 'test_author_log'
654
wt.commit(message='add a',
655
timestamp=1132711707,
657
committer='Lorem Ipsum <test@example.com>',
658
authors=['John Doe <jdoe@example.com>',
659
'Jane Rey <jrey@example.com>'])
661
formatter = log.LongLogFormatter(to_file=sio)
662
log.show_log(b, formatter)
663
self.assertEqualDiff('''\
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("""\
664
571
------------------------------------------------------------
666
573
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
667
574
committer: Lorem Ipsum <test@example.com>
668
575
branch nick: test_author_log
669
timestamp: Wed 2005-11-23 12:08:27 +1000
576
timestamp: Tue 2005-11-22 00:00:00 +0000
580
wt.branch, log.LongLogFormatter)
675
582
def test_properties_in_log(self):
676
583
"""Log includes the custom properties returned by the registered
679
wt = self.make_branch_and_tree('.')
681
self.build_tree(['a'])
683
b.nick = 'test_properties_in_log'
684
wt.commit(message='add a',
685
timestamp=1132711707,
687
committer='Lorem Ipsum <test@example.com>',
688
authors=['John Doe <jdoe@example.com>'])
690
formatter = log.LongLogFormatter(to_file=sio)
692
def trivial_custom_prop_handler(revision):
693
return {'test_prop':'test_value'}
586
wt = self.make_standard_commit('test_properties_in_log')
587
def trivial_custom_prop_handler(revision):
588
return {'test_prop':'test_value'}
695
log.properties_handler_registry.register(
696
'trivial_custom_prop_handler',
697
trivial_custom_prop_handler)
698
log.show_log(b, formatter)
700
log.properties_handler_registry.remove(
701
'trivial_custom_prop_handler')
702
self.assertEqualDiff('''\
590
# Cleaned up in setUp()
591
log.properties_handler_registry.register(
592
'trivial_custom_prop_handler',
593
trivial_custom_prop_handler)
594
self.assertFormatterResult("""\
703
595
------------------------------------------------------------
705
597
test_prop: test_value
706
598
author: John Doe <jdoe@example.com>
707
599
committer: Lorem Ipsum <test@example.com>
708
600
branch nick: test_properties_in_log
709
timestamp: Wed 2005-11-23 12:08:27 +1000
601
timestamp: Tue 2005-11-22 00:00:00 +0000
605
wt.branch, log.LongLogFormatter)
715
607
def test_properties_in_short_log(self):
716
608
"""Log includes the custom properties returned by the registered
719
wt = self.make_branch_and_tree('.')
721
self.build_tree(['a'])
723
b.nick = 'test_properties_in_short_log'
724
wt.commit(message='add a',
725
timestamp=1132711707,
727
committer='Lorem Ipsum <test@example.com>',
728
authors=['John Doe <jdoe@example.com>'])
730
formatter = log.ShortLogFormatter(to_file=sio)
732
def trivial_custom_prop_handler(revision):
733
return {'test_prop':'test_value'}
611
wt = self.make_standard_commit('test_properties_in_short_log')
612
def trivial_custom_prop_handler(revision):
613
return {'test_prop':'test_value'}
735
log.properties_handler_registry.register(
736
'trivial_custom_prop_handler',
737
trivial_custom_prop_handler)
738
log.show_log(b, formatter)
740
log.properties_handler_registry.remove(
741
'trivial_custom_prop_handler')
742
self.assertEqualDiff('''\
743
1 John Doe\t2005-11-23
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
744
620
test_prop: test_value
624
wt.branch, log.ShortLogFormatter)
750
626
def test_error_in_properties_handler(self):
751
627
"""Log includes the custom properties returned by the registered
754
wt = self.make_branch_and_tree('.')
756
self.build_tree(['a'])
758
b.nick = 'test_author_log'
759
wt.commit(message='add a',
760
timestamp=1132711707,
762
committer='Lorem Ipsum <test@example.com>',
763
authors=['John Doe <jdoe@example.com>'],
764
revprops={'first_prop':'first_value'})
630
wt = self.make_standard_commit('error_in_properties_handler',
631
revprops={'first_prop':'first_value'})
632
sio = self.make_utf8_encoded_stringio()
766
633
formatter = log.LongLogFormatter(to_file=sio)
768
def trivial_custom_prop_handler(revision):
769
raise StandardError("a test error")
634
def trivial_custom_prop_handler(revision):
635
raise StandardError("a test error")
771
log.properties_handler_registry.register(
772
'trivial_custom_prop_handler',
773
trivial_custom_prop_handler)
774
self.assertRaises(StandardError, log.show_log, b, formatter,)
776
log.properties_handler_registry.remove(
777
'trivial_custom_prop_handler')
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,)
779
642
def test_properties_handler_bad_argument(self):
780
wt = self.make_branch_and_tree('.')
782
self.build_tree(['a'])
784
b.nick = 'test_author_log'
785
wt.commit(message='add a',
786
timestamp=1132711707,
788
committer='Lorem Ipsum <test@example.com>',
789
authors=['John Doe <jdoe@example.com>'],
790
revprops={'a_prop':'test_value'})
643
wt = self.make_standard_commit('bad_argument',
644
revprops={'a_prop':'test_value'})
645
sio = self.make_utf8_encoded_stringio()
792
646
formatter = log.LongLogFormatter(to_file=sio)
794
def bad_argument_prop_handler(revision):
795
return {'custom_prop_name':revision.properties['a_prop']}
797
log.properties_handler_registry.register(
798
'bad_argument_prop_handler',
799
bad_argument_prop_handler)
801
self.assertRaises(AttributeError, formatter.show_properties,
804
revision = b.repository.get_revision(b.last_revision())
805
formatter.show_properties(revision, '')
806
self.assertEqualDiff('''custom_prop_name: test_value\n''',
809
log.properties_handler_registry.remove(
810
'bad_argument_prop_handler')
813
class TestLongLogFormatterWithoutMergeRevisions(TestCaseWithoutPropsHandler):
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):
815
665
def test_long_verbose_log(self):
816
666
"""Verbose log includes changed files
820
wt = self.make_branch_and_tree('.')
822
self.build_tree(['a'])
824
# XXX: why does a longer nick show up?
825
b.nick = 'test_verbose_log'
826
wt.commit(message='add a',
827
timestamp=1132711707,
829
committer='Lorem Ipsum <test@example.com>')
830
logfile = file('out.tmp', 'w+')
831
formatter = log.LongLogFormatter(to_file=logfile, levels=1)
832
log.show_log(b, formatter, verbose=True)
835
log_contents = logfile.read()
836
self.assertEqualDiff('''\
670
wt = self.make_standard_commit('test_long_verbose_log', authors=[])
671
self.assertFormatterResult("""\
837
672
------------------------------------------------------------
839
674
committer: Lorem Ipsum <test@example.com>
840
branch nick: test_verbose_log
841
timestamp: Wed 2005-11-23 12:08:27 +1000
675
branch nick: test_long_verbose_log
676
timestamp: Tue 2005-11-22 00:00:00 +0000
682
wt.branch, log.LongLogFormatter,
683
formatter_kwargs=dict(levels=1),
684
show_log_kwargs=dict(verbose=True))
849
686
def test_long_verbose_contain_deltas(self):
850
687
wt = self.make_branch_and_tree('parent')
851
688
self.build_tree(['parent/f1', 'parent/f2'])
852
689
wt.add(['f1','f2'])
853
wt.commit('first post')
854
self.run_bzr('branch parent child')
690
self.wt_commit(wt, 'first post')
691
child_wt = wt.bzrdir.sprout('child').open_workingtree()
855
692
os.unlink('child/f1')
856
file('child/f2', 'wb').write('hello\n')
857
self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
860
self.run_bzr('merge ../child')
861
wt.commit('merge branch 1')
863
sio = self.make_utf8_encoded_stringio()
864
lf = log.LongLogFormatter(to_file=sio, levels=1)
865
log.show_log(b, lf, verbose=True)
866
the_log = normalize_log(sio.getvalue())
867
self.assertEqualDiff("""\
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("""\
868
698
------------------------------------------------------------
870
committer: Lorem Ipsum <test@example.com>
700
committer: Joe Foo <joe@foo.com>
871
701
branch nick: parent
702
timestamp: Tue 2005-11-22 00:00:02 +0000
920
746
committer: Joe Foo <joe@foo.com>
921
747
branch nick: test
922
timestamp: Mon 2005-11-21 09:24:15 -0600
748
timestamp: Tue 2005-11-22 00:00:00 +0000
924
750
simple log message
752
b, log.LongLogFormatter,
753
formatter_kwargs=dict(levels=1))
928
755
def test_long_author_in_log(self):
929
756
"""Log includes the author name if it's set in
930
757
the revision properties
932
wt = self.make_branch_and_tree('.')
934
self.build_tree(['a'])
936
b.nick = 'test_author_log'
937
wt.commit(message='add a',
938
timestamp=1132711707,
940
committer='Lorem Ipsum <test@example.com>',
941
authors=['John Doe <jdoe@example.com>'])
943
formatter = log.LongLogFormatter(to_file=sio, levels=1)
944
log.show_log(b, formatter)
945
self.assertEqualDiff('''\
759
wt = self.make_standard_commit('test_author_log')
760
self.assertFormatterResult("""\
946
761
------------------------------------------------------------
948
763
author: John Doe <jdoe@example.com>
949
764
committer: Lorem Ipsum <test@example.com>
950
765
branch nick: test_author_log
951
timestamp: Wed 2005-11-23 12:08:27 +1000
766
timestamp: Tue 2005-11-22 00:00:00 +0000
770
wt.branch, log.LongLogFormatter,
771
formatter_kwargs=dict(levels=1))
957
773
def test_long_properties_in_log(self):
958
774
"""Log includes the custom properties returned by the registered
961
wt = self.make_branch_and_tree('.')
963
self.build_tree(['a'])
965
b.nick = 'test_properties_in_log'
966
wt.commit(message='add a',
967
timestamp=1132711707,
969
committer='Lorem Ipsum <test@example.com>',
970
authors=['John Doe <jdoe@example.com>'])
972
formatter = log.LongLogFormatter(to_file=sio, levels=1)
974
def trivial_custom_prop_handler(revision):
975
return {'test_prop':'test_value'}
777
wt = self.make_standard_commit('test_properties_in_log')
778
def trivial_custom_prop_handler(revision):
779
return {'test_prop':'test_value'}
977
log.properties_handler_registry.register(
978
'trivial_custom_prop_handler',
979
trivial_custom_prop_handler)
980
log.show_log(b, formatter)
982
log.properties_handler_registry.remove(
983
'trivial_custom_prop_handler')
984
self.assertEqualDiff('''\
781
log.properties_handler_registry.register(
782
'trivial_custom_prop_handler',
783
trivial_custom_prop_handler)
784
self.assertFormatterResult("""\
985
785
------------------------------------------------------------
987
787
test_prop: test_value
988
788
author: John Doe <jdoe@example.com>
989
789
committer: Lorem Ipsum <test@example.com>
990
790
branch nick: test_properties_in_log
991
timestamp: Wed 2005-11-23 12:08:27 +1000
791
timestamp: Tue 2005-11-22 00:00:00 +0000
998
class TestLineLogFormatter(tests.TestCaseWithTransport):
795
wt.branch, log.LongLogFormatter,
796
formatter_kwargs=dict(levels=1))
799
class TestLineLogFormatter(TestCaseForLogFormatter):
1000
801
def test_line_log(self):
1001
802
"""Line log should show revno
1005
wt = self.make_branch_and_tree('.')
1007
self.build_tree(['a'])
1009
b.nick = 'test-line-log'
1010
wt.commit(message='add a',
1011
timestamp=1132711707,
1013
committer='Line-Log-Formatter Tester <test@line.log>')
1014
logfile = file('out.tmp', 'w+')
1015
formatter = log.LineLogFormatter(to_file=logfile)
1016
log.show_log(b, formatter)
1019
log_contents = logfile.read()
1020
self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
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)
1023
814
def test_trailing_newlines(self):
1024
815
wt = self.make_branch_and_tree('.')
1025
b = make_commits_with_trailing_newlines(wt)
1026
sio = self.make_utf8_encoded_stringio()
1027
lf = log.LineLogFormatter(to_file=sio)
1029
self.assertEqualDiff("""\
1030
3: Joe Foo 2005-11-21 single line with trailing newline
1031
2: Joe Bar 2005-11-21 multiline
1032
1: Joe Foo 2005-11-21 simple log message
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
def _prepare_tree_with_merges(self, with_tags=False):
1037
wt = self.make_branch_and_memory_tree('.')
1039
self.addCleanup(wt.unlock)
1041
wt.commit('rev-1', rev_id='rev-1',
1042
timestamp=1132586655, timezone=36000,
1043
committer='Joe Foo <joe@foo.com>')
1044
wt.commit('rev-merged', rev_id='rev-2a',
1045
timestamp=1132586700, timezone=36000,
1046
committer='Joe Foo <joe@foo.com>')
1047
wt.set_parent_ids(['rev-1', 'rev-2a'])
1048
wt.branch.set_last_revision_info(1, 'rev-1')
1049
wt.commit('rev-2', rev_id='rev-2b',
1050
timestamp=1132586800, timezone=36000,
1051
committer='Joe Foo <joe@foo.com>')
1054
branch.tags.set_tag('v0.2', 'rev-2b')
1055
wt.commit('rev-3', rev_id='rev-3',
1056
timestamp=1132586900, timezone=36000,
1057
committer='Jane Foo <jane@foo.com>')
1058
branch.tags.set_tag('v1.0rc1', 'rev-3')
1059
branch.tags.set_tag('v1.0', 'rev-3')
822
b, log.LineLogFormatter)
1062
824
def test_line_log_single_merge_revision(self):
1063
825
wt = self._prepare_tree_with_merges()
1064
logfile = self.make_utf8_encoded_stringio()
1065
formatter = log.LineLogFormatter(to_file=logfile)
1066
826
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1068
rev = revspec.in_history(wtb)
1069
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1070
self.assertEqualDiff("""\
827
rev = revspec.in_history(wt.branch)
828
self.assertFormatterResult("""\
1071
829
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))
1075
834
def test_line_log_with_tags(self):
1076
835
wt = self._prepare_tree_with_merges(with_tags=True)
1077
logfile = self.make_utf8_encoded_stringio()
1078
formatter = log.LineLogFormatter(to_file=logfile)
1079
log.show_log(wt.branch, formatter)
1080
self.assertEqualDiff("""\
1081
3: Jane Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
836
self.assertFormatterResult("""\
837
3: Joe Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
1082
838
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
1083
839
1: Joe Foo 2005-11-22 rev-1
1087
class TestLineLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
841
wt.branch, log.LineLogFormatter)
844
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
1089
846
def test_line_merge_revs_log(self):
1090
847
"""Line log should show revno
1094
wt = self.make_branch_and_tree('.')
1096
self.build_tree(['a'])
1098
b.nick = 'test-line-log'
1099
wt.commit(message='add a',
1100
timestamp=1132711707,
1102
committer='Line-Log-Formatter Tester <test@line.log>')
1103
logfile = file('out.tmp', 'w+')
1104
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1105
log.show_log(b, formatter)
1108
log_contents = logfile.read()
1109
self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
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)
1112
859
def test_line_merge_revs_log_single_merge_revision(self):
1113
wt = self.make_branch_and_memory_tree('.')
1115
self.addCleanup(wt.unlock)
1117
wt.commit('rev-1', rev_id='rev-1',
1118
timestamp=1132586655, timezone=36000,
1119
committer='Joe Foo <joe@foo.com>')
1120
wt.commit('rev-merged', rev_id='rev-2a',
1121
timestamp=1132586700, timezone=36000,
1122
committer='Joe Foo <joe@foo.com>')
1123
wt.set_parent_ids(['rev-1', 'rev-2a'])
1124
wt.branch.set_last_revision_info(1, 'rev-1')
1125
wt.commit('rev-2', rev_id='rev-2b',
1126
timestamp=1132586800, timezone=36000,
1127
committer='Joe Foo <joe@foo.com>')
1128
logfile = self.make_utf8_encoded_stringio()
1129
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
860
wt = self._prepare_tree_with_merges()
1130
861
revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1132
rev = revspec.in_history(wtb)
1133
log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1134
self.assertEqualDiff("""\
862
rev = revspec.in_history(wt.branch)
863
self.assertFormatterResult("""\
1135
864
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))
1139
870
def test_line_merge_revs_log_with_merges(self):
1140
wt = self.make_branch_and_memory_tree('.')
1142
self.addCleanup(wt.unlock)
1144
wt.commit('rev-1', rev_id='rev-1',
1145
timestamp=1132586655, timezone=36000,
1146
committer='Joe Foo <joe@foo.com>')
1147
wt.commit('rev-merged', rev_id='rev-2a',
1148
timestamp=1132586700, timezone=36000,
1149
committer='Joe Foo <joe@foo.com>')
1150
wt.set_parent_ids(['rev-1', 'rev-2a'])
1151
wt.branch.set_last_revision_info(1, 'rev-1')
1152
wt.commit('rev-2', rev_id='rev-2b',
1153
timestamp=1132586800, timezone=36000,
1154
committer='Joe Foo <joe@foo.com>')
1155
logfile = self.make_utf8_encoded_stringio()
1156
formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1157
log.show_log(wt.branch, formatter)
1158
self.assertEqualDiff("""\
871
wt = self._prepare_tree_with_merges()
872
self.assertFormatterResult("""\
1159
873
2: Joe Foo 2005-11-22 [merge] rev-2
1160
874
1.1.1: Joe Foo 2005-11-22 rev-merged
1161
875
1: Joe Foo 2005-11-22 rev-1
1165
class TestGetViewRevisions(tests.TestCaseWithTransport):
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)
1167
924
def make_tree_with_commits(self):
1168
925
"""Create a tree with well-known revision ids"""
1169
926
wt = self.make_branch_and_tree('tree1')
1170
wt.commit('commit one', rev_id='1')
1171
wt.commit('commit two', rev_id='2')
1172
wt.commit('commit three', rev_id='3')
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')
1173
930
mainline_revs = [None, '1', '2', '3']
1174
931
rev_nos = {'1': 1, '2': 2, '3': 3}
1175
932
return mainline_revs, rev_nos, wt
1178
935
"""Create a tree with well-known revision ids and a merge"""
1179
936
mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1180
937
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1181
tree2.commit('four-a', rev_id='4a')
938
self.wt_commit(tree2, 'four-a', rev_id='4a')
1182
939
wt.merge_from_branch(tree2.branch)
1183
wt.commit('four-b', rev_id='4b')
940
self.wt_commit(wt, 'four-b', rev_id='4b')
1184
941
mainline_revs.append('4b')
1185
942
rev_nos['4b'] = 4
1187
944
return mainline_revs, rev_nos, wt
1189
def make_tree_with_many_merges(self):
946
def make_branch_with_many_merges(self):
1190
947
"""Create a tree with well-known revision ids"""
1191
wt = self.make_branch_and_tree('tree1')
1192
self.build_tree_contents([('tree1/f', '1\n')])
1193
wt.add(['f'], ['f-id'])
1194
wt.commit('commit one', rev_id='1')
1195
wt.commit('commit two', rev_id='2')
1197
tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
1198
self.build_tree_contents([('tree3/f', '1\n2\n3a\n')])
1199
tree3.commit('commit three a', rev_id='3a')
1201
tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1202
tree2.merge_from_branch(tree3.branch)
1203
tree2.commit('commit three b', rev_id='3b')
1205
wt.merge_from_branch(tree2.branch)
1206
wt.commit('commit three c', rev_id='3c')
1207
tree2.commit('four-a', rev_id='4a')
1209
wt.merge_from_branch(tree2.branch)
1210
wt.commit('four-b', rev_id='4b')
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()
1212
976
mainline_revs = [None, '1', '2', '3c', '4b']
1213
977
rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
1287
1051
def test_get_view_revisions_merge2(self):
1288
1052
"""Test get_view_revisions when there are merges"""
1289
mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1291
self.addCleanup(wt.unlock)
1292
revisions = list(log.get_view_revisions(
1293
mainline_revs, rev_nos, wt.branch, 'forward'))
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'))
1294
1058
expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1295
('3a', '2.1.1', 1), ('3b', '2.2.1', 1), ('4b', '4', 0),
1059
('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1296
1060
('4a', '2.2.2', 1)]
1297
1061
self.assertEqual(expected, revisions)
1298
revisions = list(log.get_view_revisions(
1299
mainline_revs, rev_nos, wt.branch, 'forward',
1062
revisions = list(self._get_view_revisions(
1063
mainline_revs, rev_nos, b, 'forward',
1300
1064
include_merges=False))
1301
1065
self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1302
1066
('4b', '4', 0)],
1306
1069
def test_file_id_for_range(self):
1307
mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1309
self.addCleanup(wt.unlock)
1070
mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1072
self.addCleanup(b.unlock)
1311
1074
def rev_from_rev_id(revid, branch):
1312
1075
revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1313
1076
return revspec.in_history(branch)
1315
1078
def view_revs(start_rev, end_rev, file_id, direction):
1316
revs = log.calculate_view_revisions(
1079
revs = self.applyDeprecated(
1080
symbol_versioning.deprecated_in((2, 2, 0)),
1081
log.calculate_view_revisions,
1318
1083
start_rev, # start_revision
1319
1084
end_rev, # end_revision
1320
1085
direction, # direction
1501
1275
class TestLogFormatter(tests.TestCase):
1278
super(TestLogFormatter, self).setUp()
1279
self.rev = revision.Revision('a-id')
1280
self.lf = log.LogFormatter(None)
1503
1282
def test_short_committer(self):
1504
rev = revision.Revision('a-id')
1505
rev.committer = 'John Doe <jdoe@example.com>'
1506
lf = log.LogFormatter(None)
1507
self.assertEqual('John Doe', lf.short_committer(rev))
1508
rev.committer = 'John Smith <jsmith@example.com>'
1509
self.assertEqual('John Smith', lf.short_committer(rev))
1510
rev.committer = 'John Smith'
1511
self.assertEqual('John Smith', lf.short_committer(rev))
1512
rev.committer = 'jsmith@example.com'
1513
self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1514
rev.committer = '<jsmith@example.com>'
1515
self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1516
rev.committer = 'John Smith jsmith@example.com'
1517
self.assertEqual('John Smith', lf.short_committer(rev))
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')
1519
1294
def test_short_author(self):
1520
rev = revision.Revision('a-id')
1521
rev.committer = 'John Doe <jdoe@example.com>'
1522
lf = log.LogFormatter(None)
1523
self.assertEqual('John Doe', lf.short_author(rev))
1524
rev.properties['author'] = 'John Smith <jsmith@example.com>'
1525
self.assertEqual('John Smith', lf.short_author(rev))
1526
rev.properties['author'] = 'John Smith'
1527
self.assertEqual('John Smith', lf.short_author(rev))
1528
rev.properties['author'] = 'jsmith@example.com'
1529
self.assertEqual('jsmith@example.com', lf.short_author(rev))
1530
rev.properties['author'] = '<jsmith@example.com>'
1531
self.assertEqual('jsmith@example.com', lf.short_author(rev))
1532
rev.properties['author'] = 'John Smith jsmith@example.com'
1533
self.assertEqual('John Smith', lf.short_author(rev))
1534
del rev.properties['author']
1535
rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1536
'Jane Rey <jrey@example.com>')
1537
self.assertEqual('John Smith', lf.short_author(rev))
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))
1540
1315
class TestReverseByDepth(tests.TestCase):
1686
1461
log.show_branch_change(tree.branch, s, 3, '3b')
1687
1462
self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1688
1463
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')
1547
class TestLogForAuthors(TestCaseForLogFormatter):
1550
TestCaseForLogFormatter.setUp(self)
1551
self.wt = self.make_standard_commit('nicky',
1552
authors=['John Doe <jdoe@example.com>',
1553
'Jane Rey <jrey@example.com>'])
1555
def assertFormatterResult(self, formatter, who, result):
1556
formatter_kwargs = dict()
1558
author_list_handler = log.author_list_registry.get(who)
1559
formatter_kwargs['author_list_handler'] = author_list_handler
1560
TestCaseForLogFormatter.assertFormatterResult(self, result,
1561
self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1563
def test_line_default(self):
1564
self.assertFormatterResult(log.LineLogFormatter, None, """\
1565
1: John Doe 2005-11-22 add a
1568
def test_line_committer(self):
1569
self.assertFormatterResult(log.LineLogFormatter, 'committer', """\
1570
1: Lorem Ipsum 2005-11-22 add a
1573
def test_line_first(self):
1574
self.assertFormatterResult(log.LineLogFormatter, 'first', """\
1575
1: John Doe 2005-11-22 add a
1578
def test_line_all(self):
1579
self.assertFormatterResult(log.LineLogFormatter, 'all', """\
1580
1: John Doe, Jane Rey 2005-11-22 add a
1584
def test_short_default(self):
1585
self.assertFormatterResult(log.ShortLogFormatter, None, """\
1586
1 John Doe\t2005-11-22
1591
def test_short_committer(self):
1592
self.assertFormatterResult(log.ShortLogFormatter, 'committer', """\
1593
1 Lorem Ipsum\t2005-11-22
1598
def test_short_first(self):
1599
self.assertFormatterResult(log.ShortLogFormatter, 'first', """\
1600
1 John Doe\t2005-11-22
1605
def test_short_all(self):
1606
self.assertFormatterResult(log.ShortLogFormatter, 'all', """\
1607
1 John Doe, Jane Rey\t2005-11-22
1612
def test_long_default(self):
1613
self.assertFormatterResult(log.LongLogFormatter, None, """\
1614
------------------------------------------------------------
1616
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1617
committer: Lorem Ipsum <test@example.com>
1619
timestamp: Tue 2005-11-22 00:00:00 +0000
1624
def test_long_committer(self):
1625
self.assertFormatterResult(log.LongLogFormatter, 'committer', """\
1626
------------------------------------------------------------
1628
committer: Lorem Ipsum <test@example.com>
1630
timestamp: Tue 2005-11-22 00:00:00 +0000
1635
def test_long_first(self):
1636
self.assertFormatterResult(log.LongLogFormatter, 'first', """\
1637
------------------------------------------------------------
1639
author: John Doe <jdoe@example.com>
1640
committer: Lorem Ipsum <test@example.com>
1642
timestamp: Tue 2005-11-22 00:00:00 +0000
1647
def test_long_all(self):
1648
self.assertFormatterResult(log.LongLogFormatter, 'all', """\
1649
------------------------------------------------------------
1651
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1652
committer: Lorem Ipsum <test@example.com>
1654
timestamp: Tue 2005-11-22 00:00:00 +0000
1659
def test_gnu_changelog_default(self):
1660
self.assertFormatterResult(log.GnuChangelogLogFormatter, None, """\
1661
2005-11-22 John Doe <jdoe@example.com>
1667
def test_gnu_changelog_committer(self):
1668
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', """\
1669
2005-11-22 Lorem Ipsum <test@example.com>
1675
def test_gnu_changelog_first(self):
1676
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', """\
1677
2005-11-22 John Doe <jdoe@example.com>
1683
def test_gnu_changelog_all(self):
1684
self.assertFormatterResult(log.GnuChangelogLogFormatter, 'all', """\
1685
2005-11-22 John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1691
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1693
def make_branch_with_alternate_ancestries(self, relpath='.'):
1694
# See test_merge_sorted_exclude_ancestry below for the difference with
1695
# bt.per_branch.test_iter_merge_sorted_revision.
1696
# TestIterMergeSortedRevisionsBushyGraph.
1697
# make_branch_with_alternate_ancestries
1698
# and test_merge_sorted_exclude_ancestry
1699
# See the FIXME in assertLogRevnos too.
1700
builder = branchbuilder.BranchBuilder(self.get_transport(relpath))
1712
builder.start_series()
1713
builder.build_snapshot('1', None, [
1714
('add', ('', 'TREE_ROOT', 'directory', '')),])
1715
builder.build_snapshot('1.1.1', ['1'], [])
1716
builder.build_snapshot('2', ['1'], [])
1717
builder.build_snapshot('1.2.1', ['1.1.1'], [])
1718
builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1719
builder.build_snapshot('3', ['2', '1.1.2'], [])
1720
builder.finish_series()
1721
br = builder.get_branch()
1723
self.addCleanup(br.unlock)
1726
def assertLogRevnos(self, expected_revnos, b, start, end,
1727
exclude_common_ancestry, generate_merge_revisions=True):
1728
# FIXME: the layering in log makes it hard to test intermediate levels,
1729
# I wish adding filters with their parameters were easier...
1731
iter_revs = log._calc_view_revisions(
1732
b, start, end, direction='reverse',
1733
generate_merge_revisions=generate_merge_revisions,
1734
exclude_common_ancestry=exclude_common_ancestry)
1735
self.assertEqual(expected_revnos,
1736
[revid for revid, revno, depth in iter_revs])
1738
def test_merge_sorted_exclude_ancestry(self):
1739
b = self.make_branch_with_alternate_ancestries()
1740
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1741
b, '1', '3', exclude_common_ancestry=False)
1742
# '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1743
# it should be mentioned even if merge_sort order will make it appear
1745
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1746
b, '1.1.1', '3', exclude_common_ancestry=True)
1748
def test_merge_sorted_simple_revnos_exclude_ancestry(self):
1749
b = self.make_branch_with_alternate_ancestries()
1750
self.assertLogRevnos(['3', '2'],
1751
b, '1', '3', exclude_common_ancestry=True,
1752
generate_merge_revisions=False)
1753
self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2'],
1754
b, '1', '3', exclude_common_ancestry=True,
1755
generate_merge_revisions=True)