/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_log.py

  • Committer: Martin
  • Date: 2010-05-25 17:27:52 UTC
  • mfrom: (5254 +trunk)
  • mto: This revision was merged to the branch mainline in revision 5257.
  • Revision ID: gzlist@googlemail.com-20100525172752-amm089xcikv968sw
Merge bzr.dev to unite with similar changes already made

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
1
# Copyright (C) 2005-2010 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
18
18
from cStringIO import StringIO
19
19
 
20
20
from bzrlib import (
 
21
    branchbuilder,
21
22
    errors,
22
23
    log,
23
24
    registry,
24
25
    revision,
25
26
    revisionspec,
 
27
    symbol_versioning,
26
28
    tests,
27
29
    )
28
30
 
29
31
 
30
 
class TestCaseWithoutPropsHandler(tests.TestCaseWithTransport):
 
32
class TestLogMixin(object):
 
33
 
 
34
    def wt_commit(self, wt, message, **kwargs):
 
35
        """Use some mostly fixed values for commits to simplify tests.
 
36
 
 
37
        Tests can use this function to get some commit attributes. The time
 
38
        stamp is incremented at each commit.
 
39
        """
 
40
        if getattr(self, 'timestamp', None) is None:
 
41
            self.timestamp = 1132617600 # Mon 2005-11-22 00:00:00 +0000
 
42
        else:
 
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>')
 
47
 
 
48
        return wt.commit(message, **kwargs)
 
49
 
 
50
 
 
51
class TestCaseForLogFormatter(tests.TestCaseWithTransport, TestLogMixin):
31
52
 
32
53
    def setUp(self):
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
57
        # Use a clean registry for log
40
61
            log.properties_handler_registry = self.properties_handler_registry
41
62
        self.addCleanup(restore)
42
63
 
 
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:
 
68
            formatter_kwargs = {}
 
69
        formatter = formatter_class(to_file=logfile, **formatter_kwargs)
 
70
        if show_log_kwargs is None:
 
71
            show_log_kwargs = {}
 
72
        log.show_log(branch, formatter, **show_log_kwargs)
 
73
        self.assertEqualDiff(result, logfile.getvalue())
 
74
 
 
75
    def make_standard_commit(self, branch_nick, **kwargs):
 
76
        wt = self.make_branch_and_tree('.')
 
77
        wt.lock_write()
 
78
        self.addCleanup(wt.unlock)
 
79
        self.build_tree(['a'])
 
80
        wt.add(['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)
 
85
        return wt
 
86
 
 
87
    def make_commits_with_trailing_newlines(self, wt):
 
88
        """Helper method for LogFormatter tests"""
 
89
        b = wt.branch
 
90
        b.nick = 'test'
 
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')])
 
94
        wt.add('b')
 
95
        self.wt_commit(wt, 'multiline\nlog\nmessage\n', rev_id='a2')
 
96
 
 
97
        self.build_tree_contents([('c', 'just another manic monday\n')])
 
98
        wt.add('c')
 
99
        self.wt_commit(wt, 'single line with trailing newline\n', rev_id='a3')
 
100
        return b
 
101
 
 
102
    def _prepare_tree_with_merges(self, with_tags=False):
 
103
        wt = self.make_branch_and_memory_tree('.')
 
104
        wt.lock_write()
 
105
        self.addCleanup(wt.unlock)
 
106
        wt.add('')
 
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')
 
112
        if with_tags:
 
113
            branch = wt.branch
 
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')
 
118
        return wt
43
119
 
44
120
class LogCatcher(log.LogFormatter):
45
121
    """Pull log messages into a list rather than displaying them.
49
125
    being dependent on the formatting.
50
126
    """
51
127
 
 
128
    supports_merge_revisions = True
52
129
    supports_delta = True
 
130
    supports_diff = True
 
131
    preferred_levels = 0
53
132
 
54
 
    def __init__(self):
55
 
        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)
56
136
        self.revisions = []
57
137
 
58
138
    def log_revision(self, revision):
201
281
        self.checkDelta(logentry.delta, added=['file1', 'file2'])
202
282
 
203
283
 
204
 
def make_commits_with_trailing_newlines(wt):
205
 
    """Helper method for LogFormatter tests"""
206
 
    b = wt.branch
207
 
    b.nick='test'
208
 
    open('a', 'wb').write('hello moto\n')
209
 
    wt.add('a')
210
 
    wt.commit('simple log message', rev_id='a1',
211
 
              timestamp=1132586655.459960938, timezone=-6*3600,
212
 
              committer='Joe Foo <joe@foo.com>')
213
 
    open('b', 'wb').write('goodbye\n')
214
 
    wt.add('b')
215
 
    wt.commit('multiline\nlog\nmessage\n', rev_id='a2',
216
 
              timestamp=1132586842.411175966, timezone=-6*3600,
217
 
              committer='Joe Foo <joe@foo.com>',
218
 
              authors=['Joe Bar <joe@bar.com>'])
219
 
 
220
 
    open('c', 'wb').write('just another manic monday\n')
221
 
    wt.add('c')
222
 
    wt.commit('single line with trailing newline\n', rev_id='a3',
223
 
              timestamp=1132587176.835228920, timezone=-6*3600,
224
 
              committer = 'Joe Foo <joe@foo.com>')
225
 
    return b
226
 
 
227
 
 
228
 
def normalize_log(log):
229
 
    """Replaces the variable lines of logs with fixed lines"""
230
 
    author = 'author: Dolor Sit <test@example.com>'
231
 
    committer = 'committer: Lorem Ipsum <test@example.com>'
232
 
    lines = log.splitlines(True)
233
 
    for idx,line in enumerate(lines):
234
 
        stripped_line = line.lstrip()
235
 
        indent = ' ' * (len(line) - len(stripped_line))
236
 
        if stripped_line.startswith('author:'):
237
 
            lines[idx] = indent + author + '\n'
238
 
        elif stripped_line.startswith('committer:'):
239
 
            lines[idx] = indent + committer + '\n'
240
 
        elif stripped_line.startswith('timestamp:'):
241
 
            lines[idx] = indent + 'timestamp: Just now\n'
242
 
    return ''.join(lines)
243
 
 
244
 
 
245
 
class TestShortLogFormatter(tests.TestCaseWithTransport):
 
284
class TestShortLogFormatter(TestCaseForLogFormatter):
246
285
 
247
286
    def test_trailing_newlines(self):
248
287
        wt = self.make_branch_and_tree('.')
249
 
        b = make_commits_with_trailing_newlines(wt)
250
 
        sio = self.make_utf8_encoded_stringio()
251
 
        lf = log.ShortLogFormatter(to_file=sio)
252
 
        log.show_log(b, lf)
253
 
        self.assertEqualDiff("""\
254
 
    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
255
291
      single line with trailing newline
256
292
 
257
 
    2 Joe Bar\t2005-11-21
 
293
    2 Joe Foo\t2005-11-22
258
294
      multiline
259
295
      log
260
296
      message
261
297
 
262
 
    1 Joe Foo\t2005-11-21
 
298
    1 Joe Foo\t2005-11-22
263
299
      simple log message
264
300
 
265
301
""",
266
 
                             sio.getvalue())
267
 
 
268
 
    def _prepare_tree_with_merges(self, with_tags=False):
269
 
        wt = self.make_branch_and_memory_tree('.')
270
 
        wt.lock_write()
271
 
        self.addCleanup(wt.unlock)
272
 
        wt.add('')
273
 
        wt.commit('rev-1', rev_id='rev-1',
274
 
                  timestamp=1132586655, timezone=36000,
275
 
                  committer='Joe Foo <joe@foo.com>')
276
 
        wt.commit('rev-merged', rev_id='rev-2a',
277
 
                  timestamp=1132586700, timezone=36000,
278
 
                  committer='Joe Foo <joe@foo.com>')
279
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
280
 
        wt.branch.set_last_revision_info(1, 'rev-1')
281
 
        wt.commit('rev-2', rev_id='rev-2b',
282
 
                  timestamp=1132586800, timezone=36000,
283
 
                  committer='Joe Foo <joe@foo.com>')
284
 
        if with_tags:
285
 
            branch = wt.branch
286
 
            branch.tags.set_tag('v0.2', 'rev-2b')
287
 
            wt.commit('rev-3', rev_id='rev-3',
288
 
                      timestamp=1132586900, timezone=36000,
289
 
                      committer='Jane Foo <jane@foo.com>')
290
 
            branch.tags.set_tag('v1.0rc1', 'rev-3')
291
 
            branch.tags.set_tag('v1.0', 'rev-3')
292
 
        return wt
 
302
            b, log.ShortLogFormatter)
293
303
 
294
304
    def test_short_log_with_merges(self):
295
305
        wt = self._prepare_tree_with_merges()
296
 
        logfile = self.make_utf8_encoded_stringio()
297
 
        formatter = log.ShortLogFormatter(to_file=logfile)
298
 
        log.show_log(wt.branch, formatter)
299
 
        self.assertEqualDiff("""\
 
306
        self.assertFormatterResult("""\
300
307
    2 Joe Foo\t2005-11-22 [merge]
301
308
      rev-2
302
309
 
304
311
      rev-1
305
312
 
306
313
""",
307
 
                             logfile.getvalue())
 
314
            wt.branch, log.ShortLogFormatter)
308
315
 
309
316
    def test_short_log_with_merges_and_advice(self):
310
317
        wt = self._prepare_tree_with_merges()
311
 
        logfile = self.make_utf8_encoded_stringio()
312
 
        formatter = log.ShortLogFormatter(to_file=logfile,
313
 
            show_advice=True)
314
 
        log.show_log(wt.branch, formatter)
315
 
        self.assertEqualDiff("""\
 
318
        self.assertFormatterResult("""\
316
319
    2 Joe Foo\t2005-11-22 [merge]
317
320
      rev-2
318
321
 
321
324
 
322
325
Use --include-merges or -n0 to see merged revisions.
323
326
""",
324
 
                             logfile.getvalue())
 
327
            wt.branch, log.ShortLogFormatter,
 
328
            formatter_kwargs=dict(show_advice=True))
325
329
 
326
330
    def test_short_log_with_merges_and_range(self):
327
 
        wt = self.make_branch_and_memory_tree('.')
328
 
        wt.lock_write()
329
 
        self.addCleanup(wt.unlock)
330
 
        wt.add('')
331
 
        wt.commit('rev-1', rev_id='rev-1',
332
 
                  timestamp=1132586655, timezone=36000,
333
 
                  committer='Joe Foo <joe@foo.com>')
334
 
        wt.commit('rev-merged', rev_id='rev-2a',
335
 
                  timestamp=1132586700, timezone=36000,
336
 
                  committer='Joe Foo <joe@foo.com>')
337
 
        wt.branch.set_last_revision_info(1, 'rev-1')
338
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
339
 
        wt.commit('rev-2b', rev_id='rev-2b',
340
 
                  timestamp=1132586800, timezone=36000,
341
 
                  committer='Joe Foo <joe@foo.com>')
342
 
        wt.commit('rev-3a', rev_id='rev-3a',
343
 
                  timestamp=1132586800, timezone=36000,
344
 
                  committer='Joe Foo <joe@foo.com>')
 
331
        wt = self._prepare_tree_with_merges()
 
332
        self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
345
333
        wt.branch.set_last_revision_info(2, 'rev-2b')
346
334
        wt.set_parent_ids(['rev-2b', 'rev-3a'])
347
 
        wt.commit('rev-3b', rev_id='rev-3b',
348
 
                  timestamp=1132586800, timezone=36000,
349
 
                  committer='Joe Foo <joe@foo.com>')
350
 
        logfile = self.make_utf8_encoded_stringio()
351
 
        formatter = log.ShortLogFormatter(to_file=logfile)
352
 
        log.show_log(wt.branch, formatter,
353
 
            start_revision=2, end_revision=3)
354
 
        self.assertEqualDiff("""\
 
335
        self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
 
336
        self.assertFormatterResult("""\
355
337
    3 Joe Foo\t2005-11-22 [merge]
356
338
      rev-3b
357
339
 
358
340
    2 Joe Foo\t2005-11-22 [merge]
359
 
      rev-2b
 
341
      rev-2
360
342
 
361
343
""",
362
 
                             logfile.getvalue())
 
344
            wt.branch, log.ShortLogFormatter,
 
345
            show_log_kwargs=dict(start_revision=2, end_revision=3))
363
346
 
364
347
    def test_short_log_with_tags(self):
365
348
        wt = self._prepare_tree_with_merges(with_tags=True)
366
 
        logfile = self.make_utf8_encoded_stringio()
367
 
        formatter = log.ShortLogFormatter(to_file=logfile)
368
 
        log.show_log(wt.branch, formatter)
369
 
        self.assertEqualDiff("""\
370
 
    3 Jane Foo\t2005-11-22 {v1.0, v1.0rc1}
 
349
        self.assertFormatterResult("""\
 
350
    3 Joe Foo\t2005-11-22 {v1.0, v1.0rc1}
371
351
      rev-3
372
352
 
373
353
    2 Joe Foo\t2005-11-22 {v0.2} [merge]
377
357
      rev-1
378
358
 
379
359
""",
380
 
                             logfile.getvalue())
 
360
            wt.branch, log.ShortLogFormatter)
381
361
 
382
362
    def test_short_log_single_merge_revision(self):
383
 
        wt = self.make_branch_and_memory_tree('.')
384
 
        wt.lock_write()
385
 
        self.addCleanup(wt.unlock)
386
 
        wt.add('')
387
 
        wt.commit('rev-1', rev_id='rev-1',
388
 
                  timestamp=1132586655, timezone=36000,
389
 
                  committer='Joe Foo <joe@foo.com>')
390
 
        wt.commit('rev-merged', rev_id='rev-2a',
391
 
                  timestamp=1132586700, timezone=36000,
392
 
                  committer='Joe Foo <joe@foo.com>')
393
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
394
 
        wt.branch.set_last_revision_info(1, 'rev-1')
395
 
        wt.commit('rev-2', rev_id='rev-2b',
396
 
                  timestamp=1132586800, timezone=36000,
397
 
                  committer='Joe Foo <joe@foo.com>')
398
 
        logfile = self.make_utf8_encoded_stringio()
399
 
        formatter = log.ShortLogFormatter(to_file=logfile)
 
363
        wt = self._prepare_tree_with_merges()
400
364
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
401
 
        wtb = wt.branch
402
 
        rev = revspec.in_history(wtb)
403
 
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
404
 
        self.assertEqualDiff("""\
 
365
        rev = revspec.in_history(wt.branch)
 
366
        self.assertFormatterResult("""\
405
367
      1.1.1 Joe Foo\t2005-11-22
406
368
            rev-merged
407
369
 
408
370
""",
409
 
                             logfile.getvalue())
410
 
 
411
 
 
412
 
class TestShortLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
 
371
            wt.branch, log.ShortLogFormatter,
 
372
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
 
373
 
 
374
 
 
375
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
413
376
 
414
377
    def test_short_merge_revs_log_with_merges(self):
415
 
        wt = self.make_branch_and_memory_tree('.')
416
 
        wt.lock_write()
417
 
        self.addCleanup(wt.unlock)
418
 
        wt.add('')
419
 
        wt.commit('rev-1', rev_id='rev-1',
420
 
                  timestamp=1132586655, timezone=36000,
421
 
                  committer='Joe Foo <joe@foo.com>')
422
 
        wt.commit('rev-merged', rev_id='rev-2a',
423
 
                  timestamp=1132586700, timezone=36000,
424
 
                  committer='Joe Foo <joe@foo.com>')
425
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
426
 
        wt.branch.set_last_revision_info(1, 'rev-1')
427
 
        wt.commit('rev-2', rev_id='rev-2b',
428
 
                  timestamp=1132586800, timezone=36000,
429
 
                  committer='Joe Foo <joe@foo.com>')
430
 
        logfile = self.make_utf8_encoded_stringio()
431
 
        formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
432
 
        log.show_log(wt.branch, formatter)
 
378
        wt = self._prepare_tree_with_merges()
433
379
        # Note that the 1.1.1 indenting is in fact correct given that
434
380
        # the revision numbers are right justified within 5 characters
435
381
        # for mainline revnos and 9 characters for dotted revnos.
436
 
        self.assertEqualDiff("""\
 
382
        self.assertFormatterResult("""\
437
383
    2 Joe Foo\t2005-11-22 [merge]
438
384
      rev-2
439
385
 
444
390
      rev-1
445
391
 
446
392
""",
447
 
                             logfile.getvalue())
 
393
            wt.branch, log.ShortLogFormatter,
 
394
            formatter_kwargs=dict(levels=0))
448
395
 
449
396
    def test_short_merge_revs_log_single_merge_revision(self):
450
 
        wt = self.make_branch_and_memory_tree('.')
451
 
        wt.lock_write()
452
 
        self.addCleanup(wt.unlock)
453
 
        wt.add('')
454
 
        wt.commit('rev-1', rev_id='rev-1',
455
 
                  timestamp=1132586655, timezone=36000,
456
 
                  committer='Joe Foo <joe@foo.com>')
457
 
        wt.commit('rev-merged', rev_id='rev-2a',
458
 
                  timestamp=1132586700, timezone=36000,
459
 
                  committer='Joe Foo <joe@foo.com>')
460
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
461
 
        wt.branch.set_last_revision_info(1, 'rev-1')
462
 
        wt.commit('rev-2', rev_id='rev-2b',
463
 
                  timestamp=1132586800, timezone=36000,
464
 
                  committer='Joe Foo <joe@foo.com>')
465
 
        logfile = self.make_utf8_encoded_stringio()
466
 
        formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
 
397
        wt = self._prepare_tree_with_merges()
467
398
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
468
 
        wtb = wt.branch
469
 
        rev = revspec.in_history(wtb)
470
 
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
471
 
        self.assertEqualDiff("""\
 
399
        rev = revspec.in_history(wt.branch)
 
400
        self.assertFormatterResult("""\
472
401
      1.1.1 Joe Foo\t2005-11-22
473
402
            rev-merged
474
403
 
475
404
""",
476
 
                             logfile.getvalue())
477
 
 
478
 
 
479
 
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))
 
408
 
 
409
 
 
410
class TestLongLogFormatter(TestCaseForLogFormatter):
480
411
 
481
412
    def test_verbose_log(self):
482
413
        """Verbose log includes changed files
483
414
 
484
415
        bug #4676
485
416
        """
486
 
        wt = self.make_branch_and_tree('.')
487
 
        b = wt.branch
488
 
        self.build_tree(['a'])
489
 
        wt.add('a')
490
 
        # XXX: why does a longer nick show up?
491
 
        b.nick = 'test_verbose_log'
492
 
        wt.commit(message='add a',
493
 
                  timestamp=1132711707,
494
 
                  timezone=36000,
495
 
                  committer='Lorem Ipsum <test@example.com>')
496
 
        logfile = file('out.tmp', 'w+')
497
 
        formatter = log.LongLogFormatter(to_file=logfile)
498
 
        log.show_log(b, formatter, verbose=True)
499
 
        logfile.flush()
500
 
        logfile.seek(0)
501
 
        log_contents = logfile.read()
502
 
        self.assertEqualDiff('''\
 
417
        wt = self.make_standard_commit('test_verbose_log', authors=[])
 
418
        self.assertFormatterResult('''\
503
419
------------------------------------------------------------
504
420
revno: 1
505
421
committer: Lorem Ipsum <test@example.com>
506
422
branch nick: test_verbose_log
507
 
timestamp: Wed 2005-11-23 12:08:27 +1000
 
423
timestamp: Tue 2005-11-22 00:00:00 +0000
508
424
message:
509
425
  add a
510
426
added:
511
427
  a
512
428
''',
513
 
                             log_contents)
 
429
            wt.branch, log.LongLogFormatter,
 
430
            show_log_kwargs=dict(verbose=True))
514
431
 
515
432
    def test_merges_are_indented_by_level(self):
516
433
        wt = self.make_branch_and_tree('parent')
517
 
        wt.commit('first post')
518
 
        self.run_bzr('branch parent child')
519
 
        self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
520
 
        self.run_bzr('branch child smallerchild')
521
 
        self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
522
 
            'smallerchild'])
523
 
        os.chdir('child')
524
 
        self.run_bzr('merge ../smallerchild')
525
 
        self.run_bzr(['commit', '-m', 'merge branch 2'])
526
 
        os.chdir('../parent')
527
 
        self.run_bzr('merge ../child')
528
 
        wt.commit('merge branch 1')
529
 
        b = wt.branch
530
 
        sio = self.make_utf8_encoded_stringio()
531
 
        lf = log.LongLogFormatter(to_file=sio, levels=0)
532
 
        log.show_log(b, lf, verbose=True)
533
 
        the_log = normalize_log(sio.getvalue())
534
 
        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("""\
535
444
------------------------------------------------------------
536
445
revno: 2 [merge]
537
 
committer: Lorem Ipsum <test@example.com>
 
446
committer: Joe Foo <joe@foo.com>
538
447
branch nick: parent
539
 
timestamp: Just now
 
448
timestamp: Tue 2005-11-22 00:00:04 +0000
540
449
message:
541
450
  merge branch 1
542
451
    ------------------------------------------------------------
543
452
    revno: 1.1.2 [merge]
544
 
    committer: Lorem Ipsum <test@example.com>
 
453
    committer: Joe Foo <joe@foo.com>
545
454
    branch nick: child
546
 
    timestamp: Just now
 
455
    timestamp: Tue 2005-11-22 00:00:03 +0000
547
456
    message:
548
457
      merge branch 2
549
458
        ------------------------------------------------------------
550
459
        revno: 1.2.1
551
 
        committer: Lorem Ipsum <test@example.com>
 
460
        committer: Joe Foo <joe@foo.com>
552
461
        branch nick: smallerchild
553
 
        timestamp: Just now
 
462
        timestamp: Tue 2005-11-22 00:00:02 +0000
554
463
        message:
555
464
          branch 2
556
465
    ------------------------------------------------------------
557
466
    revno: 1.1.1
558
 
    committer: Lorem Ipsum <test@example.com>
 
467
    committer: Joe Foo <joe@foo.com>
559
468
    branch nick: child
560
 
    timestamp: Just now
 
469
    timestamp: Tue 2005-11-22 00:00:01 +0000
561
470
    message:
562
471
      branch 1
563
472
------------------------------------------------------------
564
473
revno: 1
565
 
committer: Lorem Ipsum <test@example.com>
 
474
committer: Joe Foo <joe@foo.com>
566
475
branch nick: parent
567
 
timestamp: Just now
 
476
timestamp: Tue 2005-11-22 00:00:00 +0000
568
477
message:
569
478
  first post
570
479
""",
571
 
                             the_log)
 
480
            wt.branch, log.LongLogFormatter,
 
481
            formatter_kwargs=dict(levels=0),
 
482
            show_log_kwargs=dict(verbose=True))
572
483
 
573
484
    def test_verbose_merge_revisions_contain_deltas(self):
574
485
        wt = self.make_branch_and_tree('parent')
575
486
        self.build_tree(['parent/f1', 'parent/f2'])
576
487
        wt.add(['f1','f2'])
577
 
        wt.commit('first post')
578
 
        self.run_bzr('branch parent child')
 
488
        self.wt_commit(wt, 'first post')
 
489
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
579
490
        os.unlink('child/f1')
580
 
        file('child/f2', 'wb').write('hello\n')
581
 
        self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
582
 
            'child'])
583
 
        os.chdir('parent')
584
 
        self.run_bzr('merge ../child')
585
 
        wt.commit('merge branch 1')
586
 
        b = wt.branch
587
 
        sio = self.make_utf8_encoded_stringio()
588
 
        lf = log.LongLogFormatter(to_file=sio, levels=0)
589
 
        log.show_log(b, lf, verbose=True)
590
 
        the_log = normalize_log(sio.getvalue())
591
 
        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("""\
592
496
------------------------------------------------------------
593
497
revno: 2 [merge]
594
 
committer: Lorem Ipsum <test@example.com>
 
498
committer: Joe Foo <joe@foo.com>
595
499
branch nick: parent
596
 
timestamp: Just now
 
500
timestamp: Tue 2005-11-22 00:00:02 +0000
597
501
message:
598
502
  merge branch 1
599
503
removed:
602
506
  f2
603
507
    ------------------------------------------------------------
604
508
    revno: 1.1.1
605
 
    committer: Lorem Ipsum <test@example.com>
 
509
    committer: Joe Foo <joe@foo.com>
606
510
    branch nick: child
607
 
    timestamp: Just now
 
511
    timestamp: Tue 2005-11-22 00:00:01 +0000
608
512
    message:
609
513
      removed f1 and modified f2
610
514
    removed:
613
517
      f2
614
518
------------------------------------------------------------
615
519
revno: 1
616
 
committer: Lorem Ipsum <test@example.com>
 
520
committer: Joe Foo <joe@foo.com>
617
521
branch nick: parent
618
 
timestamp: Just now
 
522
timestamp: Tue 2005-11-22 00:00:00 +0000
619
523
message:
620
524
  first post
621
525
added:
622
526
  f1
623
527
  f2
624
528
""",
625
 
                             the_log)
 
529
            wt.branch, log.LongLogFormatter,
 
530
            formatter_kwargs=dict(levels=0),
 
531
            show_log_kwargs=dict(verbose=True))
626
532
 
627
533
    def test_trailing_newlines(self):
628
534
        wt = self.make_branch_and_tree('.')
629
 
        b = make_commits_with_trailing_newlines(wt)
630
 
        sio = self.make_utf8_encoded_stringio()
631
 
        lf = log.LongLogFormatter(to_file=sio)
632
 
        log.show_log(b, lf)
633
 
        self.assertEqualDiff("""\
 
535
        b = self.make_commits_with_trailing_newlines(wt)
 
536
        self.assertFormatterResult("""\
634
537
------------------------------------------------------------
635
538
revno: 3
636
539
committer: Joe Foo <joe@foo.com>
637
540
branch nick: test
638
 
timestamp: Mon 2005-11-21 09:32:56 -0600
 
541
timestamp: Tue 2005-11-22 00:00:02 +0000
639
542
message:
640
543
  single line with trailing newline
641
544
------------------------------------------------------------
642
545
revno: 2
643
 
author: Joe Bar <joe@bar.com>
644
546
committer: Joe Foo <joe@foo.com>
645
547
branch nick: test
646
 
timestamp: Mon 2005-11-21 09:27:22 -0600
 
548
timestamp: Tue 2005-11-22 00:00:01 +0000
647
549
message:
648
550
  multiline
649
551
  log
652
554
revno: 1
653
555
committer: Joe Foo <joe@foo.com>
654
556
branch nick: test
655
 
timestamp: Mon 2005-11-21 09:24:15 -0600
 
557
timestamp: Tue 2005-11-22 00:00:00 +0000
656
558
message:
657
559
  simple log message
658
560
""",
659
 
                             sio.getvalue())
 
561
        b, log.LongLogFormatter)
660
562
 
661
563
    def test_author_in_log(self):
662
564
        """Log includes the author name if it's set in
663
565
        the revision properties
664
566
        """
665
 
        wt = self.make_branch_and_tree('.')
666
 
        b = wt.branch
667
 
        self.build_tree(['a'])
668
 
        wt.add('a')
669
 
        b.nick = 'test_author_log'
670
 
        wt.commit(message='add a',
671
 
                  timestamp=1132711707,
672
 
                  timezone=36000,
673
 
                  committer='Lorem Ipsum <test@example.com>',
674
 
                  authors=['John Doe <jdoe@example.com>',
675
 
                           'Jane Rey <jrey@example.com>'])
676
 
        sio = StringIO()
677
 
        formatter = log.LongLogFormatter(to_file=sio)
678
 
        log.show_log(b, formatter)
679
 
        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("""\
680
571
------------------------------------------------------------
681
572
revno: 1
682
573
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
683
574
committer: Lorem Ipsum <test@example.com>
684
575
branch nick: test_author_log
685
 
timestamp: Wed 2005-11-23 12:08:27 +1000
 
576
timestamp: Tue 2005-11-22 00:00:00 +0000
686
577
message:
687
578
  add a
688
 
''',
689
 
                             sio.getvalue())
 
579
""",
 
580
        wt.branch, log.LongLogFormatter)
690
581
 
691
582
    def test_properties_in_log(self):
692
583
        """Log includes the custom properties returned by the registered
693
584
        handlers.
694
585
        """
695
 
        wt = self.make_branch_and_tree('.')
696
 
        b = wt.branch
697
 
        self.build_tree(['a'])
698
 
        wt.add('a')
699
 
        b.nick = 'test_properties_in_log'
700
 
        wt.commit(message='add a',
701
 
                  timestamp=1132711707,
702
 
                  timezone=36000,
703
 
                  committer='Lorem Ipsum <test@example.com>',
704
 
                  authors=['John Doe <jdoe@example.com>'])
705
 
        sio = StringIO()
706
 
        formatter = log.LongLogFormatter(to_file=sio)
707
 
        try:
708
 
            def trivial_custom_prop_handler(revision):
709
 
                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'}
710
589
 
711
 
            log.properties_handler_registry.register(
712
 
                'trivial_custom_prop_handler',
713
 
                trivial_custom_prop_handler)
714
 
            log.show_log(b, formatter)
715
 
        finally:
716
 
            log.properties_handler_registry.remove(
717
 
                'trivial_custom_prop_handler')
718
 
            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("""\
719
595
------------------------------------------------------------
720
596
revno: 1
721
597
test_prop: test_value
722
598
author: John Doe <jdoe@example.com>
723
599
committer: Lorem Ipsum <test@example.com>
724
600
branch nick: test_properties_in_log
725
 
timestamp: Wed 2005-11-23 12:08:27 +1000
 
601
timestamp: Tue 2005-11-22 00:00:00 +0000
726
602
message:
727
603
  add a
728
 
''',
729
 
                                 sio.getvalue())
 
604
""",
 
605
            wt.branch, log.LongLogFormatter)
730
606
 
731
607
    def test_properties_in_short_log(self):
732
608
        """Log includes the custom properties returned by the registered
733
609
        handlers.
734
610
        """
735
 
        wt = self.make_branch_and_tree('.')
736
 
        b = wt.branch
737
 
        self.build_tree(['a'])
738
 
        wt.add('a')
739
 
        b.nick = 'test_properties_in_short_log'
740
 
        wt.commit(message='add a',
741
 
                  timestamp=1132711707,
742
 
                  timezone=36000,
743
 
                  committer='Lorem Ipsum <test@example.com>',
744
 
                  authors=['John Doe <jdoe@example.com>'])
745
 
        sio = StringIO()
746
 
        formatter = log.ShortLogFormatter(to_file=sio)
747
 
        try:
748
 
            def trivial_custom_prop_handler(revision):
749
 
                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'}
750
614
 
751
 
            log.properties_handler_registry.register(
752
 
                'trivial_custom_prop_handler',
753
 
                trivial_custom_prop_handler)
754
 
            log.show_log(b, formatter)
755
 
        finally:
756
 
            log.properties_handler_registry.remove(
757
 
                'trivial_custom_prop_handler')
758
 
            self.assertEqualDiff('''\
759
 
    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
760
620
      test_prop: test_value
761
621
      add a
762
622
 
763
 
''',
764
 
                                 sio.getvalue())
 
623
""",
 
624
            wt.branch, log.ShortLogFormatter)
765
625
 
766
626
    def test_error_in_properties_handler(self):
767
627
        """Log includes the custom properties returned by the registered
768
628
        handlers.
769
629
        """
770
 
        wt = self.make_branch_and_tree('.')
771
 
        b = wt.branch
772
 
        self.build_tree(['a'])
773
 
        wt.add('a')
774
 
        b.nick = 'test_author_log'
775
 
        wt.commit(message='add a',
776
 
                  timestamp=1132711707,
777
 
                  timezone=36000,
778
 
                  committer='Lorem Ipsum <test@example.com>',
779
 
                  authors=['John Doe <jdoe@example.com>'],
780
 
                  revprops={'first_prop':'first_value'})
781
 
        sio = StringIO()
 
630
        wt = self.make_standard_commit('error_in_properties_handler',
 
631
            revprops={'first_prop':'first_value'})
 
632
        sio = self.make_utf8_encoded_stringio()
782
633
        formatter = log.LongLogFormatter(to_file=sio)
783
 
        try:
784
 
            def trivial_custom_prop_handler(revision):
785
 
                raise StandardError("a test error")
 
634
        def trivial_custom_prop_handler(revision):
 
635
            raise StandardError("a test error")
786
636
 
787
 
            log.properties_handler_registry.register(
788
 
                'trivial_custom_prop_handler',
789
 
                trivial_custom_prop_handler)
790
 
            self.assertRaises(StandardError, log.show_log, b, formatter,)
791
 
        finally:
792
 
            log.properties_handler_registry.remove(
793
 
                '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,)
794
641
 
795
642
    def test_properties_handler_bad_argument(self):
796
 
        wt = self.make_branch_and_tree('.')
797
 
        b = wt.branch
798
 
        self.build_tree(['a'])
799
 
        wt.add('a')
800
 
        b.nick = 'test_author_log'
801
 
        wt.commit(message='add a',
802
 
                  timestamp=1132711707,
803
 
                  timezone=36000,
804
 
                  committer='Lorem Ipsum <test@example.com>',
805
 
                  authors=['John Doe <jdoe@example.com>'],
806
 
                  revprops={'a_prop':'test_value'})
807
 
        sio = StringIO()
 
643
        wt = self.make_standard_commit('bad_argument',
 
644
              revprops={'a_prop':'test_value'})
 
645
        sio = self.make_utf8_encoded_stringio()
808
646
        formatter = log.LongLogFormatter(to_file=sio)
809
 
        try:
810
 
            def bad_argument_prop_handler(revision):
811
 
                return {'custom_prop_name':revision.properties['a_prop']}
812
 
 
813
 
            log.properties_handler_registry.register(
814
 
                'bad_argument_prop_handler',
815
 
                bad_argument_prop_handler)
816
 
 
817
 
            self.assertRaises(AttributeError, formatter.show_properties,
818
 
                              'a revision', '')
819
 
 
820
 
            revision = b.repository.get_revision(b.last_revision())
821
 
            formatter.show_properties(revision, '')
822
 
            self.assertEqualDiff('''custom_prop_name: test_value\n''',
823
 
                                 sio.getvalue())
824
 
        finally:
825
 
            log.properties_handler_registry.remove(
826
 
                'bad_argument_prop_handler')
827
 
 
828
 
 
829
 
class TestLongLogFormatterWithoutMergeRevisions(TestCaseWithoutPropsHandler):
 
647
        def bad_argument_prop_handler(revision):
 
648
            return {'custom_prop_name':revision.properties['a_prop']}
 
649
 
 
650
        log.properties_handler_registry.register(
 
651
            'bad_argument_prop_handler',
 
652
            bad_argument_prop_handler)
 
653
 
 
654
        self.assertRaises(AttributeError, formatter.show_properties,
 
655
                          'a revision', '')
 
656
 
 
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''',
 
660
                             sio.getvalue())
 
661
 
 
662
 
 
663
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
830
664
 
831
665
    def test_long_verbose_log(self):
832
666
        """Verbose log includes changed files
833
667
 
834
668
        bug #4676
835
669
        """
836
 
        wt = self.make_branch_and_tree('.')
837
 
        b = wt.branch
838
 
        self.build_tree(['a'])
839
 
        wt.add('a')
840
 
        # XXX: why does a longer nick show up?
841
 
        b.nick = 'test_verbose_log'
842
 
        wt.commit(message='add a',
843
 
                  timestamp=1132711707,
844
 
                  timezone=36000,
845
 
                  committer='Lorem Ipsum <test@example.com>')
846
 
        logfile = file('out.tmp', 'w+')
847
 
        formatter = log.LongLogFormatter(to_file=logfile, levels=1)
848
 
        log.show_log(b, formatter, verbose=True)
849
 
        logfile.flush()
850
 
        logfile.seek(0)
851
 
        log_contents = logfile.read()
852
 
        self.assertEqualDiff('''\
 
670
        wt = self.make_standard_commit('test_long_verbose_log', authors=[])
 
671
        self.assertFormatterResult("""\
853
672
------------------------------------------------------------
854
673
revno: 1
855
674
committer: Lorem Ipsum <test@example.com>
856
 
branch nick: test_verbose_log
857
 
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
858
677
message:
859
678
  add a
860
679
added:
861
680
  a
862
 
''',
863
 
                             log_contents)
 
681
""",
 
682
            wt.branch, log.LongLogFormatter,
 
683
            formatter_kwargs=dict(levels=1),
 
684
            show_log_kwargs=dict(verbose=True))
864
685
 
865
686
    def test_long_verbose_contain_deltas(self):
866
687
        wt = self.make_branch_and_tree('parent')
867
688
        self.build_tree(['parent/f1', 'parent/f2'])
868
689
        wt.add(['f1','f2'])
869
 
        wt.commit('first post')
870
 
        self.run_bzr('branch parent child')
 
690
        self.wt_commit(wt, 'first post')
 
691
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
871
692
        os.unlink('child/f1')
872
 
        file('child/f2', 'wb').write('hello\n')
873
 
        self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
874
 
            'child'])
875
 
        os.chdir('parent')
876
 
        self.run_bzr('merge ../child')
877
 
        wt.commit('merge branch 1')
878
 
        b = wt.branch
879
 
        sio = self.make_utf8_encoded_stringio()
880
 
        lf = log.LongLogFormatter(to_file=sio, levels=1)
881
 
        log.show_log(b, lf, verbose=True)
882
 
        the_log = normalize_log(sio.getvalue())
883
 
        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("""\
884
698
------------------------------------------------------------
885
699
revno: 2 [merge]
886
 
committer: Lorem Ipsum <test@example.com>
 
700
committer: Joe Foo <joe@foo.com>
887
701
branch nick: parent
888
 
timestamp: Just now
 
702
timestamp: Tue 2005-11-22 00:00:02 +0000
889
703
message:
890
704
  merge branch 1
891
705
removed:
894
708
  f2
895
709
------------------------------------------------------------
896
710
revno: 1
897
 
committer: Lorem Ipsum <test@example.com>
 
711
committer: Joe Foo <joe@foo.com>
898
712
branch nick: parent
899
 
timestamp: Just now
 
713
timestamp: Tue 2005-11-22 00:00:00 +0000
900
714
message:
901
715
  first post
902
716
added:
903
717
  f1
904
718
  f2
905
719
""",
906
 
                             the_log)
 
720
            wt.branch, log.LongLogFormatter,
 
721
            formatter_kwargs=dict(levels=1),
 
722
            show_log_kwargs=dict(verbose=True))
907
723
 
908
724
    def test_long_trailing_newlines(self):
909
725
        wt = self.make_branch_and_tree('.')
910
 
        b = make_commits_with_trailing_newlines(wt)
911
 
        sio = self.make_utf8_encoded_stringio()
912
 
        lf = log.LongLogFormatter(to_file=sio, levels=1)
913
 
        log.show_log(b, lf)
914
 
        self.assertEqualDiff("""\
 
726
        b = self.make_commits_with_trailing_newlines(wt)
 
727
        self.assertFormatterResult("""\
915
728
------------------------------------------------------------
916
729
revno: 3
917
730
committer: Joe Foo <joe@foo.com>
918
731
branch nick: test
919
 
timestamp: Mon 2005-11-21 09:32:56 -0600
 
732
timestamp: Tue 2005-11-22 00:00:02 +0000
920
733
message:
921
734
  single line with trailing newline
922
735
------------------------------------------------------------
923
736
revno: 2
924
 
author: Joe Bar <joe@bar.com>
925
737
committer: Joe Foo <joe@foo.com>
926
738
branch nick: test
927
 
timestamp: Mon 2005-11-21 09:27:22 -0600
 
739
timestamp: Tue 2005-11-22 00:00:01 +0000
928
740
message:
929
741
  multiline
930
742
  log
933
745
revno: 1
934
746
committer: Joe Foo <joe@foo.com>
935
747
branch nick: test
936
 
timestamp: Mon 2005-11-21 09:24:15 -0600
 
748
timestamp: Tue 2005-11-22 00:00:00 +0000
937
749
message:
938
750
  simple log message
939
751
""",
940
 
                             sio.getvalue())
 
752
        b, log.LongLogFormatter,
 
753
        formatter_kwargs=dict(levels=1))
941
754
 
942
755
    def test_long_author_in_log(self):
943
756
        """Log includes the author name if it's set in
944
757
        the revision properties
945
758
        """
946
 
        wt = self.make_branch_and_tree('.')
947
 
        b = wt.branch
948
 
        self.build_tree(['a'])
949
 
        wt.add('a')
950
 
        b.nick = 'test_author_log'
951
 
        wt.commit(message='add a',
952
 
                  timestamp=1132711707,
953
 
                  timezone=36000,
954
 
                  committer='Lorem Ipsum <test@example.com>',
955
 
                  authors=['John Doe <jdoe@example.com>'])
956
 
        sio = StringIO()
957
 
        formatter = log.LongLogFormatter(to_file=sio, levels=1)
958
 
        log.show_log(b, formatter)
959
 
        self.assertEqualDiff('''\
 
759
        wt = self.make_standard_commit('test_author_log')
 
760
        self.assertFormatterResult("""\
960
761
------------------------------------------------------------
961
762
revno: 1
962
763
author: John Doe <jdoe@example.com>
963
764
committer: Lorem Ipsum <test@example.com>
964
765
branch nick: test_author_log
965
 
timestamp: Wed 2005-11-23 12:08:27 +1000
 
766
timestamp: Tue 2005-11-22 00:00:00 +0000
966
767
message:
967
768
  add a
968
 
''',
969
 
                             sio.getvalue())
 
769
""",
 
770
            wt.branch, log.LongLogFormatter,
 
771
            formatter_kwargs=dict(levels=1))
970
772
 
971
773
    def test_long_properties_in_log(self):
972
774
        """Log includes the custom properties returned by the registered
973
775
        handlers.
974
776
        """
975
 
        wt = self.make_branch_and_tree('.')
976
 
        b = wt.branch
977
 
        self.build_tree(['a'])
978
 
        wt.add('a')
979
 
        b.nick = 'test_properties_in_log'
980
 
        wt.commit(message='add a',
981
 
                  timestamp=1132711707,
982
 
                  timezone=36000,
983
 
                  committer='Lorem Ipsum <test@example.com>',
984
 
                  authors=['John Doe <jdoe@example.com>'])
985
 
        sio = StringIO()
986
 
        formatter = log.LongLogFormatter(to_file=sio, levels=1)
987
 
        try:
988
 
            def trivial_custom_prop_handler(revision):
989
 
                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'}
990
780
 
991
 
            log.properties_handler_registry.register(
992
 
                'trivial_custom_prop_handler',
993
 
                trivial_custom_prop_handler)
994
 
            log.show_log(b, formatter)
995
 
        finally:
996
 
            log.properties_handler_registry.remove(
997
 
                'trivial_custom_prop_handler')
998
 
            self.assertEqualDiff('''\
 
781
        log.properties_handler_registry.register(
 
782
            'trivial_custom_prop_handler',
 
783
            trivial_custom_prop_handler)
 
784
        self.assertFormatterResult("""\
999
785
------------------------------------------------------------
1000
786
revno: 1
1001
787
test_prop: test_value
1002
788
author: John Doe <jdoe@example.com>
1003
789
committer: Lorem Ipsum <test@example.com>
1004
790
branch nick: test_properties_in_log
1005
 
timestamp: Wed 2005-11-23 12:08:27 +1000
 
791
timestamp: Tue 2005-11-22 00:00:00 +0000
1006
792
message:
1007
793
  add a
1008
 
''',
1009
 
                                 sio.getvalue())
1010
 
 
1011
 
 
1012
 
class TestLineLogFormatter(tests.TestCaseWithTransport):
 
794
""",
 
795
            wt.branch, log.LongLogFormatter,
 
796
            formatter_kwargs=dict(levels=1))
 
797
 
 
798
 
 
799
class TestLineLogFormatter(TestCaseForLogFormatter):
1013
800
 
1014
801
    def test_line_log(self):
1015
802
        """Line log should show revno
1016
803
 
1017
804
        bug #5162
1018
805
        """
1019
 
        wt = self.make_branch_and_tree('.')
1020
 
        b = wt.branch
1021
 
        self.build_tree(['a'])
1022
 
        wt.add('a')
1023
 
        b.nick = 'test-line-log'
1024
 
        wt.commit(message='add a',
1025
 
                  timestamp=1132711707,
1026
 
                  timezone=36000,
1027
 
                  committer='Line-Log-Formatter Tester <test@line.log>')
1028
 
        logfile = file('out.tmp', 'w+')
1029
 
        formatter = log.LineLogFormatter(to_file=logfile)
1030
 
        log.show_log(b, formatter)
1031
 
        logfile.flush()
1032
 
        logfile.seek(0)
1033
 
        log_contents = logfile.read()
1034
 
        self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
1035
 
                             log_contents)
 
806
        wt = self.make_standard_commit('test-line-log',
 
807
                committer='Line-Log-Formatter Tester <test@line.log>',
 
808
                authors=[])
 
809
        self.assertFormatterResult("""\
 
810
1: Line-Log-Formatte... 2005-11-22 add a
 
811
""",
 
812
            wt.branch, log.LineLogFormatter)
1036
813
 
1037
814
    def test_trailing_newlines(self):
1038
815
        wt = self.make_branch_and_tree('.')
1039
 
        b = make_commits_with_trailing_newlines(wt)
1040
 
        sio = self.make_utf8_encoded_stringio()
1041
 
        lf = log.LineLogFormatter(to_file=sio)
1042
 
        log.show_log(b, lf)
1043
 
        self.assertEqualDiff("""\
1044
 
3: Joe Foo 2005-11-21 single line with trailing newline
1045
 
2: Joe Bar 2005-11-21 multiline
1046
 
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
1047
821
""",
1048
 
                             sio.getvalue())
1049
 
 
1050
 
    def _prepare_tree_with_merges(self, with_tags=False):
1051
 
        wt = self.make_branch_and_memory_tree('.')
1052
 
        wt.lock_write()
1053
 
        self.addCleanup(wt.unlock)
1054
 
        wt.add('')
1055
 
        wt.commit('rev-1', rev_id='rev-1',
1056
 
                  timestamp=1132586655, timezone=36000,
1057
 
                  committer='Joe Foo <joe@foo.com>')
1058
 
        wt.commit('rev-merged', rev_id='rev-2a',
1059
 
                  timestamp=1132586700, timezone=36000,
1060
 
                  committer='Joe Foo <joe@foo.com>')
1061
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
1062
 
        wt.branch.set_last_revision_info(1, 'rev-1')
1063
 
        wt.commit('rev-2', rev_id='rev-2b',
1064
 
                  timestamp=1132586800, timezone=36000,
1065
 
                  committer='Joe Foo <joe@foo.com>')
1066
 
        if with_tags:
1067
 
            branch = wt.branch
1068
 
            branch.tags.set_tag('v0.2', 'rev-2b')
1069
 
            wt.commit('rev-3', rev_id='rev-3',
1070
 
                      timestamp=1132586900, timezone=36000,
1071
 
                      committer='Jane Foo <jane@foo.com>')
1072
 
            branch.tags.set_tag('v1.0rc1', 'rev-3')
1073
 
            branch.tags.set_tag('v1.0', 'rev-3')
1074
 
        return wt
 
822
            b, log.LineLogFormatter)
1075
823
 
1076
824
    def test_line_log_single_merge_revision(self):
1077
825
        wt = self._prepare_tree_with_merges()
1078
 
        logfile = self.make_utf8_encoded_stringio()
1079
 
        formatter = log.LineLogFormatter(to_file=logfile)
1080
826
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1081
 
        wtb = wt.branch
1082
 
        rev = revspec.in_history(wtb)
1083
 
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1084
 
        self.assertEqualDiff("""\
 
827
        rev = revspec.in_history(wt.branch)
 
828
        self.assertFormatterResult("""\
1085
829
1.1.1: Joe Foo 2005-11-22 rev-merged
1086
830
""",
1087
 
                             logfile.getvalue())
 
831
            wt.branch, log.LineLogFormatter,
 
832
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1088
833
 
1089
834
    def test_line_log_with_tags(self):
1090
835
        wt = self._prepare_tree_with_merges(with_tags=True)
1091
 
        logfile = self.make_utf8_encoded_stringio()
1092
 
        formatter = log.LineLogFormatter(to_file=logfile)
1093
 
        log.show_log(wt.branch, formatter)
1094
 
        self.assertEqualDiff("""\
1095
 
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
1096
838
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
1097
839
1: Joe Foo 2005-11-22 rev-1
1098
840
""",
1099
 
                             logfile.getvalue())
1100
 
 
1101
 
class TestLineLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
 
841
            wt.branch, log.LineLogFormatter)
 
842
 
 
843
 
 
844
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
1102
845
 
1103
846
    def test_line_merge_revs_log(self):
1104
847
        """Line log should show revno
1105
848
 
1106
849
        bug #5162
1107
850
        """
1108
 
        wt = self.make_branch_and_tree('.')
1109
 
        b = wt.branch
1110
 
        self.build_tree(['a'])
1111
 
        wt.add('a')
1112
 
        b.nick = 'test-line-log'
1113
 
        wt.commit(message='add a',
1114
 
                  timestamp=1132711707,
1115
 
                  timezone=36000,
1116
 
                  committer='Line-Log-Formatter Tester <test@line.log>')
1117
 
        logfile = file('out.tmp', 'w+')
1118
 
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1119
 
        log.show_log(b, formatter)
1120
 
        logfile.flush()
1121
 
        logfile.seek(0)
1122
 
        log_contents = logfile.read()
1123
 
        self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
1124
 
                             log_contents)
 
851
        wt = self.make_standard_commit('test-line-log',
 
852
                committer='Line-Log-Formatter Tester <test@line.log>',
 
853
                authors=[])
 
854
        self.assertFormatterResult("""\
 
855
1: Line-Log-Formatte... 2005-11-22 add a
 
856
""",
 
857
            wt.branch, log.LineLogFormatter)
1125
858
 
1126
859
    def test_line_merge_revs_log_single_merge_revision(self):
1127
 
        wt = self.make_branch_and_memory_tree('.')
1128
 
        wt.lock_write()
1129
 
        self.addCleanup(wt.unlock)
1130
 
        wt.add('')
1131
 
        wt.commit('rev-1', rev_id='rev-1',
1132
 
                  timestamp=1132586655, timezone=36000,
1133
 
                  committer='Joe Foo <joe@foo.com>')
1134
 
        wt.commit('rev-merged', rev_id='rev-2a',
1135
 
                  timestamp=1132586700, timezone=36000,
1136
 
                  committer='Joe Foo <joe@foo.com>')
1137
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
1138
 
        wt.branch.set_last_revision_info(1, 'rev-1')
1139
 
        wt.commit('rev-2', rev_id='rev-2b',
1140
 
                  timestamp=1132586800, timezone=36000,
1141
 
                  committer='Joe Foo <joe@foo.com>')
1142
 
        logfile = self.make_utf8_encoded_stringio()
1143
 
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
 
860
        wt = self._prepare_tree_with_merges()
1144
861
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1145
 
        wtb = wt.branch
1146
 
        rev = revspec.in_history(wtb)
1147
 
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1148
 
        self.assertEqualDiff("""\
 
862
        rev = revspec.in_history(wt.branch)
 
863
        self.assertFormatterResult("""\
1149
864
1.1.1: Joe Foo 2005-11-22 rev-merged
1150
865
""",
1151
 
                             logfile.getvalue())
 
866
            wt.branch, log.LineLogFormatter,
 
867
            formatter_kwargs=dict(levels=0),
 
868
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1152
869
 
1153
870
    def test_line_merge_revs_log_with_merges(self):
1154
 
        wt = self.make_branch_and_memory_tree('.')
1155
 
        wt.lock_write()
1156
 
        self.addCleanup(wt.unlock)
1157
 
        wt.add('')
1158
 
        wt.commit('rev-1', rev_id='rev-1',
1159
 
                  timestamp=1132586655, timezone=36000,
1160
 
                  committer='Joe Foo <joe@foo.com>')
1161
 
        wt.commit('rev-merged', rev_id='rev-2a',
1162
 
                  timestamp=1132586700, timezone=36000,
1163
 
                  committer='Joe Foo <joe@foo.com>')
1164
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
1165
 
        wt.branch.set_last_revision_info(1, 'rev-1')
1166
 
        wt.commit('rev-2', rev_id='rev-2b',
1167
 
                  timestamp=1132586800, timezone=36000,
1168
 
                  committer='Joe Foo <joe@foo.com>')
1169
 
        logfile = self.make_utf8_encoded_stringio()
1170
 
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1171
 
        log.show_log(wt.branch, formatter)
1172
 
        self.assertEqualDiff("""\
 
871
        wt = self._prepare_tree_with_merges()
 
872
        self.assertFormatterResult("""\
1173
873
2: Joe Foo 2005-11-22 [merge] rev-2
1174
874
  1.1.1: Joe Foo 2005-11-22 rev-merged
1175
875
1: Joe Foo 2005-11-22 rev-1
1176
876
""",
1177
 
                             logfile.getvalue())
1178
 
 
1179
 
class TestGetViewRevisions(tests.TestCaseWithTransport):
 
877
            wt.branch, log.LineLogFormatter,
 
878
            formatter_kwargs=dict(levels=0))
 
879
 
 
880
 
 
881
class TestGnuChangelogFormatter(TestCaseForLogFormatter):
 
882
 
 
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>
 
887
 
 
888
\tadd a
 
889
 
 
890
''',
 
891
            wt.branch, log.GnuChangelogLogFormatter)
 
892
 
 
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>
 
899
 
 
900
\tadd a
 
901
 
 
902
''',
 
903
            wt.branch, log.GnuChangelogLogFormatter)
 
904
 
 
905
    def test_verbose(self):
 
906
        wt = self.make_standard_commit('nicky')
 
907
        self.assertFormatterResult('''\
 
908
2005-11-22  John Doe  <jdoe@example.com>
 
909
 
 
910
\t* a:
 
911
 
 
912
\tadd a
 
913
 
 
914
''',
 
915
            wt.branch, log.GnuChangelogLogFormatter,
 
916
            show_log_kwargs=dict(verbose=True))
 
917
 
 
918
class TestGetViewRevisions(tests.TestCaseWithTransport, TestLogMixin):
 
919
 
 
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)
1180
923
 
1181
924
    def make_tree_with_commits(self):
1182
925
        """Create a tree with well-known revision ids"""
1183
926
        wt = self.make_branch_and_tree('tree1')
1184
 
        wt.commit('commit one', rev_id='1')
1185
 
        wt.commit('commit two', rev_id='2')
1186
 
        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')
1187
930
        mainline_revs = [None, '1', '2', '3']
1188
931
        rev_nos = {'1': 1, '2': 2, '3': 3}
1189
932
        return mainline_revs, rev_nos, wt
1192
935
        """Create a tree with well-known revision ids and a merge"""
1193
936
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1194
937
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1195
 
        tree2.commit('four-a', rev_id='4a')
 
938
        self.wt_commit(tree2, 'four-a', rev_id='4a')
1196
939
        wt.merge_from_branch(tree2.branch)
1197
 
        wt.commit('four-b', rev_id='4b')
 
940
        self.wt_commit(wt, 'four-b', rev_id='4b')
1198
941
        mainline_revs.append('4b')
1199
942
        rev_nos['4b'] = 4
1200
943
        # 4a: 3.1.1
1248
991
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1249
992
        wt.lock_read()
1250
993
        self.addCleanup(wt.unlock)
1251
 
        revisions = list(log.get_view_revisions(
 
994
        revisions = list(self._get_view_revisions(
1252
995
                mainline_revs, rev_nos, wt.branch, 'forward'))
1253
996
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
1254
997
                         revisions)
1255
 
        revisions2 = list(log.get_view_revisions(
 
998
        revisions2 = list(self._get_view_revisions(
1256
999
                mainline_revs, rev_nos, wt.branch, 'forward',
1257
1000
                include_merges=False))
1258
1001
        self.assertEqual(revisions, revisions2)
1262
1005
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1263
1006
        wt.lock_read()
1264
1007
        self.addCleanup(wt.unlock)
1265
 
        revisions = list(log.get_view_revisions(
 
1008
        revisions = list(self._get_view_revisions(
1266
1009
                mainline_revs, rev_nos, wt.branch, 'reverse'))
1267
1010
        self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
1268
1011
                         revisions)
1269
 
        revisions2 = list(log.get_view_revisions(
 
1012
        revisions2 = list(self._get_view_revisions(
1270
1013
                mainline_revs, rev_nos, wt.branch, 'reverse',
1271
1014
                include_merges=False))
1272
1015
        self.assertEqual(revisions, revisions2)
1276
1019
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1277
1020
        wt.lock_read()
1278
1021
        self.addCleanup(wt.unlock)
1279
 
        revisions = list(log.get_view_revisions(
 
1022
        revisions = list(self._get_view_revisions(
1280
1023
                mainline_revs, rev_nos, wt.branch, 'forward'))
1281
1024
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1282
1025
                          ('4b', '4', 0), ('4a', '3.1.1', 1)],
1283
1026
                         revisions)
1284
 
        revisions = list(log.get_view_revisions(
 
1027
        revisions = list(self._get_view_revisions(
1285
1028
                mainline_revs, rev_nos, wt.branch, 'forward',
1286
1029
                include_merges=False))
1287
1030
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1293
1036
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1294
1037
        wt.lock_read()
1295
1038
        self.addCleanup(wt.unlock)
1296
 
        revisions = list(log.get_view_revisions(
 
1039
        revisions = list(self._get_view_revisions(
1297
1040
                mainline_revs, rev_nos, wt.branch, 'reverse'))
1298
1041
        self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
1299
1042
                          ('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
1300
1043
                         revisions)
1301
 
        revisions = list(log.get_view_revisions(
 
1044
        revisions = list(self._get_view_revisions(
1302
1045
                mainline_revs, rev_nos, wt.branch, 'reverse',
1303
1046
                include_merges=False))
1304
1047
        self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
1310
1053
        mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1311
1054
        b.lock_read()
1312
1055
        self.addCleanup(b.unlock)
1313
 
        revisions = list(log.get_view_revisions(
 
1056
        revisions = list(self._get_view_revisions(
1314
1057
                mainline_revs, rev_nos, b, 'forward'))
1315
1058
        expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1316
1059
                    ('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1317
1060
                    ('4a', '2.2.2', 1)]
1318
1061
        self.assertEqual(expected, revisions)
1319
 
        revisions = list(log.get_view_revisions(
 
1062
        revisions = list(self._get_view_revisions(
1320
1063
                mainline_revs, rev_nos, b, 'forward',
1321
1064
                include_merges=False))
1322
1065
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1323
1066
                          ('4b', '4', 0)],
1324
1067
                         revisions)
1325
1068
 
1326
 
 
1327
1069
    def test_file_id_for_range(self):
1328
1070
        mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1329
1071
        b.lock_read()
1334
1076
            return revspec.in_history(branch)
1335
1077
 
1336
1078
        def view_revs(start_rev, end_rev, file_id, direction):
1337
 
            revs = log.calculate_view_revisions(
 
1079
            revs = self.applyDeprecated(
 
1080
                symbol_versioning.deprecated_in((2, 2, 0)),
 
1081
                log.calculate_view_revisions,
1338
1082
                b,
1339
1083
                start_rev, # start_revision
1340
1084
                end_rev, # end_revision
1346
1090
 
1347
1091
        rev_3a = rev_from_rev_id('3a', b)
1348
1092
        rev_4b = rev_from_rev_id('4b', b)
1349
 
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1), ('3a', '2.1.1', 2)],
 
1093
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
 
1094
                          ('3a', '2.1.1', 2)],
1350
1095
                          view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
1351
1096
        # Note: 3c still appears before 3a here because of depth-based sorting
1352
 
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1), ('3a', '2.1.1', 2)],
 
1097
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
 
1098
                          ('3a', '2.1.1', 2)],
1353
1099
                          view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1354
1100
 
1355
1101
 
1356
1102
class TestGetRevisionsTouchingFileID(tests.TestCaseWithTransport):
1357
1103
 
 
1104
    def get_view_revisions(self, *args):
 
1105
        return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
 
1106
                                    log.get_view_revisions, *args)
 
1107
 
1358
1108
    def create_tree_with_single_merge(self):
1359
1109
        """Create a branch with a moderate layout.
1360
1110
 
1378
1128
        #       use it. Since 'log' only uses the tree in a readonly
1379
1129
        #       fashion, it seems a shame to regenerate an identical
1380
1130
        #       tree for each test.
 
1131
        # TODO: vila 20100122 One way to address the shame above will be to
 
1132
        #       create a memory tree during test parametrization and give a
 
1133
        #       *copy* of this tree to each test. Copying a memory tree ought
 
1134
        #       to be cheap, at least cheaper than creating them with such
 
1135
        #       complex setups.
1381
1136
        tree = self.make_branch_and_tree('tree')
1382
1137
        tree.lock_write()
1383
1138
        self.addCleanup(tree.unlock)
1458
1213
        mainline = tree.branch.revision_history()
1459
1214
        mainline.insert(0, None)
1460
1215
        revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
1461
 
        view_revs_iter = log.get_view_revisions(mainline, revnos, tree.branch,
1462
 
                                                'reverse', True)
 
1216
        view_revs_iter = self.get_view_revisions(
 
1217
            mainline, revnos, tree.branch, 'reverse', True)
1463
1218
        actual_revs = log._filter_revisions_touching_file_id(
1464
 
                            tree.branch,
1465
 
                            file_id,
1466
 
                            list(view_revs_iter))
 
1219
            tree.branch, file_id, list(view_revs_iter))
1467
1220
        self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
1468
1221
 
1469
1222
    def test_file_id_f1(self):
1521
1274
 
1522
1275
class TestLogFormatter(tests.TestCase):
1523
1276
 
 
1277
    def setUp(self):
 
1278
        super(TestLogFormatter, self).setUp()
 
1279
        self.rev = revision.Revision('a-id')
 
1280
        self.lf = log.LogFormatter(None)
 
1281
 
1524
1282
    def test_short_committer(self):
1525
 
        rev = revision.Revision('a-id')
1526
 
        rev.committer = 'John Doe <jdoe@example.com>'
1527
 
        lf = log.LogFormatter(None)
1528
 
        self.assertEqual('John Doe', lf.short_committer(rev))
1529
 
        rev.committer = 'John Smith <jsmith@example.com>'
1530
 
        self.assertEqual('John Smith', lf.short_committer(rev))
1531
 
        rev.committer = 'John Smith'
1532
 
        self.assertEqual('John Smith', lf.short_committer(rev))
1533
 
        rev.committer = 'jsmith@example.com'
1534
 
        self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1535
 
        rev.committer = '<jsmith@example.com>'
1536
 
        self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1537
 
        rev.committer = 'John Smith jsmith@example.com'
1538
 
        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))
 
1286
 
 
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')
1539
1293
 
1540
1294
    def test_short_author(self):
1541
 
        rev = revision.Revision('a-id')
1542
 
        rev.committer = 'John Doe <jdoe@example.com>'
1543
 
        lf = log.LogFormatter(None)
1544
 
        self.assertEqual('John Doe', lf.short_author(rev))
1545
 
        rev.properties['author'] = 'John Smith <jsmith@example.com>'
1546
 
        self.assertEqual('John Smith', lf.short_author(rev))
1547
 
        rev.properties['author'] = 'John Smith'
1548
 
        self.assertEqual('John Smith', lf.short_author(rev))
1549
 
        rev.properties['author'] = 'jsmith@example.com'
1550
 
        self.assertEqual('jsmith@example.com', lf.short_author(rev))
1551
 
        rev.properties['author'] = '<jsmith@example.com>'
1552
 
        self.assertEqual('jsmith@example.com', lf.short_author(rev))
1553
 
        rev.properties['author'] = 'John Smith jsmith@example.com'
1554
 
        self.assertEqual('John Smith', lf.short_author(rev))
1555
 
        del rev.properties['author']
1556
 
        rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1557
 
                'Jane Rey <jrey@example.com>')
1558
 
        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))
 
1298
 
 
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')
 
1304
 
 
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))
 
1308
 
 
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))
1559
1313
 
1560
1314
 
1561
1315
class TestReverseByDepth(tests.TestCase):
1707
1461
        log.show_branch_change(tree.branch, s, 3, '3b')
1708
1462
        self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1709
1463
        self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
 
1464
 
 
1465
 
 
1466
 
 
1467
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
 
1468
 
 
1469
    def setUp(self):
 
1470
        TestCaseForLogFormatter.setUp(self)
 
1471
        log.properties_handler_registry.register(
 
1472
            'bugs_properties_handler',
 
1473
            log._bugs_properties_handler)
 
1474
 
 
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'])
 
1479
        tree.add('a')
 
1480
        self.wt_commit(tree, 'simple log message', rev_id='a1',
 
1481
                       revprops={'bugs': 'test://bug/id fixed'})
 
1482
        tree.add('b')
 
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'})
 
1487
        return tree
 
1488
 
 
1489
 
 
1490
    def test_long_bugs(self):
 
1491
        tree = self.make_commits_with_bugs()
 
1492
        self.assertFormatterResult("""\
 
1493
------------------------------------------------------------
 
1494
revno: 2
 
1495
fixes bug(s): test://bug/id test://bug/2
 
1496
author: Joe Bar <joe@bar.com>
 
1497
committer: Joe Foo <joe@foo.com>
 
1498
branch nick: work
 
1499
timestamp: Tue 2005-11-22 00:00:01 +0000
 
1500
message:
 
1501
  multiline
 
1502
  log
 
1503
  message
 
1504
------------------------------------------------------------
 
1505
revno: 1
 
1506
fixes bug(s): test://bug/id
 
1507
committer: Joe Foo <joe@foo.com>
 
1508
branch nick: work
 
1509
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1510
message:
 
1511
  simple log message
 
1512
""",
 
1513
            tree.branch, log.LongLogFormatter)
 
1514
 
 
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
 
1520
      multiline
 
1521
      log
 
1522
      message
 
1523
 
 
1524
    1 Joe Foo\t2005-11-22
 
1525
      fixes bug(s): test://bug/id
 
1526
      simple log message
 
1527
 
 
1528
""",
 
1529
            tree.branch, log.ShortLogFormatter)
 
1530
 
 
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
 
1538
      simple log message
 
1539
 
 
1540
""",
 
1541
            tree.branch, log.ShortLogFormatter)
 
1542
 
 
1543
    def test_bugs_handler_present(self):
 
1544
        self.properties_handler_registry.get('bugs_properties_handler')
 
1545
 
 
1546
 
 
1547
class TestLogForAuthors(TestCaseForLogFormatter):
 
1548
 
 
1549
    def setUp(self):
 
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>'])
 
1554
 
 
1555
    def assertFormatterResult(self, formatter, who, result):
 
1556
        formatter_kwargs = dict()
 
1557
        if who is not None:
 
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)
 
1562
 
 
1563
    def test_line_default(self):
 
1564
        self.assertFormatterResult(log.LineLogFormatter, None, """\
 
1565
1: John Doe 2005-11-22 add a
 
1566
""")
 
1567
 
 
1568
    def test_line_committer(self):
 
1569
        self.assertFormatterResult(log.LineLogFormatter, 'committer', """\
 
1570
1: Lorem Ipsum 2005-11-22 add a
 
1571
""")
 
1572
 
 
1573
    def test_line_first(self):
 
1574
        self.assertFormatterResult(log.LineLogFormatter, 'first', """\
 
1575
1: John Doe 2005-11-22 add a
 
1576
""")
 
1577
 
 
1578
    def test_line_all(self):
 
1579
        self.assertFormatterResult(log.LineLogFormatter, 'all', """\
 
1580
1: John Doe, Jane Rey 2005-11-22 add a
 
1581
""")
 
1582
 
 
1583
 
 
1584
    def test_short_default(self):
 
1585
        self.assertFormatterResult(log.ShortLogFormatter, None, """\
 
1586
    1 John Doe\t2005-11-22
 
1587
      add a
 
1588
 
 
1589
""")
 
1590
 
 
1591
    def test_short_committer(self):
 
1592
        self.assertFormatterResult(log.ShortLogFormatter, 'committer', """\
 
1593
    1 Lorem Ipsum\t2005-11-22
 
1594
      add a
 
1595
 
 
1596
""")
 
1597
 
 
1598
    def test_short_first(self):
 
1599
        self.assertFormatterResult(log.ShortLogFormatter, 'first', """\
 
1600
    1 John Doe\t2005-11-22
 
1601
      add a
 
1602
 
 
1603
""")
 
1604
 
 
1605
    def test_short_all(self):
 
1606
        self.assertFormatterResult(log.ShortLogFormatter, 'all', """\
 
1607
    1 John Doe, Jane Rey\t2005-11-22
 
1608
      add a
 
1609
 
 
1610
""")
 
1611
 
 
1612
    def test_long_default(self):
 
1613
        self.assertFormatterResult(log.LongLogFormatter, None, """\
 
1614
------------------------------------------------------------
 
1615
revno: 1
 
1616
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
 
1617
committer: Lorem Ipsum <test@example.com>
 
1618
branch nick: nicky
 
1619
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1620
message:
 
1621
  add a
 
1622
""")
 
1623
 
 
1624
    def test_long_committer(self):
 
1625
        self.assertFormatterResult(log.LongLogFormatter, 'committer', """\
 
1626
------------------------------------------------------------
 
1627
revno: 1
 
1628
committer: Lorem Ipsum <test@example.com>
 
1629
branch nick: nicky
 
1630
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1631
message:
 
1632
  add a
 
1633
""")
 
1634
 
 
1635
    def test_long_first(self):
 
1636
        self.assertFormatterResult(log.LongLogFormatter, 'first', """\
 
1637
------------------------------------------------------------
 
1638
revno: 1
 
1639
author: John Doe <jdoe@example.com>
 
1640
committer: Lorem Ipsum <test@example.com>
 
1641
branch nick: nicky
 
1642
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1643
message:
 
1644
  add a
 
1645
""")
 
1646
 
 
1647
    def test_long_all(self):
 
1648
        self.assertFormatterResult(log.LongLogFormatter, 'all', """\
 
1649
------------------------------------------------------------
 
1650
revno: 1
 
1651
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
 
1652
committer: Lorem Ipsum <test@example.com>
 
1653
branch nick: nicky
 
1654
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1655
message:
 
1656
  add a
 
1657
""")
 
1658
 
 
1659
    def test_gnu_changelog_default(self):
 
1660
        self.assertFormatterResult(log.GnuChangelogLogFormatter, None, """\
 
1661
2005-11-22  John Doe  <jdoe@example.com>
 
1662
 
 
1663
\tadd a
 
1664
 
 
1665
""")
 
1666
 
 
1667
    def test_gnu_changelog_committer(self):
 
1668
        self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', """\
 
1669
2005-11-22  Lorem Ipsum  <test@example.com>
 
1670
 
 
1671
\tadd a
 
1672
 
 
1673
""")
 
1674
 
 
1675
    def test_gnu_changelog_first(self):
 
1676
        self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', """\
 
1677
2005-11-22  John Doe  <jdoe@example.com>
 
1678
 
 
1679
\tadd a
 
1680
 
 
1681
""")
 
1682
 
 
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>
 
1686
 
 
1687
\tadd a
 
1688
 
 
1689
""")
 
1690
 
 
1691
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
 
1692
 
 
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))
 
1701
        # 1
 
1702
        # |\
 
1703
        # 2 \
 
1704
        # |  |
 
1705
        # |  1.1.1
 
1706
        # |  | \
 
1707
        # |  |  1.2.1
 
1708
        # |  | /
 
1709
        # |  1.1.2
 
1710
        # | /
 
1711
        # 3
 
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()
 
1722
        br.lock_read()
 
1723
        self.addCleanup(br.unlock)
 
1724
        return br
 
1725
 
 
1726
    def assertLogRevnos(self, expected_revnos, b, start, end,
 
1727
                        exclude_common_ancestry):
 
1728
        # FIXME: the layering in log makes it hard to test intermediate levels,
 
1729
        # I wish adding filters with their parameters were easier...
 
1730
        # -- vila 20100413
 
1731
        iter_revs = log._calc_view_revisions(
 
1732
            b, start, end, direction='reverse',
 
1733
            generate_merge_revisions=True,
 
1734
            exclude_common_ancestry=exclude_common_ancestry)
 
1735
        self.assertEqual(expected_revnos,
 
1736
                         [revid for revid, revno, depth in iter_revs])
 
1737
 
 
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', 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
 
1744
        # after 1.1.1
 
1745
        self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
 
1746
                             b, '1.1.1', '3', True)
 
1747
 
 
1748