~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Vincent Ladeuil
  • Date: 2010-01-25 15:55:48 UTC
  • mto: (4985.1.4 add-attr-cleanup)
  • mto: This revision was merged to the branch mainline in revision 4988.
  • Revision ID: v.ladeuil+lp@free.fr-20100125155548-0l352pujvt5bzl5e
Deploy addAttrCleanup on the whole test suite.

Several use case worth mentioning:

- setting a module or any other object attribute is the majority
by far. In some cases the setting itself is deferred but most of
the time we want to set at the same time we add the cleanup.

- there multiple occurrences of protecting hooks or ui factory
which are now useless (the test framework takes care of that now),

- there was some lambda uses that can now be avoided.

That first cleanup already simplifies things a lot.

Show diffs side-by-side

added added

removed removed

Lines of Context:
17
17
 
18
18
"""Black-box tests for bzr log."""
19
19
 
 
20
from itertools import izip
20
21
import os
21
22
import re
22
23
 
23
24
from bzrlib import (
 
25
    branchbuilder,
 
26
    log,
24
27
    osutils,
25
28
    tests,
26
29
    )
27
 
from bzrlib.tests import test_log
28
 
 
29
 
 
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
 
30
from bzrlib.tests import (
 
31
    script,
 
32
    test_log,
 
33
    )
 
34
 
 
35
 
 
36
class TestLog(tests.TestCaseWithTransport, test_log.TestLogMixin):
36
37
 
37
38
    def make_minimal_branch(self, path='.', format=None):
38
39
        tree = self.make_branch_and_tree(path, format=format)
63
64
        tree.commit(message='merge')
64
65
        return tree
65
66
 
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):
 
67
 
 
68
class TestLogWithLogCatcher(TestLog):
 
69
 
 
70
    def setUp(self):
 
71
        super(TestLogWithLogCatcher, self).setUp()
 
72
        # Capture log formatter creations
 
73
        class MyLogFormatter(test_log.LogCatcher):
 
74
 
 
75
            def __new__(klass, *args, **kwargs):
 
76
                self.log_catcher = test_log.LogCatcher(*args, **kwargs)
 
77
                # Always return our own log formatter
 
78
                return self.log_catcher
 
79
 
 
80
        self.addAttrCleanup(log.log_formatter_registry, 'get_default')
 
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
        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'])
95
109
 
96
110
    def test_log_null_end_revspec(self):
97
111
        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)
105
 
 
106
 
        full_log = self.run_bzr(['log'])[0]
107
 
        log = self.run_bzr("log -r 1..")[0]
108
 
        self.assertEqualDiff(log, full_log)
 
112
        self.assertLogRevnos(['-r1..'], ['3', '2', '1'])
109
113
 
110
114
    def test_log_null_begin_revspec(self):
111
115
        self.make_linear_branch()
112
 
        full_log = self.run_bzr(['log'])[0]
113
 
        log = self.run_bzr("log -r ..3")[0]
114
 
        self.assertEqualDiff(full_log, log)
 
116
        self.assertLogRevnos(['-r..3'], ['3', '2', '1'])
115
117
 
116
118
    def test_log_null_both_revspecs(self):
117
119
        self.make_linear_branch()
118
 
        full_log = self.run_bzr(['log'])[0]
119
 
        log = self.run_bzr("log -r ..")[0]
120
 
        self.assertEqualDiff(full_log, log)
121
 
 
122
 
    def test_log_zero_revspec(self):
123
 
        self.make_minimal_branch()
124
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
125
 
                           ['log', '-r0'])
126
 
 
127
 
    def test_log_zero_begin_revspec(self):
128
 
        self.make_linear_branch()
129
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
130
 
                           ['log', '-r0..2'])
131
 
 
132
 
    def test_log_zero_end_revspec(self):
133
 
        self.make_linear_branch()
134
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
135
 
                           ['log', '-r-2..0'])
 
120
        self.assertLogRevnos(['-r..'], ['3', '2', '1'])
136
121
 
137
122
    def test_log_negative_begin_revspec_full_log(self):
138
123
        self.make_linear_branch()
139
 
        full_log = self.run_bzr(['log'])[0]
140
 
        log = self.run_bzr("log -r -3..")[0]
141
 
        self.assertEqualDiff(full_log, log)
 
124
        self.assertLogRevnos(['-r-3..'], ['3', '2', '1'])
142
125
 
143
126
    def test_log_negative_both_revspec_full_log(self):
144
127
        self.make_linear_branch()
145
 
        full_log = self.run_bzr(['log'])[0]
146
 
        log = self.run_bzr("log -r -3..-1")[0]
147
 
        self.assertEqualDiff(full_log, log)
 
128
        self.assertLogRevnos(['-r-3..-1'], ['3', '2', '1'])
148
129
 
149
130
    def test_log_negative_both_revspec_partial(self):
150
131
        self.make_linear_branch()
151
 
        log = self.run_bzr("log -r -3..-2")[0]
152
 
        self.assertTrue('revno: 1\n' in log)
153
 
        self.assertTrue('revno: 2\n' in log)
154
 
        self.assertTrue('revno: 3\n' not in log)
 
132
        self.assertLogRevnos(['-r-3..-2'], ['2', '1'])
155
133
 
156
134
    def test_log_negative_begin_revspec(self):
157
135
        self.make_linear_branch()
158
 
        log = self.run_bzr("log -r -2..")[0]
159
 
        self.assertTrue('revno: 1\n' not in log)
160
 
        self.assertTrue('revno: 2\n' in log)
161
 
        self.assertTrue('revno: 3\n' in log)
 
136
        self.assertLogRevnos(['-r-2..'], ['3', '2'])
162
137
 
163
138
    def test_log_positive_revspecs(self):
164
139
        self.make_linear_branch()
165
 
        full_log = self.run_bzr(['log'])[0]
166
 
        log = self.run_bzr("log -r 1..3")[0]
167
 
        self.assertEqualDiff(full_log, log)
 
140
        self.assertLogRevnos(['-r1..3'], ['3', '2', '1'])
168
141
 
169
142
    def test_log_dotted_revspecs(self):
170
143
        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))
173
 
 
174
 
    def test_log_reversed_revspecs(self):
175
 
        self.make_linear_branch()
176
 
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
177
 
                            'the end revision.\n',),
178
 
                           ['log', '-r3..1'])
179
 
 
180
 
    def test_log_reversed_dotted_revspecs(self):
181
 
        self.make_merged_branch()
182
 
        self.run_bzr_error(('bzr: ERROR: Start revision not found in '
183
 
                            'left-hand history of end revision.\n',),
184
 
                           "log -r 1.1.1..1")
 
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 TestBug474807(TestLogWithLogCatcher):
 
163
 
 
164
    def setUp(self):
 
165
        super(TestBug474807, 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 TestLogRevSpecsWithPaths(TestLogWithLogCatcher):
 
207
 
 
208
    def test_log_revno_n_path_wrong_namespace(self):
 
209
        self.make_linear_branch('branch1')
 
210
        self.make_linear_branch('branch2')
 
211
        # There is no guarantee that a path exist between two arbitrary
 
212
        # revisions.
 
213
        self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)
 
214
        # But may be it's worth trying though ? -- vila 100115
 
215
 
 
216
    def test_log_revno_n_path_correct_order(self):
 
217
        self.make_linear_branch('branch2')
 
218
        self.assertLogRevnos(['-rrevno:1:branch2..revno:3:branch2'],
 
219
                             ['3', '2','1'])
185
220
 
186
221
    def test_log_revno_n_path(self):
187
 
        self.make_linear_branch('branch1')
188
222
        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
192
 
        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)
195
 
        log = self.run_bzr("log -r revno:1:branch2")[0]
196
 
        self.assertTrue('revno: 1\n' in log)
197
 
        self.assertTrue('revno: 2\n' not in log)
198
 
        self.assertTrue('branch nick: branch2\n' in log)
199
 
        self.assertTrue('branch nick: branch1\n' not in log)
 
223
        self.assertLogRevnos(['-rrevno:1:branch2'],
 
224
                             ['1'])
 
225
        rev_props = self.log_catcher.revisions[0].rev.properties
 
226
        self.assertEqual('branch2', rev_props['branch-nick'])
 
227
 
 
228
 
 
229
class TestLogErrors(TestLog):
 
230
 
 
231
    def test_log_zero_revspec(self):
 
232
        self.make_minimal_branch()
 
233
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
234
                           ['log', '-r0'])
 
235
 
 
236
    def test_log_zero_begin_revspec(self):
 
237
        self.make_linear_branch()
 
238
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
239
                           ['log', '-r0..2'])
 
240
 
 
241
    def test_log_zero_end_revspec(self):
 
242
        self.make_linear_branch()
 
243
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
 
244
                           ['log', '-r-2..0'])
200
245
 
201
246
    def test_log_nonexistent_revno(self):
202
247
        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'])
 
248
        self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
 
249
                            "does not exist in branch:"],
 
250
                           ['log', '-r1234'])
207
251
 
208
252
    def test_log_nonexistent_dotted_revno(self):
209
253
        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)
 
254
        self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
 
255
                            "does not exist in branch:"],
 
256
                           ['log',  '-r123.123'])
220
257
 
221
258
    def test_log_change_nonexistent_revno(self):
222
259
        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'])
 
260
        self.run_bzr_error(["bzr: ERROR: Requested revision: '1234' "
 
261
                            "does not exist in branch:"],
 
262
                           ['log',  '-c1234'])
227
263
 
228
264
    def test_log_change_nonexistent_dotted_revno(self):
229
265
        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'])
 
266
        self.run_bzr_error(["bzr: ERROR: Requested revision: '123.123' "
 
267
                            "does not exist in branch:"],
 
268
                           ['log', '-c123.123'])
234
269
 
235
270
    def test_log_change_single_revno_only(self):
236
271
        self.make_minimal_branch()
252
287
                              'Path unknown at end or start of revision range: '
253
288
                              'does-not-exist')
254
289
 
 
290
    def test_log_reversed_revspecs(self):
 
291
        self.make_linear_branch()
 
292
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
 
293
                            'the end revision.\n',),
 
294
                           ['log', '-r3..1'])
 
295
 
 
296
    def test_log_reversed_dotted_revspecs(self):
 
297
        self.make_merged_branch()
 
298
        self.run_bzr_error(('bzr: ERROR: Start revision not found in '
 
299
                            'left-hand history of end revision.\n',),
 
300
                           "log -r 1.1.1..1")
 
301
 
 
302
    def test_log_bad_message_re(self):
 
303
        """Bad --message argument gives a sensible message
 
304
        
 
305
        See https://bugs.launchpad.net/bzr/+bug/251352
 
306
        """
 
307
        self.make_minimal_branch()
 
308
        out, err = self.run_bzr(['log', '-m', '*'], retcode=3)
 
309
        self.assertEqual("bzr: ERROR: Invalid regular expression"
 
310
            " in log message filter"
 
311
            ": '*'"
 
312
            ": nothing to repeat\n", err)
 
313
        self.assertEqual('', out)
 
314
 
 
315
    def test_log_unsupported_timezone(self):
 
316
        self.make_linear_branch()
 
317
        self.run_bzr_error(['bzr: ERROR: Unsupported timezone format "foo", '
 
318
                            'options are "utc", "original", "local".'],
 
319
                           ['log', '--timezone', 'foo'])
 
320
 
 
321
 
 
322
class TestLogTags(TestLog):
 
323
 
255
324
    def test_log_with_tags(self):
256
325
        tree = self.make_linear_branch(format='dirstate-tags')
257
326
        branch = tree.branch
282
351
        log = self.run_bzr("log -n0 -r3.1.1", working_dir='branch2')[0]
283
352
        self.assertContainsRe(log, r'tags: tag1')
284
353
 
285
 
    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)
290
 
        log = self.run_bzr("log --limit 2")[0]
291
 
        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')
301
 
 
302
 
    def test_log_limit_short(self):
303
 
        self.make_linear_branch()
304
 
        log = self.run_bzr("log -l 2")[0]
305
 
        self.assertNotContainsRe(log, r'revno: 1\n')
306
 
        self.assertContainsRe(log, r'revno: 2\n')
307
 
        self.assertContainsRe(log, r'revno: 3\n')
308
 
 
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
354
 
332
355
class TestLogVerbose(TestLog):
333
356
 
364
387
        self.assertUseLongDeltaFormat(['log', '--long', '-vv'])
365
388
 
366
389
 
367
 
class TestLogMerges(TestLog):
 
390
class TestLogMerges(TestLogWithLogCatcher):
368
391
 
369
392
    def setUp(self):
370
393
        super(TestLogMerges, self).setUp()
372
395
 
373
396
    def make_branches_with_merges(self):
374
397
        level0 = self.make_branch_and_tree('level0')
375
 
        level0.commit(message='in branch level0', **self.commit_options())
376
 
 
 
398
        self.wt_commit(level0, 'in branch level0')
377
399
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
378
 
        level1.commit(message='in branch level1', **self.commit_options())
379
 
 
 
400
        self.wt_commit(level1, 'in branch level1')
380
401
        level2 = level1.bzrdir.sprout('level2').open_workingtree()
381
 
        level2.commit(message='in branch level2', **self.commit_options())
382
 
 
 
402
        self.wt_commit(level2, 'in branch level2')
383
403
        level1.merge_from_branch(level2.branch)
384
 
        level1.commit(message='merge branch level2', **self.commit_options())
385
 
 
 
404
        self.wt_commit(level1, 'merge branch level2')
386
405
        level0.merge_from_branch(level1.branch)
387
 
        level0.commit(message='merge branch level1', **self.commit_options())
 
406
        self.wt_commit(level0, 'merge branch level1')
388
407
 
389
408
    def test_merges_are_indented_by_level(self):
390
 
        expected = """\
391
 
------------------------------------------------------------
392
 
revno: 2 [merge]
393
 
committer: Lorem Ipsum <test@example.com>
394
 
branch nick: level0
395
 
timestamp: Just now
396
 
message:
397
 
  merge branch level1
398
 
    ------------------------------------------------------------
399
 
    revno: 1.1.2 [merge]
400
 
    committer: Lorem Ipsum <test@example.com>
401
 
    branch nick: level1
402
 
    timestamp: Just now
403
 
    message:
404
 
      merge branch level2
405
 
        ------------------------------------------------------------
406
 
        revno: 1.2.1
407
 
        committer: Lorem Ipsum <test@example.com>
408
 
        branch nick: level2
409
 
        timestamp: Just now
410
 
        message:
411
 
          in branch level2
412
 
    ------------------------------------------------------------
413
 
    revno: 1.1.1
414
 
    committer: Lorem Ipsum <test@example.com>
415
 
    branch nick: level1
416
 
    timestamp: Just now
417
 
    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'])
 
409
        self.run_bzr(['log', '-n0'], working_dir='level0')
 
410
        revnos_and_depth = [(r.revno, r.merge_depth)
 
411
                            for r in self.get_captured_revisions()]
 
412
        self.assertEqual([('2', 0), ('1.1.2', 1), ('1.2.1', 2), ('1.1.1', 1),
 
413
                          ('1', 0)],
 
414
                         [(r.revno, r.merge_depth)
 
415
                            for r in self.get_captured_revisions()])
428
416
 
429
417
    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'])
 
418
        self.assertLogRevnos(['-n1'], ['2', '1'], working_dir='level0')
447
419
 
448
420
    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'])
 
421
        self.assertLogRevnos(['-n0'], ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
 
422
                             working_dir='level0')
467
423
 
468
424
    def test_include_merges(self):
469
425
        # Confirm --include-merges gives the same output as -n0
 
426
        self.assertLogRevnos(['--include-merges'],
 
427
                             ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
 
428
                             working_dir='level0')
 
429
        self.assertLogRevnos(['--include-merges'],
 
430
                             ['2', '1.1.2', '1.2.1', '1.1.1', '1'],
 
431
                             working_dir='level0')
470
432
        out_im, err_im = self.run_bzr('log --include-merges',
471
433
                                      working_dir='level0')
472
434
        out_n0, err_n0 = self.run_bzr('log -n0', working_dir='level0')
475
437
        self.assertEqual(out_im, out_n0)
476
438
 
477
439
    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'])
 
440
        self.assertLogRevnos(['-n2'],
 
441
                             ['2', '1.1.2', '1.1.1', '1'],
 
442
                             working_dir='level0')
493
443
 
494
444
    def test_merges_single_merge_rev(self):
495
 
        expected = """\
496
 
------------------------------------------------------------
497
 
revno: 1.1.2 [merge]
498
 
committer: Lorem Ipsum <test@example.com>
499
 
branch nick: level1
500
 
timestamp: Just now
501
 
message:
502
 
  merge branch level2
503
 
    ------------------------------------------------------------
504
 
    revno: 1.2.1
505
 
    committer: Lorem Ipsum <test@example.com>
506
 
    branch nick: level2
507
 
    timestamp: Just now
508
 
    message:
509
 
      in branch level2
510
 
"""
511
 
        self.check_log(expected, ['-n0', '-r1.1.2'])
 
445
        self.assertLogRevnosAndDepths(['-n0', '-r1.1.2'],
 
446
                                      [('1.1.2', 0), ('1.2.1', 1)],
 
447
                                      working_dir='level0')
512
448
 
513
449
    def test_merges_partial_range(self):
514
 
        expected = """\
515
 
------------------------------------------------------------
516
 
revno: 1.1.2 [merge]
517
 
committer: Lorem Ipsum <test@example.com>
518
 
branch nick: level1
519
 
timestamp: Just now
520
 
message:
521
 
  merge branch level2
522
 
    ------------------------------------------------------------
523
 
    revno: 1.2.1
524
 
    committer: Lorem Ipsum <test@example.com>
525
 
    branch nick: level2
526
 
    timestamp: Just now
527
 
    message:
528
 
      in branch level2
529
 
------------------------------------------------------------
530
 
revno: 1.1.1
531
 
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):
 
450
        self.assertLogRevnosAndDepths(
 
451
                ['-n0', '-r1.1.1..1.1.2'],
 
452
                [('1.1.2', 0), ('1.2.1', 1), ('1.1.1', 0)],
 
453
                working_dir='level0')
 
454
 
 
455
    def test_merges_partial_range_ignore_before_lower_bound(self):
 
456
        """Dont show revisions before the lower bound's merged revs"""
 
457
        self.assertLogRevnosAndDepths(
 
458
                ['-n0', '-r1.1.2..2'],
 
459
                [('2', 0), ('1.1.2', 1), ('1.2.1', 2)],
 
460
                working_dir='level0')
 
461
 
 
462
 
 
463
class TestLogDiff(TestLogWithLogCatcher):
 
464
 
 
465
    # FIXME: We need specific tests for each LogFormatter about how the diffs
 
466
    # are displayed: --long indent them by depth, --short use a fixed
 
467
    # indent and --line does't display them. -- vila 10019
541
468
 
542
469
    def setUp(self):
543
470
        super(TestLogDiff, self).setUp()
548
475
        self.build_tree(['level0/file1', 'level0/file2'])
549
476
        level0.add('file1')
550
477
        level0.add('file2')
551
 
        level0.commit(message='in branch level0', **self.commit_options())
 
478
        self.wt_commit(level0, 'in branch level0')
552
479
 
553
480
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
554
481
        self.build_tree_contents([('level1/file2', 'hello\n')])
555
 
        level1.commit(message='in branch level1', **self.commit_options())
 
482
        self.wt_commit(level1, 'in branch level1')
556
483
        level0.merge_from_branch(level1.branch)
557
 
        level0.commit(message='merge branch level1', **self.commit_options())
 
484
        self.wt_commit(level0, 'merge branch level1')
558
485
 
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'
 
486
    def _diff_file1_revno1(self):
 
487
        return """=== added file 'file1'
601
488
--- file1\t1970-01-01 00:00:00 +0000
602
 
+++ file1\t2005-11-22 00:00:01 +0000
 
489
+++ file1\t2005-11-22 00:00:00 +0000
603
490
@@ -0,0 +1,1 @@
604
491
+contents of level0/file1
605
492
 
606
 
=== added file 'file2'
 
493
"""
 
494
 
 
495
    def _diff_file2_revno2(self):
 
496
        return """=== modified file 'file2'
 
497
--- file2\t2005-11-22 00:00:00 +0000
 
498
+++ file2\t2005-11-22 00:00:01 +0000
 
499
@@ -1,1 +1,1 @@
 
500
-contents of level0/file2
 
501
+hello
 
502
 
 
503
"""
 
504
 
 
505
    def _diff_file2_revno1_1_1(self):
 
506
        return """=== modified file 'file2'
 
507
--- file2\t2005-11-22 00:00:00 +0000
 
508
+++ file2\t2005-11-22 00:00:01 +0000
 
509
@@ -1,1 +1,1 @@
 
510
-contents of level0/file2
 
511
+hello
 
512
 
 
513
"""
 
514
 
 
515
    def _diff_file2_revno1(self):
 
516
        return """=== added file 'file2'
607
517
--- file2\t1970-01-01 00:00:00 +0000
608
 
+++ file2\t2005-11-22 00:00:01 +0000
 
518
+++ file2\t2005-11-22 00:00:00 +0000
609
519
@@ -0,0 +1,1 @@
610
520
+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'])
 
521
 
 
522
"""
 
523
 
 
524
    def assertLogRevnosAndDiff(self, args, expected,
 
525
                            working_dir='.'):
 
526
        self.run_bzr(['log', '-p'] + args, working_dir=working_dir)
 
527
        expected_revnos_and_depths = [
 
528
            (revno, depth) for revno, depth, diff in expected]
 
529
        # Check the revnos and depths first to make debugging easier
 
530
        self.assertEqual(expected_revnos_and_depths,
 
531
                         [(r.revno, r.merge_depth)
 
532
                           for r in self.get_captured_revisions()])
 
533
        # Now check the diffs, adding the revno  in case of failure
 
534
        fmt = 'In revno %s\n%s'
 
535
        for expected_rev, actual_rev in izip(expected,
 
536
                                             self.get_captured_revisions()):
 
537
            revno, depth, expected_diff = expected_rev
 
538
            actual_diff = actual_rev.diff
 
539
            self.assertEqualDiff(fmt % (revno, expected_diff),
 
540
                                 fmt % (revno, actual_diff))
 
541
 
 
542
    def test_log_diff_with_merges(self):
 
543
        self.assertLogRevnosAndDiff(
 
544
            ['-n0'],
 
545
            [('2', 0, self._diff_file2_revno2()),
 
546
             ('1.1.1', 1, self._diff_file2_revno1_1_1()),
 
547
             ('1', 0, self._diff_file1_revno1()
 
548
              + self._diff_file2_revno1())],
 
549
            working_dir='level0')
 
550
 
 
551
 
 
552
    def test_log_diff_file1(self):
 
553
        self.assertLogRevnosAndDiff(['-n0', 'file1'],
 
554
                                    [('1', 0, self._diff_file1_revno1())],
 
555
                                    working_dir='level0')
 
556
 
 
557
    def test_log_diff_file2(self):
 
558
        self.assertLogRevnosAndDiff(['-n1', 'file2'],
 
559
                                    [('2', 0, self._diff_file2_revno2()),
 
560
                                     ('1', 0, self._diff_file2_revno1())],
 
561
                                    working_dir='level0')
688
562
 
689
563
 
690
564
class TestLogUnicodeDiff(TestLog):
733
607
 
734
608
    def setUp(self):
735
609
        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)
 
610
        self.addAttrCleanup(osutils, '_cached_user_encoding')
740
611
 
741
612
    def create_branch(self):
742
613
        bzr = self.run_bzr
743
614
        bzr('init')
744
 
        open('a', 'wb').write('some stuff\n')
 
615
        self.build_tree_contents([('a', 'some stuff\n')])
745
616
        bzr('add a')
746
617
        bzr(['commit', '-m', self._message])
747
618
 
810
681
        self.assertEquals(-1, stdout.find(test_in_cp1251))
811
682
 
812
683
 
813
 
class TestLogFile(tests.TestCaseWithTransport):
 
684
class TestLogFile(TestLogWithLogCatcher):
814
685
 
815
686
    def test_log_local_branch_file(self):
816
687
        """We should be able to log files in local treeless branches"""
845
716
            tree.commit('remove file1')
846
717
        os.chdir('parent')
847
718
 
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 ')
 
719
    # FIXME: It would be good to parametrize the following tests against all
 
720
    # formatters. But the revisions selection is not *currently* part of the
 
721
    # LogFormatter contract, so using LogCatcher is sufficient -- vila 100118
 
722
    def test_log_file1(self):
 
723
        self.prepare_tree()
 
724
        self.assertLogRevnos(['-n0', 'file1'], ['1'])
 
725
 
 
726
    def test_log_file2(self):
 
727
        self.prepare_tree()
 
728
        # file2 full history
 
729
        self.assertLogRevnos(['-n0', 'file2'], ['4', '3.1.1', '2'])
 
730
        # file2 in a merge revision
 
731
        self.assertLogRevnos(['-n0', '-r3.1.1', 'file2'], ['3.1.1'])
 
732
        # file2 in a mainline revision
 
733
        self.assertLogRevnos(['-n0', '-r4', 'file2'], ['4', '3.1.1'])
 
734
        # file2 since a revision
 
735
        self.assertLogRevnos(['-n0', '-r3..', 'file2'], ['4', '3.1.1'])
 
736
        # file2 up to a revision
 
737
        self.assertLogRevnos(['-n0', '-r..3', 'file2'], ['2'])
 
738
 
 
739
    def test_log_file3(self):
 
740
        self.prepare_tree()
 
741
        self.assertLogRevnos(['-n0', 'file3'], ['3'])
893
742
 
894
743
    def test_log_file_historical_missing(self):
895
744
        # Check logging a deleted file gives an error if the
903
752
        # Check logging a deleted file is ok if the file existed
904
753
        # at the end the revision range
905
754
        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 ')
 
755
        self.assertLogRevnos(['-n0', '-r..4', 'file2'], ['4', '3.1.1', '2'])
913
756
 
914
757
    def test_log_file_historical_start(self):
915
758
        # Check logging a deleted file is ok if the file existed
916
759
        # at the start of the revision range
917
760
        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 ')
 
761
        self.assertLogRevnos(['file1'], ['1'])
925
762
 
926
763
    def test_log_file_renamed(self):
927
764
        """File matched against revision range, not current tree."""
933
770
        self.assertContainsRe(err, err_msg)
934
771
 
935
772
        # 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):
 
773
        self.assertLogRevnos(['-r..4', 'file3'], ['3'])
 
774
 
 
775
 
 
776
class TestLogMultiple(TestLogWithLogCatcher):
1009
777
 
1010
778
    def prepare_tree(self):
1011
779
        tree = self.make_branch_and_tree('parent')
1034
802
        tree.commit(message='merge child branch')
1035
803
        os.chdir('parent')
1036
804
 
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
805
    def test_log_files(self):
1045
806
        """The log for multiple file should only list revs for those files"""
1046
807
        self.prepare_tree()
1047
 
        self.assertRevnos('file1 file2 dir1/dir2/file3',
1048
 
            ['6', '5.1.1', '3', '2', '1'])
 
808
        self.assertLogRevnos(['file1', 'file2', 'dir1/dir2/file3'],
 
809
                             ['6', '5.1.1', '3', '2', '1'])
1049
810
 
1050
811
    def test_log_directory(self):
1051
812
        """The log for a directory should show all nested files."""
1052
813
        self.prepare_tree()
1053
 
        self.assertRevnos('dir1', ['5', '3'])
 
814
        self.assertLogRevnos(['dir1'], ['5', '3'])
1054
815
 
1055
816
    def test_log_nested_directory(self):
1056
817
        """The log for a directory should show all nested files."""
1057
818
        self.prepare_tree()
1058
 
        self.assertRevnos('dir1/dir2', ['3'])
 
819
        self.assertLogRevnos(['dir1/dir2'], ['3'])
1059
820
 
1060
821
    def test_log_in_nested_directory(self):
1061
822
        """The log for a directory should show all nested files."""
1062
823
        self.prepare_tree()
1063
824
        os.chdir("dir1")
1064
 
        self.assertRevnos('.', ['5', '3'])
 
825
        self.assertLogRevnos(['.'], ['5', '3'])
1065
826
 
1066
827
    def test_log_files_and_directories(self):
1067
828
        """Logging files and directories together should be fine."""
1068
829
        self.prepare_tree()
1069
 
        self.assertRevnos('file4 dir1/dir2', ['4', '3'])
 
830
        self.assertLogRevnos(['file4', 'dir1/dir2'], ['4', '3'])
1070
831
 
1071
832
    def test_log_files_and_dirs_in_nested_directory(self):
1072
833
        """The log for a directory should show all nested files."""
1073
834
        self.prepare_tree()
1074
835
        os.chdir("dir1")
1075
 
        self.assertRevnos('dir2 file5', ['5', '3'])
 
836
        self.assertLogRevnos(['dir2', 'file5'], ['5', '3'])