~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_log.py

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