~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_log.py

  • Committer: Andrew Bennetts
  • Date: 2010-01-15 05:30:30 UTC
  • mto: (4973.1.1 integration)
  • mto: This revision was merged to the branch mainline in revision 4975.
  • Revision ID: andrew.bennetts@canonical.com-20100115053030-1d6qd89pnj8hmb55
Pass kinds (not pairs) to MergeHookParams.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
18
from cStringIO import StringIO
27
27
    )
28
28
 
29
29
 
30
 
class TestCaseWithoutPropsHandler(tests.TestCaseWithTransport):
 
30
class TestCaseForLogFormatter(tests.TestCaseWithTransport):
31
31
 
32
32
    def setUp(self):
33
 
        super(TestCaseWithoutPropsHandler, self).setUp()
 
33
        super(TestCaseForLogFormatter, self).setUp()
34
34
        # keep a reference to the "current" custom prop. handler registry
35
35
        self.properties_handler_registry = log.properties_handler_registry
36
 
        # clean up the registry in log
 
36
        # Use a clean registry for log
37
37
        log.properties_handler_registry = registry.Registry()
38
38
 
39
 
    def _cleanup(self):
40
 
        super(TestCaseWithoutPropsHandler, self)._cleanup()
41
 
        # restore the custom properties handler registry
42
 
        log.properties_handler_registry = self.properties_handler_registry
 
39
        def restore():
 
40
            log.properties_handler_registry = self.properties_handler_registry
 
41
        self.addCleanup(restore)
 
42
 
 
43
    def assertFormatterResult(self, result, branch, formatter_class,
 
44
                              formatter_kwargs=None, show_log_kwargs=None,
 
45
                              normalize=False):
 
46
        logfile = self.make_utf8_encoded_stringio()
 
47
        if formatter_kwargs is None:
 
48
            formatter_kwargs = {}
 
49
        formatter = formatter_class(to_file=logfile, **formatter_kwargs)
 
50
        if show_log_kwargs is None:
 
51
            show_log_kwargs = {}
 
52
        log.show_log(branch, formatter, **show_log_kwargs)
 
53
        log_content = logfile.getvalue()
 
54
        if normalize:
 
55
            log_content = normalize_log(log_content)
 
56
        self.assertEqualDiff(result, log_content)
 
57
 
 
58
    def make_standard_commit(self, branch_nick, **kwargs):
 
59
        wt = self.make_branch_and_tree('.')
 
60
        wt.lock_write()
 
61
        self.addCleanup(wt.unlock)
 
62
        self.build_tree(['a'])
 
63
        wt.add(['a'])
 
64
        wt.branch.nick = branch_nick
 
65
        kwargs = dict(kwargs)
 
66
        kwargs.setdefault('message', 'add a')
 
67
        kwargs.setdefault('timestamp', 1132711707)
 
68
        kwargs.setdefault('timezone', 36000)
 
69
        kwargs.setdefault('committer', 'Lorem Ipsum <test@example.com>')
 
70
        kwargs.setdefault('authors', ['John Doe <jdoe@example.com>'])
 
71
        wt.commit(**kwargs)
 
72
        return wt
 
73
 
 
74
    def _prepare_tree_with_merges(self, with_tags=False):
 
75
        wt = self.make_branch_and_memory_tree('.')
 
76
        wt.lock_write()
 
77
        self.addCleanup(wt.unlock)
 
78
        wt.add('')
 
79
        wt.commit('rev-1', rev_id='rev-1',
 
80
                  timestamp=1132586655, timezone=36000,
 
81
                  committer='Joe Foo <joe@foo.com>')
 
82
        wt.commit('rev-merged', rev_id='rev-2a',
 
83
                  timestamp=1132586700, timezone=36000,
 
84
                  committer='Joe Foo <joe@foo.com>')
 
85
        wt.set_parent_ids(['rev-1', 'rev-2a'])
 
86
        wt.branch.set_last_revision_info(1, 'rev-1')
 
87
        wt.commit('rev-2', rev_id='rev-2b',
 
88
                  timestamp=1132586800, timezone=36000,
 
89
                  committer='Joe Foo <joe@foo.com>')
 
90
        if with_tags:
 
91
            branch = wt.branch
 
92
            branch.tags.set_tag('v0.2', 'rev-2b')
 
93
            wt.commit('rev-3', rev_id='rev-3',
 
94
                      timestamp=1132586900, timezone=36000,
 
95
                      committer='Jane Foo <jane@foo.com>')
 
96
            branch.tags.set_tag('v1.0rc1', 'rev-3')
 
97
            branch.tags.set_tag('v1.0', 'rev-3')
 
98
        return wt
 
99
 
 
100
        
43
101
 
44
102
 
45
103
class LogCatcher(log.LogFormatter):
46
 
    """Pull log messages into list rather than displaying them.
47
 
 
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.
51
 
 
52
 
    We should also test the LogFormatter.
 
104
    """Pull log messages into a list rather than displaying them.
 
105
 
 
106
    To simplify testing we save logged revisions here rather than actually
 
107
    formatting anything, so that we can precisely check the result without
 
108
    being dependent on the formatting.
53
109
    """
54
110
 
55
111
    supports_delta = True
56
112
 
57
113
    def __init__(self):
58
114
        super(LogCatcher, self).__init__(to_file=None)
59
 
        self.logs = []
 
115
        self.revisions = []
60
116
 
61
117
    def log_revision(self, revision):
62
 
        self.logs.append(revision)
 
118
        self.revisions.append(revision)
63
119
 
64
120
 
65
121
class TestShowLog(tests.TestCaseWithTransport):
106
162
        lf = LogCatcher()
107
163
        log.show_log(wt.branch, lf)
108
164
        # no entries yet
109
 
        self.assertEqual([], lf.logs)
 
165
        self.assertEqual([], lf.revisions)
110
166
 
111
167
    def test_empty_commit(self):
112
168
        wt = self.make_branch_and_tree('.')
114
170
        wt.commit('empty commit')
115
171
        lf = LogCatcher()
116
172
        log.show_log(wt.branch, lf, verbose=True)
117
 
        self.assertEqual(1, len(lf.logs))
118
 
        self.assertEqual('1', lf.logs[0].revno)
119
 
        self.assertEqual('empty commit', lf.logs[0].rev.message)
120
 
        self.checkDelta(lf.logs[0].delta)
 
173
        revs = lf.revisions
 
174
        self.assertEqual(1, len(revs))
 
175
        self.assertEqual('1', revs[0].revno)
 
176
        self.assertEqual('empty commit', revs[0].rev.message)
 
177
        self.checkDelta(revs[0].delta)
121
178
 
122
179
    def test_simple_commit(self):
123
180
        wt = self.make_branch_and_tree('.')
129
186
                            u'<test@example.com>')
130
187
        lf = LogCatcher()
131
188
        log.show_log(wt.branch, lf, verbose=True)
132
 
        self.assertEqual(2, len(lf.logs))
 
189
        self.assertEqual(2, len(lf.revisions))
133
190
        # first one is most recent
134
 
        log_entry = lf.logs[0]
 
191
        log_entry = lf.revisions[0]
135
192
        self.assertEqual('2', log_entry.revno)
136
193
        self.assertEqual('add one file', log_entry.rev.message)
137
194
        self.checkDelta(log_entry.delta, added=['hello'])
143
200
        wt.commit(msg)
144
201
        lf = LogCatcher()
145
202
        log.show_log(wt.branch, lf, verbose=True)
146
 
        committed_msg = lf.logs[0].rev.message
147
 
        self.assertNotEqual(msg, committed_msg)
148
 
        self.assertTrue(len(committed_msg) > len(msg))
 
203
        committed_msg = lf.revisions[0].rev.message
 
204
        if wt.branch.repository._serializer.squashes_xml_invalid_characters:
 
205
            self.assertNotEqual(msg, committed_msg)
 
206
            self.assertTrue(len(committed_msg) > len(msg))
 
207
        else:
 
208
            self.assertEqual(msg, committed_msg)
149
209
 
150
210
    def test_commit_message_without_control_chars(self):
151
211
        wt = self.make_branch_and_tree('.')
157
217
        wt.commit(msg)
158
218
        lf = LogCatcher()
159
219
        log.show_log(wt.branch, lf, verbose=True)
160
 
        committed_msg = lf.logs[0].rev.message
 
220
        committed_msg = lf.revisions[0].rev.message
161
221
        self.assertEqual(msg, committed_msg)
162
222
 
163
223
    def test_deltas_in_merge_revisions(self):
181
241
        lf.supports_merge_revisions = True
182
242
        log.show_log(b, lf, verbose=True)
183
243
 
184
 
        self.assertEqual(3, len(lf.logs))
 
244
        revs = lf.revisions
 
245
        self.assertEqual(3, len(revs))
185
246
 
186
 
        logentry = lf.logs[0]
 
247
        logentry = revs[0]
187
248
        self.assertEqual('2', logentry.revno)
188
249
        self.assertEqual('merge child branch', logentry.rev.message)
189
250
        self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
190
251
 
191
 
        logentry = lf.logs[1]
 
252
        logentry = revs[1]
192
253
        self.assertEqual('1.1.1', logentry.revno)
193
254
        self.assertEqual('remove file1 and modify file2', logentry.rev.message)
194
255
        self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
195
256
 
196
 
        logentry = lf.logs[2]
 
257
        logentry = revs[2]
197
258
        self.assertEqual('1', logentry.revno)
198
259
        self.assertEqual('add file1 and file2', logentry.rev.message)
199
260
        self.checkDelta(logentry.delta, added=['file1', 'file2'])
200
261
 
201
 
    def test_merges_nonsupporting_formatter(self):
202
 
        """Tests that show_log will raise if the formatter doesn't
203
 
        support merge revisions."""
204
 
        wt = self.make_branch_and_memory_tree('.')
205
 
        wt.lock_write()
206
 
        self.addCleanup(wt.unlock)
207
 
        wt.add('')
208
 
        wt.commit('rev-1', rev_id='rev-1',
209
 
                  timestamp=1132586655, timezone=36000,
210
 
                  committer='Joe Foo <joe@foo.com>')
211
 
        wt.commit('rev-merged', rev_id='rev-2a',
212
 
                  timestamp=1132586700, timezone=36000,
213
 
                  committer='Joe Foo <joe@foo.com>')
214
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
215
 
        wt.branch.set_last_revision_info(1, 'rev-1')
216
 
        wt.commit('rev-2', rev_id='rev-2b',
217
 
                  timestamp=1132586800, timezone=36000,
218
 
                  committer='Joe Foo <joe@foo.com>')
219
 
        logfile = self.make_utf8_encoded_stringio()
220
 
        formatter = log.ShortLogFormatter(to_file=logfile)
221
 
        wtb = wt.branch
222
 
        lf = LogCatcher()
223
 
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
224
 
        rev = revspec.in_history(wtb)
225
 
        self.assertRaises(errors.BzrCommandError, log.show_log, wtb, lf,
226
 
                          start_revision=rev, end_revision=rev)
227
 
 
228
262
 
229
263
def make_commits_with_trailing_newlines(wt):
230
264
    """Helper method for LogFormatter tests"""
240
274
    wt.commit('multiline\nlog\nmessage\n', rev_id='a2',
241
275
              timestamp=1132586842.411175966, timezone=-6*3600,
242
276
              committer='Joe Foo <joe@foo.com>',
243
 
              author='Joe Bar <joe@bar.com>')
 
277
              authors=['Joe Bar <joe@bar.com>'])
244
278
 
245
279
    open('c', 'wb').write('just another manic monday\n')
246
280
    wt.add('c')
267
301
    return ''.join(lines)
268
302
 
269
303
 
270
 
class TestShortLogFormatter(tests.TestCaseWithTransport):
 
304
class TestShortLogFormatter(TestCaseForLogFormatter):
271
305
 
272
306
    def test_trailing_newlines(self):
273
307
        wt = self.make_branch_and_tree('.')
274
308
        b = make_commits_with_trailing_newlines(wt)
275
 
        sio = self.make_utf8_encoded_stringio()
276
 
        lf = log.ShortLogFormatter(to_file=sio)
277
 
        log.show_log(b, lf)
278
 
        self.assertEqualDiff("""\
 
309
        self.assertFormatterResult("""\
279
310
    3 Joe Foo\t2005-11-21
280
311
      single line with trailing newline
281
312
 
288
319
      simple log message
289
320
 
290
321
""",
291
 
                             sio.getvalue())
292
 
 
293
 
    def _prepare_tree_with_merges(self, with_tags=False):
294
 
        wt = self.make_branch_and_memory_tree('.')
295
 
        wt.lock_write()
296
 
        self.addCleanup(wt.unlock)
297
 
        wt.add('')
298
 
        wt.commit('rev-1', rev_id='rev-1',
299
 
                  timestamp=1132586655, timezone=36000,
300
 
                  committer='Joe Foo <joe@foo.com>')
301
 
        wt.commit('rev-merged', rev_id='rev-2a',
302
 
                  timestamp=1132586700, timezone=36000,
303
 
                  committer='Joe Foo <joe@foo.com>')
304
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
305
 
        wt.branch.set_last_revision_info(1, 'rev-1')
306
 
        wt.commit('rev-2', rev_id='rev-2b',
307
 
                  timestamp=1132586800, timezone=36000,
308
 
                  committer='Joe Foo <joe@foo.com>')
309
 
        if with_tags:
310
 
            branch = wt.branch
311
 
            branch.tags.set_tag('v0.2', 'rev-2b')
312
 
            wt.commit('rev-3', rev_id='rev-3',
313
 
                      timestamp=1132586900, timezone=36000,
314
 
                      committer='Jane Foo <jane@foo.com>')
315
 
            branch.tags.set_tag('v1.0rc1', 'rev-3')
316
 
            branch.tags.set_tag('v1.0', 'rev-3')
317
 
        return wt
 
322
            b, log.ShortLogFormatter)
318
323
 
319
324
    def test_short_log_with_merges(self):
320
325
        wt = self._prepare_tree_with_merges()
321
 
        logfile = self.make_utf8_encoded_stringio()
322
 
        formatter = log.ShortLogFormatter(to_file=logfile)
323
 
        log.show_log(wt.branch, formatter)
324
 
        self.assertEqualDiff("""\
325
 
    2 Joe Foo\t2005-11-22 [merge]
326
 
      rev-2
327
 
 
328
 
    1 Joe Foo\t2005-11-22
329
 
      rev-1
330
 
 
331
 
""",
332
 
                             logfile.getvalue())
 
326
        self.assertFormatterResult("""\
 
327
    2 Joe Foo\t2005-11-22 [merge]
 
328
      rev-2
 
329
 
 
330
    1 Joe Foo\t2005-11-22
 
331
      rev-1
 
332
 
 
333
""",
 
334
            wt.branch, log.ShortLogFormatter)
 
335
 
 
336
    def test_short_log_with_merges_and_advice(self):
 
337
        wt = self._prepare_tree_with_merges()
 
338
        self.assertFormatterResult("""\
 
339
    2 Joe Foo\t2005-11-22 [merge]
 
340
      rev-2
 
341
 
 
342
    1 Joe Foo\t2005-11-22
 
343
      rev-1
 
344
 
 
345
Use --include-merges or -n0 to see merged revisions.
 
346
""",
 
347
            wt.branch, log.ShortLogFormatter,
 
348
            formatter_kwargs=dict(show_advice=True))
333
349
 
334
350
    def test_short_log_with_merges_and_range(self):
335
351
        wt = self.make_branch_and_memory_tree('.')
355
371
        wt.commit('rev-3b', rev_id='rev-3b',
356
372
                  timestamp=1132586800, timezone=36000,
357
373
                  committer='Joe Foo <joe@foo.com>')
358
 
        logfile = self.make_utf8_encoded_stringio()
359
 
        formatter = log.ShortLogFormatter(to_file=logfile)
360
 
        log.show_log(wt.branch, formatter,
361
 
            start_revision=2, end_revision=3)
362
 
        self.assertEqualDiff("""\
 
374
        self.assertFormatterResult("""\
363
375
    3 Joe Foo\t2005-11-22 [merge]
364
376
      rev-3b
365
377
 
367
379
      rev-2b
368
380
 
369
381
""",
370
 
                             logfile.getvalue())
 
382
            wt.branch, log.ShortLogFormatter,
 
383
            show_log_kwargs=dict(start_revision=2, end_revision=3))
371
384
 
372
385
    def test_short_log_with_tags(self):
373
386
        wt = self._prepare_tree_with_merges(with_tags=True)
374
 
        logfile = self.make_utf8_encoded_stringio()
375
 
        formatter = log.ShortLogFormatter(to_file=logfile)
376
 
        log.show_log(wt.branch, formatter)
377
 
        self.assertEqualDiff("""\
 
387
        self.assertFormatterResult("""\
378
388
    3 Jane Foo\t2005-11-22 {v1.0, v1.0rc1}
379
389
      rev-3
380
390
 
385
395
      rev-1
386
396
 
387
397
""",
388
 
                             logfile.getvalue())
 
398
            wt.branch, log.ShortLogFormatter)
389
399
 
390
400
    def test_short_log_single_merge_revision(self):
391
401
        wt = self.make_branch_and_memory_tree('.')
403
413
        wt.commit('rev-2', rev_id='rev-2b',
404
414
                  timestamp=1132586800, timezone=36000,
405
415
                  committer='Joe Foo <joe@foo.com>')
406
 
        logfile = self.make_utf8_encoded_stringio()
407
 
        formatter = log.ShortLogFormatter(to_file=logfile)
408
416
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
409
 
        wtb = wt.branch
410
 
        rev = revspec.in_history(wtb)
411
 
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
412
 
        self.assertEqualDiff("""\
 
417
        rev = revspec.in_history(wt.branch)
 
418
        self.assertFormatterResult("""\
413
419
      1.1.1 Joe Foo\t2005-11-22
414
420
            rev-merged
415
421
 
416
422
""",
417
 
                             logfile.getvalue())
418
 
 
419
 
 
420
 
class TestShortLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
 
423
            wt.branch, log.ShortLogFormatter,
 
424
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
 
425
 
 
426
 
 
427
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
421
428
 
422
429
    def test_short_merge_revs_log_with_merges(self):
423
430
        wt = self.make_branch_and_memory_tree('.')
435
442
        wt.commit('rev-2', rev_id='rev-2b',
436
443
                  timestamp=1132586800, timezone=36000,
437
444
                  committer='Joe Foo <joe@foo.com>')
438
 
        logfile = self.make_utf8_encoded_stringio()
439
 
        formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
440
 
        log.show_log(wt.branch, formatter)
441
445
        # Note that the 1.1.1 indenting is in fact correct given that
442
446
        # the revision numbers are right justified within 5 characters
443
447
        # for mainline revnos and 9 characters for dotted revnos.
444
 
        self.assertEqualDiff("""\
 
448
        self.assertFormatterResult("""\
445
449
    2 Joe Foo\t2005-11-22 [merge]
446
450
      rev-2
447
451
 
452
456
      rev-1
453
457
 
454
458
""",
455
 
                             logfile.getvalue())
 
459
            wt.branch, log.ShortLogFormatter,
 
460
            formatter_kwargs=dict(levels=0))
456
461
 
457
462
    def test_short_merge_revs_log_single_merge_revision(self):
458
463
        wt = self.make_branch_and_memory_tree('.')
470
475
        wt.commit('rev-2', rev_id='rev-2b',
471
476
                  timestamp=1132586800, timezone=36000,
472
477
                  committer='Joe Foo <joe@foo.com>')
473
 
        logfile = self.make_utf8_encoded_stringio()
474
 
        formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
475
478
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
476
 
        wtb = wt.branch
477
 
        rev = revspec.in_history(wtb)
478
 
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
479
 
        self.assertEqualDiff("""\
 
479
        rev = revspec.in_history(wt.branch)
 
480
        self.assertFormatterResult("""\
480
481
      1.1.1 Joe Foo\t2005-11-22
481
482
            rev-merged
482
483
 
483
484
""",
484
 
                             logfile.getvalue())
485
 
 
486
 
 
487
 
class TestLongLogFormatter(TestCaseWithoutPropsHandler):
 
485
            wt.branch, log.ShortLogFormatter,
 
486
            formatter_kwargs=dict(levels=0),
 
487
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
 
488
 
 
489
 
 
490
class TestLongLogFormatter(TestCaseForLogFormatter):
488
491
 
489
492
    def test_verbose_log(self):
490
493
        """Verbose log includes changed files
491
 
        
 
494
 
492
495
        bug #4676
493
496
        """
494
 
        wt = self.make_branch_and_tree('.')
495
 
        b = wt.branch
496
 
        self.build_tree(['a'])
497
 
        wt.add('a')
498
 
        # XXX: why does a longer nick show up?
499
 
        b.nick = 'test_verbose_log'
500
 
        wt.commit(message='add a',
501
 
                  timestamp=1132711707,
502
 
                  timezone=36000,
503
 
                  committer='Lorem Ipsum <test@example.com>')
504
 
        logfile = file('out.tmp', 'w+')
505
 
        formatter = log.LongLogFormatter(to_file=logfile)
506
 
        log.show_log(b, formatter, verbose=True)
507
 
        logfile.flush()
508
 
        logfile.seek(0)
509
 
        log_contents = logfile.read()
510
 
        self.assertEqualDiff('''\
 
497
        wt = self.make_standard_commit('test_verbose_log', authors=[])
 
498
        self.assertFormatterResult('''\
511
499
------------------------------------------------------------
512
500
revno: 1
513
501
committer: Lorem Ipsum <test@example.com>
518
506
added:
519
507
  a
520
508
''',
521
 
                             log_contents)
 
509
            wt.branch, log.LongLogFormatter,
 
510
            show_log_kwargs=dict(verbose=True))
522
511
 
523
512
    def test_merges_are_indented_by_level(self):
524
513
        wt = self.make_branch_and_tree('parent')
534
523
        os.chdir('../parent')
535
524
        self.run_bzr('merge ../child')
536
525
        wt.commit('merge branch 1')
537
 
        b = wt.branch
538
 
        sio = self.make_utf8_encoded_stringio()
539
 
        lf = log.LongLogFormatter(to_file=sio)
540
 
        log.show_log(b, lf, verbose=True)
541
 
        the_log = normalize_log(sio.getvalue())
542
 
        self.assertEqualDiff("""\
 
526
        self.assertFormatterResult("""\
543
527
------------------------------------------------------------
544
 
revno: 2
 
528
revno: 2 [merge]
545
529
committer: Lorem Ipsum <test@example.com>
546
530
branch nick: parent
547
531
timestamp: Just now
548
532
message:
549
533
  merge branch 1
550
534
    ------------------------------------------------------------
551
 
    revno: 1.1.2
 
535
    revno: 1.1.2 [merge]
552
536
    committer: Lorem Ipsum <test@example.com>
553
537
    branch nick: child
554
538
    timestamp: Just now
576
560
message:
577
561
  first post
578
562
""",
579
 
                             the_log)
 
563
            wt.branch, log.LongLogFormatter,
 
564
            formatter_kwargs=dict(levels=0),
 
565
            show_log_kwargs=dict(verbose=True),
 
566
            normalize=True)
580
567
 
581
568
    def test_verbose_merge_revisions_contain_deltas(self):
582
569
        wt = self.make_branch_and_tree('parent')
591
578
        os.chdir('parent')
592
579
        self.run_bzr('merge ../child')
593
580
        wt.commit('merge branch 1')
594
 
        b = wt.branch
595
 
        sio = self.make_utf8_encoded_stringio()
596
 
        lf = log.LongLogFormatter(to_file=sio)
597
 
        log.show_log(b, lf, verbose=True)
598
 
        the_log = normalize_log(sio.getvalue())
599
 
        self.assertEqualDiff("""\
 
581
        self.assertFormatterResult("""\
600
582
------------------------------------------------------------
601
 
revno: 2
 
583
revno: 2 [merge]
602
584
committer: Lorem Ipsum <test@example.com>
603
585
branch nick: parent
604
586
timestamp: Just now
630
612
  f1
631
613
  f2
632
614
""",
633
 
                             the_log)
 
615
            wt.branch, log.LongLogFormatter,
 
616
            formatter_kwargs=dict(levels=0),
 
617
            show_log_kwargs=dict(verbose=True),
 
618
            normalize=True)
634
619
 
635
620
    def test_trailing_newlines(self):
636
621
        wt = self.make_branch_and_tree('.')
637
622
        b = make_commits_with_trailing_newlines(wt)
638
 
        sio = self.make_utf8_encoded_stringio()
639
 
        lf = log.LongLogFormatter(to_file=sio)
640
 
        log.show_log(b, lf)
641
 
        self.assertEqualDiff("""\
 
623
        self.assertFormatterResult("""\
642
624
------------------------------------------------------------
643
625
revno: 3
644
626
committer: Joe Foo <joe@foo.com>
664
646
message:
665
647
  simple log message
666
648
""",
667
 
                             sio.getvalue())
 
649
        b, log.LongLogFormatter)
668
650
 
669
651
    def test_author_in_log(self):
670
652
        """Log includes the author name if it's set in
671
653
        the revision properties
672
654
        """
673
 
        wt = self.make_branch_and_tree('.')
674
 
        b = wt.branch
675
 
        self.build_tree(['a'])
676
 
        wt.add('a')
677
 
        b.nick = 'test_author_log'
678
 
        wt.commit(message='add a',
679
 
                  timestamp=1132711707,
680
 
                  timezone=36000,
681
 
                  committer='Lorem Ipsum <test@example.com>',
682
 
                  author='John Doe <jdoe@example.com>')
683
 
        sio = StringIO()
684
 
        formatter = log.LongLogFormatter(to_file=sio)
685
 
        log.show_log(b, formatter)
686
 
        self.assertEqualDiff('''\
 
655
        wt = self.make_standard_commit('test_author_log',
 
656
            authors=['John Doe <jdoe@example.com>',
 
657
                     'Jane Rey <jrey@example.com>'])
 
658
        self.assertFormatterResult("""\
687
659
------------------------------------------------------------
688
660
revno: 1
689
 
author: John Doe <jdoe@example.com>
 
661
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
690
662
committer: Lorem Ipsum <test@example.com>
691
663
branch nick: test_author_log
692
664
timestamp: Wed 2005-11-23 12:08:27 +1000
693
665
message:
694
666
  add a
695
 
''',
696
 
                             sio.getvalue())
 
667
""",
 
668
        wt.branch, log.LongLogFormatter)
697
669
 
698
670
    def test_properties_in_log(self):
699
 
        """Log includes the custom properties returned by the registered 
 
671
        """Log includes the custom properties returned by the registered
700
672
        handlers.
701
673
        """
702
 
        wt = self.make_branch_and_tree('.')
703
 
        b = wt.branch
704
 
        self.build_tree(['a'])
705
 
        wt.add('a')
706
 
        b.nick = 'test_properties_in_log'
707
 
        wt.commit(message='add a',
708
 
                  timestamp=1132711707,
709
 
                  timezone=36000,
710
 
                  committer='Lorem Ipsum <test@example.com>',
711
 
                  author='John Doe <jdoe@example.com>')
712
 
        sio = StringIO()
713
 
        formatter = log.LongLogFormatter(to_file=sio)
714
 
        try:
715
 
            def trivial_custom_prop_handler(revision):
716
 
                return {'test_prop':'test_value'}
 
674
        wt = self.make_standard_commit('test_properties_in_log')
 
675
        def trivial_custom_prop_handler(revision):
 
676
            return {'test_prop':'test_value'}
717
677
 
718
 
            log.properties_handler_registry.register(
719
 
                'trivial_custom_prop_handler',
720
 
                trivial_custom_prop_handler)
721
 
            log.show_log(b, formatter)
722
 
        finally:
723
 
            log.properties_handler_registry.remove(
724
 
                'trivial_custom_prop_handler')
725
 
            self.assertEqualDiff('''\
 
678
        # Cleaned up in setUp()
 
679
        log.properties_handler_registry.register(
 
680
            'trivial_custom_prop_handler',
 
681
            trivial_custom_prop_handler)
 
682
        self.assertFormatterResult("""\
726
683
------------------------------------------------------------
727
684
revno: 1
728
685
test_prop: test_value
732
689
timestamp: Wed 2005-11-23 12:08:27 +1000
733
690
message:
734
691
  add a
735
 
''',
736
 
                                 sio.getvalue())
 
692
""",
 
693
            wt.branch, log.LongLogFormatter)
737
694
 
738
695
    def test_properties_in_short_log(self):
739
 
        """Log includes the custom properties returned by the registered 
 
696
        """Log includes the custom properties returned by the registered
740
697
        handlers.
741
698
        """
742
 
        wt = self.make_branch_and_tree('.')
743
 
        b = wt.branch
744
 
        self.build_tree(['a'])
745
 
        wt.add('a')
746
 
        b.nick = 'test_properties_in_short_log'
747
 
        wt.commit(message='add a',
748
 
                  timestamp=1132711707,
749
 
                  timezone=36000,
750
 
                  committer='Lorem Ipsum <test@example.com>',
751
 
                  author='John Doe <jdoe@example.com>')
752
 
        sio = StringIO()
753
 
        formatter = log.ShortLogFormatter(to_file=sio)
754
 
        try:
755
 
            def trivial_custom_prop_handler(revision):
756
 
                return {'test_prop':'test_value'}
 
699
        wt = self.make_standard_commit('test_properties_in_short_log')
 
700
        def trivial_custom_prop_handler(revision):
 
701
            return {'test_prop':'test_value'}
757
702
 
758
 
            log.properties_handler_registry.register(
759
 
                'trivial_custom_prop_handler',
760
 
                trivial_custom_prop_handler)
761
 
            log.show_log(b, formatter)
762
 
        finally:
763
 
            log.properties_handler_registry.remove(
764
 
                'trivial_custom_prop_handler')
765
 
            self.assertEqualDiff('''\
 
703
        log.properties_handler_registry.register(
 
704
            'trivial_custom_prop_handler',
 
705
            trivial_custom_prop_handler)
 
706
        self.assertFormatterResult("""\
766
707
    1 John Doe\t2005-11-23
767
708
      test_prop: test_value
768
709
      add a
769
710
 
770
 
''',
771
 
                                 sio.getvalue())
 
711
""",
 
712
            wt.branch, log.ShortLogFormatter)
772
713
 
773
714
    def test_error_in_properties_handler(self):
774
 
        """Log includes the custom properties returned by the registered 
 
715
        """Log includes the custom properties returned by the registered
775
716
        handlers.
776
717
        """
777
 
        wt = self.make_branch_and_tree('.')
778
 
        b = wt.branch
779
 
        self.build_tree(['a'])
780
 
        wt.add('a')
781
 
        b.nick = 'test_author_log'
782
 
        wt.commit(message='add a',
783
 
                  timestamp=1132711707,
784
 
                  timezone=36000,
785
 
                  committer='Lorem Ipsum <test@example.com>',
786
 
                  author='John Doe <jdoe@example.com>',
787
 
                  revprops={'first_prop':'first_value'})
788
 
        sio = StringIO()
 
718
        wt = self.make_standard_commit('error_in_properties_handler',
 
719
            revprops={'first_prop':'first_value'})
 
720
        sio = self.make_utf8_encoded_stringio()
789
721
        formatter = log.LongLogFormatter(to_file=sio)
790
 
        try:
791
 
            def trivial_custom_prop_handler(revision):
792
 
                raise StandardError("a test error")
 
722
        def trivial_custom_prop_handler(revision):
 
723
            raise StandardError("a test error")
793
724
 
794
 
            log.properties_handler_registry.register(
795
 
                'trivial_custom_prop_handler',
796
 
                trivial_custom_prop_handler)
797
 
            self.assertRaises(StandardError, log.show_log, b, formatter,)
798
 
        finally:
799
 
            log.properties_handler_registry.remove(
800
 
                'trivial_custom_prop_handler')
 
725
        log.properties_handler_registry.register(
 
726
            'trivial_custom_prop_handler',
 
727
            trivial_custom_prop_handler)
 
728
        self.assertRaises(StandardError, log.show_log, wt.branch, formatter,)
801
729
 
802
730
    def test_properties_handler_bad_argument(self):
803
 
        wt = self.make_branch_and_tree('.')
804
 
        b = wt.branch
805
 
        self.build_tree(['a'])
806
 
        wt.add('a')
807
 
        b.nick = 'test_author_log'
808
 
        wt.commit(message='add a',
809
 
                  timestamp=1132711707,
810
 
                  timezone=36000,
811
 
                  committer='Lorem Ipsum <test@example.com>',
812
 
                  author='John Doe <jdoe@example.com>',
813
 
                  revprops={'a_prop':'test_value'})
814
 
        sio = StringIO()
 
731
        wt = self.make_standard_commit('bad_argument',
 
732
              revprops={'a_prop':'test_value'})
 
733
        sio = self.make_utf8_encoded_stringio()
815
734
        formatter = log.LongLogFormatter(to_file=sio)
816
 
        try:
817
 
            def bad_argument_prop_handler(revision):
818
 
                return {'custom_prop_name':revision.properties['a_prop']}
819
 
 
820
 
            log.properties_handler_registry.register(
821
 
                'bad_argument_prop_handler',
822
 
                bad_argument_prop_handler)
823
 
 
824
 
            self.assertRaises(AttributeError, formatter.show_properties,
825
 
                              'a revision', '')
826
 
 
827
 
            revision = b.repository.get_revision(b.last_revision())
828
 
            formatter.show_properties(revision, '')
829
 
            self.assertEqualDiff('''custom_prop_name: test_value\n''',
830
 
                                 sio.getvalue())
831
 
        finally:
832
 
            log.properties_handler_registry.remove(
833
 
                'bad_argument_prop_handler')
834
 
 
835
 
 
836
 
class TestLongLogFormatterWithoutMergeRevisions(TestCaseWithoutPropsHandler):
 
735
        def bad_argument_prop_handler(revision):
 
736
            return {'custom_prop_name':revision.properties['a_prop']}
 
737
 
 
738
        log.properties_handler_registry.register(
 
739
            'bad_argument_prop_handler',
 
740
            bad_argument_prop_handler)
 
741
 
 
742
        self.assertRaises(AttributeError, formatter.show_properties,
 
743
                          'a revision', '')
 
744
 
 
745
        revision = wt.branch.repository.get_revision(wt.branch.last_revision())
 
746
        formatter.show_properties(revision, '')
 
747
        self.assertEqualDiff('''custom_prop_name: test_value\n''',
 
748
                             sio.getvalue())
 
749
 
 
750
 
 
751
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
837
752
 
838
753
    def test_long_verbose_log(self):
839
754
        """Verbose log includes changed files
840
 
        
 
755
 
841
756
        bug #4676
842
757
        """
843
 
        wt = self.make_branch_and_tree('.')
844
 
        b = wt.branch
845
 
        self.build_tree(['a'])
846
 
        wt.add('a')
847
 
        # XXX: why does a longer nick show up?
848
 
        b.nick = 'test_verbose_log'
849
 
        wt.commit(message='add a',
850
 
                  timestamp=1132711707,
851
 
                  timezone=36000,
852
 
                  committer='Lorem Ipsum <test@example.com>')
853
 
        logfile = file('out.tmp', 'w+')
854
 
        formatter = log.LongLogFormatter(to_file=logfile, levels=1)
855
 
        log.show_log(b, formatter, verbose=True)
856
 
        logfile.flush()
857
 
        logfile.seek(0)
858
 
        log_contents = logfile.read()
859
 
        self.assertEqualDiff('''\
 
758
        wt = self.make_standard_commit('test_long_verbose_log', authors=[])
 
759
        self.assertFormatterResult("""\
860
760
------------------------------------------------------------
861
761
revno: 1
862
762
committer: Lorem Ipsum <test@example.com>
863
 
branch nick: test_verbose_log
 
763
branch nick: test_long_verbose_log
864
764
timestamp: Wed 2005-11-23 12:08:27 +1000
865
765
message:
866
766
  add a
867
767
added:
868
768
  a
869
 
''',
870
 
                             log_contents)
 
769
""",
 
770
            wt.branch, log.LongLogFormatter,
 
771
            formatter_kwargs=dict(levels=1),
 
772
            show_log_kwargs=dict(verbose=True))
871
773
 
872
774
    def test_long_verbose_contain_deltas(self):
873
775
        wt = self.make_branch_and_tree('parent')
874
776
        self.build_tree(['parent/f1', 'parent/f2'])
875
777
        wt.add(['f1','f2'])
876
778
        wt.commit('first post')
877
 
        self.run_bzr('branch parent child')
 
779
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
878
780
        os.unlink('child/f1')
879
 
        file('child/f2', 'wb').write('hello\n')
880
 
        self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
881
 
            'child'])
882
 
        os.chdir('parent')
883
 
        self.run_bzr('merge ../child')
 
781
        self.build_tree_contents([('child/f2', 'hello\n')])
 
782
        child_wt.commit('removed f1 and modified f2')
 
783
        wt.merge_from_branch(child_wt.branch)
884
784
        wt.commit('merge branch 1')
885
 
        b = wt.branch
886
 
        sio = self.make_utf8_encoded_stringio()
887
 
        lf = log.LongLogFormatter(to_file=sio, levels=1)
888
 
        log.show_log(b, lf, verbose=True)
889
 
        the_log = normalize_log(sio.getvalue())
890
 
        self.assertEqualDiff("""\
 
785
        self.assertFormatterResult("""\
891
786
------------------------------------------------------------
892
 
revno: 2
 
787
revno: 2 [merge]
893
788
committer: Lorem Ipsum <test@example.com>
894
789
branch nick: parent
895
790
timestamp: Just now
910
805
  f1
911
806
  f2
912
807
""",
913
 
                             the_log)
 
808
            wt.branch, log.LongLogFormatter,
 
809
            formatter_kwargs=dict(levels=1),
 
810
            show_log_kwargs=dict(verbose=True),
 
811
            normalize=True)
914
812
 
915
813
    def test_long_trailing_newlines(self):
916
814
        wt = self.make_branch_and_tree('.')
917
815
        b = make_commits_with_trailing_newlines(wt)
918
 
        sio = self.make_utf8_encoded_stringio()
919
 
        lf = log.LongLogFormatter(to_file=sio, levels=1)
920
 
        log.show_log(b, lf)
921
 
        self.assertEqualDiff("""\
 
816
        self.assertFormatterResult("""\
922
817
------------------------------------------------------------
923
818
revno: 3
924
819
committer: Joe Foo <joe@foo.com>
944
839
message:
945
840
  simple log message
946
841
""",
947
 
                             sio.getvalue())
 
842
        b, log.LongLogFormatter,
 
843
        formatter_kwargs=dict(levels=1))
948
844
 
949
845
    def test_long_author_in_log(self):
950
846
        """Log includes the author name if it's set in
951
847
        the revision properties
952
848
        """
953
 
        wt = self.make_branch_and_tree('.')
954
 
        b = wt.branch
955
 
        self.build_tree(['a'])
956
 
        wt.add('a')
957
 
        b.nick = 'test_author_log'
958
 
        wt.commit(message='add a',
959
 
                  timestamp=1132711707,
960
 
                  timezone=36000,
961
 
                  committer='Lorem Ipsum <test@example.com>',
962
 
                  author='John Doe <jdoe@example.com>')
963
 
        sio = StringIO()
964
 
        formatter = log.LongLogFormatter(to_file=sio, levels=1)
965
 
        log.show_log(b, formatter)
966
 
        self.assertEqualDiff('''\
 
849
        wt = self.make_standard_commit('test_author_log')
 
850
        self.assertFormatterResult("""\
967
851
------------------------------------------------------------
968
852
revno: 1
969
853
author: John Doe <jdoe@example.com>
972
856
timestamp: Wed 2005-11-23 12:08:27 +1000
973
857
message:
974
858
  add a
975
 
''',
976
 
                             sio.getvalue())
 
859
""",
 
860
            wt.branch, log.LongLogFormatter,
 
861
            formatter_kwargs=dict(levels=1))
977
862
 
978
863
    def test_long_properties_in_log(self):
979
 
        """Log includes the custom properties returned by the registered 
 
864
        """Log includes the custom properties returned by the registered
980
865
        handlers.
981
866
        """
982
 
        wt = self.make_branch_and_tree('.')
983
 
        b = wt.branch
984
 
        self.build_tree(['a'])
985
 
        wt.add('a')
986
 
        b.nick = 'test_properties_in_log'
987
 
        wt.commit(message='add a',
988
 
                  timestamp=1132711707,
989
 
                  timezone=36000,
990
 
                  committer='Lorem Ipsum <test@example.com>',
991
 
                  author='John Doe <jdoe@example.com>')
992
 
        sio = StringIO()
993
 
        formatter = log.LongLogFormatter(to_file=sio, levels=1)
994
 
        try:
995
 
            def trivial_custom_prop_handler(revision):
996
 
                return {'test_prop':'test_value'}
 
867
        wt = self.make_standard_commit('test_properties_in_log')
 
868
        def trivial_custom_prop_handler(revision):
 
869
            return {'test_prop':'test_value'}
997
870
 
998
 
            log.properties_handler_registry.register(
999
 
                'trivial_custom_prop_handler',
1000
 
                trivial_custom_prop_handler)
1001
 
            log.show_log(b, formatter)
1002
 
        finally:
1003
 
            log.properties_handler_registry.remove(
1004
 
                'trivial_custom_prop_handler')
1005
 
            self.assertEqualDiff('''\
 
871
        log.properties_handler_registry.register(
 
872
            'trivial_custom_prop_handler',
 
873
            trivial_custom_prop_handler)
 
874
        self.assertFormatterResult("""\
1006
875
------------------------------------------------------------
1007
876
revno: 1
1008
877
test_prop: test_value
1012
881
timestamp: Wed 2005-11-23 12:08:27 +1000
1013
882
message:
1014
883
  add a
1015
 
''',
1016
 
                                 sio.getvalue())
1017
 
 
1018
 
 
1019
 
class TestLineLogFormatter(tests.TestCaseWithTransport):
 
884
""",
 
885
            wt.branch, log.LongLogFormatter,
 
886
            formatter_kwargs=dict(levels=1))
 
887
 
 
888
 
 
889
class TestLineLogFormatter(TestCaseForLogFormatter):
1020
890
 
1021
891
    def test_line_log(self):
1022
892
        """Line log should show revno
1023
 
        
 
893
 
1024
894
        bug #5162
1025
895
        """
1026
 
        wt = self.make_branch_and_tree('.')
1027
 
        b = wt.branch
1028
 
        self.build_tree(['a'])
1029
 
        wt.add('a')
1030
 
        b.nick = 'test-line-log'
1031
 
        wt.commit(message='add a',
1032
 
                  timestamp=1132711707,
1033
 
                  timezone=36000,
1034
 
                  committer='Line-Log-Formatter Tester <test@line.log>')
1035
 
        logfile = file('out.tmp', 'w+')
1036
 
        formatter = log.LineLogFormatter(to_file=logfile)
1037
 
        log.show_log(b, formatter)
1038
 
        logfile.flush()
1039
 
        logfile.seek(0)
1040
 
        log_contents = logfile.read()
1041
 
        self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
1042
 
                             log_contents)
 
896
        wt = self.make_standard_commit('test-line-log',
 
897
                committer='Line-Log-Formatter Tester <test@line.log>',
 
898
                authors=[])
 
899
        self.assertFormatterResult("""\
 
900
1: Line-Log-Formatte... 2005-11-23 add a
 
901
""",
 
902
            wt.branch, log.LineLogFormatter)
1043
903
 
1044
904
    def test_trailing_newlines(self):
1045
905
        wt = self.make_branch_and_tree('.')
1046
906
        b = make_commits_with_trailing_newlines(wt)
1047
 
        sio = self.make_utf8_encoded_stringio()
1048
 
        lf = log.LineLogFormatter(to_file=sio)
1049
 
        log.show_log(b, lf)
1050
 
        self.assertEqualDiff("""\
 
907
        self.assertFormatterResult("""\
1051
908
3: Joe Foo 2005-11-21 single line with trailing newline
1052
909
2: Joe Bar 2005-11-21 multiline
1053
910
1: Joe Foo 2005-11-21 simple log message
1054
911
""",
1055
 
                             sio.getvalue())
1056
 
 
1057
 
    def _prepare_tree_with_merges(self, with_tags=False):
1058
 
        wt = self.make_branch_and_memory_tree('.')
1059
 
        wt.lock_write()
1060
 
        self.addCleanup(wt.unlock)
1061
 
        wt.add('')
1062
 
        wt.commit('rev-1', rev_id='rev-1',
1063
 
                  timestamp=1132586655, timezone=36000,
1064
 
                  committer='Joe Foo <joe@foo.com>')
1065
 
        wt.commit('rev-merged', rev_id='rev-2a',
1066
 
                  timestamp=1132586700, timezone=36000,
1067
 
                  committer='Joe Foo <joe@foo.com>')
1068
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
1069
 
        wt.branch.set_last_revision_info(1, 'rev-1')
1070
 
        wt.commit('rev-2', rev_id='rev-2b',
1071
 
                  timestamp=1132586800, timezone=36000,
1072
 
                  committer='Joe Foo <joe@foo.com>')
1073
 
        if with_tags:
1074
 
            branch = wt.branch
1075
 
            branch.tags.set_tag('v0.2', 'rev-2b')
1076
 
            wt.commit('rev-3', rev_id='rev-3',
1077
 
                      timestamp=1132586900, timezone=36000,
1078
 
                      committer='Jane Foo <jane@foo.com>')
1079
 
            branch.tags.set_tag('v1.0rc1', 'rev-3')
1080
 
            branch.tags.set_tag('v1.0', 'rev-3')
1081
 
        return wt
 
912
            b, log.LineLogFormatter)
1082
913
 
1083
914
    def test_line_log_single_merge_revision(self):
1084
915
        wt = self._prepare_tree_with_merges()
1085
 
        logfile = self.make_utf8_encoded_stringio()
1086
 
        formatter = log.LineLogFormatter(to_file=logfile)
1087
916
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1088
 
        wtb = wt.branch
1089
 
        rev = revspec.in_history(wtb)
1090
 
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1091
 
        self.assertEqualDiff("""\
 
917
        rev = revspec.in_history(wt.branch)
 
918
        self.assertFormatterResult("""\
1092
919
1.1.1: Joe Foo 2005-11-22 rev-merged
1093
920
""",
1094
 
                             logfile.getvalue())
 
921
            wt.branch, log.LineLogFormatter,
 
922
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1095
923
 
1096
924
    def test_line_log_with_tags(self):
1097
925
        wt = self._prepare_tree_with_merges(with_tags=True)
1098
 
        logfile = self.make_utf8_encoded_stringio()
1099
 
        formatter = log.LineLogFormatter(to_file=logfile)
1100
 
        log.show_log(wt.branch, formatter)
1101
 
        self.assertEqualDiff("""\
 
926
        self.assertFormatterResult("""\
1102
927
3: Jane Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
1103
928
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
1104
929
1: Joe Foo 2005-11-22 rev-1
1105
930
""",
1106
 
                             logfile.getvalue())
1107
 
 
1108
 
class TestLineLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
 
931
            wt.branch, log.LineLogFormatter)
 
932
 
 
933
 
 
934
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
1109
935
 
1110
936
    def test_line_merge_revs_log(self):
1111
937
        """Line log should show revno
1112
 
        
 
938
 
1113
939
        bug #5162
1114
940
        """
1115
 
        wt = self.make_branch_and_tree('.')
1116
 
        b = wt.branch
1117
 
        self.build_tree(['a'])
1118
 
        wt.add('a')
1119
 
        b.nick = 'test-line-log'
1120
 
        wt.commit(message='add a',
1121
 
                  timestamp=1132711707,
1122
 
                  timezone=36000,
1123
 
                  committer='Line-Log-Formatter Tester <test@line.log>')
1124
 
        logfile = file('out.tmp', 'w+')
1125
 
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1126
 
        log.show_log(b, formatter)
1127
 
        logfile.flush()
1128
 
        logfile.seek(0)
1129
 
        log_contents = logfile.read()
1130
 
        self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
1131
 
                             log_contents)
 
941
        wt = self.make_standard_commit('test-line-log',
 
942
                committer='Line-Log-Formatter Tester <test@line.log>',
 
943
                authors=[])
 
944
        self.assertFormatterResult("""\
 
945
1: Line-Log-Formatte... 2005-11-23 add a
 
946
""",
 
947
            wt.branch, log.LineLogFormatter)
1132
948
 
1133
949
    def test_line_merge_revs_log_single_merge_revision(self):
1134
950
        wt = self.make_branch_and_memory_tree('.')
1146
962
        wt.commit('rev-2', rev_id='rev-2b',
1147
963
                  timestamp=1132586800, timezone=36000,
1148
964
                  committer='Joe Foo <joe@foo.com>')
1149
 
        logfile = self.make_utf8_encoded_stringio()
1150
 
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1151
965
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1152
 
        wtb = wt.branch
1153
 
        rev = revspec.in_history(wtb)
1154
 
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1155
 
        self.assertEqualDiff("""\
 
966
        rev = revspec.in_history(wt.branch)
 
967
        self.assertFormatterResult("""\
1156
968
1.1.1: Joe Foo 2005-11-22 rev-merged
1157
969
""",
1158
 
                             logfile.getvalue())
 
970
            wt.branch, log.LineLogFormatter,
 
971
            formatter_kwargs=dict(levels=0),
 
972
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1159
973
 
1160
974
    def test_line_merge_revs_log_with_merges(self):
1161
975
        wt = self.make_branch_and_memory_tree('.')
1173
987
        wt.commit('rev-2', rev_id='rev-2b',
1174
988
                  timestamp=1132586800, timezone=36000,
1175
989
                  committer='Joe Foo <joe@foo.com>')
1176
 
        logfile = self.make_utf8_encoded_stringio()
1177
 
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1178
 
        log.show_log(wt.branch, formatter)
1179
 
        self.assertEqualDiff("""\
 
990
        self.assertFormatterResult("""\
1180
991
2: Joe Foo 2005-11-22 [merge] rev-2
1181
992
  1.1.1: Joe Foo 2005-11-22 rev-merged
1182
993
1: Joe Foo 2005-11-22 rev-1
1183
994
""",
1184
 
                             logfile.getvalue())
 
995
            wt.branch, log.LineLogFormatter,
 
996
            formatter_kwargs=dict(levels=0))
 
997
 
1185
998
 
1186
999
class TestGetViewRevisions(tests.TestCaseWithTransport):
1187
1000
 
1207
1020
        # 4a: 3.1.1
1208
1021
        return mainline_revs, rev_nos, wt
1209
1022
 
1210
 
    def make_tree_with_many_merges(self):
 
1023
    def make_branch_with_many_merges(self):
1211
1024
        """Create a tree with well-known revision ids"""
1212
 
        wt = self.make_branch_and_tree('tree1')
1213
 
        self.build_tree_contents([('tree1/f', '1\n')])
1214
 
        wt.add(['f'], ['f-id'])
1215
 
        wt.commit('commit one', rev_id='1')
1216
 
        wt.commit('commit two', rev_id='2')
1217
 
 
1218
 
        tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
1219
 
        self.build_tree_contents([('tree3/f', '1\n2\n3a\n')])
1220
 
        tree3.commit('commit three a', rev_id='3a')
1221
 
 
1222
 
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1223
 
        tree2.merge_from_branch(tree3.branch)
1224
 
        tree2.commit('commit three b', rev_id='3b')
1225
 
 
1226
 
        wt.merge_from_branch(tree2.branch)
1227
 
        wt.commit('commit three c', rev_id='3c')
1228
 
        tree2.commit('four-a', rev_id='4a')
1229
 
 
1230
 
        wt.merge_from_branch(tree2.branch)
1231
 
        wt.commit('four-b', rev_id='4b')
 
1025
        builder = self.make_branch_builder('tree1')
 
1026
        builder.start_series()
 
1027
        builder.build_snapshot('1', None, [
 
1028
            ('add', ('', 'TREE_ROOT', 'directory', '')),
 
1029
            ('add', ('f', 'f-id', 'file', '1\n'))])
 
1030
        builder.build_snapshot('2', ['1'], [])
 
1031
        builder.build_snapshot('3a', ['2'], [
 
1032
            ('modify', ('f-id', '1\n2\n3a\n'))])
 
1033
        builder.build_snapshot('3b', ['2', '3a'], [
 
1034
            ('modify', ('f-id', '1\n2\n3a\n'))])
 
1035
        builder.build_snapshot('3c', ['2', '3b'], [
 
1036
            ('modify', ('f-id', '1\n2\n3a\n'))])
 
1037
        builder.build_snapshot('4a', ['3b'], [])
 
1038
        builder.build_snapshot('4b', ['3c', '4a'], [])
 
1039
        builder.finish_series()
 
1040
 
 
1041
        # 1
 
1042
        # |
 
1043
        # 2-.
 
1044
        # |\ \
 
1045
        # | | 3a
 
1046
        # | |/
 
1047
        # | 3b
 
1048
        # |/|
 
1049
        # 3c4a
 
1050
        # |/
 
1051
        # 4b
1232
1052
 
1233
1053
        mainline_revs = [None, '1', '2', '3c', '4b']
1234
1054
        rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
1241
1061
            '4a': '2.2.2', # second commit tree 2
1242
1062
            '4b': '4', # merges 4a to main
1243
1063
            }
1244
 
        return mainline_revs, rev_nos, wt
 
1064
        return mainline_revs, rev_nos, builder.get_branch()
1245
1065
 
1246
1066
    def test_get_view_revisions_forward(self):
1247
1067
        """Test the get_view_revisions method"""
1307
1127
 
1308
1128
    def test_get_view_revisions_merge2(self):
1309
1129
        """Test get_view_revisions when there are merges"""
1310
 
        mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1311
 
        wt.lock_read()
1312
 
        self.addCleanup(wt.unlock)
 
1130
        mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
 
1131
        b.lock_read()
 
1132
        self.addCleanup(b.unlock)
1313
1133
        revisions = list(log.get_view_revisions(
1314
 
                mainline_revs, rev_nos, wt.branch, 'forward'))
 
1134
                mainline_revs, rev_nos, b, 'forward'))
1315
1135
        expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1316
 
                    ('3a', '2.1.1', 1), ('3b', '2.2.1', 1), ('4b', '4', 0),
 
1136
                    ('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1317
1137
                    ('4a', '2.2.2', 1)]
1318
1138
        self.assertEqual(expected, revisions)
1319
1139
        revisions = list(log.get_view_revisions(
1320
 
                mainline_revs, rev_nos, wt.branch, 'forward',
 
1140
                mainline_revs, rev_nos, b, 'forward',
1321
1141
                include_merges=False))
1322
1142
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1323
1143
                          ('4b', '4', 0)],
1325
1145
 
1326
1146
 
1327
1147
    def test_file_id_for_range(self):
1328
 
        mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1329
 
        wt.lock_read()
1330
 
        self.addCleanup(wt.unlock)
 
1148
        mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
 
1149
        b.lock_read()
 
1150
        self.addCleanup(b.unlock)
1331
1151
 
1332
1152
        def rev_from_rev_id(revid, branch):
1333
1153
            revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1335
1155
 
1336
1156
        def view_revs(start_rev, end_rev, file_id, direction):
1337
1157
            revs = log.calculate_view_revisions(
1338
 
                wt.branch,
 
1158
                b,
1339
1159
                start_rev, # start_revision
1340
1160
                end_rev, # end_revision
1341
1161
                direction, # direction
1342
1162
                file_id, # specific_fileid
1343
1163
                True, # generate_merge_revisions
1344
 
                True, # allow_single_merge_revision
1345
1164
                )
1346
1165
            return revs
1347
1166
 
1348
 
        rev_3a = rev_from_rev_id('3a', wt.branch)
1349
 
        rev_4b = rev_from_rev_id('4b', wt.branch)
1350
 
        self.assertEqual([('3c', '3', 0), ('3a', '2.1.1', 1)],
 
1167
        rev_3a = rev_from_rev_id('3a', b)
 
1168
        rev_4b = rev_from_rev_id('4b', b)
 
1169
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1), ('3a', '2.1.1', 2)],
1351
1170
                          view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
1352
1171
        # Note: 3c still appears before 3a here because of depth-based sorting
1353
 
        self.assertEqual([('3c', '3', 0), ('3a', '2.1.1', 1)],
 
1172
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1), ('3a', '2.1.1', 2)],
1354
1173
                          view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1355
1174
 
1356
1175
 
1498
1317
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['XX', 'B', 'A'])
1499
1318
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1500
1319
 
 
1320
    def test_unknown_file_id(self):
 
1321
        tree = self.create_tree_with_single_merge()
 
1322
        self.assertAllRevisionsForFileID(tree, 'unknown', [])
 
1323
 
 
1324
    def test_empty_branch_unknown_file_id(self):
 
1325
        tree = self.make_branch_and_tree('tree')
 
1326
        self.assertAllRevisionsForFileID(tree, 'unknown', [])
 
1327
 
1501
1328
 
1502
1329
class TestShowChangedRevisions(tests.TestCaseWithTransport):
1503
1330
 
1545
1372
        self.assertEqual('jsmith@example.com', lf.short_author(rev))
1546
1373
        rev.properties['author'] = 'John Smith jsmith@example.com'
1547
1374
        self.assertEqual('John Smith', lf.short_author(rev))
 
1375
        del rev.properties['author']
 
1376
        rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
 
1377
                'Jane Rey <jrey@example.com>')
 
1378
        self.assertEqual('John Smith', lf.short_author(rev))
1548
1379
 
1549
1380
 
1550
1381
class TestReverseByDepth(tests.TestCase):
1696
1527
        log.show_branch_change(tree.branch, s, 3, '3b')
1697
1528
        self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1698
1529
        self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
 
1530
 
 
1531
 
 
1532
 
 
1533
class TestLogWithBugs(TestCaseForLogFormatter):
 
1534
 
 
1535
    def setUp(self):
 
1536
        TestCaseForLogFormatter.setUp(self)
 
1537
        log.properties_handler_registry.register(
 
1538
            'bugs_properties_handler',
 
1539
            log._bugs_properties_handler)
 
1540
 
 
1541
    def make_commits_with_bugs(self):
 
1542
        """Helper method for LogFormatter tests"""
 
1543
        tree = self.make_branch_and_tree(u'.')
 
1544
        self.build_tree(['a', 'b'])
 
1545
        tree.add('a')
 
1546
        tree.commit('simple log message', rev_id='a1',
 
1547
                    timestamp=1132586655.459960938, timezone=-6*3600,
 
1548
                    committer='Joe Foo <joe@foo.com>',
 
1549
                    revprops={'bugs': 'test://bug/id fixed'})
 
1550
        tree.add('b')
 
1551
        tree.commit('multiline\nlog\nmessage\n', rev_id='a2',
 
1552
                    timestamp=1132586842.411175966, timezone=-6*3600,
 
1553
                    committer='Joe Foo <joe@foo.com>',
 
1554
                    authors=['Joe Bar <joe@bar.com>'],
 
1555
                    revprops={'bugs': 'test://bug/id fixed\n'
 
1556
                                      'test://bug/2 fixed'})
 
1557
        return tree
 
1558
 
 
1559
 
 
1560
    def test_long_bugs(self):
 
1561
        tree = self.make_commits_with_bugs()
 
1562
        self.assertFormatterResult("""\
 
1563
------------------------------------------------------------
 
1564
revno: 2
 
1565
fixes bug(s): test://bug/id test://bug/2
 
1566
author: Joe Bar <joe@bar.com>
 
1567
committer: Joe Foo <joe@foo.com>
 
1568
branch nick: work
 
1569
timestamp: Mon 2005-11-21 09:27:22 -0600
 
1570
message:
 
1571
  multiline
 
1572
  log
 
1573
  message
 
1574
------------------------------------------------------------
 
1575
revno: 1
 
1576
fixes bug(s): test://bug/id
 
1577
committer: Joe Foo <joe@foo.com>
 
1578
branch nick: work
 
1579
timestamp: Mon 2005-11-21 09:24:15 -0600
 
1580
message:
 
1581
  simple log message
 
1582
""",
 
1583
            tree.branch, log.LongLogFormatter)
 
1584
 
 
1585
    def test_short_bugs(self):
 
1586
        tree = self.make_commits_with_bugs()
 
1587
        self.assertFormatterResult("""\
 
1588
    2 Joe Bar\t2005-11-21
 
1589
      fixes bug(s): test://bug/id test://bug/2
 
1590
      multiline
 
1591
      log
 
1592
      message
 
1593
 
 
1594
    1 Joe Foo\t2005-11-21
 
1595
      fixes bug(s): test://bug/id
 
1596
      simple log message
 
1597
 
 
1598
""",
 
1599
            tree.branch, log.ShortLogFormatter)
 
1600
 
 
1601
    def test_wrong_bugs_property(self):
 
1602
        tree = self.make_branch_and_tree(u'.')
 
1603
        self.build_tree(['foo'])
 
1604
        tree.commit('simple log message', rev_id='a1',
 
1605
              timestamp=1132586655.459960938, timezone=-6*3600,
 
1606
              committer='Joe Foo <joe@foo.com>',
 
1607
              revprops={'bugs': 'test://bug/id invalid_value'})
 
1608
        self.assertFormatterResult("""\
 
1609
    1 Joe Foo\t2005-11-21
 
1610
      simple log message
 
1611
 
 
1612
""",
 
1613
            tree.branch, log.ShortLogFormatter)
 
1614
 
 
1615
    def test_bugs_handler_present(self):
 
1616
        self.properties_handler_registry.get('bugs_properties_handler')