/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1685.1.80 by Wouter van Heyst
more code cleanup
2
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1685.1.80 by Wouter van Heyst
more code cleanup
7
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1685.1.80 by Wouter van Heyst
more code cleanup
12
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
import os
1123 by Martin Pool
* move bzr-specific code from testsweet into bzrlib.selftest
18
from cStringIO import StringIO
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
19
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
20
from bzrlib import log, registry
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
21
from bzrlib.tests import TestCase, TestCaseWithTransport
2490.1.2 by John Arbash Meinel
Cleanup according to PEP8 and some other small whitespace fixes
22
from bzrlib.log import (show_log,
23
                        get_view_revisions,
2466.8.1 by Kent Gibson
Reworked LogFormatter API to simplify extending the attributes of the revision being logged. Added support for begin_log() and end_log() hooks in LogFormatters.
24
                        LogRevision,
2490.1.2 by John Arbash Meinel
Cleanup according to PEP8 and some other small whitespace fixes
25
                        LogFormatter,
26
                        LongLogFormatter,
27
                        ShortLogFormatter,
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
28
                        LineLogFormatter)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
29
from bzrlib.branch import Branch
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
30
from bzrlib.errors import (
31
    BzrCommandError,
32
    InvalidRevisionNumber,
33
    )
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
34
from bzrlib.revision import Revision
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
35
from bzrlib.revisionspec import (
36
    RevisionInfo,
37
    RevisionSpec,
38
    )
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
39
1685.1.69 by Wouter van Heyst
merge bzr.dev 1740
40
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
41
class TestCaseWithoutPropsHandler(TestCaseWithTransport):
42
43
    def setUp(self):
44
        super(TestCaseWithoutPropsHandler, self).setUp()
45
        # keep a reference to the "current" custom prop. handler registry
46
        self.properties_handler_registry = \
47
            log.properties_handler_registry
48
        # clean up the registry in log
49
        log.properties_handler_registry = registry.Registry()
50
        
51
    def _cleanup(self):
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
52
        super(TestCaseWithoutPropsHandler, self)._cleanup()
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
53
        # restore the custom properties handler registry
54
        log.properties_handler_registry = \
55
            self.properties_handler_registry
56
57
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
58
class LogCatcher(LogFormatter):
59
    """Pull log messages into list rather than displaying them.
60
61
    For ease of testing we save log messages here rather than actually
62
    formatting them, so that we can precisely check the result without
63
    being too dependent on the exact formatting.
64
65
    We should also test the LogFormatter.
66
    """
2466.8.1 by Kent Gibson
Reworked LogFormatter API to simplify extending the attributes of the revision being logged. Added support for begin_log() and end_log() hooks in LogFormatters.
67
2490.1.2 by John Arbash Meinel
Cleanup according to PEP8 and some other small whitespace fixes
68
    supports_delta = True
2466.8.1 by Kent Gibson
Reworked LogFormatter API to simplify extending the attributes of the revision being logged. Added support for begin_log() and end_log() hooks in LogFormatters.
69
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
70
    def __init__(self):
71
        super(LogCatcher, self).__init__(to_file=None)
72
        self.logs = []
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
73
2466.8.1 by Kent Gibson
Reworked LogFormatter API to simplify extending the attributes of the revision being logged. Added support for begin_log() and end_log() hooks in LogFormatters.
74
    def log_revision(self, revision):
75
        self.logs.append(revision)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
76
77
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
78
class TestShowLog(TestCaseWithTransport):
1102 by Martin Pool
- merge test refactoring from robertc
79
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
80
    def checkDelta(self, delta, **kw):
81
        """Check the filenames touched by a delta are as expected."""
82
        for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
83
            expected = kw.get(n, [])
84
            # strip out only the path components
85
            got = [x[0] for x in getattr(delta, n)]
86
            self.assertEquals(expected, got)
87
974.1.54 by aaron.bentley at utoronto
Fixed the revno bug in log
88
    def test_cur_revno(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
89
        wt = self.make_branch_and_tree('.')
90
        b = wt.branch
1092.3.4 by Robert Collins
update symlink branch to integration
91
92
        lf = LogCatcher()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
93
        wt.commit('empty commit')
1092.3.4 by Robert Collins
update symlink branch to integration
94
        show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
95
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
96
                          start_revision=2, end_revision=1) 
97
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
98
                          start_revision=1, end_revision=2) 
99
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
100
                          start_revision=0, end_revision=2) 
101
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
102
                          start_revision=1, end_revision=0) 
103
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
104
                          start_revision=-1, end_revision=1) 
105
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
106
                          start_revision=1, end_revision=-1) 
107
1102 by Martin Pool
- merge test refactoring from robertc
108
    def test_simple_log(self):
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
109
        eq = self.assertEquals
110
        
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
111
        wt = self.make_branch_and_tree('.')
112
        b = wt.branch
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
113
114
        lf = LogCatcher()
115
        show_log(b, lf)
116
        # no entries yet
117
        eq(lf.logs, [])
118
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
119
        wt.commit('empty commit')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
120
        lf = LogCatcher()
121
        show_log(b, lf, verbose=True)
122
        eq(len(lf.logs), 1)
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
123
        eq(lf.logs[0].revno, '1')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
124
        eq(lf.logs[0].rev.message, 'empty commit')
125
        d = lf.logs[0].delta
126
        self.log('log delta: %r' % d)
127
        self.checkDelta(d)
128
129
        self.build_tree(['hello'])
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
130
        wt.add('hello')
2717.1.1 by Lukáš Lalinsky
Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names.
131
        wt.commit('add one file',
132
                  committer=u'\u013d\xf3r\xe9m \xcdp\u0161\xfam '
133
                            u'<test@example.com>')
1123 by Martin Pool
* move bzr-specific code from testsweet into bzrlib.selftest
134
2717.1.1 by Lukáš Lalinsky
Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names.
135
        lf = self.make_utf8_encoded_stringio()
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
136
        # log using regular thing
1123 by Martin Pool
* move bzr-specific code from testsweet into bzrlib.selftest
137
        show_log(b, LongLogFormatter(lf))
138
        lf.seek(0)
139
        for l in lf.readlines():
140
            self.log(l)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
141
142
        # get log as data structure
143
        lf = LogCatcher()
144
        show_log(b, lf, verbose=True)
145
        eq(len(lf.logs), 2)
146
        self.log('log entries:')
147
        for logentry in lf.logs:
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
148
            self.log('%4s %s' % (logentry.revno, logentry.rev.message))
3831.1.6 by John Arbash Meinel
For the simple-log tests, avoid using '\r' in the test.
149
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
150
        # first one is most recent
151
        logentry = lf.logs[0]
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
152
        eq(logentry.revno, '2')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
153
        eq(logentry.rev.message, 'add one file')
154
        d = logentry.delta
155
        self.log('log 2 delta: %r' % d)
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
156
        self.checkDelta(d, added=['hello'])
3831.1.6 by John Arbash Meinel
For the simple-log tests, avoid using '\r' in the test.
157
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
158
        # commit a log message with control characters
3831.1.6 by John Arbash Meinel
For the simple-log tests, avoid using '\r' in the test.
159
        msg = u"All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)])
160
        msg = msg.replace(u'\r', u'\n')
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
161
        self.log("original commit message: %r", msg)
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
162
        wt.commit(msg)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
163
        lf = LogCatcher()
164
        show_log(b, lf, verbose=True)
165
        committed_msg = lf.logs[0].rev.message
166
        self.log("escaped commit message: %r", committed_msg)
167
        self.assert_(msg != committed_msg)
168
        self.assert_(len(committed_msg) > len(msg))
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
169
170
        # Check that log message with only XML-valid characters isn't
171
        # escaped.  As ElementTree apparently does some kind of
172
        # newline conversion, neither LF (\x0A) nor CR (\x0D) are
173
        # included in the test commit message, even though they are
174
        # valid XML 1.0 characters.
175
        msg = "\x09" + ''.join([unichr(x) for x in range(0x20, 256)])
176
        self.log("original commit message: %r", msg)
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
177
        wt.commit(msg)
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
178
        lf = LogCatcher()
179
        show_log(b, lf, verbose=True)
180
        committed_msg = lf.logs[0].rev.message
181
        self.log("escaped commit message: %r", committed_msg)
182
        self.assert_(msg == committed_msg)
1185.31.22 by John Arbash Meinel
[merge] bzr.dev
183
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
184
    def test_deltas_in_merge_revisions(self):
185
        """Check deltas created for both mainline and merge revisions"""
186
        eq = self.assertEquals
187
        wt = self.make_branch_and_tree('parent')
188
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
189
        wt.add('file1')
190
        wt.add('file2')
191
        wt.commit(message='add file1 and file2')
2581.1.6 by Martin Pool
fix up more run_bzr callers
192
        self.run_bzr('branch parent child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
193
        os.unlink('child/file1')
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
194
        file('child/file2', 'wb').write('hello\n')
2581.1.6 by Martin Pool
fix up more run_bzr callers
195
        self.run_bzr(['commit', '-m', 'remove file1 and modify file2',
196
            'child'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
197
        os.chdir('parent')
2581.1.6 by Martin Pool
fix up more run_bzr callers
198
        self.run_bzr('merge ../child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
199
        wt.commit('merge child branch')
200
        os.chdir('..')
201
        b = wt.branch
202
        lf = LogCatcher()
203
        lf.supports_merge_revisions = True
204
        show_log(b, lf, verbose=True)
205
        eq(len(lf.logs),3)
206
        logentry = lf.logs[0]
207
        eq(logentry.revno, '2')
208
        eq(logentry.rev.message, 'merge child branch')
209
        d = logentry.delta
210
        self.checkDelta(d, removed=['file1'], modified=['file2'])
211
        logentry = lf.logs[1]
212
        eq(logentry.revno, '1.1.1')
213
        eq(logentry.rev.message, 'remove file1 and modify file2')
214
        d = logentry.delta
215
        self.checkDelta(d, removed=['file1'], modified=['file2'])
216
        logentry = lf.logs[2]
217
        eq(logentry.revno, '1')
218
        eq(logentry.rev.message, 'add file1 and file2')
219
        d = logentry.delta
220
        self.checkDelta(d, added=['file1', 'file2'])
221
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
222
    def test_merges_nonsupporting_formatter(self):
223
        """Tests that show_log will raise if the formatter doesn't
224
        support merge revisions."""
225
        wt = self.make_branch_and_memory_tree('.')
226
        wt.lock_write()
227
        try:
228
            wt.add('')
229
            wt.commit('rev-1', rev_id='rev-1',
230
                      timestamp=1132586655, timezone=36000,
231
                      committer='Joe Foo <joe@foo.com>')
232
            wt.commit('rev-merged', rev_id='rev-2a',
233
                      timestamp=1132586700, timezone=36000,
234
                      committer='Joe Foo <joe@foo.com>')
235
            wt.set_parent_ids(['rev-1', 'rev-2a'])
236
            wt.branch.set_last_revision_info(1, 'rev-1')
237
            wt.commit('rev-2', rev_id='rev-2b',
238
                      timestamp=1132586800, timezone=36000,
239
                      committer='Joe Foo <joe@foo.com>')
240
            logfile = self.make_utf8_encoded_stringio()
241
            formatter = ShortLogFormatter(to_file=logfile)
242
            wtb = wt.branch
243
            lf = LogCatcher()
244
            revspec = RevisionSpec.from_string('1.1.1')
245
            rev = revspec.in_history(wtb)
246
            self.assertRaises(BzrCommandError, show_log, wtb, lf,
247
                              start_revision=rev, end_revision=rev)
248
        finally:
249
            wt.unlock()
250
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
251
252
def make_commits_with_trailing_newlines(wt):
253
    """Helper method for LogFormatter tests"""    
254
    b = wt.branch
255
    b.nick='test'
256
    open('a', 'wb').write('hello moto\n')
257
    wt.add('a')
2671.5.4 by Lukáš Lalinsky
Replace the committer with the author in log, the committer is displayed only in the long format and only if it's different from the author.
258
    wt.commit('simple log message', rev_id='a1',
259
              timestamp=1132586655.459960938, timezone=-6*3600,
260
              committer='Joe Foo <joe@foo.com>')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
261
    open('b', 'wb').write('goodbye\n')
262
    wt.add('b')
2671.5.4 by Lukáš Lalinsky
Replace the committer with the author in log, the committer is displayed only in the long format and only if it's different from the author.
263
    wt.commit('multiline\nlog\nmessage\n', rev_id='a2',
264
              timestamp=1132586842.411175966, timezone=-6*3600,
265
              committer='Joe Foo <joe@foo.com>',
266
              author='Joe Bar <joe@bar.com>')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
267
268
    open('c', 'wb').write('just another manic monday\n')
269
    wt.add('c')
2671.5.4 by Lukáš Lalinsky
Replace the committer with the author in log, the committer is displayed only in the long format and only if it's different from the author.
270
    wt.commit('single line with trailing newline\n', rev_id='a3',
271
              timestamp=1132587176.835228920, timezone=-6*3600,
272
              committer = 'Joe Foo <joe@foo.com>')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
273
    return b
274
275
2978.6.1 by Kent Gibson
Use normalize_log to more accurately test blackbox log output.
276
def normalize_log(log):
277
    """Replaces the variable lines of logs with fixed lines"""
278
    author = 'author: Dolor Sit <test@example.com>'
279
    committer = 'committer: Lorem Ipsum <test@example.com>'
280
    lines = log.splitlines(True)
281
    for idx,line in enumerate(lines):
282
        stripped_line = line.lstrip()
283
        indent = ' ' * (len(line) - len(stripped_line))
284
        if stripped_line.startswith('author:'):
285
            lines[idx] = indent + author + '\n'
286
        elif stripped_line.startswith('committer:'):
287
            lines[idx] = indent + committer + '\n'
288
        elif stripped_line.startswith('timestamp:'):
289
            lines[idx] = indent + 'timestamp: Just now\n'
290
    return ''.join(lines)
291
292
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
293
class TestShortLogFormatter(TestCaseWithTransport):
294
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
295
    def test_trailing_newlines(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
296
        wt = self.make_branch_and_tree('.')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
297
        b = make_commits_with_trailing_newlines(wt)
2717.1.1 by Lukáš Lalinsky
Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names.
298
        sio = self.make_utf8_encoded_stringio()
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
299
        lf = ShortLogFormatter(to_file=sio)
300
        show_log(b, lf)
2978.6.2 by Kent Gibson
When comparing logs using assertEqualDiff, pass the igenerated log first then the expected log so the output reflects what is additional in or missing from the generated log.
301
        self.assertEqualDiff(sio.getvalue(), """\
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
302
    3 Joe Foo\t2005-11-21
303
      single line with trailing newline
304
2671.5.4 by Lukáš Lalinsky
Replace the committer with the author in log, the committer is displayed only in the long format and only if it's different from the author.
305
    2 Joe Bar\t2005-11-21
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
306
      multiline
307
      log
308
      message
309
310
    1 Joe Foo\t2005-11-21
311
      simple log message
312
313
""")
314
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
315
    def test_short_log_with_merges(self):
316
        wt = self.make_branch_and_memory_tree('.')
317
        wt.lock_write()
318
        try:
319
            wt.add('')
320
            wt.commit('rev-1', rev_id='rev-1',
321
                      timestamp=1132586655, timezone=36000,
322
                      committer='Joe Foo <joe@foo.com>')
323
            wt.commit('rev-merged', rev_id='rev-2a',
324
                      timestamp=1132586700, timezone=36000,
325
                      committer='Joe Foo <joe@foo.com>')
326
            wt.set_parent_ids(['rev-1', 'rev-2a'])
327
            wt.branch.set_last_revision_info(1, 'rev-1')
328
            wt.commit('rev-2', rev_id='rev-2b',
329
                      timestamp=1132586800, timezone=36000,
330
                      committer='Joe Foo <joe@foo.com>')
331
            logfile = self.make_utf8_encoded_stringio()
332
            formatter = ShortLogFormatter(to_file=logfile)
333
            show_log(wt.branch, formatter)
334
            self.assertEqualDiff(logfile.getvalue(), """\
335
    2 Joe Foo\t2005-11-22 [merge]
336
      rev-2
337
338
    1 Joe Foo\t2005-11-22
339
      rev-1
340
341
""")
342
        finally:
343
            wt.unlock()
344
345
    def test_short_log_single_merge_revision(self):
346
        wt = self.make_branch_and_memory_tree('.')
347
        wt.lock_write()
348
        try:
349
            wt.add('')
350
            wt.commit('rev-1', rev_id='rev-1',
351
                      timestamp=1132586655, timezone=36000,
352
                      committer='Joe Foo <joe@foo.com>')
353
            wt.commit('rev-merged', rev_id='rev-2a',
354
                      timestamp=1132586700, timezone=36000,
355
                      committer='Joe Foo <joe@foo.com>')
356
            wt.set_parent_ids(['rev-1', 'rev-2a'])
357
            wt.branch.set_last_revision_info(1, 'rev-1')
358
            wt.commit('rev-2', rev_id='rev-2b',
359
                      timestamp=1132586800, timezone=36000,
360
                      committer='Joe Foo <joe@foo.com>')
361
            logfile = self.make_utf8_encoded_stringio()
362
            formatter = ShortLogFormatter(to_file=logfile)
363
            revspec = RevisionSpec.from_string('1.1.1')
364
            wtb = wt.branch
365
            rev = revspec.in_history(wtb)
366
            show_log(wtb, formatter, start_revision=rev, end_revision=rev)
367
            self.assertEqualDiff(logfile.getvalue(), """\
368
1.1.1 Joe Foo\t2005-11-22
369
      rev-merged
370
371
""")
372
        finally:
373
            wt.unlock()
374
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
375
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
376
class TestLongLogFormatter(TestCaseWithoutPropsHandler):
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
377
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
378
    def test_verbose_log(self):
379
        """Verbose log includes changed files
380
        
381
        bug #4676
382
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
383
        wt = self.make_branch_and_tree('.')
384
        b = wt.branch
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
385
        self.build_tree(['a'])
1185.33.45 by Martin Pool
[merge] refactoring of branch vs working tree, etc (robertc)
386
        wt.add('a')
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
387
        # XXX: why does a longer nick show up?
388
        b.nick = 'test_verbose_log'
389
        wt.commit(message='add a', 
390
                  timestamp=1132711707, 
391
                  timezone=36000,
392
                  committer='Lorem Ipsum <test@example.com>')
393
        logfile = file('out.tmp', 'w+')
394
        formatter = LongLogFormatter(to_file=logfile)
395
        show_log(b, formatter, verbose=True)
396
        logfile.flush()
397
        logfile.seek(0)
398
        log_contents = logfile.read()
399
        self.assertEqualDiff(log_contents, '''\
400
------------------------------------------------------------
401
revno: 1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
402
committer: Lorem Ipsum <test@example.com>
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
403
branch nick: test_verbose_log
404
timestamp: Wed 2005-11-23 12:08:27 +1000
405
message:
406
  add a
407
added:
408
  a
409
''')
1185.85.4 by John Arbash Meinel
currently broken, trying to fix things up.
410
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
411
    def test_merges_are_indented_by_level(self):
412
        wt = self.make_branch_and_tree('parent')
413
        wt.commit('first post')
2581.1.6 by Martin Pool
fix up more run_bzr callers
414
        self.run_bzr('branch parent child')
415
        self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
416
        self.run_bzr('branch child smallerchild')
417
        self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
418
            'smallerchild'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
419
        os.chdir('child')
2581.1.6 by Martin Pool
fix up more run_bzr callers
420
        self.run_bzr('merge ../smallerchild')
421
        self.run_bzr(['commit', '-m', 'merge branch 2'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
422
        os.chdir('../parent')
2581.1.6 by Martin Pool
fix up more run_bzr callers
423
        self.run_bzr('merge ../child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
424
        wt.commit('merge branch 1')
425
        b = wt.branch
2717.1.1 by Lukáš Lalinsky
Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names.
426
        sio = self.make_utf8_encoded_stringio()
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
427
        lf = LongLogFormatter(to_file=sio)
428
        show_log(b, lf, verbose=True)
2978.6.1 by Kent Gibson
Use normalize_log to more accurately test blackbox log output.
429
        log = normalize_log(sio.getvalue())
2978.6.2 by Kent Gibson
When comparing logs using assertEqualDiff, pass the igenerated log first then the expected log so the output reflects what is additional in or missing from the generated log.
430
        self.assertEqualDiff(log, """\
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
431
------------------------------------------------------------
432
revno: 2
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
433
committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
434
branch nick: parent
435
timestamp: Just now
436
message:
437
  merge branch 1
438
    ------------------------------------------------------------
439
    revno: 1.1.2
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
440
    committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
441
    branch nick: child
442
    timestamp: Just now
443
    message:
444
      merge branch 2
445
        ------------------------------------------------------------
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
446
        revno: 1.2.1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
447
        committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
448
        branch nick: smallerchild
449
        timestamp: Just now
450
        message:
451
          branch 2
452
    ------------------------------------------------------------
453
    revno: 1.1.1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
454
    committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
455
    branch nick: child
456
    timestamp: Just now
457
    message:
458
      branch 1
459
------------------------------------------------------------
460
revno: 1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
461
committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
462
branch nick: parent
463
timestamp: Just now
464
message:
465
  first post
2978.6.2 by Kent Gibson
When comparing logs using assertEqualDiff, pass the igenerated log first then the expected log so the output reflects what is additional in or missing from the generated log.
466
""")
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
467
468
    def test_verbose_merge_revisions_contain_deltas(self):
469
        wt = self.make_branch_and_tree('parent')
470
        self.build_tree(['parent/f1', 'parent/f2'])
471
        wt.add(['f1','f2'])
472
        wt.commit('first post')
2581.1.6 by Martin Pool
fix up more run_bzr callers
473
        self.run_bzr('branch parent child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
474
        os.unlink('child/f1')
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
475
        file('child/f2', 'wb').write('hello\n')
2581.1.6 by Martin Pool
fix up more run_bzr callers
476
        self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
477
            'child'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
478
        os.chdir('parent')
2581.1.6 by Martin Pool
fix up more run_bzr callers
479
        self.run_bzr('merge ../child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
480
        wt.commit('merge branch 1')
481
        b = wt.branch
2717.1.1 by Lukáš Lalinsky
Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names.
482
        sio = self.make_utf8_encoded_stringio()
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
483
        lf = LongLogFormatter(to_file=sio)
484
        show_log(b, lf, verbose=True)
2978.6.1 by Kent Gibson
Use normalize_log to more accurately test blackbox log output.
485
        log = normalize_log(sio.getvalue())
2978.6.2 by Kent Gibson
When comparing logs using assertEqualDiff, pass the igenerated log first then the expected log so the output reflects what is additional in or missing from the generated log.
486
        self.assertEqualDiff(log, """\
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
487
------------------------------------------------------------
488
revno: 2
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
489
committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
490
branch nick: parent
491
timestamp: Just now
492
message:
493
  merge branch 1
494
removed:
495
  f1
496
modified:
497
  f2
498
    ------------------------------------------------------------
499
    revno: 1.1.1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
500
    committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
501
    branch nick: child
502
    timestamp: Just now
503
    message:
504
      removed f1 and modified f2
505
    removed:
506
      f1
507
    modified:
508
      f2
509
------------------------------------------------------------
510
revno: 1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
511
committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
512
branch nick: parent
513
timestamp: Just now
514
message:
515
  first post
516
added:
517
  f1
518
  f2
2978.6.2 by Kent Gibson
When comparing logs using assertEqualDiff, pass the igenerated log first then the expected log so the output reflects what is additional in or missing from the generated log.
519
""")
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
520
521
    def test_trailing_newlines(self):
522
        wt = self.make_branch_and_tree('.')
523
        b = make_commits_with_trailing_newlines(wt)
2717.1.1 by Lukáš Lalinsky
Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names.
524
        sio = self.make_utf8_encoded_stringio()
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
525
        lf = LongLogFormatter(to_file=sio)
526
        show_log(b, lf)
527
        self.assertEqualDiff(sio.getvalue(), """\
528
------------------------------------------------------------
529
revno: 3
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
530
committer: Joe Foo <joe@foo.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
531
branch nick: test
532
timestamp: Mon 2005-11-21 09:32:56 -0600
533
message:
534
  single line with trailing newline
535
------------------------------------------------------------
536
revno: 2
2671.5.4 by Lukáš Lalinsky
Replace the committer with the author in log, the committer is displayed only in the long format and only if it's different from the author.
537
author: Joe Bar <joe@bar.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
538
committer: Joe Foo <joe@foo.com>
539
branch nick: test
540
timestamp: Mon 2005-11-21 09:27:22 -0600
541
message:
542
  multiline
543
  log
544
  message
545
------------------------------------------------------------
546
revno: 1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
547
committer: Joe Foo <joe@foo.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
548
branch nick: test
549
timestamp: Mon 2005-11-21 09:24:15 -0600
550
message:
551
  simple log message
552
""")
553
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
554
    def test_author_in_log(self):
555
        """Log includes the author name if it's set in
556
        the revision properties
2671.2.1 by Lukáš Lalinský
Add --author option to 'bzr commit' to record the author's name, if it's different from the committer.
557
        """
558
        wt = self.make_branch_and_tree('.')
559
        b = wt.branch
560
        self.build_tree(['a'])
561
        wt.add('a')
562
        b.nick = 'test_author_log'
563
        wt.commit(message='add a',
564
                  timestamp=1132711707,
565
                  timezone=36000,
566
                  committer='Lorem Ipsum <test@example.com>',
2671.2.5 by Lukáš Lalinský
Fixes for comments from the mailing list.
567
                  author='John Doe <jdoe@example.com>')
2671.2.1 by Lukáš Lalinský
Add --author option to 'bzr commit' to record the author's name, if it's different from the committer.
568
        sio = StringIO()
569
        formatter = LongLogFormatter(to_file=sio)
570
        show_log(b, formatter)
571
        self.assertEqualDiff(sio.getvalue(), '''\
572
------------------------------------------------------------
573
revno: 1
574
author: John Doe <jdoe@example.com>
2671.5.4 by Lukáš Lalinsky
Replace the committer with the author in log, the committer is displayed only in the long format and only if it's different from the author.
575
committer: Lorem Ipsum <test@example.com>
2671.2.1 by Lukáš Lalinský
Add --author option to 'bzr commit' to record the author's name, if it's different from the committer.
576
branch nick: test_author_log
577
timestamp: Wed 2005-11-23 12:08:27 +1000
578
message:
579
  add a
580
''')
581
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
582
    def test_properties_in_log(self):
583
        """Log includes the custom properties returned by the registered 
584
        handlers.
585
        """
586
        wt = self.make_branch_and_tree('.')
587
        b = wt.branch
588
        self.build_tree(['a'])
589
        wt.add('a')
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
590
        b.nick = 'test_properties_in_log'
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
591
        wt.commit(message='add a',
592
                  timestamp=1132711707,
593
                  timezone=36000,
594
                  committer='Lorem Ipsum <test@example.com>',
595
                  author='John Doe <jdoe@example.com>')
596
        sio = StringIO()
597
        formatter = LongLogFormatter(to_file=sio)
598
        try:
599
            def trivial_custom_prop_handler(revision):
600
                return {'test_prop':'test_value'}
601
            
602
            log.properties_handler_registry.register(
603
                'trivial_custom_prop_handler', 
604
                trivial_custom_prop_handler)
605
            show_log(b, formatter)
606
        finally:
607
            log.properties_handler_registry.remove(
608
                'trivial_custom_prop_handler')
609
            self.assertEqualDiff(sio.getvalue(), '''\
610
------------------------------------------------------------
611
revno: 1
612
test_prop: test_value
613
author: John Doe <jdoe@example.com>
614
committer: Lorem Ipsum <test@example.com>
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
615
branch nick: test_properties_in_log
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
616
timestamp: Wed 2005-11-23 12:08:27 +1000
617
message:
618
  add a
619
''')
620
621
    def test_error_in_properties_handler(self):
622
        """Log includes the custom properties returned by the registered 
623
        handlers.
624
        """
625
        wt = self.make_branch_and_tree('.')
626
        b = wt.branch
627
        self.build_tree(['a'])
628
        wt.add('a')
629
        b.nick = 'test_author_log'
630
        wt.commit(message='add a',
631
                  timestamp=1132711707,
632
                  timezone=36000,
633
                  committer='Lorem Ipsum <test@example.com>',
634
                  author='John Doe <jdoe@example.com>',
635
                  revprops={'first_prop':'first_value'})
636
        sio = StringIO()
637
        formatter = LongLogFormatter(to_file=sio)
638
        try:
639
            def trivial_custom_prop_handler(revision):
640
                raise StandardError("a test error")
641
            
642
            log.properties_handler_registry.register(
643
                'trivial_custom_prop_handler', 
644
                trivial_custom_prop_handler)
645
            self.assertRaises(StandardError, show_log, b, formatter,)
646
        finally:
647
            log.properties_handler_registry.remove(
648
                'trivial_custom_prop_handler')
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
649
                
650
    def test_properties_handler_bad_argument(self):
651
        wt = self.make_branch_and_tree('.')
652
        b = wt.branch
653
        self.build_tree(['a'])
654
        wt.add('a')
655
        b.nick = 'test_author_log'
656
        wt.commit(message='add a',
657
                  timestamp=1132711707,
658
                  timezone=36000,
659
                  committer='Lorem Ipsum <test@example.com>',
660
                  author='John Doe <jdoe@example.com>',
661
                  revprops={'a_prop':'test_value'})
662
        sio = StringIO()
663
        formatter = LongLogFormatter(to_file=sio)
664
        try:
665
            def bad_argument_prop_handler(revision):
666
                return {'custom_prop_name':revision.properties['a_prop']}
667
                
668
            log.properties_handler_registry.register(
669
                'bad_argument_prop_handler', 
670
                bad_argument_prop_handler)
671
            
672
            self.assertRaises(AttributeError, formatter.show_properties, 
673
                'a revision', '')
674
            
675
            revision = b.repository.get_revision(b.last_revision())
676
            formatter.show_properties(revision, '')
677
            self.assertEqualDiff(sio.getvalue(),
678
                '''custom_prop_name: test_value\n''')
679
        finally:
680
            log.properties_handler_registry.remove(
681
                'bad_argument_prop_handler')
2671.2.1 by Lukáš Lalinský
Add --author option to 'bzr commit' to record the author's name, if it's different from the committer.
682
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
683
684
class TestLineLogFormatter(TestCaseWithTransport):
685
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
686
    def test_line_log(self):
687
        """Line log should show revno
688
        
689
        bug #5162
690
        """
691
        wt = self.make_branch_and_tree('.')
692
        b = wt.branch
693
        self.build_tree(['a'])
694
        wt.add('a')
695
        b.nick = 'test-line-log'
3642.1.5 by Robert Collins
Separate out batching of revisions.
696
        wt.commit(message='add a',
697
                  timestamp=1132711707,
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
698
                  timezone=36000,
699
                  committer='Line-Log-Formatter Tester <test@line.log>')
700
        logfile = file('out.tmp', 'w+')
701
        formatter = LineLogFormatter(to_file=logfile)
702
        show_log(b, formatter)
703
        logfile.flush()
704
        logfile.seek(0)
705
        log_contents = logfile.read()
2978.6.2 by Kent Gibson
When comparing logs using assertEqualDiff, pass the igenerated log first then the expected log so the output reflects what is additional in or missing from the generated log.
706
        self.assertEqualDiff(log_contents,
707
            '1: Line-Log-Formatte... 2005-11-23 add a\n')
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
708
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
709
    def test_trailing_newlines(self):
710
        wt = self.make_branch_and_tree('.')
711
        b = make_commits_with_trailing_newlines(wt)
2717.1.1 by Lukáš Lalinsky
Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names.
712
        sio = self.make_utf8_encoded_stringio()
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
713
        lf = LineLogFormatter(to_file=sio)
714
        show_log(b, lf)
715
        self.assertEqualDiff(sio.getvalue(), """\
716
3: Joe Foo 2005-11-21 single line with trailing newline
2671.5.4 by Lukáš Lalinsky
Replace the committer with the author in log, the committer is displayed only in the long format and only if it's different from the author.
717
2: Joe Bar 2005-11-21 multiline
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
718
1: Joe Foo 2005-11-21 simple log message
719
""")
720
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
721
    def test_line_log_single_merge_revision(self):
722
        wt = self.make_branch_and_memory_tree('.')
723
        wt.lock_write()
724
        try:
725
            wt.add('')
726
            wt.commit('rev-1', rev_id='rev-1',
727
                      timestamp=1132586655, timezone=36000,
728
                      committer='Joe Foo <joe@foo.com>')
729
            wt.commit('rev-merged', rev_id='rev-2a',
730
                      timestamp=1132586700, timezone=36000,
731
                      committer='Joe Foo <joe@foo.com>')
732
            wt.set_parent_ids(['rev-1', 'rev-2a'])
733
            wt.branch.set_last_revision_info(1, 'rev-1')
734
            wt.commit('rev-2', rev_id='rev-2b',
735
                      timestamp=1132586800, timezone=36000,
736
                      committer='Joe Foo <joe@foo.com>')
737
            logfile = self.make_utf8_encoded_stringio()
738
            formatter = LineLogFormatter(to_file=logfile)
739
            revspec = RevisionSpec.from_string('1.1.1')
740
            wtb = wt.branch
741
            rev = revspec.in_history(wtb)
742
            show_log(wtb, formatter, start_revision=rev, end_revision=rev)
743
            self.assertEqualDiff(logfile.getvalue(), """\
744
1.1.1: Joe Foo 2005-11-22 rev-merged
745
""")
746
        finally:
747
            wt.unlock()
748
749
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
750
751
class TestGetViewRevisions(TestCaseWithTransport):
752
1756.2.22 by Aaron Bentley
Apply review comments
753
    def make_tree_with_commits(self):
754
        """Create a tree with well-known revision ids"""
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
755
        wt = self.make_branch_and_tree('tree1')
756
        wt.commit('commit one', rev_id='1')
757
        wt.commit('commit two', rev_id='2')
758
        wt.commit('commit three', rev_id='3')
759
        mainline_revs = [None, '1', '2', '3']
1756.2.22 by Aaron Bentley
Apply review comments
760
        rev_nos = {'1': 1, '2': 2, '3': 3}
761
        return mainline_revs, rev_nos, wt
762
763
    def make_tree_with_merges(self):
764
        """Create a tree with well-known revision ids and a merge"""
765
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
766
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
767
        tree2.commit('four-a', rev_id='4a')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
768
        wt.merge_from_branch(tree2.branch)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
769
        wt.commit('four-b', rev_id='4b')
770
        mainline_revs.append('4b')
1756.2.22 by Aaron Bentley
Apply review comments
771
        rev_nos['4b'] = 4
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
772
        # 4a: 3.1.1
1756.2.22 by Aaron Bentley
Apply review comments
773
        return mainline_revs, rev_nos, wt
774
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
775
    def make_tree_with_many_merges(self):
776
        """Create a tree with well-known revision ids"""
777
        wt = self.make_branch_and_tree('tree1')
778
        wt.commit('commit one', rev_id='1')
779
        wt.commit('commit two', rev_id='2')
780
        tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
781
        tree3.commit('commit three a', rev_id='3a')
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
782
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
783
        tree2.merge_from_branch(tree3.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
784
        tree2.commit('commit three b', rev_id='3b')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
785
        wt.merge_from_branch(tree2.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
786
        wt.commit('commit three c', rev_id='3c')
787
        tree2.commit('four-a', rev_id='4a')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
788
        wt.merge_from_branch(tree2.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
789
        wt.commit('four-b', rev_id='4b')
790
        mainline_revs = [None, '1', '2', '3c', '4b']
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
791
        rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
792
        full_rev_nos_for_reference = {
793
            '1': '1',
794
            '2': '2',
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
795
            '3a': '2.1.1', #first commit tree 3
796
            '3b': '2.2.1', # first commit tree 2
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
797
            '3c': '3', #merges 3b to main
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
798
            '4a': '2.2.2', # second commit tree 2
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
799
            '4b': '4', # merges 4a to main
800
            }
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
801
        return mainline_revs, rev_nos, wt
802
1756.2.22 by Aaron Bentley
Apply review comments
803
    def test_get_view_revisions_forward(self):
804
        """Test the get_view_revisions method"""
805
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
3287.6.1 by Robert Collins
* ``VersionedFile.get_graph`` is deprecated, with no replacement method.
806
        wt.lock_read()
807
        self.addCleanup(wt.unlock)
1756.2.22 by Aaron Bentley
Apply review comments
808
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
809
                                            'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
810
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
811
            revisions)
1756.2.22 by Aaron Bentley
Apply review comments
812
        revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
813
                                             'forward', include_merges=False))
814
        self.assertEqual(revisions, revisions2)
815
816
    def test_get_view_revisions_reverse(self):
817
        """Test the get_view_revisions with reverse"""
818
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
3287.6.1 by Robert Collins
* ``VersionedFile.get_graph`` is deprecated, with no replacement method.
819
        wt.lock_read()
820
        self.addCleanup(wt.unlock)
1756.2.22 by Aaron Bentley
Apply review comments
821
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
822
                                            'reverse'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
823
        self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
824
            revisions)
1756.2.22 by Aaron Bentley
Apply review comments
825
        revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
826
                                             'reverse', include_merges=False))
827
        self.assertEqual(revisions, revisions2)
828
829
    def test_get_view_revisions_merge(self):
830
        """Test get_view_revisions when there are merges"""
831
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
3287.6.1 by Robert Collins
* ``VersionedFile.get_graph`` is deprecated, with no replacement method.
832
        wt.lock_read()
833
        self.addCleanup(wt.unlock)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
834
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
835
                                            'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
836
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
837
            ('4b', '4', 0), ('4a', '3.1.1', 1)],
838
            revisions)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
839
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
1756.2.22 by Aaron Bentley
Apply review comments
840
                                             'forward', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
841
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
842
            ('4b', '4', 0)],
843
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
844
845
    def test_get_view_revisions_merge_reverse(self):
846
        """Test get_view_revisions in reverse when there are merges"""
847
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
3287.6.1 by Robert Collins
* ``VersionedFile.get_graph`` is deprecated, with no replacement method.
848
        wt.lock_read()
849
        self.addCleanup(wt.unlock)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
850
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
851
                                            'reverse'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
852
        self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
853
            ('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
854
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
855
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
856
                                             'reverse', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
857
        self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
858
            ('1', '1', 0)],
859
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
860
861
    def test_get_view_revisions_merge2(self):
862
        """Test get_view_revisions when there are merges"""
863
        mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
3287.6.1 by Robert Collins
* ``VersionedFile.get_graph`` is deprecated, with no replacement method.
864
        wt.lock_read()
865
        self.addCleanup(wt.unlock)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
866
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
867
                                            'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
868
        expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
869
            ('3a', '2.1.1', 1), ('3b', '2.2.1', 1), ('4b', '4', 0),
870
            ('4a', '2.2.2', 1)]
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
871
        self.assertEqual(expected, revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
872
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
873
                                             'forward', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
874
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
875
            ('4b', '4', 0)],
876
            revisions)
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
877
878
879
class TestGetRevisionsTouchingFileID(TestCaseWithTransport):
880
881
    def create_tree_with_single_merge(self):
882
        """Create a branch with a moderate layout.
883
884
        The revision graph looks like:
885
886
           A
887
           |\
888
           B C
889
           |/
890
           D
891
892
        In this graph, A introduced files f1 and f2 and f3.
893
        B modifies f1 and f3, and C modifies f2 and f3.
894
        D merges the changes from B and C and resolves the conflict for f3.
895
        """
896
        # TODO: jam 20070218 This seems like it could really be done
897
        #       with make_branch_and_memory_tree() if we could just
898
        #       create the content of those files.
899
        # TODO: jam 20070218 Another alternative is that we would really
900
        #       like to only create this tree 1 time for all tests that
901
        #       use it. Since 'log' only uses the tree in a readonly
902
        #       fashion, it seems a shame to regenerate an identical
903
        #       tree for each test.
904
        tree = self.make_branch_and_tree('tree')
905
        tree.lock_write()
906
        self.addCleanup(tree.unlock)
907
908
        self.build_tree_contents([('tree/f1', 'A\n'),
909
                                  ('tree/f2', 'A\n'),
910
                                  ('tree/f3', 'A\n'),
911
                                 ])
912
        tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
913
        tree.commit('A', rev_id='A')
914
915
        self.build_tree_contents([('tree/f2', 'A\nC\n'),
916
                                  ('tree/f3', 'A\nC\n'),
917
                                 ])
918
        tree.commit('C', rev_id='C')
919
        # Revert back to A to build the other history.
920
        tree.set_last_revision('A')
921
        tree.branch.set_last_revision_info(1, 'A')
922
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
923
                                  ('tree/f2', 'A\n'),
924
                                  ('tree/f3', 'A\nB\n'),
925
                                 ])
926
        tree.commit('B', rev_id='B')
927
        tree.set_parent_ids(['B', 'C'])
928
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
929
                                  ('tree/f2', 'A\nC\n'),
930
                                  ('tree/f3', 'A\nB\nC\n'),
931
                                 ])
932
        tree.commit('D', rev_id='D')
933
934
        # Switch to a read lock for this tree.
935
        # We still have addCleanup(unlock)
936
        tree.unlock()
937
        tree.lock_read()
938
        return tree
939
940
    def test_tree_with_single_merge(self):
941
        """Make sure the tree layout is correct."""
942
        tree = self.create_tree_with_single_merge()
943
        rev_A_tree = tree.branch.repository.revision_tree('A')
944
        rev_B_tree = tree.branch.repository.revision_tree('B')
945
946
        f1_changed = (u'f1', 'f1-id', 'file', True, False)
947
        f2_changed = (u'f2', 'f2-id', 'file', True, False)
948
        f3_changed = (u'f3', 'f3-id', 'file', True, False)
949
950
        delta = rev_B_tree.changes_from(rev_A_tree)
951
        self.assertEqual([f1_changed, f3_changed], delta.modified)
952
        self.assertEqual([], delta.renamed)
953
        self.assertEqual([], delta.added)
954
        self.assertEqual([], delta.removed)
955
956
        rev_C_tree = tree.branch.repository.revision_tree('C')
957
        delta = rev_C_tree.changes_from(rev_A_tree)
958
        self.assertEqual([f2_changed, f3_changed], delta.modified)
959
        self.assertEqual([], delta.renamed)
960
        self.assertEqual([], delta.added)
961
        self.assertEqual([], delta.removed)
962
963
        rev_D_tree = tree.branch.repository.revision_tree('D')
964
        delta = rev_D_tree.changes_from(rev_B_tree)
965
        self.assertEqual([f2_changed, f3_changed], delta.modified)
966
        self.assertEqual([], delta.renamed)
967
        self.assertEqual([], delta.added)
968
        self.assertEqual([], delta.removed)
969
970
        delta = rev_D_tree.changes_from(rev_C_tree)
971
        self.assertEqual([f1_changed, f3_changed], delta.modified)
972
        self.assertEqual([], delta.renamed)
973
        self.assertEqual([], delta.added)
974
        self.assertEqual([], delta.removed)
975
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
976
    def assertAllRevisionsForFileID(self, tree, file_id, revisions):
2466.12.1 by Kent Gibson
Fix ``bzr log -r`` to support selecting merge revisions.
977
        """Make sure _filter_revisions_touching_file_id returns the right values.
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
978
2466.12.1 by Kent Gibson
Fix ``bzr log -r`` to support selecting merge revisions.
979
        Get the return value from _filter_revisions_touching_file_id and make
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
980
        sure they are correct.
981
        """
982
        # The api for _get_revisions_touching_file_id is a little crazy,
983
        # So we do the setup here.
984
        mainline = tree.branch.revision_history()
985
        mainline.insert(0, None)
986
        revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
987
        view_revs_iter = log.get_view_revisions(mainline, revnos, tree.branch,
988
                                                'reverse', True)
2466.12.1 by Kent Gibson
Fix ``bzr log -r`` to support selecting merge revisions.
989
        actual_revs = log._filter_revisions_touching_file_id(
3711.3.23 by John Arbash Meinel
Documentation and cleanup.
990
                            tree.branch,
2466.12.1 by Kent Gibson
Fix ``bzr log -r`` to support selecting merge revisions.
991
                            file_id,
3711.3.17 by John Arbash Meinel
Fix the 'test_log' tests
992
                            list(view_revs_iter),
993
                            'reverse')
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
994
        self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
995
996
    def test_file_id_f1(self):
997
        tree = self.create_tree_with_single_merge()
998
        # f1 should be marked as modified by revisions A and B
999
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
1000
1001
    def test_file_id_f2(self):
1002
        tree = self.create_tree_with_single_merge()
1003
        # f2 should be marked as modified by revisions A, C, and D
1004
        # because D merged the changes from C.
1005
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1006
1007
    def test_file_id_f3(self):
1008
        tree = self.create_tree_with_single_merge()
1009
        # f3 should be marked as modified by revisions A, B, C, and D
1010
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1551.17.2 by Aaron Bentley
Stop showing deltas in pull -v output
1011
3373.2.1 by John Arbash Meinel
Fix bug #209948, properly skip over ghosts when displaying the changes for a single file.
1012
    def test_file_id_with_ghosts(self):
1013
        # This is testing bug #209948, where having a ghost would cause
1014
        # _filter_revisions_touching_file_id() to fail.
1015
        tree = self.create_tree_with_single_merge()
1016
        # We need to add a revision, so switch back to a write-locked tree
1017
        tree.unlock()
1018
        tree.lock_write()
1019
        first_parent = tree.last_revision()
1020
        tree.set_parent_ids([first_parent, 'ghost-revision-id'])
1021
        self.build_tree_contents([('tree/f1', 'A\nB\nXX\n')])
1022
        tree.commit('commit with a ghost', rev_id='XX')
1023
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['XX', 'B', 'A'])
1024
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1025
1551.17.2 by Aaron Bentley
Stop showing deltas in pull -v output
1026
1027
class TestShowChangedRevisions(TestCaseWithTransport):
1028
1029
    def test_show_changed_revisions_verbose(self):
1030
        tree = self.make_branch_and_tree('tree_a')
1031
        self.build_tree(['tree_a/foo'])
1032
        tree.add('foo')
1033
        tree.commit('bar', rev_id='bar-id')
2717.1.1 by Lukáš Lalinsky
Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names.
1034
        s = self.make_utf8_encoded_stringio()
1551.17.2 by Aaron Bentley
Stop showing deltas in pull -v output
1035
        log.show_changed_revisions(tree.branch, [], ['bar-id'], s)
1036
        self.assertContainsRe(s.getvalue(), 'bar')
1037
        self.assertNotContainsRe(s.getvalue(), 'foo')
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
1038
1039
1040
class TestLogFormatter(TestCase):
1041
1042
    def test_short_committer(self):
1043
        rev = Revision('a-id')
1044
        rev.committer = 'John Doe <jdoe@example.com>'
1045
        lf = LogFormatter(None)
1046
        self.assertEqual('John Doe', lf.short_committer(rev))
3063.3.1 by Lukáš Lalinský
Fall back to showing e-mail in ``log --short/--line`` if the committer/author has only e-mail.
1047
        rev.committer = 'John Smith <jsmith@example.com>'
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1048
        self.assertEqual('John Smith', lf.short_committer(rev))
3063.3.1 by Lukáš Lalinský
Fall back to showing e-mail in ``log --short/--line`` if the committer/author has only e-mail.
1049
        rev.committer = 'John Smith'
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1050
        self.assertEqual('John Smith', lf.short_committer(rev))
3063.3.1 by Lukáš Lalinský
Fall back to showing e-mail in ``log --short/--line`` if the committer/author has only e-mail.
1051
        rev.committer = 'jsmith@example.com'
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1052
        self.assertEqual('jsmith@example.com', lf.short_committer(rev))
3063.3.1 by Lukáš Lalinský
Fall back to showing e-mail in ``log --short/--line`` if the committer/author has only e-mail.
1053
        rev.committer = '<jsmith@example.com>'
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1054
        self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1055
        rev.committer = 'John Smith jsmith@example.com'
1056
        self.assertEqual('John Smith', lf.short_committer(rev))
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
1057
1058
    def test_short_author(self):
1059
        rev = Revision('a-id')
1060
        rev.committer = 'John Doe <jdoe@example.com>'
1061
        lf = LogFormatter(None)
1062
        self.assertEqual('John Doe', lf.short_author(rev))
1063
        rev.properties['author'] = 'John Smith <jsmith@example.com>'
1064
        self.assertEqual('John Smith', lf.short_author(rev))
3063.3.1 by Lukáš Lalinský
Fall back to showing e-mail in ``log --short/--line`` if the committer/author has only e-mail.
1065
        rev.properties['author'] = 'John Smith'
1066
        self.assertEqual('John Smith', lf.short_author(rev))
1067
        rev.properties['author'] = 'jsmith@example.com'
1068
        self.assertEqual('jsmith@example.com', lf.short_author(rev))
1069
        rev.properties['author'] = '<jsmith@example.com>'
1070
        self.assertEqual('jsmith@example.com', lf.short_author(rev))
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1071
        rev.properties['author'] = 'John Smith jsmith@example.com'
1072
        self.assertEqual('John Smith', lf.short_author(rev))