~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_log.py

  • Committer: Aaron Bentley
  • Date: 2005-12-15 06:48:46 UTC
  • mto: This revision was merged to the branch mainline in revision 1533.
  • Revision ID: aaron.bentley@utoronto.ca-20051215064846-aa6cb6c42313c8e3
Updated NEWS

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2013, 2016 Canonical Ltd
2
 
#
 
1
# Copyright (C) 2005 by Canonical Ltd
 
2
 
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
#
 
7
 
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
#
 
12
 
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
17
17
import os
18
18
from cStringIO import StringIO
19
19
 
20
 
from bzrlib import (
21
 
    branchbuilder,
22
 
    errors,
23
 
    log,
24
 
    registry,
25
 
    revision,
26
 
    revisionspec,
27
 
    tests,
28
 
    gpg,
29
 
    trace,
30
 
    )
31
 
 
32
 
 
33
 
class TestLogMixin(object):
34
 
 
35
 
    def wt_commit(self, wt, message, **kwargs):
36
 
        """Use some mostly fixed values for commits to simplify tests.
37
 
 
38
 
        Tests can use this function to get some commit attributes. The time
39
 
        stamp is incremented at each commit.
40
 
        """
41
 
        if getattr(self, 'timestamp', None) is None:
42
 
            self.timestamp = 1132617600 # Mon 2005-11-22 00:00:00 +0000
43
 
        else:
44
 
            self.timestamp += 1 # 1 second between each commit
45
 
        kwargs.setdefault('timestamp', self.timestamp)
46
 
        kwargs.setdefault('timezone', 0) # UTC
47
 
        kwargs.setdefault('committer', 'Joe Foo <joe@foo.com>')
48
 
 
49
 
        return wt.commit(message, **kwargs)
50
 
 
51
 
 
52
 
class TestCaseForLogFormatter(tests.TestCaseWithTransport, TestLogMixin):
53
 
 
54
 
    def setUp(self):
55
 
        super(TestCaseForLogFormatter, self).setUp()
56
 
        # keep a reference to the "current" custom prop. handler registry
57
 
        self.properties_handler_registry = log.properties_handler_registry
58
 
        # Use a clean registry for log
59
 
        log.properties_handler_registry = registry.Registry()
60
 
 
61
 
        def restore():
62
 
            log.properties_handler_registry = self.properties_handler_registry
63
 
        self.addCleanup(restore)
64
 
 
65
 
    def assertFormatterResult(self, result, branch, formatter_class,
66
 
                              formatter_kwargs=None, show_log_kwargs=None):
67
 
        logfile = self.make_utf8_encoded_stringio()
68
 
        if formatter_kwargs is None:
69
 
            formatter_kwargs = {}
70
 
        formatter = formatter_class(to_file=logfile, **formatter_kwargs)
71
 
        if show_log_kwargs is None:
72
 
            show_log_kwargs = {}
73
 
        log.show_log(branch, formatter, **show_log_kwargs)
74
 
        self.assertEqualDiff(result, logfile.getvalue())
75
 
 
76
 
    def make_standard_commit(self, branch_nick, **kwargs):
77
 
        wt = self.make_branch_and_tree('.')
78
 
        wt.lock_write()
79
 
        self.addCleanup(wt.unlock)
80
 
        self.build_tree(['a'])
81
 
        wt.add(['a'])
82
 
        wt.branch.nick = branch_nick
83
 
        kwargs.setdefault('committer', 'Lorem Ipsum <test@example.com>')
84
 
        kwargs.setdefault('authors', ['John Doe <jdoe@example.com>'])
85
 
        self.wt_commit(wt, 'add a', **kwargs)
86
 
        return wt
87
 
 
88
 
    def make_commits_with_trailing_newlines(self, wt):
89
 
        """Helper method for LogFormatter tests"""
90
 
        b = wt.branch
91
 
        b.nick = 'test'
92
 
        self.build_tree_contents([('a', 'hello moto\n')])
93
 
        self.wt_commit(wt, 'simple log message', rev_id='a1')
94
 
        self.build_tree_contents([('b', 'goodbye\n')])
95
 
        wt.add('b')
96
 
        self.wt_commit(wt, 'multiline\nlog\nmessage\n', rev_id='a2')
97
 
 
98
 
        self.build_tree_contents([('c', 'just another manic monday\n')])
99
 
        wt.add('c')
100
 
        self.wt_commit(wt, 'single line with trailing newline\n', rev_id='a3')
101
 
        return b
102
 
 
103
 
    def _prepare_tree_with_merges(self, with_tags=False):
104
 
        wt = self.make_branch_and_memory_tree('.')
105
 
        wt.lock_write()
106
 
        self.addCleanup(wt.unlock)
107
 
        wt.add('')
108
 
        self.wt_commit(wt, 'rev-1', rev_id='rev-1')
109
 
        self.wt_commit(wt, 'rev-merged', rev_id='rev-2a')
110
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
111
 
        wt.branch.set_last_revision_info(1, 'rev-1')
112
 
        self.wt_commit(wt, 'rev-2', rev_id='rev-2b')
113
 
        if with_tags:
114
 
            branch = wt.branch
115
 
            branch.tags.set_tag('v0.2', 'rev-2b')
116
 
            self.wt_commit(wt, 'rev-3', rev_id='rev-3')
117
 
            branch.tags.set_tag('v1.0rc1', 'rev-3')
118
 
            branch.tags.set_tag('v1.0', 'rev-3')
119
 
        return wt
120
 
 
121
 
 
122
 
class LogCatcher(log.LogFormatter):
123
 
    """Pull log messages into a list rather than displaying them.
124
 
 
125
 
    To simplify testing we save logged revisions here rather than actually
126
 
    formatting anything, so that we can precisely check the result without
127
 
    being dependent on the formatting.
 
20
from bzrlib.tests import BzrTestBase, TestCaseInTempDir
 
21
from bzrlib.log import LogFormatter, show_log, LongLogFormatter, ShortLogFormatter
 
22
from bzrlib.branch import Branch
 
23
from bzrlib.errors import InvalidRevisionNumber
 
24
 
 
25
class _LogEntry(object):
 
26
    # should probably move into bzrlib.log?
 
27
    pass
 
28
 
 
29
 
 
30
class LogCatcher(LogFormatter):
 
31
    """Pull log messages into list rather than displaying them.
 
32
 
 
33
    For ease of testing we save log messages here rather than actually
 
34
    formatting them, so that we can precisely check the result without
 
35
    being too dependent on the exact formatting.
 
36
 
 
37
    We should also test the LogFormatter.
128
38
    """
129
 
 
130
 
    supports_merge_revisions = True
131
 
    supports_delta = True
132
 
    supports_diff = True
133
 
    preferred_levels = 0
134
 
 
135
 
    def __init__(self, *args, **kwargs):
136
 
        kwargs.update(dict(to_file=None))
137
 
        super(LogCatcher, self).__init__(*args, **kwargs)
138
 
        self.revisions = []
139
 
 
140
 
    def log_revision(self, revision):
141
 
        self.revisions.append(revision)
142
 
 
143
 
 
144
 
class TestShowLog(tests.TestCaseWithTransport):
 
39
    def __init__(self):
 
40
        super(LogCatcher, self).__init__(to_file=None)
 
41
        self.logs = []
 
42
        
 
43
        
 
44
    def show(self, revno, rev, delta):
 
45
        le = _LogEntry()
 
46
        le.revno = revno
 
47
        le.rev = rev
 
48
        le.delta = delta
 
49
        self.logs.append(le)
 
50
 
 
51
 
 
52
class SimpleLogTest(TestCaseInTempDir):
145
53
 
146
54
    def checkDelta(self, delta, **kw):
147
 
        """Check the filenames touched by a delta are as expected.
148
 
 
149
 
        Caller only have to pass in the list of files for each part, all
150
 
        unspecified parts are considered empty (and checked as such).
151
 
        """
 
55
        """Check the filenames touched by a delta are as expected."""
152
56
        for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
153
 
            # By default we expect an empty list
154
57
            expected = kw.get(n, [])
 
58
 
 
59
            # tests are written with unix paths; fix them up for windows
 
60
            if os.sep != '/':
 
61
                expected = [x.replace('/', os.sep) for x in expected]
 
62
 
155
63
            # strip out only the path components
156
64
            got = [x[0] for x in getattr(delta, n)]
157
 
            self.assertEqual(expected, got)
158
 
 
159
 
    def assertInvalidRevisonNumber(self, br, start, end):
160
 
        lf = LogCatcher()
161
 
        self.assertRaises(errors.InvalidRevisionNumber,
162
 
                          log.show_log, br, lf,
163
 
                          start_revision=start, end_revision=end)
164
 
 
165
 
    def test_cur_revno(self):
166
 
        wt = self.make_branch_and_tree('.')
167
 
        b = wt.branch
168
 
 
169
 
        lf = LogCatcher()
170
 
        wt.commit('empty commit')
171
 
        log.show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
172
 
 
173
 
        # Since there is a single revision in the branch all the combinations
174
 
        # below should fail.
175
 
        self.assertInvalidRevisonNumber(b, 2, 1)
176
 
        self.assertInvalidRevisonNumber(b, 1, 2)
177
 
        self.assertInvalidRevisonNumber(b, 0, 2)
178
 
        self.assertInvalidRevisonNumber(b, 1, 0)
179
 
        self.assertInvalidRevisonNumber(b, -1, 1)
180
 
        self.assertInvalidRevisonNumber(b, 1, -1)
181
 
 
182
 
    def test_empty_branch(self):
183
 
        wt = self.make_branch_and_tree('.')
184
 
 
185
 
        lf = LogCatcher()
186
 
        log.show_log(wt.branch, lf)
 
65
            self.assertEquals(expected, got)
 
66
 
 
67
    def test_cur_revno(self):
 
68
        b = Branch(u'.', init=True)
 
69
 
 
70
        lf = LogCatcher()
 
71
        b.working_tree().commit('empty commit')
 
72
        show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
 
73
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
74
                          start_revision=2, end_revision=1) 
 
75
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
76
                          start_revision=1, end_revision=2) 
 
77
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
78
                          start_revision=0, end_revision=2) 
 
79
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
80
                          start_revision=1, end_revision=0) 
 
81
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
82
                          start_revision=-1, end_revision=1) 
 
83
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
84
                          start_revision=1, end_revision=-1) 
 
85
 
 
86
    def test_cur_revno(self):
 
87
        b = Branch.initialize(u'.')
 
88
 
 
89
        lf = LogCatcher()
 
90
        b.working_tree().commit('empty commit')
 
91
        show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
 
92
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
93
                          start_revision=2, end_revision=1) 
 
94
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
95
                          start_revision=1, end_revision=2) 
 
96
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
97
                          start_revision=0, end_revision=2) 
 
98
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
99
                          start_revision=1, end_revision=0) 
 
100
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
101
                          start_revision=-1, end_revision=1) 
 
102
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
 
103
                          start_revision=1, end_revision=-1) 
 
104
 
 
105
    def test_simple_log(self):
 
106
        eq = self.assertEquals
 
107
        
 
108
        b = Branch.initialize(u'.')
 
109
 
 
110
        lf = LogCatcher()
 
111
        show_log(b, lf)
187
112
        # no entries yet
188
 
        self.assertEqual([], lf.revisions)
189
 
 
190
 
    def test_empty_commit(self):
191
 
        wt = self.make_branch_and_tree('.')
192
 
 
193
 
        wt.commit('empty commit')
 
113
        eq(lf.logs, [])
 
114
 
 
115
        b.working_tree().commit('empty commit')
194
116
        lf = LogCatcher()
195
 
        log.show_log(wt.branch, lf, verbose=True)
196
 
        revs = lf.revisions
197
 
        self.assertEqual(1, len(revs))
198
 
        self.assertEqual('1', revs[0].revno)
199
 
        self.assertEqual('empty commit', revs[0].rev.message)
200
 
        self.checkDelta(revs[0].delta)
 
117
        show_log(b, lf, verbose=True)
 
118
        eq(len(lf.logs), 1)
 
119
        eq(lf.logs[0].revno, 1)
 
120
        eq(lf.logs[0].rev.message, 'empty commit')
 
121
        d = lf.logs[0].delta
 
122
        self.log('log delta: %r' % d)
 
123
        self.checkDelta(d)
201
124
 
202
 
    def test_simple_commit(self):
203
 
        wt = self.make_branch_and_tree('.')
204
 
        wt.commit('empty commit')
205
125
        self.build_tree(['hello'])
206
 
        wt.add('hello')
207
 
        wt.commit('add one file',
208
 
                  committer=u'\u013d\xf3r\xe9m \xcdp\u0161\xfam '
209
 
                            u'<test@example.com>')
 
126
        b.working_tree().add('hello')
 
127
        b.working_tree().commit('add one file')
 
128
 
 
129
        lf = StringIO()
 
130
        # log using regular thing
 
131
        show_log(b, LongLogFormatter(lf))
 
132
        lf.seek(0)
 
133
        for l in lf.readlines():
 
134
            self.log(l)
 
135
 
 
136
        # get log as data structure
210
137
        lf = LogCatcher()
211
 
        log.show_log(wt.branch, lf, verbose=True)
212
 
        self.assertEqual(2, len(lf.revisions))
 
138
        show_log(b, lf, verbose=True)
 
139
        eq(len(lf.logs), 2)
 
140
        self.log('log entries:')
 
141
        for logentry in lf.logs:
 
142
            self.log('%4d %s' % (logentry.revno, logentry.rev.message))
 
143
        
213
144
        # first one is most recent
214
 
        log_entry = lf.revisions[0]
215
 
        self.assertEqual('2', log_entry.revno)
216
 
        self.assertEqual('add one file', log_entry.rev.message)
217
 
        self.checkDelta(log_entry.delta, added=['hello'])
218
 
 
219
 
    def test_commit_message_with_control_chars(self):
220
 
        wt = self.make_branch_and_tree('.')
221
 
        msg = u"All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)])
222
 
        msg = msg.replace(u'\r', u'\n')
223
 
        wt.commit(msg)
 
145
        logentry = lf.logs[0]
 
146
        eq(logentry.revno, 2)
 
147
        eq(logentry.rev.message, 'add one file')
 
148
        d = logentry.delta
 
149
        self.log('log 2 delta: %r' % d)
 
150
        # self.checkDelta(d, added=['hello'])
 
151
        
 
152
        # commit a log message with control characters
 
153
        msg = "All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)])
 
154
        self.log("original commit message: %r", msg)
 
155
        b.working_tree().commit(msg)
224
156
        lf = LogCatcher()
225
 
        log.show_log(wt.branch, lf, verbose=True)
226
 
        committed_msg = lf.revisions[0].rev.message
227
 
        if wt.branch.repository._serializer.squashes_xml_invalid_characters:
228
 
            self.assertNotEqual(msg, committed_msg)
229
 
            self.assertTrue(len(committed_msg) > len(msg))
230
 
        else:
231
 
            self.assertEqual(msg, committed_msg)
 
157
        show_log(b, lf, verbose=True)
 
158
        committed_msg = lf.logs[0].rev.message
 
159
        self.log("escaped commit message: %r", committed_msg)
 
160
        self.assert_(msg != committed_msg)
 
161
        self.assert_(len(committed_msg) > len(msg))
232
162
 
233
 
    def test_commit_message_without_control_chars(self):
234
 
        wt = self.make_branch_and_tree('.')
 
163
        # Check that log message with only XML-valid characters isn't
235
164
        # escaped.  As ElementTree apparently does some kind of
236
165
        # newline conversion, neither LF (\x0A) nor CR (\x0D) are
237
166
        # included in the test commit message, even though they are
238
167
        # valid XML 1.0 characters.
239
168
        msg = "\x09" + ''.join([unichr(x) for x in range(0x20, 256)])
240
 
        wt.commit(msg)
241
 
        lf = LogCatcher()
242
 
        log.show_log(wt.branch, lf, verbose=True)
243
 
        committed_msg = lf.revisions[0].rev.message
244
 
        self.assertEqual(msg, committed_msg)
245
 
 
246
 
    def test_deltas_in_merge_revisions(self):
247
 
        """Check deltas created for both mainline and merge revisions"""
248
 
        wt = self.make_branch_and_tree('parent')
249
 
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
250
 
        wt.add('file1')
251
 
        wt.add('file2')
252
 
        wt.commit(message='add file1 and file2')
253
 
        self.run_bzr('branch parent child')
254
 
        os.unlink('child/file1')
255
 
        with file('child/file2', 'wb') as f: f.write('hello\n')
256
 
        self.run_bzr(['commit', '-m', 'remove file1 and modify file2',
257
 
            'child'])
258
 
        os.chdir('parent')
259
 
        self.run_bzr('merge ../child')
260
 
        wt.commit('merge child branch')
261
 
        os.chdir('..')
262
 
        b = wt.branch
263
 
        lf = LogCatcher()
264
 
        lf.supports_merge_revisions = True
265
 
        log.show_log(b, lf, verbose=True)
266
 
 
267
 
        revs = lf.revisions
268
 
        self.assertEqual(3, len(revs))
269
 
 
270
 
        logentry = revs[0]
271
 
        self.assertEqual('2', logentry.revno)
272
 
        self.assertEqual('merge child branch', logentry.rev.message)
273
 
        self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
274
 
 
275
 
        logentry = revs[1]
276
 
        self.assertEqual('1.1.1', logentry.revno)
277
 
        self.assertEqual('remove file1 and modify file2', logentry.rev.message)
278
 
        self.checkDelta(logentry.delta, removed=['file1'], modified=['file2'])
279
 
 
280
 
        logentry = revs[2]
281
 
        self.assertEqual('1', logentry.revno)
282
 
        self.assertEqual('add file1 and file2', logentry.rev.message)
283
 
        self.checkDelta(logentry.delta, added=['file1', 'file2'])
284
 
 
285
 
 
286
 
class TestFormatSignatureValidity(tests.TestCaseWithTransport):
287
 
    class UTFLoopbackGPGStrategy(gpg.LoopbackGPGStrategy):
288
 
        def verify(self, content, testament):
289
 
            return (gpg.SIGNATURE_VALID,
290
 
                u'UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>')
291
 
 
292
 
    def has_signature_for_revision_id(self, revision_id):
293
 
        return True
294
 
 
295
 
    def get_signature_text(self, revision_id):
296
 
        return ''
297
 
 
298
 
    def test_format_signature_validity_utf(self):
299
 
        """Check that GPG signatures containing UTF-8 names are formatted
300
 
        correctly."""
301
 
        # Monkey patch to use our UTF-8 generating GPGStrategy
302
 
        self.overrideAttr(gpg, 'GPGStrategy', self.UTFLoopbackGPGStrategy)
303
 
        wt = self.make_branch_and_tree('.')
304
 
        revid = wt.commit('empty commit')
305
 
        repo = wt.branch.repository
306
 
        # Monkey patch out checking if this rev is actually signed, since we
307
 
        # can't sign it without a heavier TestCase and LoopbackGPGStrategy
308
 
        # doesn't care anyways.
309
 
        self.overrideAttr(repo, 'has_signature_for_revision_id',
310
 
                self.has_signature_for_revision_id)
311
 
        self.overrideAttr(repo, 'get_signature_text', self.get_signature_text)
312
 
        out = log.format_signature_validity(revid, repo)
313
 
        self.assertEqual(
314
 
u'valid signature from UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>',
315
 
                out)
316
 
 
317
 
 
318
 
class TestShortLogFormatter(TestCaseForLogFormatter):
 
169
        self.log("original commit message: %r", msg)
 
170
        b.working_tree().commit(msg)
 
171
        lf = LogCatcher()
 
172
        show_log(b, lf, verbose=True)
 
173
        committed_msg = lf.logs[0].rev.message
 
174
        self.log("escaped commit message: %r", committed_msg)
 
175
        self.assert_(msg == committed_msg)
319
176
 
320
177
    def test_trailing_newlines(self):
321
 
        wt = self.make_branch_and_tree('.')
322
 
        b = self.make_commits_with_trailing_newlines(wt)
323
 
        self.assertFormatterResult("""\
324
 
    3 Joe Foo\t2005-11-22
 
178
        b = Branch.initialize(u'.')
 
179
        b.nick='test'
 
180
        wt = b.working_tree()
 
181
        open('a', 'wb').write('hello moto\n')
 
182
        wt.add('a')
 
183
        wt.commit('simple log message', rev_id='a1'
 
184
                , timestamp=1132586655.459960938, timezone=-6*3600
 
185
                , committer='Joe Foo <joe@foo.com>')
 
186
        open('b', 'wb').write('goodbye\n')
 
187
        wt.add('b')
 
188
        wt.commit('multiline\nlog\nmessage\n', rev_id='a2'
 
189
                , timestamp=1132586842.411175966, timezone=-6*3600
 
190
                , committer='Joe Foo <joe@foo.com>')
 
191
 
 
192
        open('c', 'wb').write('just another manic monday\n')
 
193
        wt.add('c')
 
194
        wt.commit('single line with trailing newline\n', rev_id='a3'
 
195
                , timestamp=1132587176.835228920, timezone=-6*3600
 
196
                , committer = 'Joe Foo <joe@foo.com>')
 
197
 
 
198
        sio = StringIO()
 
199
        lf = ShortLogFormatter(to_file=sio)
 
200
        show_log(b, lf)
 
201
        self.assertEquals(sio.getvalue(), """\
 
202
    3 Joe Foo\t2005-11-21
325
203
      single line with trailing newline
326
204
 
327
 
    2 Joe Foo\t2005-11-22
 
205
    2 Joe Foo\t2005-11-21
328
206
      multiline
329
207
      log
330
208
      message
331
209
 
332
 
    1 Joe Foo\t2005-11-22
 
210
    1 Joe Foo\t2005-11-21
333
211
      simple log message
334
212
 
335
 
""",
336
 
            b, log.ShortLogFormatter)
337
 
 
338
 
    def test_short_log_with_merges(self):
339
 
        wt = self._prepare_tree_with_merges()
340
 
        self.assertFormatterResult("""\
341
 
    2 Joe Foo\t2005-11-22 [merge]
342
 
      rev-2
343
 
 
344
 
    1 Joe Foo\t2005-11-22
345
 
      rev-1
346
 
 
347
 
""",
348
 
            wt.branch, log.ShortLogFormatter)
349
 
 
350
 
    def test_short_log_with_merges_and_advice(self):
351
 
        wt = self._prepare_tree_with_merges()
352
 
        self.assertFormatterResult("""\
353
 
    2 Joe Foo\t2005-11-22 [merge]
354
 
      rev-2
355
 
 
356
 
    1 Joe Foo\t2005-11-22
357
 
      rev-1
358
 
 
359
 
Use --include-merged or -n0 to see merged revisions.
360
 
""",
361
 
            wt.branch, log.ShortLogFormatter,
362
 
            formatter_kwargs=dict(show_advice=True))
363
 
 
364
 
    def test_short_log_with_merges_and_range(self):
365
 
        wt = self._prepare_tree_with_merges()
366
 
        self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
367
 
        wt.branch.set_last_revision_info(2, 'rev-2b')
368
 
        wt.set_parent_ids(['rev-2b', 'rev-3a'])
369
 
        self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
370
 
        self.assertFormatterResult("""\
371
 
    3 Joe Foo\t2005-11-22 [merge]
372
 
      rev-3b
373
 
 
374
 
    2 Joe Foo\t2005-11-22 [merge]
375
 
      rev-2
376
 
 
377
 
""",
378
 
            wt.branch, log.ShortLogFormatter,
379
 
            show_log_kwargs=dict(start_revision=2, end_revision=3))
380
 
 
381
 
    def test_short_log_with_tags(self):
382
 
        wt = self._prepare_tree_with_merges(with_tags=True)
383
 
        self.assertFormatterResult("""\
384
 
    3 Joe Foo\t2005-11-22 {v1.0, v1.0rc1}
385
 
      rev-3
386
 
 
387
 
    2 Joe Foo\t2005-11-22 {v0.2} [merge]
388
 
      rev-2
389
 
 
390
 
    1 Joe Foo\t2005-11-22
391
 
      rev-1
392
 
 
393
 
""",
394
 
            wt.branch, log.ShortLogFormatter)
395
 
 
396
 
    def test_short_log_single_merge_revision(self):
397
 
        wt = self._prepare_tree_with_merges()
398
 
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
399
 
        rev = revspec.in_history(wt.branch)
400
 
        self.assertFormatterResult("""\
401
 
      1.1.1 Joe Foo\t2005-11-22
402
 
            rev-merged
403
 
 
404
 
""",
405
 
            wt.branch, log.ShortLogFormatter,
406
 
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
407
 
 
408
 
    def test_show_ids(self):
409
 
        wt = self.make_branch_and_tree('parent')
410
 
        self.build_tree(['parent/f1', 'parent/f2'])
411
 
        wt.add(['f1','f2'])
412
 
        self.wt_commit(wt, 'first post', rev_id='a')
413
 
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
414
 
        self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
415
 
        wt.merge_from_branch(child_wt.branch)
416
 
        self.wt_commit(wt, 'merge branch 1', rev_id='c')
417
 
        self.assertFormatterResult("""\
418
 
    2 Joe Foo\t2005-11-22 [merge]
419
 
      revision-id:c
420
 
      merge branch 1
421
 
 
422
 
          1.1.1 Joe Foo\t2005-11-22
423
 
                revision-id:b
424
 
                branch 1 changes
425
 
 
426
 
    1 Joe Foo\t2005-11-22
427
 
      revision-id:a
428
 
      first post
429
 
 
430
 
""",
431
 
            wt.branch, log.ShortLogFormatter,
432
 
            formatter_kwargs=dict(levels=0,show_ids=True))
433
 
 
434
 
 
435
 
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
436
 
 
437
 
    def test_short_merge_revs_log_with_merges(self):
438
 
        wt = self._prepare_tree_with_merges()
439
 
        # Note that the 1.1.1 indenting is in fact correct given that
440
 
        # the revision numbers are right justified within 5 characters
441
 
        # for mainline revnos and 9 characters for dotted revnos.
442
 
        self.assertFormatterResult("""\
443
 
    2 Joe Foo\t2005-11-22 [merge]
444
 
      rev-2
445
 
 
446
 
          1.1.1 Joe Foo\t2005-11-22
447
 
                rev-merged
448
 
 
449
 
    1 Joe Foo\t2005-11-22
450
 
      rev-1
451
 
 
452
 
""",
453
 
            wt.branch, log.ShortLogFormatter,
454
 
            formatter_kwargs=dict(levels=0))
455
 
 
456
 
    def test_short_merge_revs_log_single_merge_revision(self):
457
 
        wt = self._prepare_tree_with_merges()
458
 
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
459
 
        rev = revspec.in_history(wt.branch)
460
 
        self.assertFormatterResult("""\
461
 
      1.1.1 Joe Foo\t2005-11-22
462
 
            rev-merged
463
 
 
464
 
""",
465
 
            wt.branch, log.ShortLogFormatter,
466
 
            formatter_kwargs=dict(levels=0),
467
 
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
468
 
 
469
 
 
470
 
class TestLongLogFormatter(TestCaseForLogFormatter):
471
 
 
 
213
""")
 
214
 
 
215
        sio = StringIO()
 
216
        lf = LongLogFormatter(to_file=sio)
 
217
        show_log(b, lf)
 
218
        self.assertEquals(sio.getvalue(), """\
 
219
------------------------------------------------------------
 
220
revno: 3
 
221
committer: Joe Foo <joe@foo.com>
 
222
branch nick: test
 
223
timestamp: Mon 2005-11-21 09:32:56 -0600
 
224
message:
 
225
  single line with trailing newline
 
226
------------------------------------------------------------
 
227
revno: 2
 
228
committer: Joe Foo <joe@foo.com>
 
229
branch nick: test
 
230
timestamp: Mon 2005-11-21 09:27:22 -0600
 
231
message:
 
232
  multiline
 
233
  log
 
234
  message
 
235
------------------------------------------------------------
 
236
revno: 1
 
237
committer: Joe Foo <joe@foo.com>
 
238
branch nick: test
 
239
timestamp: Mon 2005-11-21 09:24:15 -0600
 
240
message:
 
241
  simple log message
 
242
""")
 
243
        
472
244
    def test_verbose_log(self):
473
245
        """Verbose log includes changed files
474
 
 
 
246
        
475
247
        bug #4676
476
248
        """
477
 
        wt = self.make_standard_commit('test_verbose_log', authors=[])
478
 
        self.assertFormatterResult('''\
 
249
        b = Branch.initialize(u'.')
 
250
        self.build_tree(['a'])
 
251
        wt = b.working_tree()
 
252
        wt.add('a')
 
253
        # XXX: why does a longer nick show up?
 
254
        b.nick = 'test_verbose_log'
 
255
        wt.commit(message='add a', 
 
256
                  timestamp=1132711707, 
 
257
                  timezone=36000,
 
258
                  committer='Lorem Ipsum <test@example.com>')
 
259
        logfile = file('out.tmp', 'w+')
 
260
        formatter = LongLogFormatter(to_file=logfile)
 
261
        show_log(b, formatter, verbose=True)
 
262
        logfile.flush()
 
263
        logfile.seek(0)
 
264
        log_contents = logfile.read()
 
265
        self.assertEqualDiff(log_contents, '''\
479
266
------------------------------------------------------------
480
267
revno: 1
481
268
committer: Lorem Ipsum <test@example.com>
482
269
branch nick: test_verbose_log
483
 
timestamp: Tue 2005-11-22 00:00:00 +0000
484
 
message:
485
 
  add a
486
 
added:
487
 
  a
488
 
''',
489
 
            wt.branch, log.LongLogFormatter,
490
 
            show_log_kwargs=dict(verbose=True))
491
 
 
492
 
    def test_merges_are_indented_by_level(self):
493
 
        wt = self.make_branch_and_tree('parent')
494
 
        self.wt_commit(wt, 'first post')
495
 
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
496
 
        self.wt_commit(child_wt, 'branch 1')
497
 
        smallerchild_wt = wt.bzrdir.sprout('smallerchild').open_workingtree()
498
 
        self.wt_commit(smallerchild_wt, 'branch 2')
499
 
        child_wt.merge_from_branch(smallerchild_wt.branch)
500
 
        self.wt_commit(child_wt, 'merge branch 2')
501
 
        wt.merge_from_branch(child_wt.branch)
502
 
        self.wt_commit(wt, 'merge branch 1')
503
 
        self.assertFormatterResult("""\
504
 
------------------------------------------------------------
505
 
revno: 2 [merge]
506
 
committer: Joe Foo <joe@foo.com>
507
 
branch nick: parent
508
 
timestamp: Tue 2005-11-22 00:00:04 +0000
509
 
message:
510
 
  merge branch 1
511
 
    ------------------------------------------------------------
512
 
    revno: 1.1.2 [merge]
513
 
    committer: Joe Foo <joe@foo.com>
514
 
    branch nick: child
515
 
    timestamp: Tue 2005-11-22 00:00:03 +0000
516
 
    message:
517
 
      merge branch 2
518
 
        ------------------------------------------------------------
519
 
        revno: 1.2.1
520
 
        committer: Joe Foo <joe@foo.com>
521
 
        branch nick: smallerchild
522
 
        timestamp: Tue 2005-11-22 00:00:02 +0000
523
 
        message:
524
 
          branch 2
525
 
    ------------------------------------------------------------
526
 
    revno: 1.1.1
527
 
    committer: Joe Foo <joe@foo.com>
528
 
    branch nick: child
529
 
    timestamp: Tue 2005-11-22 00:00:01 +0000
530
 
    message:
531
 
      branch 1
532
 
------------------------------------------------------------
533
 
revno: 1
534
 
committer: Joe Foo <joe@foo.com>
535
 
branch nick: parent
536
 
timestamp: Tue 2005-11-22 00:00:00 +0000
537
 
message:
538
 
  first post
539
 
""",
540
 
            wt.branch, log.LongLogFormatter,
541
 
            formatter_kwargs=dict(levels=0),
542
 
            show_log_kwargs=dict(verbose=True))
543
 
 
544
 
    def test_verbose_merge_revisions_contain_deltas(self):
545
 
        wt = self.make_branch_and_tree('parent')
546
 
        self.build_tree(['parent/f1', 'parent/f2'])
547
 
        wt.add(['f1','f2'])
548
 
        self.wt_commit(wt, 'first post')
549
 
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
550
 
        os.unlink('child/f1')
551
 
        self.build_tree_contents([('child/f2', 'hello\n')])
552
 
        self.wt_commit(child_wt, 'removed f1 and modified f2')
553
 
        wt.merge_from_branch(child_wt.branch)
554
 
        self.wt_commit(wt, 'merge branch 1')
555
 
        self.assertFormatterResult("""\
556
 
------------------------------------------------------------
557
 
revno: 2 [merge]
558
 
committer: Joe Foo <joe@foo.com>
559
 
branch nick: parent
560
 
timestamp: Tue 2005-11-22 00:00:02 +0000
561
 
message:
562
 
  merge branch 1
563
 
removed:
564
 
  f1
565
 
modified:
566
 
  f2
567
 
    ------------------------------------------------------------
568
 
    revno: 1.1.1
569
 
    committer: Joe Foo <joe@foo.com>
570
 
    branch nick: child
571
 
    timestamp: Tue 2005-11-22 00:00:01 +0000
572
 
    message:
573
 
      removed f1 and modified f2
574
 
    removed:
575
 
      f1
576
 
    modified:
577
 
      f2
578
 
------------------------------------------------------------
579
 
revno: 1
580
 
committer: Joe Foo <joe@foo.com>
581
 
branch nick: parent
582
 
timestamp: Tue 2005-11-22 00:00:00 +0000
583
 
message:
584
 
  first post
585
 
added:
586
 
  f1
587
 
  f2
588
 
""",
589
 
            wt.branch, log.LongLogFormatter,
590
 
            formatter_kwargs=dict(levels=0),
591
 
            show_log_kwargs=dict(verbose=True))
592
 
 
593
 
    def test_trailing_newlines(self):
594
 
        wt = self.make_branch_and_tree('.')
595
 
        b = self.make_commits_with_trailing_newlines(wt)
596
 
        self.assertFormatterResult("""\
597
 
------------------------------------------------------------
598
 
revno: 3
599
 
committer: Joe Foo <joe@foo.com>
600
 
branch nick: test
601
 
timestamp: Tue 2005-11-22 00:00:02 +0000
602
 
message:
603
 
  single line with trailing newline
604
 
------------------------------------------------------------
605
 
revno: 2
606
 
committer: Joe Foo <joe@foo.com>
607
 
branch nick: test
608
 
timestamp: Tue 2005-11-22 00:00:01 +0000
609
 
message:
610
 
  multiline
611
 
  log
612
 
  message
613
 
------------------------------------------------------------
614
 
revno: 1
615
 
committer: Joe Foo <joe@foo.com>
616
 
branch nick: test
617
 
timestamp: Tue 2005-11-22 00:00:00 +0000
618
 
message:
619
 
  simple log message
620
 
""",
621
 
        b, log.LongLogFormatter)
622
 
 
623
 
    def test_author_in_log(self):
624
 
        """Log includes the author name if it's set in
625
 
        the revision properties
626
 
        """
627
 
        wt = self.make_standard_commit('test_author_log',
628
 
            authors=['John Doe <jdoe@example.com>',
629
 
                     'Jane Rey <jrey@example.com>'])
630
 
        self.assertFormatterResult("""\
631
 
------------------------------------------------------------
632
 
revno: 1
633
 
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
634
 
committer: Lorem Ipsum <test@example.com>
635
 
branch nick: test_author_log
636
 
timestamp: Tue 2005-11-22 00:00:00 +0000
637
 
message:
638
 
  add a
639
 
""",
640
 
        wt.branch, log.LongLogFormatter)
641
 
 
642
 
    def test_properties_in_log(self):
643
 
        """Log includes the custom properties returned by the registered
644
 
        handlers.
645
 
        """
646
 
        wt = self.make_standard_commit('test_properties_in_log')
647
 
        def trivial_custom_prop_handler(revision):
648
 
            return {'test_prop':'test_value'}
649
 
 
650
 
        # Cleaned up in setUp()
651
 
        log.properties_handler_registry.register(
652
 
            'trivial_custom_prop_handler',
653
 
            trivial_custom_prop_handler)
654
 
        self.assertFormatterResult("""\
655
 
------------------------------------------------------------
656
 
revno: 1
657
 
test_prop: test_value
658
 
author: John Doe <jdoe@example.com>
659
 
committer: Lorem Ipsum <test@example.com>
660
 
branch nick: test_properties_in_log
661
 
timestamp: Tue 2005-11-22 00:00:00 +0000
662
 
message:
663
 
  add a
664
 
""",
665
 
            wt.branch, log.LongLogFormatter)
666
 
 
667
 
    def test_properties_in_short_log(self):
668
 
        """Log includes the custom properties returned by the registered
669
 
        handlers.
670
 
        """
671
 
        wt = self.make_standard_commit('test_properties_in_short_log')
672
 
        def trivial_custom_prop_handler(revision):
673
 
            return {'test_prop':'test_value'}
674
 
 
675
 
        log.properties_handler_registry.register(
676
 
            'trivial_custom_prop_handler',
677
 
            trivial_custom_prop_handler)
678
 
        self.assertFormatterResult("""\
679
 
    1 John Doe\t2005-11-22
680
 
      test_prop: test_value
681
 
      add a
682
 
 
683
 
""",
684
 
            wt.branch, log.ShortLogFormatter)
685
 
 
686
 
    def test_error_in_properties_handler(self):
687
 
        """Log includes the custom properties returned by the registered
688
 
        handlers.
689
 
        """
690
 
        wt = self.make_standard_commit('error_in_properties_handler',
691
 
            revprops={'first_prop':'first_value'})
692
 
        sio = self.make_utf8_encoded_stringio()
693
 
        formatter = log.LongLogFormatter(to_file=sio)
694
 
        def trivial_custom_prop_handler(revision):
695
 
            raise StandardError("a test error")
696
 
 
697
 
        log.properties_handler_registry.register(
698
 
            'trivial_custom_prop_handler',
699
 
            trivial_custom_prop_handler)
700
 
        self.assertRaises(StandardError, log.show_log, wt.branch, formatter,)
701
 
 
702
 
    def test_properties_handler_bad_argument(self):
703
 
        wt = self.make_standard_commit('bad_argument',
704
 
              revprops={'a_prop':'test_value'})
705
 
        sio = self.make_utf8_encoded_stringio()
706
 
        formatter = log.LongLogFormatter(to_file=sio)
707
 
        def bad_argument_prop_handler(revision):
708
 
            return {'custom_prop_name':revision.properties['a_prop']}
709
 
 
710
 
        log.properties_handler_registry.register(
711
 
            'bad_argument_prop_handler',
712
 
            bad_argument_prop_handler)
713
 
 
714
 
        self.assertRaises(AttributeError, formatter.show_properties,
715
 
                          'a revision', '')
716
 
 
717
 
        revision = wt.branch.repository.get_revision(wt.branch.last_revision())
718
 
        formatter.show_properties(revision, '')
719
 
        self.assertEqualDiff('''custom_prop_name: test_value\n''',
720
 
                             sio.getvalue())
721
 
 
722
 
    def test_show_ids(self):
723
 
        wt = self.make_branch_and_tree('parent')
724
 
        self.build_tree(['parent/f1', 'parent/f2'])
725
 
        wt.add(['f1','f2'])
726
 
        self.wt_commit(wt, 'first post', rev_id='a')
727
 
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
728
 
        self.wt_commit(child_wt, 'branch 1 changes', rev_id='b')
729
 
        wt.merge_from_branch(child_wt.branch)
730
 
        self.wt_commit(wt, 'merge branch 1', rev_id='c')
731
 
        self.assertFormatterResult("""\
732
 
------------------------------------------------------------
733
 
revno: 2 [merge]
734
 
revision-id: c
735
 
parent: a
736
 
parent: b
737
 
committer: Joe Foo <joe@foo.com>
738
 
branch nick: parent
739
 
timestamp: Tue 2005-11-22 00:00:02 +0000
740
 
message:
741
 
  merge branch 1
742
 
    ------------------------------------------------------------
743
 
    revno: 1.1.1
744
 
    revision-id: b
745
 
    parent: a
746
 
    committer: Joe Foo <joe@foo.com>
747
 
    branch nick: child
748
 
    timestamp: Tue 2005-11-22 00:00:01 +0000
749
 
    message:
750
 
      branch 1 changes
751
 
------------------------------------------------------------
752
 
revno: 1
753
 
revision-id: a
754
 
committer: Joe Foo <joe@foo.com>
755
 
branch nick: parent
756
 
timestamp: Tue 2005-11-22 00:00:00 +0000
757
 
message:
758
 
  first post
759
 
""",
760
 
            wt.branch, log.LongLogFormatter,
761
 
            formatter_kwargs=dict(levels=0,show_ids=True))
762
 
 
763
 
 
764
 
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
765
 
 
766
 
    def test_long_verbose_log(self):
767
 
        """Verbose log includes changed files
768
 
 
769
 
        bug #4676
770
 
        """
771
 
        wt = self.make_standard_commit('test_long_verbose_log', authors=[])
772
 
        self.assertFormatterResult("""\
773
 
------------------------------------------------------------
774
 
revno: 1
775
 
committer: Lorem Ipsum <test@example.com>
776
 
branch nick: test_long_verbose_log
777
 
timestamp: Tue 2005-11-22 00:00:00 +0000
778
 
message:
779
 
  add a
780
 
added:
781
 
  a
782
 
""",
783
 
            wt.branch, log.LongLogFormatter,
784
 
            formatter_kwargs=dict(levels=1),
785
 
            show_log_kwargs=dict(verbose=True))
786
 
 
787
 
    def test_long_verbose_contain_deltas(self):
788
 
        wt = self.make_branch_and_tree('parent')
789
 
        self.build_tree(['parent/f1', 'parent/f2'])
790
 
        wt.add(['f1','f2'])
791
 
        self.wt_commit(wt, 'first post')
792
 
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
793
 
        os.unlink('child/f1')
794
 
        self.build_tree_contents([('child/f2', 'hello\n')])
795
 
        self.wt_commit(child_wt, 'removed f1 and modified f2')
796
 
        wt.merge_from_branch(child_wt.branch)
797
 
        self.wt_commit(wt, 'merge branch 1')
798
 
        self.assertFormatterResult("""\
799
 
------------------------------------------------------------
800
 
revno: 2 [merge]
801
 
committer: Joe Foo <joe@foo.com>
802
 
branch nick: parent
803
 
timestamp: Tue 2005-11-22 00:00:02 +0000
804
 
message:
805
 
  merge branch 1
806
 
removed:
807
 
  f1
808
 
modified:
809
 
  f2
810
 
------------------------------------------------------------
811
 
revno: 1
812
 
committer: Joe Foo <joe@foo.com>
813
 
branch nick: parent
814
 
timestamp: Tue 2005-11-22 00:00:00 +0000
815
 
message:
816
 
  first post
817
 
added:
818
 
  f1
819
 
  f2
820
 
""",
821
 
            wt.branch, log.LongLogFormatter,
822
 
            formatter_kwargs=dict(levels=1),
823
 
            show_log_kwargs=dict(verbose=True))
824
 
 
825
 
    def test_long_trailing_newlines(self):
826
 
        wt = self.make_branch_and_tree('.')
827
 
        b = self.make_commits_with_trailing_newlines(wt)
828
 
        self.assertFormatterResult("""\
829
 
------------------------------------------------------------
830
 
revno: 3
831
 
committer: Joe Foo <joe@foo.com>
832
 
branch nick: test
833
 
timestamp: Tue 2005-11-22 00:00:02 +0000
834
 
message:
835
 
  single line with trailing newline
836
 
------------------------------------------------------------
837
 
revno: 2
838
 
committer: Joe Foo <joe@foo.com>
839
 
branch nick: test
840
 
timestamp: Tue 2005-11-22 00:00:01 +0000
841
 
message:
842
 
  multiline
843
 
  log
844
 
  message
845
 
------------------------------------------------------------
846
 
revno: 1
847
 
committer: Joe Foo <joe@foo.com>
848
 
branch nick: test
849
 
timestamp: Tue 2005-11-22 00:00:00 +0000
850
 
message:
851
 
  simple log message
852
 
""",
853
 
        b, log.LongLogFormatter,
854
 
        formatter_kwargs=dict(levels=1))
855
 
 
856
 
    def test_long_author_in_log(self):
857
 
        """Log includes the author name if it's set in
858
 
        the revision properties
859
 
        """
860
 
        wt = self.make_standard_commit('test_author_log')
861
 
        self.assertFormatterResult("""\
862
 
------------------------------------------------------------
863
 
revno: 1
864
 
author: John Doe <jdoe@example.com>
865
 
committer: Lorem Ipsum <test@example.com>
866
 
branch nick: test_author_log
867
 
timestamp: Tue 2005-11-22 00:00:00 +0000
868
 
message:
869
 
  add a
870
 
""",
871
 
            wt.branch, log.LongLogFormatter,
872
 
            formatter_kwargs=dict(levels=1))
873
 
 
874
 
    def test_long_properties_in_log(self):
875
 
        """Log includes the custom properties returned by the registered
876
 
        handlers.
877
 
        """
878
 
        wt = self.make_standard_commit('test_properties_in_log')
879
 
        def trivial_custom_prop_handler(revision):
880
 
            return {'test_prop':'test_value'}
881
 
 
882
 
        log.properties_handler_registry.register(
883
 
            'trivial_custom_prop_handler',
884
 
            trivial_custom_prop_handler)
885
 
        self.assertFormatterResult("""\
886
 
------------------------------------------------------------
887
 
revno: 1
888
 
test_prop: test_value
889
 
author: John Doe <jdoe@example.com>
890
 
committer: Lorem Ipsum <test@example.com>
891
 
branch nick: test_properties_in_log
892
 
timestamp: Tue 2005-11-22 00:00:00 +0000
893
 
message:
894
 
  add a
895
 
""",
896
 
            wt.branch, log.LongLogFormatter,
897
 
            formatter_kwargs=dict(levels=1))
898
 
 
899
 
 
900
 
class TestLineLogFormatter(TestCaseForLogFormatter):
901
 
 
902
 
    def test_line_log(self):
903
 
        """Line log should show revno
904
 
 
905
 
        bug #5162
906
 
        """
907
 
        wt = self.make_standard_commit('test-line-log',
908
 
                committer='Line-Log-Formatter Tester <test@line.log>',
909
 
                authors=[])
910
 
        self.assertFormatterResult("""\
911
 
1: Line-Log-Formatte... 2005-11-22 add a
912
 
""",
913
 
            wt.branch, log.LineLogFormatter)
914
 
 
915
 
    def test_trailing_newlines(self):
916
 
        wt = self.make_branch_and_tree('.')
917
 
        b = self.make_commits_with_trailing_newlines(wt)
918
 
        self.assertFormatterResult("""\
919
 
3: Joe Foo 2005-11-22 single line with trailing newline
920
 
2: Joe Foo 2005-11-22 multiline
921
 
1: Joe Foo 2005-11-22 simple log message
922
 
""",
923
 
            b, log.LineLogFormatter)
924
 
 
925
 
    def test_line_log_single_merge_revision(self):
926
 
        wt = self._prepare_tree_with_merges()
927
 
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
928
 
        rev = revspec.in_history(wt.branch)
929
 
        self.assertFormatterResult("""\
930
 
1.1.1: Joe Foo 2005-11-22 rev-merged
931
 
""",
932
 
            wt.branch, log.LineLogFormatter,
933
 
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
934
 
 
935
 
    def test_line_log_with_tags(self):
936
 
        wt = self._prepare_tree_with_merges(with_tags=True)
937
 
        self.assertFormatterResult("""\
938
 
3: Joe Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
939
 
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
940
 
1: Joe Foo 2005-11-22 rev-1
941
 
""",
942
 
            wt.branch, log.LineLogFormatter)
943
 
 
944
 
 
945
 
class TestLineLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
946
 
 
947
 
    def test_line_merge_revs_log(self):
948
 
        """Line log should show revno
949
 
 
950
 
        bug #5162
951
 
        """
952
 
        wt = self.make_standard_commit('test-line-log',
953
 
                committer='Line-Log-Formatter Tester <test@line.log>',
954
 
                authors=[])
955
 
        self.assertFormatterResult("""\
956
 
1: Line-Log-Formatte... 2005-11-22 add a
957
 
""",
958
 
            wt.branch, log.LineLogFormatter)
959
 
 
960
 
    def test_line_merge_revs_log_single_merge_revision(self):
961
 
        wt = self._prepare_tree_with_merges()
962
 
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
963
 
        rev = revspec.in_history(wt.branch)
964
 
        self.assertFormatterResult("""\
965
 
1.1.1: Joe Foo 2005-11-22 rev-merged
966
 
""",
967
 
            wt.branch, log.LineLogFormatter,
968
 
            formatter_kwargs=dict(levels=0),
969
 
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
970
 
 
971
 
    def test_line_merge_revs_log_with_merges(self):
972
 
        wt = self._prepare_tree_with_merges()
973
 
        self.assertFormatterResult("""\
974
 
2: Joe Foo 2005-11-22 [merge] rev-2
975
 
  1.1.1: Joe Foo 2005-11-22 rev-merged
976
 
1: Joe Foo 2005-11-22 rev-1
977
 
""",
978
 
            wt.branch, log.LineLogFormatter,
979
 
            formatter_kwargs=dict(levels=0))
980
 
 
981
 
 
982
 
class TestGnuChangelogFormatter(TestCaseForLogFormatter):
983
 
 
984
 
    def test_gnu_changelog(self):
985
 
        wt = self.make_standard_commit('nicky', authors=[])
986
 
        self.assertFormatterResult('''\
987
 
2005-11-22  Lorem Ipsum  <test@example.com>
988
 
 
989
 
\tadd a
990
 
 
991
 
''',
992
 
            wt.branch, log.GnuChangelogLogFormatter)
993
 
 
994
 
    def test_with_authors(self):
995
 
        wt = self.make_standard_commit('nicky',
996
 
            authors=['Fooa Fooz <foo@example.com>',
997
 
                     'Bari Baro <bar@example.com>'])
998
 
        self.assertFormatterResult('''\
999
 
2005-11-22  Fooa Fooz  <foo@example.com>
1000
 
 
1001
 
\tadd a
1002
 
 
1003
 
''',
1004
 
            wt.branch, log.GnuChangelogLogFormatter)
1005
 
 
1006
 
    def test_verbose(self):
1007
 
        wt = self.make_standard_commit('nicky')
1008
 
        self.assertFormatterResult('''\
1009
 
2005-11-22  John Doe  <jdoe@example.com>
1010
 
 
1011
 
\t* a:
1012
 
 
1013
 
\tadd a
1014
 
 
1015
 
''',
1016
 
            wt.branch, log.GnuChangelogLogFormatter,
1017
 
            show_log_kwargs=dict(verbose=True))
1018
 
 
1019
 
 
1020
 
class TestShowChangedRevisions(tests.TestCaseWithTransport):
1021
 
 
1022
 
    def test_show_changed_revisions_verbose(self):
1023
 
        tree = self.make_branch_and_tree('tree_a')
1024
 
        self.build_tree(['tree_a/foo'])
1025
 
        tree.add('foo')
1026
 
        tree.commit('bar', rev_id='bar-id')
1027
 
        s = self.make_utf8_encoded_stringio()
1028
 
        log.show_changed_revisions(tree.branch, [], ['bar-id'], s)
1029
 
        self.assertContainsRe(s.getvalue(), 'bar')
1030
 
        self.assertNotContainsRe(s.getvalue(), 'foo')
1031
 
 
1032
 
 
1033
 
class TestLogFormatter(tests.TestCase):
1034
 
 
1035
 
    def setUp(self):
1036
 
        super(TestLogFormatter, self).setUp()
1037
 
        self.rev = revision.Revision('a-id')
1038
 
        self.lf = log.LogFormatter(None)
1039
 
 
1040
 
    def test_short_committer(self):
1041
 
        def assertCommitter(expected, committer):
1042
 
            self.rev.committer = committer
1043
 
            self.assertEqual(expected, self.lf.short_committer(self.rev))
1044
 
 
1045
 
        assertCommitter('John Doe', 'John Doe <jdoe@example.com>')
1046
 
        assertCommitter('John Smith', 'John Smith <jsmith@example.com>')
1047
 
        assertCommitter('John Smith', 'John Smith')
1048
 
        assertCommitter('jsmith@example.com', 'jsmith@example.com')
1049
 
        assertCommitter('jsmith@example.com', '<jsmith@example.com>')
1050
 
        assertCommitter('John Smith', 'John Smith jsmith@example.com')
1051
 
 
1052
 
    def test_short_author(self):
1053
 
        def assertAuthor(expected, author):
1054
 
            self.rev.properties['author'] = author
1055
 
            self.assertEqual(expected, self.lf.short_author(self.rev))
1056
 
 
1057
 
        assertAuthor('John Smith', 'John Smith <jsmith@example.com>')
1058
 
        assertAuthor('John Smith', 'John Smith')
1059
 
        assertAuthor('jsmith@example.com', 'jsmith@example.com')
1060
 
        assertAuthor('jsmith@example.com', '<jsmith@example.com>')
1061
 
        assertAuthor('John Smith', 'John Smith jsmith@example.com')
1062
 
 
1063
 
    def test_short_author_from_committer(self):
1064
 
        self.rev.committer = 'John Doe <jdoe@example.com>'
1065
 
        self.assertEqual('John Doe', self.lf.short_author(self.rev))
1066
 
 
1067
 
    def test_short_author_from_authors(self):
1068
 
        self.rev.properties['authors'] = ('John Smith <jsmith@example.com>\n'
1069
 
                                          'Jane Rey <jrey@example.com>')
1070
 
        self.assertEqual('John Smith', self.lf.short_author(self.rev))
1071
 
 
1072
 
 
1073
 
class TestReverseByDepth(tests.TestCase):
1074
 
    """Test reverse_by_depth behavior.
1075
 
 
1076
 
    This is used to present revisions in forward (oldest first) order in a nice
1077
 
    layout.
1078
 
 
1079
 
    The tests use lighter revision description to ease reading.
1080
 
    """
1081
 
 
1082
 
    def assertReversed(self, forward, backward):
1083
 
        # Transform the descriptions to suit the API: tests use (revno, depth),
1084
 
        # while the API expects (revid, revno, depth)
1085
 
        def complete_revisions(l):
1086
 
            """Transform the description to suit the API.
1087
 
 
1088
 
            Tests use (revno, depth) whil the API expects (revid, revno, depth).
1089
 
            Since the revid is arbitrary, we just duplicate revno
1090
 
            """
1091
 
            return [ (r, r, d) for r, d in l]
1092
 
        forward = complete_revisions(forward)
1093
 
        backward= complete_revisions(backward)
1094
 
        self.assertEqual(forward, log.reverse_by_depth(backward))
1095
 
 
1096
 
 
1097
 
    def test_mainline_revisions(self):
1098
 
        self.assertReversed([( '1', 0), ('2', 0)],
1099
 
                            [('2', 0), ('1', 0)])
1100
 
 
1101
 
    def test_merged_revisions(self):
1102
 
        self.assertReversed([('1', 0), ('2', 0), ('2.2', 1), ('2.1', 1),],
1103
 
                            [('2', 0), ('2.1', 1), ('2.2', 1), ('1', 0),])
1104
 
    def test_shifted_merged_revisions(self):
1105
 
        """Test irregular layout.
1106
 
 
1107
 
        Requesting revisions touching a file can produce "holes" in the depths.
1108
 
        """
1109
 
        self.assertReversed([('1', 0), ('2', 0), ('1.1', 2), ('1.2', 2),],
1110
 
                            [('2', 0), ('1.2', 2), ('1.1', 2), ('1', 0),])
1111
 
 
1112
 
    def test_merged_without_child_revisions(self):
1113
 
        """Test irregular layout.
1114
 
 
1115
 
        Revision ranges can produce "holes" in the depths.
1116
 
        """
1117
 
        # When a revision of higher depth doesn't follow one of lower depth, we
1118
 
        # assume a lower depth one is virtually there
1119
 
        self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1120
 
                            [('4', 4), ('3', 3), ('2', 2), ('1', 2),])
1121
 
        # So we get the same order after reversing below even if the original
1122
 
        # revisions are not in the same order.
1123
 
        self.assertReversed([('1', 2), ('2', 2), ('3', 3), ('4', 4)],
1124
 
                            [('3', 3), ('4', 4), ('2', 2), ('1', 2),])
1125
 
 
1126
 
 
1127
 
class TestHistoryChange(tests.TestCaseWithTransport):
1128
 
 
1129
 
    def setup_a_tree(self):
1130
 
        tree = self.make_branch_and_tree('tree')
1131
 
        tree.lock_write()
1132
 
        self.addCleanup(tree.unlock)
1133
 
        tree.commit('1a', rev_id='1a')
1134
 
        tree.commit('2a', rev_id='2a')
1135
 
        tree.commit('3a', rev_id='3a')
1136
 
        return tree
1137
 
 
1138
 
    def setup_ab_tree(self):
1139
 
        tree = self.setup_a_tree()
1140
 
        tree.set_last_revision('1a')
1141
 
        tree.branch.set_last_revision_info(1, '1a')
1142
 
        tree.commit('2b', rev_id='2b')
1143
 
        tree.commit('3b', rev_id='3b')
1144
 
        return tree
1145
 
 
1146
 
    def setup_ac_tree(self):
1147
 
        tree = self.setup_a_tree()
1148
 
        tree.set_last_revision(revision.NULL_REVISION)
1149
 
        tree.branch.set_last_revision_info(0, revision.NULL_REVISION)
1150
 
        tree.commit('1c', rev_id='1c')
1151
 
        tree.commit('2c', rev_id='2c')
1152
 
        tree.commit('3c', rev_id='3c')
1153
 
        return tree
1154
 
 
1155
 
    def test_all_new(self):
1156
 
        tree = self.setup_ab_tree()
1157
 
        old, new = log.get_history_change('1a', '3a', tree.branch.repository)
1158
 
        self.assertEqual([], old)
1159
 
        self.assertEqual(['2a', '3a'], new)
1160
 
 
1161
 
    def test_all_old(self):
1162
 
        tree = self.setup_ab_tree()
1163
 
        old, new = log.get_history_change('3a', '1a', tree.branch.repository)
1164
 
        self.assertEqual([], new)
1165
 
        self.assertEqual(['2a', '3a'], old)
1166
 
 
1167
 
    def test_null_old(self):
1168
 
        tree = self.setup_ab_tree()
1169
 
        old, new = log.get_history_change(revision.NULL_REVISION,
1170
 
                                          '3a', tree.branch.repository)
1171
 
        self.assertEqual([], old)
1172
 
        self.assertEqual(['1a', '2a', '3a'], new)
1173
 
 
1174
 
    def test_null_new(self):
1175
 
        tree = self.setup_ab_tree()
1176
 
        old, new = log.get_history_change('3a', revision.NULL_REVISION,
1177
 
                                          tree.branch.repository)
1178
 
        self.assertEqual([], new)
1179
 
        self.assertEqual(['1a', '2a', '3a'], old)
1180
 
 
1181
 
    def test_diverged(self):
1182
 
        tree = self.setup_ab_tree()
1183
 
        old, new = log.get_history_change('3a', '3b', tree.branch.repository)
1184
 
        self.assertEqual(old, ['2a', '3a'])
1185
 
        self.assertEqual(new, ['2b', '3b'])
1186
 
 
1187
 
    def test_unrelated(self):
1188
 
        tree = self.setup_ac_tree()
1189
 
        old, new = log.get_history_change('3a', '3c', tree.branch.repository)
1190
 
        self.assertEqual(old, ['1a', '2a', '3a'])
1191
 
        self.assertEqual(new, ['1c', '2c', '3c'])
1192
 
 
1193
 
    def test_show_branch_change(self):
1194
 
        tree = self.setup_ab_tree()
1195
 
        s = StringIO()
1196
 
        log.show_branch_change(tree.branch, s, 3, '3a')
1197
 
        self.assertContainsRe(s.getvalue(),
1198
 
            '[*]{60}\nRemoved Revisions:\n(.|\n)*2a(.|\n)*3a(.|\n)*'
1199
 
            '[*]{60}\n\nAdded Revisions:\n(.|\n)*2b(.|\n)*3b')
1200
 
 
1201
 
    def test_show_branch_change_no_change(self):
1202
 
        tree = self.setup_ab_tree()
1203
 
        s = StringIO()
1204
 
        log.show_branch_change(tree.branch, s, 3, '3b')
1205
 
        self.assertEqual(s.getvalue(),
1206
 
            'Nothing seems to have changed\n')
1207
 
 
1208
 
    def test_show_branch_change_no_old(self):
1209
 
        tree = self.setup_ab_tree()
1210
 
        s = StringIO()
1211
 
        log.show_branch_change(tree.branch, s, 2, '2b')
1212
 
        self.assertContainsRe(s.getvalue(), 'Added Revisions:')
1213
 
        self.assertNotContainsRe(s.getvalue(), 'Removed Revisions:')
1214
 
 
1215
 
    def test_show_branch_change_no_new(self):
1216
 
        tree = self.setup_ab_tree()
1217
 
        tree.branch.set_last_revision_info(2, '2b')
1218
 
        s = StringIO()
1219
 
        log.show_branch_change(tree.branch, s, 3, '3b')
1220
 
        self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1221
 
        self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1222
 
 
1223
 
 
1224
 
class TestRevisionNotInBranch(TestCaseForLogFormatter):
1225
 
 
1226
 
    def setup_a_tree(self):
1227
 
        tree = self.make_branch_and_tree('tree')
1228
 
        tree.lock_write()
1229
 
        self.addCleanup(tree.unlock)
1230
 
        kwargs = {
1231
 
            'committer': 'Joe Foo <joe@foo.com>',
1232
 
            'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1233
 
            'timezone': 0, # UTC
1234
 
        }
1235
 
        tree.commit('commit 1a', rev_id='1a', **kwargs)
1236
 
        tree.commit('commit 2a', rev_id='2a', **kwargs)
1237
 
        tree.commit('commit 3a', rev_id='3a', **kwargs)
1238
 
        return tree
1239
 
 
1240
 
    def setup_ab_tree(self):
1241
 
        tree = self.setup_a_tree()
1242
 
        tree.set_last_revision('1a')
1243
 
        tree.branch.set_last_revision_info(1, '1a')
1244
 
        kwargs = {
1245
 
            'committer': 'Joe Foo <joe@foo.com>',
1246
 
            'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
1247
 
            'timezone': 0, # UTC
1248
 
        }
1249
 
        tree.commit('commit 2b', rev_id='2b', **kwargs)
1250
 
        tree.commit('commit 3b', rev_id='3b', **kwargs)
1251
 
        return tree
1252
 
 
1253
 
    def test_one_revision(self):
1254
 
        tree = self.setup_ab_tree()
1255
 
        lf = LogCatcher()
1256
 
        rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1257
 
        log.show_log(tree.branch, lf, verbose=True, start_revision=rev,
1258
 
                     end_revision=rev)
1259
 
        self.assertEqual(1, len(lf.revisions))
1260
 
        self.assertEqual(None, lf.revisions[0].revno)   # Out-of-branch
1261
 
        self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1262
 
 
1263
 
    def test_many_revisions(self):
1264
 
        tree = self.setup_ab_tree()
1265
 
        lf = LogCatcher()
1266
 
        start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1267
 
        end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1268
 
        log.show_log(tree.branch, lf, verbose=True, start_revision=start_rev,
1269
 
                     end_revision=end_rev)
1270
 
        self.assertEqual(3, len(lf.revisions))
1271
 
        self.assertEqual(None, lf.revisions[0].revno)   # Out-of-branch
1272
 
        self.assertEqual('3a', lf.revisions[0].rev.revision_id)
1273
 
        self.assertEqual(None, lf.revisions[1].revno)   # Out-of-branch
1274
 
        self.assertEqual('2a', lf.revisions[1].rev.revision_id)
1275
 
        self.assertEqual('1', lf.revisions[2].revno)    # In-branch
1276
 
 
1277
 
    def test_long_format(self):
1278
 
        tree = self.setup_ab_tree()
1279
 
        start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1280
 
        end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1281
 
        self.assertFormatterResult("""\
1282
 
------------------------------------------------------------
1283
 
revision-id: 3a
1284
 
committer: Joe Foo <joe@foo.com>
1285
 
branch nick: tree
1286
 
timestamp: Tue 2005-11-22 00:00:00 +0000
1287
 
message:
1288
 
  commit 3a
1289
 
------------------------------------------------------------
1290
 
revision-id: 2a
1291
 
committer: Joe Foo <joe@foo.com>
1292
 
branch nick: tree
1293
 
timestamp: Tue 2005-11-22 00:00:00 +0000
1294
 
message:
1295
 
  commit 2a
1296
 
------------------------------------------------------------
1297
 
revno: 1
1298
 
committer: Joe Foo <joe@foo.com>
1299
 
branch nick: tree
1300
 
timestamp: Tue 2005-11-22 00:00:00 +0000
1301
 
message:
1302
 
  commit 1a
1303
 
""",
1304
 
            tree.branch, log.LongLogFormatter, show_log_kwargs={
1305
 
                'start_revision': start_rev, 'end_revision': end_rev
1306
 
            })
1307
 
 
1308
 
    def test_short_format(self):
1309
 
        tree = self.setup_ab_tree()
1310
 
        start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1311
 
        end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1312
 
        self.assertFormatterResult("""\
1313
 
      Joe Foo\t2005-11-22
1314
 
      revision-id:3a
1315
 
      commit 3a
1316
 
 
1317
 
      Joe Foo\t2005-11-22
1318
 
      revision-id:2a
1319
 
      commit 2a
1320
 
 
1321
 
    1 Joe Foo\t2005-11-22
1322
 
      commit 1a
1323
 
 
1324
 
""",
1325
 
            tree.branch, log.ShortLogFormatter, show_log_kwargs={
1326
 
                'start_revision': start_rev, 'end_revision': end_rev
1327
 
            })
1328
 
 
1329
 
    def test_line_format(self):
1330
 
        tree = self.setup_ab_tree()
1331
 
        start_rev = revisionspec.RevisionInfo(tree.branch, None, '1a')
1332
 
        end_rev = revisionspec.RevisionInfo(tree.branch, None, '3a')
1333
 
        self.assertFormatterResult("""\
1334
 
Joe Foo 2005-11-22 commit 3a
1335
 
Joe Foo 2005-11-22 commit 2a
1336
 
1: Joe Foo 2005-11-22 commit 1a
1337
 
""",
1338
 
            tree.branch, log.LineLogFormatter, show_log_kwargs={
1339
 
                'start_revision': start_rev, 'end_revision': end_rev
1340
 
            })
1341
 
 
1342
 
 
1343
 
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1344
 
 
1345
 
    def setUp(self):
1346
 
        super(TestLogWithBugs, self).setUp()
1347
 
        log.properties_handler_registry.register(
1348
 
            'bugs_properties_handler',
1349
 
            log._bugs_properties_handler)
1350
 
 
1351
 
    def make_commits_with_bugs(self):
1352
 
        """Helper method for LogFormatter tests"""
1353
 
        tree = self.make_branch_and_tree(u'.')
1354
 
        self.build_tree(['a', 'b'])
1355
 
        tree.add('a')
1356
 
        self.wt_commit(tree, 'simple log message', rev_id='a1',
1357
 
                       revprops={'bugs': 'test://bug/id fixed'})
1358
 
        tree.add('b')
1359
 
        self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id='a2',
1360
 
                       authors=['Joe Bar <joe@bar.com>'],
1361
 
                       revprops={'bugs': 'test://bug/id fixed\n'
1362
 
                                 'test://bug/2 fixed'})
1363
 
        return tree
1364
 
 
1365
 
 
1366
 
    def test_long_bugs(self):
1367
 
        tree = self.make_commits_with_bugs()
1368
 
        self.assertFormatterResult("""\
1369
 
------------------------------------------------------------
1370
 
revno: 2
1371
 
fixes bugs: test://bug/id test://bug/2
1372
 
author: Joe Bar <joe@bar.com>
1373
 
committer: Joe Foo <joe@foo.com>
1374
 
branch nick: work
1375
 
timestamp: Tue 2005-11-22 00:00:01 +0000
1376
 
message:
1377
 
  multiline
1378
 
  log
1379
 
  message
1380
 
------------------------------------------------------------
1381
 
revno: 1
1382
 
fixes bug: test://bug/id
1383
 
committer: Joe Foo <joe@foo.com>
1384
 
branch nick: work
1385
 
timestamp: Tue 2005-11-22 00:00:00 +0000
1386
 
message:
1387
 
  simple log message
1388
 
""",
1389
 
            tree.branch, log.LongLogFormatter)
1390
 
 
1391
 
    def test_short_bugs(self):
1392
 
        tree = self.make_commits_with_bugs()
1393
 
        self.assertFormatterResult("""\
1394
 
    2 Joe Bar\t2005-11-22
1395
 
      fixes bugs: test://bug/id test://bug/2
1396
 
      multiline
1397
 
      log
1398
 
      message
1399
 
 
1400
 
    1 Joe Foo\t2005-11-22
1401
 
      fixes bug: test://bug/id
1402
 
      simple log message
1403
 
 
1404
 
""",
1405
 
            tree.branch, log.ShortLogFormatter)
1406
 
 
1407
 
    def test_wrong_bugs_property(self):
1408
 
        tree = self.make_branch_and_tree(u'.')
1409
 
        self.build_tree(['foo'])
1410
 
        self.wt_commit(tree, 'simple log message', rev_id='a1',
1411
 
                       revprops={'bugs': 'test://bug/id invalid_value'})
1412
 
        self.assertFormatterResult("""\
1413
 
    1 Joe Foo\t2005-11-22
1414
 
      simple log message
1415
 
 
1416
 
""",
1417
 
            tree.branch, log.ShortLogFormatter)
1418
 
 
1419
 
    def test_bugs_handler_present(self):
1420
 
        self.properties_handler_registry.get('bugs_properties_handler')
1421
 
 
1422
 
 
1423
 
class TestLogForAuthors(TestCaseForLogFormatter):
1424
 
 
1425
 
    def setUp(self):
1426
 
        super(TestLogForAuthors, self).setUp()
1427
 
        self.wt = self.make_standard_commit('nicky',
1428
 
            authors=['John Doe <jdoe@example.com>',
1429
 
                     'Jane Rey <jrey@example.com>'])
1430
 
 
1431
 
    def assertFormatterResult(self, formatter, who, result):
1432
 
        formatter_kwargs = dict()
1433
 
        if who is not None:
1434
 
            author_list_handler = log.author_list_registry.get(who)
1435
 
            formatter_kwargs['author_list_handler'] = author_list_handler
1436
 
        TestCaseForLogFormatter.assertFormatterResult(self, result,
1437
 
            self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
1438
 
 
1439
 
    def test_line_default(self):
1440
 
        self.assertFormatterResult(log.LineLogFormatter, None, """\
1441
 
1: John Doe 2005-11-22 add a
1442
 
""")
1443
 
 
1444
 
    def test_line_committer(self):
1445
 
        self.assertFormatterResult(log.LineLogFormatter, 'committer', """\
1446
 
1: Lorem Ipsum 2005-11-22 add a
1447
 
""")
1448
 
 
1449
 
    def test_line_first(self):
1450
 
        self.assertFormatterResult(log.LineLogFormatter, 'first', """\
1451
 
1: John Doe 2005-11-22 add a
1452
 
""")
1453
 
 
1454
 
    def test_line_all(self):
1455
 
        self.assertFormatterResult(log.LineLogFormatter, 'all', """\
1456
 
1: John Doe, Jane Rey 2005-11-22 add a
1457
 
""")
1458
 
 
1459
 
 
1460
 
    def test_short_default(self):
1461
 
        self.assertFormatterResult(log.ShortLogFormatter, None, """\
1462
 
    1 John Doe\t2005-11-22
1463
 
      add a
1464
 
 
1465
 
""")
1466
 
 
1467
 
    def test_short_committer(self):
1468
 
        self.assertFormatterResult(log.ShortLogFormatter, 'committer', """\
1469
 
    1 Lorem Ipsum\t2005-11-22
1470
 
      add a
1471
 
 
1472
 
""")
1473
 
 
1474
 
    def test_short_first(self):
1475
 
        self.assertFormatterResult(log.ShortLogFormatter, 'first', """\
1476
 
    1 John Doe\t2005-11-22
1477
 
      add a
1478
 
 
1479
 
""")
1480
 
 
1481
 
    def test_short_all(self):
1482
 
        self.assertFormatterResult(log.ShortLogFormatter, 'all', """\
1483
 
    1 John Doe, Jane Rey\t2005-11-22
1484
 
      add a
1485
 
 
1486
 
""")
1487
 
 
1488
 
    def test_long_default(self):
1489
 
        self.assertFormatterResult(log.LongLogFormatter, None, """\
1490
 
------------------------------------------------------------
1491
 
revno: 1
1492
 
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1493
 
committer: Lorem Ipsum <test@example.com>
1494
 
branch nick: nicky
1495
 
timestamp: Tue 2005-11-22 00:00:00 +0000
1496
 
message:
1497
 
  add a
1498
 
""")
1499
 
 
1500
 
    def test_long_committer(self):
1501
 
        self.assertFormatterResult(log.LongLogFormatter, 'committer', """\
1502
 
------------------------------------------------------------
1503
 
revno: 1
1504
 
committer: Lorem Ipsum <test@example.com>
1505
 
branch nick: nicky
1506
 
timestamp: Tue 2005-11-22 00:00:00 +0000
1507
 
message:
1508
 
  add a
1509
 
""")
1510
 
 
1511
 
    def test_long_first(self):
1512
 
        self.assertFormatterResult(log.LongLogFormatter, 'first', """\
1513
 
------------------------------------------------------------
1514
 
revno: 1
1515
 
author: John Doe <jdoe@example.com>
1516
 
committer: Lorem Ipsum <test@example.com>
1517
 
branch nick: nicky
1518
 
timestamp: Tue 2005-11-22 00:00:00 +0000
1519
 
message:
1520
 
  add a
1521
 
""")
1522
 
 
1523
 
    def test_long_all(self):
1524
 
        self.assertFormatterResult(log.LongLogFormatter, 'all', """\
1525
 
------------------------------------------------------------
1526
 
revno: 1
1527
 
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
1528
 
committer: Lorem Ipsum <test@example.com>
1529
 
branch nick: nicky
1530
 
timestamp: Tue 2005-11-22 00:00:00 +0000
1531
 
message:
1532
 
  add a
1533
 
""")
1534
 
 
1535
 
    def test_gnu_changelog_default(self):
1536
 
        self.assertFormatterResult(log.GnuChangelogLogFormatter, None, """\
1537
 
2005-11-22  John Doe  <jdoe@example.com>
1538
 
 
1539
 
\tadd a
1540
 
 
1541
 
""")
1542
 
 
1543
 
    def test_gnu_changelog_committer(self):
1544
 
        self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', """\
1545
 
2005-11-22  Lorem Ipsum  <test@example.com>
1546
 
 
1547
 
\tadd a
1548
 
 
1549
 
""")
1550
 
 
1551
 
    def test_gnu_changelog_first(self):
1552
 
        self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', """\
1553
 
2005-11-22  John Doe  <jdoe@example.com>
1554
 
 
1555
 
\tadd a
1556
 
 
1557
 
""")
1558
 
 
1559
 
    def test_gnu_changelog_all(self):
1560
 
        self.assertFormatterResult(log.GnuChangelogLogFormatter, 'all', """\
1561
 
2005-11-22  John Doe  <jdoe@example.com>, Jane Rey  <jrey@example.com>
1562
 
 
1563
 
\tadd a
1564
 
 
1565
 
""")
1566
 
 
1567
 
 
1568
 
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1569
 
 
1570
 
    def make_branch_with_alternate_ancestries(self, relpath='.'):
1571
 
        # See test_merge_sorted_exclude_ancestry below for the difference with
1572
 
        # bt.per_branch.test_iter_merge_sorted_revision.
1573
 
        # TestIterMergeSortedRevisionsBushyGraph.
1574
 
        # make_branch_with_alternate_ancestries
1575
 
        # and test_merge_sorted_exclude_ancestry
1576
 
        # See the FIXME in assertLogRevnos too.
1577
 
        builder = branchbuilder.BranchBuilder(self.get_transport(relpath))
1578
 
        # 1
1579
 
        # |\
1580
 
        # 2 \
1581
 
        # |  |
1582
 
        # |  1.1.1
1583
 
        # |  | \
1584
 
        # |  |  1.2.1
1585
 
        # |  | /
1586
 
        # |  1.1.2
1587
 
        # | /
1588
 
        # 3
1589
 
        builder.start_series()
1590
 
        builder.build_snapshot('1', None, [
1591
 
            ('add', ('', 'TREE_ROOT', 'directory', '')),])
1592
 
        builder.build_snapshot('1.1.1', ['1'], [])
1593
 
        builder.build_snapshot('2', ['1'], [])
1594
 
        builder.build_snapshot('1.2.1', ['1.1.1'], [])
1595
 
        builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1596
 
        builder.build_snapshot('3', ['2', '1.1.2'], [])
1597
 
        builder.finish_series()
1598
 
        br = builder.get_branch()
1599
 
        br.lock_read()
1600
 
        self.addCleanup(br.unlock)
1601
 
        return br
1602
 
 
1603
 
    def assertLogRevnos(self, expected_revnos, b, start, end,
1604
 
                        exclude_common_ancestry, generate_merge_revisions=True):
1605
 
        # FIXME: the layering in log makes it hard to test intermediate levels,
1606
 
        # I wish adding filters with their parameters was easier...
1607
 
        # -- vila 20100413
1608
 
        iter_revs = log._calc_view_revisions(
1609
 
            b, start, end, direction='reverse',
1610
 
            generate_merge_revisions=generate_merge_revisions,
1611
 
            exclude_common_ancestry=exclude_common_ancestry)
1612
 
        self.assertEqual(expected_revnos,
1613
 
                         [revid for revid, revno, depth in iter_revs])
1614
 
 
1615
 
    def test_merge_sorted_exclude_ancestry(self):
1616
 
        b = self.make_branch_with_alternate_ancestries()
1617
 
        self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1618
 
                             b, '1', '3', exclude_common_ancestry=False)
1619
 
        # '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1620
 
        # it should be mentioned even if merge_sort order will make it appear
1621
 
        # after 1.1.1
1622
 
        self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1623
 
                             b, '1.1.1', '3', exclude_common_ancestry=True)
1624
 
 
1625
 
    def test_merge_sorted_simple_revnos_exclude_ancestry(self):
1626
 
        b = self.make_branch_with_alternate_ancestries()
1627
 
        self.assertLogRevnos(['3', '2'],
1628
 
                             b, '1', '3', exclude_common_ancestry=True,
1629
 
                             generate_merge_revisions=False)
1630
 
        self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2'],
1631
 
                             b, '1', '3', exclude_common_ancestry=True,
1632
 
                             generate_merge_revisions=True)
1633
 
 
1634
 
 
1635
 
class TestLogDefaults(TestCaseForLogFormatter):
1636
 
    def test_default_log_level(self):
1637
 
        """
1638
 
        Test to ensure that specifying 'levels=1' to make_log_request_dict
1639
 
        doesn't get overwritten when using a LogFormatter that supports more
1640
 
        detail.
1641
 
        Fixes bug #747958.
1642
 
        """
1643
 
        wt = self._prepare_tree_with_merges()
1644
 
        b = wt.branch
1645
 
 
1646
 
        class CustomLogFormatter(log.LogFormatter):
1647
 
            def __init__(self, *args, **kwargs):
1648
 
                super(CustomLogFormatter, self).__init__(*args, **kwargs)
1649
 
                self.revisions = []
1650
 
            def get_levels(self):
1651
 
                # log formatter supports all levels:
1652
 
                return 0
1653
 
            def log_revision(self, revision):
1654
 
                self.revisions.append(revision)
1655
 
 
1656
 
        log_formatter = LogCatcher()
1657
 
        # First request we don't specify number of levels, we should get a
1658
 
        # sensible default (whatever the LogFormatter handles - which in this
1659
 
        # case is 0/everything):
1660
 
        request = log.make_log_request_dict(limit=10)
1661
 
        log.Logger(b, request).show(log_formatter)
1662
 
        # should have all three revisions:
1663
 
        self.assertEqual(len(log_formatter.revisions), 3)
1664
 
 
1665
 
        del log_formatter
1666
 
        log_formatter = LogCatcher()
1667
 
        # now explicitly request mainline revisions only:
1668
 
        request = log.make_log_request_dict(limit=10, levels=1)
1669
 
        log.Logger(b, request).show(log_formatter)
1670
 
        # should now only have 2 revisions:
1671
 
        self.assertEqual(len(log_formatter.revisions), 2)
1672
 
 
 
270
timestamp: Wed 2005-11-23 12:08:27 +1000
 
271
message:
 
272
  add a
 
273
added:
 
274
  a
 
275
''')