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