~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/blackbox/test_log.py

  • Committer: Andrew Bennetts
  • Date: 2009-07-27 05:35:00 UTC
  • mfrom: (4570 +trunk)
  • mto: (4634.6.29 2.0)
  • mto: This revision was merged to the branch mainline in revision 4680.
  • Revision ID: andrew.bennetts@canonical.com-20090727053500-q76zsn2dx33jhmj5
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
2
 
# -*- coding: utf-8 -*-
 
1
# Copyright (C) 2005, 2006, 2007, 2009 Canonical Ltd
3
2
#
4
3
# This program is free software; you can redistribute it and/or modify
5
4
# it under the terms of the GNU General Public License as published by
13
12
#
14
13
# You should have received a copy of the GNU General Public License
15
14
# along with this program; if not, write to the Free Software
16
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
16
 
18
17
 
19
18
"""Black-box tests for bzr log."""
20
19
 
21
 
import os, re
 
20
import os
 
21
import re
22
22
 
23
 
from bzrlib import osutils
24
 
from bzrlib.tests.blackbox import ExternalBase
25
 
from bzrlib.tests import KnownFailure, TestCaseInTempDir, TestCaseWithTransport
26
 
from bzrlib.tests.test_log import (
27
 
    normalize_log,
 
23
from bzrlib import (
 
24
    osutils,
 
25
    tests,
28
26
    )
29
27
from bzrlib.tests import test_log
30
28
 
31
29
 
32
 
class TestCaseWithoutPropsHandler(ExternalBase,
33
 
                                  test_log.TestCaseWithoutPropsHandler):
34
 
    pass
35
 
 
36
 
 
37
 
class TestLog(ExternalBase):
38
 
 
39
 
    def _prepare(self, path='.', format=None):
 
30
class TestLog(tests.TestCaseWithTransport):
 
31
 
 
32
    def setUp(self):
 
33
        super(TestLog, self).setUp()
 
34
        self.timezone = 0 # UTC
 
35
        self.timestamp = 1132617600 # Mon 2005-11-22 00:00:00 +0000
 
36
 
 
37
    def make_minimal_branch(self, path='.', format=None):
 
38
        tree = self.make_branch_and_tree(path, format=format)
 
39
        self.build_tree([path + '/hello.txt'])
 
40
        tree.add('hello.txt')
 
41
        tree.commit(message='message1')
 
42
        return tree
 
43
 
 
44
    def make_linear_branch(self, path='.', format=None):
40
45
        tree = self.make_branch_and_tree(path, format=format)
41
46
        self.build_tree(
42
47
            [path + '/hello.txt', path + '/goodbye.txt', path + '/meep.txt'])
46
51
        tree.commit(message='message2')
47
52
        tree.add('meep.txt')
48
53
        tree.commit(message='message3')
49
 
        self.full_log = self.run_bzr(["log", path])[0]
50
 
        return tree
 
54
        return tree
 
55
 
 
56
    def make_merged_branch(self, path='.', format=None):
 
57
        tree = self.make_linear_branch(path, format)
 
58
        tree2 = tree.bzrdir.sprout('tree2',
 
59
            revision_id=tree.branch.get_rev_id(1)).open_workingtree()
 
60
        tree2.commit(message='tree2 message2')
 
61
        tree2.commit(message='tree2 message3')
 
62
        tree.merge_from_branch(tree2.branch)
 
63
        tree.commit(message='merge')
 
64
        return tree
 
65
 
 
66
    def assertRevnos(self, log, must_have=(), must_not_have=()):
 
67
        """Check if revnos are in or not in the log output"""
 
68
        for revno in must_have:
 
69
            self.assertTrue(('revno: %s\n' % revno) in log,
 
70
                'Does not contain expected revno %s' % revno)
 
71
        for revno in must_not_have:
 
72
            self.assertFalse(('revno: %s\n' % revno) in log,
 
73
                'Contains unexpected revno %s' % revno)
 
74
 
 
75
    def commit_options(self):
 
76
        """Use some mostly fixed values for commits to simplify tests.
 
77
 
 
78
        Tests can use this function to get some commit attributes. The time
 
79
        stamp is incremented at each commit.
 
80
        """
 
81
        self.timestamp += 1 # 1 second between each commit
 
82
        return dict(committer='Lorem Ipsum <joe@foo.com>',
 
83
                 timezone=self.timezone,
 
84
                 timestamp=self.timestamp,
 
85
                 )
 
86
 
 
87
    def check_log(self, expected, args, working_dir='level0'):
 
88
        out, err = self.run_bzr(['log', '--timezone', 'utc'] + args,
 
89
                                working_dir=working_dir)
 
90
        self.assertEqual('', err)
 
91
        self.assertEqualDiff(expected, test_log.normalize_log(out))
 
92
 
 
93
 
 
94
class TestLogRevSpecs(TestLog):
51
95
 
52
96
    def test_log_null_end_revspec(self):
53
 
        self._prepare()
54
 
        self.assertTrue('revno: 1\n' in self.full_log)
55
 
        self.assertTrue('revno: 2\n' in self.full_log)
56
 
        self.assertTrue('revno: 3\n' in self.full_log)
57
 
        self.assertTrue('message:\n  message1\n' in self.full_log)
58
 
        self.assertTrue('message:\n  message2\n' in self.full_log)
59
 
        self.assertTrue('message:\n  message3\n' in self.full_log)
 
97
        self.make_linear_branch()
 
98
        log = self.run_bzr(['log'])[0]
 
99
        self.assertTrue('revno: 1\n' in log)
 
100
        self.assertTrue('revno: 2\n' in log)
 
101
        self.assertTrue('revno: 3\n' in log)
 
102
        self.assertTrue('message:\n  message1\n' in log)
 
103
        self.assertTrue('message:\n  message2\n' in log)
 
104
        self.assertTrue('message:\n  message3\n' in log)
60
105
 
 
106
        full_log = self.run_bzr(['log'])[0]
61
107
        log = self.run_bzr("log -r 1..")[0]
62
 
        self.assertEqualDiff(log, self.full_log)
 
108
        self.assertEqualDiff(log, full_log)
63
109
 
64
110
    def test_log_null_begin_revspec(self):
65
 
        self._prepare()
 
111
        self.make_linear_branch()
 
112
        full_log = self.run_bzr(['log'])[0]
66
113
        log = self.run_bzr("log -r ..3")[0]
67
 
        self.assertEqualDiff(self.full_log, log)
 
114
        self.assertEqualDiff(full_log, log)
68
115
 
69
116
    def test_log_null_both_revspecs(self):
70
 
        self._prepare()
 
117
        self.make_linear_branch()
 
118
        full_log = self.run_bzr(['log'])[0]
71
119
        log = self.run_bzr("log -r ..")[0]
72
 
        self.assertEqualDiff(self.full_log, log)
 
120
        self.assertEqualDiff(full_log, log)
73
121
 
74
122
    def test_log_zero_revspec(self):
75
 
        self._prepare()
76
 
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
 
123
        self.make_minimal_branch()
 
124
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
77
125
                           ['log', '-r0'])
78
126
 
79
127
    def test_log_zero_begin_revspec(self):
80
 
        self._prepare()
81
 
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
 
128
        self.make_linear_branch()
 
129
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
82
130
                           ['log', '-r0..2'])
83
131
 
84
132
    def test_log_zero_end_revspec(self):
85
 
        self._prepare()
86
 
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
 
133
        self.make_linear_branch()
 
134
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
87
135
                           ['log', '-r-2..0'])
88
136
 
89
 
    def test_log_unsupported_timezone(self):
90
 
        self._prepare()
91
 
        self.run_bzr_error('bzr: ERROR: Unsupported timezone format "foo", '
92
 
                           'options are "utc", "original", "local".',
93
 
                           ['log', '--timezone', 'foo'])
94
 
 
95
137
    def test_log_negative_begin_revspec_full_log(self):
96
 
        self._prepare()
 
138
        self.make_linear_branch()
 
139
        full_log = self.run_bzr(['log'])[0]
97
140
        log = self.run_bzr("log -r -3..")[0]
98
 
        self.assertEqualDiff(self.full_log, log)
 
141
        self.assertEqualDiff(full_log, log)
99
142
 
100
143
    def test_log_negative_both_revspec_full_log(self):
101
 
        self._prepare()
 
144
        self.make_linear_branch()
 
145
        full_log = self.run_bzr(['log'])[0]
102
146
        log = self.run_bzr("log -r -3..-1")[0]
103
 
        self.assertEqualDiff(self.full_log, log)
 
147
        self.assertEqualDiff(full_log, log)
104
148
 
105
149
    def test_log_negative_both_revspec_partial(self):
106
 
        self._prepare()
 
150
        self.make_linear_branch()
107
151
        log = self.run_bzr("log -r -3..-2")[0]
108
152
        self.assertTrue('revno: 1\n' in log)
109
153
        self.assertTrue('revno: 2\n' in log)
110
154
        self.assertTrue('revno: 3\n' not in log)
111
155
 
112
156
    def test_log_negative_begin_revspec(self):
113
 
        self._prepare()
 
157
        self.make_linear_branch()
114
158
        log = self.run_bzr("log -r -2..")[0]
115
159
        self.assertTrue('revno: 1\n' not in log)
116
160
        self.assertTrue('revno: 2\n' in log)
117
161
        self.assertTrue('revno: 3\n' in log)
118
162
 
119
163
    def test_log_positive_revspecs(self):
120
 
        self._prepare()
 
164
        self.make_linear_branch()
 
165
        full_log = self.run_bzr(['log'])[0]
121
166
        log = self.run_bzr("log -r 1..3")[0]
122
 
        self.assertEqualDiff(self.full_log, log)
 
167
        self.assertEqualDiff(full_log, log)
 
168
 
 
169
    def test_log_dotted_revspecs(self):
 
170
        self.make_merged_branch()
 
171
        log = self.run_bzr("log -n0 -r 1..1.1.1")[0]
 
172
        self.assertRevnos(log, (1, '1.1.1'), (2, 3, '1.1.2', 4))
123
173
 
124
174
    def test_log_reversed_revspecs(self):
125
 
        self._prepare()
 
175
        self.make_linear_branch()
126
176
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
127
177
                            'the end revision.\n',),
128
178
                           ['log', '-r3..1'])
129
179
 
 
180
    def test_log_reversed_dotted_revspecs(self):
 
181
        self.make_merged_branch()
 
182
        self.run_bzr_error(('bzr: ERROR: Start revision not found in '
 
183
                            'left-hand history of end revision.\n',),
 
184
                           "log -r 1.1.1..1")
 
185
 
130
186
    def test_log_revno_n_path(self):
131
 
        self._prepare(path='branch1')
132
 
        self._prepare(path='branch2')
133
 
        log = self.run_bzr("log -r revno:2:branch1..revno:3:branch2",
134
 
                          retcode=3)[0]
 
187
        self.make_linear_branch('branch1')
 
188
        self.make_linear_branch('branch2')
 
189
        # Swapped revisions
 
190
        self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)[0]
 
191
        # Correct order
135
192
        log = self.run_bzr("log -r revno:1:branch2..revno:3:branch2")[0]
136
 
        self.assertEqualDiff(self.full_log, log)
 
193
        full_log = self.run_bzr(['log'], working_dir='branch2')[0]
 
194
        self.assertEqualDiff(full_log, log)
137
195
        log = self.run_bzr("log -r revno:1:branch2")[0]
138
196
        self.assertTrue('revno: 1\n' in log)
139
197
        self.assertTrue('revno: 2\n' not in log)
141
199
        self.assertTrue('branch nick: branch1\n' not in log)
142
200
 
143
201
    def test_log_nonexistent_revno(self):
144
 
        self._prepare()
145
 
        (out, err) = self.run_bzr_error(args="log -r 1234",
146
 
            error_regexes=["bzr: ERROR: Requested revision: '1234' "
147
 
                "does not exist in branch:"])
 
202
        self.make_minimal_branch()
 
203
        (out, err) = self.run_bzr_error(
 
204
            ["bzr: ERROR: Requested revision: '1234' "
 
205
             "does not exist in branch:"],
 
206
            ['log', '-r1234'])
148
207
 
149
208
    def test_log_nonexistent_dotted_revno(self):
150
 
        self._prepare()
151
 
        (out, err) = self.run_bzr_error(args="log -r 123.123",
152
 
            error_regexes=["bzr: ERROR: Requested revision: '123.123' "
153
 
                "does not exist in branch:"])
 
209
        self.make_minimal_branch()
 
210
        (out, err) = self.run_bzr_error(
 
211
            ["bzr: ERROR: Requested revision: '123.123' "
 
212
             "does not exist in branch:"],
 
213
            ['log',  '-r123.123'])
154
214
 
155
215
    def test_log_change_revno(self):
156
 
        self._prepare()
 
216
        self.make_linear_branch()
157
217
        expected_log = self.run_bzr("log -r 1")[0]
158
218
        log = self.run_bzr("log -c 1")[0]
159
219
        self.assertEqualDiff(expected_log, log)
160
220
 
161
221
    def test_log_change_nonexistent_revno(self):
162
 
        self._prepare()
163
 
        (out, err) = self.run_bzr_error(args="log -c 1234",
164
 
            error_regexes=["bzr: ERROR: Requested revision: '1234' "
165
 
                "does not exist in branch:"])
 
222
        self.make_minimal_branch()
 
223
        (out, err) = self.run_bzr_error(
 
224
            ["bzr: ERROR: Requested revision: '1234' "
 
225
             "does not exist in branch:"],
 
226
            ['log',  '-c1234'])
166
227
 
167
228
    def test_log_change_nonexistent_dotted_revno(self):
168
 
        self._prepare()
169
 
        (out, err) = self.run_bzr_error(args="log -c 123.123",
170
 
            error_regexes=["bzr: ERROR: Requested revision: '123.123' "
171
 
                "does not exist in branch:"])
 
229
        self.make_minimal_branch()
 
230
        (out, err) = self.run_bzr_error(
 
231
            ["bzr: ERROR: Requested revision: '123.123' "
 
232
             "does not exist in branch:"],
 
233
            ['log', '-c123.123'])
172
234
 
173
 
    def test_log_change_single_revno(self):
174
 
        self._prepare()
175
 
        self.run_bzr_error('bzr: ERROR: Option --change does not'
176
 
                           ' accept revision ranges',
 
235
    def test_log_change_single_revno_only(self):
 
236
        self.make_minimal_branch()
 
237
        self.run_bzr_error(['bzr: ERROR: Option --change does not'
 
238
                           ' accept revision ranges'],
177
239
                           ['log', '--change', '2..3'])
178
240
 
179
241
    def test_log_change_incompatible_with_revision(self):
180
 
        self._prepare()
181
 
        self.run_bzr_error('bzr: ERROR: --revision and --change'
182
 
                           ' are mutually exclusive',
 
242
        self.run_bzr_error(['bzr: ERROR: --revision and --change'
 
243
                           ' are mutually exclusive'],
183
244
                           ['log', '--change', '2', '--revision', '3'])
184
245
 
185
246
    def test_log_nonexistent_file(self):
 
247
        self.make_minimal_branch()
186
248
        # files that don't exist in either the basis tree or working tree
187
249
        # should give an error
188
 
        wt = self.make_branch_and_tree('.')
189
250
        out, err = self.run_bzr('log does-not-exist', retcode=3)
190
 
        self.assertContainsRe(
191
 
            err, 'Path unknown at end or start of revision range: does-not-exist')
 
251
        self.assertContainsRe(err,
 
252
                              'Path unknown at end or start of revision range: '
 
253
                              'does-not-exist')
192
254
 
193
255
    def test_log_with_tags(self):
194
 
        tree = self._prepare(format='dirstate-tags')
 
256
        tree = self.make_linear_branch(format='dirstate-tags')
195
257
        branch = tree.branch
196
258
        branch.tags.set_tag('tag1', branch.get_rev_id(1))
197
259
        branch.tags.set_tag('tag1.1', branch.get_rev_id(1))
206
268
        self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
207
269
 
208
270
    def test_merged_log_with_tags(self):
209
 
        branch1_tree = self._prepare(path='branch1', format='dirstate-tags')
 
271
        branch1_tree = self.make_linear_branch('branch1',
 
272
                                               format='dirstate-tags')
210
273
        branch1 = branch1_tree.branch
211
274
        branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
212
275
        branch1_tree.commit(message='foobar', allow_pointless=True)
213
276
        branch1.tags.set_tag('tag1', branch1.last_revision())
214
 
        os.chdir('branch2')
215
 
        self.run_bzr('merge ../branch1') # tags don't propagate otherwise
 
277
        # tags don't propagate if we don't merge
 
278
        self.run_bzr('merge ../branch1', working_dir='branch2')
216
279
        branch2_tree.commit(message='merge branch 1')
217
 
        log = self.run_bzr("log -r-1")[0]
 
280
        log = self.run_bzr("log -n0 -r-1", working_dir='branch2')[0]
218
281
        self.assertContainsRe(log, r'    tags: tag1')
219
 
        log = self.run_bzr("log -r3.1.1")[0]
 
282
        log = self.run_bzr("log -n0 -r3.1.1", working_dir='branch2')[0]
220
283
        self.assertContainsRe(log, r'tags: tag1')
221
284
 
222
285
    def test_log_limit(self):
237
300
        self.assertContainsRe(log, r'revno: 10\n')
238
301
 
239
302
    def test_log_limit_short(self):
240
 
        self._prepare()
 
303
        self.make_linear_branch()
241
304
        log = self.run_bzr("log -l 2")[0]
242
305
        self.assertNotContainsRe(log, r'revno: 1\n')
243
306
        self.assertContainsRe(log, r'revno: 2\n')
244
307
        self.assertContainsRe(log, r'revno: 3\n')
245
308
 
246
 
 
247
 
class TestLogVerbose(TestCaseWithTransport):
 
309
    def test_log_bad_message_re(self):
 
310
        """Bad --message argument gives a sensible message
 
311
        
 
312
        See https://bugs.launchpad.net/bzr/+bug/251352
 
313
        """
 
314
        self.make_minimal_branch()
 
315
        out, err = self.run_bzr(['log', '-m', '*'], retcode=3)
 
316
        self.assertEqual("bzr: ERROR: Invalid regular expression"
 
317
            " in log message filter"
 
318
            ": '*'"
 
319
            ": nothing to repeat\n", err)
 
320
        self.assertEqual('', out)
 
321
 
 
322
 
 
323
class TestLogTimeZone(TestLog):
 
324
 
 
325
    def test_log_unsupported_timezone(self):
 
326
        self.make_linear_branch()
 
327
        self.run_bzr_error(['bzr: ERROR: Unsupported timezone format "foo", '
 
328
                            'options are "utc", "original", "local".'],
 
329
                           ['log', '--timezone', 'foo'])
 
330
 
 
331
 
 
332
class TestLogVerbose(TestLog):
248
333
 
249
334
    def setUp(self):
250
335
        super(TestLogVerbose, self).setUp()
251
 
        tree = self.make_branch_and_tree('.')
252
 
        self.build_tree(['hello.txt'])
253
 
        tree.add('hello.txt')
254
 
        tree.commit(message='message1')
 
336
        self.make_minimal_branch()
255
337
 
256
338
    def assertUseShortDeltaFormat(self, cmd):
257
339
        log = self.run_bzr(cmd)[0]
282
364
        self.assertUseLongDeltaFormat(['log', '--long', '-vv'])
283
365
 
284
366
 
285
 
class TestLogMerges(TestCaseWithoutPropsHandler):
286
 
 
287
 
    def _prepare(self):
288
 
        parent_tree = self.make_branch_and_tree('parent')
289
 
        parent_tree.commit(message='first post', allow_pointless=True)
290
 
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
291
 
        child_tree.commit(message='branch 1', allow_pointless=True)
292
 
        smaller_tree = \
293
 
                child_tree.bzrdir.sprout('smallerchild').open_workingtree()
294
 
        smaller_tree.commit(message='branch 2', allow_pointless=True)
295
 
        child_tree.merge_from_branch(smaller_tree.branch)
296
 
        child_tree.commit(message='merge branch 2')
297
 
        parent_tree.merge_from_branch(child_tree.branch)
298
 
        parent_tree.commit(message='merge branch 1')
299
 
        os.chdir('parent')
300
 
 
301
 
    def _prepare_short(self):
302
 
        parent_tree = self.make_branch_and_tree('parent')
303
 
        parent_tree.commit(message='first post',
304
 
            timestamp=1132586700, timezone=36000,
305
 
            committer='Joe Foo <joe@foo.com>')
306
 
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
307
 
        child_tree.commit(message='branch 1',
308
 
            timestamp=1132586800, timezone=36000,
309
 
            committer='Joe Foo <joe@foo.com>')
310
 
        smaller_tree = \
311
 
                child_tree.bzrdir.sprout('smallerchild').open_workingtree()
312
 
        smaller_tree.commit(message='branch 2',
313
 
            timestamp=1132586900, timezone=36000,
314
 
            committer='Joe Foo <joe@foo.com>')
315
 
        child_tree.merge_from_branch(smaller_tree.branch)
316
 
        child_tree.commit(message='merge branch 2',
317
 
            timestamp=1132587000, timezone=36000,
318
 
            committer='Joe Foo <joe@foo.com>')
319
 
        parent_tree.merge_from_branch(child_tree.branch)
320
 
        parent_tree.commit(message='merge branch 1',
321
 
            timestamp=1132587100, timezone=36000,
322
 
            committer='Joe Foo <joe@foo.com>')
323
 
        os.chdir('parent')
 
367
class TestLogMerges(TestLog):
 
368
 
 
369
    def setUp(self):
 
370
        super(TestLogMerges, self).setUp()
 
371
        self.make_branches_with_merges()
 
372
 
 
373
    def make_branches_with_merges(self):
 
374
        level0 = self.make_branch_and_tree('level0')
 
375
        level0.commit(message='in branch level0', **self.commit_options())
 
376
 
 
377
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
 
378
        level1.commit(message='in branch level1', **self.commit_options())
 
379
 
 
380
        level2 = level1.bzrdir.sprout('level2').open_workingtree()
 
381
        level2.commit(message='in branch level2', **self.commit_options())
 
382
 
 
383
        level1.merge_from_branch(level2.branch)
 
384
        level1.commit(message='merge branch level2', **self.commit_options())
 
385
 
 
386
        level0.merge_from_branch(level1.branch)
 
387
        level0.commit(message='merge branch level1', **self.commit_options())
324
388
 
325
389
    def test_merges_are_indented_by_level(self):
326
 
        self._prepare()
327
 
        out,err = self.run_bzr('log')
328
 
        self.assertEqual('', err)
329
 
        log = normalize_log(out)
330
 
        self.assertEqualDiff(log, """\
 
390
        expected = """\
331
391
------------------------------------------------------------
332
 
revno: 2
 
392
revno: 2 [merge]
333
393
committer: Lorem Ipsum <test@example.com>
334
 
branch nick: parent
 
394
branch nick: level0
335
395
timestamp: Just now
336
396
message:
337
 
  merge branch 1
 
397
  merge branch level1
338
398
    ------------------------------------------------------------
339
 
    revno: 1.1.2
 
399
    revno: 1.1.2 [merge]
340
400
    committer: Lorem Ipsum <test@example.com>
341
 
    branch nick: child
 
401
    branch nick: level1
342
402
    timestamp: Just now
343
403
    message:
344
 
      merge branch 2
 
404
      merge branch level2
345
405
        ------------------------------------------------------------
346
406
        revno: 1.2.1
347
407
        committer: Lorem Ipsum <test@example.com>
348
 
        branch nick: smallerchild
 
408
        branch nick: level2
349
409
        timestamp: Just now
350
410
        message:
351
 
          branch 2
 
411
          in branch level2
352
412
    ------------------------------------------------------------
353
413
    revno: 1.1.1
354
414
    committer: Lorem Ipsum <test@example.com>
355
 
    branch nick: child
 
415
    branch nick: level1
356
416
    timestamp: Just now
357
417
    message:
358
 
      branch 1
 
418
      in branch level1
359
419
------------------------------------------------------------
360
420
revno: 1
361
421
committer: Lorem Ipsum <test@example.com>
362
 
branch nick: parent
 
422
branch nick: level0
363
423
timestamp: Just now
364
424
message:
365
 
  first post
366
 
""")
 
425
  in branch level0
 
426
"""
 
427
        self.check_log(expected, ['-n0'])
367
428
 
368
429
    def test_force_merge_revisions_off(self):
369
 
        self._prepare()
370
 
        out,err = self.run_bzr('log --long -n1')
371
 
        self.assertEqual('', err)
372
 
        log = normalize_log(out)
373
 
        self.assertEqualDiff(log, """\
 
430
        expected = """\
374
431
------------------------------------------------------------
375
 
revno: 2
 
432
revno: 2 [merge]
376
433
committer: Lorem Ipsum <test@example.com>
377
 
branch nick: parent
 
434
branch nick: level0
378
435
timestamp: Just now
379
436
message:
380
 
  merge branch 1
 
437
  merge branch level1
381
438
------------------------------------------------------------
382
439
revno: 1
383
440
committer: Lorem Ipsum <test@example.com>
384
 
branch nick: parent
 
441
branch nick: level0
385
442
timestamp: Just now
386
443
message:
387
 
  first post
388
 
""")
 
444
  in branch level0
 
445
"""
 
446
        self.check_log(expected, ['--long', '-n1'])
389
447
 
390
448
    def test_force_merge_revisions_on(self):
391
 
        self._prepare_short()
392
 
        out,err = self.run_bzr('log --short -n0')
393
 
        self.assertEqual('', err)
394
 
        log = normalize_log(out)
395
 
        self.assertEqualDiff(log, """\
396
 
    2 Joe Foo\t2005-11-22 [merge]
397
 
      merge branch 1
398
 
 
399
 
          1.1.2 Joe Foo\t2005-11-22 [merge]
400
 
                merge branch 2
401
 
 
402
 
              1.2.1 Joe Foo\t2005-11-22
403
 
                    branch 2
404
 
 
405
 
          1.1.1 Joe Foo\t2005-11-22
406
 
                branch 1
407
 
 
408
 
    1 Joe Foo\t2005-11-22
409
 
      first post
410
 
 
411
 
""")
 
449
        expected = """\
 
450
    2 Lorem Ipsum\t2005-11-22 [merge]
 
451
      merge branch level1
 
452
 
 
453
          1.1.2 Lorem Ipsum\t2005-11-22 [merge]
 
454
                merge branch level2
 
455
 
 
456
              1.2.1 Lorem Ipsum\t2005-11-22
 
457
                    in branch level2
 
458
 
 
459
          1.1.1 Lorem Ipsum\t2005-11-22
 
460
                in branch level1
 
461
 
 
462
    1 Lorem Ipsum\t2005-11-22
 
463
      in branch level0
 
464
 
 
465
"""
 
466
        self.check_log(expected, ['--short', '-n0'])
 
467
 
 
468
    def test_include_merges(self):
 
469
        # Confirm --include-merges gives the same output as -n0
 
470
        out_im, err_im = self.run_bzr('log --include-merges',
 
471
                                      working_dir='level0')
 
472
        out_n0, err_n0 = self.run_bzr('log -n0', working_dir='level0')
 
473
        self.assertEqual('', err_im)
 
474
        self.assertEqual('', err_n0)
 
475
        self.assertEqual(out_im, out_n0)
412
476
 
413
477
    def test_force_merge_revisions_N(self):
414
 
        self._prepare_short()
415
 
        out,err = self.run_bzr('log --short -n2')
416
 
        self.assertEqual('', err)
417
 
        log = normalize_log(out)
418
 
        self.assertEqualDiff(log, """\
419
 
    2 Joe Foo\t2005-11-22 [merge]
420
 
      merge branch 1
421
 
 
422
 
          1.1.2 Joe Foo\t2005-11-22 [merge]
423
 
                merge branch 2
424
 
 
425
 
          1.1.1 Joe Foo\t2005-11-22
426
 
                branch 1
427
 
 
428
 
    1 Joe Foo\t2005-11-22
429
 
      first post
430
 
 
431
 
""")
 
478
        expected = """\
 
479
    2 Lorem Ipsum\t2005-11-22 [merge]
 
480
      merge branch level1
 
481
 
 
482
          1.1.2 Lorem Ipsum\t2005-11-22 [merge]
 
483
                merge branch level2
 
484
 
 
485
          1.1.1 Lorem Ipsum\t2005-11-22
 
486
                in branch level1
 
487
 
 
488
    1 Lorem Ipsum\t2005-11-22
 
489
      in branch level0
 
490
 
 
491
"""
 
492
        self.check_log(expected, ['--short', '-n2'])
432
493
 
433
494
    def test_merges_single_merge_rev(self):
434
 
        self._prepare()
435
 
        out,err = self.run_bzr('log -r1.1.2')
436
 
        self.assertEqual('', err)
437
 
        log = normalize_log(out)
438
 
        self.assertEqualDiff(log, """\
 
495
        expected = """\
439
496
------------------------------------------------------------
440
 
revno: 1.1.2
 
497
revno: 1.1.2 [merge]
441
498
committer: Lorem Ipsum <test@example.com>
442
 
branch nick: child
 
499
branch nick: level1
443
500
timestamp: Just now
444
501
message:
445
 
  merge branch 2
 
502
  merge branch level2
446
503
    ------------------------------------------------------------
447
504
    revno: 1.2.1
448
505
    committer: Lorem Ipsum <test@example.com>
449
 
    branch nick: smallerchild
 
506
    branch nick: level2
450
507
    timestamp: Just now
451
508
    message:
452
 
      branch 2
453
 
""")
 
509
      in branch level2
 
510
"""
 
511
        self.check_log(expected, ['-n0', '-r1.1.2'])
454
512
 
455
513
    def test_merges_partial_range(self):
456
 
        self._prepare()
457
 
        out, err = self.run_bzr('log -r1.1.1..1.1.2')
458
 
        self.assertEqual('', err)
459
 
        log = normalize_log(out)
460
 
        self.assertEqualDiff(log, """\
 
514
        expected = """\
461
515
------------------------------------------------------------
462
 
revno: 1.1.2
 
516
revno: 1.1.2 [merge]
463
517
committer: Lorem Ipsum <test@example.com>
464
 
branch nick: child
 
518
branch nick: level1
465
519
timestamp: Just now
466
520
message:
467
 
  merge branch 2
 
521
  merge branch level2
468
522
    ------------------------------------------------------------
469
523
    revno: 1.2.1
470
524
    committer: Lorem Ipsum <test@example.com>
471
 
    branch nick: smallerchild
 
525
    branch nick: level2
472
526
    timestamp: Just now
473
527
    message:
474
 
      branch 2
 
528
      in branch level2
475
529
------------------------------------------------------------
476
530
revno: 1.1.1
477
531
committer: Lorem Ipsum <test@example.com>
478
 
branch nick: child
 
532
branch nick: level1
479
533
timestamp: Just now
480
534
message:
481
 
  branch 1
482
 
""")
483
 
 
484
 
    def test_merges_nonsupporting_formatter(self):
485
 
        # This "feature" of log formatters is madness. If a log
486
 
        # formatter cannot display a dotted-revno, it ought to ignore it.
487
 
        # Otherwise, a linear sequence is always expected to be handled now.
488
 
        raise KnownFailure('log formatters must support linear sequences now')
489
 
        self._prepare()
490
 
        err_msg = 'Selected log formatter only supports mainline revisions.'
491
 
        # The single revision case is tested in the core tests
492
 
        # since all standard formatters support single merge revisions.
493
 
        out,err = self.run_bzr('log --short -r1..1.1.2', retcode=3)
494
 
        self.assertContainsRe(err, err_msg)
495
 
        out,err = self.run_bzr('log --short -r1.1.1..1.1.2', retcode=3)
496
 
        self.assertContainsRe(err, err_msg)
497
 
 
498
 
 
499
 
def subst_dates(string):
500
 
    """Replace date strings with constant values."""
501
 
    return re.sub(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-\+]\d{4}',
502
 
                  'YYYY-MM-DD HH:MM:SS +ZZZZ', string)
503
 
 
504
 
 
505
 
class TestLogDiff(TestCaseWithoutPropsHandler):
506
 
 
507
 
    def _prepare(self):
508
 
        parent_tree = self.make_branch_and_tree('parent')
509
 
        self.build_tree(['parent/file1', 'parent/file2'])
510
 
        parent_tree.add('file1')
511
 
        parent_tree.add('file2')
512
 
        parent_tree.commit(message='first post',
513
 
            timestamp=1132586655, timezone=36000,
514
 
            committer='Lorem Ipsum <test@example.com>')
515
 
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
516
 
        self.build_tree_contents([('child/file2', 'hello\n')])
517
 
        child_tree.commit(message='branch 1',
518
 
            timestamp=1132586700, timezone=36000,
519
 
            committer='Lorem Ipsum <test@example.com>')
520
 
        parent_tree.merge_from_branch(child_tree.branch)
521
 
        parent_tree.commit(message='merge branch 1',
522
 
            timestamp=1132586800, timezone=36000,
523
 
            committer='Lorem Ipsum <test@example.com>')
524
 
        os.chdir('parent')
525
 
 
526
 
    def test_log_show_diff_long(self):
527
 
        self._prepare()
528
 
        out,err = self.run_bzr('log -p')
 
535
  in branch level1
 
536
"""
 
537
        self.check_log(expected, ['-n0', '-r1.1.1..1.1.2'])
 
538
 
 
539
 
 
540
class TestLogDiff(TestLog):
 
541
 
 
542
    def setUp(self):
 
543
        super(TestLogDiff, self).setUp()
 
544
        self.make_branch_with_diffs()
 
545
 
 
546
    def make_branch_with_diffs(self):
 
547
        level0 = self.make_branch_and_tree('level0')
 
548
        self.build_tree(['level0/file1', 'level0/file2'])
 
549
        level0.add('file1')
 
550
        level0.add('file2')
 
551
        level0.commit(message='in branch level0', **self.commit_options())
 
552
 
 
553
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
 
554
        self.build_tree_contents([('level1/file2', 'hello\n')])
 
555
        level1.commit(message='in branch level1', **self.commit_options())
 
556
        level0.merge_from_branch(level1.branch)
 
557
        level0.commit(message='merge branch level1', **self.commit_options())
 
558
 
 
559
    def test_log_show_diff_long_with_merges(self):
 
560
        out,err = self.run_bzr('log -p -n0')
529
561
        self.assertEqual('', err)
530
 
        log = normalize_log(out)
531
 
        self.assertEqualDiff(subst_dates(log), """\
 
562
        log = test_log.normalize_log(out)
 
563
        expected = """\
532
564
------------------------------------------------------------
533
 
revno: 2
 
565
revno: 2 [merge]
534
566
committer: Lorem Ipsum <test@example.com>
535
 
branch nick: parent
 
567
branch nick: level0
536
568
timestamp: Just now
537
569
message:
538
 
  merge branch 1
 
570
  merge branch level1
539
571
diff:
540
572
=== modified file 'file2'
541
 
--- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
542
 
+++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
573
--- file2\t2005-11-22 00:00:01 +0000
 
574
+++ file2\t2005-11-22 00:00:02 +0000
543
575
@@ -1,1 +1,1 @@
544
 
-contents of parent/file2
 
576
-contents of level0/file2
545
577
+hello
546
578
    ------------------------------------------------------------
547
579
    revno: 1.1.1
548
580
    committer: Lorem Ipsum <test@example.com>
549
 
    branch nick: child
 
581
    branch nick: level1
550
582
    timestamp: Just now
551
583
    message:
552
 
      branch 1
 
584
      in branch level1
553
585
    diff:
554
586
    === modified file 'file2'
555
 
    --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
556
 
    +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
587
    --- file2\t2005-11-22 00:00:01 +0000
 
588
    +++ file2\t2005-11-22 00:00:02 +0000
557
589
    @@ -1,1 +1,1 @@
558
 
    -contents of parent/file2
 
590
    -contents of level0/file2
559
591
    +hello
560
592
------------------------------------------------------------
561
593
revno: 1
562
594
committer: Lorem Ipsum <test@example.com>
563
 
branch nick: parent
 
595
branch nick: level0
564
596
timestamp: Just now
565
597
message:
566
 
  first post
 
598
  in branch level0
567
599
diff:
568
600
=== added file 'file1'
569
 
--- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
570
 
+++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
601
--- file1\t1970-01-01 00:00:00 +0000
 
602
+++ file1\t2005-11-22 00:00:01 +0000
571
603
@@ -0,0 +1,1 @@
572
 
+contents of parent/file1
 
604
+contents of level0/file1
573
605
 
574
606
=== added file 'file2'
575
 
--- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
576
 
+++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
607
--- file2\t1970-01-01 00:00:00 +0000
 
608
+++ file2\t2005-11-22 00:00:01 +0000
577
609
@@ -0,0 +1,1 @@
578
 
+contents of parent/file2
579
 
""")
 
610
+contents of level0/file2
 
611
"""
 
612
        self.check_log(expected, ['-p', '-n0'])
580
613
 
581
614
    def test_log_show_diff_short(self):
582
 
        self._prepare()
583
 
        out,err = self.run_bzr('log -p --short')
584
 
        self.assertEqual('', err)
585
 
        log = normalize_log(out)
586
 
        self.assertEqualDiff(subst_dates(log), """\
 
615
        expected = """\
587
616
    2 Lorem Ipsum\t2005-11-22 [merge]
588
 
      merge branch 1
 
617
      merge branch level1
589
618
      === modified file 'file2'
590
 
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
591
 
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
619
      --- file2\t2005-11-22 00:00:01 +0000
 
620
      +++ file2\t2005-11-22 00:00:02 +0000
592
621
      @@ -1,1 +1,1 @@
593
 
      -contents of parent/file2
 
622
      -contents of level0/file2
594
623
      +hello
595
624
 
596
625
    1 Lorem Ipsum\t2005-11-22
597
 
      first post
 
626
      in branch level0
598
627
      === added file 'file1'
599
 
      --- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
600
 
      +++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
628
      --- file1\t1970-01-01 00:00:00 +0000
 
629
      +++ file1\t2005-11-22 00:00:01 +0000
601
630
      @@ -0,0 +1,1 @@
602
 
      +contents of parent/file1
 
631
      +contents of level0/file1
603
632
\x20\x20\x20\x20\x20\x20
604
633
      === added file 'file2'
605
 
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
606
 
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
634
      --- file2\t1970-01-01 00:00:00 +0000
 
635
      +++ file2\t2005-11-22 00:00:01 +0000
607
636
      @@ -0,0 +1,1 @@
608
 
      +contents of parent/file2
 
637
      +contents of level0/file2
609
638
 
610
 
""")
 
639
Use --include-merges or -n0 to see merged revisions.
 
640
"""
 
641
        self.check_log(expected, ['-p', '--short'])
611
642
 
612
643
    def test_log_show_diff_line(self):
613
 
        self._prepare()
 
644
        # Not supported by this formatter so expect plain output
 
645
        expected = """\
 
646
2: Lorem Ipsum 2005-11-22 [merge] merge branch level1
 
647
1: Lorem Ipsum 2005-11-22 in branch level0
 
648
"""
 
649
        self.check_log(expected, ['-p', '--line'])
 
650
 
 
651
    def test_log_show_diff_file1(self):
 
652
        """Only the diffs for the given file are to be shown"""
 
653
        expected = """\
 
654
    1 Lorem Ipsum\t2005-11-22
 
655
      in branch level0
 
656
      === added file 'file1'
 
657
      --- file1\t1970-01-01 00:00:00 +0000
 
658
      +++ file1\t2005-11-22 00:00:01 +0000
 
659
      @@ -0,0 +1,1 @@
 
660
      +contents of level0/file1
 
661
 
 
662
"""
 
663
        self.check_log(expected, ['-p', '--short', 'file1'])
 
664
 
 
665
    def test_log_show_diff_file2(self):
 
666
        """Only the diffs for the given file are to be shown"""
 
667
        expected = """\
 
668
    2 Lorem Ipsum\t2005-11-22 [merge]
 
669
      merge branch level1
 
670
      === modified file 'file2'
 
671
      --- file2\t2005-11-22 00:00:01 +0000
 
672
      +++ file2\t2005-11-22 00:00:02 +0000
 
673
      @@ -1,1 +1,1 @@
 
674
      -contents of level0/file2
 
675
      +hello
 
676
 
 
677
    1 Lorem Ipsum\t2005-11-22
 
678
      in branch level0
 
679
      === added file 'file2'
 
680
      --- file2\t1970-01-01 00:00:00 +0000
 
681
      +++ file2\t2005-11-22 00:00:01 +0000
 
682
      @@ -0,0 +1,1 @@
 
683
      +contents of level0/file2
 
684
 
 
685
Use --include-merges or -n0 to see merged revisions.
 
686
"""
 
687
        self.check_log(expected, ['-p', '--short', 'file2'])
 
688
 
 
689
 
 
690
class TestLogUnicodeDiff(TestLog):
 
691
 
 
692
    def test_log_show_diff_non_ascii(self):
 
693
        # Smoke test for bug #328007 UnicodeDecodeError on 'log -p'
 
694
        message = u'Message with \xb5'
 
695
        body = 'Body with \xb5\n'
 
696
        wt = self.make_branch_and_tree('.')
 
697
        self.build_tree_contents([('foo', body)])
 
698
        wt.add('foo')
 
699
        wt.commit(message=message)
 
700
        # check that command won't fail with unicode error
 
701
        # don't care about exact output because we have other tests for this
 
702
        out,err = self.run_bzr('log -p --long')
 
703
        self.assertNotEqual('', out)
 
704
        self.assertEqual('', err)
 
705
        out,err = self.run_bzr('log -p --short')
 
706
        self.assertNotEqual('', out)
 
707
        self.assertEqual('', err)
614
708
        out,err = self.run_bzr('log -p --line')
615
 
        self.assertEqual('', err)
616
 
        log = normalize_log(out)
617
 
        # Not supported by this formatter so expect plain output
618
 
        self.assertEqualDiff(subst_dates(log), """\
619
 
2: Lorem Ipsum 2005-11-22 [merge] merge branch 1
620
 
1: Lorem Ipsum 2005-11-22 first post
621
 
""")
622
 
 
623
 
    def test_log_show_diff_file(self):
624
 
        """Only the diffs for the given file are to be shown"""
625
 
        self._prepare()
626
 
        out,err = self.run_bzr('log -p --short file2')
627
 
        self.assertEqual('', err)
628
 
        log = normalize_log(out)
629
 
        self.assertEqualDiff(subst_dates(log), """\
630
 
    2 Lorem Ipsum\t2005-11-22 [merge]
631
 
      merge branch 1
632
 
      === modified file 'file2'
633
 
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
634
 
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
635
 
      @@ -1,1 +1,1 @@
636
 
      -contents of parent/file2
637
 
      +hello
638
 
 
639
 
    1 Lorem Ipsum\t2005-11-22
640
 
      first post
641
 
      === added file 'file2'
642
 
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
643
 
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
644
 
      @@ -0,0 +1,1 @@
645
 
      +contents of parent/file2
646
 
 
647
 
""")
648
 
        out,err = self.run_bzr('log -p --short file1')
649
 
        self.assertEqual('', err)
650
 
        log = normalize_log(out)
651
 
        self.assertEqualDiff(subst_dates(log), """\
652
 
    1 Lorem Ipsum\t2005-11-22
653
 
      first post
654
 
      === added file 'file1'
655
 
      --- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
656
 
      +++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
657
 
      @@ -0,0 +1,1 @@
658
 
      +contents of parent/file1
659
 
 
660
 
""")
661
 
 
662
 
 
663
 
class TestLogEncodings(TestCaseInTempDir):
 
709
        self.assertNotEqual('', out)
 
710
        self.assertEqual('', err)
 
711
 
 
712
 
 
713
class TestLogEncodings(tests.TestCaseInTempDir):
664
714
 
665
715
    _mu = u'\xb5'
666
716
    _message = u'Message with \xb5'
671
721
        'latin-1',
672
722
        'iso-8859-1',
673
723
        'cp437', # Common windows encoding
674
 
        'cp1251', # Alexander Belchenko's windows encoding
 
724
        'cp1251', # Russian windows encoding
675
725
        'cp1258', # Common windows encoding
676
726
    ]
677
727
    # Encodings which cannot encode mu
682
732
    ]
683
733
 
684
734
    def setUp(self):
685
 
        TestCaseInTempDir.setUp(self)
 
735
        super(TestLogEncodings, self).setUp()
686
736
        self.user_encoding = osutils._cached_user_encoding
687
 
 
688
 
    def tearDown(self):
689
 
        osutils._cached_user_encoding = self.user_encoding
690
 
        TestCaseInTempDir.tearDown(self)
 
737
        def restore():
 
738
            osutils._cached_user_encoding = self.user_encoding
 
739
        self.addCleanup(restore)
691
740
 
692
741
    def create_branch(self):
693
742
        bzr = self.run_bzr
761
810
        self.assertEquals(-1, stdout.find(test_in_cp1251))
762
811
 
763
812
 
764
 
class TestLogFile(TestCaseWithTransport):
 
813
class TestLogFile(tests.TestCaseWithTransport):
765
814
 
766
815
    def test_log_local_branch_file(self):
767
816
        """We should be able to log files in local treeless branches"""
799
848
    def test_log_file(self):
800
849
        """The log for a particular file should only list revs for that file"""
801
850
        self.prepare_tree()
802
 
        log = self.run_bzr('log file1')[0]
 
851
        log = self.run_bzr('log -n0 file1')[0]
803
852
        self.assertContainsRe(log, 'revno: 1\n')
804
853
        self.assertNotContainsRe(log, 'revno: 2\n')
805
854
        self.assertNotContainsRe(log, 'revno: 3\n')
806
855
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
807
 
        self.assertNotContainsRe(log, 'revno: 4\n')
808
 
        log = self.run_bzr('log file2')[0]
 
856
        self.assertNotContainsRe(log, 'revno: 4 ')
 
857
        log = self.run_bzr('log -n0 file2')[0]
809
858
        self.assertNotContainsRe(log, 'revno: 1\n')
810
859
        self.assertContainsRe(log, 'revno: 2\n')
811
860
        self.assertNotContainsRe(log, 'revno: 3\n')
812
861
        self.assertContainsRe(log, 'revno: 3.1.1\n')
813
 
        self.assertContainsRe(log, 'revno: 4\n')
814
 
        log = self.run_bzr('log file3')[0]
 
862
        self.assertContainsRe(log, 'revno: 4 ')
 
863
        log = self.run_bzr('log -n0 file3')[0]
815
864
        self.assertNotContainsRe(log, 'revno: 1\n')
816
865
        self.assertNotContainsRe(log, 'revno: 2\n')
817
866
        self.assertContainsRe(log, 'revno: 3\n')
818
867
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
819
 
        self.assertNotContainsRe(log, 'revno: 4\n')
820
 
        log = self.run_bzr('log -r3.1.1 file2')[0]
821
 
        self.assertNotContainsRe(log, 'revno: 1\n')
822
 
        self.assertNotContainsRe(log, 'revno: 2\n')
823
 
        self.assertNotContainsRe(log, 'revno: 3\n')
824
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
825
 
        self.assertNotContainsRe(log, 'revno: 4\n')
826
 
        log = self.run_bzr('log -r4 file2')[0]
827
 
        self.assertNotContainsRe(log, 'revno: 1\n')
828
 
        self.assertNotContainsRe(log, 'revno: 2\n')
829
 
        self.assertNotContainsRe(log, 'revno: 3\n')
830
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
831
 
        self.assertContainsRe(log, 'revno: 4\n')
832
 
        log = self.run_bzr('log -r3.. file2')[0]
833
 
        self.assertNotContainsRe(log, 'revno: 1\n')
834
 
        self.assertNotContainsRe(log, 'revno: 2\n')
835
 
        self.assertNotContainsRe(log, 'revno: 3\n')
836
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
837
 
        self.assertContainsRe(log, 'revno: 4\n')
838
 
        log = self.run_bzr('log -r..3 file2')[0]
 
868
        self.assertNotContainsRe(log, 'revno: 4 ')
 
869
        log = self.run_bzr('log -n0 -r3.1.1 file2')[0]
 
870
        self.assertNotContainsRe(log, 'revno: 1\n')
 
871
        self.assertNotContainsRe(log, 'revno: 2\n')
 
872
        self.assertNotContainsRe(log, 'revno: 3\n')
 
873
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
874
        self.assertNotContainsRe(log, 'revno: 4 ')
 
875
        log = self.run_bzr('log -n0 -r4 file2')[0]
 
876
        self.assertNotContainsRe(log, 'revno: 1\n')
 
877
        self.assertNotContainsRe(log, 'revno: 2\n')
 
878
        self.assertNotContainsRe(log, 'revno: 3\n')
 
879
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
880
        self.assertContainsRe(log, 'revno: 4 ')
 
881
        log = self.run_bzr('log -n0 -r3.. file2')[0]
 
882
        self.assertNotContainsRe(log, 'revno: 1\n')
 
883
        self.assertNotContainsRe(log, 'revno: 2\n')
 
884
        self.assertNotContainsRe(log, 'revno: 3\n')
 
885
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
886
        self.assertContainsRe(log, 'revno: 4 ')
 
887
        log = self.run_bzr('log -n0 -r..3 file2')[0]
839
888
        self.assertNotContainsRe(log, 'revno: 1\n')
840
889
        self.assertContainsRe(log, 'revno: 2\n')
841
890
        self.assertNotContainsRe(log, 'revno: 3\n')
842
891
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
843
 
        self.assertNotContainsRe(log, 'revno: 4\n')
 
892
        self.assertNotContainsRe(log, 'revno: 4 ')
844
893
 
845
894
    def test_log_file_historical_missing(self):
846
895
        # Check logging a deleted file gives an error if the
854
903
        # Check logging a deleted file is ok if the file existed
855
904
        # at the end the revision range
856
905
        self.prepare_tree(complex=True)
857
 
        log, err = self.run_bzr('log -r..4 file2')
 
906
        log, err = self.run_bzr('log -n0 -r..4 file2')
858
907
        self.assertEquals('', err)
859
908
        self.assertNotContainsRe(log, 'revno: 1\n')
860
909
        self.assertContainsRe(log, 'revno: 2\n')
861
910
        self.assertNotContainsRe(log, 'revno: 3\n')
862
911
        self.assertContainsRe(log, 'revno: 3.1.1\n')
863
 
        self.assertContainsRe(log, 'revno: 4\n')
 
912
        self.assertContainsRe(log, 'revno: 4 ')
864
913
 
865
914
    def test_log_file_historical_start(self):
866
915
        # Check logging a deleted file is ok if the file existed
872
921
        self.assertNotContainsRe(log, 'revno: 2\n')
873
922
        self.assertNotContainsRe(log, 'revno: 3\n')
874
923
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
875
 
        self.assertNotContainsRe(log, 'revno: 4\n')
 
924
        self.assertNotContainsRe(log, 'revno: 4 ')
876
925
 
877
926
    def test_log_file_renamed(self):
878
927
        """File matched against revision range, not current tree."""
890
939
        self.assertNotContainsRe(log, 'revno: 2\n')
891
940
        self.assertContainsRe(log, 'revno: 3\n')
892
941
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
893
 
        self.assertNotContainsRe(log, 'revno: 4\n')
 
942
        self.assertNotContainsRe(log, 'revno: 4 ')
894
943
 
895
944
    def test_line_log_file(self):
896
945
        """The line log for a file should only list relevant mainline revs"""
954
1003
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
955
1004
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
956
1005
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
 
1006
 
 
1007
 
 
1008
class TestLogMultiple(tests.TestCaseWithTransport):
 
1009
 
 
1010
    def prepare_tree(self):
 
1011
        tree = self.make_branch_and_tree('parent')
 
1012
        self.build_tree([
 
1013
            'parent/file1',
 
1014
            'parent/file2',
 
1015
            'parent/dir1/',
 
1016
            'parent/dir1/file5',
 
1017
            'parent/dir1/dir2/',
 
1018
            'parent/dir1/dir2/file3',
 
1019
            'parent/file4'])
 
1020
        tree.add('file1')
 
1021
        tree.commit('add file1')
 
1022
        tree.add('file2')
 
1023
        tree.commit('add file2')
 
1024
        tree.add(['dir1', 'dir1/dir2', 'dir1/dir2/file3'])
 
1025
        tree.commit('add file3')
 
1026
        tree.add('file4')
 
1027
        tree.commit('add file4')
 
1028
        tree.add('dir1/file5')
 
1029
        tree.commit('add file5')
 
1030
        child_tree = tree.bzrdir.sprout('child').open_workingtree()
 
1031
        self.build_tree_contents([('child/file2', 'hello')])
 
1032
        child_tree.commit(message='branch 1')
 
1033
        tree.merge_from_branch(child_tree.branch)
 
1034
        tree.commit(message='merge child branch')
 
1035
        os.chdir('parent')
 
1036
 
 
1037
    def assertRevnos(self, paths_str, expected_revnos):
 
1038
        # confirm the revision numbers in log --line output are those expected
 
1039
        out, err = self.run_bzr('log --line -n0 %s' % (paths_str,))
 
1040
        self.assertEqual('', err)
 
1041
        revnos = [s.split(':', 1)[0].lstrip() for s in out.splitlines()]
 
1042
        self.assertEqual(expected_revnos, revnos)
 
1043
 
 
1044
    def test_log_files(self):
 
1045
        """The log for multiple file should only list revs for those files"""
 
1046
        self.prepare_tree()
 
1047
        self.assertRevnos('file1 file2 dir1/dir2/file3',
 
1048
            ['6', '5.1.1', '3', '2', '1'])
 
1049
 
 
1050
    def test_log_directory(self):
 
1051
        """The log for a directory should show all nested files."""
 
1052
        self.prepare_tree()
 
1053
        self.assertRevnos('dir1', ['5', '3'])
 
1054
 
 
1055
    def test_log_nested_directory(self):
 
1056
        """The log for a directory should show all nested files."""
 
1057
        self.prepare_tree()
 
1058
        self.assertRevnos('dir1/dir2', ['3'])
 
1059
 
 
1060
    def test_log_in_nested_directory(self):
 
1061
        """The log for a directory should show all nested files."""
 
1062
        self.prepare_tree()
 
1063
        os.chdir("dir1")
 
1064
        self.assertRevnos('.', ['5', '3'])
 
1065
 
 
1066
    def test_log_files_and_directories(self):
 
1067
        """Logging files and directories together should be fine."""
 
1068
        self.prepare_tree()
 
1069
        self.assertRevnos('file4 dir1/dir2', ['4', '3'])
 
1070
 
 
1071
    def test_log_files_and_dirs_in_nested_directory(self):
 
1072
        """The log for a directory should show all nested files."""
 
1073
        self.prepare_tree()
 
1074
        os.chdir("dir1")
 
1075
        self.assertRevnos('dir2 file5', ['5', '3'])