/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1685.1.80 by Wouter van Heyst
more code cleanup
2
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1685.1.80 by Wouter van Heyst
more code cleanup
7
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1685.1.80 by Wouter van Heyst
more code cleanup
12
#
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
import os
1123 by Martin Pool
* move bzr-specific code from testsweet into bzrlib.selftest
18
from cStringIO import StringIO
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
19
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
20
from bzrlib import log
2530.3.6 by Martin Pool
Remove BzrTestBase alias (little used)
21
from bzrlib.tests import TestCaseWithTransport
2490.1.2 by John Arbash Meinel
Cleanup according to PEP8 and some other small whitespace fixes
22
from bzrlib.log import (show_log,
23
                        get_view_revisions,
2466.8.1 by Kent Gibson
Reworked LogFormatter API to simplify extending the attributes of the revision being logged. Added support for begin_log() and end_log() hooks in LogFormatters.
24
                        LogRevision,
2490.1.2 by John Arbash Meinel
Cleanup according to PEP8 and some other small whitespace fixes
25
                        LogFormatter,
26
                        LongLogFormatter,
27
                        ShortLogFormatter,
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
28
                        LineLogFormatter)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
29
from bzrlib.branch import Branch
974.1.54 by aaron.bentley at utoronto
Fixed the revno bug in log
30
from bzrlib.errors import InvalidRevisionNumber
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
31
1685.1.69 by Wouter van Heyst
merge bzr.dev 1740
32
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
33
class LogCatcher(LogFormatter):
34
    """Pull log messages into list rather than displaying them.
35
36
    For ease of testing we save log messages here rather than actually
37
    formatting them, so that we can precisely check the result without
38
    being too dependent on the exact formatting.
39
40
    We should also test the LogFormatter.
41
    """
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.
42
2490.1.2 by John Arbash Meinel
Cleanup according to PEP8 and some other small whitespace fixes
43
    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.
44
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
45
    def __init__(self):
46
        super(LogCatcher, self).__init__(to_file=None)
47
        self.logs = []
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
48
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.
49
    def log_revision(self, revision):
50
        self.logs.append(revision)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
51
52
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
53
class TestShowLog(TestCaseWithTransport):
1102 by Martin Pool
- merge test refactoring from robertc
54
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
55
    def checkDelta(self, delta, **kw):
56
        """Check the filenames touched by a delta are as expected."""
57
        for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
58
            expected = kw.get(n, [])
59
            # strip out only the path components
60
            got = [x[0] for x in getattr(delta, n)]
61
            self.assertEquals(expected, got)
62
974.1.54 by aaron.bentley at utoronto
Fixed the revno bug in log
63
    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.
64
        wt = self.make_branch_and_tree('.')
65
        b = wt.branch
1092.3.4 by Robert Collins
update symlink branch to integration
66
67
        lf = LogCatcher()
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
68
        wt.commit('empty commit')
1092.3.4 by Robert Collins
update symlink branch to integration
69
        show_log(b, lf, verbose=True, start_revision=1, end_revision=1)
70
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
71
                          start_revision=2, end_revision=1) 
72
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
73
                          start_revision=1, end_revision=2) 
74
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
75
                          start_revision=0, end_revision=2) 
76
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
77
                          start_revision=1, end_revision=0) 
78
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
79
                          start_revision=-1, end_revision=1) 
80
        self.assertRaises(InvalidRevisionNumber, show_log, b, lf,
81
                          start_revision=1, end_revision=-1) 
82
1102 by Martin Pool
- merge test refactoring from robertc
83
    def test_simple_log(self):
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
84
        eq = self.assertEquals
85
        
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
86
        wt = self.make_branch_and_tree('.')
87
        b = wt.branch
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
88
89
        lf = LogCatcher()
90
        show_log(b, lf)
91
        # no entries yet
92
        eq(lf.logs, [])
93
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
94
        wt.commit('empty commit')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
95
        lf = LogCatcher()
96
        show_log(b, lf, verbose=True)
97
        eq(len(lf.logs), 1)
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
98
        eq(lf.logs[0].revno, '1')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
99
        eq(lf.logs[0].rev.message, 'empty commit')
100
        d = lf.logs[0].delta
101
        self.log('log delta: %r' % d)
102
        self.checkDelta(d)
103
104
        self.build_tree(['hello'])
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
105
        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.
106
        wt.commit('add one file',
107
                  committer=u'\u013d\xf3r\xe9m \xcdp\u0161\xfam '
108
                            u'<test@example.com>')
1123 by Martin Pool
* move bzr-specific code from testsweet into bzrlib.selftest
109
2717.1.1 by Lukáš Lalinsky
Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names.
110
        lf = self.make_utf8_encoded_stringio()
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
111
        # log using regular thing
1123 by Martin Pool
* move bzr-specific code from testsweet into bzrlib.selftest
112
        show_log(b, LongLogFormatter(lf))
113
        lf.seek(0)
114
        for l in lf.readlines():
115
            self.log(l)
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
116
117
        # get log as data structure
118
        lf = LogCatcher()
119
        show_log(b, lf, verbose=True)
120
        eq(len(lf.logs), 2)
121
        self.log('log entries:')
122
        for logentry in lf.logs:
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
123
            self.log('%4s %s' % (logentry.revno, logentry.rev.message))
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
124
        
125
        # first one is most recent
126
        logentry = lf.logs[0]
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
127
        eq(logentry.revno, '2')
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
128
        eq(logentry.rev.message, 'add one file')
129
        d = logentry.delta
130
        self.log('log 2 delta: %r' % d)
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
131
        self.checkDelta(d, added=['hello'])
974.1.26 by aaron.bentley at utoronto
merged mbp@sourcefrog.net-20050817233101-0939da1cf91f2472
132
        
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
133
        # commit a log message with control characters
134
        msg = "All 8-bit chars: " +  ''.join([unichr(x) for x in range(256)])
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
135
        self.log("original commit message: %r", msg)
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
136
        wt.commit(msg)
1185.11.5 by John Arbash Meinel
Merged up-to-date against mainline, still broken.
137
        lf = LogCatcher()
138
        show_log(b, lf, verbose=True)
139
        committed_msg = lf.logs[0].rev.message
140
        self.log("escaped commit message: %r", committed_msg)
141
        self.assert_(msg != committed_msg)
142
        self.assert_(len(committed_msg) > len(msg))
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
143
144
        # Check that log message with only XML-valid characters isn't
145
        # escaped.  As ElementTree apparently does some kind of
146
        # newline conversion, neither LF (\x0A) nor CR (\x0D) are
147
        # included in the test commit message, even though they are
148
        # valid XML 1.0 characters.
149
        msg = "\x09" + ''.join([unichr(x) for x in range(0x20, 256)])
150
        self.log("original commit message: %r", msg)
1534.4.36 by Robert Collins
Finish deprecating Branch.working_tree()
151
        wt.commit(msg)
1393.4.2 by Harald Meland
Cleanup + better test of commit-msg control character escape code.
152
        lf = LogCatcher()
153
        show_log(b, lf, verbose=True)
154
        committed_msg = lf.logs[0].rev.message
155
        self.log("escaped commit message: %r", committed_msg)
156
        self.assert_(msg == committed_msg)
1185.31.22 by John Arbash Meinel
[merge] bzr.dev
157
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
158
    def test_deltas_in_merge_revisions(self):
159
        """Check deltas created for both mainline and merge revisions"""
160
        eq = self.assertEquals
161
        wt = self.make_branch_and_tree('parent')
162
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
163
        wt.add('file1')
164
        wt.add('file2')
165
        wt.commit(message='add file1 and file2')
2581.1.6 by Martin Pool
fix up more run_bzr callers
166
        self.run_bzr('branch parent child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
167
        os.unlink('child/file1')
168
        print >> file('child/file2', 'wb'), 'hello'
2581.1.6 by Martin Pool
fix up more run_bzr callers
169
        self.run_bzr(['commit', '-m', 'remove file1 and modify file2',
170
            'child'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
171
        os.chdir('parent')
2581.1.6 by Martin Pool
fix up more run_bzr callers
172
        self.run_bzr('merge ../child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
173
        wt.commit('merge child branch')
174
        os.chdir('..')
175
        b = wt.branch
176
        lf = LogCatcher()
177
        lf.supports_merge_revisions = True
178
        show_log(b, lf, verbose=True)
179
        eq(len(lf.logs),3)
180
        logentry = lf.logs[0]
181
        eq(logentry.revno, '2')
182
        eq(logentry.rev.message, 'merge child branch')
183
        d = logentry.delta
184
        self.checkDelta(d, removed=['file1'], modified=['file2'])
185
        logentry = lf.logs[1]
186
        eq(logentry.revno, '1.1.1')
187
        eq(logentry.rev.message, 'remove file1 and modify file2')
188
        d = logentry.delta
189
        self.checkDelta(d, removed=['file1'], modified=['file2'])
190
        logentry = lf.logs[2]
191
        eq(logentry.revno, '1')
192
        eq(logentry.rev.message, 'add file1 and file2')
193
        d = logentry.delta
194
        self.checkDelta(d, added=['file1', 'file2'])
195
196
197
def make_commits_with_trailing_newlines(wt):
198
    """Helper method for LogFormatter tests"""    
199
    b = wt.branch
200
    b.nick='test'
201
    open('a', 'wb').write('hello moto\n')
202
    wt.add('a')
203
    wt.commit('simple log message', rev_id='a1'
204
            , timestamp=1132586655.459960938, timezone=-6*3600
205
            , committer='Joe Foo <joe@foo.com>')
206
    open('b', 'wb').write('goodbye\n')
207
    wt.add('b')
208
    wt.commit('multiline\nlog\nmessage\n', rev_id='a2'
209
            , timestamp=1132586842.411175966, timezone=-6*3600
210
            , committer='Joe Foo <joe@foo.com>')
211
212
    open('c', 'wb').write('just another manic monday\n')
213
    wt.add('c')
214
    wt.commit('single line with trailing newline\n', rev_id='a3'
215
            , timestamp=1132587176.835228920, timezone=-6*3600
216
            , committer = 'Joe Foo <joe@foo.com>')
217
    return b
218
219
220
class TestShortLogFormatter(TestCaseWithTransport):
221
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
222
    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.
223
        wt = self.make_branch_and_tree('.')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
224
        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.
225
        sio = self.make_utf8_encoded_stringio()
1185.31.21 by John Arbash Meinel
Added test for log formatting, found bug when redirecting short logs to a file instead of stdout.
226
        lf = ShortLogFormatter(to_file=sio)
227
        show_log(b, lf)
228
        self.assertEquals(sio.getvalue(), """\
229
    3 Joe Foo\t2005-11-21
230
      single line with trailing newline
231
232
    2 Joe Foo\t2005-11-21
233
      multiline
234
      log
235
      message
236
237
    1 Joe Foo\t2005-11-21
238
      simple log message
239
240
""")
241
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
242
243
class TestLongLogFormatter(TestCaseWithTransport):
244
245
    def normalize_log(self,log):
246
        """Replaces the variable lines of logs with fixed lines"""
247
        committer = 'committer: Lorem Ipsum <test@example.com>'
248
        lines = log.splitlines(True)
249
        for idx,line in enumerate(lines):
250
            stripped_line = line.lstrip()
251
            indent = ' ' * (len(line) - len(stripped_line))
252
            if stripped_line.startswith('committer:'):
253
                lines[idx] = indent + committer + '\n'
254
            if stripped_line.startswith('timestamp:'):
255
                lines[idx] = indent + 'timestamp: Just now\n'
256
        return ''.join(lines)
257
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
258
    def test_verbose_log(self):
259
        """Verbose log includes changed files
260
        
261
        bug #4676
262
        """
1534.4.26 by Robert Collins
Move working tree initialisation out from Branch.initialize, deprecated Branch.initialize to Branch.create.
263
        wt = self.make_branch_and_tree('.')
264
        b = wt.branch
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
265
        self.build_tree(['a'])
1185.33.45 by Martin Pool
[merge] refactoring of branch vs working tree, etc (robertc)
266
        wt.add('a')
1185.33.41 by Martin Pool
Fix regression of 'bzr log -v' - it wasn't showing changed files at all. (#4676)
267
        # XXX: why does a longer nick show up?
268
        b.nick = 'test_verbose_log'
269
        wt.commit(message='add a', 
270
                  timestamp=1132711707, 
271
                  timezone=36000,
272
                  committer='Lorem Ipsum <test@example.com>')
273
        logfile = file('out.tmp', 'w+')
274
        formatter = LongLogFormatter(to_file=logfile)
275
        show_log(b, formatter, verbose=True)
276
        logfile.flush()
277
        logfile.seek(0)
278
        log_contents = logfile.read()
279
        self.assertEqualDiff(log_contents, '''\
280
------------------------------------------------------------
281
revno: 1
282
committer: Lorem Ipsum <test@example.com>
283
branch nick: test_verbose_log
284
timestamp: Wed 2005-11-23 12:08:27 +1000
285
message:
286
  add a
287
added:
288
  a
289
''')
1185.85.4 by John Arbash Meinel
currently broken, trying to fix things up.
290
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
291
    def test_merges_are_indented_by_level(self):
292
        wt = self.make_branch_and_tree('parent')
293
        wt.commit('first post')
2581.1.6 by Martin Pool
fix up more run_bzr callers
294
        self.run_bzr('branch parent child')
295
        self.run_bzr(['commit', '-m', 'branch 1', '--unchanged', 'child'])
296
        self.run_bzr('branch child smallerchild')
297
        self.run_bzr(['commit', '-m', 'branch 2', '--unchanged',
298
            'smallerchild'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
299
        os.chdir('child')
2581.1.6 by Martin Pool
fix up more run_bzr callers
300
        self.run_bzr('merge ../smallerchild')
301
        self.run_bzr(['commit', '-m', 'merge branch 2'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
302
        os.chdir('../parent')
2581.1.6 by Martin Pool
fix up more run_bzr callers
303
        self.run_bzr('merge ../child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
304
        wt.commit('merge branch 1')
305
        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.
306
        sio = self.make_utf8_encoded_stringio()
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
307
        lf = LongLogFormatter(to_file=sio)
308
        show_log(b, lf, verbose=True)
309
        log = self.normalize_log(sio.getvalue())
310
        self.assertEqualDiff("""\
311
------------------------------------------------------------
312
revno: 2
313
committer: Lorem Ipsum <test@example.com>
314
branch nick: parent
315
timestamp: Just now
316
message:
317
  merge branch 1
318
    ------------------------------------------------------------
319
    revno: 1.1.2
320
    committer: Lorem Ipsum <test@example.com>
321
    branch nick: child
322
    timestamp: Just now
323
    message:
324
      merge branch 2
325
        ------------------------------------------------------------
326
        revno: 1.1.1.1.1
327
        committer: Lorem Ipsum <test@example.com>
328
        branch nick: smallerchild
329
        timestamp: Just now
330
        message:
331
          branch 2
332
    ------------------------------------------------------------
333
    revno: 1.1.1
334
    committer: Lorem Ipsum <test@example.com>
335
    branch nick: child
336
    timestamp: Just now
337
    message:
338
      branch 1
339
------------------------------------------------------------
340
revno: 1
341
committer: Lorem Ipsum <test@example.com>
342
branch nick: parent
343
timestamp: Just now
344
message:
345
  first post
346
""", log)
347
348
    def test_verbose_merge_revisions_contain_deltas(self):
349
        wt = self.make_branch_and_tree('parent')
350
        self.build_tree(['parent/f1', 'parent/f2'])
351
        wt.add(['f1','f2'])
352
        wt.commit('first post')
2581.1.6 by Martin Pool
fix up more run_bzr callers
353
        self.run_bzr('branch parent child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
354
        os.unlink('child/f1')
355
        print >> file('child/f2', 'wb'), 'hello'
2581.1.6 by Martin Pool
fix up more run_bzr callers
356
        self.run_bzr(['commit', '-m', 'removed f1 and modified f2',
357
            'child'])
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
358
        os.chdir('parent')
2581.1.6 by Martin Pool
fix up more run_bzr callers
359
        self.run_bzr('merge ../child')
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
360
        wt.commit('merge branch 1')
361
        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.
362
        sio = self.make_utf8_encoded_stringio()
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
363
        lf = LongLogFormatter(to_file=sio)
364
        show_log(b, lf, verbose=True)
365
        log = self.normalize_log(sio.getvalue())
366
        self.assertEqualDiff("""\
367
------------------------------------------------------------
368
revno: 2
369
committer: Lorem Ipsum <test@example.com>
370
branch nick: parent
371
timestamp: Just now
372
message:
373
  merge branch 1
374
removed:
375
  f1
376
modified:
377
  f2
378
    ------------------------------------------------------------
379
    revno: 1.1.1
380
    committer: Lorem Ipsum <test@example.com>
381
    branch nick: child
382
    timestamp: Just now
383
    message:
384
      removed f1 and modified f2
385
    removed:
386
      f1
387
    modified:
388
      f2
389
------------------------------------------------------------
390
revno: 1
391
committer: Lorem Ipsum <test@example.com>
392
branch nick: parent
393
timestamp: Just now
394
message:
395
  first post
396
added:
397
  f1
398
  f2
399
""", log)
400
401
    def test_trailing_newlines(self):
402
        wt = self.make_branch_and_tree('.')
403
        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.
404
        sio = self.make_utf8_encoded_stringio()
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
405
        lf = LongLogFormatter(to_file=sio)
406
        show_log(b, lf)
407
        self.assertEqualDiff(sio.getvalue(), """\
408
------------------------------------------------------------
409
revno: 3
410
committer: Joe Foo <joe@foo.com>
411
branch nick: test
412
timestamp: Mon 2005-11-21 09:32:56 -0600
413
message:
414
  single line with trailing newline
415
------------------------------------------------------------
416
revno: 2
417
committer: Joe Foo <joe@foo.com>
418
branch nick: test
419
timestamp: Mon 2005-11-21 09:27:22 -0600
420
message:
421
  multiline
422
  log
423
  message
424
------------------------------------------------------------
425
revno: 1
426
committer: Joe Foo <joe@foo.com>
427
branch nick: test
428
timestamp: Mon 2005-11-21 09:24:15 -0600
429
message:
430
  simple log message
431
""")
432
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.
433
    def test_author_in_log(self):
434
        """Log includes the author name if it's set in
435
        the revision properties
436
        """
437
        wt = self.make_branch_and_tree('.')
438
        b = wt.branch
439
        self.build_tree(['a'])
440
        wt.add('a')
441
        b.nick = 'test_author_log'
442
        wt.commit(message='add a',
443
                  timestamp=1132711707,
444
                  timezone=36000,
445
                  committer='Lorem Ipsum <test@example.com>',
2671.2.5 by Lukáš Lalinský
Fixes for comments from the mailing list.
446
                  author='John Doe <jdoe@example.com>')
2671.2.1 by Lukáš Lalinský
Add --author option to 'bzr commit' to record the author's name, if it's different from the committer.
447
        sio = StringIO()
448
        formatter = LongLogFormatter(to_file=sio)
449
        show_log(b, formatter)
450
        self.assertEqualDiff(sio.getvalue(), '''\
451
------------------------------------------------------------
452
revno: 1
453
committer: Lorem Ipsum <test@example.com>
454
author: John Doe <jdoe@example.com>
455
branch nick: test_author_log
456
timestamp: Wed 2005-11-23 12:08:27 +1000
457
message:
458
  add a
459
''')
460
461
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
462
463
class TestLineLogFormatter(TestCaseWithTransport):
464
1704.2.20 by Martin Pool
log --line shows revision numbers (Alexander)
465
    def test_line_log(self):
466
        """Line log should show revno
467
        
468
        bug #5162
469
        """
470
        wt = self.make_branch_and_tree('.')
471
        b = wt.branch
472
        self.build_tree(['a'])
473
        wt.add('a')
474
        b.nick = 'test-line-log'
475
        wt.commit(message='add a', 
476
                  timestamp=1132711707, 
477
                  timezone=36000,
478
                  committer='Line-Log-Formatter Tester <test@line.log>')
479
        logfile = file('out.tmp', 'w+')
480
        formatter = LineLogFormatter(to_file=logfile)
481
        show_log(b, formatter)
482
        logfile.flush()
483
        logfile.seek(0)
484
        log_contents = logfile.read()
485
        self.assertEqualDiff(log_contents, '1: Line-Log-Formatte... 2005-11-23 add a\n')
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
486
2483.2.1 by John Arbash Meinel
Add a test with a merged revision
487
    def test_short_log_with_merges(self):
488
        wt = self.make_branch_and_memory_tree('.')
489
        wt.lock_write()
490
        try:
491
            wt.add('')
492
            wt.commit('rev-1', rev_id='rev-1',
493
                      timestamp=1132586655, timezone=36000,
494
                      committer='Joe Foo <joe@foo.com>')
495
            wt.commit('rev-merged', rev_id='rev-2a',
496
                      timestamp=1132586700, timezone=36000,
497
                      committer='Joe Foo <joe@foo.com>')
498
            wt.set_parent_ids(['rev-1', 'rev-2a'])
499
            wt.branch.set_last_revision_info(1, 'rev-1')
500
            wt.commit('rev-2', rev_id='rev-2b',
501
                      timestamp=1132586800, timezone=36000,
502
                      committer='Joe Foo <joe@foo.com>')
2717.1.1 by Lukáš Lalinsky
Use UTF-8 encoded StringIO for log tests to avoid failures on non-ASCII committer names.
503
            logfile = self.make_utf8_encoded_stringio()
2483.2.1 by John Arbash Meinel
Add a test with a merged revision
504
            formatter = ShortLogFormatter(to_file=logfile)
505
            show_log(wt.branch, formatter)
506
            logfile.flush()
507
            self.assertEqualDiff("""\
2483.2.2 by John Arbash Meinel
Add [merge] after the timestamp for revisions with merges.
508
    2 Joe Foo\t2005-11-22 [merge]
2483.2.1 by John Arbash Meinel
Add a test with a merged revision
509
      rev-2
510
511
    1 Joe Foo\t2005-11-22
512
      rev-1
513
514
""", logfile.getvalue())
515
        finally:
516
            wt.unlock()
517
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
518
    def test_trailing_newlines(self):
519
        wt = self.make_branch_and_tree('.')
520
        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.
521
        sio = self.make_utf8_encoded_stringio()
2466.11.2 by Kent Gibson
Add tests for deltas in merge revisions
522
        lf = LineLogFormatter(to_file=sio)
523
        show_log(b, lf)
524
        self.assertEqualDiff(sio.getvalue(), """\
525
3: Joe Foo 2005-11-21 single line with trailing newline
526
2: Joe Foo 2005-11-21 multiline
527
1: Joe Foo 2005-11-21 simple log message
528
""")
529
530
531
class TestGetViewRevisions(TestCaseWithTransport):
532
1756.2.22 by Aaron Bentley
Apply review comments
533
    def make_tree_with_commits(self):
534
        """Create a tree with well-known revision ids"""
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
535
        wt = self.make_branch_and_tree('tree1')
536
        wt.commit('commit one', rev_id='1')
537
        wt.commit('commit two', rev_id='2')
538
        wt.commit('commit three', rev_id='3')
539
        mainline_revs = [None, '1', '2', '3']
1756.2.22 by Aaron Bentley
Apply review comments
540
        rev_nos = {'1': 1, '2': 2, '3': 3}
541
        return mainline_revs, rev_nos, wt
542
543
    def make_tree_with_merges(self):
544
        """Create a tree with well-known revision ids and a merge"""
545
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
546
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
547
        tree2.commit('four-a', rev_id='4a')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
548
        wt.merge_from_branch(tree2.branch)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
549
        wt.commit('four-b', rev_id='4b')
550
        mainline_revs.append('4b')
1756.2.22 by Aaron Bentley
Apply review comments
551
        rev_nos['4b'] = 4
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
552
        # 4a: 3.1.1
1756.2.22 by Aaron Bentley
Apply review comments
553
        return mainline_revs, rev_nos, wt
554
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
555
    def make_tree_with_many_merges(self):
556
        """Create a tree with well-known revision ids"""
557
        wt = self.make_branch_and_tree('tree1')
558
        wt.commit('commit one', rev_id='1')
559
        wt.commit('commit two', rev_id='2')
560
        tree3 = wt.bzrdir.sprout('tree3').open_workingtree()
561
        tree3.commit('commit three a', rev_id='3a')
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
562
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
563
        tree2.merge_from_branch(tree3.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
564
        tree2.commit('commit three b', rev_id='3b')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
565
        wt.merge_from_branch(tree2.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
566
        wt.commit('commit three c', rev_id='3c')
567
        tree2.commit('four-a', rev_id='4a')
1979.2.1 by Robert Collins
(robertc) adds a convenience method "merge_from_branch" to WorkingTree.
568
        wt.merge_from_branch(tree2.branch)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
569
        wt.commit('four-b', rev_id='4b')
570
        mainline_revs = [None, '1', '2', '3c', '4b']
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
571
        rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
572
        full_rev_nos_for_reference = {
573
            '1': '1',
574
            '2': '2',
575
            '3a': '2.2.1', #first commit tree 3
576
            '3b': '2.1.1', # first commit tree 2
577
            '3c': '3', #merges 3b to main
578
            '4a': '2.1.2', # second commit tree 2
579
            '4b': '4', # merges 4a to main
580
            }
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
581
        return mainline_revs, rev_nos, wt
582
1756.2.22 by Aaron Bentley
Apply review comments
583
    def test_get_view_revisions_forward(self):
584
        """Test the get_view_revisions method"""
585
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
586
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
587
                                            'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
588
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
589
            revisions)
1756.2.22 by Aaron Bentley
Apply review comments
590
        revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
591
                                             'forward', include_merges=False))
592
        self.assertEqual(revisions, revisions2)
593
594
    def test_get_view_revisions_reverse(self):
595
        """Test the get_view_revisions with reverse"""
596
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
597
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
598
                                            'reverse'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
599
        self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
600
            revisions)
1756.2.22 by Aaron Bentley
Apply review comments
601
        revisions2 = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
602
                                             'reverse', include_merges=False))
603
        self.assertEqual(revisions, revisions2)
604
605
    def test_get_view_revisions_merge(self):
606
        """Test get_view_revisions when there are merges"""
607
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
608
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
609
                                            'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
610
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
611
            ('4b', '4', 0), ('4a', '3.1.1', 1)],
612
            revisions)
1756.2.20 by Aaron Bentley
Optimize log formats that don't show merges
613
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
1756.2.22 by Aaron Bentley
Apply review comments
614
                                             'forward', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
615
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
616
            ('4b', '4', 0)],
617
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
618
619
    def test_get_view_revisions_merge_reverse(self):
620
        """Test get_view_revisions in reverse when there are merges"""
621
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
622
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
623
                                            'reverse'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
624
        self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
625
            ('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
626
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
627
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
628
                                             'reverse', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
629
        self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
630
            ('1', '1', 0)],
631
            revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
632
633
    def test_get_view_revisions_merge2(self):
634
        """Test get_view_revisions when there are merges"""
635
        mainline_revs, rev_nos, wt = self.make_tree_with_many_merges()
636
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
637
                                            'forward'))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
638
        expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
639
            ('3a', '2.2.1', 1), ('3b', '2.1.1', 1), ('4b', '4', 0),
640
            ('4a', '2.1.2', 1)]
641
        self.assertEqual(expected, revisions)
1756.2.24 by Aaron Bentley
Forward sorting shows merges under mainline revision
642
        revisions = list(get_view_revisions(mainline_revs, rev_nos, wt.branch,
643
                                             'forward', include_merges=False))
1988.4.2 by Robert Collins
``bzr log`` Now shows dotted-decimal revision numbers for all revisions,
644
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
645
            ('4b', '4', 0)],
646
            revisions)
2359.1.6 by John Arbash Meinel
Create a helper tree which has a semi-interesting history.
647
648
649
class TestGetRevisionsTouchingFileID(TestCaseWithTransport):
650
651
    def create_tree_with_single_merge(self):
652
        """Create a branch with a moderate layout.
653
654
        The revision graph looks like:
655
656
           A
657
           |\
658
           B C
659
           |/
660
           D
661
662
        In this graph, A introduced files f1 and f2 and f3.
663
        B modifies f1 and f3, and C modifies f2 and f3.
664
        D merges the changes from B and C and resolves the conflict for f3.
665
        """
666
        # TODO: jam 20070218 This seems like it could really be done
667
        #       with make_branch_and_memory_tree() if we could just
668
        #       create the content of those files.
669
        # TODO: jam 20070218 Another alternative is that we would really
670
        #       like to only create this tree 1 time for all tests that
671
        #       use it. Since 'log' only uses the tree in a readonly
672
        #       fashion, it seems a shame to regenerate an identical
673
        #       tree for each test.
674
        tree = self.make_branch_and_tree('tree')
675
        tree.lock_write()
676
        self.addCleanup(tree.unlock)
677
678
        self.build_tree_contents([('tree/f1', 'A\n'),
679
                                  ('tree/f2', 'A\n'),
680
                                  ('tree/f3', 'A\n'),
681
                                 ])
682
        tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
683
        tree.commit('A', rev_id='A')
684
685
        self.build_tree_contents([('tree/f2', 'A\nC\n'),
686
                                  ('tree/f3', 'A\nC\n'),
687
                                 ])
688
        tree.commit('C', rev_id='C')
689
        # Revert back to A to build the other history.
690
        tree.set_last_revision('A')
691
        tree.branch.set_last_revision_info(1, 'A')
692
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
693
                                  ('tree/f2', 'A\n'),
694
                                  ('tree/f3', 'A\nB\n'),
695
                                 ])
696
        tree.commit('B', rev_id='B')
697
        tree.set_parent_ids(['B', 'C'])
698
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
699
                                  ('tree/f2', 'A\nC\n'),
700
                                  ('tree/f3', 'A\nB\nC\n'),
701
                                 ])
702
        tree.commit('D', rev_id='D')
703
704
        # Switch to a read lock for this tree.
705
        # We still have addCleanup(unlock)
706
        tree.unlock()
707
        tree.lock_read()
708
        return tree
709
710
    def test_tree_with_single_merge(self):
711
        """Make sure the tree layout is correct."""
712
        tree = self.create_tree_with_single_merge()
713
        rev_A_tree = tree.branch.repository.revision_tree('A')
714
        rev_B_tree = tree.branch.repository.revision_tree('B')
715
716
        f1_changed = (u'f1', 'f1-id', 'file', True, False)
717
        f2_changed = (u'f2', 'f2-id', 'file', True, False)
718
        f3_changed = (u'f3', 'f3-id', 'file', True, False)
719
720
        delta = rev_B_tree.changes_from(rev_A_tree)
721
        self.assertEqual([f1_changed, f3_changed], delta.modified)
722
        self.assertEqual([], delta.renamed)
723
        self.assertEqual([], delta.added)
724
        self.assertEqual([], delta.removed)
725
726
        rev_C_tree = tree.branch.repository.revision_tree('C')
727
        delta = rev_C_tree.changes_from(rev_A_tree)
728
        self.assertEqual([f2_changed, f3_changed], delta.modified)
729
        self.assertEqual([], delta.renamed)
730
        self.assertEqual([], delta.added)
731
        self.assertEqual([], delta.removed)
732
733
        rev_D_tree = tree.branch.repository.revision_tree('D')
734
        delta = rev_D_tree.changes_from(rev_B_tree)
735
        self.assertEqual([f2_changed, f3_changed], delta.modified)
736
        self.assertEqual([], delta.renamed)
737
        self.assertEqual([], delta.added)
738
        self.assertEqual([], delta.removed)
739
740
        delta = rev_D_tree.changes_from(rev_C_tree)
741
        self.assertEqual([f1_changed, f3_changed], delta.modified)
742
        self.assertEqual([], delta.renamed)
743
        self.assertEqual([], delta.added)
744
        self.assertEqual([], delta.removed)
745
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
746
    def assertAllRevisionsForFileID(self, tree, file_id, revisions):
2466.12.1 by Kent Gibson
Fix ``bzr log -r`` to support selecting merge revisions.
747
        """Make sure _filter_revisions_touching_file_id returns the right values.
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
748
2466.12.1 by Kent Gibson
Fix ``bzr log -r`` to support selecting merge revisions.
749
        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
750
        sure they are correct.
751
        """
752
        # The api for _get_revisions_touching_file_id is a little crazy,
753
        # So we do the setup here.
754
        mainline = tree.branch.revision_history()
755
        mainline.insert(0, None)
756
        revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
757
        view_revs_iter = log.get_view_revisions(mainline, revnos, tree.branch,
758
                                                'reverse', True)
2466.12.1 by Kent Gibson
Fix ``bzr log -r`` to support selecting merge revisions.
759
        actual_revs = log._filter_revisions_touching_file_id(
760
                            tree.branch, 
761
                            file_id,
762
                            mainline,
763
                            list(view_revs_iter))
2359.1.7 by John Arbash Meinel
Create a direct test for _get_revisions_touching_file_id
764
        self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
765
766
    def test_file_id_f1(self):
767
        tree = self.create_tree_with_single_merge()
768
        # f1 should be marked as modified by revisions A and B
769
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
770
771
    def test_file_id_f2(self):
772
        tree = self.create_tree_with_single_merge()
773
        # f2 should be marked as modified by revisions A, C, and D
774
        # because D merged the changes from C.
775
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
776
777
    def test_file_id_f3(self):
778
        tree = self.create_tree_with_single_merge()
779
        # f3 should be marked as modified by revisions A, B, C, and D
780
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1551.17.2 by Aaron Bentley
Stop showing deltas in pull -v output
781
782
783
class TestShowChangedRevisions(TestCaseWithTransport):
784
785
    def test_show_changed_revisions_verbose(self):
786
        tree = self.make_branch_and_tree('tree_a')
787
        self.build_tree(['tree_a/foo'])
788
        tree.add('foo')
789
        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.
790
        s = self.make_utf8_encoded_stringio()
1551.17.2 by Aaron Bentley
Stop showing deltas in pull -v output
791
        log.show_changed_revisions(tree.branch, [], ['bar-id'], s)
792
        self.assertContainsRe(s.getvalue(), 'bar')
793
        self.assertNotContainsRe(s.getvalue(), 'foo')