/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: John Arbash Meinel
  • Date: 2008-11-25 18:51:48 UTC
  • mto: This revision was merged to the branch mainline in revision 3854.
  • Revision ID: john@arbash-meinel.com-20081125185148-jsfkqnzfjjqsleds
It seems we have some direct tests that don't use strings and expect a value error as well.

They would be sanitized later on by Revision. We could use that code, but this test
depends on the serializer, which Revision wouldn't know about.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
 
2
# -*- coding: utf-8 -*-
 
3
#
 
4
# This program is free software; you can redistribute it and/or modify
 
5
# it under the terms of the GNU General Public License as published by
 
6
# the Free Software Foundation; either version 2 of the License, or
 
7
# (at your option) any later version.
 
8
#
 
9
# This program is distributed in the hope that it will be useful,
 
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
# GNU General Public License for more details.
 
13
#
 
14
# You should have received a copy of the GNU General Public License
 
15
# along with this program; if not, write to the Free Software
 
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
17
 
 
18
 
 
19
"""Black-box tests for bzr log."""
 
20
 
 
21
import os
 
22
 
 
23
from bzrlib import osutils
 
24
from bzrlib.tests.blackbox import ExternalBase
 
25
from bzrlib.tests import TestCaseInTempDir, TestCaseWithTransport
 
26
from bzrlib.tests.test_log import (
 
27
    normalize_log,
 
28
    )
 
29
from bzrlib.tests import test_log
 
30
 
 
31
 
 
32
class TestCaseWithoutPropsHandler(ExternalBase, test_log.TestCaseWithoutPropsHandler):
 
33
    pass
 
34
 
 
35
 
 
36
class TestLog(ExternalBase):
 
37
 
 
38
    def _prepare(self, path='.', format=None):
 
39
        tree = self.make_branch_and_tree(path, format=format)
 
40
        self.build_tree(
 
41
            [path + '/hello.txt', path + '/goodbye.txt', path + '/meep.txt'])
 
42
        tree.add('hello.txt')
 
43
        tree.commit(message='message1')
 
44
        tree.add('goodbye.txt')
 
45
        tree.commit(message='message2')
 
46
        tree.add('meep.txt')
 
47
        tree.commit(message='message3')
 
48
        self.full_log = self.run_bzr(["log", path])[0]
 
49
        return tree
 
50
 
 
51
    def test_log_null_end_revspec(self):
 
52
        self._prepare()
 
53
        self.assertTrue('revno: 1\n' in self.full_log)
 
54
        self.assertTrue('revno: 2\n' in self.full_log)
 
55
        self.assertTrue('revno: 3\n' in self.full_log)
 
56
        self.assertTrue('message:\n  message1\n' in self.full_log)
 
57
        self.assertTrue('message:\n  message2\n' in self.full_log)
 
58
        self.assertTrue('message:\n  message3\n' in self.full_log)
 
59
 
 
60
        log = self.run_bzr("log -r 1..")[0]
 
61
        self.assertEqualDiff(log, self.full_log)
 
62
 
 
63
    def test_log_null_begin_revspec(self):
 
64
        self._prepare()
 
65
        log = self.run_bzr("log -r ..3")[0]
 
66
        self.assertEqualDiff(self.full_log, log)
 
67
 
 
68
    def test_log_null_both_revspecs(self):
 
69
        self._prepare()
 
70
        log = self.run_bzr("log -r ..")[0]
 
71
        self.assertEqualDiff(self.full_log, log)
 
72
 
 
73
    def test_log_zero_revspec(self):
 
74
        self._prepare()
 
75
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
 
76
                           ['log', '-r0'])
 
77
 
 
78
    def test_log_zero_begin_revspec(self):
 
79
        self._prepare()
 
80
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
 
81
                           ['log', '-r0..2'])
 
82
 
 
83
    def test_log_zero_end_revspec(self):
 
84
        self._prepare()
 
85
        self.run_bzr_error('bzr: ERROR: Logging revision 0 is invalid.',
 
86
                           ['log', '-r-2..0'])
 
87
 
 
88
    def test_log_unsupported_timezone(self):
 
89
        self._prepare()
 
90
        self.run_bzr_error('bzr: ERROR: Unsupported timezone format "foo", '
 
91
                           'options are "utc", "original", "local".',
 
92
                           ['log', '--timezone', 'foo'])
 
93
 
 
94
    def test_log_negative_begin_revspec_full_log(self):
 
95
        self._prepare()
 
96
        log = self.run_bzr("log -r -3..")[0]
 
97
        self.assertEqualDiff(self.full_log, log)
 
98
 
 
99
    def test_log_negative_both_revspec_full_log(self):
 
100
        self._prepare()
 
101
        log = self.run_bzr("log -r -3..-1")[0]
 
102
        self.assertEqualDiff(self.full_log, log)
 
103
 
 
104
    def test_log_negative_both_revspec_partial(self):
 
105
        self._prepare()
 
106
        log = self.run_bzr("log -r -3..-2")[0]
 
107
        self.assertTrue('revno: 1\n' in log)
 
108
        self.assertTrue('revno: 2\n' in log)
 
109
        self.assertTrue('revno: 3\n' not in log)
 
110
 
 
111
    def test_log_negative_begin_revspec(self):
 
112
        self._prepare()
 
113
        log = self.run_bzr("log -r -2..")[0]
 
114
        self.assertTrue('revno: 1\n' not in log)
 
115
        self.assertTrue('revno: 2\n' in log)
 
116
        self.assertTrue('revno: 3\n' in log)
 
117
 
 
118
    def test_log_positive_revspecs(self):
 
119
        self._prepare()
 
120
        log = self.run_bzr("log -r 1..3")[0]
 
121
        self.assertEqualDiff(self.full_log, log)
 
122
 
 
123
    def test_log_reversed_revspecs(self):
 
124
        self._prepare()
 
125
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
 
126
                            'the end revision.\n',),
 
127
                           ['log', '-r3..1'])
 
128
 
 
129
    def test_log_revno_n_path(self):
 
130
        self._prepare(path='branch1')
 
131
        self._prepare(path='branch2')
 
132
        log = self.run_bzr("log -r revno:2:branch1..revno:3:branch2",
 
133
                          retcode=3)[0]
 
134
        log = self.run_bzr("log -r revno:1:branch2..revno:3:branch2")[0]
 
135
        self.assertEqualDiff(self.full_log, log)
 
136
        log = self.run_bzr("log -r revno:1:branch2")[0]
 
137
        self.assertTrue('revno: 1\n' in log)
 
138
        self.assertTrue('revno: 2\n' not in log)
 
139
        self.assertTrue('branch nick: branch2\n' in log)
 
140
        self.assertTrue('branch nick: branch1\n' not in log)
 
141
 
 
142
    def test_log_change_revno(self):
 
143
        self._prepare()
 
144
        expected_log = self.run_bzr("log -r 1")[0]
 
145
        log = self.run_bzr("log -c 1")[0]
 
146
        self.assertEqualDiff(expected_log, log)
 
147
 
 
148
    def test_log_change_single_revno(self):
 
149
        self._prepare()
 
150
        self.run_bzr_error('bzr: ERROR: Option --change does not'
 
151
                           ' accept revision ranges',
 
152
                           ['log', '--change', '2..3'])
 
153
 
 
154
    def test_log_change_incompatible_with_revision(self):
 
155
        self._prepare()
 
156
        self.run_bzr_error('bzr: ERROR: --revision and --change'
 
157
                           ' are mutually exclusive',
 
158
                           ['log', '--change', '2', '--revision', '3'])
 
159
 
 
160
    def test_log_nonexistent_file(self):
 
161
        # files that don't exist in either the basis tree or working tree
 
162
        # should give an error
 
163
        wt = self.make_branch_and_tree('.')
 
164
        out, err = self.run_bzr('log does-not-exist', retcode=3)
 
165
        self.assertContainsRe(
 
166
            err, 'Path does not have any revision history: does-not-exist')
 
167
 
 
168
    def test_log_with_tags(self):
 
169
        tree = self._prepare(format='dirstate-tags')
 
170
        branch = tree.branch
 
171
        branch.tags.set_tag('tag1', branch.get_rev_id(1))
 
172
        branch.tags.set_tag('tag1.1', branch.get_rev_id(1))
 
173
        branch.tags.set_tag('tag3', branch.last_revision()) 
 
174
        
 
175
        log = self.run_bzr("log -r-1")[0]
 
176
        self.assertTrue('tags: tag3' in log)
 
177
 
 
178
        log = self.run_bzr("log -r1")[0]
 
179
        # I guess that we can't know the order of tags in the output
 
180
        # since dicts are unordered, need to check both possibilities
 
181
        self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
 
182
 
 
183
    def test_merged_log_with_tags(self):
 
184
        branch1_tree = self._prepare(path='branch1', format='dirstate-tags')
 
185
        branch1 = branch1_tree.branch
 
186
        branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
 
187
        branch1_tree.commit(message='foobar', allow_pointless=True)
 
188
        branch1.tags.set_tag('tag1', branch1.last_revision())
 
189
        os.chdir('branch2')
 
190
        self.run_bzr('merge ../branch1') # tags don't propagate otherwise
 
191
        branch2_tree.commit(message='merge branch 1')
 
192
        log = self.run_bzr("log -r-1")[0]
 
193
        self.assertContainsRe(log, r'    tags: tag1')
 
194
        log = self.run_bzr("log -r3.1.1")[0]
 
195
        self.assertContainsRe(log, r'tags: tag1')
 
196
 
 
197
    def test_log_limit(self):
 
198
        tree = self.make_branch_and_tree('.')
 
199
        # We want more commits than our batch size starts at
 
200
        for pos in range(10):
 
201
            tree.commit("%s" % pos)
 
202
        log = self.run_bzr("log --limit 2")[0]
 
203
        self.assertNotContainsRe(log, r'revno: 1\n')
 
204
        self.assertNotContainsRe(log, r'revno: 2\n')
 
205
        self.assertNotContainsRe(log, r'revno: 3\n')
 
206
        self.assertNotContainsRe(log, r'revno: 4\n')
 
207
        self.assertNotContainsRe(log, r'revno: 5\n')
 
208
        self.assertNotContainsRe(log, r'revno: 6\n')
 
209
        self.assertNotContainsRe(log, r'revno: 7\n')
 
210
        self.assertNotContainsRe(log, r'revno: 8\n')
 
211
        self.assertContainsRe(log, r'revno: 9\n')
 
212
        self.assertContainsRe(log, r'revno: 10\n')
 
213
 
 
214
    def test_log_limit_short(self):
 
215
        self._prepare()
 
216
        log = self.run_bzr("log -l 2")[0]
 
217
        self.assertNotContainsRe(log, r'revno: 1\n')
 
218
        self.assertContainsRe(log, r'revno: 2\n')
 
219
        self.assertContainsRe(log, r'revno: 3\n')
 
220
 
 
221
 
 
222
class TestLogMerges(TestCaseWithoutPropsHandler):
 
223
 
 
224
    def _prepare(self):
 
225
        parent_tree = self.make_branch_and_tree('parent')
 
226
        parent_tree.commit(message='first post', allow_pointless=True)
 
227
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
 
228
        child_tree.commit(message='branch 1', allow_pointless=True)
 
229
        smaller_tree = \
 
230
                child_tree.bzrdir.sprout('smallerchild').open_workingtree()
 
231
        smaller_tree.commit(message='branch 2', allow_pointless=True)
 
232
        child_tree.merge_from_branch(smaller_tree.branch)
 
233
        child_tree.commit(message='merge branch 2')
 
234
        parent_tree.merge_from_branch(child_tree.branch)
 
235
        parent_tree.commit(message='merge branch 1')
 
236
        os.chdir('parent')
 
237
 
 
238
    def test_merges_are_indented_by_level(self):
 
239
        self._prepare()
 
240
        out,err = self.run_bzr('log')
 
241
        self.assertEqual('', err)
 
242
        log = normalize_log(out)
 
243
        self.assertEqualDiff(log, """\
 
244
------------------------------------------------------------
 
245
revno: 2
 
246
committer: Lorem Ipsum <test@example.com>
 
247
branch nick: parent
 
248
timestamp: Just now
 
249
message:
 
250
  merge branch 1
 
251
    ------------------------------------------------------------
 
252
    revno: 1.1.2
 
253
    committer: Lorem Ipsum <test@example.com>
 
254
    branch nick: child
 
255
    timestamp: Just now
 
256
    message:
 
257
      merge branch 2
 
258
        ------------------------------------------------------------
 
259
        revno: 1.2.1
 
260
        committer: Lorem Ipsum <test@example.com>
 
261
        branch nick: smallerchild
 
262
        timestamp: Just now
 
263
        message:
 
264
          branch 2
 
265
    ------------------------------------------------------------
 
266
    revno: 1.1.1
 
267
    committer: Lorem Ipsum <test@example.com>
 
268
    branch nick: child
 
269
    timestamp: Just now
 
270
    message:
 
271
      branch 1
 
272
------------------------------------------------------------
 
273
revno: 1
 
274
committer: Lorem Ipsum <test@example.com>
 
275
branch nick: parent
 
276
timestamp: Just now
 
277
message:
 
278
  first post
 
279
""")
 
280
 
 
281
    def test_merges_single_merge_rev(self):
 
282
        self._prepare()
 
283
        out,err = self.run_bzr('log -r1.1.2')
 
284
        self.assertEqual('', err)
 
285
        log = normalize_log(out)
 
286
        self.assertEqualDiff(log, """\
 
287
------------------------------------------------------------
 
288
revno: 1.1.2
 
289
committer: Lorem Ipsum <test@example.com>
 
290
branch nick: child
 
291
timestamp: Just now
 
292
message:
 
293
  merge branch 2
 
294
    ------------------------------------------------------------
 
295
    revno: 1.2.1
 
296
    committer: Lorem Ipsum <test@example.com>
 
297
    branch nick: smallerchild
 
298
    timestamp: Just now
 
299
    message:
 
300
      branch 2
 
301
""")
 
302
 
 
303
    def test_merges_partial_range(self):
 
304
        self._prepare()
 
305
        out,err = self.run_bzr('log -r1.1.1..1.1.2')
 
306
        self.assertEqual('', err)
 
307
        log = normalize_log(out)
 
308
        self.assertEqualDiff(log, """\
 
309
------------------------------------------------------------
 
310
revno: 1.1.2
 
311
committer: Lorem Ipsum <test@example.com>
 
312
branch nick: child
 
313
timestamp: Just now
 
314
message:
 
315
  merge branch 2
 
316
    ------------------------------------------------------------
 
317
    revno: 1.2.1
 
318
    committer: Lorem Ipsum <test@example.com>
 
319
    branch nick: smallerchild
 
320
    timestamp: Just now
 
321
    message:
 
322
      branch 2
 
323
------------------------------------------------------------
 
324
revno: 1.1.1
 
325
committer: Lorem Ipsum <test@example.com>
 
326
branch nick: child
 
327
timestamp: Just now
 
328
message:
 
329
  branch 1
 
330
""")
 
331
 
 
332
    def test_merges_nonsupporting_formatter(self):
 
333
        self._prepare()
 
334
        err_msg = 'Selected log formatter only supports mainline revisions.'
 
335
        # The single revision case is tested in the core tests
 
336
        # since all standard formatters support single merge revisions.
 
337
        out,err = self.run_bzr('log --short -r1..1.1.2', retcode=3)
 
338
        self.assertContainsRe(err, err_msg)
 
339
        out,err = self.run_bzr('log --short -r1.1.1..1.1.2', retcode=3)
 
340
        self.assertContainsRe(err, err_msg)
 
341
 
 
342
 
 
343
class TestLogEncodings(TestCaseInTempDir):
 
344
 
 
345
    _mu = u'\xb5'
 
346
    _message = u'Message with \xb5'
 
347
 
 
348
    # Encodings which can encode mu
 
349
    good_encodings = [
 
350
        'utf-8',
 
351
        'latin-1',
 
352
        'iso-8859-1',
 
353
        'cp437', # Common windows encoding
 
354
        'cp1251', # Alexander Belchenko's windows encoding
 
355
        'cp1258', # Common windows encoding
 
356
    ]
 
357
    # Encodings which cannot encode mu
 
358
    bad_encodings = [
 
359
        'ascii',
 
360
        'iso-8859-2',
 
361
        'koi8_r',
 
362
    ]
 
363
 
 
364
    def setUp(self):
 
365
        TestCaseInTempDir.setUp(self)
 
366
        self.user_encoding = osutils._cached_user_encoding
 
367
 
 
368
    def tearDown(self):
 
369
        osutils._cached_user_encoding = self.user_encoding
 
370
        TestCaseInTempDir.tearDown(self)
 
371
 
 
372
    def create_branch(self):
 
373
        bzr = self.run_bzr
 
374
        bzr('init')
 
375
        open('a', 'wb').write('some stuff\n')
 
376
        bzr('add a')
 
377
        bzr(['commit', '-m', self._message])
 
378
 
 
379
    def try_encoding(self, encoding, fail=False):
 
380
        bzr = self.run_bzr
 
381
        if fail:
 
382
            self.assertRaises(UnicodeEncodeError,
 
383
                self._mu.encode, encoding)
 
384
            encoded_msg = self._message.encode(encoding, 'replace')
 
385
        else:
 
386
            encoded_msg = self._message.encode(encoding)
 
387
 
 
388
        old_encoding = osutils._cached_user_encoding
 
389
        # This test requires that 'run_bzr' uses the current
 
390
        # bzrlib, because we override user_encoding, and expect
 
391
        # it to be used
 
392
        try:
 
393
            osutils._cached_user_encoding = 'ascii'
 
394
            # We should be able to handle any encoding
 
395
            out, err = bzr('log', encoding=encoding)
 
396
            if not fail:
 
397
                # Make sure we wrote mu as we expected it to exist
 
398
                self.assertNotEqual(-1, out.find(encoded_msg))
 
399
                out_unicode = out.decode(encoding)
 
400
                self.assertNotEqual(-1, out_unicode.find(self._message))
 
401
            else:
 
402
                self.assertNotEqual(-1, out.find('Message with ?'))
 
403
        finally:
 
404
            osutils._cached_user_encoding = old_encoding
 
405
 
 
406
    def test_log_handles_encoding(self):
 
407
        self.create_branch()
 
408
 
 
409
        for encoding in self.good_encodings:
 
410
            self.try_encoding(encoding)
 
411
 
 
412
    def test_log_handles_bad_encoding(self):
 
413
        self.create_branch()
 
414
 
 
415
        for encoding in self.bad_encodings:
 
416
            self.try_encoding(encoding, fail=True)
 
417
 
 
418
    def test_stdout_encoding(self):
 
419
        bzr = self.run_bzr
 
420
        osutils._cached_user_encoding = "cp1251"
 
421
 
 
422
        bzr('init')
 
423
        self.build_tree(['a'])
 
424
        bzr('add a')
 
425
        bzr(['commit', '-m', u'\u0422\u0435\u0441\u0442'])
 
426
        stdout, stderr = self.run_bzr('log', encoding='cp866')
 
427
 
 
428
        message = stdout.splitlines()[-1]
 
429
 
 
430
        # explanation of the check:
 
431
        # u'\u0422\u0435\u0441\u0442' is word 'Test' in russian
 
432
        # in cp866  encoding this is string '\x92\xa5\xe1\xe2'
 
433
        # in cp1251 encoding this is string '\xd2\xe5\xf1\xf2'
 
434
        # This test should check that output of log command
 
435
        # encoded to sys.stdout.encoding
 
436
        test_in_cp866 = '\x92\xa5\xe1\xe2'
 
437
        test_in_cp1251 = '\xd2\xe5\xf1\xf2'
 
438
        # Make sure the log string is encoded in cp866
 
439
        self.assertEquals(test_in_cp866, message[2:])
 
440
        # Make sure the cp1251 string is not found anywhere
 
441
        self.assertEquals(-1, stdout.find(test_in_cp1251))
 
442
 
 
443
 
 
444
class TestLogFile(TestCaseWithTransport):
 
445
 
 
446
    def test_log_local_branch_file(self):
 
447
        """We should be able to log files in local treeless branches"""
 
448
        tree = self.make_branch_and_tree('tree')
 
449
        self.build_tree(['tree/file'])
 
450
        tree.add('file')
 
451
        tree.commit('revision 1')
 
452
        tree.bzrdir.destroy_workingtree()
 
453
        self.run_bzr('log tree/file')
 
454
 
 
455
    def test_log_file(self):
 
456
        """The log for a particular file should only list revs for that file"""
 
457
        tree = self.make_branch_and_tree('parent')
 
458
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
 
459
        tree.add('file1')
 
460
        tree.commit('add file1')
 
461
        tree.add('file2')
 
462
        tree.commit('add file2')
 
463
        tree.add('file3')
 
464
        tree.commit('add file3')
 
465
        child_tree = tree.bzrdir.sprout('child').open_workingtree()
 
466
        self.build_tree_contents([('child/file2', 'hello')])
 
467
        child_tree.commit(message='branch 1')
 
468
        tree.merge_from_branch(child_tree.branch)
 
469
        tree.commit(message='merge child branch')
 
470
        os.chdir('parent')
 
471
        log = self.run_bzr('log file1')[0]
 
472
        self.assertContainsRe(log, 'revno: 1\n')
 
473
        self.assertNotContainsRe(log, 'revno: 2\n')
 
474
        self.assertNotContainsRe(log, 'revno: 3\n')
 
475
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
476
        self.assertNotContainsRe(log, 'revno: 4\n')
 
477
        log = self.run_bzr('log file2')[0]
 
478
        self.assertNotContainsRe(log, 'revno: 1\n')
 
479
        self.assertContainsRe(log, 'revno: 2\n')
 
480
        self.assertNotContainsRe(log, 'revno: 3\n')
 
481
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
482
        self.assertContainsRe(log, 'revno: 4\n')
 
483
        log = self.run_bzr('log file3')[0]
 
484
        self.assertNotContainsRe(log, 'revno: 1\n')
 
485
        self.assertNotContainsRe(log, 'revno: 2\n')
 
486
        self.assertContainsRe(log, 'revno: 3\n')
 
487
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
488
        self.assertNotContainsRe(log, 'revno: 4\n')
 
489
        log = self.run_bzr('log -r3.1.1 file2')[0]
 
490
        self.assertNotContainsRe(log, 'revno: 1\n')
 
491
        self.assertNotContainsRe(log, 'revno: 2\n')
 
492
        self.assertNotContainsRe(log, 'revno: 3\n')
 
493
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
494
        self.assertNotContainsRe(log, 'revno: 4\n')
 
495
        log = self.run_bzr('log -r4 file2')[0]
 
496
        self.assertNotContainsRe(log, 'revno: 1\n')
 
497
        self.assertNotContainsRe(log, 'revno: 2\n')
 
498
        self.assertNotContainsRe(log, 'revno: 3\n')
 
499
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
500
        self.assertContainsRe(log, 'revno: 4\n')
 
501
        log = self.run_bzr('log -r3.. file2')[0]
 
502
        self.assertNotContainsRe(log, 'revno: 1\n')
 
503
        self.assertNotContainsRe(log, 'revno: 2\n')
 
504
        self.assertNotContainsRe(log, 'revno: 3\n')
 
505
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
506
        self.assertContainsRe(log, 'revno: 4\n')
 
507
        log = self.run_bzr('log -r..3 file2')[0]
 
508
        self.assertNotContainsRe(log, 'revno: 1\n')
 
509
        self.assertContainsRe(log, 'revno: 2\n')
 
510
        self.assertNotContainsRe(log, 'revno: 3\n')
 
511
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
512
        self.assertNotContainsRe(log, 'revno: 4\n')