~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_log.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-09-01 08:02:42 UTC
  • mfrom: (5390.3.3 faster-revert-593560)
  • Revision ID: pqm@pqm.ubuntu.com-20100901080242-esg62ody4frwmy66
(spiv) Avoid repeatedly calling self.target.all_file_ids() in
 InterTree.iter_changes. (Andrew Bennetts)

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
 
        # clean up the registry in log
 
57
        # Use a clean registry for log
37
58
        log.properties_handler_registry = registry.Registry()
38
59
 
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
43
 
 
 
60
        def restore():
 
61
            log.properties_handler_registry = self.properties_handler_registry
 
62
        self.addCleanup(restore)
 
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
44
119
 
45
120
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.
 
121
    """Pull log messages into a list rather than displaying them.
 
122
 
 
123
    To simplify testing we save logged revisions here rather than actually
 
124
    formatting anything, so that we can precisely check the result without
 
125
    being dependent on the formatting.
53
126
    """
54
127
 
 
128
    supports_merge_revisions = True
55
129
    supports_delta = True
 
130
    supports_diff = True
 
131
    preferred_levels = 0
56
132
 
57
 
    def __init__(self):
58
 
        super(LogCatcher, self).__init__(to_file=None)
59
 
        self.logs = []
 
133
    def __init__(self, *args, **kwargs):
 
134
        kwargs.update(dict(to_file=None))
 
135
        super(LogCatcher, self).__init__(*args, **kwargs)
 
136
        self.revisions = []
60
137
 
61
138
    def log_revision(self, revision):
62
 
        self.logs.append(revision)
 
139
        self.revisions.append(revision)
63
140
 
64
141
 
65
142
class TestShowLog(tests.TestCaseWithTransport):
106
183
        lf = LogCatcher()
107
184
        log.show_log(wt.branch, lf)
108
185
        # no entries yet
109
 
        self.assertEqual([], lf.logs)
 
186
        self.assertEqual([], lf.revisions)
110
187
 
111
188
    def test_empty_commit(self):
112
189
        wt = self.make_branch_and_tree('.')
114
191
        wt.commit('empty commit')
115
192
        lf = LogCatcher()
116
193
        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)
 
194
        revs = lf.revisions
 
195
        self.assertEqual(1, len(revs))
 
196
        self.assertEqual('1', revs[0].revno)
 
197
        self.assertEqual('empty commit', revs[0].rev.message)
 
198
        self.checkDelta(revs[0].delta)
121
199
 
122
200
    def test_simple_commit(self):
123
201
        wt = self.make_branch_and_tree('.')
129
207
                            u'<test@example.com>')
130
208
        lf = LogCatcher()
131
209
        log.show_log(wt.branch, lf, verbose=True)
132
 
        self.assertEqual(2, len(lf.logs))
 
210
        self.assertEqual(2, len(lf.revisions))
133
211
        # first one is most recent
134
 
        log_entry = lf.logs[0]
 
212
        log_entry = lf.revisions[0]
135
213
        self.assertEqual('2', log_entry.revno)
136
214
        self.assertEqual('add one file', log_entry.rev.message)
137
215
        self.checkDelta(log_entry.delta, added=['hello'])
143
221
        wt.commit(msg)
144
222
        lf = LogCatcher()
145
223
        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))
 
224
        committed_msg = lf.revisions[0].rev.message
 
225
        if wt.branch.repository._serializer.squashes_xml_invalid_characters:
 
226
            self.assertNotEqual(msg, committed_msg)
 
227
            self.assertTrue(len(committed_msg) > len(msg))
 
228
        else:
 
229
            self.assertEqual(msg, committed_msg)
149
230
 
150
231
    def test_commit_message_without_control_chars(self):
151
232
        wt = self.make_branch_and_tree('.')
157
238
        wt.commit(msg)
158
239
        lf = LogCatcher()
159
240
        log.show_log(wt.branch, lf, verbose=True)
160
 
        committed_msg = lf.logs[0].rev.message
 
241
        committed_msg = lf.revisions[0].rev.message
161
242
        self.assertEqual(msg, committed_msg)
162
243
 
163
244
    def test_deltas_in_merge_revisions(self):
181
262
        lf.supports_merge_revisions = True
182
263
        log.show_log(b, lf, verbose=True)
183
264
 
184
 
        self.assertEqual(3, len(lf.logs))
 
265
        revs = lf.revisions
 
266
        self.assertEqual(3, len(revs))
185
267
 
186
 
        logentry = lf.logs[0]
 
268
        logentry = revs[0]
187
269
        self.assertEqual('2', logentry.revno)
188
270
        self.assertEqual('merge child branch', logentry.rev.message)
189
271
        self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
190
272
 
191
 
        logentry = lf.logs[1]
 
273
        logentry = revs[1]
192
274
        self.assertEqual('1.1.1', logentry.revno)
193
275
        self.assertEqual('remove file1 and modify file2', logentry.rev.message)
194
276
        self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
195
277
 
196
 
        logentry = lf.logs[2]
 
278
        logentry = revs[2]
197
279
        self.assertEqual('1', logentry.revno)
198
280
        self.assertEqual('add file1 and file2', logentry.rev.message)
199
281
        self.checkDelta(logentry.delta, added=['file1', 'file2'])
200
282
 
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
 
 
229
 
def make_commits_with_trailing_newlines(wt):
230
 
    """Helper method for LogFormatter tests"""
231
 
    b = wt.branch
232
 
    b.nick='test'
233
 
    open('a', 'wb').write('hello moto\n')
234
 
    wt.add('a')
235
 
    wt.commit('simple log message', rev_id='a1',
236
 
              timestamp=1132586655.459960938, timezone=-6*3600,
237
 
              committer='Joe Foo <joe@foo.com>')
238
 
    open('b', 'wb').write('goodbye\n')
239
 
    wt.add('b')
240
 
    wt.commit('multiline\nlog\nmessage\n', rev_id='a2',
241
 
              timestamp=1132586842.411175966, timezone=-6*3600,
242
 
              committer='Joe Foo <joe@foo.com>',
243
 
              authors=['Joe Bar <joe@bar.com>'])
244
 
 
245
 
    open('c', 'wb').write('just another manic monday\n')
246
 
    wt.add('c')
247
 
    wt.commit('single line with trailing newline\n', rev_id='a3',
248
 
              timestamp=1132587176.835228920, timezone=-6*3600,
249
 
              committer = 'Joe Foo <joe@foo.com>')
250
 
    return b
251
 
 
252
 
 
253
 
def normalize_log(log):
254
 
    """Replaces the variable lines of logs with fixed lines"""
255
 
    author = 'author: Dolor Sit <test@example.com>'
256
 
    committer = 'committer: Lorem Ipsum <test@example.com>'
257
 
    lines = log.splitlines(True)
258
 
    for idx,line in enumerate(lines):
259
 
        stripped_line = line.lstrip()
260
 
        indent = ' ' * (len(line) - len(stripped_line))
261
 
        if stripped_line.startswith('author:'):
262
 
            lines[idx] = indent + author + '\n'
263
 
        elif stripped_line.startswith('committer:'):
264
 
            lines[idx] = indent + committer + '\n'
265
 
        elif stripped_line.startswith('timestamp:'):
266
 
            lines[idx] = indent + 'timestamp: Just now\n'
267
 
    return ''.join(lines)
268
 
 
269
 
 
270
 
class TestShortLogFormatter(tests.TestCaseWithTransport):
 
283
 
 
284
class TestShortLogFormatter(TestCaseForLogFormatter):
271
285
 
272
286
    def test_trailing_newlines(self):
273
287
        wt = self.make_branch_and_tree('.')
274
 
        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("""\
279
 
    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
280
291
      single line with trailing newline
281
292
 
282
 
    2 Joe Bar\t2005-11-21
 
293
    2 Joe Foo\t2005-11-22
283
294
      multiline
284
295
      log
285
296
      message
286
297
 
287
 
    1 Joe Foo\t2005-11-21
 
298
    1 Joe Foo\t2005-11-22
288
299
      simple log message
289
300
 
290
301
""",
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
 
302
            b, log.ShortLogFormatter)
318
303
 
319
304
    def test_short_log_with_merges(self):
320
305
        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())
 
306
        self.assertFormatterResult("""\
 
307
    2 Joe Foo\t2005-11-22 [merge]
 
308
      rev-2
 
309
 
 
310
    1 Joe Foo\t2005-11-22
 
311
      rev-1
 
312
 
 
313
""",
 
314
            wt.branch, log.ShortLogFormatter)
 
315
 
 
316
    def test_short_log_with_merges_and_advice(self):
 
317
        wt = self._prepare_tree_with_merges()
 
318
        self.assertFormatterResult("""\
 
319
    2 Joe Foo\t2005-11-22 [merge]
 
320
      rev-2
 
321
 
 
322
    1 Joe Foo\t2005-11-22
 
323
      rev-1
 
324
 
 
325
Use --include-merges or -n0 to see merged revisions.
 
326
""",
 
327
            wt.branch, log.ShortLogFormatter,
 
328
            formatter_kwargs=dict(show_advice=True))
333
329
 
334
330
    def test_short_log_with_merges_and_range(self):
335
 
        wt = self.make_branch_and_memory_tree('.')
336
 
        wt.lock_write()
337
 
        self.addCleanup(wt.unlock)
338
 
        wt.add('')
339
 
        wt.commit('rev-1', rev_id='rev-1',
340
 
                  timestamp=1132586655, timezone=36000,
341
 
                  committer='Joe Foo <joe@foo.com>')
342
 
        wt.commit('rev-merged', rev_id='rev-2a',
343
 
                  timestamp=1132586700, timezone=36000,
344
 
                  committer='Joe Foo <joe@foo.com>')
345
 
        wt.branch.set_last_revision_info(1, 'rev-1')
346
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
347
 
        wt.commit('rev-2b', rev_id='rev-2b',
348
 
                  timestamp=1132586800, timezone=36000,
349
 
                  committer='Joe Foo <joe@foo.com>')
350
 
        wt.commit('rev-3a', rev_id='rev-3a',
351
 
                  timestamp=1132586800, timezone=36000,
352
 
                  committer='Joe Foo <joe@foo.com>')
 
331
        wt = self._prepare_tree_with_merges()
 
332
        self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
353
333
        wt.branch.set_last_revision_info(2, 'rev-2b')
354
334
        wt.set_parent_ids(['rev-2b', 'rev-3a'])
355
 
        wt.commit('rev-3b', rev_id='rev-3b',
356
 
                  timestamp=1132586800, timezone=36000,
357
 
                  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("""\
 
335
        self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
 
336
        self.assertFormatterResult("""\
363
337
    3 Joe Foo\t2005-11-22 [merge]
364
338
      rev-3b
365
339
 
366
340
    2 Joe Foo\t2005-11-22 [merge]
367
 
      rev-2b
 
341
      rev-2
368
342
 
369
343
""",
370
 
                             logfile.getvalue())
 
344
            wt.branch, log.ShortLogFormatter,
 
345
            show_log_kwargs=dict(start_revision=2, end_revision=3))
371
346
 
372
347
    def test_short_log_with_tags(self):
373
348
        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("""\
378
 
    3 Jane Foo\t2005-11-22 {v1.0, v1.0rc1}
 
349
        self.assertFormatterResult("""\
 
350
    3 Joe Foo\t2005-11-22 {v1.0, v1.0rc1}
379
351
      rev-3
380
352
 
381
353
    2 Joe Foo\t2005-11-22 {v0.2} [merge]
385
357
      rev-1
386
358
 
387
359
""",
388
 
                             logfile.getvalue())
 
360
            wt.branch, log.ShortLogFormatter)
389
361
 
390
362
    def test_short_log_single_merge_revision(self):
391
 
        wt = self.make_branch_and_memory_tree('.')
392
 
        wt.lock_write()
393
 
        self.addCleanup(wt.unlock)
394
 
        wt.add('')
395
 
        wt.commit('rev-1', rev_id='rev-1',
396
 
                  timestamp=1132586655, timezone=36000,
397
 
                  committer='Joe Foo <joe@foo.com>')
398
 
        wt.commit('rev-merged', rev_id='rev-2a',
399
 
                  timestamp=1132586700, timezone=36000,
400
 
                  committer='Joe Foo <joe@foo.com>')
401
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
402
 
        wt.branch.set_last_revision_info(1, 'rev-1')
403
 
        wt.commit('rev-2', rev_id='rev-2b',
404
 
                  timestamp=1132586800, timezone=36000,
405
 
                  committer='Joe Foo <joe@foo.com>')
406
 
        logfile = self.make_utf8_encoded_stringio()
407
 
        formatter = log.ShortLogFormatter(to_file=logfile)
 
363
        wt = self._prepare_tree_with_merges()
408
364
        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("""\
 
365
        rev = revspec.in_history(wt.branch)
 
366
        self.assertFormatterResult("""\
413
367
      1.1.1 Joe Foo\t2005-11-22
414
368
            rev-merged
415
369
 
416
370
""",
417
 
                             logfile.getvalue())
418
 
 
419
 
 
420
 
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):
421
376
 
422
377
    def test_short_merge_revs_log_with_merges(self):
423
 
        wt = self.make_branch_and_memory_tree('.')
424
 
        wt.lock_write()
425
 
        self.addCleanup(wt.unlock)
426
 
        wt.add('')
427
 
        wt.commit('rev-1', rev_id='rev-1',
428
 
                  timestamp=1132586655, timezone=36000,
429
 
                  committer='Joe Foo <joe@foo.com>')
430
 
        wt.commit('rev-merged', rev_id='rev-2a',
431
 
                  timestamp=1132586700, timezone=36000,
432
 
                  committer='Joe Foo <joe@foo.com>')
433
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
434
 
        wt.branch.set_last_revision_info(1, 'rev-1')
435
 
        wt.commit('rev-2', rev_id='rev-2b',
436
 
                  timestamp=1132586800, timezone=36000,
437
 
                  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)
 
378
        wt = self._prepare_tree_with_merges()
441
379
        # Note that the 1.1.1 indenting is in fact correct given that
442
380
        # the revision numbers are right justified within 5 characters
443
381
        # for mainline revnos and 9 characters for dotted revnos.
444
 
        self.assertEqualDiff("""\
 
382
        self.assertFormatterResult("""\
445
383
    2 Joe Foo\t2005-11-22 [merge]
446
384
      rev-2
447
385
 
452
390
      rev-1
453
391
 
454
392
""",
455
 
                             logfile.getvalue())
 
393
            wt.branch, log.ShortLogFormatter,
 
394
            formatter_kwargs=dict(levels=0))
456
395
 
457
396
    def test_short_merge_revs_log_single_merge_revision(self):
458
 
        wt = self.make_branch_and_memory_tree('.')
459
 
        wt.lock_write()
460
 
        self.addCleanup(wt.unlock)
461
 
        wt.add('')
462
 
        wt.commit('rev-1', rev_id='rev-1',
463
 
                  timestamp=1132586655, timezone=36000,
464
 
                  committer='Joe Foo <joe@foo.com>')
465
 
        wt.commit('rev-merged', rev_id='rev-2a',
466
 
                  timestamp=1132586700, timezone=36000,
467
 
                  committer='Joe Foo <joe@foo.com>')
468
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
469
 
        wt.branch.set_last_revision_info(1, 'rev-1')
470
 
        wt.commit('rev-2', rev_id='rev-2b',
471
 
                  timestamp=1132586800, timezone=36000,
472
 
                  committer='Joe Foo <joe@foo.com>')
473
 
        logfile = self.make_utf8_encoded_stringio()
474
 
        formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
 
397
        wt = self._prepare_tree_with_merges()
475
398
        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("""\
 
399
        rev = revspec.in_history(wt.branch)
 
400
        self.assertFormatterResult("""\
480
401
      1.1.1 Joe Foo\t2005-11-22
481
402
            rev-merged
482
403
 
483
404
""",
484
 
                             logfile.getvalue())
485
 
 
486
 
 
487
 
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):
488
411
 
489
412
    def test_verbose_log(self):
490
413
        """Verbose log includes changed files
491
414
 
492
415
        bug #4676
493
416
        """
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('''\
 
417
        wt = self.make_standard_commit('test_verbose_log', authors=[])
 
418
        self.assertFormatterResult('''\
511
419
------------------------------------------------------------
512
420
revno: 1
513
421
committer: Lorem Ipsum <test@example.com>
514
422
branch nick: test_verbose_log
515
 
timestamp: Wed 2005-11-23 12:08:27 +1000
 
423
timestamp: Tue 2005-11-22 00:00:00 +0000
516
424
message:
517
425
  add a
518
426
added:
519
427
  a
520
428
''',
521
 
                             log_contents)
 
429
            wt.branch, log.LongLogFormatter,
 
430
            show_log_kwargs=dict(verbose=True))
522
431
 
523
432
    def test_merges_are_indented_by_level(self):
524
433
        wt = self.make_branch_and_tree('parent')
525
 
        wt.commit('first post')
526
 
        self.run_bzr('branch parent child')
527
 
        self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
528
 
        self.run_bzr('branch child smallerchild')
529
 
        self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
530
 
            'smallerchild'])
531
 
        os.chdir('child')
532
 
        self.run_bzr('merge ../smallerchild')
533
 
        self.run_bzr(['commit', '-m', 'merge branch 2'])
534
 
        os.chdir('../parent')
535
 
        self.run_bzr('merge ../child')
536
 
        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("""\
 
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("""\
543
444
------------------------------------------------------------
544
 
revno: 2
545
 
committer: Lorem Ipsum <test@example.com>
 
445
revno: 2 [merge]
 
446
committer: Joe Foo <joe@foo.com>
546
447
branch nick: parent
547
 
timestamp: Just now
 
448
timestamp: Tue 2005-11-22 00:00:04 +0000
548
449
message:
549
450
  merge branch 1
550
451
    ------------------------------------------------------------
551
 
    revno: 1.1.2
552
 
    committer: Lorem Ipsum <test@example.com>
 
452
    revno: 1.1.2 [merge]
 
453
    committer: Joe Foo <joe@foo.com>
553
454
    branch nick: child
554
 
    timestamp: Just now
 
455
    timestamp: Tue 2005-11-22 00:00:03 +0000
555
456
    message:
556
457
      merge branch 2
557
458
        ------------------------------------------------------------
558
459
        revno: 1.2.1
559
 
        committer: Lorem Ipsum <test@example.com>
 
460
        committer: Joe Foo <joe@foo.com>
560
461
        branch nick: smallerchild
561
 
        timestamp: Just now
 
462
        timestamp: Tue 2005-11-22 00:00:02 +0000
562
463
        message:
563
464
          branch 2
564
465
    ------------------------------------------------------------
565
466
    revno: 1.1.1
566
 
    committer: Lorem Ipsum <test@example.com>
 
467
    committer: Joe Foo <joe@foo.com>
567
468
    branch nick: child
568
 
    timestamp: Just now
 
469
    timestamp: Tue 2005-11-22 00:00:01 +0000
569
470
    message:
570
471
      branch 1
571
472
------------------------------------------------------------
572
473
revno: 1
573
 
committer: Lorem Ipsum <test@example.com>
 
474
committer: Joe Foo <joe@foo.com>
574
475
branch nick: parent
575
 
timestamp: Just now
 
476
timestamp: Tue 2005-11-22 00:00:00 +0000
576
477
message:
577
478
  first post
578
479
""",
579
 
                             the_log)
 
480
            wt.branch, log.LongLogFormatter,
 
481
            formatter_kwargs=dict(levels=0),
 
482
            show_log_kwargs=dict(verbose=True))
580
483
 
581
484
    def test_verbose_merge_revisions_contain_deltas(self):
582
485
        wt = self.make_branch_and_tree('parent')
583
486
        self.build_tree(['parent/f1', 'parent/f2'])
584
487
        wt.add(['f1','f2'])
585
 
        wt.commit('first post')
586
 
        self.run_bzr('branch parent child')
 
488
        self.wt_commit(wt, 'first post')
 
489
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
587
490
        os.unlink('child/f1')
588
 
        file('child/f2', 'wb').write('hello\n')
589
 
        self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
590
 
            'child'])
591
 
        os.chdir('parent')
592
 
        self.run_bzr('merge ../child')
593
 
        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("""\
 
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("""\
600
496
------------------------------------------------------------
601
 
revno: 2
602
 
committer: Lorem Ipsum <test@example.com>
 
497
revno: 2 [merge]
 
498
committer: Joe Foo <joe@foo.com>
603
499
branch nick: parent
604
 
timestamp: Just now
 
500
timestamp: Tue 2005-11-22 00:00:02 +0000
605
501
message:
606
502
  merge branch 1
607
503
removed:
610
506
  f2
611
507
    ------------------------------------------------------------
612
508
    revno: 1.1.1
613
 
    committer: Lorem Ipsum <test@example.com>
 
509
    committer: Joe Foo <joe@foo.com>
614
510
    branch nick: child
615
 
    timestamp: Just now
 
511
    timestamp: Tue 2005-11-22 00:00:01 +0000
616
512
    message:
617
513
      removed f1 and modified f2
618
514
    removed:
621
517
      f2
622
518
------------------------------------------------------------
623
519
revno: 1
624
 
committer: Lorem Ipsum <test@example.com>
 
520
committer: Joe Foo <joe@foo.com>
625
521
branch nick: parent
626
 
timestamp: Just now
 
522
timestamp: Tue 2005-11-22 00:00:00 +0000
627
523
message:
628
524
  first post
629
525
added:
630
526
  f1
631
527
  f2
632
528
""",
633
 
                             the_log)
 
529
            wt.branch, log.LongLogFormatter,
 
530
            formatter_kwargs=dict(levels=0),
 
531
            show_log_kwargs=dict(verbose=True))
634
532
 
635
533
    def test_trailing_newlines(self):
636
534
        wt = self.make_branch_and_tree('.')
637
 
        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("""\
 
535
        b = self.make_commits_with_trailing_newlines(wt)
 
536
        self.assertFormatterResult("""\
642
537
------------------------------------------------------------
643
538
revno: 3
644
539
committer: Joe Foo <joe@foo.com>
645
540
branch nick: test
646
 
timestamp: Mon 2005-11-21 09:32:56 -0600
 
541
timestamp: Tue 2005-11-22 00:00:02 +0000
647
542
message:
648
543
  single line with trailing newline
649
544
------------------------------------------------------------
650
545
revno: 2
651
 
author: Joe Bar <joe@bar.com>
652
546
committer: Joe Foo <joe@foo.com>
653
547
branch nick: test
654
 
timestamp: Mon 2005-11-21 09:27:22 -0600
 
548
timestamp: Tue 2005-11-22 00:00:01 +0000
655
549
message:
656
550
  multiline
657
551
  log
660
554
revno: 1
661
555
committer: Joe Foo <joe@foo.com>
662
556
branch nick: test
663
 
timestamp: Mon 2005-11-21 09:24:15 -0600
 
557
timestamp: Tue 2005-11-22 00:00:00 +0000
664
558
message:
665
559
  simple log message
666
560
""",
667
 
                             sio.getvalue())
 
561
        b, log.LongLogFormatter)
668
562
 
669
563
    def test_author_in_log(self):
670
564
        """Log includes the author name if it's set in
671
565
        the revision properties
672
566
        """
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
 
                  authors=['John Doe <jdoe@example.com>',
683
 
                           'Jane Rey <jrey@example.com>'])
684
 
        sio = StringIO()
685
 
        formatter = log.LongLogFormatter(to_file=sio)
686
 
        log.show_log(b, formatter)
687
 
        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("""\
688
571
------------------------------------------------------------
689
572
revno: 1
690
573
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
691
574
committer: Lorem Ipsum <test@example.com>
692
575
branch nick: test_author_log
693
 
timestamp: Wed 2005-11-23 12:08:27 +1000
 
576
timestamp: Tue 2005-11-22 00:00:00 +0000
694
577
message:
695
578
  add a
696
 
''',
697
 
                             sio.getvalue())
 
579
""",
 
580
        wt.branch, log.LongLogFormatter)
698
581
 
699
582
    def test_properties_in_log(self):
700
583
        """Log includes the custom properties returned by the registered
701
584
        handlers.
702
585
        """
703
 
        wt = self.make_branch_and_tree('.')
704
 
        b = wt.branch
705
 
        self.build_tree(['a'])
706
 
        wt.add('a')
707
 
        b.nick = 'test_properties_in_log'
708
 
        wt.commit(message='add a',
709
 
                  timestamp=1132711707,
710
 
                  timezone=36000,
711
 
                  committer='Lorem Ipsum <test@example.com>',
712
 
                  authors=['John Doe <jdoe@example.com>'])
713
 
        sio = StringIO()
714
 
        formatter = log.LongLogFormatter(to_file=sio)
715
 
        try:
716
 
            def trivial_custom_prop_handler(revision):
717
 
                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'}
718
589
 
719
 
            log.properties_handler_registry.register(
720
 
                'trivial_custom_prop_handler',
721
 
                trivial_custom_prop_handler)
722
 
            log.show_log(b, formatter)
723
 
        finally:
724
 
            log.properties_handler_registry.remove(
725
 
                'trivial_custom_prop_handler')
726
 
            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("""\
727
595
------------------------------------------------------------
728
596
revno: 1
729
597
test_prop: test_value
730
598
author: John Doe <jdoe@example.com>
731
599
committer: Lorem Ipsum <test@example.com>
732
600
branch nick: test_properties_in_log
733
 
timestamp: Wed 2005-11-23 12:08:27 +1000
 
601
timestamp: Tue 2005-11-22 00:00:00 +0000
734
602
message:
735
603
  add a
736
 
''',
737
 
                                 sio.getvalue())
 
604
""",
 
605
            wt.branch, log.LongLogFormatter)
738
606
 
739
607
    def test_properties_in_short_log(self):
740
608
        """Log includes the custom properties returned by the registered
741
609
        handlers.
742
610
        """
743
 
        wt = self.make_branch_and_tree('.')
744
 
        b = wt.branch
745
 
        self.build_tree(['a'])
746
 
        wt.add('a')
747
 
        b.nick = 'test_properties_in_short_log'
748
 
        wt.commit(message='add a',
749
 
                  timestamp=1132711707,
750
 
                  timezone=36000,
751
 
                  committer='Lorem Ipsum <test@example.com>',
752
 
                  authors=['John Doe <jdoe@example.com>'])
753
 
        sio = StringIO()
754
 
        formatter = log.ShortLogFormatter(to_file=sio)
755
 
        try:
756
 
            def trivial_custom_prop_handler(revision):
757
 
                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'}
758
614
 
759
 
            log.properties_handler_registry.register(
760
 
                'trivial_custom_prop_handler',
761
 
                trivial_custom_prop_handler)
762
 
            log.show_log(b, formatter)
763
 
        finally:
764
 
            log.properties_handler_registry.remove(
765
 
                'trivial_custom_prop_handler')
766
 
            self.assertEqualDiff('''\
767
 
    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
768
620
      test_prop: test_value
769
621
      add a
770
622
 
771
 
''',
772
 
                                 sio.getvalue())
 
623
""",
 
624
            wt.branch, log.ShortLogFormatter)
773
625
 
774
626
    def test_error_in_properties_handler(self):
775
627
        """Log includes the custom properties returned by the registered
776
628
        handlers.
777
629
        """
778
 
        wt = self.make_branch_and_tree('.')
779
 
        b = wt.branch
780
 
        self.build_tree(['a'])
781
 
        wt.add('a')
782
 
        b.nick = 'test_author_log'
783
 
        wt.commit(message='add a',
784
 
                  timestamp=1132711707,
785
 
                  timezone=36000,
786
 
                  committer='Lorem Ipsum <test@example.com>',
787
 
                  authors=['John Doe <jdoe@example.com>'],
788
 
                  revprops={'first_prop':'first_value'})
789
 
        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()
790
633
        formatter = log.LongLogFormatter(to_file=sio)
791
 
        try:
792
 
            def trivial_custom_prop_handler(revision):
793
 
                raise StandardError("a test error")
 
634
        def trivial_custom_prop_handler(revision):
 
635
            raise StandardError("a test error")
794
636
 
795
 
            log.properties_handler_registry.register(
796
 
                'trivial_custom_prop_handler',
797
 
                trivial_custom_prop_handler)
798
 
            self.assertRaises(StandardError, log.show_log, b, formatter,)
799
 
        finally:
800
 
            log.properties_handler_registry.remove(
801
 
                '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,)
802
641
 
803
642
    def test_properties_handler_bad_argument(self):
804
 
        wt = self.make_branch_and_tree('.')
805
 
        b = wt.branch
806
 
        self.build_tree(['a'])
807
 
        wt.add('a')
808
 
        b.nick = 'test_author_log'
809
 
        wt.commit(message='add a',
810
 
                  timestamp=1132711707,
811
 
                  timezone=36000,
812
 
                  committer='Lorem Ipsum <test@example.com>',
813
 
                  authors=['John Doe <jdoe@example.com>'],
814
 
                  revprops={'a_prop':'test_value'})
815
 
        sio = StringIO()
 
643
        wt = self.make_standard_commit('bad_argument',
 
644
              revprops={'a_prop':'test_value'})
 
645
        sio = self.make_utf8_encoded_stringio()
816
646
        formatter = log.LongLogFormatter(to_file=sio)
817
 
        try:
818
 
            def bad_argument_prop_handler(revision):
819
 
                return {'custom_prop_name':revision.properties['a_prop']}
820
 
 
821
 
            log.properties_handler_registry.register(
822
 
                'bad_argument_prop_handler',
823
 
                bad_argument_prop_handler)
824
 
 
825
 
            self.assertRaises(AttributeError, formatter.show_properties,
826
 
                              'a revision', '')
827
 
 
828
 
            revision = b.repository.get_revision(b.last_revision())
829
 
            formatter.show_properties(revision, '')
830
 
            self.assertEqualDiff('''custom_prop_name: test_value\n''',
831
 
                                 sio.getvalue())
832
 
        finally:
833
 
            log.properties_handler_registry.remove(
834
 
                'bad_argument_prop_handler')
835
 
 
836
 
 
837
 
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):
838
664
 
839
665
    def test_long_verbose_log(self):
840
666
        """Verbose log includes changed files
841
667
 
842
668
        bug #4676
843
669
        """
844
 
        wt = self.make_branch_and_tree('.')
845
 
        b = wt.branch
846
 
        self.build_tree(['a'])
847
 
        wt.add('a')
848
 
        # XXX: why does a longer nick show up?
849
 
        b.nick = 'test_verbose_log'
850
 
        wt.commit(message='add a',
851
 
                  timestamp=1132711707,
852
 
                  timezone=36000,
853
 
                  committer='Lorem Ipsum <test@example.com>')
854
 
        logfile = file('out.tmp', 'w+')
855
 
        formatter = log.LongLogFormatter(to_file=logfile, levels=1)
856
 
        log.show_log(b, formatter, verbose=True)
857
 
        logfile.flush()
858
 
        logfile.seek(0)
859
 
        log_contents = logfile.read()
860
 
        self.assertEqualDiff('''\
 
670
        wt = self.make_standard_commit('test_long_verbose_log', authors=[])
 
671
        self.assertFormatterResult("""\
861
672
------------------------------------------------------------
862
673
revno: 1
863
674
committer: Lorem Ipsum <test@example.com>
864
 
branch nick: test_verbose_log
865
 
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
866
677
message:
867
678
  add a
868
679
added:
869
680
  a
870
 
''',
871
 
                             log_contents)
 
681
""",
 
682
            wt.branch, log.LongLogFormatter,
 
683
            formatter_kwargs=dict(levels=1),
 
684
            show_log_kwargs=dict(verbose=True))
872
685
 
873
686
    def test_long_verbose_contain_deltas(self):
874
687
        wt = self.make_branch_and_tree('parent')
875
688
        self.build_tree(['parent/f1', 'parent/f2'])
876
689
        wt.add(['f1','f2'])
877
 
        wt.commit('first post')
878
 
        self.run_bzr('branch parent child')
 
690
        self.wt_commit(wt, 'first post')
 
691
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
879
692
        os.unlink('child/f1')
880
 
        file('child/f2', 'wb').write('hello\n')
881
 
        self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
882
 
            'child'])
883
 
        os.chdir('parent')
884
 
        self.run_bzr('merge ../child')
885
 
        wt.commit('merge branch 1')
886
 
        b = wt.branch
887
 
        sio = self.make_utf8_encoded_stringio()
888
 
        lf = log.LongLogFormatter(to_file=sio, levels=1)
889
 
        log.show_log(b, lf, verbose=True)
890
 
        the_log = normalize_log(sio.getvalue())
891
 
        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("""\
892
698
------------------------------------------------------------
893
 
revno: 2
894
 
committer: Lorem Ipsum <test@example.com>
 
699
revno: 2 [merge]
 
700
committer: Joe Foo <joe@foo.com>
895
701
branch nick: parent
896
 
timestamp: Just now
 
702
timestamp: Tue 2005-11-22 00:00:02 +0000
897
703
message:
898
704
  merge branch 1
899
705
removed:
902
708
  f2
903
709
------------------------------------------------------------
904
710
revno: 1
905
 
committer: Lorem Ipsum <test@example.com>
 
711
committer: Joe Foo <joe@foo.com>
906
712
branch nick: parent
907
 
timestamp: Just now
 
713
timestamp: Tue 2005-11-22 00:00:00 +0000
908
714
message:
909
715
  first post
910
716
added:
911
717
  f1
912
718
  f2
913
719
""",
914
 
                             the_log)
 
720
            wt.branch, log.LongLogFormatter,
 
721
            formatter_kwargs=dict(levels=1),
 
722
            show_log_kwargs=dict(verbose=True))
915
723
 
916
724
    def test_long_trailing_newlines(self):
917
725
        wt = self.make_branch_and_tree('.')
918
 
        b = make_commits_with_trailing_newlines(wt)
919
 
        sio = self.make_utf8_encoded_stringio()
920
 
        lf = log.LongLogFormatter(to_file=sio, levels=1)
921
 
        log.show_log(b, lf)
922
 
        self.assertEqualDiff("""\
 
726
        b = self.make_commits_with_trailing_newlines(wt)
 
727
        self.assertFormatterResult("""\
923
728
------------------------------------------------------------
924
729
revno: 3
925
730
committer: Joe Foo <joe@foo.com>
926
731
branch nick: test
927
 
timestamp: Mon 2005-11-21 09:32:56 -0600
 
732
timestamp: Tue 2005-11-22 00:00:02 +0000
928
733
message:
929
734
  single line with trailing newline
930
735
------------------------------------------------------------
931
736
revno: 2
932
 
author: Joe Bar <joe@bar.com>
933
737
committer: Joe Foo <joe@foo.com>
934
738
branch nick: test
935
 
timestamp: Mon 2005-11-21 09:27:22 -0600
 
739
timestamp: Tue 2005-11-22 00:00:01 +0000
936
740
message:
937
741
  multiline
938
742
  log
941
745
revno: 1
942
746
committer: Joe Foo <joe@foo.com>
943
747
branch nick: test
944
 
timestamp: Mon 2005-11-21 09:24:15 -0600
 
748
timestamp: Tue 2005-11-22 00:00:00 +0000
945
749
message:
946
750
  simple log message
947
751
""",
948
 
                             sio.getvalue())
 
752
        b, log.LongLogFormatter,
 
753
        formatter_kwargs=dict(levels=1))
949
754
 
950
755
    def test_long_author_in_log(self):
951
756
        """Log includes the author name if it's set in
952
757
        the revision properties
953
758
        """
954
 
        wt = self.make_branch_and_tree('.')
955
 
        b = wt.branch
956
 
        self.build_tree(['a'])
957
 
        wt.add('a')
958
 
        b.nick = 'test_author_log'
959
 
        wt.commit(message='add a',
960
 
                  timestamp=1132711707,
961
 
                  timezone=36000,
962
 
                  committer='Lorem Ipsum <test@example.com>',
963
 
                  authors=['John Doe <jdoe@example.com>'])
964
 
        sio = StringIO()
965
 
        formatter = log.LongLogFormatter(to_file=sio, levels=1)
966
 
        log.show_log(b, formatter)
967
 
        self.assertEqualDiff('''\
 
759
        wt = self.make_standard_commit('test_author_log')
 
760
        self.assertFormatterResult("""\
968
761
------------------------------------------------------------
969
762
revno: 1
970
763
author: John Doe <jdoe@example.com>
971
764
committer: Lorem Ipsum <test@example.com>
972
765
branch nick: test_author_log
973
 
timestamp: Wed 2005-11-23 12:08:27 +1000
 
766
timestamp: Tue 2005-11-22 00:00:00 +0000
974
767
message:
975
768
  add a
976
 
''',
977
 
                             sio.getvalue())
 
769
""",
 
770
            wt.branch, log.LongLogFormatter,
 
771
            formatter_kwargs=dict(levels=1))
978
772
 
979
773
    def test_long_properties_in_log(self):
980
774
        """Log includes the custom properties returned by the registered
981
775
        handlers.
982
776
        """
983
 
        wt = self.make_branch_and_tree('.')
984
 
        b = wt.branch
985
 
        self.build_tree(['a'])
986
 
        wt.add('a')
987
 
        b.nick = 'test_properties_in_log'
988
 
        wt.commit(message='add a',
989
 
                  timestamp=1132711707,
990
 
                  timezone=36000,
991
 
                  committer='Lorem Ipsum <test@example.com>',
992
 
                  authors=['John Doe <jdoe@example.com>'])
993
 
        sio = StringIO()
994
 
        formatter = log.LongLogFormatter(to_file=sio, levels=1)
995
 
        try:
996
 
            def trivial_custom_prop_handler(revision):
997
 
                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'}
998
780
 
999
 
            log.properties_handler_registry.register(
1000
 
                'trivial_custom_prop_handler',
1001
 
                trivial_custom_prop_handler)
1002
 
            log.show_log(b, formatter)
1003
 
        finally:
1004
 
            log.properties_handler_registry.remove(
1005
 
                'trivial_custom_prop_handler')
1006
 
            self.assertEqualDiff('''\
 
781
        log.properties_handler_registry.register(
 
782
            'trivial_custom_prop_handler',
 
783
            trivial_custom_prop_handler)
 
784
        self.assertFormatterResult("""\
1007
785
------------------------------------------------------------
1008
786
revno: 1
1009
787
test_prop: test_value
1010
788
author: John Doe <jdoe@example.com>
1011
789
committer: Lorem Ipsum <test@example.com>
1012
790
branch nick: test_properties_in_log
1013
 
timestamp: Wed 2005-11-23 12:08:27 +1000
 
791
timestamp: Tue 2005-11-22 00:00:00 +0000
1014
792
message:
1015
793
  add a
1016
 
''',
1017
 
                                 sio.getvalue())
1018
 
 
1019
 
 
1020
 
class TestLineLogFormatter(tests.TestCaseWithTransport):
 
794
""",
 
795
            wt.branch, log.LongLogFormatter,
 
796
            formatter_kwargs=dict(levels=1))
 
797
 
 
798
 
 
799
class TestLineLogFormatter(TestCaseForLogFormatter):
1021
800
 
1022
801
    def test_line_log(self):
1023
802
        """Line log should show revno
1024
803
 
1025
804
        bug #5162
1026
805
        """
1027
 
        wt = self.make_branch_and_tree('.')
1028
 
        b = wt.branch
1029
 
        self.build_tree(['a'])
1030
 
        wt.add('a')
1031
 
        b.nick = 'test-line-log'
1032
 
        wt.commit(message='add a',
1033
 
                  timestamp=1132711707,
1034
 
                  timezone=36000,
1035
 
                  committer='Line-Log-Formatter Tester <test@line.log>')
1036
 
        logfile = file('out.tmp', 'w+')
1037
 
        formatter = log.LineLogFormatter(to_file=logfile)
1038
 
        log.show_log(b, formatter)
1039
 
        logfile.flush()
1040
 
        logfile.seek(0)
1041
 
        log_contents = logfile.read()
1042
 
        self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
1043
 
                             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)
1044
813
 
1045
814
    def test_trailing_newlines(self):
1046
815
        wt = self.make_branch_and_tree('.')
1047
 
        b = make_commits_with_trailing_newlines(wt)
1048
 
        sio = self.make_utf8_encoded_stringio()
1049
 
        lf = log.LineLogFormatter(to_file=sio)
1050
 
        log.show_log(b, lf)
1051
 
        self.assertEqualDiff("""\
1052
 
3: Joe Foo 2005-11-21 single line with trailing newline
1053
 
2: Joe Bar 2005-11-21 multiline
1054
 
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
1055
821
""",
1056
 
                             sio.getvalue())
1057
 
 
1058
 
    def _prepare_tree_with_merges(self, with_tags=False):
1059
 
        wt = self.make_branch_and_memory_tree('.')
1060
 
        wt.lock_write()
1061
 
        self.addCleanup(wt.unlock)
1062
 
        wt.add('')
1063
 
        wt.commit('rev-1', rev_id='rev-1',
1064
 
                  timestamp=1132586655, timezone=36000,
1065
 
                  committer='Joe Foo <joe@foo.com>')
1066
 
        wt.commit('rev-merged', rev_id='rev-2a',
1067
 
                  timestamp=1132586700, timezone=36000,
1068
 
                  committer='Joe Foo <joe@foo.com>')
1069
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
1070
 
        wt.branch.set_last_revision_info(1, 'rev-1')
1071
 
        wt.commit('rev-2', rev_id='rev-2b',
1072
 
                  timestamp=1132586800, timezone=36000,
1073
 
                  committer='Joe Foo <joe@foo.com>')
1074
 
        if with_tags:
1075
 
            branch = wt.branch
1076
 
            branch.tags.set_tag('v0.2', 'rev-2b')
1077
 
            wt.commit('rev-3', rev_id='rev-3',
1078
 
                      timestamp=1132586900, timezone=36000,
1079
 
                      committer='Jane Foo <jane@foo.com>')
1080
 
            branch.tags.set_tag('v1.0rc1', 'rev-3')
1081
 
            branch.tags.set_tag('v1.0', 'rev-3')
1082
 
        return wt
 
822
            b, log.LineLogFormatter)
1083
823
 
1084
824
    def test_line_log_single_merge_revision(self):
1085
825
        wt = self._prepare_tree_with_merges()
1086
 
        logfile = self.make_utf8_encoded_stringio()
1087
 
        formatter = log.LineLogFormatter(to_file=logfile)
1088
826
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1089
 
        wtb = wt.branch
1090
 
        rev = revspec.in_history(wtb)
1091
 
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1092
 
        self.assertEqualDiff("""\
 
827
        rev = revspec.in_history(wt.branch)
 
828
        self.assertFormatterResult("""\
1093
829
1.1.1: Joe Foo 2005-11-22 rev-merged
1094
830
""",
1095
 
                             logfile.getvalue())
 
831
            wt.branch, log.LineLogFormatter,
 
832
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1096
833
 
1097
834
    def test_line_log_with_tags(self):
1098
835
        wt = self._prepare_tree_with_merges(with_tags=True)
1099
 
        logfile = self.make_utf8_encoded_stringio()
1100
 
        formatter = log.LineLogFormatter(to_file=logfile)
1101
 
        log.show_log(wt.branch, formatter)
1102
 
        self.assertEqualDiff("""\
1103
 
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
1104
838
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
1105
839
1: Joe Foo 2005-11-22 rev-1
1106
840
""",
1107
 
                             logfile.getvalue())
1108
 
 
1109
 
class TestLineLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
 
841
            wt.branch, log.LineLogFormatter)
 
842
 
 
843
 
 
844
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
1110
845
 
1111
846
    def test_line_merge_revs_log(self):
1112
847
        """Line log should show revno
1113
848
 
1114
849
        bug #5162
1115
850
        """
1116
 
        wt = self.make_branch_and_tree('.')
1117
 
        b = wt.branch
1118
 
        self.build_tree(['a'])
1119
 
        wt.add('a')
1120
 
        b.nick = 'test-line-log'
1121
 
        wt.commit(message='add a',
1122
 
                  timestamp=1132711707,
1123
 
                  timezone=36000,
1124
 
                  committer='Line-Log-Formatter Tester <test@line.log>')
1125
 
        logfile = file('out.tmp', 'w+')
1126
 
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1127
 
        log.show_log(b, formatter)
1128
 
        logfile.flush()
1129
 
        logfile.seek(0)
1130
 
        log_contents = logfile.read()
1131
 
        self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
1132
 
                             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)
1133
858
 
1134
859
    def test_line_merge_revs_log_single_merge_revision(self):
1135
 
        wt = self.make_branch_and_memory_tree('.')
1136
 
        wt.lock_write()
1137
 
        self.addCleanup(wt.unlock)
1138
 
        wt.add('')
1139
 
        wt.commit('rev-1', rev_id='rev-1',
1140
 
                  timestamp=1132586655, timezone=36000,
1141
 
                  committer='Joe Foo <joe@foo.com>')
1142
 
        wt.commit('rev-merged', rev_id='rev-2a',
1143
 
                  timestamp=1132586700, timezone=36000,
1144
 
                  committer='Joe Foo <joe@foo.com>')
1145
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
1146
 
        wt.branch.set_last_revision_info(1, 'rev-1')
1147
 
        wt.commit('rev-2', rev_id='rev-2b',
1148
 
                  timestamp=1132586800, timezone=36000,
1149
 
                  committer='Joe Foo <joe@foo.com>')
1150
 
        logfile = self.make_utf8_encoded_stringio()
1151
 
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
 
860
        wt = self._prepare_tree_with_merges()
1152
861
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1153
 
        wtb = wt.branch
1154
 
        rev = revspec.in_history(wtb)
1155
 
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1156
 
        self.assertEqualDiff("""\
 
862
        rev = revspec.in_history(wt.branch)
 
863
        self.assertFormatterResult("""\
1157
864
1.1.1: Joe Foo 2005-11-22 rev-merged
1158
865
""",
1159
 
                             logfile.getvalue())
 
866
            wt.branch, log.LineLogFormatter,
 
867
            formatter_kwargs=dict(levels=0),
 
868
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
1160
869
 
1161
870
    def test_line_merge_revs_log_with_merges(self):
1162
 
        wt = self.make_branch_and_memory_tree('.')
1163
 
        wt.lock_write()
1164
 
        self.addCleanup(wt.unlock)
1165
 
        wt.add('')
1166
 
        wt.commit('rev-1', rev_id='rev-1',
1167
 
                  timestamp=1132586655, timezone=36000,
1168
 
                  committer='Joe Foo <joe@foo.com>')
1169
 
        wt.commit('rev-merged', rev_id='rev-2a',
1170
 
                  timestamp=1132586700, timezone=36000,
1171
 
                  committer='Joe Foo <joe@foo.com>')
1172
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
1173
 
        wt.branch.set_last_revision_info(1, 'rev-1')
1174
 
        wt.commit('rev-2', rev_id='rev-2b',
1175
 
                  timestamp=1132586800, timezone=36000,
1176
 
                  committer='Joe Foo <joe@foo.com>')
1177
 
        logfile = self.make_utf8_encoded_stringio()
1178
 
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
1179
 
        log.show_log(wt.branch, formatter)
1180
 
        self.assertEqualDiff("""\
 
871
        wt = self._prepare_tree_with_merges()
 
872
        self.assertFormatterResult("""\
1181
873
2: Joe Foo 2005-11-22 [merge] rev-2
1182
874
  1.1.1: Joe Foo 2005-11-22 rev-merged
1183
875
1: Joe Foo 2005-11-22 rev-1
1184
876
""",
1185
 
                             logfile.getvalue())
1186
 
 
1187
 
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)
1188
923
 
1189
924
    def make_tree_with_commits(self):
1190
925
        """Create a tree with well-known revision ids"""
1191
926
        wt = self.make_branch_and_tree('tree1')
1192
 
        wt.commit('commit one', rev_id='1')
1193
 
        wt.commit('commit two', rev_id='2')
1194
 
        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')
1195
930
        mainline_revs = [None, '1', '2', '3']
1196
931
        rev_nos = {'1': 1, '2': 2, '3': 3}
1197
932
        return mainline_revs, rev_nos, wt
1200
935
        """Create a tree with well-known revision ids and a merge"""
1201
936
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1202
937
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1203
 
        tree2.commit('four-a', rev_id='4a')
 
938
        self.wt_commit(tree2, 'four-a', rev_id='4a')
1204
939
        wt.merge_from_branch(tree2.branch)
1205
 
        wt.commit('four-b', rev_id='4b')
 
940
        self.wt_commit(wt, 'four-b', rev_id='4b')
1206
941
        mainline_revs.append('4b')
1207
942
        rev_nos['4b'] = 4
1208
943
        # 4a: 3.1.1
1209
944
        return mainline_revs, rev_nos, wt
1210
945
 
1211
 
    def make_tree_with_many_merges(self):
 
946
    def make_branch_with_many_merges(self):
1212
947
        """Create a tree with well-known revision ids"""
1213
 
        wt = self.make_branch_and_tree('tree1')
1214
 
        self.build_tree_contents([('tree1/f', '1\n')])
1215
 
        wt.add(['f'], ['f-id'])
1216
 
        wt.commit('commit one', rev_id='1')
1217
 
        wt.commit('commit two', rev_id='2')
1218
 
 
1219
 
        tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
1220
 
        self.build_tree_contents([('tree3/f', '1\n2\n3a\n')])
1221
 
        tree3.commit('commit three a', rev_id='3a')
1222
 
 
1223
 
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1224
 
        tree2.merge_from_branch(tree3.branch)
1225
 
        tree2.commit('commit three b', rev_id='3b')
1226
 
 
1227
 
        wt.merge_from_branch(tree2.branch)
1228
 
        wt.commit('commit three c', rev_id='3c')
1229
 
        tree2.commit('four-a', rev_id='4a')
1230
 
 
1231
 
        wt.merge_from_branch(tree2.branch)
1232
 
        wt.commit('four-b', rev_id='4b')
 
948
        builder = self.make_branch_builder('tree1')
 
949
        builder.start_series()
 
950
        builder.build_snapshot('1', None, [
 
951
            ('add', ('', 'TREE_ROOT', 'directory', '')),
 
952
            ('add', ('f', 'f-id', 'file', '1\n'))])
 
953
        builder.build_snapshot('2', ['1'], [])
 
954
        builder.build_snapshot('3a', ['2'], [
 
955
            ('modify', ('f-id', '1\n2\n3a\n'))])
 
956
        builder.build_snapshot('3b', ['2', '3a'], [
 
957
            ('modify', ('f-id', '1\n2\n3a\n'))])
 
958
        builder.build_snapshot('3c', ['2', '3b'], [
 
959
            ('modify', ('f-id', '1\n2\n3a\n'))])
 
960
        builder.build_snapshot('4a', ['3b'], [])
 
961
        builder.build_snapshot('4b', ['3c', '4a'], [])
 
962
        builder.finish_series()
 
963
 
 
964
        # 1
 
965
        # |
 
966
        # 2-.
 
967
        # |\ \
 
968
        # | | 3a
 
969
        # | |/
 
970
        # | 3b
 
971
        # |/|
 
972
        # 3c4a
 
973
        # |/
 
974
        # 4b
1233
975
 
1234
976
        mainline_revs = [None, '1', '2', '3c', '4b']
1235
977
        rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
1242
984
            '4a': '2.2.2', # second commit tree 2
1243
985
            '4b': '4', # merges 4a to main
1244
986
            }
1245
 
        return mainline_revs, rev_nos, wt
 
987
        return mainline_revs, rev_nos, builder.get_branch()
1246
988
 
1247
989
    def test_get_view_revisions_forward(self):
1248
990
        """Test the get_view_revisions method"""
1249
991
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1250
992
        wt.lock_read()
1251
993
        self.addCleanup(wt.unlock)
1252
 
        revisions = list(log.get_view_revisions(
 
994
        revisions = list(self._get_view_revisions(
1253
995
                mainline_revs, rev_nos, wt.branch, 'forward'))
1254
996
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
1255
997
                         revisions)
1256
 
        revisions2 = list(log.get_view_revisions(
 
998
        revisions2 = list(self._get_view_revisions(
1257
999
                mainline_revs, rev_nos, wt.branch, 'forward',
1258
1000
                include_merges=False))
1259
1001
        self.assertEqual(revisions, revisions2)
1263
1005
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1264
1006
        wt.lock_read()
1265
1007
        self.addCleanup(wt.unlock)
1266
 
        revisions = list(log.get_view_revisions(
 
1008
        revisions = list(self._get_view_revisions(
1267
1009
                mainline_revs, rev_nos, wt.branch, 'reverse'))
1268
1010
        self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
1269
1011
                         revisions)
1270
 
        revisions2 = list(log.get_view_revisions(
 
1012
        revisions2 = list(self._get_view_revisions(
1271
1013
                mainline_revs, rev_nos, wt.branch, 'reverse',
1272
1014
                include_merges=False))
1273
1015
        self.assertEqual(revisions, revisions2)
1277
1019
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1278
1020
        wt.lock_read()
1279
1021
        self.addCleanup(wt.unlock)
1280
 
        revisions = list(log.get_view_revisions(
 
1022
        revisions = list(self._get_view_revisions(
1281
1023
                mainline_revs, rev_nos, wt.branch, 'forward'))
1282
1024
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1283
1025
                          ('4b', '4', 0), ('4a', '3.1.1', 1)],
1284
1026
                         revisions)
1285
 
        revisions = list(log.get_view_revisions(
 
1027
        revisions = list(self._get_view_revisions(
1286
1028
                mainline_revs, rev_nos, wt.branch, 'forward',
1287
1029
                include_merges=False))
1288
1030
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1294
1036
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1295
1037
        wt.lock_read()
1296
1038
        self.addCleanup(wt.unlock)
1297
 
        revisions = list(log.get_view_revisions(
 
1039
        revisions = list(self._get_view_revisions(
1298
1040
                mainline_revs, rev_nos, wt.branch, 'reverse'))
1299
1041
        self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
1300
1042
                          ('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
1301
1043
                         revisions)
1302
 
        revisions = list(log.get_view_revisions(
 
1044
        revisions = list(self._get_view_revisions(
1303
1045
                mainline_revs, rev_nos, wt.branch, 'reverse',
1304
1046
                include_merges=False))
1305
1047
        self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
1308
1050
 
1309
1051
    def test_get_view_revisions_merge2(self):
1310
1052
        """Test get_view_revisions when there are merges"""
1311
 
        mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1312
 
        wt.lock_read()
1313
 
        self.addCleanup(wt.unlock)
1314
 
        revisions = list(log.get_view_revisions(
1315
 
                mainline_revs, rev_nos, wt.branch, 'forward'))
 
1053
        mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
 
1054
        b.lock_read()
 
1055
        self.addCleanup(b.unlock)
 
1056
        revisions = list(self._get_view_revisions(
 
1057
                mainline_revs, rev_nos, b, 'forward'))
1316
1058
        expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1317
 
                    ('3a', '2.1.1', 1), ('3b', '2.2.1', 1), ('4b', '4', 0),
 
1059
                    ('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1318
1060
                    ('4a', '2.2.2', 1)]
1319
1061
        self.assertEqual(expected, revisions)
1320
 
        revisions = list(log.get_view_revisions(
1321
 
                mainline_revs, rev_nos, wt.branch, 'forward',
 
1062
        revisions = list(self._get_view_revisions(
 
1063
                mainline_revs, rev_nos, b, 'forward',
1322
1064
                include_merges=False))
1323
1065
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1324
1066
                          ('4b', '4', 0)],
1325
1067
                         revisions)
1326
1068
 
1327
 
 
1328
1069
    def test_file_id_for_range(self):
1329
 
        mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
1330
 
        wt.lock_read()
1331
 
        self.addCleanup(wt.unlock)
 
1070
        mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
 
1071
        b.lock_read()
 
1072
        self.addCleanup(b.unlock)
1332
1073
 
1333
1074
        def rev_from_rev_id(revid, branch):
1334
1075
            revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1335
1076
            return revspec.in_history(branch)
1336
1077
 
1337
1078
        def view_revs(start_rev, end_rev, file_id, direction):
1338
 
            revs = log.calculate_view_revisions(
1339
 
                wt.branch,
 
1079
            revs = self.applyDeprecated(
 
1080
                symbol_versioning.deprecated_in((2, 2, 0)),
 
1081
                log.calculate_view_revisions,
 
1082
                b,
1340
1083
                start_rev, # start_revision
1341
1084
                end_rev, # end_revision
1342
1085
                direction, # direction
1343
1086
                file_id, # specific_fileid
1344
1087
                True, # generate_merge_revisions
1345
 
                True, # allow_single_merge_revision
1346
1088
                )
1347
1089
            return revs
1348
1090
 
1349
 
        rev_3a = rev_from_rev_id('3a', wt.branch)
1350
 
        rev_4b = rev_from_rev_id('4b', wt.branch)
1351
 
        self.assertEqual([('3c', '3', 0), ('3a', '2.1.1', 1)],
 
1091
        rev_3a = rev_from_rev_id('3a', b)
 
1092
        rev_4b = rev_from_rev_id('4b', b)
 
1093
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
 
1094
                          ('3a', '2.1.1', 2)],
1352
1095
                          view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
1353
1096
        # Note: 3c still appears before 3a here because of depth-based sorting
1354
 
        self.assertEqual([('3c', '3', 0), ('3a', '2.1.1', 1)],
 
1097
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
 
1098
                          ('3a', '2.1.1', 2)],
1355
1099
                          view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1356
1100
 
1357
1101
 
1358
1102
class TestGetRevisionsTouchingFileID(tests.TestCaseWithTransport):
1359
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
 
1360
1108
    def create_tree_with_single_merge(self):
1361
1109
        """Create a branch with a moderate layout.
1362
1110
 
1380
1128
        #       use it. Since 'log' only uses the tree in a readonly
1381
1129
        #       fashion, it seems a shame to regenerate an identical
1382
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.
1383
1136
        tree = self.make_branch_and_tree('tree')
1384
1137
        tree.lock_write()
1385
1138
        self.addCleanup(tree.unlock)
1460
1213
        mainline = tree.branch.revision_history()
1461
1214
        mainline.insert(0, None)
1462
1215
        revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
1463
 
        view_revs_iter = log.get_view_revisions(mainline, revnos, tree.branch,
1464
 
                                                'reverse', True)
 
1216
        view_revs_iter = self.get_view_revisions(
 
1217
            mainline, revnos, tree.branch, 'reverse', True)
1465
1218
        actual_revs = log._filter_revisions_touching_file_id(
1466
 
                            tree.branch,
1467
 
                            file_id,
1468
 
                            list(view_revs_iter))
 
1219
            tree.branch, file_id, list(view_revs_iter))
1469
1220
        self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
1470
1221
 
1471
1222
    def test_file_id_f1(self):
1523
1274
 
1524
1275
class TestLogFormatter(tests.TestCase):
1525
1276
 
 
1277
    def setUp(self):
 
1278
        super(TestLogFormatter, self).setUp()
 
1279
        self.rev = revision.Revision('a-id')
 
1280
        self.lf = log.LogFormatter(None)
 
1281
 
1526
1282
    def test_short_committer(self):
1527
 
        rev = revision.Revision('a-id')
1528
 
        rev.committer = 'John Doe <jdoe@example.com>'
1529
 
        lf = log.LogFormatter(None)
1530
 
        self.assertEqual('John Doe', lf.short_committer(rev))
1531
 
        rev.committer = 'John Smith <jsmith@example.com>'
1532
 
        self.assertEqual('John Smith', lf.short_committer(rev))
1533
 
        rev.committer = 'John Smith'
1534
 
        self.assertEqual('John Smith', lf.short_committer(rev))
1535
 
        rev.committer = 'jsmith@example.com'
1536
 
        self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1537
 
        rev.committer = '<jsmith@example.com>'
1538
 
        self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1539
 
        rev.committer = 'John Smith jsmith@example.com'
1540
 
        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')
1541
1293
 
1542
1294
    def test_short_author(self):
1543
 
        rev = revision.Revision('a-id')
1544
 
        rev.committer = 'John Doe <jdoe@example.com>'
1545
 
        lf = log.LogFormatter(None)
1546
 
        self.assertEqual('John Doe', lf.short_author(rev))
1547
 
        rev.properties['author'] = 'John Smith <jsmith@example.com>'
1548
 
        self.assertEqual('John Smith', lf.short_author(rev))
1549
 
        rev.properties['author'] = 'John Smith'
1550
 
        self.assertEqual('John Smith', 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'] = '<jsmith@example.com>'
1554
 
        self.assertEqual('jsmith@example.com', lf.short_author(rev))
1555
 
        rev.properties['author'] = 'John Smith jsmith@example.com'
1556
 
        self.assertEqual('John Smith', lf.short_author(rev))
1557
 
        del rev.properties['author']
1558
 
        rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1559
 
                'Jane Rey <jrey@example.com>')
1560
 
        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))
1561
1313
 
1562
1314
 
1563
1315
class TestReverseByDepth(tests.TestCase):
1709
1461
        log.show_branch_change(tree.branch, s, 3, '3b')
1710
1462
        self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1711
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, generate_merge_revisions=True):
 
1728
        # FIXME: the layering in log makes it hard to test intermediate levels,
 
1729
        # I wish adding filters with their parameters were easier...
 
1730
        # -- vila 20100413
 
1731
        iter_revs = log._calc_view_revisions(
 
1732
            b, start, end, direction='reverse',
 
1733
            generate_merge_revisions=generate_merge_revisions,
 
1734
            exclude_common_ancestry=exclude_common_ancestry)
 
1735
        self.assertEqual(expected_revnos,
 
1736
                         [revid for revid, revno, depth in iter_revs])
 
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', exclude_common_ancestry=False)
 
1742
        # '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
 
1743
        # it should be mentioned even if merge_sort order will make it appear
 
1744
        # after 1.1.1
 
1745
        self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
 
1746
                             b, '1.1.1', '3', exclude_common_ancestry=True)
 
1747
 
 
1748
    def test_merge_sorted_simple_revnos_exclude_ancestry(self):
 
1749
        b = self.make_branch_with_alternate_ancestries()
 
1750
        self.assertLogRevnos(['3', '2'],
 
1751
                             b, '1', '3', exclude_common_ancestry=True,
 
1752
                             generate_merge_revisions=False)
 
1753
        self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2'],
 
1754
                             b, '1', '3', exclude_common_ancestry=True,
 
1755
                             generate_merge_revisions=True)
 
1756