~bzr-pqm/bzr/bzr.dev

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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
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
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
20
from bzrlib import (
21
    errors,
22
    log,
23
    registry,
24
    revision,
25
    revisionspec,
26
    tests,
27
    )
28
29
30
class TestCaseWithoutPropsHandler(tests.TestCaseWithTransport):
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
31
32
    def setUp(self):
33
        super(TestCaseWithoutPropsHandler, self).setUp()
34
        # keep a reference to the "current" custom prop. handler registry
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
35
        self.properties_handler_registry = log.properties_handler_registry
4325.4.3 by Vincent Ladeuil
More cleanups.
36
        # Use a clean registry for log
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
37
        log.properties_handler_registry = registry.Registry()
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
38
4325.4.3 by Vincent Ladeuil
More cleanups.
39
        def restore():
40
            log.properties_handler_registry = self.properties_handler_registry
41
        self.addCleanup(restore)
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
42
43
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
44
class LogCatcher(log.LogFormatter):
4325.4.3 by Vincent Ladeuil
More cleanups.
45
    """Pull log messages into a list rather than displaying them.
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
46
4325.4.3 by Vincent Ladeuil
More cleanups.
47
    To simplify testing we save logged revisions here rather than actually
4325.4.1 by Vincent Ladeuil
Some cleanups.
48
    formatting anything, so that we can precisely check the result without
4325.4.3 by Vincent Ladeuil
More cleanups.
49
    being dependent on the formatting.
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
50
    """
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.
51
2490.1.2 by John Arbash Meinel
Cleanup according to PEP8 and some other small whitespace fixes
52
    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.
53
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
54
    def __init__(self):
55
        super(LogCatcher, self).__init__(to_file=None)
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
56
        self.revisions = []
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
57
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.
58
    def log_revision(self, revision):
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
59
        self.revisions.append(revision)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
60
61
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
62
class TestShowLog(tests.TestCaseWithTransport):
1102 by Martin Pool
- merge test refactoring from robertc
63
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
64
    def checkDelta(self, delta, **kw):
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
65
        """Check the filenames touched by a delta are as expected.
66
67
        Caller only have to pass in the list of files for each part, all
68
        unspecified parts are considered empty (and checked as such).
69
        """
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
70
        for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
71
            # By default we expect an empty list
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
72
            expected = kw.get(n, [])
73
            # strip out only the path components
74
            got = [x[0] for x in getattr(delta, n)]
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
75
            self.assertEqual(expected, got)
76
77
    def assertInvalidRevisonNumber(self, br, start, end):
78
        lf = LogCatcher()
79
        self.assertRaises(errors.InvalidRevisionNumber,
80
                          log.show_log, br, lf,
81
                          start_revision=start, end_revision=end)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
82
974.1.54 by aaron.bentley at utoronto
Fixed the revno bug in log
83
    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.
84
        wt = self.make_branch_and_tree('.')
85
        b = wt.branch
1092.3.4 by Robert Collins
update symlink branch to integration
86
87
        lf = LogCatcher()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
88
        wt.commit('empty commit')
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
89
        log.show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
90
91
        # Since there is a single revision in the branch all the combinations
92
        # below should fail.
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
93
        self.assertInvalidRevisonNumber(b, 2, 1)
94
        self.assertInvalidRevisonNumber(b, 1, 2)
95
        self.assertInvalidRevisonNumber(b, 0, 2)
96
        self.assertInvalidRevisonNumber(b, 1, 0)
97
        self.assertInvalidRevisonNumber(b, -1, 1)
98
        self.assertInvalidRevisonNumber(b, 1, -1)
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
99
100
    def test_empty_branch(self):
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
101
        wt = self.make_branch_and_tree('.')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
102
103
        lf = LogCatcher()
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
104
        log.show_log(wt.branch, lf)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
105
        # no entries yet
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
106
        self.assertEqual([], lf.revisions)
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
107
108
    def test_empty_commit(self):
109
        wt = self.make_branch_and_tree('.')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
110
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
111
        wt.commit('empty commit')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
112
        lf = LogCatcher()
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
113
        log.show_log(wt.branch, lf, verbose=True)
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
114
        revs = lf.revisions
115
        self.assertEqual(1, len(revs))
116
        self.assertEqual('1', revs[0].revno)
117
        self.assertEqual('empty commit', revs[0].rev.message)
118
        self.checkDelta(revs[0].delta)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
119
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
120
    def test_simple_commit(self):
121
        wt = self.make_branch_and_tree('.')
122
        wt.commit('empty commit')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
123
        self.build_tree(['hello'])
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
124
        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.
125
        wt.commit('add one file',
126
                  committer=u'\u013d\xf3r\xe9m \xcdp\u0161\xfam '
127
                            u'<test@example.com>')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
128
        lf = LogCatcher()
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
129
        log.show_log(wt.branch, lf, verbose=True)
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
130
        self.assertEqual(2, len(lf.revisions))
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
131
        # first one is most recent
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
132
        log_entry = lf.revisions[0]
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
133
        self.assertEqual('2', log_entry.revno)
134
        self.assertEqual('add one file', log_entry.rev.message)
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
135
        self.checkDelta(log_entry.delta, added=['hello'])
3831.1.6 by John Arbash Meinel
For the simple-log tests, avoid using '\r' in the test.
136
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
137
    def test_commit_message_with_control_chars(self):
138
        wt = self.make_branch_and_tree('.')
3831.1.6 by John Arbash Meinel
For the simple-log tests, avoid using '\r' in the test.
139
        msg = u"All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)])
140
        msg = msg.replace(u'\r', u'\n')
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
141
        wt.commit(msg)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
142
        lf = LogCatcher()
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
143
        log.show_log(wt.branch, lf, verbose=True)
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
144
        committed_msg = lf.revisions[0].rev.message
4627.1.1 by Robert Collins
Review feedback per IanC.
145
        if wt.branch.repository._serializer.squashes_xml_invalid_characters:
146
            self.assertNotEqual(msg, committed_msg)
147
            self.assertTrue(len(committed_msg) > len(msg))
148
        else:
149
            self.assertEqual(msg, committed_msg)
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
150
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
151
    def test_commit_message_without_control_chars(self):
152
        wt = self.make_branch_and_tree('.')
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
153
        # escaped.  As ElementTree apparently does some kind of
154
        # newline conversion, neither LF (\x0A) nor CR (\x0D) are
155
        # included in the test commit message, even though they are
156
        # valid XML 1.0 characters.
157
        msg = "\x09" + ''.join([unichr(x) for x in range(0x20, 256)])
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
158
        wt.commit(msg)
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
159
        lf = LogCatcher()
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
160
        log.show_log(wt.branch, lf, verbose=True)
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
161
        committed_msg = lf.revisions[0].rev.message
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
162
        self.assertEqual(msg, committed_msg)
1185.31.22 by John Arbash Meinel
[merge] bzr.dev
163
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
164
    def test_deltas_in_merge_revisions(self):
165
        """Check deltas created for both mainline and merge revisions"""
166
        wt = self.make_branch_and_tree('parent')
167
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
168
        wt.add('file1')
169
        wt.add('file2')
170
        wt.commit(message='add file1 and file2')
2581.1.6 by Martin Pool
fix up more run_bzr callers
171
        self.run_bzr('branch parent child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
172
        os.unlink('child/file1')
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
173
        file('child/file2', 'wb').write('hello\n')
2581.1.6 by Martin Pool
fix up more run_bzr callers
174
        self.run_bzr(['commit', '-m', 'remove file1 and modify file2',
175
            'child'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
176
        os.chdir('parent')
2581.1.6 by Martin Pool
fix up more run_bzr callers
177
        self.run_bzr('merge ../child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
178
        wt.commit('merge child branch')
179
        os.chdir('..')
180
        b = wt.branch
181
        lf = LogCatcher()
182
        lf.supports_merge_revisions = True
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
183
        log.show_log(b, lf, verbose=True)
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
184
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
185
        revs = lf.revisions
186
        self.assertEqual(3, len(revs))
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
187
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
188
        logentry = revs[0]
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
189
        self.assertEqual('2', logentry.revno)
190
        self.assertEqual('merge child branch', logentry.rev.message)
191
        self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
192
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
193
        logentry = revs[1]
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
194
        self.assertEqual('1.1.1', logentry.revno)
195
        self.assertEqual('remove file1 and modify file2', logentry.rev.message)
196
        self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
197
4325.4.4 by Vincent Ladeuil
Clarify LogCatcher purpose.
198
        logentry = revs[2]
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
199
        self.assertEqual('1', logentry.revno)
200
        self.assertEqual('add file1 and file2', logentry.rev.message)
201
        self.checkDelta(logentry.delta, added=['file1', 'file2'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
202
203
204
def make_commits_with_trailing_newlines(wt):
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
205
    """Helper method for LogFormatter tests"""
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
206
    b = wt.branch
207
    b.nick='test'
208
    open('a', 'wb').write('hello moto\n')
209
    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.
210
    wt.commit('simple log message', rev_id='a1',
211
              timestamp=1132586655.459960938, timezone=-6*3600,
212
              committer='Joe Foo <joe@foo.com>')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
213
    open('b', 'wb').write('goodbye\n')
214
    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.
215
    wt.commit('multiline\nlog\nmessage\n', rev_id='a2',
216
              timestamp=1132586842.411175966, timezone=-6*3600,
217
              committer='Joe Foo <joe@foo.com>',
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
218
              authors=['Joe Bar <joe@bar.com>'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
219
220
    open('c', 'wb').write('just another manic monday\n')
221
    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.
222
    wt.commit('single line with trailing newline\n', rev_id='a3',
223
              timestamp=1132587176.835228920, timezone=-6*3600,
224
              committer = 'Joe Foo <joe@foo.com>')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
225
    return b
226
227
2978.6.1 by Kent Gibson
Use normalize_log to more accurately test blackbox log output.
228
def normalize_log(log):
229
    """Replaces the variable lines of logs with fixed lines"""
230
    author = 'author: Dolor Sit <test@example.com>'
231
    committer = 'committer: Lorem Ipsum <test@example.com>'
232
    lines = log.splitlines(True)
233
    for idx,line in enumerate(lines):
234
        stripped_line = line.lstrip()
235
        indent = ' ' * (len(line) - len(stripped_line))
236
        if stripped_line.startswith('author:'):
237
            lines[idx] = indent + author + '\n'
238
        elif stripped_line.startswith('committer:'):
239
            lines[idx] = indent + committer + '\n'
240
        elif stripped_line.startswith('timestamp:'):
241
            lines[idx] = indent + 'timestamp: Just now\n'
242
    return ''.join(lines)
243
244
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
245
class TestShortLogFormatter(tests.TestCaseWithTransport):
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
246
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
247
    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.
248
        wt = self.make_branch_and_tree('.')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
249
        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.
250
        sio = self.make_utf8_encoded_stringio()
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
251
        lf = log.ShortLogFormatter(to_file=sio)
252
        log.show_log(b, lf)
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
253
        self.assertEqualDiff("""\
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
254
    3 Joe Foo\t2005-11-21
255
      single line with trailing newline
256
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.
257
    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.
258
      multiline
259
      log
260
      message
261
262
    1 Joe Foo\t2005-11-21
263
      simple log message
264
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
265
""",
266
                             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.
267
3946.3.2 by Ian Clatworthy
add tests & NEWS item
268
    def _prepare_tree_with_merges(self, with_tags=False):
269
        wt = self.make_branch_and_memory_tree('.')
270
        wt.lock_write()
271
        self.addCleanup(wt.unlock)
272
        wt.add('')
273
        wt.commit('rev-1', rev_id='rev-1',
274
                  timestamp=1132586655, timezone=36000,
275
                  committer='Joe Foo <joe@foo.com>')
276
        wt.commit('rev-merged', rev_id='rev-2a',
277
                  timestamp=1132586700, timezone=36000,
278
                  committer='Joe Foo <joe@foo.com>')
279
        wt.set_parent_ids(['rev-1', 'rev-2a'])
280
        wt.branch.set_last_revision_info(1, 'rev-1')
281
        wt.commit('rev-2', rev_id='rev-2b',
282
                  timestamp=1132586800, timezone=36000,
283
                  committer='Joe Foo <joe@foo.com>')
284
        if with_tags:
285
            branch = wt.branch
286
            branch.tags.set_tag('v0.2', 'rev-2b')
287
            wt.commit('rev-3', rev_id='rev-3',
288
                      timestamp=1132586900, timezone=36000,
289
                      committer='Jane Foo <jane@foo.com>')
290
            branch.tags.set_tag('v1.0rc1', 'rev-3')
291
            branch.tags.set_tag('v1.0', 'rev-3')
292
        return wt
293
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
294
    def test_short_log_with_merges(self):
3946.3.2 by Ian Clatworthy
add tests & NEWS item
295
        wt = self._prepare_tree_with_merges()
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
296
        logfile = self.make_utf8_encoded_stringio()
297
        formatter = log.ShortLogFormatter(to_file=logfile)
298
        log.show_log(wt.branch, formatter)
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
299
        self.assertEqualDiff("""\
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
300
    2 Joe Foo\t2005-11-22 [merge]
301
      rev-2
302
303
    1 Joe Foo\t2005-11-22
304
      rev-1
305
4221.2.3 by Ian Clatworthy
jam feedback: don't show advice if --levels explicitly given
306
""",
307
                             logfile.getvalue())
308
309
    def test_short_log_with_merges_and_advice(self):
310
        wt = self._prepare_tree_with_merges()
311
        logfile = self.make_utf8_encoded_stringio()
312
        formatter = log.ShortLogFormatter(to_file=logfile,
313
            show_advice=True)
314
        log.show_log(wt.branch, formatter)
315
        self.assertEqualDiff("""\
316
    2 Joe Foo\t2005-11-22 [merge]
317
      rev-2
318
319
    1 Joe Foo\t2005-11-22
320
      rev-1
321
4221.2.1 by Ian Clatworthy
--include-merges as an alias for --levels 0 in log
322
Use --include-merges or -n0 to see merged revisions.
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
323
""",
324
                             logfile.getvalue())
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
325
3943.4.2 by John Arbash Meinel
Add a test case which exercises this code path.
326
    def test_short_log_with_merges_and_range(self):
327
        wt = self.make_branch_and_memory_tree('.')
328
        wt.lock_write()
329
        self.addCleanup(wt.unlock)
330
        wt.add('')
331
        wt.commit('rev-1', rev_id='rev-1',
332
                  timestamp=1132586655, timezone=36000,
333
                  committer='Joe Foo <joe@foo.com>')
334
        wt.commit('rev-merged', rev_id='rev-2a',
335
                  timestamp=1132586700, timezone=36000,
336
                  committer='Joe Foo <joe@foo.com>')
337
        wt.branch.set_last_revision_info(1, 'rev-1')
338
        wt.set_parent_ids(['rev-1', 'rev-2a'])
339
        wt.commit('rev-2b', rev_id='rev-2b',
340
                  timestamp=1132586800, timezone=36000,
341
                  committer='Joe Foo <joe@foo.com>')
342
        wt.commit('rev-3a', rev_id='rev-3a',
343
                  timestamp=1132586800, timezone=36000,
344
                  committer='Joe Foo <joe@foo.com>')
345
        wt.branch.set_last_revision_info(2, 'rev-2b')
346
        wt.set_parent_ids(['rev-2b', 'rev-3a'])
347
        wt.commit('rev-3b', rev_id='rev-3b',
348
                  timestamp=1132586800, timezone=36000,
349
                  committer='Joe Foo <joe@foo.com>')
350
        logfile = self.make_utf8_encoded_stringio()
351
        formatter = log.ShortLogFormatter(to_file=logfile)
352
        log.show_log(wt.branch, formatter,
353
            start_revision=2, end_revision=3)
354
        self.assertEqualDiff("""\
355
    3 Joe Foo\t2005-11-22 [merge]
356
      rev-3b
357
358
    2 Joe Foo\t2005-11-22 [merge]
359
      rev-2b
360
361
""",
362
                             logfile.getvalue())
363
3946.3.2 by Ian Clatworthy
add tests & NEWS item
364
    def test_short_log_with_tags(self):
365
        wt = self._prepare_tree_with_merges(with_tags=True)
366
        logfile = self.make_utf8_encoded_stringio()
367
        formatter = log.ShortLogFormatter(to_file=logfile)
368
        log.show_log(wt.branch, formatter)
369
        self.assertEqualDiff("""\
370
    3 Jane Foo\t2005-11-22 {v1.0, v1.0rc1}
371
      rev-3
372
373
    2 Joe Foo\t2005-11-22 {v0.2} [merge]
374
      rev-2
375
376
    1 Joe Foo\t2005-11-22
377
      rev-1
378
379
""",
380
                             logfile.getvalue())
381
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
382
    def test_short_log_single_merge_revision(self):
383
        wt = self.make_branch_and_memory_tree('.')
384
        wt.lock_write()
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
385
        self.addCleanup(wt.unlock)
386
        wt.add('')
387
        wt.commit('rev-1', rev_id='rev-1',
388
                  timestamp=1132586655, timezone=36000,
389
                  committer='Joe Foo <joe@foo.com>')
390
        wt.commit('rev-merged', rev_id='rev-2a',
391
                  timestamp=1132586700, timezone=36000,
392
                  committer='Joe Foo <joe@foo.com>')
393
        wt.set_parent_ids(['rev-1', 'rev-2a'])
394
        wt.branch.set_last_revision_info(1, 'rev-1')
395
        wt.commit('rev-2', rev_id='rev-2b',
396
                  timestamp=1132586800, timezone=36000,
397
                  committer='Joe Foo <joe@foo.com>')
398
        logfile = self.make_utf8_encoded_stringio()
399
        formatter = log.ShortLogFormatter(to_file=logfile)
400
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
401
        wtb = wt.branch
402
        rev = revspec.in_history(wtb)
403
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
404
        self.assertEqualDiff("""\
3947.1.10 by Ian Clatworthy
review feedback from vila
405
      1.1.1 Joe Foo\t2005-11-22
406
            rev-merged
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
407
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
408
""",
409
                             logfile.getvalue())
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
410
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
411
3947.1.2 by Ian Clatworthy
formatter tests
412
class TestShortLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
413
414
    def test_short_merge_revs_log_with_merges(self):
415
        wt = self.make_branch_and_memory_tree('.')
416
        wt.lock_write()
417
        self.addCleanup(wt.unlock)
418
        wt.add('')
419
        wt.commit('rev-1', rev_id='rev-1',
420
                  timestamp=1132586655, timezone=36000,
421
                  committer='Joe Foo <joe@foo.com>')
422
        wt.commit('rev-merged', rev_id='rev-2a',
423
                  timestamp=1132586700, timezone=36000,
424
                  committer='Joe Foo <joe@foo.com>')
425
        wt.set_parent_ids(['rev-1', 'rev-2a'])
426
        wt.branch.set_last_revision_info(1, 'rev-1')
427
        wt.commit('rev-2', rev_id='rev-2b',
428
                  timestamp=1132586800, timezone=36000,
429
                  committer='Joe Foo <joe@foo.com>')
430
        logfile = self.make_utf8_encoded_stringio()
3947.1.6 by Ian Clatworthy
log -n/--level-count N option
431
        formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
3947.1.2 by Ian Clatworthy
formatter tests
432
        log.show_log(wt.branch, formatter)
3947.1.7 by Ian Clatworthy
tweak indenting/offsetting for --short given dotted revno lengths
433
        # Note that the 1.1.1 indenting is in fact correct given that
434
        # the revision numbers are right justified within 5 characters
435
        # for mainline revnos and 9 characters for dotted revnos.
3947.1.2 by Ian Clatworthy
formatter tests
436
        self.assertEqualDiff("""\
437
    2 Joe Foo\t2005-11-22 [merge]
438
      rev-2
439
3947.1.10 by Ian Clatworthy
review feedback from vila
440
          1.1.1 Joe Foo\t2005-11-22
441
                rev-merged
3947.1.2 by Ian Clatworthy
formatter tests
442
443
    1 Joe Foo\t2005-11-22
444
      rev-1
445
446
""",
447
                             logfile.getvalue())
448
449
    def test_short_merge_revs_log_single_merge_revision(self):
450
        wt = self.make_branch_and_memory_tree('.')
451
        wt.lock_write()
452
        self.addCleanup(wt.unlock)
453
        wt.add('')
454
        wt.commit('rev-1', rev_id='rev-1',
455
                  timestamp=1132586655, timezone=36000,
456
                  committer='Joe Foo <joe@foo.com>')
457
        wt.commit('rev-merged', rev_id='rev-2a',
458
                  timestamp=1132586700, timezone=36000,
459
                  committer='Joe Foo <joe@foo.com>')
460
        wt.set_parent_ids(['rev-1', 'rev-2a'])
461
        wt.branch.set_last_revision_info(1, 'rev-1')
462
        wt.commit('rev-2', rev_id='rev-2b',
463
                  timestamp=1132586800, timezone=36000,
464
                  committer='Joe Foo <joe@foo.com>')
465
        logfile = self.make_utf8_encoded_stringio()
3947.1.6 by Ian Clatworthy
log -n/--level-count N option
466
        formatter = log.ShortLogFormatter(to_file=logfile, levels=0)
3947.1.2 by Ian Clatworthy
formatter tests
467
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
468
        wtb = wt.branch
469
        rev = revspec.in_history(wtb)
470
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
471
        self.assertEqualDiff("""\
3947.1.10 by Ian Clatworthy
review feedback from vila
472
      1.1.1 Joe Foo\t2005-11-22
473
            rev-merged
3947.1.2 by Ian Clatworthy
formatter tests
474
475
""",
476
                             logfile.getvalue())
477
478
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
479
class TestLongLogFormatter(TestCaseWithoutPropsHandler):
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
480
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
481
    def test_verbose_log(self):
482
        """Verbose log includes changed files
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
483
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
484
        bug #4676
485
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
486
        wt = self.make_branch_and_tree('.')
487
        b = wt.branch
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
488
        self.build_tree(['a'])
1185.33.45 by Martin Pool
[merge] refactoring of branch vs working tree, etc (robertc)
489
        wt.add('a')
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
490
        # XXX: why does a longer nick show up?
491
        b.nick = 'test_verbose_log'
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
492
        wt.commit(message='add a',
493
                  timestamp=1132711707,
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
494
                  timezone=36000,
495
                  committer='Lorem Ipsum <test@example.com>')
496
        logfile = file('out.tmp', 'w+')
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
497
        formatter = log.LongLogFormatter(to_file=logfile)
498
        log.show_log(b, formatter, verbose=True)
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
499
        logfile.flush()
500
        logfile.seek(0)
501
        log_contents = logfile.read()
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
502
        self.assertEqualDiff('''\
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
503
------------------------------------------------------------
504
revno: 1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
505
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)
506
branch nick: test_verbose_log
507
timestamp: Wed 2005-11-23 12:08:27 +1000
508
message:
509
  add a
510
added:
511
  a
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
512
''',
513
                             log_contents)
1185.85.4 by John Arbash Meinel
currently broken, trying to fix things up.
514
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
515
    def test_merges_are_indented_by_level(self):
516
        wt = self.make_branch_and_tree('parent')
517
        wt.commit('first post')
2581.1.6 by Martin Pool
fix up more run_bzr callers
518
        self.run_bzr('branch parent child')
519
        self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
520
        self.run_bzr('branch child smallerchild')
521
        self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
522
            'smallerchild'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
523
        os.chdir('child')
2581.1.6 by Martin Pool
fix up more run_bzr callers
524
        self.run_bzr('merge ../smallerchild')
525
        self.run_bzr(['commit', '-m', 'merge branch 2'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
526
        os.chdir('../parent')
2581.1.6 by Martin Pool
fix up more run_bzr callers
527
        self.run_bzr('merge ../child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
528
        wt.commit('merge branch 1')
529
        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.
530
        sio = self.make_utf8_encoded_stringio()
4206.1.1 by Ian Clatworthy
log mainline by default
531
        lf = log.LongLogFormatter(to_file=sio, levels=0)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
532
        log.show_log(b, lf, verbose=True)
533
        the_log = normalize_log(sio.getvalue())
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
534
        self.assertEqualDiff("""\
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
535
------------------------------------------------------------
4208.2.1 by Ian Clatworthy
merge indicators in log --long
536
revno: 2 [merge]
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
537
committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
538
branch nick: parent
539
timestamp: Just now
540
message:
541
  merge branch 1
542
    ------------------------------------------------------------
4208.2.1 by Ian Clatworthy
merge indicators in log --long
543
    revno: 1.1.2 [merge]
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
544
    committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
545
    branch nick: child
546
    timestamp: Just now
547
    message:
548
      merge branch 2
549
        ------------------------------------------------------------
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
550
        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.
551
        committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
552
        branch nick: smallerchild
553
        timestamp: Just now
554
        message:
555
          branch 2
556
    ------------------------------------------------------------
557
    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.
558
    committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
559
    branch nick: child
560
    timestamp: Just now
561
    message:
562
      branch 1
563
------------------------------------------------------------
564
revno: 1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
565
committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
566
branch nick: parent
567
timestamp: Just now
568
message:
569
  first post
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
570
""",
571
                             the_log)
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
572
573
    def test_verbose_merge_revisions_contain_deltas(self):
574
        wt = self.make_branch_and_tree('parent')
575
        self.build_tree(['parent/f1', 'parent/f2'])
576
        wt.add(['f1','f2'])
577
        wt.commit('first post')
2581.1.6 by Martin Pool
fix up more run_bzr callers
578
        self.run_bzr('branch parent child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
579
        os.unlink('child/f1')
2911.6.1 by Blake Winton
Change 'print >> f,'s to 'f.write('s.
580
        file('child/f2', 'wb').write('hello\n')
2581.1.6 by Martin Pool
fix up more run_bzr callers
581
        self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
582
            'child'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
583
        os.chdir('parent')
2581.1.6 by Martin Pool
fix up more run_bzr callers
584
        self.run_bzr('merge ../child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
585
        wt.commit('merge branch 1')
586
        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.
587
        sio = self.make_utf8_encoded_stringio()
4206.1.1 by Ian Clatworthy
log mainline by default
588
        lf = log.LongLogFormatter(to_file=sio, levels=0)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
589
        log.show_log(b, lf, verbose=True)
590
        the_log = normalize_log(sio.getvalue())
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
591
        self.assertEqualDiff("""\
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
592
------------------------------------------------------------
4208.2.1 by Ian Clatworthy
merge indicators in log --long
593
revno: 2 [merge]
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
594
committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
595
branch nick: parent
596
timestamp: Just now
597
message:
598
  merge branch 1
599
removed:
600
  f1
601
modified:
602
  f2
603
    ------------------------------------------------------------
604
    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.
605
    committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
606
    branch nick: child
607
    timestamp: Just now
608
    message:
609
      removed f1 and modified f2
610
    removed:
611
      f1
612
    modified:
613
      f2
614
------------------------------------------------------------
615
revno: 1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
616
committer: Lorem Ipsum <test@example.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
617
branch nick: parent
618
timestamp: Just now
619
message:
620
  first post
621
added:
622
  f1
623
  f2
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
624
""",
625
                             the_log)
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
626
627
    def test_trailing_newlines(self):
628
        wt = self.make_branch_and_tree('.')
629
        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.
630
        sio = self.make_utf8_encoded_stringio()
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
631
        lf = log.LongLogFormatter(to_file=sio)
632
        log.show_log(b, lf)
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
633
        self.assertEqualDiff("""\
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
634
------------------------------------------------------------
635
revno: 3
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
636
committer: Joe Foo <joe@foo.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
637
branch nick: test
638
timestamp: Mon 2005-11-21 09:32:56 -0600
639
message:
640
  single line with trailing newline
641
------------------------------------------------------------
642
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.
643
author: Joe Bar <joe@bar.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
644
committer: Joe Foo <joe@foo.com>
645
branch nick: test
646
timestamp: Mon 2005-11-21 09:27:22 -0600
647
message:
648
  multiline
649
  log
650
  message
651
------------------------------------------------------------
652
revno: 1
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
653
committer: Joe Foo <joe@foo.com>
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
654
branch nick: test
655
timestamp: Mon 2005-11-21 09:24:15 -0600
656
message:
657
  simple log message
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
658
""",
659
                             sio.getvalue())
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
660
2671.5.7 by Lukáš Lalinsky
Rename get_author to get_apparent_author, revert the long log back to displaying the committer.
661
    def test_author_in_log(self):
662
        """Log includes the author name if it's set in
663
        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.
664
        """
665
        wt = self.make_branch_and_tree('.')
666
        b = wt.branch
667
        self.build_tree(['a'])
668
        wt.add('a')
669
        b.nick = 'test_author_log'
670
        wt.commit(message='add a',
671
                  timestamp=1132711707,
672
                  timezone=36000,
673
                  committer='Lorem Ipsum <test@example.com>',
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
674
                  authors=['John Doe <jdoe@example.com>',
675
                           'Jane Rey <jrey@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.
676
        sio = StringIO()
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
677
        formatter = log.LongLogFormatter(to_file=sio)
678
        log.show_log(b, formatter)
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
679
        self.assertEqualDiff('''\
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.
680
------------------------------------------------------------
681
revno: 1
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
682
author: John Doe <jdoe@example.com>, Jane Rey <jrey@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.
683
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.
684
branch nick: test_author_log
685
timestamp: Wed 2005-11-23 12:08:27 +1000
686
message:
687
  add a
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
688
''',
689
                             sio.getvalue())
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.
690
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
691
    def test_properties_in_log(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
692
        """Log includes the custom properties returned by the registered
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
693
        handlers.
694
        """
695
        wt = self.make_branch_and_tree('.')
696
        b = wt.branch
697
        self.build_tree(['a'])
698
        wt.add('a')
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
699
        b.nick = 'test_properties_in_log'
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
700
        wt.commit(message='add a',
701
                  timestamp=1132711707,
702
                  timezone=36000,
703
                  committer='Lorem Ipsum <test@example.com>',
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
704
                  authors=['John Doe <jdoe@example.com>'])
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
705
        sio = StringIO()
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
706
        formatter = log.LongLogFormatter(to_file=sio)
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
707
        try:
708
            def trivial_custom_prop_handler(revision):
709
                return {'test_prop':'test_value'}
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
710
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
711
            log.properties_handler_registry.register(
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
712
                'trivial_custom_prop_handler',
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
713
                trivial_custom_prop_handler)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
714
            log.show_log(b, formatter)
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
715
        finally:
716
            log.properties_handler_registry.remove(
717
                'trivial_custom_prop_handler')
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
718
            self.assertEqualDiff('''\
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
719
------------------------------------------------------------
720
revno: 1
721
test_prop: test_value
722
author: John Doe <jdoe@example.com>
723
committer: Lorem Ipsum <test@example.com>
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
724
branch nick: test_properties_in_log
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
725
timestamp: Wed 2005-11-23 12:08:27 +1000
726
message:
727
  add a
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
728
''',
729
                                 sio.getvalue())
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
730
3976.3.1 by Neil Martinsen-Burrell
Add custom properties handling to short log format
731
    def test_properties_in_short_log(self):
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
732
        """Log includes the custom properties returned by the registered
3976.3.1 by Neil Martinsen-Burrell
Add custom properties handling to short log format
733
        handlers.
734
        """
735
        wt = self.make_branch_and_tree('.')
736
        b = wt.branch
737
        self.build_tree(['a'])
738
        wt.add('a')
739
        b.nick = 'test_properties_in_short_log'
740
        wt.commit(message='add a',
741
                  timestamp=1132711707,
742
                  timezone=36000,
743
                  committer='Lorem Ipsum <test@example.com>',
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
744
                  authors=['John Doe <jdoe@example.com>'])
3976.3.1 by Neil Martinsen-Burrell
Add custom properties handling to short log format
745
        sio = StringIO()
746
        formatter = log.ShortLogFormatter(to_file=sio)
747
        try:
748
            def trivial_custom_prop_handler(revision):
749
                return {'test_prop':'test_value'}
750
751
            log.properties_handler_registry.register(
752
                'trivial_custom_prop_handler',
753
                trivial_custom_prop_handler)
754
            log.show_log(b, formatter)
755
        finally:
756
            log.properties_handler_registry.remove(
757
                'trivial_custom_prop_handler')
758
            self.assertEqualDiff('''\
3976.3.3 by Jelmer Vernooij
remove a tab character.
759
    1 John Doe\t2005-11-23
3976.3.1 by Neil Martinsen-Burrell
Add custom properties handling to short log format
760
      test_prop: test_value
761
      add a
762
763
''',
764
                                 sio.getvalue())
765
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
766
    def test_error_in_properties_handler(self):
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
767
        """Log includes the custom properties returned by the registered
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
768
        handlers.
769
        """
770
        wt = self.make_branch_and_tree('.')
771
        b = wt.branch
772
        self.build_tree(['a'])
773
        wt.add('a')
774
        b.nick = 'test_author_log'
775
        wt.commit(message='add a',
776
                  timestamp=1132711707,
777
                  timezone=36000,
778
                  committer='Lorem Ipsum <test@example.com>',
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
779
                  authors=['John Doe <jdoe@example.com>'],
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
780
                  revprops={'first_prop':'first_value'})
781
        sio = StringIO()
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
782
        formatter = log.LongLogFormatter(to_file=sio)
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
783
        try:
784
            def trivial_custom_prop_handler(revision):
785
                raise StandardError("a test error")
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
786
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
787
            log.properties_handler_registry.register(
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
788
                'trivial_custom_prop_handler',
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
789
                trivial_custom_prop_handler)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
790
            self.assertRaises(StandardError, log.show_log, b, formatter,)
3144.7.9 by Guillermo Gonzalez
* bzrlib.log.show_roperties don't hide handler errors
791
        finally:
792
            log.properties_handler_registry.remove(
793
                'trivial_custom_prop_handler')
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
794
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
795
    def test_properties_handler_bad_argument(self):
796
        wt = self.make_branch_and_tree('.')
797
        b = wt.branch
798
        self.build_tree(['a'])
799
        wt.add('a')
800
        b.nick = 'test_author_log'
801
        wt.commit(message='add a',
802
                  timestamp=1132711707,
803
                  timezone=36000,
804
                  committer='Lorem Ipsum <test@example.com>',
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
805
                  authors=['John Doe <jdoe@example.com>'],
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
806
                  revprops={'a_prop':'test_value'})
807
        sio = StringIO()
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
808
        formatter = log.LongLogFormatter(to_file=sio)
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
809
        try:
810
            def bad_argument_prop_handler(revision):
811
                return {'custom_prop_name':revision.properties['a_prop']}
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
812
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
813
            log.properties_handler_registry.register(
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
814
                'bad_argument_prop_handler',
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
815
                bad_argument_prop_handler)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
816
817
            self.assertRaises(AttributeError, formatter.show_properties,
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
818
                              'a revision', '')
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
819
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
820
            revision = b.repository.get_revision(b.last_revision())
821
            formatter.show_properties(revision, '')
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
822
            self.assertEqualDiff('''custom_prop_name: test_value\n''',
823
                                 sio.getvalue())
3144.7.13 by Guillermo Gonzalez
* fixed typo LogFormatter.show_properties in docstring
824
        finally:
825
            log.properties_handler_registry.remove(
826
                '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.
827
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
828
3947.1.2 by Ian Clatworthy
formatter tests
829
class TestLongLogFormatterWithoutMergeRevisions(TestCaseWithoutPropsHandler):
830
831
    def test_long_verbose_log(self):
832
        """Verbose log includes changed files
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
833
3947.1.2 by Ian Clatworthy
formatter tests
834
        bug #4676
835
        """
836
        wt = self.make_branch_and_tree('.')
837
        b = wt.branch
838
        self.build_tree(['a'])
839
        wt.add('a')
840
        # XXX: why does a longer nick show up?
841
        b.nick = 'test_verbose_log'
842
        wt.commit(message='add a',
843
                  timestamp=1132711707,
844
                  timezone=36000,
845
                  committer='Lorem Ipsum <test@example.com>')
846
        logfile = file('out.tmp', 'w+')
3947.1.6 by Ian Clatworthy
log -n/--level-count N option
847
        formatter = log.LongLogFormatter(to_file=logfile, levels=1)
3947.1.2 by Ian Clatworthy
formatter tests
848
        log.show_log(b, formatter, verbose=True)
849
        logfile.flush()
850
        logfile.seek(0)
851
        log_contents = logfile.read()
852
        self.assertEqualDiff('''\
853
------------------------------------------------------------
854
revno: 1
855
committer: Lorem Ipsum <test@example.com>
856
branch nick: test_verbose_log
857
timestamp: Wed 2005-11-23 12:08:27 +1000
858
message:
859
  add a
860
added:
861
  a
862
''',
863
                             log_contents)
864
865
    def test_long_verbose_contain_deltas(self):
866
        wt = self.make_branch_and_tree('parent')
867
        self.build_tree(['parent/f1', 'parent/f2'])
868
        wt.add(['f1','f2'])
869
        wt.commit('first post')
870
        self.run_bzr('branch parent child')
871
        os.unlink('child/f1')
872
        file('child/f2', 'wb').write('hello\n')
873
        self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
874
            'child'])
875
        os.chdir('parent')
876
        self.run_bzr('merge ../child')
877
        wt.commit('merge branch 1')
878
        b = wt.branch
879
        sio = self.make_utf8_encoded_stringio()
3947.1.6 by Ian Clatworthy
log -n/--level-count N option
880
        lf = log.LongLogFormatter(to_file=sio, levels=1)
3947.1.2 by Ian Clatworthy
formatter tests
881
        log.show_log(b, lf, verbose=True)
882
        the_log = normalize_log(sio.getvalue())
883
        self.assertEqualDiff("""\
884
------------------------------------------------------------
4208.2.1 by Ian Clatworthy
merge indicators in log --long
885
revno: 2 [merge]
3947.1.2 by Ian Clatworthy
formatter tests
886
committer: Lorem Ipsum <test@example.com>
887
branch nick: parent
888
timestamp: Just now
889
message:
890
  merge branch 1
891
removed:
892
  f1
893
modified:
894
  f2
895
------------------------------------------------------------
896
revno: 1
897
committer: Lorem Ipsum <test@example.com>
898
branch nick: parent
899
timestamp: Just now
900
message:
901
  first post
902
added:
903
  f1
904
  f2
905
""",
906
                             the_log)
907
908
    def test_long_trailing_newlines(self):
909
        wt = self.make_branch_and_tree('.')
910
        b = make_commits_with_trailing_newlines(wt)
911
        sio = self.make_utf8_encoded_stringio()
3947.1.6 by Ian Clatworthy
log -n/--level-count N option
912
        lf = log.LongLogFormatter(to_file=sio, levels=1)
3947.1.2 by Ian Clatworthy
formatter tests
913
        log.show_log(b, lf)
914
        self.assertEqualDiff("""\
915
------------------------------------------------------------
916
revno: 3
917
committer: Joe Foo <joe@foo.com>
918
branch nick: test
919
timestamp: Mon 2005-11-21 09:32:56 -0600
920
message:
921
  single line with trailing newline
922
------------------------------------------------------------
923
revno: 2
924
author: Joe Bar <joe@bar.com>
925
committer: Joe Foo <joe@foo.com>
926
branch nick: test
927
timestamp: Mon 2005-11-21 09:27:22 -0600
928
message:
929
  multiline
930
  log
931
  message
932
------------------------------------------------------------
933
revno: 1
934
committer: Joe Foo <joe@foo.com>
935
branch nick: test
936
timestamp: Mon 2005-11-21 09:24:15 -0600
937
message:
938
  simple log message
939
""",
940
                             sio.getvalue())
941
942
    def test_long_author_in_log(self):
943
        """Log includes the author name if it's set in
944
        the revision properties
945
        """
946
        wt = self.make_branch_and_tree('.')
947
        b = wt.branch
948
        self.build_tree(['a'])
949
        wt.add('a')
950
        b.nick = 'test_author_log'
951
        wt.commit(message='add a',
952
                  timestamp=1132711707,
953
                  timezone=36000,
954
                  committer='Lorem Ipsum <test@example.com>',
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
955
                  authors=['John Doe <jdoe@example.com>'])
3947.1.2 by Ian Clatworthy
formatter tests
956
        sio = StringIO()
3947.1.6 by Ian Clatworthy
log -n/--level-count N option
957
        formatter = log.LongLogFormatter(to_file=sio, levels=1)
3947.1.2 by Ian Clatworthy
formatter tests
958
        log.show_log(b, formatter)
959
        self.assertEqualDiff('''\
960
------------------------------------------------------------
961
revno: 1
962
author: John Doe <jdoe@example.com>
963
committer: Lorem Ipsum <test@example.com>
964
branch nick: test_author_log
965
timestamp: Wed 2005-11-23 12:08:27 +1000
966
message:
967
  add a
968
''',
969
                             sio.getvalue())
970
971
    def test_long_properties_in_log(self):
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
972
        """Log includes the custom properties returned by the registered
3947.1.2 by Ian Clatworthy
formatter tests
973
        handlers.
974
        """
975
        wt = self.make_branch_and_tree('.')
976
        b = wt.branch
977
        self.build_tree(['a'])
978
        wt.add('a')
979
        b.nick = 'test_properties_in_log'
980
        wt.commit(message='add a',
981
                  timestamp=1132711707,
982
                  timezone=36000,
983
                  committer='Lorem Ipsum <test@example.com>',
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
984
                  authors=['John Doe <jdoe@example.com>'])
3947.1.2 by Ian Clatworthy
formatter tests
985
        sio = StringIO()
3947.1.6 by Ian Clatworthy
log -n/--level-count N option
986
        formatter = log.LongLogFormatter(to_file=sio, levels=1)
3947.1.2 by Ian Clatworthy
formatter tests
987
        try:
988
            def trivial_custom_prop_handler(revision):
989
                return {'test_prop':'test_value'}
990
991
            log.properties_handler_registry.register(
992
                'trivial_custom_prop_handler',
993
                trivial_custom_prop_handler)
994
            log.show_log(b, formatter)
995
        finally:
996
            log.properties_handler_registry.remove(
997
                'trivial_custom_prop_handler')
998
            self.assertEqualDiff('''\
999
------------------------------------------------------------
1000
revno: 1
1001
test_prop: test_value
1002
author: John Doe <jdoe@example.com>
1003
committer: Lorem Ipsum <test@example.com>
1004
branch nick: test_properties_in_log
1005
timestamp: Wed 2005-11-23 12:08:27 +1000
1006
message:
1007
  add a
1008
''',
1009
                                 sio.getvalue())
1010
1011
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1012
class TestLineLogFormatter(tests.TestCaseWithTransport):
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
1013
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
1014
    def test_line_log(self):
1015
        """Line log should show revno
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
1016
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
1017
        bug #5162
1018
        """
1019
        wt = self.make_branch_and_tree('.')
1020
        b = wt.branch
1021
        self.build_tree(['a'])
1022
        wt.add('a')
1023
        b.nick = 'test-line-log'
3642.1.5 by Robert Collins
Separate out batching of revisions.
1024
        wt.commit(message='add a',
1025
                  timestamp=1132711707,
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
1026
                  timezone=36000,
1027
                  committer='Line-Log-Formatter Tester <test@line.log>')
1028
        logfile = file('out.tmp', 'w+')
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1029
        formatter = log.LineLogFormatter(to_file=logfile)
1030
        log.show_log(b, formatter)
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
1031
        logfile.flush()
1032
        logfile.seek(0)
1033
        log_contents = logfile.read()
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
1034
        self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
1035
                             log_contents)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
1036
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
1037
    def test_trailing_newlines(self):
1038
        wt = self.make_branch_and_tree('.')
1039
        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.
1040
        sio = self.make_utf8_encoded_stringio()
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1041
        lf = log.LineLogFormatter(to_file=sio)
1042
        log.show_log(b, lf)
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
1043
        self.assertEqualDiff("""\
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
1044
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.
1045
2: Joe Bar 2005-11-21 multiline
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
1046
1: Joe Foo 2005-11-21 simple log message
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
1047
""",
1048
                             sio.getvalue())
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
1049
3946.3.2 by Ian Clatworthy
add tests & NEWS item
1050
    def _prepare_tree_with_merges(self, with_tags=False):
1051
        wt = self.make_branch_and_memory_tree('.')
1052
        wt.lock_write()
1053
        self.addCleanup(wt.unlock)
1054
        wt.add('')
1055
        wt.commit('rev-1', rev_id='rev-1',
1056
                  timestamp=1132586655, timezone=36000,
1057
                  committer='Joe Foo <joe@foo.com>')
1058
        wt.commit('rev-merged', rev_id='rev-2a',
1059
                  timestamp=1132586700, timezone=36000,
1060
                  committer='Joe Foo <joe@foo.com>')
1061
        wt.set_parent_ids(['rev-1', 'rev-2a'])
1062
        wt.branch.set_last_revision_info(1, 'rev-1')
1063
        wt.commit('rev-2', rev_id='rev-2b',
1064
                  timestamp=1132586800, timezone=36000,
1065
                  committer='Joe Foo <joe@foo.com>')
1066
        if with_tags:
1067
            branch = wt.branch
1068
            branch.tags.set_tag('v0.2', 'rev-2b')
1069
            wt.commit('rev-3', rev_id='rev-3',
1070
                      timestamp=1132586900, timezone=36000,
1071
                      committer='Jane Foo <jane@foo.com>')
1072
            branch.tags.set_tag('v1.0rc1', 'rev-3')
1073
            branch.tags.set_tag('v1.0', 'rev-3')
1074
        return wt
1075
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
1076
    def test_line_log_single_merge_revision(self):
3946.3.2 by Ian Clatworthy
add tests & NEWS item
1077
        wt = self._prepare_tree_with_merges()
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
1078
        logfile = self.make_utf8_encoded_stringio()
1079
        formatter = log.LineLogFormatter(to_file=logfile)
1080
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1081
        wtb = wt.branch
1082
        rev = revspec.in_history(wtb)
1083
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
1084
        self.assertEqualDiff("""\
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
1085
1.1.1: Joe Foo 2005-11-22 rev-merged
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
1086
""",
1087
                             logfile.getvalue())
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
1088
3946.3.2 by Ian Clatworthy
add tests & NEWS item
1089
    def test_line_log_with_tags(self):
1090
        wt = self._prepare_tree_with_merges(with_tags=True)
1091
        logfile = self.make_utf8_encoded_stringio()
1092
        formatter = log.LineLogFormatter(to_file=logfile)
1093
        log.show_log(wt.branch, formatter)
1094
        self.assertEqualDiff("""\
3946.3.3 by Ian Clatworthy
feedback from jelmer re position of tags in --line
1095
3: Jane Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
3983.2.1 by Neil Martinsen-Burrell
add merge indication to the line format
1096
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
3946.3.2 by Ian Clatworthy
add tests & NEWS item
1097
1: Joe Foo 2005-11-22 rev-1
1098
""",
1099
                             logfile.getvalue())
2997.1.1 by Kent Gibson
Support logging single merge revisions with short and line log formatters.
1100
3947.1.2 by Ian Clatworthy
formatter tests
1101
class TestLineLogFormatterWithMergeRevisions(tests.TestCaseWithTransport):
1102
1103
    def test_line_merge_revs_log(self):
1104
        """Line log should show revno
4032.1.2 by John Arbash Meinel
Track down a few more files that have trailing whitespace.
1105
3947.1.2 by Ian Clatworthy
formatter tests
1106
        bug #5162
1107
        """
1108
        wt = self.make_branch_and_tree('.')
1109
        b = wt.branch
1110
        self.build_tree(['a'])
1111
        wt.add('a')
1112
        b.nick = 'test-line-log'
1113
        wt.commit(message='add a',
1114
                  timestamp=1132711707,
1115
                  timezone=36000,
1116
                  committer='Line-Log-Formatter Tester <test@line.log>')
1117
        logfile = file('out.tmp', 'w+')
3947.1.6 by Ian Clatworthy
log -n/--level-count N option
1118
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
3947.1.2 by Ian Clatworthy
formatter tests
1119
        log.show_log(b, formatter)
1120
        logfile.flush()
1121
        logfile.seek(0)
1122
        log_contents = logfile.read()
1123
        self.assertEqualDiff('1: Line-Log-Formatte... 2005-11-23 add a\n',
1124
                             log_contents)
1125
1126
    def test_line_merge_revs_log_single_merge_revision(self):
1127
        wt = self.make_branch_and_memory_tree('.')
1128
        wt.lock_write()
1129
        self.addCleanup(wt.unlock)
1130
        wt.add('')
1131
        wt.commit('rev-1', rev_id='rev-1',
1132
                  timestamp=1132586655, timezone=36000,
1133
                  committer='Joe Foo <joe@foo.com>')
1134
        wt.commit('rev-merged', rev_id='rev-2a',
1135
                  timestamp=1132586700, timezone=36000,
1136
                  committer='Joe Foo <joe@foo.com>')
1137
        wt.set_parent_ids(['rev-1', 'rev-2a'])
1138
        wt.branch.set_last_revision_info(1, 'rev-1')
1139
        wt.commit('rev-2', rev_id='rev-2b',
1140
                  timestamp=1132586800, timezone=36000,
1141
                  committer='Joe Foo <joe@foo.com>')
1142
        logfile = self.make_utf8_encoded_stringio()
3947.1.6 by Ian Clatworthy
log -n/--level-count N option
1143
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
3947.1.2 by Ian Clatworthy
formatter tests
1144
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
1145
        wtb = wt.branch
1146
        rev = revspec.in_history(wtb)
1147
        log.show_log(wtb, formatter, start_revision=rev, end_revision=rev)
1148
        self.assertEqualDiff("""\
1149
1.1.1: Joe Foo 2005-11-22 rev-merged
1150
""",
1151
                             logfile.getvalue())
1152
1153
    def test_line_merge_revs_log_with_merges(self):
1154
        wt = self.make_branch_and_memory_tree('.')
1155
        wt.lock_write()
1156
        self.addCleanup(wt.unlock)
1157
        wt.add('')
1158
        wt.commit('rev-1', rev_id='rev-1',
1159
                  timestamp=1132586655, timezone=36000,
1160
                  committer='Joe Foo <joe@foo.com>')
1161
        wt.commit('rev-merged', rev_id='rev-2a',
1162
                  timestamp=1132586700, timezone=36000,
1163
                  committer='Joe Foo <joe@foo.com>')
1164
        wt.set_parent_ids(['rev-1', 'rev-2a'])
1165
        wt.branch.set_last_revision_info(1, 'rev-1')
1166
        wt.commit('rev-2', rev_id='rev-2b',
1167
                  timestamp=1132586800, timezone=36000,
1168
                  committer='Joe Foo <joe@foo.com>')
1169
        logfile = self.make_utf8_encoded_stringio()
3947.1.6 by Ian Clatworthy
log -n/--level-count N option
1170
        formatter = log.LineLogFormatter(to_file=logfile, levels=0)
3947.1.2 by Ian Clatworthy
formatter tests
1171
        log.show_log(wt.branch, formatter)
1172
        self.assertEqualDiff("""\
3983.2.1 by Neil Martinsen-Burrell
add merge indication to the line format
1173
2: Joe Foo 2005-11-22 [merge] rev-2
3947.1.2 by Ian Clatworthy
formatter tests
1174
  1.1.1: Joe Foo 2005-11-22 rev-merged
1175
1: Joe Foo 2005-11-22 rev-1
1176
""",
1177
                             logfile.getvalue())
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
1178
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1179
class TestGetViewRevisions(tests.TestCaseWithTransport):
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
1180
1756.2.22 by Aaron Bentley
Apply review comments
1181
    def make_tree_with_commits(self):
1182
        """Create a tree with well-known revision ids"""
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
1183
        wt = self.make_branch_and_tree('tree1')
1184
        wt.commit('commit one', rev_id='1')
1185
        wt.commit('commit two', rev_id='2')
1186
        wt.commit('commit three', rev_id='3')
1187
        mainline_revs = [None, '1', '2', '3']
1756.2.22 by Aaron Bentley
Apply review comments
1188
        rev_nos = {'1': 1, '2': 2, '3': 3}
1189
        return mainline_revs, rev_nos, wt
1190
1191
    def make_tree_with_merges(self):
1192
        """Create a tree with well-known revision ids and a merge"""
1193
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
1194
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1195
        tree2.commit('four-a', rev_id='4a')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
1196
        wt.merge_from_branch(tree2.branch)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
1197
        wt.commit('four-b', rev_id='4b')
1198
        mainline_revs.append('4b')
1756.2.22 by Aaron Bentley
Apply review comments
1199
        rev_nos['4b'] = 4
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1200
        # 4a: 3.1.1
1756.2.22 by Aaron Bentley
Apply review comments
1201
        return mainline_revs, rev_nos, wt
1202
4615.1.2 by John Arbash Meinel
clarify the test a bit by using BranchBuilder.
1203
    def make_branch_with_many_merges(self):
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
1204
        """Create a tree with well-known revision ids"""
4615.1.2 by John Arbash Meinel
clarify the test a bit by using BranchBuilder.
1205
        builder = self.make_branch_builder('tree1')
1206
        builder.start_series()
1207
        builder.build_snapshot('1', None, [
1208
            ('add', ('', 'TREE_ROOT', 'directory', '')),
1209
            ('add', ('f', 'f-id', 'file', '1\n'))])
1210
        builder.build_snapshot('2', ['1'], [])
1211
        builder.build_snapshot('3a', ['2'], [
1212
            ('modify', ('f-id', '1\n2\n3a\n'))])
1213
        builder.build_snapshot('3b', ['2', '3a'], [
1214
            ('modify', ('f-id', '1\n2\n3a\n'))])
1215
        builder.build_snapshot('3c', ['2', '3b'], [
1216
            ('modify', ('f-id', '1\n2\n3a\n'))])
1217
        builder.build_snapshot('4a', ['3b'], [])
1218
        builder.build_snapshot('4b', ['3c', '4a'], [])
1219
        builder.finish_series()
1220
1221
        # 1
1222
        # |
1223
        # 2-.
1224
        # |\ \
1225
        # | | 3a
1226
        # | |/
1227
        # | 3b
1228
        # |/|
1229
        # 3c4a
1230
        # |/
1231
        # 4b
3842.2.5 by Vincent Ladeuil
Better fix for bug #300055.
1232
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
1233
        mainline_revs = [None, '1', '2', '3c', '4b']
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1234
        rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
1235
        full_rev_nos_for_reference = {
1236
            '1': '1',
1237
            '2': '2',
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
1238
            '3a': '2.1.1', #first commit tree 3
1239
            '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,
1240
            '3c': '3', #merges 3b to main
3170.3.4 by John Arbash Meinel
Update the tests for the new revision numbering.
1241
            '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,
1242
            '4b': '4', # merges 4a to main
1243
            }
4615.1.2 by John Arbash Meinel
clarify the test a bit by using BranchBuilder.
1244
        return mainline_revs, rev_nos, builder.get_branch()
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
1245
1756.2.22 by Aaron Bentley
Apply review comments
1246
    def test_get_view_revisions_forward(self):
1247
        """Test the get_view_revisions method"""
1248
        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.
1249
        wt.lock_read()
1250
        self.addCleanup(wt.unlock)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1251
        revisions = list(log.get_view_revisions(
1252
                mainline_revs, rev_nos, wt.branch, 'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1253
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
3842.2.2 by Vincent Ladeuil
Reproduce bug #300055.
1254
                         revisions)
1255
        revisions2 = list(log.get_view_revisions(
1256
                mainline_revs, rev_nos, wt.branch, 'forward',
1257
                include_merges=False))
1756.2.22 by Aaron Bentley
Apply review comments
1258
        self.assertEqual(revisions, revisions2)
1259
1260
    def test_get_view_revisions_reverse(self):
1261
        """Test the get_view_revisions with reverse"""
1262
        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.
1263
        wt.lock_read()
1264
        self.addCleanup(wt.unlock)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1265
        revisions = list(log.get_view_revisions(
1266
                mainline_revs, rev_nos, wt.branch, 'reverse'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1267
        self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
3842.2.2 by Vincent Ladeuil
Reproduce bug #300055.
1268
                         revisions)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1269
        revisions2 = list(log.get_view_revisions(
1270
                mainline_revs, rev_nos, wt.branch, 'reverse',
1271
                include_merges=False))
1756.2.22 by Aaron Bentley
Apply review comments
1272
        self.assertEqual(revisions, revisions2)
1273
1274
    def test_get_view_revisions_merge(self):
1275
        """Test get_view_revisions when there are merges"""
1276
        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.
1277
        wt.lock_read()
1278
        self.addCleanup(wt.unlock)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1279
        revisions = list(log.get_view_revisions(
1280
                mainline_revs, rev_nos, wt.branch, 'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1281
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
3842.2.2 by Vincent Ladeuil
Reproduce bug #300055.
1282
                          ('4b', '4', 0), ('4a', '3.1.1', 1)],
1283
                         revisions)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1284
        revisions = list(log.get_view_revisions(
1285
                mainline_revs, rev_nos, wt.branch, 'forward',
1286
                include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1287
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
3842.2.2 by Vincent Ladeuil
Reproduce bug #300055.
1288
                          ('4b', '4', 0)],
1289
                         revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
1290
1291
    def test_get_view_revisions_merge_reverse(self):
1292
        """Test get_view_revisions in reverse when there are merges"""
1293
        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.
1294
        wt.lock_read()
1295
        self.addCleanup(wt.unlock)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1296
        revisions = list(log.get_view_revisions(
1297
                mainline_revs, rev_nos, wt.branch, 'reverse'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1298
        self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
3842.2.2 by Vincent Ladeuil
Reproduce bug #300055.
1299
                          ('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
1300
                         revisions)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1301
        revisions = list(log.get_view_revisions(
1302
                mainline_revs, rev_nos, wt.branch, 'reverse',
1303
                include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1304
        self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
3842.2.2 by Vincent Ladeuil
Reproduce bug #300055.
1305
                          ('1', '1', 0)],
1306
                         revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
1307
1308
    def test_get_view_revisions_merge2(self):
1309
        """Test get_view_revisions when there are merges"""
4615.1.2 by John Arbash Meinel
clarify the test a bit by using BranchBuilder.
1310
        mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1311
        b.lock_read()
1312
        self.addCleanup(b.unlock)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1313
        revisions = list(log.get_view_revisions(
4615.1.2 by John Arbash Meinel
clarify the test a bit by using BranchBuilder.
1314
                mainline_revs, rev_nos, b, 'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1315
        expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
4615.1.3 by John Arbash Meinel
Since the merge depth changed, it causes log to change slightly as well.
1316
                    ('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
3842.2.2 by Vincent Ladeuil
Reproduce bug #300055.
1317
                    ('4a', '2.2.2', 1)]
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1318
        self.assertEqual(expected, revisions)
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1319
        revisions = list(log.get_view_revisions(
4615.1.2 by John Arbash Meinel
clarify the test a bit by using BranchBuilder.
1320
                mainline_revs, rev_nos, b, 'forward',
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1321
                include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
1322
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
3842.2.2 by Vincent Ladeuil
Reproduce bug #300055.
1323
                          ('4b', '4', 0)],
1324
                         revisions)
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
1325
1326
3842.2.5 by Vincent Ladeuil
Better fix for bug #300055.
1327
    def test_file_id_for_range(self):
4615.1.2 by John Arbash Meinel
clarify the test a bit by using BranchBuilder.
1328
        mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1329
        b.lock_read()
1330
        self.addCleanup(b.unlock)
3842.2.5 by Vincent Ladeuil
Better fix for bug #300055.
1331
1332
        def rev_from_rev_id(revid, branch):
1333
            revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1334
            return revspec.in_history(branch)
1335
1336
        def view_revs(start_rev, end_rev, file_id, direction):
1337
            revs = log.calculate_view_revisions(
4615.1.2 by John Arbash Meinel
clarify the test a bit by using BranchBuilder.
1338
                b,
3842.2.5 by Vincent Ladeuil
Better fix for bug #300055.
1339
                start_rev, # start_revision
1340
                end_rev, # end_revision
1341
                direction, # direction
1342
                file_id, # specific_fileid
1343
                True, # generate_merge_revisions
1344
                )
1345
            return revs
1346
4615.1.2 by John Arbash Meinel
clarify the test a bit by using BranchBuilder.
1347
        rev_3a = rev_from_rev_id('3a', b)
1348
        rev_4b = rev_from_rev_id('4b', b)
4615.1.3 by John Arbash Meinel
Since the merge depth changed, it causes log to change slightly as well.
1349
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1), ('3a', '2.1.1', 2)],
3842.2.5 by Vincent Ladeuil
Better fix for bug #300055.
1350
                          view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
3936.3.30 by Ian Clatworthy
use iter_merge_sorted_revisions() with stop_range feature
1351
        # Note: 3c still appears before 3a here because of depth-based sorting
4615.1.3 by John Arbash Meinel
Since the merge depth changed, it causes log to change slightly as well.
1352
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1), ('3a', '2.1.1', 2)],
3842.2.5 by Vincent Ladeuil
Better fix for bug #300055.
1353
                          view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1354
1355
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1356
class TestGetRevisionsTouchingFileID(tests.TestCaseWithTransport):
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
1357
1358
    def create_tree_with_single_merge(self):
1359
        """Create a branch with a moderate layout.
1360
1361
        The revision graph looks like:
1362
1363
           A
1364
           |\
1365
           B C
1366
           |/
1367
           D
1368
1369
        In this graph, A introduced files f1 and f2 and f3.
1370
        B modifies f1 and f3, and C modifies f2 and f3.
1371
        D merges the changes from B and C and resolves the conflict for f3.
1372
        """
1373
        # TODO: jam 20070218 This seems like it could really be done
1374
        #       with make_branch_and_memory_tree() if we could just
1375
        #       create the content of those files.
1376
        # TODO: jam 20070218 Another alternative is that we would really
1377
        #       like to only create this tree 1 time for all tests that
1378
        #       use it. Since 'log' only uses the tree in a readonly
1379
        #       fashion, it seems a shame to regenerate an identical
1380
        #       tree for each test.
1381
        tree = self.make_branch_and_tree('tree')
1382
        tree.lock_write()
1383
        self.addCleanup(tree.unlock)
1384
1385
        self.build_tree_contents([('tree/f1', 'A\n'),
1386
                                  ('tree/f2', 'A\n'),
1387
                                  ('tree/f3', 'A\n'),
1388
                                 ])
1389
        tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
1390
        tree.commit('A', rev_id='A')
1391
1392
        self.build_tree_contents([('tree/f2', 'A\nC\n'),
1393
                                  ('tree/f3', 'A\nC\n'),
1394
                                 ])
1395
        tree.commit('C', rev_id='C')
1396
        # Revert back to A to build the other history.
1397
        tree.set_last_revision('A')
1398
        tree.branch.set_last_revision_info(1, 'A')
1399
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
1400
                                  ('tree/f2', 'A\n'),
1401
                                  ('tree/f3', 'A\nB\n'),
1402
                                 ])
1403
        tree.commit('B', rev_id='B')
1404
        tree.set_parent_ids(['B', 'C'])
1405
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
1406
                                  ('tree/f2', 'A\nC\n'),
1407
                                  ('tree/f3', 'A\nB\nC\n'),
1408
                                 ])
1409
        tree.commit('D', rev_id='D')
1410
1411
        # Switch to a read lock for this tree.
3842.2.5 by Vincent Ladeuil
Better fix for bug #300055.
1412
        # We still have an addCleanup(tree.unlock) pending
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
1413
        tree.unlock()
1414
        tree.lock_read()
1415
        return tree
1416
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
1417
    def check_delta(self, delta, **kw):
1418
        """Check the filenames touched by a delta are as expected.
1419
1420
        Caller only have to pass in the list of files for each part, all
1421
        unspecified parts are considered empty (and checked as such).
1422
        """
1423
        for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
1424
            # By default we expect an empty list
1425
            expected = kw.get(n, [])
1426
            # strip out only the path components
1427
            got = [x[0] for x in getattr(delta, n)]
3842.2.7 by Vincent Ladeuil
Fixed as per Jonh's review.
1428
            self.assertEqual(expected, got)
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
1429
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
1430
    def test_tree_with_single_merge(self):
1431
        """Make sure the tree layout is correct."""
1432
        tree = self.create_tree_with_single_merge()
1433
        rev_A_tree = tree.branch.repository.revision_tree('A')
1434
        rev_B_tree = tree.branch.repository.revision_tree('B')
1435
        rev_C_tree = tree.branch.repository.revision_tree('C')
1436
        rev_D_tree = tree.branch.repository.revision_tree('D')
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
1437
1438
        self.check_delta(rev_B_tree.changes_from(rev_A_tree),
1439
                         modified=['f1', 'f3'])
1440
1441
        self.check_delta(rev_C_tree.changes_from(rev_A_tree),
1442
                         modified=['f2', 'f3'])
1443
1444
        self.check_delta(rev_D_tree.changes_from(rev_B_tree),
1445
                         modified=['f2', 'f3'])
1446
1447
        self.check_delta(rev_D_tree.changes_from(rev_C_tree),
1448
                         modified=['f1', 'f3'])
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
1449
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
1450
    def assertAllRevisionsForFileID(self, tree, file_id, revisions):
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1451
        """Ensure _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
1452
2466.12.1 by Kent Gibson
Fix ``bzr log -r`` to support selecting merge revisions.
1453
        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
1454
        sure they are correct.
1455
        """
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
1456
        # The api for _filter_revisions_touching_file_id is a little crazy.
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
1457
        # So we do the setup here.
1458
        mainline = tree.branch.revision_history()
1459
        mainline.insert(0, None)
1460
        revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
1461
        view_revs_iter = log.get_view_revisions(mainline, revnos, tree.branch,
1462
                                                'reverse', True)
2466.12.1 by Kent Gibson
Fix ``bzr log -r`` to support selecting merge revisions.
1463
        actual_revs = log._filter_revisions_touching_file_id(
3711.3.23 by John Arbash Meinel
Documentation and cleanup.
1464
                            tree.branch,
2466.12.1 by Kent Gibson
Fix ``bzr log -r`` to support selecting merge revisions.
1465
                            file_id,
3842.2.5 by Vincent Ladeuil
Better fix for bug #300055.
1466
                            list(view_revs_iter))
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
1467
        self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
1468
1469
    def test_file_id_f1(self):
1470
        tree = self.create_tree_with_single_merge()
1471
        # f1 should be marked as modified by revisions A and B
1472
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
1473
1474
    def test_file_id_f2(self):
1475
        tree = self.create_tree_with_single_merge()
1476
        # f2 should be marked as modified by revisions A, C, and D
1477
        # because D merged the changes from C.
1478
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1479
1480
    def test_file_id_f3(self):
1481
        tree = self.create_tree_with_single_merge()
1482
        # f3 should be marked as modified by revisions A, B, C, and D
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
1483
        self.assertAllRevisionsForFileID(tree, 'f3-id', ['D', 'C', 'B', 'A'])
1551.17.2 by Aaron Bentley
Stop showing deltas in pull -v output
1484
3373.2.1 by John Arbash Meinel
Fix bug #209948, properly skip over ghosts when displaying the changes for a single file.
1485
    def test_file_id_with_ghosts(self):
1486
        # This is testing bug #209948, where having a ghost would cause
1487
        # _filter_revisions_touching_file_id() to fail.
1488
        tree = self.create_tree_with_single_merge()
1489
        # We need to add a revision, so switch back to a write-locked tree
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
1490
        # (still a single addCleanup(tree.unlock) pending).
3373.2.1 by John Arbash Meinel
Fix bug #209948, properly skip over ghosts when displaying the changes for a single file.
1491
        tree.unlock()
1492
        tree.lock_write()
1493
        first_parent = tree.last_revision()
1494
        tree.set_parent_ids([first_parent, 'ghost-revision-id'])
1495
        self.build_tree_contents([('tree/f1', 'A\nB\nXX\n')])
1496
        tree.commit('commit with a ghost', rev_id='XX')
1497
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['XX', 'B', 'A'])
1498
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1499
4183.3.1 by Vincent Ladeuil
Fix bug #346431 by allowing log._filter_revisions_touching_file_id to be
1500
    def test_unknown_file_id(self):
1501
        tree = self.create_tree_with_single_merge()
1502
        self.assertAllRevisionsForFileID(tree, 'unknown', [])
1503
1504
    def test_empty_branch_unknown_file_id(self):
1505
        tree = self.make_branch_and_tree('tree')
1506
        self.assertAllRevisionsForFileID(tree, 'unknown', [])
1507
1551.17.2 by Aaron Bentley
Stop showing deltas in pull -v output
1508
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1509
class TestShowChangedRevisions(tests.TestCaseWithTransport):
1551.17.2 by Aaron Bentley
Stop showing deltas in pull -v output
1510
1511
    def test_show_changed_revisions_verbose(self):
1512
        tree = self.make_branch_and_tree('tree_a')
1513
        self.build_tree(['tree_a/foo'])
1514
        tree.add('foo')
1515
        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.
1516
        s = self.make_utf8_encoded_stringio()
1551.17.2 by Aaron Bentley
Stop showing deltas in pull -v output
1517
        log.show_changed_revisions(tree.branch, [], ['bar-id'], s)
1518
        self.assertContainsRe(s.getvalue(), 'bar')
1519
        self.assertNotContainsRe(s.getvalue(), 'foo')
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
1520
1521
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1522
class TestLogFormatter(tests.TestCase):
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
1523
1524
    def test_short_committer(self):
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1525
        rev = revision.Revision('a-id')
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
1526
        rev.committer = 'John Doe <jdoe@example.com>'
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1527
        lf = log.LogFormatter(None)
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
1528
        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.
1529
        rev.committer = 'John Smith <jsmith@example.com>'
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1530
        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.
1531
        rev.committer = 'John Smith'
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1532
        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.
1533
        rev.committer = 'jsmith@example.com'
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1534
        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.
1535
        rev.committer = '<jsmith@example.com>'
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1536
        self.assertEqual('jsmith@example.com', lf.short_committer(rev))
1537
        rev.committer = 'John Smith jsmith@example.com'
1538
        self.assertEqual('John Smith', lf.short_committer(rev))
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
1539
1540
    def test_short_author(self):
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1541
        rev = revision.Revision('a-id')
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
1542
        rev.committer = 'John Doe <jdoe@example.com>'
3842.2.1 by Vincent Ladeuil
Cosmetic changes.
1543
        lf = log.LogFormatter(None)
2671.5.8 by Lukáš Lalinsky
Add tests for LogFormatter.short_committer and LogFormatter.short_author.
1544
        self.assertEqual('John Doe', lf.short_author(rev))
1545
        rev.properties['author'] = 'John Smith <jsmith@example.com>'
1546
        self.assertEqual('John Smith', lf.short_author(rev))
3063.3.1 by Lukáš Lalinský
Fall back to showing e-mail in ``log --short/--line`` if the committer/author has only e-mail.
1547
        rev.properties['author'] = 'John Smith'
1548
        self.assertEqual('John Smith', lf.short_author(rev))
1549
        rev.properties['author'] = 'jsmith@example.com'
1550
        self.assertEqual('jsmith@example.com', lf.short_author(rev))
1551
        rev.properties['author'] = '<jsmith@example.com>'
1552
        self.assertEqual('jsmith@example.com', lf.short_author(rev))
3063.3.3 by Lukáš Lalinský
Add one more test for config.parse_username().
1553
        rev.properties['author'] = 'John Smith jsmith@example.com'
1554
        self.assertEqual('John Smith', lf.short_author(rev))
4056.2.3 by James Westby
Use a new "authors" revision property to allow multiple authors
1555
        del rev.properties['author']
1556
        rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1557
                'Jane Rey <jrey@example.com>')
1558
        self.assertEqual('John Smith', lf.short_author(rev))
3842.2.2 by Vincent Ladeuil
Reproduce bug #300055.
1559
1560
1561
class TestReverseByDepth(tests.TestCase):
1562
    """Test reverse_by_depth behavior.
1563
1564
    This is used to present revisions in forward (oldest first) order in a nice
1565
    layout.
1566
1567
    The tests use lighter revision description to ease reading.
1568
    """
1569
1570
    def assertReversed(self, forward, backward):
1571
        # Transform the descriptions to suit the API: tests use (revno, depth),
1572
        # while the API expects (revid, revno, depth)
1573
        def complete_revisions(l):
1574
            """Transform the description to suit the API.
1575
1576
            Tests use (revno, depth) whil the API expects (revid, revno, depth).
1577
            Since the revid is arbitrary, we just duplicate revno
1578
            """
1579
            return [ (r, r, d) for r, d in l]
1580
        forward = complete_revisions(forward)
1581
        backward= complete_revisions(backward)
1582
        self.assertEqual(forward, log.reverse_by_depth(backward))
1583
1584
1585
    def test_mainline_revisions(self):
1586
        self.assertReversed([( '1', 0), ('2', 0)],
1587
                            [('2', 0), ('1', 0)])
1588
1589
    def test_merged_revisions(self):
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
1590
        self.assertReversed([('1', 0), ('2', 0), ('2.2', 1), ('2.1', 1),],
1591
                            [('2', 0), ('2.1', 1), ('2.2', 1), ('1', 0),])
3842.2.2 by Vincent Ladeuil
Reproduce bug #300055.
1592
    def test_shifted_merged_revisions(self):
1593
        """Test irregular layout.
1594
1595
        Requesting revisions touching a file can produce "holes" in the depths.
1596
        """
1597
        self.assertReversed([('1', 0), ('2', 0), ('1.1', 2), ('1.2', 2),],
1598
                            [('2', 0), ('1.2', 2), ('1.1', 2), ('1', 0),])
3842.2.3 by Vincent Ladeuil
Yet more cleanup and fix test_file_id_f3 bogus test.
1599
1600
    def test_merged_without_child_revisions(self):
1601
        """Test irregular layout.
1602
1603
        Revision ranges can produce "holes" in the depths.
1604
        """
1605
        # When a revision of higher depth doesn't follow one of lower depth, we
1606
        # assume a lower depth one is virtually there
1607
        self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1608
                            [('4', 4), ('3', 3), ('2', 2), ('1', 2),])
1609
        # So we get the same order after reversing below even if the original
1610
        # revisions are not in the same order.
1611
        self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1612
                            [('3', 3), ('4', 4), ('2', 2), ('1', 2),])
3848.1.6 by Aaron Bentley
Implement get_history_change
1613
1614
3848.1.8 by Aaron Bentley
Implement basic show_branch_change
1615
class TestHistoryChange(tests.TestCaseWithTransport):
3848.1.6 by Aaron Bentley
Implement get_history_change
1616
1617
    def setup_a_tree(self):
1618
        tree = self.make_branch_and_tree('tree')
1619
        tree.lock_write()
1620
        self.addCleanup(tree.unlock)
1621
        tree.commit('1a', rev_id='1a')
1622
        tree.commit('2a', rev_id='2a')
1623
        tree.commit('3a', rev_id='3a')
1624
        return tree
1625
1626
    def setup_ab_tree(self):
1627
        tree = self.setup_a_tree()
1628
        tree.set_last_revision('1a')
1629
        tree.branch.set_last_revision_info(1, '1a')
1630
        tree.commit('2b', rev_id='2b')
1631
        tree.commit('3b', rev_id='3b')
1632
        return tree
1633
1634
    def setup_ac_tree(self):
1635
        tree = self.setup_a_tree()
1636
        tree.set_last_revision(revision.NULL_REVISION)
1637
        tree.branch.set_last_revision_info(0, revision.NULL_REVISION)
1638
        tree.commit('1c', rev_id='1c')
1639
        tree.commit('2c', rev_id='2c')
1640
        tree.commit('3c', rev_id='3c')
1641
        return tree
1642
1643
    def test_all_new(self):
1644
        tree = self.setup_ab_tree()
3848.1.7 by Aaron Bentley
Use repository in get_history_change
1645
        old, new = log.get_history_change('1a', '3a', tree.branch.repository)
3848.1.6 by Aaron Bentley
Implement get_history_change
1646
        self.assertEqual([], old)
1647
        self.assertEqual(['2a', '3a'], new)
1648
1649
    def test_all_old(self):
1650
        tree = self.setup_ab_tree()
3848.1.7 by Aaron Bentley
Use repository in get_history_change
1651
        old, new = log.get_history_change('3a', '1a', tree.branch.repository)
3848.1.6 by Aaron Bentley
Implement get_history_change
1652
        self.assertEqual([], new)
1653
        self.assertEqual(['2a', '3a'], old)
1654
1655
    def test_null_old(self):
1656
        tree = self.setup_ab_tree()
1657
        old, new = log.get_history_change(revision.NULL_REVISION,
3848.1.7 by Aaron Bentley
Use repository in get_history_change
1658
                                          '3a', tree.branch.repository)
3848.1.6 by Aaron Bentley
Implement get_history_change
1659
        self.assertEqual([], old)
1660
        self.assertEqual(['1a', '2a', '3a'], new)
1661
1662
    def test_null_new(self):
1663
        tree = self.setup_ab_tree()
3848.1.7 by Aaron Bentley
Use repository in get_history_change
1664
        old, new = log.get_history_change('3a', revision.NULL_REVISION,
1665
                                          tree.branch.repository)
3848.1.6 by Aaron Bentley
Implement get_history_change
1666
        self.assertEqual([], new)
1667
        self.assertEqual(['1a', '2a', '3a'], old)
1668
1669
    def test_diverged(self):
1670
        tree = self.setup_ab_tree()
3848.1.7 by Aaron Bentley
Use repository in get_history_change
1671
        old, new = log.get_history_change('3a', '3b', tree.branch.repository)
3848.1.6 by Aaron Bentley
Implement get_history_change
1672
        self.assertEqual(old, ['2a', '3a'])
1673
        self.assertEqual(new, ['2b', '3b'])
1674
1675
    def test_unrelated(self):
1676
        tree = self.setup_ac_tree()
3848.1.7 by Aaron Bentley
Use repository in get_history_change
1677
        old, new = log.get_history_change('3a', '3c', tree.branch.repository)
3848.1.6 by Aaron Bentley
Implement get_history_change
1678
        self.assertEqual(old, ['1a', '2a', '3a'])
1679
        self.assertEqual(new, ['1c', '2c', '3c'])
3848.1.8 by Aaron Bentley
Implement basic show_branch_change
1680
1681
    def test_show_branch_change(self):
1682
        tree = self.setup_ab_tree()
1683
        s = StringIO()
3848.1.12 by Aaron Bentley
Fix test parameter order
1684
        log.show_branch_change(tree.branch, s, 3, '3a')
3848.1.8 by Aaron Bentley
Implement basic show_branch_change
1685
        self.assertContainsRe(s.getvalue(),
1686
            '[*]{60}\nRemoved Revisions:\n(.|\n)*2a(.|\n)*3a(.|\n)*'
1687
            '[*]{60}\n\nAdded Revisions:\n(.|\n)*2b(.|\n)*3b')
1688
1689
    def test_show_branch_change_no_change(self):
1690
        tree = self.setup_ab_tree()
1691
        s = StringIO()
3848.1.12 by Aaron Bentley
Fix test parameter order
1692
        log.show_branch_change(tree.branch, s, 3, '3b')
3848.1.8 by Aaron Bentley
Implement basic show_branch_change
1693
        self.assertEqual(s.getvalue(),
1694
            'Nothing seems to have changed\n')
1695
3848.1.9 by Aaron Bentley
new/old sections are omitted as appropriate.
1696
    def test_show_branch_change_no_old(self):
1697
        tree = self.setup_ab_tree()
1698
        s = StringIO()
3848.1.12 by Aaron Bentley
Fix test parameter order
1699
        log.show_branch_change(tree.branch, s, 2, '2b')
3848.1.9 by Aaron Bentley
new/old sections are omitted as appropriate.
1700
        self.assertContainsRe(s.getvalue(), 'Added Revisions:')
1701
        self.assertNotContainsRe(s.getvalue(), 'Removed Revisions:')
1702
1703
    def test_show_branch_change_no_new(self):
1704
        tree = self.setup_ab_tree()
1705
        tree.branch.set_last_revision_info(2, '2b')
1706
        s = StringIO()
3848.1.12 by Aaron Bentley
Fix test parameter order
1707
        log.show_branch_change(tree.branch, s, 3, '3b')
3848.1.9 by Aaron Bentley
new/old sections are omitted as appropriate.
1708
        self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1709
        self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')