/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

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

  • Committer: Martin Pool
  • Date: 2007-10-03 08:06:44 UTC
  • mto: This revision was merged to the branch mainline in revision 2901.
  • Revision ID: mbp@sourcefrog.net-20071003080644-oivy0gkg98sex0ed
Avoid internal error tracebacks on failure to lock on readonly transport (#129701).

Add new LockFailed, which doesn't imply that we failed to get it because of
contention.  Raise this if we fail to create the pending or lock directories
because of Transport errors.

UnlockableTransport is not an internal error.

ReadOnlyLockError has a message which didn't match its name or usage; it's now
deprecated and callers are updated to use LockFailed which is more appropriate.

Add zero_ninetytwo deprecation symbol.

Unify assertMatchesRe with TestCase.assertContainsRe.

When the constructor is deprecated, just say that the class is deprecated, not
the __init__ method - this works better with applyDeprecated in tests.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2010 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
 
from itertools import izip
21
21
import os
22
 
import re
23
 
 
24
 
from bzrlib import (
25
 
    branchbuilder,
26
 
    errors,
27
 
    log,
28
 
    osutils,
29
 
    tests,
30
 
    )
31
 
from bzrlib.tests import (
32
 
    script,
33
 
    test_log,
34
 
    )
35
 
 
36
 
 
37
 
class TestLog(tests.TestCaseWithTransport, test_log.TestLogMixin):
38
 
 
39
 
    def make_minimal_branch(self, path='.', format=None):
40
 
        tree = self.make_branch_and_tree(path, format=format)
41
 
        self.build_tree([path + '/hello.txt'])
42
 
        tree.add('hello.txt')
43
 
        tree.commit(message='message1')
44
 
        return tree
45
 
 
46
 
    def make_linear_branch(self, path='.', format=None):
 
22
 
 
23
import bzrlib
 
24
from bzrlib.tests.blackbox import ExternalBase
 
25
from bzrlib.tests import TestCaseInTempDir, TestCaseWithTransport
 
26
 
 
27
 
 
28
class TestLog(ExternalBase):
 
29
 
 
30
    def _prepare(self, path='.', format=None):
47
31
        tree = self.make_branch_and_tree(path, format=format)
48
32
        self.build_tree(
49
33
            [path + '/hello.txt', path + '/goodbye.txt', path + '/meep.txt'])
53
37
        tree.commit(message='message2')
54
38
        tree.add('meep.txt')
55
39
        tree.commit(message='message3')
56
 
        return tree
57
 
 
58
 
    def make_merged_branch(self, path='.', format=None):
59
 
        tree = self.make_linear_branch(path, format)
60
 
        tree2 = tree.bzrdir.sprout('tree2',
61
 
            revision_id=tree.branch.get_rev_id(1)).open_workingtree()
62
 
        tree2.commit(message='tree2 message2')
63
 
        tree2.commit(message='tree2 message3')
64
 
        tree.merge_from_branch(tree2.branch)
65
 
        tree.commit(message='merge')
66
 
        return tree
67
 
 
68
 
 
69
 
class TestLogWithLogCatcher(TestLog):
70
 
 
71
 
    def setUp(self):
72
 
        super(TestLogWithLogCatcher, self).setUp()
73
 
        # Capture log formatter creations
74
 
        class MyLogFormatter(test_log.LogCatcher):
75
 
 
76
 
            def __new__(klass, *args, **kwargs):
77
 
                self.log_catcher = test_log.LogCatcher(*args, **kwargs)
78
 
                # Always return our own log formatter
79
 
                return self.log_catcher
80
 
 
81
 
        def getme(branch):
82
 
                # Always return our own log formatter class hijacking the
83
 
                # default behavior (which requires setting up a config
84
 
                # variable)
85
 
            return MyLogFormatter
86
 
        self.overrideAttr(log.log_formatter_registry, 'get_default', getme)
87
 
 
88
 
    def get_captured_revisions(self):
89
 
        return self.log_catcher.revisions
90
 
 
91
 
    def assertLogRevnos(self, args, expected_revnos, working_dir='.'):
92
 
        self.run_bzr(['log'] + args, working_dir=working_dir)
93
 
        self.assertEqual(expected_revnos,
94
 
                         [r.revno for r in self.get_captured_revisions()])
95
 
 
96
 
    def assertLogRevnosAndDepths(self, args, expected_revnos_and_depths,
97
 
                                working_dir='.'):
98
 
        self.run_bzr(['log'] + args, working_dir=working_dir)
99
 
        self.assertEqual(expected_revnos_and_depths,
100
 
                         [(r.revno, r.merge_depth)
101
 
                           for r in self.get_captured_revisions()])
102
 
 
103
 
 
104
 
class TestLogRevSpecs(TestLogWithLogCatcher):
105
 
 
106
 
    def test_log_no_revspec(self):
107
 
        self.make_linear_branch()
108
 
        self.assertLogRevnos([], ['3', '2', '1'])
 
40
        self.full_log = self.run_bzr(["log", path])[0]
 
41
        return tree
109
42
 
110
43
    def test_log_null_end_revspec(self):
111
 
        self.make_linear_branch()
112
 
        self.assertLogRevnos(['-r1..'], ['3', '2', '1'])
 
44
        self._prepare()
 
45
        self.assertTrue('revno: 1\n' in self.full_log)
 
46
        self.assertTrue('revno: 2\n' in self.full_log)
 
47
        self.assertTrue('revno: 3\n' in self.full_log)
 
48
        self.assertTrue('message:\n  message1\n' in self.full_log)
 
49
        self.assertTrue('message:\n  message2\n' in self.full_log)
 
50
        self.assertTrue('message:\n  message3\n' in self.full_log)
 
51
 
 
52
        log = self.run_bzr("log -r 1..")[0]
 
53
        self.assertEqualDiff(log, self.full_log)
113
54
 
114
55
    def test_log_null_begin_revspec(self):
115
 
        self.make_linear_branch()
116
 
        self.assertLogRevnos(['-r..3'], ['3', '2', '1'])
 
56
        self._prepare()
 
57
        log = self.run_bzr("log -r ..3")[0]
 
58
        self.assertEqualDiff(self.full_log, log)
117
59
 
118
60
    def test_log_null_both_revspecs(self):
119
 
        self.make_linear_branch()
120
 
        self.assertLogRevnos(['-r..'], ['3', '2', '1'])
 
61
        self._prepare()
 
62
        log = self.run_bzr("log -r ..")[0]
 
63
        self.assertEquals(self.full_log, log)
 
64
        self.assertEqualDiff(self.full_log, log)
121
65
 
122
66
    def test_log_negative_begin_revspec_full_log(self):
123
 
        self.make_linear_branch()
124
 
        self.assertLogRevnos(['-r-3..'], ['3', '2', '1'])
 
67
        self._prepare()
 
68
        log = self.run_bzr("log -r -3..")[0]
 
69
        self.assertEqualDiff(self.full_log, log)
125
70
 
126
71
    def test_log_negative_both_revspec_full_log(self):
127
 
        self.make_linear_branch()
128
 
        self.assertLogRevnos(['-r-3..-1'], ['3', '2', '1'])
 
72
        self._prepare()
 
73
        log = self.run_bzr("log -r -3..-1")[0]
 
74
        self.assertEqualDiff(self.full_log, log)
129
75
 
130
76
    def test_log_negative_both_revspec_partial(self):
131
 
        self.make_linear_branch()
132
 
        self.assertLogRevnos(['-r-3..-2'], ['2', '1'])
 
77
        self._prepare()
 
78
        log = self.run_bzr("log -r -3..-2")[0]
 
79
        self.assertTrue('revno: 1\n' in log)
 
80
        self.assertTrue('revno: 2\n' in log)
 
81
        self.assertTrue('revno: 3\n' not in log)
133
82
 
134
83
    def test_log_negative_begin_revspec(self):
135
 
        self.make_linear_branch()
136
 
        self.assertLogRevnos(['-r-2..'], ['3', '2'])
137
 
 
138
 
    def test_log_positive_revspecs(self):
139
 
        self.make_linear_branch()
140
 
        self.assertLogRevnos(['-r1..3'], ['3', '2', '1'])
141
 
 
142
 
    def test_log_dotted_revspecs(self):
143
 
        self.make_merged_branch()
144
 
        self.assertLogRevnos(['-n0', '-r1..1.1.1'], ['1.1.1', '1'])
145
 
 
146
 
    def test_log_limit(self):
147
 
        tree = self.make_branch_and_tree('.')
148
 
        # We want more commits than our batch size starts at
149
 
        for pos in range(10):
150
 
            tree.commit("%s" % pos)
151
 
        self.assertLogRevnos(['--limit', '2'], ['10', '9'])
152
 
 
153
 
    def test_log_limit_short(self):
154
 
        self.make_linear_branch()
155
 
        self.assertLogRevnos(['-l', '2'], ['3', '2'])
156
 
 
157
 
    def test_log_change_revno(self):
158
 
        self.make_linear_branch()
159
 
        self.assertLogRevnos(['-c1'], ['1'])
160
 
 
161
 
 
162
 
class TestLogMergedLinearAncestry(TestLogWithLogCatcher):
163
 
 
164
 
    def setUp(self):
165
 
        super(TestLogMergedLinearAncestry, self).setUp()
166
 
        # FIXME: Using a MemoryTree would be even better here (but until we
167
 
        # stop calling run_bzr, there is no point) --vila 100118.
168
 
        builder = branchbuilder.BranchBuilder(self.get_transport())
169
 
        builder.start_series()
170
 
        # mainline
171
 
        builder.build_snapshot('1', None, [
172
 
            ('add', ('', 'root-id', 'directory', ''))])
173
 
        builder.build_snapshot('2', ['1'], [])
174
 
        # branch
175
 
        builder.build_snapshot('1.1.1', ['1'], [])
176
 
        # merge branch into mainline
177
 
        builder.build_snapshot('3', ['2', '1.1.1'], [])
178
 
        # new commits in branch
179
 
        builder.build_snapshot('1.1.2', ['1.1.1'], [])
180
 
        builder.build_snapshot('1.1.3', ['1.1.2'], [])
181
 
        # merge branch into mainline
182
 
        builder.build_snapshot('4', ['3', '1.1.3'], [])
183
 
        # merge mainline into branch
184
 
        builder.build_snapshot('1.1.4', ['1.1.3', '4'], [])
185
 
        # merge branch into mainline
186
 
        builder.build_snapshot('5', ['4', '1.1.4'], [])
187
 
        builder.finish_series()
188
 
 
189
 
    def test_n0(self):
190
 
        self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4'],
191
 
                             ['1.1.4', '4', '1.1.3', '1.1.2', '3', '1.1.1'])
192
 
    def test_n0_forward(self):
193
 
        self.assertLogRevnos(['-n0', '-r1.1.1..1.1.4', '--forward'],
194
 
                             ['3', '1.1.1', '4', '1.1.2', '1.1.3', '1.1.4'])
195
 
 
196
 
    def test_n1(self):
197
 
        # starting from 1.1.4 we follow the left-hand ancestry
198
 
        self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4'],
199
 
                             ['1.1.4', '1.1.3', '1.1.2', '1.1.1'])
200
 
 
201
 
    def test_n1_forward(self):
202
 
        self.assertLogRevnos(['-n1', '-r1.1.1..1.1.4', '--forward'],
203
 
                             ['1.1.1', '1.1.2', '1.1.3', '1.1.4'])
204
 
 
205
 
 
206
 
class Test_GenerateAllRevisions(TestLogWithLogCatcher):
207
 
 
208
 
    def setUp(self):
209
 
        super(Test_GenerateAllRevisions, self).setUp()
210
 
        builder = self.make_branch_with_many_merges()
211
 
        b = builder.get_branch()
212
 
        b.lock_read()
213
 
        self.addCleanup(b.unlock)
214
 
        self.branch = b
215
 
 
216
 
    def make_branch_with_many_merges(self, path='.', format=None):
217
 
        builder = branchbuilder.BranchBuilder(self.get_transport())
218
 
        builder.start_series()
219
 
        # The graph below may look a bit complicated (and it may be but I've
220
 
        # banged my head enough on it) but the bug requires at least dotted
221
 
        # revnos *and* merged revisions below that.
222
 
        builder.build_snapshot('1', None, [
223
 
            ('add', ('', 'root-id', 'directory', ''))])
224
 
        builder.build_snapshot('2', ['1'], [])
225
 
        builder.build_snapshot('1.1.1', ['1'], [])
226
 
        builder.build_snapshot('2.1.1', ['2'], [])
227
 
        builder.build_snapshot('3', ['2', '1.1.1'], [])
228
 
        builder.build_snapshot('2.1.2', ['2.1.1'], [])
229
 
        builder.build_snapshot('2.2.1', ['2.1.1'], [])
230
 
        builder.build_snapshot('2.1.3', ['2.1.2', '2.2.1'], [])
231
 
        builder.build_snapshot('4', ['3', '2.1.3'], [])
232
 
        builder.build_snapshot('5', ['4', '2.1.2'], [])
233
 
        builder.finish_series()
234
 
        return builder
235
 
 
236
 
    def test_not_an_ancestor(self):
237
 
        self.assertRaises(errors.BzrCommandError,
238
 
                          log._generate_all_revisions,
239
 
                          self.branch, '1.1.1', '2.1.3', 'reverse',
240
 
                          delayed_graph_generation=True)
241
 
 
242
 
    def test_wrong_order(self):
243
 
        self.assertRaises(errors.BzrCommandError,
244
 
                          log._generate_all_revisions,
245
 
                          self.branch, '5', '2.1.3', 'reverse',
246
 
                          delayed_graph_generation=True)
247
 
 
248
 
    def test_no_start_rev_id_with_end_rev_id_being_a_merge(self):
249
 
        revs = log._generate_all_revisions(
250
 
            self.branch, None, '2.1.3',
251
 
            'reverse', delayed_graph_generation=True)
252
 
 
253
 
 
254
 
class TestLogRevSpecsWithPaths(TestLogWithLogCatcher):
255
 
 
256
 
    def test_log_revno_n_path_wrong_namespace(self):
257
 
        self.make_linear_branch('branch1')
258
 
        self.make_linear_branch('branch2')
259
 
        # There is no guarantee that a path exist between two arbitrary
260
 
        # revisions.
261
 
        self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)
262
 
 
263
 
    def test_log_revno_n_path_correct_order(self):
264
 
        self.make_linear_branch('branch2')
265
 
        self.assertLogRevnos(['-rrevno:1:branch2..revno:3:branch2'],
266
 
                             ['3', '2','1'])
 
84
        self._prepare()
 
85
        log = self.run_bzr("log -r -2..")[0]
 
86
        self.assertTrue('revno: 1\n' not in log)
 
87
        self.assertTrue('revno: 2\n' in log)
 
88
        self.assertTrue('revno: 3\n' in log)
 
89
 
 
90
    def test_log_postive_revspecs(self):
 
91
        self._prepare()
 
92
        log = self.run_bzr("log -r 1..3")[0]
 
93
        self.assertEqualDiff(self.full_log, log)
 
94
 
 
95
    def test_log_reversed_revspecs(self):
 
96
        self._prepare()
 
97
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
 
98
                            'the end revision.\n',),
 
99
                           ['log', '-r3..1'])
267
100
 
268
101
    def test_log_revno_n_path(self):
269
 
        self.make_linear_branch('branch2')
270
 
        self.assertLogRevnos(['-rrevno:1:branch2'],
271
 
                             ['1'])
272
 
        rev_props = self.log_catcher.revisions[0].rev.properties
273
 
        self.assertEqual('branch2', rev_props['branch-nick'])
274
 
 
275
 
 
276
 
class TestLogErrors(TestLog):
277
 
 
278
 
    def test_log_zero_revspec(self):
279
 
        self.make_minimal_branch()
280
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
281
 
                           ['log', '-r0'])
282
 
 
283
 
    def test_log_zero_begin_revspec(self):
284
 
        self.make_linear_branch()
285
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
286
 
                           ['log', '-r0..2'])
287
 
 
288
 
    def test_log_zero_end_revspec(self):
289
 
        self.make_linear_branch()
290
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
291
 
                           ['log', '-r-2..0'])
292
 
 
293
 
    def test_log_nonexistent_revno(self):
294
 
        self.make_minimal_branch()
295
 
        self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
296
 
                            "does not exist in branch:"],
297
 
                           ['log', '-r1234'])
298
 
 
299
 
    def test_log_nonexistent_dotted_revno(self):
300
 
        self.make_minimal_branch()
301
 
        self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
302
 
                            "does not exist in branch:"],
303
 
                           ['log',  '-r123.123'])
304
 
 
305
 
    def test_log_change_nonexistent_revno(self):
306
 
        self.make_minimal_branch()
307
 
        self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
308
 
                            "does not exist in branch:"],
309
 
                           ['log',  '-c1234'])
310
 
 
311
 
    def test_log_change_nonexistent_dotted_revno(self):
312
 
        self.make_minimal_branch()
313
 
        self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
314
 
                            "does not exist in branch:"],
315
 
                           ['log', '-c123.123'])
316
 
 
317
 
    def test_log_change_single_revno_only(self):
318
 
        self.make_minimal_branch()
319
 
        self.run_bzr_error(['bzr: ERROR: Option --change does not'
320
 
                           ' accept revision ranges'],
321
 
                           ['log', '--change', '2..3'])
322
 
 
323
 
    def test_log_change_incompatible_with_revision(self):
324
 
        self.run_bzr_error(['bzr: ERROR: --revision and --change'
325
 
                           ' are mutually exclusive'],
326
 
                           ['log', '--change', '2', '--revision', '3'])
327
 
 
 
102
        self._prepare(path='branch1')
 
103
        self._prepare(path='branch2')
 
104
        log = self.run_bzr("log -r revno:2:branch1..revno:3:branch2",
 
105
                          retcode=3)[0]
 
106
        log = self.run_bzr("log -r revno:1:branch2..revno:3:branch2")[0]
 
107
        self.assertEqualDiff(self.full_log, log)
 
108
        log = self.run_bzr("log -r revno:1:branch2")[0]
 
109
        self.assertTrue('revno: 1\n' in log)
 
110
        self.assertTrue('revno: 2\n' not in log)
 
111
        self.assertTrue('branch nick: branch2\n' in log)
 
112
        self.assertTrue('branch nick: branch1\n' not in log)
 
113
        
328
114
    def test_log_nonexistent_file(self):
329
 
        self.make_minimal_branch()
330
115
        # files that don't exist in either the basis tree or working tree
331
116
        # should give an error
 
117
        wt = self.make_branch_and_tree('.')
332
118
        out, err = self.run_bzr('log does-not-exist', retcode=3)
333
 
        self.assertContainsRe(err,
334
 
                              'Path unknown at end or start of revision range: '
335
 
                              'does-not-exist')
336
 
 
337
 
    def test_log_reversed_revspecs(self):
338
 
        self.make_linear_branch()
339
 
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
340
 
                            'the end revision.\n',),
341
 
                           ['log', '-r3..1'])
342
 
 
343
 
    def test_log_reversed_dotted_revspecs(self):
344
 
        self.make_merged_branch()
345
 
        self.run_bzr_error(('bzr: ERROR: Start revision not found in '
346
 
                            'left-hand history of end revision.\n',),
347
 
                           "log -r 1.1.1..1")
348
 
 
349
 
    def test_log_bad_message_re(self):
350
 
        """Bad --message argument gives a sensible message
351
 
        
352
 
        See https://bugs.launchpad.net/bzr/+bug/251352
353
 
        """
354
 
        self.make_minimal_branch()
355
 
        out, err = self.run_bzr(['log', '-m', '*'], retcode=3)
356
 
        self.assertEqual("bzr: ERROR: Invalid regular expression"
357
 
            " in log message filter"
358
 
            ": '*'"
359
 
            ": nothing to repeat\n", err)
360
 
        self.assertEqual('', out)
361
 
 
362
 
    def test_log_unsupported_timezone(self):
363
 
        self.make_linear_branch()
364
 
        self.run_bzr_error(['bzr: ERROR: Unsupported timezone format "foo", '
365
 
                            'options are "utc", "original", "local".'],
366
 
                           ['log', '--timezone', 'foo'])
367
 
 
368
 
    def test_log_exclude_ancestry_no_range(self):
369
 
        self.make_linear_branch()
370
 
        self.run_bzr_error(['bzr: ERROR: --exclude-common-ancestry'
371
 
                            ' requires -r with two revisions'],
372
 
                           ['log', '--exclude-common-ancestry'])
373
 
 
374
 
    def test_log_exclude_ancestry_single_revision(self):
375
 
        self.make_merged_branch()
376
 
        self.run_bzr_error(['bzr: ERROR: --exclude-common-ancestry'
377
 
                            ' requires two different revisions'],
378
 
                           ['log', '--exclude-common-ancestry',
379
 
                            '-r1.1.1..1.1.1'])
380
 
 
381
 
class TestLogTags(TestLog):
 
119
        self.assertContainsRe(
 
120
            err, 'Path does not have any revision history: does-not-exist')
382
121
 
383
122
    def test_log_with_tags(self):
384
 
        tree = self.make_linear_branch(format='dirstate-tags')
 
123
        tree = self._prepare(format='dirstate-tags')
385
124
        branch = tree.branch
386
125
        branch.tags.set_tag('tag1', branch.get_rev_id(1))
387
126
        branch.tags.set_tag('tag1.1', branch.get_rev_id(1))
388
 
        branch.tags.set_tag('tag3', branch.last_revision())
389
 
 
 
127
        branch.tags.set_tag('tag3', branch.last_revision()) 
 
128
        
390
129
        log = self.run_bzr("log -r-1")[0]
391
130
        self.assertTrue('tags: tag3' in log)
392
131
 
396
135
        self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
397
136
 
398
137
    def test_merged_log_with_tags(self):
399
 
        branch1_tree = self.make_linear_branch('branch1',
400
 
                                               format='dirstate-tags')
 
138
        branch1_tree = self._prepare(path='branch1', format='dirstate-tags')
401
139
        branch1 = branch1_tree.branch
402
140
        branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
403
141
        branch1_tree.commit(message='foobar', allow_pointless=True)
404
142
        branch1.tags.set_tag('tag1', branch1.last_revision())
405
 
        # tags don't propagate if we don't merge
406
 
        self.run_bzr('merge ../branch1', working_dir='branch2')
 
143
        os.chdir('branch2')
 
144
        self.run_bzr('merge ../branch1') # tags don't propagate otherwise
407
145
        branch2_tree.commit(message='merge branch 1')
408
 
        log = self.run_bzr("log -n0 -r-1", working_dir='branch2')[0]
 
146
        log = self.run_bzr("log -r-1")[0]
409
147
        self.assertContainsRe(log, r'    tags: tag1')
410
 
        log = self.run_bzr("log -n0 -r3.1.1", working_dir='branch2')[0]
 
148
        log = self.run_bzr("log -r3.1.1")[0]
411
149
        self.assertContainsRe(log, r'tags: tag1')
412
150
 
413
 
 
414
 
class TestLogVerbose(TestLog):
415
 
 
416
 
    def setUp(self):
417
 
        super(TestLogVerbose, self).setUp()
418
 
        self.make_minimal_branch()
419
 
 
420
 
    def assertUseShortDeltaFormat(self, cmd):
421
 
        log = self.run_bzr(cmd)[0]
422
 
        # Check that we use the short status format
423
 
        self.assertContainsRe(log, '(?m)^\s*A  hello.txt$')
424
 
        self.assertNotContainsRe(log, '(?m)^\s*added:$')
425
 
 
426
 
    def assertUseLongDeltaFormat(self, cmd):
427
 
        log = self.run_bzr(cmd)[0]
428
 
        # Check that we use the long status format
429
 
        self.assertNotContainsRe(log, '(?m)^\s*A  hello.txt$')
430
 
        self.assertContainsRe(log, '(?m)^\s*added:$')
431
 
 
432
 
    def test_log_short_verbose(self):
433
 
        self.assertUseShortDeltaFormat(['log', '--short', '-v'])
434
 
 
435
 
    def test_log_short_verbose_verbose(self):
436
 
        self.assertUseLongDeltaFormat(['log', '--short', '-vv'])
437
 
 
438
 
    def test_log_long_verbose(self):
439
 
        # Check that we use the long status format, ignoring the verbosity
440
 
        # level
441
 
        self.assertUseLongDeltaFormat(['log', '--long', '-v'])
442
 
 
443
 
    def test_log_long_verbose_verbose(self):
444
 
        # Check that we use the long status format, ignoring the verbosity
445
 
        # level
446
 
        self.assertUseLongDeltaFormat(['log', '--long', '-vv'])
447
 
 
448
 
 
449
 
class TestLogMerges(TestLogWithLogCatcher):
450
 
 
451
 
    def setUp(self):
452
 
        super(TestLogMerges, self).setUp()
453
 
        self.make_branches_with_merges()
454
 
 
455
 
    def make_branches_with_merges(self):
456
 
        level0 = self.make_branch_and_tree('level0')
457
 
        self.wt_commit(level0, 'in branch level0')
458
 
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
459
 
        self.wt_commit(level1, 'in branch level1')
460
 
        level2 = level1.bzrdir.sprout('level2').open_workingtree()
461
 
        self.wt_commit(level2, 'in branch level2')
462
 
        level1.merge_from_branch(level2.branch)
463
 
        self.wt_commit(level1, 'merge branch level2')
464
 
        level0.merge_from_branch(level1.branch)
465
 
        self.wt_commit(level0, 'merge branch level1')
 
151
    def test_log_limit(self):
 
152
        self._prepare()
 
153
        log = self.run_bzr("log --limit 2")[0]
 
154
        self.assertTrue('revno: 1\n' not in log)
 
155
        self.assertTrue('revno: 2\n' in log)
 
156
        self.assertTrue('revno: 3\n' in log)
 
157
 
 
158
class TestLogMerges(ExternalBase):
 
159
 
 
160
    def _prepare(self):
 
161
        parent_tree = self.make_branch_and_tree('parent')
 
162
        parent_tree.commit(message='first post', allow_pointless=True)
 
163
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
 
164
        child_tree.commit(message='branch 1', allow_pointless=True)
 
165
        smaller_tree = \
 
166
                child_tree.bzrdir.sprout('smallerchild').open_workingtree()
 
167
        smaller_tree.commit(message='branch 2', allow_pointless=True)
 
168
        child_tree.merge_from_branch(smaller_tree.branch)
 
169
        child_tree.commit(message='merge branch 2')
 
170
        parent_tree.merge_from_branch(child_tree.branch)
 
171
        parent_tree.commit(message='merge branch 1')
 
172
        os.chdir('parent')
466
173
 
467
174
    def test_merges_are_indented_by_level(self):
468
 
        self.run_bzr(['log', '-n0'], working_dir='level0')
469
 
        revnos_and_depth = [(r.revno, r.merge_depth)
470
 
                            for r in self.get_captured_revisions()]
471
 
        self.assertEqual([('2', 0), ('1.1.2', 1), ('1.2.1', 2), ('1.1.1', 1),
472
 
                          ('1', 0)],
473
 
                         [(r.revno, r.merge_depth)
474
 
                            for r in self.get_captured_revisions()])
475
 
 
476
 
    def test_force_merge_revisions_off(self):
477
 
        self.assertLogRevnos(['-n1'], ['2', '1'], working_dir='level0')
478
 
 
479
 
    def test_force_merge_revisions_on(self):
480
 
        self.assertLogRevnos(['-n0'], ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
481
 
                             working_dir='level0')
482
 
 
483
 
    def test_include_merges(self):
484
 
        # Confirm --include-merges gives the same output as -n0
485
 
        self.assertLogRevnos(['--include-merges'],
486
 
                             ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
487
 
                             working_dir='level0')
488
 
        self.assertLogRevnos(['--include-merges'],
489
 
                             ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
490
 
                             working_dir='level0')
491
 
        out_im, err_im = self.run_bzr('log --include-merges',
492
 
                                      working_dir='level0')
493
 
        out_n0, err_n0 = self.run_bzr('log -n0', working_dir='level0')
494
 
        self.assertEqual('', err_im)
495
 
        self.assertEqual('', err_n0)
496
 
        self.assertEqual(out_im, out_n0)
497
 
 
498
 
    def test_force_merge_revisions_N(self):
499
 
        self.assertLogRevnos(['-n2'],
500
 
                             ['2', '1.1.2', '1.1.1', '1'],
501
 
                             working_dir='level0')
 
175
        self._prepare()
 
176
        out,err = self.run_bzr('log')
 
177
        # the log will look something like:
 
178
#        self.assertEqual("""\
 
179
#------------------------------------------------------------
 
180
#revno: 2
 
181
#committer: Robert Collins <foo@example.com>
 
182
#branch nick: parent
 
183
#timestamp: Tue 2006-03-28 22:31:40 +1100
 
184
#message:
 
185
#  merge branch 1
 
186
#    ------------------------------------------------------------
 
187
#    revno: 1.1.2  
 
188
#    committer: Robert Collins <foo@example.com>
 
189
#    branch nick: child
 
190
#    timestamp: Tue 2006-03-28 22:31:40 +1100
 
191
#    message:
 
192
#      merge branch 2
 
193
#        ------------------------------------------------------------
 
194
#        revno: 1.1.1.1
 
195
#        committer: Robert Collins <foo@example.com>
 
196
#        branch nick: smallerchild
 
197
#        timestamp: Tue 2006-03-28 22:31:40 +1100
 
198
#        message:
 
199
#          branch 2
 
200
#    ------------------------------------------------------------
 
201
#    revno: 1.1.1
 
202
#    committer: Robert Collins <foo@example.com>
 
203
#    branch nick: child
 
204
#    timestamp: Tue 2006-03-28 22:31:40 +1100
 
205
#    message:
 
206
#      branch 1
 
207
#------------------------------------------------------------
 
208
#revno: 1
 
209
#committer: Robert Collins <foo@example.com>
 
210
#branch nick: parent
 
211
#timestamp: Tue 2006-03-28 22:31:39 +1100
 
212
#message:
 
213
#  first post
 
214
#""", out)
 
215
        # but we dont have a nice pattern matcher hooked up yet, so:
 
216
        # we check for the indenting of the commit message and the 
 
217
        # revision numbers 
 
218
        self.assertTrue('revno: 2' in out)
 
219
        self.assertTrue('  merge branch 1' in out)
 
220
        self.assertTrue('    revno: 1.1.2' in out)
 
221
        self.assertTrue('      merge branch 2' in out)
 
222
        self.assertTrue('        revno: 1.1.1.1' in out)
 
223
        self.assertTrue('          branch 2' in out)
 
224
        self.assertTrue('    revno: 1.1.1' in out)
 
225
        self.assertTrue('      branch 1' in out)
 
226
        self.assertTrue('revno: 1\n' in out)
 
227
        self.assertTrue('  first post' in out)
 
228
        self.assertEqual('', err)
502
229
 
503
230
    def test_merges_single_merge_rev(self):
504
 
        self.assertLogRevnosAndDepths(['-n0', '-r1.1.2'],
505
 
                                      [('1.1.2', 0), ('1.2.1', 1)],
506
 
                                      working_dir='level0')
 
231
        self._prepare()
 
232
        out,err = self.run_bzr('log -r1.1.2')
 
233
        # the log will look something like:
 
234
#        self.assertEqual("""\
 
235
#------------------------------------------------------------
 
236
#revno: 1.1.2  
 
237
#committer: Robert Collins <foo@example.com>
 
238
#branch nick: child
 
239
#timestamp: Tue 2006-03-28 22:31:40 +1100
 
240
#message:
 
241
#  merge branch 2
 
242
#    ------------------------------------------------------------
 
243
#    revno: 1.1.1.1
 
244
#    committer: Robert Collins <foo@example.com>
 
245
#    branch nick: smallerchild
 
246
#    timestamp: Tue 2006-03-28 22:31:40 +1100
 
247
#    message:
 
248
#      branch 2
 
249
#""", out)
 
250
        # but we dont have a nice pattern matcher hooked up yet, so:
 
251
        # we check for the indenting of the commit message and the 
 
252
        # revision numbers 
 
253
        self.assertTrue('revno: 2' not in out)
 
254
        self.assertTrue('  merge branch 1' not in out)
 
255
        self.assertTrue('revno: 1.1.2' in out)
 
256
        self.assertTrue('  merge branch 2' in out)
 
257
        self.assertTrue('    revno: 1.1.1.1' in out)
 
258
        self.assertTrue('      branch 2' in out)
 
259
        self.assertTrue('revno: 1.1.1\n' not in out)
 
260
        self.assertTrue('  branch 1' not in out)
 
261
        self.assertTrue('revno: 1\n' not in out)
 
262
        self.assertTrue('  first post' not in out)
 
263
        self.assertEqual('', err)
507
264
 
508
265
    def test_merges_partial_range(self):
509
 
        self.assertLogRevnosAndDepths(
510
 
                ['-n0', '-r1.1.1..1.1.2'],
511
 
                [('1.1.2', 0), ('1.2.1', 1), ('1.1.1', 0)],
512
 
                working_dir='level0')
513
 
 
514
 
    def test_merges_partial_range_ignore_before_lower_bound(self):
515
 
        """Dont show revisions before the lower bound's merged revs"""
516
 
        self.assertLogRevnosAndDepths(
517
 
                ['-n0', '-r1.1.2..2'],
518
 
                [('2', 0), ('1.1.2', 1), ('1.2.1', 2)],
519
 
                working_dir='level0')
520
 
 
521
 
 
522
 
class TestLogDiff(TestLogWithLogCatcher):
523
 
 
524
 
    # FIXME: We need specific tests for each LogFormatter about how the diffs
525
 
    # are displayed: --long indent them by depth, --short use a fixed
526
 
    # indent and --line does't display them. -- vila 10019
527
 
 
528
 
    def setUp(self):
529
 
        super(TestLogDiff, self).setUp()
530
 
        self.make_branch_with_diffs()
531
 
 
532
 
    def make_branch_with_diffs(self):
533
 
        level0 = self.make_branch_and_tree('level0')
534
 
        self.build_tree(['level0/file1', 'level0/file2'])
535
 
        level0.add('file1')
536
 
        level0.add('file2')
537
 
        self.wt_commit(level0, 'in branch level0')
538
 
 
539
 
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
540
 
        self.build_tree_contents([('level1/file2', 'hello\n')])
541
 
        self.wt_commit(level1, 'in branch level1')
542
 
        level0.merge_from_branch(level1.branch)
543
 
        self.wt_commit(level0, 'merge branch level1')
544
 
 
545
 
    def _diff_file1_revno1(self):
546
 
        return """=== added file 'file1'
547
 
--- file1\t1970-01-01 00:00:00 +0000
548
 
+++ file1\t2005-11-22 00:00:00 +0000
549
 
@@ -0,0 +1,1 @@
550
 
+contents of level0/file1
551
 
 
552
 
"""
553
 
 
554
 
    def _diff_file2_revno2(self):
555
 
        return """=== modified file 'file2'
556
 
--- file2\t2005-11-22 00:00:00 +0000
557
 
+++ file2\t2005-11-22 00:00:01 +0000
558
 
@@ -1,1 +1,1 @@
559
 
-contents of level0/file2
560
 
+hello
561
 
 
562
 
"""
563
 
 
564
 
    def _diff_file2_revno1_1_1(self):
565
 
        return """=== modified file 'file2'
566
 
--- file2\t2005-11-22 00:00:00 +0000
567
 
+++ file2\t2005-11-22 00:00:01 +0000
568
 
@@ -1,1 +1,1 @@
569
 
-contents of level0/file2
570
 
+hello
571
 
 
572
 
"""
573
 
 
574
 
    def _diff_file2_revno1(self):
575
 
        return """=== added file 'file2'
576
 
--- file2\t1970-01-01 00:00:00 +0000
577
 
+++ file2\t2005-11-22 00:00:00 +0000
578
 
@@ -0,0 +1,1 @@
579
 
+contents of level0/file2
580
 
 
581
 
"""
582
 
 
583
 
    def assertLogRevnosAndDiff(self, args, expected,
584
 
                            working_dir='.'):
585
 
        self.run_bzr(['log', '-p'] + args, working_dir=working_dir)
586
 
        expected_revnos_and_depths = [
587
 
            (revno, depth) for revno, depth, diff in expected]
588
 
        # Check the revnos and depths first to make debugging easier
589
 
        self.assertEqual(expected_revnos_and_depths,
590
 
                         [(r.revno, r.merge_depth)
591
 
                           for r in self.get_captured_revisions()])
592
 
        # Now check the diffs, adding the revno  in case of failure
593
 
        fmt = 'In revno %s\n%s'
594
 
        for expected_rev, actual_rev in izip(expected,
595
 
                                             self.get_captured_revisions()):
596
 
            revno, depth, expected_diff = expected_rev
597
 
            actual_diff = actual_rev.diff
598
 
            self.assertEqualDiff(fmt % (revno, expected_diff),
599
 
                                 fmt % (revno, actual_diff))
600
 
 
601
 
    def test_log_diff_with_merges(self):
602
 
        self.assertLogRevnosAndDiff(
603
 
            ['-n0'],
604
 
            [('2', 0, self._diff_file2_revno2()),
605
 
             ('1.1.1', 1, self._diff_file2_revno1_1_1()),
606
 
             ('1', 0, self._diff_file1_revno1()
607
 
              + self._diff_file2_revno1())],
608
 
            working_dir='level0')
609
 
 
610
 
 
611
 
    def test_log_diff_file1(self):
612
 
        self.assertLogRevnosAndDiff(['-n0', 'file1'],
613
 
                                    [('1', 0, self._diff_file1_revno1())],
614
 
                                    working_dir='level0')
615
 
 
616
 
    def test_log_diff_file2(self):
617
 
        self.assertLogRevnosAndDiff(['-n1', 'file2'],
618
 
                                    [('2', 0, self._diff_file2_revno2()),
619
 
                                     ('1', 0, self._diff_file2_revno1())],
620
 
                                    working_dir='level0')
621
 
 
622
 
 
623
 
class TestLogUnicodeDiff(TestLog):
624
 
 
625
 
    def test_log_show_diff_non_ascii(self):
626
 
        # Smoke test for bug #328007 UnicodeDecodeError on 'log -p'
627
 
        message = u'Message with \xb5'
628
 
        body = 'Body with \xb5\n'
629
 
        wt = self.make_branch_and_tree('.')
630
 
        self.build_tree_contents([('foo', body)])
631
 
        wt.add('foo')
632
 
        wt.commit(message=message)
633
 
        # check that command won't fail with unicode error
634
 
        # don't care about exact output because we have other tests for this
635
 
        out,err = self.run_bzr('log -p --long')
636
 
        self.assertNotEqual('', out)
637
 
        self.assertEqual('', err)
638
 
        out,err = self.run_bzr('log -p --short')
639
 
        self.assertNotEqual('', out)
640
 
        self.assertEqual('', err)
641
 
        out,err = self.run_bzr('log -p --line')
642
 
        self.assertNotEqual('', out)
643
 
        self.assertEqual('', err)
644
 
 
645
 
 
646
 
class TestLogEncodings(tests.TestCaseInTempDir):
 
266
        self._prepare()
 
267
        out,err = self.run_bzr('log -r1.1.1..1.1.2')
 
268
        # the log will look something like:
 
269
#        self.assertEqual("""\
 
270
#------------------------------------------------------------
 
271
#revno: 1.1.2  
 
272
#committer: Robert Collins <foo@example.com>
 
273
#branch nick: child
 
274
#timestamp: Tue 2006-03-28 22:31:40 +1100
 
275
#message:
 
276
#  merge branch 2
 
277
#    ------------------------------------------------------------
 
278
#    revno: 1.1.1.1
 
279
#    committer: Robert Collins <foo@example.com>
 
280
#    branch nick: smallerchild
 
281
#    timestamp: Tue 2006-03-28 22:31:40 +1100
 
282
#    message:
 
283
#      branch 2
 
284
#------------------------------------------------------------
 
285
#revno: 1.1.1
 
286
#committer: Robert Collins <foo@example.com>
 
287
#branch nick: child
 
288
#timestamp: Tue 2006-03-28 22:31:40 +1100
 
289
#message:
 
290
#  branch 1
 
291
#""", out)
 
292
        # but we dont have a nice pattern matcher hooked up yet, so:
 
293
        # we check for the indenting of the commit message and the 
 
294
        # revision numbers 
 
295
        self.assertTrue('revno: 2' not in out)
 
296
        self.assertTrue('  merge branch 1' not in out)
 
297
        self.assertTrue('revno: 1.1.2' in out)
 
298
        self.assertTrue('  merge branch 2' in out)
 
299
        self.assertTrue('    revno: 1.1.1.1' in out)
 
300
        self.assertTrue('      branch 2' in out)
 
301
        self.assertTrue('revno: 1.1.1' in out)
 
302
        self.assertTrue('  branch 1' in out)
 
303
        self.assertTrue('revno: 1\n' not in out)
 
304
        self.assertTrue('  first post' not in out)
 
305
        self.assertEqual('', err)
 
306
 
 
307
 
 
308
class TestLogEncodings(TestCaseInTempDir):
647
309
 
648
310
    _mu = u'\xb5'
649
311
    _message = u'Message with \xb5'
654
316
        'latin-1',
655
317
        'iso-8859-1',
656
318
        'cp437', # Common windows encoding
657
 
        'cp1251', # Russian windows encoding
 
319
        'cp1251', # Alexander Belchenko's windows encoding
658
320
        'cp1258', # Common windows encoding
659
321
    ]
660
322
    # Encodings which cannot encode mu
665
327
    ]
666
328
 
667
329
    def setUp(self):
668
 
        super(TestLogEncodings, self).setUp()
669
 
        self.overrideAttr(osutils, '_cached_user_encoding')
 
330
        TestCaseInTempDir.setUp(self)
 
331
        self.user_encoding = bzrlib.user_encoding
 
332
 
 
333
    def tearDown(self):
 
334
        bzrlib.user_encoding = self.user_encoding
 
335
        TestCaseInTempDir.tearDown(self)
670
336
 
671
337
    def create_branch(self):
672
338
        bzr = self.run_bzr
673
339
        bzr('init')
674
 
        self.build_tree_contents([('a', 'some stuff\n')])
 
340
        open('a', 'wb').write('some stuff\n')
675
341
        bzr('add a')
676
342
        bzr(['commit', '-m', self._message])
677
343
 
684
350
        else:
685
351
            encoded_msg = self._message.encode(encoding)
686
352
 
687
 
        old_encoding = osutils._cached_user_encoding
 
353
        old_encoding = bzrlib.user_encoding
688
354
        # This test requires that 'run_bzr' uses the current
689
355
        # bzrlib, because we override user_encoding, and expect
690
356
        # it to be used
691
357
        try:
692
 
            osutils._cached_user_encoding = 'ascii'
 
358
            bzrlib.user_encoding = 'ascii'
693
359
            # We should be able to handle any encoding
694
360
            out, err = bzr('log', encoding=encoding)
695
361
            if not fail:
700
366
            else:
701
367
                self.assertNotEqual(-1, out.find('Message with ?'))
702
368
        finally:
703
 
            osutils._cached_user_encoding = old_encoding
 
369
            bzrlib.user_encoding = old_encoding
704
370
 
705
371
    def test_log_handles_encoding(self):
706
372
        self.create_branch()
716
382
 
717
383
    def test_stdout_encoding(self):
718
384
        bzr = self.run_bzr
719
 
        osutils._cached_user_encoding = "cp1251"
 
385
        bzrlib.user_encoding = "cp1251"
720
386
 
721
387
        bzr('init')
722
388
        self.build_tree(['a'])
740
406
        self.assertEquals(-1, stdout.find(test_in_cp1251))
741
407
 
742
408
 
743
 
class TestLogFile(TestLogWithLogCatcher):
 
409
class TestLogFile(TestCaseWithTransport):
744
410
 
745
411
    def test_log_local_branch_file(self):
746
412
        """We should be able to log files in local treeless branches"""
751
417
        tree.bzrdir.destroy_workingtree()
752
418
        self.run_bzr('log tree/file')
753
419
 
754
 
    def prepare_tree(self, complex=False):
755
 
        # The complex configuration includes deletes and renames
 
420
    def test_log_file(self):
 
421
        """The log for a particular file should only list revs for that file"""
756
422
        tree = self.make_branch_and_tree('parent')
757
423
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
758
424
        tree.add('file1')
766
432
        child_tree.commit(message='branch 1')
767
433
        tree.merge_from_branch(child_tree.branch)
768
434
        tree.commit(message='merge child branch')
769
 
        if complex:
770
 
            tree.remove('file2')
771
 
            tree.commit('remove file2')
772
 
            tree.rename_one('file3', 'file4')
773
 
            tree.commit('file3 is now called file4')
774
 
            tree.remove('file1')
775
 
            tree.commit('remove file1')
776
 
        os.chdir('parent')
777
 
 
778
 
    # FIXME: It would be good to parametrize the following tests against all
779
 
    # formatters. But the revisions selection is not *currently* part of the
780
 
    # LogFormatter contract, so using LogCatcher is sufficient -- vila 100118
781
 
    def test_log_file1(self):
782
 
        self.prepare_tree()
783
 
        self.assertLogRevnos(['-n0', 'file1'], ['1'])
784
 
 
785
 
    def test_log_file2(self):
786
 
        self.prepare_tree()
787
 
        # file2 full history
788
 
        self.assertLogRevnos(['-n0', 'file2'], ['4', '3.1.1', '2'])
789
 
        # file2 in a merge revision
790
 
        self.assertLogRevnos(['-n0', '-r3.1.1', 'file2'], ['3.1.1'])
791
 
        # file2 in a mainline revision
792
 
        self.assertLogRevnos(['-n0', '-r4', 'file2'], ['4', '3.1.1'])
793
 
        # file2 since a revision
794
 
        self.assertLogRevnos(['-n0', '-r3..', 'file2'], ['4', '3.1.1'])
795
 
        # file2 up to a revision
796
 
        self.assertLogRevnos(['-n0', '-r..3', 'file2'], ['2'])
797
 
 
798
 
    def test_log_file3(self):
799
 
        self.prepare_tree()
800
 
        self.assertLogRevnos(['-n0', 'file3'], ['3'])
801
 
 
802
 
    def test_log_file_historical_missing(self):
803
 
        # Check logging a deleted file gives an error if the
804
 
        # file isn't found at the end or start of the revision range
805
 
        self.prepare_tree(complex=True)
806
 
        err_msg = "Path unknown at end or start of revision range: file2"
807
 
        err = self.run_bzr('log file2', retcode=3)[1]
808
 
        self.assertContainsRe(err, err_msg)
809
 
 
810
 
    def test_log_file_historical_end(self):
811
 
        # Check logging a deleted file is ok if the file existed
812
 
        # at the end the revision range
813
 
        self.prepare_tree(complex=True)
814
 
        self.assertLogRevnos(['-n0', '-r..4', 'file2'], ['4', '3.1.1', '2'])
815
 
 
816
 
    def test_log_file_historical_start(self):
817
 
        # Check logging a deleted file is ok if the file existed
818
 
        # at the start of the revision range
819
 
        self.prepare_tree(complex=True)
820
 
        self.assertLogRevnos(['file1'], ['1'])
821
 
 
822
 
    def test_log_file_renamed(self):
823
 
        """File matched against revision range, not current tree."""
824
 
        self.prepare_tree(complex=True)
825
 
 
826
 
        # Check logging a renamed file gives an error by default
827
 
        err_msg = "Path unknown at end or start of revision range: file3"
828
 
        err = self.run_bzr('log file3', retcode=3)[1]
829
 
        self.assertContainsRe(err, err_msg)
830
 
 
831
 
        # Check we can see a renamed file if we give the right end revision
832
 
        self.assertLogRevnos(['-r..4', 'file3'], ['3'])
833
 
 
834
 
 
835
 
class TestLogMultiple(TestLogWithLogCatcher):
836
 
 
837
 
    def prepare_tree(self):
838
 
        tree = self.make_branch_and_tree('parent')
839
 
        self.build_tree([
840
 
            'parent/file1',
841
 
            'parent/file2',
842
 
            'parent/dir1/',
843
 
            'parent/dir1/file5',
844
 
            'parent/dir1/dir2/',
845
 
            'parent/dir1/dir2/file3',
846
 
            'parent/file4'])
847
 
        tree.add('file1')
848
 
        tree.commit('add file1')
849
 
        tree.add('file2')
850
 
        tree.commit('add file2')
851
 
        tree.add(['dir1', 'dir1/dir2', 'dir1/dir2/file3'])
852
 
        tree.commit('add file3')
853
 
        tree.add('file4')
854
 
        tree.commit('add file4')
855
 
        tree.add('dir1/file5')
856
 
        tree.commit('add file5')
857
 
        child_tree = tree.bzrdir.sprout('child').open_workingtree()
858
 
        self.build_tree_contents([('child/file2', 'hello')])
859
 
        child_tree.commit(message='branch 1')
860
 
        tree.merge_from_branch(child_tree.branch)
861
 
        tree.commit(message='merge child branch')
862
 
        os.chdir('parent')
863
 
 
864
 
    def test_log_files(self):
865
 
        """The log for multiple file should only list revs for those files"""
866
 
        self.prepare_tree()
867
 
        self.assertLogRevnos(['file1', 'file2', 'dir1/dir2/file3'],
868
 
                             ['6', '5.1.1', '3', '2', '1'])
869
 
 
870
 
    def test_log_directory(self):
871
 
        """The log for a directory should show all nested files."""
872
 
        self.prepare_tree()
873
 
        self.assertLogRevnos(['dir1'], ['5', '3'])
874
 
 
875
 
    def test_log_nested_directory(self):
876
 
        """The log for a directory should show all nested files."""
877
 
        self.prepare_tree()
878
 
        self.assertLogRevnos(['dir1/dir2'], ['3'])
879
 
 
880
 
    def test_log_in_nested_directory(self):
881
 
        """The log for a directory should show all nested files."""
882
 
        self.prepare_tree()
883
 
        os.chdir("dir1")
884
 
        self.assertLogRevnos(['.'], ['5', '3'])
885
 
 
886
 
    def test_log_files_and_directories(self):
887
 
        """Logging files and directories together should be fine."""
888
 
        self.prepare_tree()
889
 
        self.assertLogRevnos(['file4', 'dir1/dir2'], ['4', '3'])
890
 
 
891
 
    def test_log_files_and_dirs_in_nested_directory(self):
892
 
        """The log for a directory should show all nested files."""
893
 
        self.prepare_tree()
894
 
        os.chdir("dir1")
895
 
        self.assertLogRevnos(['dir2', 'file5'], ['5', '3'])
 
435
        os.chdir('parent')
 
436
        log = self.run_bzr('log file1')[0]
 
437
        self.assertContainsRe(log, 'revno: 1\n')
 
438
        self.assertNotContainsRe(log, 'revno: 2\n')
 
439
        self.assertNotContainsRe(log, 'revno: 3\n')
 
440
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
441
        self.assertNotContainsRe(log, 'revno: 4\n')
 
442
        log = self.run_bzr('log file2')[0]
 
443
        self.assertNotContainsRe(log, 'revno: 1\n')
 
444
        self.assertContainsRe(log, 'revno: 2\n')
 
445
        self.assertNotContainsRe(log, 'revno: 3\n')
 
446
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
447
        self.assertContainsRe(log, 'revno: 4\n')
 
448
        log = self.run_bzr('log file3')[0]
 
449
        self.assertNotContainsRe(log, 'revno: 1\n')
 
450
        self.assertNotContainsRe(log, 'revno: 2\n')
 
451
        self.assertContainsRe(log, 'revno: 3\n')
 
452
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
453
        self.assertNotContainsRe(log, 'revno: 4\n')
 
454
        log = self.run_bzr('log -r3.1.1 file2')[0]
 
455
        self.assertNotContainsRe(log, 'revno: 1\n')
 
456
        self.assertNotContainsRe(log, 'revno: 2\n')
 
457
        self.assertNotContainsRe(log, 'revno: 3\n')
 
458
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
459
        self.assertNotContainsRe(log, 'revno: 4\n')
 
460
        log = self.run_bzr('log -r4 file2')[0]
 
461
        self.assertNotContainsRe(log, 'revno: 1\n')
 
462
        self.assertNotContainsRe(log, 'revno: 2\n')
 
463
        self.assertNotContainsRe(log, 'revno: 3\n')
 
464
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
465
        self.assertContainsRe(log, 'revno: 4\n')
 
466
        log = self.run_bzr('log -r3.. file2')[0]
 
467
        self.assertNotContainsRe(log, 'revno: 1\n')
 
468
        self.assertNotContainsRe(log, 'revno: 2\n')
 
469
        self.assertNotContainsRe(log, 'revno: 3\n')
 
470
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
471
        self.assertContainsRe(log, 'revno: 4\n')
 
472
        log = self.run_bzr('log -r..3 file2')[0]
 
473
        self.assertNotContainsRe(log, 'revno: 1\n')
 
474
        self.assertContainsRe(log, 'revno: 2\n')
 
475
        self.assertNotContainsRe(log, 'revno: 3\n')
 
476
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
477
        self.assertNotContainsRe(log, 'revno: 4\n')