~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: John Arbash Meinel
  • Date: 2008-09-05 02:29:34 UTC
  • mto: (3697.7.4 1.7)
  • mto: This revision was merged to the branch mainline in revision 3748.
  • Revision ID: john@arbash-meinel.com-20080905022934-s8692mbwpkdwi106
Cleanups to the algorithm documentation.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2009 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
2
# -*- coding: utf-8 -*-
2
3
#
3
4
# This program is free software; you can redistribute it and/or modify
4
5
# it under the terms of the GNU General Public License as published by
12
13
#
13
14
# You should have received a copy of the GNU General Public License
14
15
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
 
17
18
 
18
19
"""Black-box tests for bzr log."""
19
20
 
20
21
import os
21
 
import re
22
22
 
23
 
from bzrlib import (
24
 
    osutils,
25
 
    tests,
 
23
import bzrlib
 
24
from bzrlib.tests.blackbox import ExternalBase
 
25
from bzrlib.tests import TestCaseInTempDir, TestCaseWithTransport
 
26
from bzrlib.tests.test_log import (
 
27
    normalize_log,
26
28
    )
27
29
from bzrlib.tests import test_log
28
30
 
29
31
 
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):
 
32
class TestCaseWithoutPropsHandler(ExternalBase, test_log.TestCaseWithoutPropsHandler):
 
33
    pass
 
34
 
 
35
 
 
36
class TestLog(ExternalBase):
 
37
 
 
38
    def _prepare(self, path='.', format=None):
45
39
        tree = self.make_branch_and_tree(path, format=format)
46
40
        self.build_tree(
47
41
            [path + '/hello.txt', path + '/goodbye.txt', path + '/meep.txt'])
51
45
        tree.commit(message='message2')
52
46
        tree.add('meep.txt')
53
47
        tree.commit(message='message3')
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):
 
48
        self.full_log = self.run_bzr(["log", path])[0]
 
49
        return tree
95
50
 
96
51
    def test_log_null_end_revspec(self):
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)
 
52
        self._prepare()
 
53
        self.assertTrue('revno: 1\n' in self.full_log)
 
54
        self.assertTrue('revno: 2\n' in self.full_log)
 
55
        self.assertTrue('revno: 3\n' in self.full_log)
 
56
        self.assertTrue('message:\n  message1\n' in self.full_log)
 
57
        self.assertTrue('message:\n  message2\n' in self.full_log)
 
58
        self.assertTrue('message:\n  message3\n' in self.full_log)
105
59
 
106
 
        full_log = self.run_bzr(['log'])[0]
107
60
        log = self.run_bzr("log -r 1..")[0]
108
 
        self.assertEqualDiff(log, full_log)
 
61
        self.assertEqualDiff(log, self.full_log)
109
62
 
110
63
    def test_log_null_begin_revspec(self):
111
 
        self.make_linear_branch()
112
 
        full_log = self.run_bzr(['log'])[0]
 
64
        self._prepare()
113
65
        log = self.run_bzr("log -r ..3")[0]
114
 
        self.assertEqualDiff(full_log, log)
 
66
        self.assertEqualDiff(self.full_log, log)
115
67
 
116
68
    def test_log_null_both_revspecs(self):
117
 
        self.make_linear_branch()
118
 
        full_log = self.run_bzr(['log'])[0]
 
69
        self._prepare()
119
70
        log = self.run_bzr("log -r ..")[0]
120
 
        self.assertEqualDiff(full_log, log)
 
71
        self.assertEqualDiff(self.full_log, log)
121
72
 
122
73
    def test_log_zero_revspec(self):
123
 
        self.make_minimal_branch()
124
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
74
        self._prepare()
 
75
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
125
76
                           ['log', '-r0'])
126
77
 
127
78
    def test_log_zero_begin_revspec(self):
128
 
        self.make_linear_branch()
129
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
79
        self._prepare()
 
80
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
130
81
                           ['log', '-r0..2'])
131
82
 
132
83
    def test_log_zero_end_revspec(self):
133
 
        self.make_linear_branch()
134
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
84
        self._prepare()
 
85
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
135
86
                           ['log', '-r-2..0'])
136
87
 
 
88
    def test_log_unsupported_timezone(self):
 
89
        self._prepare()
 
90
        self.run_bzr_error('bzr: ERROR: Unsupported timezone format "foo", '
 
91
                           'options are "utc", "original", "local".',
 
92
                           ['log', '--timezone', 'foo'])
 
93
 
137
94
    def test_log_negative_begin_revspec_full_log(self):
138
 
        self.make_linear_branch()
139
 
        full_log = self.run_bzr(['log'])[0]
 
95
        self._prepare()
140
96
        log = self.run_bzr("log -r -3..")[0]
141
 
        self.assertEqualDiff(full_log, log)
 
97
        self.assertEqualDiff(self.full_log, log)
142
98
 
143
99
    def test_log_negative_both_revspec_full_log(self):
144
 
        self.make_linear_branch()
145
 
        full_log = self.run_bzr(['log'])[0]
 
100
        self._prepare()
146
101
        log = self.run_bzr("log -r -3..-1")[0]
147
 
        self.assertEqualDiff(full_log, log)
 
102
        self.assertEqualDiff(self.full_log, log)
148
103
 
149
104
    def test_log_negative_both_revspec_partial(self):
150
 
        self.make_linear_branch()
 
105
        self._prepare()
151
106
        log = self.run_bzr("log -r -3..-2")[0]
152
107
        self.assertTrue('revno: 1\n' in log)
153
108
        self.assertTrue('revno: 2\n' in log)
154
109
        self.assertTrue('revno: 3\n' not in log)
155
110
 
156
111
    def test_log_negative_begin_revspec(self):
157
 
        self.make_linear_branch()
 
112
        self._prepare()
158
113
        log = self.run_bzr("log -r -2..")[0]
159
114
        self.assertTrue('revno: 1\n' not in log)
160
115
        self.assertTrue('revno: 2\n' in log)
161
116
        self.assertTrue('revno: 3\n' in log)
162
117
 
163
118
    def test_log_positive_revspecs(self):
164
 
        self.make_linear_branch()
165
 
        full_log = self.run_bzr(['log'])[0]
 
119
        self._prepare()
166
120
        log = self.run_bzr("log -r 1..3")[0]
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))
 
121
        self.assertEqualDiff(self.full_log, log)
173
122
 
174
123
    def test_log_reversed_revspecs(self):
175
 
        self.make_linear_branch()
 
124
        self._prepare()
176
125
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
177
126
                            'the end revision.\n',),
178
127
                           ['log', '-r3..1'])
179
128
 
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
 
 
186
129
    def test_log_revno_n_path(self):
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
 
130
        self._prepare(path='branch1')
 
131
        self._prepare(path='branch2')
 
132
        log = self.run_bzr("log -r revno:2:branch1..revno:3:branch2",
 
133
                          retcode=3)[0]
192
134
        log = self.run_bzr("log -r revno:1:branch2..revno:3:branch2")[0]
193
 
        full_log = self.run_bzr(['log'], working_dir='branch2')[0]
194
 
        self.assertEqualDiff(full_log, log)
 
135
        self.assertEqualDiff(self.full_log, log)
195
136
        log = self.run_bzr("log -r revno:1:branch2")[0]
196
137
        self.assertTrue('revno: 1\n' in log)
197
138
        self.assertTrue('revno: 2\n' not in log)
198
139
        self.assertTrue('branch nick: branch2\n' in log)
199
140
        self.assertTrue('branch nick: branch1\n' not in log)
200
 
 
201
 
    def test_log_nonexistent_revno(self):
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'])
207
 
 
208
 
    def test_log_nonexistent_dotted_revno(self):
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'])
214
 
 
215
 
    def test_log_change_revno(self):
216
 
        self.make_linear_branch()
217
 
        expected_log = self.run_bzr("log -r 1")[0]
218
 
        log = self.run_bzr("log -c 1")[0]
219
 
        self.assertEqualDiff(expected_log, log)
220
 
 
221
 
    def test_log_change_nonexistent_revno(self):
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'])
227
 
 
228
 
    def test_log_change_nonexistent_dotted_revno(self):
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'])
234
 
 
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'],
239
 
                           ['log', '--change', '2..3'])
240
 
 
241
 
    def test_log_change_incompatible_with_revision(self):
242
 
        self.run_bzr_error(['bzr: ERROR: --revision and --change'
243
 
                           ' are mutually exclusive'],
244
 
                           ['log', '--change', '2', '--revision', '3'])
245
 
 
 
141
        
246
142
    def test_log_nonexistent_file(self):
247
 
        self.make_minimal_branch()
248
143
        # files that don't exist in either the basis tree or working tree
249
144
        # should give an error
 
145
        wt = self.make_branch_and_tree('.')
250
146
        out, err = self.run_bzr('log does-not-exist', retcode=3)
251
 
        self.assertContainsRe(err,
252
 
                              'Path unknown at end or start of revision range: '
253
 
                              'does-not-exist')
 
147
        self.assertContainsRe(
 
148
            err, 'Path does not have any revision history: does-not-exist')
254
149
 
255
150
    def test_log_with_tags(self):
256
 
        tree = self.make_linear_branch(format='dirstate-tags')
 
151
        tree = self._prepare(format='dirstate-tags')
257
152
        branch = tree.branch
258
153
        branch.tags.set_tag('tag1', branch.get_rev_id(1))
259
154
        branch.tags.set_tag('tag1.1', branch.get_rev_id(1))
260
 
        branch.tags.set_tag('tag3', branch.last_revision())
261
 
 
 
155
        branch.tags.set_tag('tag3', branch.last_revision()) 
 
156
        
262
157
        log = self.run_bzr("log -r-1")[0]
263
158
        self.assertTrue('tags: tag3' in log)
264
159
 
268
163
        self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
269
164
 
270
165
    def test_merged_log_with_tags(self):
271
 
        branch1_tree = self.make_linear_branch('branch1',
272
 
                                               format='dirstate-tags')
 
166
        branch1_tree = self._prepare(path='branch1', format='dirstate-tags')
273
167
        branch1 = branch1_tree.branch
274
168
        branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
275
169
        branch1_tree.commit(message='foobar', allow_pointless=True)
276
170
        branch1.tags.set_tag('tag1', branch1.last_revision())
277
 
        # tags don't propagate if we don't merge
278
 
        self.run_bzr('merge ../branch1', working_dir='branch2')
 
171
        os.chdir('branch2')
 
172
        self.run_bzr('merge ../branch1') # tags don't propagate otherwise
279
173
        branch2_tree.commit(message='merge branch 1')
280
 
        log = self.run_bzr("log -n0 -r-1", working_dir='branch2')[0]
 
174
        log = self.run_bzr("log -r-1")[0]
281
175
        self.assertContainsRe(log, r'    tags: tag1')
282
 
        log = self.run_bzr("log -n0 -r3.1.1", working_dir='branch2')[0]
 
176
        log = self.run_bzr("log -r3.1.1")[0]
283
177
        self.assertContainsRe(log, r'tags: tag1')
284
178
 
285
179
    def test_log_limit(self):
286
 
        tree = self.make_branch_and_tree('.')
287
 
        # We want more commits than our batch size starts at
288
 
        for pos in range(10):
289
 
            tree.commit("%s" % pos)
 
180
        self._prepare()
290
181
        log = self.run_bzr("log --limit 2")[0]
291
182
        self.assertNotContainsRe(log, r'revno: 1\n')
292
 
        self.assertNotContainsRe(log, r'revno: 2\n')
293
 
        self.assertNotContainsRe(log, r'revno: 3\n')
294
 
        self.assertNotContainsRe(log, r'revno: 4\n')
295
 
        self.assertNotContainsRe(log, r'revno: 5\n')
296
 
        self.assertNotContainsRe(log, r'revno: 6\n')
297
 
        self.assertNotContainsRe(log, r'revno: 7\n')
298
 
        self.assertNotContainsRe(log, r'revno: 8\n')
299
 
        self.assertContainsRe(log, r'revno: 9\n')
300
 
        self.assertContainsRe(log, r'revno: 10\n')
 
183
        self.assertContainsRe(log, r'revno: 2\n')
 
184
        self.assertContainsRe(log, r'revno: 3\n')
301
185
 
302
186
    def test_log_limit_short(self):
303
 
        self.make_linear_branch()
 
187
        self._prepare()
304
188
        log = self.run_bzr("log -l 2")[0]
305
189
        self.assertNotContainsRe(log, r'revno: 1\n')
306
190
        self.assertContainsRe(log, r'revno: 2\n')
307
191
        self.assertContainsRe(log, r'revno: 3\n')
308
192
 
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):
333
 
 
334
 
    def setUp(self):
335
 
        super(TestLogVerbose, self).setUp()
336
 
        self.make_minimal_branch()
337
 
 
338
 
    def assertUseShortDeltaFormat(self, cmd):
339
 
        log = self.run_bzr(cmd)[0]
340
 
        # Check that we use the short status format
341
 
        self.assertContainsRe(log, '(?m)^\s*A  hello.txt$')
342
 
        self.assertNotContainsRe(log, '(?m)^\s*added:$')
343
 
 
344
 
    def assertUseLongDeltaFormat(self, cmd):
345
 
        log = self.run_bzr(cmd)[0]
346
 
        # Check that we use the long status format
347
 
        self.assertNotContainsRe(log, '(?m)^\s*A  hello.txt$')
348
 
        self.assertContainsRe(log, '(?m)^\s*added:$')
349
 
 
350
 
    def test_log_short_verbose(self):
351
 
        self.assertUseShortDeltaFormat(['log', '--short', '-v'])
352
 
 
353
 
    def test_log_short_verbose_verbose(self):
354
 
        self.assertUseLongDeltaFormat(['log', '--short', '-vv'])
355
 
 
356
 
    def test_log_long_verbose(self):
357
 
        # Check that we use the long status format, ignoring the verbosity
358
 
        # level
359
 
        self.assertUseLongDeltaFormat(['log', '--long', '-v'])
360
 
 
361
 
    def test_log_long_verbose_verbose(self):
362
 
        # Check that we use the long status format, ignoring the verbosity
363
 
        # level
364
 
        self.assertUseLongDeltaFormat(['log', '--long', '-vv'])
365
 
 
366
 
 
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())
 
193
 
 
194
class TestLogMerges(TestCaseWithoutPropsHandler):
 
195
 
 
196
    def _prepare(self):
 
197
        parent_tree = self.make_branch_and_tree('parent')
 
198
        parent_tree.commit(message='first post', allow_pointless=True)
 
199
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
 
200
        child_tree.commit(message='branch 1', allow_pointless=True)
 
201
        smaller_tree = \
 
202
                child_tree.bzrdir.sprout('smallerchild').open_workingtree()
 
203
        smaller_tree.commit(message='branch 2', allow_pointless=True)
 
204
        child_tree.merge_from_branch(smaller_tree.branch)
 
205
        child_tree.commit(message='merge branch 2')
 
206
        parent_tree.merge_from_branch(child_tree.branch)
 
207
        parent_tree.commit(message='merge branch 1')
 
208
        os.chdir('parent')
388
209
 
389
210
    def test_merges_are_indented_by_level(self):
390
 
        expected = """\
 
211
        self._prepare()
 
212
        out,err = self.run_bzr('log')
 
213
        self.assertEqual('', err)
 
214
        log = normalize_log(out)
 
215
        self.assertEqualDiff(log, """\
391
216
------------------------------------------------------------
392
 
revno: 2 [merge]
 
217
revno: 2
393
218
committer: Lorem Ipsum <test@example.com>
394
 
branch nick: level0
 
219
branch nick: parent
395
220
timestamp: Just now
396
221
message:
397
 
  merge branch level1
 
222
  merge branch 1
398
223
    ------------------------------------------------------------
399
 
    revno: 1.1.2 [merge]
 
224
    revno: 1.1.2
400
225
    committer: Lorem Ipsum <test@example.com>
401
 
    branch nick: level1
 
226
    branch nick: child
402
227
    timestamp: Just now
403
228
    message:
404
 
      merge branch level2
 
229
      merge branch 2
405
230
        ------------------------------------------------------------
406
231
        revno: 1.2.1
407
232
        committer: Lorem Ipsum <test@example.com>
408
 
        branch nick: level2
 
233
        branch nick: smallerchild
409
234
        timestamp: Just now
410
235
        message:
411
 
          in branch level2
 
236
          branch 2
412
237
    ------------------------------------------------------------
413
238
    revno: 1.1.1
414
239
    committer: Lorem Ipsum <test@example.com>
415
 
    branch nick: level1
 
240
    branch nick: child
416
241
    timestamp: Just now
417
242
    message:
418
 
      in branch level1
419
 
------------------------------------------------------------
420
 
revno: 1
421
 
committer: Lorem Ipsum <test@example.com>
422
 
branch nick: level0
423
 
timestamp: Just now
424
 
message:
425
 
  in branch level0
426
 
"""
427
 
        self.check_log(expected, ['-n0'])
428
 
 
429
 
    def test_force_merge_revisions_off(self):
430
 
        expected = """\
431
 
------------------------------------------------------------
432
 
revno: 2 [merge]
433
 
committer: Lorem Ipsum <test@example.com>
434
 
branch nick: level0
435
 
timestamp: Just now
436
 
message:
437
 
  merge branch level1
438
 
------------------------------------------------------------
439
 
revno: 1
440
 
committer: Lorem Ipsum <test@example.com>
441
 
branch nick: level0
442
 
timestamp: Just now
443
 
message:
444
 
  in branch level0
445
 
"""
446
 
        self.check_log(expected, ['--long', '-n1'])
447
 
 
448
 
    def test_force_merge_revisions_on(self):
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)
476
 
 
477
 
    def test_force_merge_revisions_N(self):
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'])
 
243
      branch 1
 
244
------------------------------------------------------------
 
245
revno: 1
 
246
committer: Lorem Ipsum <test@example.com>
 
247
branch nick: parent
 
248
timestamp: Just now
 
249
message:
 
250
  first post
 
251
""")
493
252
 
494
253
    def test_merges_single_merge_rev(self):
495
 
        expected = """\
 
254
        self._prepare()
 
255
        out,err = self.run_bzr('log -r1.1.2')
 
256
        self.assertEqual('', err)
 
257
        log = normalize_log(out)
 
258
        self.assertEqualDiff(log, """\
496
259
------------------------------------------------------------
497
 
revno: 1.1.2 [merge]
 
260
revno: 1.1.2
498
261
committer: Lorem Ipsum <test@example.com>
499
 
branch nick: level1
 
262
branch nick: child
500
263
timestamp: Just now
501
264
message:
502
 
  merge branch level2
 
265
  merge branch 2
503
266
    ------------------------------------------------------------
504
267
    revno: 1.2.1
505
268
    committer: Lorem Ipsum <test@example.com>
506
 
    branch nick: level2
 
269
    branch nick: smallerchild
507
270
    timestamp: Just now
508
271
    message:
509
 
      in branch level2
510
 
"""
511
 
        self.check_log(expected, ['-n0', '-r1.1.2'])
 
272
      branch 2
 
273
""")
512
274
 
513
275
    def test_merges_partial_range(self):
514
 
        expected = """\
 
276
        self._prepare()
 
277
        out,err = self.run_bzr('log -r1.1.1..1.1.2')
 
278
        self.assertEqual('', err)
 
279
        log = normalize_log(out)
 
280
        self.assertEqualDiff(log, """\
515
281
------------------------------------------------------------
516
 
revno: 1.1.2 [merge]
 
282
revno: 1.1.2
517
283
committer: Lorem Ipsum <test@example.com>
518
 
branch nick: level1
 
284
branch nick: child
519
285
timestamp: Just now
520
286
message:
521
 
  merge branch level2
 
287
  merge branch 2
522
288
    ------------------------------------------------------------
523
289
    revno: 1.2.1
524
290
    committer: Lorem Ipsum <test@example.com>
525
 
    branch nick: level2
 
291
    branch nick: smallerchild
526
292
    timestamp: Just now
527
293
    message:
528
 
      in branch level2
 
294
      branch 2
529
295
------------------------------------------------------------
530
296
revno: 1.1.1
531
297
committer: Lorem Ipsum <test@example.com>
532
 
branch nick: level1
533
 
timestamp: Just now
534
 
message:
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')
561
 
        self.assertEqual('', err)
562
 
        log = test_log.normalize_log(out)
563
 
        expected = """\
564
 
------------------------------------------------------------
565
 
revno: 2 [merge]
566
 
committer: Lorem Ipsum <test@example.com>
567
 
branch nick: level0
568
 
timestamp: Just now
569
 
message:
570
 
  merge branch level1
571
 
diff:
572
 
=== modified file 'file2'
573
 
--- file2\t2005-11-22 00:00:01 +0000
574
 
+++ file2\t2005-11-22 00:00:02 +0000
575
 
@@ -1,1 +1,1 @@
576
 
-contents of level0/file2
577
 
+hello
578
 
    ------------------------------------------------------------
579
 
    revno: 1.1.1
580
 
    committer: Lorem Ipsum <test@example.com>
581
 
    branch nick: level1
582
 
    timestamp: Just now
583
 
    message:
584
 
      in branch level1
585
 
    diff:
586
 
    === modified file 'file2'
587
 
    --- file2\t2005-11-22 00:00:01 +0000
588
 
    +++ file2\t2005-11-22 00:00:02 +0000
589
 
    @@ -1,1 +1,1 @@
590
 
    -contents of level0/file2
591
 
    +hello
592
 
------------------------------------------------------------
593
 
revno: 1
594
 
committer: Lorem Ipsum <test@example.com>
595
 
branch nick: level0
596
 
timestamp: Just now
597
 
message:
598
 
  in branch level0
599
 
diff:
600
 
=== added file 'file1'
601
 
--- file1\t1970-01-01 00:00:00 +0000
602
 
+++ file1\t2005-11-22 00:00:01 +0000
603
 
@@ -0,0 +1,1 @@
604
 
+contents of level0/file1
605
 
 
606
 
=== added file 'file2'
607
 
--- file2\t1970-01-01 00:00:00 +0000
608
 
+++ file2\t2005-11-22 00:00:01 +0000
609
 
@@ -0,0 +1,1 @@
610
 
+contents of level0/file2
611
 
"""
612
 
        self.check_log(expected, ['-p', '-n0'])
613
 
 
614
 
    def test_log_show_diff_short(self):
615
 
        expected = """\
616
 
    2 Lorem Ipsum\t2005-11-22 [merge]
617
 
      merge branch level1
618
 
      === modified file 'file2'
619
 
      --- file2\t2005-11-22 00:00:01 +0000
620
 
      +++ file2\t2005-11-22 00:00:02 +0000
621
 
      @@ -1,1 +1,1 @@
622
 
      -contents of level0/file2
623
 
      +hello
624
 
 
625
 
    1 Lorem Ipsum\t2005-11-22
626
 
      in branch level0
627
 
      === added file 'file1'
628
 
      --- file1\t1970-01-01 00:00:00 +0000
629
 
      +++ file1\t2005-11-22 00:00:01 +0000
630
 
      @@ -0,0 +1,1 @@
631
 
      +contents of level0/file1
632
 
\x20\x20\x20\x20\x20\x20
633
 
      === added file 'file2'
634
 
      --- file2\t1970-01-01 00:00:00 +0000
635
 
      +++ file2\t2005-11-22 00:00:01 +0000
636
 
      @@ -0,0 +1,1 @@
637
 
      +contents of level0/file2
638
 
 
639
 
Use --include-merges or -n0 to see merged revisions.
640
 
"""
641
 
        self.check_log(expected, ['-p', '--short'])
642
 
 
643
 
    def test_log_show_diff_line(self):
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)
708
 
        out,err = self.run_bzr('log -p --line')
709
 
        self.assertNotEqual('', out)
710
 
        self.assertEqual('', err)
711
 
 
712
 
 
713
 
class TestLogEncodings(tests.TestCaseInTempDir):
 
298
branch nick: child
 
299
timestamp: Just now
 
300
message:
 
301
  branch 1
 
302
""")
 
303
 
 
304
    def test_merges_nonsupporting_formatter(self):
 
305
        self._prepare()
 
306
        err_msg = 'Selected log formatter only supports mainline revisions.'
 
307
        # The single revision case is tested in the core tests
 
308
        # since all standard formatters support single merge revisions.
 
309
        out,err = self.run_bzr('log --short -r1..1.1.2', retcode=3)
 
310
        self.assertContainsRe(err, err_msg)
 
311
        out,err = self.run_bzr('log --short -r1.1.1..1.1.2', retcode=3)
 
312
        self.assertContainsRe(err, err_msg)
 
313
 
 
314
 
 
315
class TestLogEncodings(TestCaseInTempDir):
714
316
 
715
317
    _mu = u'\xb5'
716
318
    _message = u'Message with \xb5'
721
323
        'latin-1',
722
324
        'iso-8859-1',
723
325
        'cp437', # Common windows encoding
724
 
        'cp1251', # Russian windows encoding
 
326
        'cp1251', # Alexander Belchenko's windows encoding
725
327
        'cp1258', # Common windows encoding
726
328
    ]
727
329
    # Encodings which cannot encode mu
732
334
    ]
733
335
 
734
336
    def setUp(self):
735
 
        super(TestLogEncodings, self).setUp()
736
 
        self.user_encoding = osutils._cached_user_encoding
737
 
        def restore():
738
 
            osutils._cached_user_encoding = self.user_encoding
739
 
        self.addCleanup(restore)
 
337
        TestCaseInTempDir.setUp(self)
 
338
        self.user_encoding = bzrlib.user_encoding
 
339
 
 
340
    def tearDown(self):
 
341
        bzrlib.user_encoding = self.user_encoding
 
342
        TestCaseInTempDir.tearDown(self)
740
343
 
741
344
    def create_branch(self):
742
345
        bzr = self.run_bzr
754
357
        else:
755
358
            encoded_msg = self._message.encode(encoding)
756
359
 
757
 
        old_encoding = osutils._cached_user_encoding
 
360
        old_encoding = bzrlib.user_encoding
758
361
        # This test requires that 'run_bzr' uses the current
759
362
        # bzrlib, because we override user_encoding, and expect
760
363
        # it to be used
761
364
        try:
762
 
            osutils._cached_user_encoding = 'ascii'
 
365
            bzrlib.user_encoding = 'ascii'
763
366
            # We should be able to handle any encoding
764
367
            out, err = bzr('log', encoding=encoding)
765
368
            if not fail:
770
373
            else:
771
374
                self.assertNotEqual(-1, out.find('Message with ?'))
772
375
        finally:
773
 
            osutils._cached_user_encoding = old_encoding
 
376
            bzrlib.user_encoding = old_encoding
774
377
 
775
378
    def test_log_handles_encoding(self):
776
379
        self.create_branch()
786
389
 
787
390
    def test_stdout_encoding(self):
788
391
        bzr = self.run_bzr
789
 
        osutils._cached_user_encoding = "cp1251"
 
392
        bzrlib.user_encoding = "cp1251"
790
393
 
791
394
        bzr('init')
792
395
        self.build_tree(['a'])
810
413
        self.assertEquals(-1, stdout.find(test_in_cp1251))
811
414
 
812
415
 
813
 
class TestLogFile(tests.TestCaseWithTransport):
 
416
class TestLogFile(TestCaseWithTransport):
814
417
 
815
418
    def test_log_local_branch_file(self):
816
419
        """We should be able to log files in local treeless branches"""
821
424
        tree.bzrdir.destroy_workingtree()
822
425
        self.run_bzr('log tree/file')
823
426
 
824
 
    def prepare_tree(self, complex=False):
825
 
        # The complex configuration includes deletes and renames
 
427
    def test_log_file(self):
 
428
        """The log for a particular file should only list revs for that file"""
826
429
        tree = self.make_branch_and_tree('parent')
827
430
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
828
431
        tree.add('file1')
836
439
        child_tree.commit(message='branch 1')
837
440
        tree.merge_from_branch(child_tree.branch)
838
441
        tree.commit(message='merge child branch')
839
 
        if complex:
840
 
            tree.remove('file2')
841
 
            tree.commit('remove file2')
842
 
            tree.rename_one('file3', 'file4')
843
 
            tree.commit('file3 is now called file4')
844
 
            tree.remove('file1')
845
 
            tree.commit('remove file1')
846
 
        os.chdir('parent')
847
 
 
848
 
    def test_log_file(self):
849
 
        """The log for a particular file should only list revs for that file"""
850
 
        self.prepare_tree()
851
 
        log = self.run_bzr('log -n0 file1')[0]
852
 
        self.assertContainsRe(log, 'revno: 1\n')
853
 
        self.assertNotContainsRe(log, 'revno: 2\n')
854
 
        self.assertNotContainsRe(log, 'revno: 3\n')
855
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
856
 
        self.assertNotContainsRe(log, 'revno: 4 ')
857
 
        log = self.run_bzr('log -n0 file2')[0]
858
 
        self.assertNotContainsRe(log, 'revno: 1\n')
859
 
        self.assertContainsRe(log, 'revno: 2\n')
860
 
        self.assertNotContainsRe(log, 'revno: 3\n')
861
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
862
 
        self.assertContainsRe(log, 'revno: 4 ')
863
 
        log = self.run_bzr('log -n0 file3')[0]
864
 
        self.assertNotContainsRe(log, 'revno: 1\n')
865
 
        self.assertNotContainsRe(log, 'revno: 2\n')
866
 
        self.assertContainsRe(log, 'revno: 3\n')
867
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
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]
888
 
        self.assertNotContainsRe(log, 'revno: 1\n')
889
 
        self.assertContainsRe(log, 'revno: 2\n')
890
 
        self.assertNotContainsRe(log, 'revno: 3\n')
891
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
892
 
        self.assertNotContainsRe(log, 'revno: 4 ')
893
 
 
894
 
    def test_log_file_historical_missing(self):
895
 
        # Check logging a deleted file gives an error if the
896
 
        # file isn't found at the end or start of the revision range
897
 
        self.prepare_tree(complex=True)
898
 
        err_msg = "Path unknown at end or start of revision range: file2"
899
 
        err = self.run_bzr('log file2', retcode=3)[1]
900
 
        self.assertContainsRe(err, err_msg)
901
 
 
902
 
    def test_log_file_historical_end(self):
903
 
        # Check logging a deleted file is ok if the file existed
904
 
        # at the end the revision range
905
 
        self.prepare_tree(complex=True)
906
 
        log, err = self.run_bzr('log -n0 -r..4 file2')
907
 
        self.assertEquals('', err)
908
 
        self.assertNotContainsRe(log, 'revno: 1\n')
909
 
        self.assertContainsRe(log, 'revno: 2\n')
910
 
        self.assertNotContainsRe(log, 'revno: 3\n')
911
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
912
 
        self.assertContainsRe(log, 'revno: 4 ')
913
 
 
914
 
    def test_log_file_historical_start(self):
915
 
        # Check logging a deleted file is ok if the file existed
916
 
        # at the start of the revision range
917
 
        self.prepare_tree(complex=True)
918
 
        log, err = self.run_bzr('log file1')
919
 
        self.assertEquals('', err)
920
 
        self.assertContainsRe(log, 'revno: 1\n')
921
 
        self.assertNotContainsRe(log, 'revno: 2\n')
922
 
        self.assertNotContainsRe(log, 'revno: 3\n')
923
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
924
 
        self.assertNotContainsRe(log, 'revno: 4 ')
925
 
 
926
 
    def test_log_file_renamed(self):
927
 
        """File matched against revision range, not current tree."""
928
 
        self.prepare_tree(complex=True)
929
 
 
930
 
        # Check logging a renamed file gives an error by default
931
 
        err_msg = "Path unknown at end or start of revision range: file3"
932
 
        err = self.run_bzr('log file3', retcode=3)[1]
933
 
        self.assertContainsRe(err, err_msg)
934
 
 
935
 
        # Check we can see a renamed file if we give the right end revision
936
 
        log, err = self.run_bzr('log -r..4 file3')
937
 
        self.assertEquals('', err)
938
 
        self.assertNotContainsRe(log, 'revno: 1\n')
939
 
        self.assertNotContainsRe(log, 'revno: 2\n')
940
 
        self.assertContainsRe(log, 'revno: 3\n')
941
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
942
 
        self.assertNotContainsRe(log, 'revno: 4 ')
943
 
 
944
 
    def test_line_log_file(self):
945
 
        """The line log for a file should only list relevant mainline revs"""
946
 
        # Note: this also implicitly  covers the short logging case.
947
 
        # We test using --line in preference to --short because matching
948
 
        # revnos in the output of --line is more reliable.
949
 
        self.prepare_tree()
950
 
 
951
 
        # full history of file1
952
 
        log = self.run_bzr('log --line file1')[0]
953
 
        self.assertContainsRe(log, '^1:', re.MULTILINE)
954
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
955
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
956
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
957
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
958
 
 
959
 
        # full history of file2
960
 
        log = self.run_bzr('log --line file2')[0]
961
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
962
 
        self.assertContainsRe(log, '^2:', re.MULTILINE)
963
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
964
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
965
 
        self.assertContainsRe(log, '^4:', re.MULTILINE)
966
 
 
967
 
        # full history of file3
968
 
        log = self.run_bzr('log --line file3')[0]
969
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
970
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
971
 
        self.assertContainsRe(log, '^3:', re.MULTILINE)
972
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
973
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
974
 
 
975
 
        # file in a merge revision
976
 
        log = self.run_bzr('log --line -r3.1.1 file2')[0]
977
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
978
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
979
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
980
 
        self.assertContainsRe(log, '^3.1.1:', re.MULTILINE)
981
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
982
 
 
983
 
        # file in a mainline revision
984
 
        log = self.run_bzr('log --line -r4 file2')[0]
985
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
986
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
987
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
988
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
989
 
        self.assertContainsRe(log, '^4:', re.MULTILINE)
990
 
 
991
 
        # file since a revision
992
 
        log = self.run_bzr('log --line -r3.. file2')[0]
993
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
994
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
995
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
996
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
997
 
        self.assertContainsRe(log, '^4:', re.MULTILINE)
998
 
 
999
 
        # file up to a revision
1000
 
        log = self.run_bzr('log --line -r..3 file2')[0]
1001
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
1002
 
        self.assertContainsRe(log, '^2:', re.MULTILINE)
1003
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
1004
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
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'])
 
442
        os.chdir('parent')
 
443
        log = self.run_bzr('log file1')[0]
 
444
        self.assertContainsRe(log, 'revno: 1\n')
 
445
        self.assertNotContainsRe(log, 'revno: 2\n')
 
446
        self.assertNotContainsRe(log, 'revno: 3\n')
 
447
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
448
        self.assertNotContainsRe(log, 'revno: 4\n')
 
449
        log = self.run_bzr('log file2')[0]
 
450
        self.assertNotContainsRe(log, 'revno: 1\n')
 
451
        self.assertContainsRe(log, 'revno: 2\n')
 
452
        self.assertNotContainsRe(log, 'revno: 3\n')
 
453
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
454
        self.assertContainsRe(log, 'revno: 4\n')
 
455
        log = self.run_bzr('log file3')[0]
 
456
        self.assertNotContainsRe(log, 'revno: 1\n')
 
457
        self.assertNotContainsRe(log, 'revno: 2\n')
 
458
        self.assertContainsRe(log, 'revno: 3\n')
 
459
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
460
        self.assertNotContainsRe(log, 'revno: 4\n')
 
461
        log = self.run_bzr('log -r3.1.1 file2')[0]
 
462
        self.assertNotContainsRe(log, 'revno: 1\n')
 
463
        self.assertNotContainsRe(log, 'revno: 2\n')
 
464
        self.assertNotContainsRe(log, 'revno: 3\n')
 
465
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
466
        self.assertNotContainsRe(log, 'revno: 4\n')
 
467
        log = self.run_bzr('log -r4 file2')[0]
 
468
        self.assertNotContainsRe(log, 'revno: 1\n')
 
469
        self.assertNotContainsRe(log, 'revno: 2\n')
 
470
        self.assertNotContainsRe(log, 'revno: 3\n')
 
471
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
472
        self.assertContainsRe(log, 'revno: 4\n')
 
473
        log = self.run_bzr('log -r3.. file2')[0]
 
474
        self.assertNotContainsRe(log, 'revno: 1\n')
 
475
        self.assertNotContainsRe(log, 'revno: 2\n')
 
476
        self.assertNotContainsRe(log, 'revno: 3\n')
 
477
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
478
        self.assertContainsRe(log, 'revno: 4\n')
 
479
        log = self.run_bzr('log -r..3 file2')[0]
 
480
        self.assertNotContainsRe(log, 'revno: 1\n')
 
481
        self.assertContainsRe(log, 'revno: 2\n')
 
482
        self.assertNotContainsRe(log, 'revno: 3\n')
 
483
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
484
        self.assertNotContainsRe(log, 'revno: 4\n')