~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: mbp at sourcefrog
  • Date: 2005-03-24 00:44:18 UTC
  • Revision ID: mbp@sourcefrog.net-20050324004418-b4a050f656c07f5f
show space usage for various stores in the info command

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2009 Canonical Ltd
2
 
#
3
 
# This program is free software; you can redistribute it and/or modify
4
 
# it under the terms of the GNU General Public License as published by
5
 
# the Free Software Foundation; either version 2 of the License, or
6
 
# (at your option) any later version.
7
 
#
8
 
# This program is distributed in the hope that it will be useful,
9
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
# GNU General Public License for more details.
12
 
#
13
 
# You should have received a copy of the GNU General Public License
14
 
# 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
 
 
17
 
 
18
 
"""Black-box tests for bzr log."""
19
 
 
20
 
import os
21
 
import re
22
 
 
23
 
from bzrlib import (
24
 
    osutils,
25
 
    tests,
26
 
    )
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
36
 
 
37
 
    def make_minimal_branch(self, path='.', format=None):
38
 
        tree = self.make_branch_and_tree(path, format=format)
39
 
        self.build_tree([path + '/hello.txt'])
40
 
        tree.add('hello.txt')
41
 
        tree.commit(message='message1')
42
 
        return tree
43
 
 
44
 
    def make_linear_branch(self, path='.', format=None):
45
 
        tree = self.make_branch_and_tree(path, format=format)
46
 
        self.build_tree(
47
 
            [path + '/hello.txt', path + '/goodbye.txt', path + '/meep.txt'])
48
 
        tree.add('hello.txt')
49
 
        tree.commit(message='message1')
50
 
        tree.add('goodbye.txt')
51
 
        tree.commit(message='message2')
52
 
        tree.add('meep.txt')
53
 
        tree.commit(message='message3')
54
 
        return tree
55
 
 
56
 
    def commit_options(self):
57
 
        """Use some mostly fixed values for commits to simplify tests.
58
 
 
59
 
        Tests can use this function to get some commit attributes. The time
60
 
        stamp is incremented at each commit.
61
 
        """
62
 
        self.timestamp += 1 # 1 second between each commit
63
 
        return dict(committer='Lorem Ipsum <joe@foo.com>',
64
 
                 timezone=self.timezone,
65
 
                 timestamp=self.timestamp,
66
 
                 )
67
 
 
68
 
    def check_log(self, expected, args, working_dir='level0'):
69
 
        out, err = self.run_bzr(['log', '--timezone', 'utc'] + args,
70
 
                                working_dir=working_dir)
71
 
        self.assertEqual('', err)
72
 
        self.assertEqualDiff(expected, test_log.normalize_log(out))
73
 
 
74
 
 
75
 
class TestLogRevSpecs(TestLog):
76
 
 
77
 
    def test_log_null_end_revspec(self):
78
 
        self.make_linear_branch()
79
 
        log = self.run_bzr(['log'])[0]
80
 
        self.assertTrue('revno: 1\n' in log)
81
 
        self.assertTrue('revno: 2\n' in log)
82
 
        self.assertTrue('revno: 3\n' in log)
83
 
        self.assertTrue('message:\n  message1\n' in log)
84
 
        self.assertTrue('message:\n  message2\n' in log)
85
 
        self.assertTrue('message:\n  message3\n' in log)
86
 
 
87
 
        full_log = self.run_bzr(['log'])[0]
88
 
        log = self.run_bzr("log -r 1..")[0]
89
 
        self.assertEqualDiff(log, full_log)
90
 
 
91
 
    def test_log_null_begin_revspec(self):
92
 
        self.make_linear_branch()
93
 
        full_log = self.run_bzr(['log'])[0]
94
 
        log = self.run_bzr("log -r ..3")[0]
95
 
        self.assertEqualDiff(full_log, log)
96
 
 
97
 
    def test_log_null_both_revspecs(self):
98
 
        self.make_linear_branch()
99
 
        full_log = self.run_bzr(['log'])[0]
100
 
        log = self.run_bzr("log -r ..")[0]
101
 
        self.assertEqualDiff(full_log, log)
102
 
 
103
 
    def test_log_zero_revspec(self):
104
 
        self.make_minimal_branch()
105
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
106
 
                           ['log', '-r0'])
107
 
 
108
 
    def test_log_zero_begin_revspec(self):
109
 
        self.make_linear_branch()
110
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
111
 
                           ['log', '-r0..2'])
112
 
 
113
 
    def test_log_zero_end_revspec(self):
114
 
        self.make_linear_branch()
115
 
        self.run_bzr_error(['bzr: ERROR: Logging revision 0 is invalid.'],
116
 
                           ['log', '-r-2..0'])
117
 
 
118
 
    def test_log_negative_begin_revspec_full_log(self):
119
 
        self.make_linear_branch()
120
 
        full_log = self.run_bzr(['log'])[0]
121
 
        log = self.run_bzr("log -r -3..")[0]
122
 
        self.assertEqualDiff(full_log, log)
123
 
 
124
 
    def test_log_negative_both_revspec_full_log(self):
125
 
        self.make_linear_branch()
126
 
        full_log = self.run_bzr(['log'])[0]
127
 
        log = self.run_bzr("log -r -3..-1")[0]
128
 
        self.assertEqualDiff(full_log, log)
129
 
 
130
 
    def test_log_negative_both_revspec_partial(self):
131
 
        self.make_linear_branch()
132
 
        log = self.run_bzr("log -r -3..-2")[0]
133
 
        self.assertTrue('revno: 1\n' in log)
134
 
        self.assertTrue('revno: 2\n' in log)
135
 
        self.assertTrue('revno: 3\n' not in log)
136
 
 
137
 
    def test_log_negative_begin_revspec(self):
138
 
        self.make_linear_branch()
139
 
        log = self.run_bzr("log -r -2..")[0]
140
 
        self.assertTrue('revno: 1\n' not in log)
141
 
        self.assertTrue('revno: 2\n' in log)
142
 
        self.assertTrue('revno: 3\n' in log)
143
 
 
144
 
    def test_log_positive_revspecs(self):
145
 
        self.make_linear_branch()
146
 
        full_log = self.run_bzr(['log'])[0]
147
 
        log = self.run_bzr("log -r 1..3")[0]
148
 
        self.assertEqualDiff(full_log, log)
149
 
 
150
 
    def test_log_reversed_revspecs(self):
151
 
        self.make_linear_branch()
152
 
        self.run_bzr_error(('bzr: ERROR: Start revision must be older than '
153
 
                            'the end revision.\n',),
154
 
                           ['log', '-r3..1'])
155
 
 
156
 
    def test_log_revno_n_path(self):
157
 
        self.make_linear_branch('branch1')
158
 
        self.make_linear_branch('branch2')
159
 
        # Swapped revisions
160
 
        self.run_bzr("log -r revno:2:branch1..revno:3:branch2", retcode=3)[0]
161
 
        # Correct order
162
 
        log = self.run_bzr("log -r revno:1:branch2..revno:3:branch2")[0]
163
 
        full_log = self.run_bzr(['log'], working_dir='branch2')[0]
164
 
        self.assertEqualDiff(full_log, log)
165
 
        log = self.run_bzr("log -r revno:1:branch2")[0]
166
 
        self.assertTrue('revno: 1\n' in log)
167
 
        self.assertTrue('revno: 2\n' not in log)
168
 
        self.assertTrue('branch nick: branch2\n' in log)
169
 
        self.assertTrue('branch nick: branch1\n' not in log)
170
 
 
171
 
    def test_log_nonexistent_revno(self):
172
 
        self.make_minimal_branch()
173
 
        (out, err) = self.run_bzr_error(
174
 
            ["bzr: ERROR: Requested revision: '1234' "
175
 
             "does not exist in branch:"],
176
 
            ['log', '-r1234'])
177
 
 
178
 
    def test_log_nonexistent_dotted_revno(self):
179
 
        self.make_minimal_branch()
180
 
        (out, err) = self.run_bzr_error(
181
 
            ["bzr: ERROR: Requested revision: '123.123' "
182
 
             "does not exist in branch:"],
183
 
            ['log',  '-r123.123'])
184
 
 
185
 
    def test_log_change_revno(self):
186
 
        self.make_linear_branch()
187
 
        expected_log = self.run_bzr("log -r 1")[0]
188
 
        log = self.run_bzr("log -c 1")[0]
189
 
        self.assertEqualDiff(expected_log, log)
190
 
 
191
 
    def test_log_change_nonexistent_revno(self):
192
 
        self.make_minimal_branch()
193
 
        (out, err) = self.run_bzr_error(
194
 
            ["bzr: ERROR: Requested revision: '1234' "
195
 
             "does not exist in branch:"],
196
 
            ['log',  '-c1234'])
197
 
 
198
 
    def test_log_change_nonexistent_dotted_revno(self):
199
 
        self.make_minimal_branch()
200
 
        (out, err) = self.run_bzr_error(
201
 
            ["bzr: ERROR: Requested revision: '123.123' "
202
 
             "does not exist in branch:"],
203
 
            ['log', '-c123.123'])
204
 
 
205
 
    def test_log_change_single_revno_only(self):
206
 
        self.make_minimal_branch()
207
 
        self.run_bzr_error(['bzr: ERROR: Option --change does not'
208
 
                           ' accept revision ranges'],
209
 
                           ['log', '--change', '2..3'])
210
 
 
211
 
    def test_log_change_incompatible_with_revision(self):
212
 
        self.run_bzr_error(['bzr: ERROR: --revision and --change'
213
 
                           ' are mutually exclusive'],
214
 
                           ['log', '--change', '2', '--revision', '3'])
215
 
 
216
 
    def test_log_nonexistent_file(self):
217
 
        self.make_minimal_branch()
218
 
        # files that don't exist in either the basis tree or working tree
219
 
        # should give an error
220
 
        out, err = self.run_bzr('log does-not-exist', retcode=3)
221
 
        self.assertContainsRe(err,
222
 
                              'Path unknown at end or start of revision range: '
223
 
                              'does-not-exist')
224
 
 
225
 
    def test_log_with_tags(self):
226
 
        tree = self.make_linear_branch(format='dirstate-tags')
227
 
        branch = tree.branch
228
 
        branch.tags.set_tag('tag1', branch.get_rev_id(1))
229
 
        branch.tags.set_tag('tag1.1', branch.get_rev_id(1))
230
 
        branch.tags.set_tag('tag3', branch.last_revision())
231
 
 
232
 
        log = self.run_bzr("log -r-1")[0]
233
 
        self.assertTrue('tags: tag3' in log)
234
 
 
235
 
        log = self.run_bzr("log -r1")[0]
236
 
        # I guess that we can't know the order of tags in the output
237
 
        # since dicts are unordered, need to check both possibilities
238
 
        self.assertContainsRe(log, r'tags: (tag1, tag1\.1|tag1\.1, tag1)')
239
 
 
240
 
    def test_merged_log_with_tags(self):
241
 
        branch1_tree = self.make_linear_branch('branch1',
242
 
                                               format='dirstate-tags')
243
 
        branch1 = branch1_tree.branch
244
 
        branch2_tree = branch1_tree.bzrdir.sprout('branch2').open_workingtree()
245
 
        branch1_tree.commit(message='foobar', allow_pointless=True)
246
 
        branch1.tags.set_tag('tag1', branch1.last_revision())
247
 
        # tags don't propagate if we don't merge
248
 
        self.run_bzr('merge ../branch1', working_dir='branch2')
249
 
        branch2_tree.commit(message='merge branch 1')
250
 
        log = self.run_bzr("log -n0 -r-1", working_dir='branch2')[0]
251
 
        self.assertContainsRe(log, r'    tags: tag1')
252
 
        log = self.run_bzr("log -n0 -r3.1.1", working_dir='branch2')[0]
253
 
        self.assertContainsRe(log, r'tags: tag1')
254
 
 
255
 
    def test_log_limit(self):
256
 
        tree = self.make_branch_and_tree('.')
257
 
        # We want more commits than our batch size starts at
258
 
        for pos in range(10):
259
 
            tree.commit("%s" % pos)
260
 
        log = self.run_bzr("log --limit 2")[0]
261
 
        self.assertNotContainsRe(log, r'revno: 1\n')
262
 
        self.assertNotContainsRe(log, r'revno: 2\n')
263
 
        self.assertNotContainsRe(log, r'revno: 3\n')
264
 
        self.assertNotContainsRe(log, r'revno: 4\n')
265
 
        self.assertNotContainsRe(log, r'revno: 5\n')
266
 
        self.assertNotContainsRe(log, r'revno: 6\n')
267
 
        self.assertNotContainsRe(log, r'revno: 7\n')
268
 
        self.assertNotContainsRe(log, r'revno: 8\n')
269
 
        self.assertContainsRe(log, r'revno: 9\n')
270
 
        self.assertContainsRe(log, r'revno: 10\n')
271
 
 
272
 
    def test_log_limit_short(self):
273
 
        self.make_linear_branch()
274
 
        log = self.run_bzr("log -l 2")[0]
275
 
        self.assertNotContainsRe(log, r'revno: 1\n')
276
 
        self.assertContainsRe(log, r'revno: 2\n')
277
 
        self.assertContainsRe(log, r'revno: 3\n')
278
 
 
279
 
    def test_log_bad_message_re(self):
280
 
        """Bad --message argument gives a sensible message
281
 
        
282
 
        See https://bugs.launchpad.net/bzr/+bug/251352
283
 
        """
284
 
        self.make_minimal_branch()
285
 
        out, err = self.run_bzr(['log', '-m', '*'], retcode=3)
286
 
        self.assertEqual("bzr: ERROR: Invalid regular expression"
287
 
            " in log message filter"
288
 
            ": '*'"
289
 
            ": nothing to repeat\n", err)
290
 
        self.assertEqual('', out)
291
 
 
292
 
 
293
 
class TestLogTimeZone(TestLog):
294
 
 
295
 
    def test_log_unsupported_timezone(self):
296
 
        self.make_linear_branch()
297
 
        self.run_bzr_error(['bzr: ERROR: Unsupported timezone format "foo", '
298
 
                            'options are "utc", "original", "local".'],
299
 
                           ['log', '--timezone', 'foo'])
300
 
 
301
 
 
302
 
class TestLogVerbose(TestLog):
303
 
 
304
 
    def setUp(self):
305
 
        super(TestLogVerbose, self).setUp()
306
 
        self.make_minimal_branch()
307
 
 
308
 
    def assertUseShortDeltaFormat(self, cmd):
309
 
        log = self.run_bzr(cmd)[0]
310
 
        # Check that we use the short status format
311
 
        self.assertContainsRe(log, '(?m)^\s*A  hello.txt$')
312
 
        self.assertNotContainsRe(log, '(?m)^\s*added:$')
313
 
 
314
 
    def assertUseLongDeltaFormat(self, cmd):
315
 
        log = self.run_bzr(cmd)[0]
316
 
        # Check that we use the long status format
317
 
        self.assertNotContainsRe(log, '(?m)^\s*A  hello.txt$')
318
 
        self.assertContainsRe(log, '(?m)^\s*added:$')
319
 
 
320
 
    def test_log_short_verbose(self):
321
 
        self.assertUseShortDeltaFormat(['log', '--short', '-v'])
322
 
 
323
 
    def test_log_short_verbose_verbose(self):
324
 
        self.assertUseLongDeltaFormat(['log', '--short', '-vv'])
325
 
 
326
 
    def test_log_long_verbose(self):
327
 
        # Check that we use the long status format, ignoring the verbosity
328
 
        # level
329
 
        self.assertUseLongDeltaFormat(['log', '--long', '-v'])
330
 
 
331
 
    def test_log_long_verbose_verbose(self):
332
 
        # Check that we use the long status format, ignoring the verbosity
333
 
        # level
334
 
        self.assertUseLongDeltaFormat(['log', '--long', '-vv'])
335
 
 
336
 
 
337
 
class TestLogMerges(TestLog):
338
 
 
339
 
    def setUp(self):
340
 
        super(TestLogMerges, self).setUp()
341
 
        self.make_branches_with_merges()
342
 
 
343
 
    def make_branches_with_merges(self):
344
 
        level0 = self.make_branch_and_tree('level0')
345
 
        level0.commit(message='in branch level0', **self.commit_options())
346
 
 
347
 
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
348
 
        level1.commit(message='in branch level1', **self.commit_options())
349
 
 
350
 
        level2 = level1.bzrdir.sprout('level2').open_workingtree()
351
 
        level2.commit(message='in branch level2', **self.commit_options())
352
 
 
353
 
        level1.merge_from_branch(level2.branch)
354
 
        level1.commit(message='merge branch level2', **self.commit_options())
355
 
 
356
 
        level0.merge_from_branch(level1.branch)
357
 
        level0.commit(message='merge branch level1', **self.commit_options())
358
 
 
359
 
    def test_merges_are_indented_by_level(self):
360
 
        expected = """\
361
 
------------------------------------------------------------
362
 
revno: 2 [merge]
363
 
committer: Lorem Ipsum <test@example.com>
364
 
branch nick: level0
365
 
timestamp: Just now
366
 
message:
367
 
  merge branch level1
368
 
    ------------------------------------------------------------
369
 
    revno: 1.1.2 [merge]
370
 
    committer: Lorem Ipsum <test@example.com>
371
 
    branch nick: level1
372
 
    timestamp: Just now
373
 
    message:
374
 
      merge branch level2
375
 
        ------------------------------------------------------------
376
 
        revno: 1.2.1
377
 
        committer: Lorem Ipsum <test@example.com>
378
 
        branch nick: level2
379
 
        timestamp: Just now
380
 
        message:
381
 
          in branch level2
382
 
    ------------------------------------------------------------
383
 
    revno: 1.1.1
384
 
    committer: Lorem Ipsum <test@example.com>
385
 
    branch nick: level1
386
 
    timestamp: Just now
387
 
    message:
388
 
      in branch level1
389
 
------------------------------------------------------------
390
 
revno: 1
391
 
committer: Lorem Ipsum <test@example.com>
392
 
branch nick: level0
393
 
timestamp: Just now
394
 
message:
395
 
  in branch level0
396
 
"""
397
 
        self.check_log(expected, ['-n0'])
398
 
 
399
 
    def test_force_merge_revisions_off(self):
400
 
        expected = """\
401
 
------------------------------------------------------------
402
 
revno: 2 [merge]
403
 
committer: Lorem Ipsum <test@example.com>
404
 
branch nick: level0
405
 
timestamp: Just now
406
 
message:
407
 
  merge branch level1
408
 
------------------------------------------------------------
409
 
revno: 1
410
 
committer: Lorem Ipsum <test@example.com>
411
 
branch nick: level0
412
 
timestamp: Just now
413
 
message:
414
 
  in branch level0
415
 
"""
416
 
        self.check_log(expected, ['--long', '-n1'])
417
 
 
418
 
    def test_force_merge_revisions_on(self):
419
 
        expected = """\
420
 
    2 Lorem Ipsum\t2005-11-22 [merge]
421
 
      merge branch level1
422
 
 
423
 
          1.1.2 Lorem Ipsum\t2005-11-22 [merge]
424
 
                merge branch level2
425
 
 
426
 
              1.2.1 Lorem Ipsum\t2005-11-22
427
 
                    in branch level2
428
 
 
429
 
          1.1.1 Lorem Ipsum\t2005-11-22
430
 
                in branch level1
431
 
 
432
 
    1 Lorem Ipsum\t2005-11-22
433
 
      in branch level0
434
 
 
435
 
"""
436
 
        self.check_log(expected, ['--short', '-n0'])
437
 
 
438
 
    def test_include_merges(self):
439
 
        # Confirm --include-merges gives the same output as -n0
440
 
        out_im, err_im = self.run_bzr('log --include-merges',
441
 
                                      working_dir='level0')
442
 
        out_n0, err_n0 = self.run_bzr('log -n0', working_dir='level0')
443
 
        self.assertEqual('', err_im)
444
 
        self.assertEqual('', err_n0)
445
 
        self.assertEqual(out_im, out_n0)
446
 
 
447
 
    def test_force_merge_revisions_N(self):
448
 
        expected = """\
449
 
    2 Lorem Ipsum\t2005-11-22 [merge]
450
 
      merge branch level1
451
 
 
452
 
          1.1.2 Lorem Ipsum\t2005-11-22 [merge]
453
 
                merge branch level2
454
 
 
455
 
          1.1.1 Lorem Ipsum\t2005-11-22
456
 
                in branch level1
457
 
 
458
 
    1 Lorem Ipsum\t2005-11-22
459
 
      in branch level0
460
 
 
461
 
"""
462
 
        self.check_log(expected, ['--short', '-n2'])
463
 
 
464
 
    def test_merges_single_merge_rev(self):
465
 
        expected = """\
466
 
------------------------------------------------------------
467
 
revno: 1.1.2 [merge]
468
 
committer: Lorem Ipsum <test@example.com>
469
 
branch nick: level1
470
 
timestamp: Just now
471
 
message:
472
 
  merge branch level2
473
 
    ------------------------------------------------------------
474
 
    revno: 1.2.1
475
 
    committer: Lorem Ipsum <test@example.com>
476
 
    branch nick: level2
477
 
    timestamp: Just now
478
 
    message:
479
 
      in branch level2
480
 
"""
481
 
        self.check_log(expected, ['-n0', '-r1.1.2'])
482
 
 
483
 
    def test_merges_partial_range(self):
484
 
        expected = """\
485
 
------------------------------------------------------------
486
 
revno: 1.1.2 [merge]
487
 
committer: Lorem Ipsum <test@example.com>
488
 
branch nick: level1
489
 
timestamp: Just now
490
 
message:
491
 
  merge branch level2
492
 
    ------------------------------------------------------------
493
 
    revno: 1.2.1
494
 
    committer: Lorem Ipsum <test@example.com>
495
 
    branch nick: level2
496
 
    timestamp: Just now
497
 
    message:
498
 
      in branch level2
499
 
------------------------------------------------------------
500
 
revno: 1.1.1
501
 
committer: Lorem Ipsum <test@example.com>
502
 
branch nick: level1
503
 
timestamp: Just now
504
 
message:
505
 
  in branch level1
506
 
"""
507
 
        self.check_log(expected, ['-n0', '-r1.1.1..1.1.2'])
508
 
 
509
 
 
510
 
class TestLogDiff(TestLog):
511
 
 
512
 
    def setUp(self):
513
 
        super(TestLogDiff, self).setUp()
514
 
        self.make_branch_with_diffs()
515
 
 
516
 
    def make_branch_with_diffs(self):
517
 
        level0 = self.make_branch_and_tree('level0')
518
 
        self.build_tree(['level0/file1', 'level0/file2'])
519
 
        level0.add('file1')
520
 
        level0.add('file2')
521
 
        level0.commit(message='in branch level0', **self.commit_options())
522
 
 
523
 
        level1 = level0.bzrdir.sprout('level1').open_workingtree()
524
 
        self.build_tree_contents([('level1/file2', 'hello\n')])
525
 
        level1.commit(message='in branch level1', **self.commit_options())
526
 
        level0.merge_from_branch(level1.branch)
527
 
        level0.commit(message='merge branch level1', **self.commit_options())
528
 
 
529
 
    def test_log_show_diff_long_with_merges(self):
530
 
        out,err = self.run_bzr('log -p -n0')
531
 
        self.assertEqual('', err)
532
 
        log = test_log.normalize_log(out)
533
 
        expected = """\
534
 
------------------------------------------------------------
535
 
revno: 2 [merge]
536
 
committer: Lorem Ipsum <test@example.com>
537
 
branch nick: level0
538
 
timestamp: Just now
539
 
message:
540
 
  merge branch level1
541
 
diff:
542
 
=== modified file 'file2'
543
 
--- file2\t2005-11-22 00:00:01 +0000
544
 
+++ file2\t2005-11-22 00:00:02 +0000
545
 
@@ -1,1 +1,1 @@
546
 
-contents of level0/file2
547
 
+hello
548
 
    ------------------------------------------------------------
549
 
    revno: 1.1.1
550
 
    committer: Lorem Ipsum <test@example.com>
551
 
    branch nick: level1
552
 
    timestamp: Just now
553
 
    message:
554
 
      in branch level1
555
 
    diff:
556
 
    === modified file 'file2'
557
 
    --- file2\t2005-11-22 00:00:01 +0000
558
 
    +++ file2\t2005-11-22 00:00:02 +0000
559
 
    @@ -1,1 +1,1 @@
560
 
    -contents of level0/file2
561
 
    +hello
562
 
------------------------------------------------------------
563
 
revno: 1
564
 
committer: Lorem Ipsum <test@example.com>
565
 
branch nick: level0
566
 
timestamp: Just now
567
 
message:
568
 
  in branch level0
569
 
diff:
570
 
=== added file 'file1'
571
 
--- file1\t1970-01-01 00:00:00 +0000
572
 
+++ file1\t2005-11-22 00:00:01 +0000
573
 
@@ -0,0 +1,1 @@
574
 
+contents of level0/file1
575
 
 
576
 
=== added file 'file2'
577
 
--- file2\t1970-01-01 00:00:00 +0000
578
 
+++ file2\t2005-11-22 00:00:01 +0000
579
 
@@ -0,0 +1,1 @@
580
 
+contents of level0/file2
581
 
"""
582
 
        self.check_log(expected, ['-p', '-n0'])
583
 
 
584
 
    def test_log_show_diff_short(self):
585
 
        expected = """\
586
 
    2 Lorem Ipsum\t2005-11-22 [merge]
587
 
      merge branch level1
588
 
      === modified file 'file2'
589
 
      --- file2\t2005-11-22 00:00:01 +0000
590
 
      +++ file2\t2005-11-22 00:00:02 +0000
591
 
      @@ -1,1 +1,1 @@
592
 
      -contents of level0/file2
593
 
      +hello
594
 
 
595
 
    1 Lorem Ipsum\t2005-11-22
596
 
      in branch level0
597
 
      === added file 'file1'
598
 
      --- file1\t1970-01-01 00:00:00 +0000
599
 
      +++ file1\t2005-11-22 00:00:01 +0000
600
 
      @@ -0,0 +1,1 @@
601
 
      +contents of level0/file1
602
 
\x20\x20\x20\x20\x20\x20
603
 
      === added file 'file2'
604
 
      --- file2\t1970-01-01 00:00:00 +0000
605
 
      +++ file2\t2005-11-22 00:00:01 +0000
606
 
      @@ -0,0 +1,1 @@
607
 
      +contents of level0/file2
608
 
 
609
 
Use --include-merges or -n0 to see merged revisions.
610
 
"""
611
 
        self.check_log(expected, ['-p', '--short'])
612
 
 
613
 
    def test_log_show_diff_line(self):
614
 
        # Not supported by this formatter so expect plain output
615
 
        expected = """\
616
 
2: Lorem Ipsum 2005-11-22 [merge] merge branch level1
617
 
1: Lorem Ipsum 2005-11-22 in branch level0
618
 
"""
619
 
        self.check_log(expected, ['-p', '--line'])
620
 
 
621
 
    def test_log_show_diff_file1(self):
622
 
        """Only the diffs for the given file are to be shown"""
623
 
        expected = """\
624
 
    1 Lorem Ipsum\t2005-11-22
625
 
      in branch level0
626
 
      === added file 'file1'
627
 
      --- file1\t1970-01-01 00:00:00 +0000
628
 
      +++ file1\t2005-11-22 00:00:01 +0000
629
 
      @@ -0,0 +1,1 @@
630
 
      +contents of level0/file1
631
 
 
632
 
"""
633
 
        self.check_log(expected, ['-p', '--short', 'file1'])
634
 
 
635
 
    def test_log_show_diff_file2(self):
636
 
        """Only the diffs for the given file are to be shown"""
637
 
        expected = """\
638
 
    2 Lorem Ipsum\t2005-11-22 [merge]
639
 
      merge branch level1
640
 
      === modified file 'file2'
641
 
      --- file2\t2005-11-22 00:00:01 +0000
642
 
      +++ file2\t2005-11-22 00:00:02 +0000
643
 
      @@ -1,1 +1,1 @@
644
 
      -contents of level0/file2
645
 
      +hello
646
 
 
647
 
    1 Lorem Ipsum\t2005-11-22
648
 
      in branch level0
649
 
      === added file 'file2'
650
 
      --- file2\t1970-01-01 00:00:00 +0000
651
 
      +++ file2\t2005-11-22 00:00:01 +0000
652
 
      @@ -0,0 +1,1 @@
653
 
      +contents of level0/file2
654
 
 
655
 
Use --include-merges or -n0 to see merged revisions.
656
 
"""
657
 
        self.check_log(expected, ['-p', '--short', 'file2'])
658
 
 
659
 
 
660
 
class TestLogUnicodeDiff(TestLog):
661
 
 
662
 
    def test_log_show_diff_non_ascii(self):
663
 
        # Smoke test for bug #328007 UnicodeDecodeError on 'log -p'
664
 
        message = u'Message with \xb5'
665
 
        body = 'Body with \xb5\n'
666
 
        wt = self.make_branch_and_tree('.')
667
 
        self.build_tree_contents([('foo', body)])
668
 
        wt.add('foo')
669
 
        wt.commit(message=message)
670
 
        # check that command won't fail with unicode error
671
 
        # don't care about exact output because we have other tests for this
672
 
        out,err = self.run_bzr('log -p --long')
673
 
        self.assertNotEqual('', out)
674
 
        self.assertEqual('', err)
675
 
        out,err = self.run_bzr('log -p --short')
676
 
        self.assertNotEqual('', out)
677
 
        self.assertEqual('', err)
678
 
        out,err = self.run_bzr('log -p --line')
679
 
        self.assertNotEqual('', out)
680
 
        self.assertEqual('', err)
681
 
 
682
 
 
683
 
class TestLogEncodings(tests.TestCaseInTempDir):
684
 
 
685
 
    _mu = u'\xb5'
686
 
    _message = u'Message with \xb5'
687
 
 
688
 
    # Encodings which can encode mu
689
 
    good_encodings = [
690
 
        'utf-8',
691
 
        'latin-1',
692
 
        'iso-8859-1',
693
 
        'cp437', # Common windows encoding
694
 
        'cp1251', # Russian windows encoding
695
 
        'cp1258', # Common windows encoding
696
 
    ]
697
 
    # Encodings which cannot encode mu
698
 
    bad_encodings = [
699
 
        'ascii',
700
 
        'iso-8859-2',
701
 
        'koi8_r',
702
 
    ]
703
 
 
704
 
    def setUp(self):
705
 
        super(TestLogEncodings, self).setUp()
706
 
        self.user_encoding = osutils._cached_user_encoding
707
 
        def restore():
708
 
            osutils._cached_user_encoding = self.user_encoding
709
 
        self.addCleanup(restore)
710
 
 
711
 
    def create_branch(self):
712
 
        bzr = self.run_bzr
713
 
        bzr('init')
714
 
        open('a', 'wb').write('some stuff\n')
715
 
        bzr('add a')
716
 
        bzr(['commit', '-m', self._message])
717
 
 
718
 
    def try_encoding(self, encoding, fail=False):
719
 
        bzr = self.run_bzr
720
 
        if fail:
721
 
            self.assertRaises(UnicodeEncodeError,
722
 
                self._mu.encode, encoding)
723
 
            encoded_msg = self._message.encode(encoding, 'replace')
724
 
        else:
725
 
            encoded_msg = self._message.encode(encoding)
726
 
 
727
 
        old_encoding = osutils._cached_user_encoding
728
 
        # This test requires that 'run_bzr' uses the current
729
 
        # bzrlib, because we override user_encoding, and expect
730
 
        # it to be used
731
 
        try:
732
 
            osutils._cached_user_encoding = 'ascii'
733
 
            # We should be able to handle any encoding
734
 
            out, err = bzr('log', encoding=encoding)
735
 
            if not fail:
736
 
                # Make sure we wrote mu as we expected it to exist
737
 
                self.assertNotEqual(-1, out.find(encoded_msg))
738
 
                out_unicode = out.decode(encoding)
739
 
                self.assertNotEqual(-1, out_unicode.find(self._message))
740
 
            else:
741
 
                self.assertNotEqual(-1, out.find('Message with ?'))
742
 
        finally:
743
 
            osutils._cached_user_encoding = old_encoding
744
 
 
745
 
    def test_log_handles_encoding(self):
746
 
        self.create_branch()
747
 
 
748
 
        for encoding in self.good_encodings:
749
 
            self.try_encoding(encoding)
750
 
 
751
 
    def test_log_handles_bad_encoding(self):
752
 
        self.create_branch()
753
 
 
754
 
        for encoding in self.bad_encodings:
755
 
            self.try_encoding(encoding, fail=True)
756
 
 
757
 
    def test_stdout_encoding(self):
758
 
        bzr = self.run_bzr
759
 
        osutils._cached_user_encoding = "cp1251"
760
 
 
761
 
        bzr('init')
762
 
        self.build_tree(['a'])
763
 
        bzr('add a')
764
 
        bzr(['commit', '-m', u'\u0422\u0435\u0441\u0442'])
765
 
        stdout, stderr = self.run_bzr('log', encoding='cp866')
766
 
 
767
 
        message = stdout.splitlines()[-1]
768
 
 
769
 
        # explanation of the check:
770
 
        # u'\u0422\u0435\u0441\u0442' is word 'Test' in russian
771
 
        # in cp866  encoding this is string '\x92\xa5\xe1\xe2'
772
 
        # in cp1251 encoding this is string '\xd2\xe5\xf1\xf2'
773
 
        # This test should check that output of log command
774
 
        # encoded to sys.stdout.encoding
775
 
        test_in_cp866 = '\x92\xa5\xe1\xe2'
776
 
        test_in_cp1251 = '\xd2\xe5\xf1\xf2'
777
 
        # Make sure the log string is encoded in cp866
778
 
        self.assertEquals(test_in_cp866, message[2:])
779
 
        # Make sure the cp1251 string is not found anywhere
780
 
        self.assertEquals(-1, stdout.find(test_in_cp1251))
781
 
 
782
 
 
783
 
class TestLogFile(tests.TestCaseWithTransport):
784
 
 
785
 
    def test_log_local_branch_file(self):
786
 
        """We should be able to log files in local treeless branches"""
787
 
        tree = self.make_branch_and_tree('tree')
788
 
        self.build_tree(['tree/file'])
789
 
        tree.add('file')
790
 
        tree.commit('revision 1')
791
 
        tree.bzrdir.destroy_workingtree()
792
 
        self.run_bzr('log tree/file')
793
 
 
794
 
    def prepare_tree(self, complex=False):
795
 
        # The complex configuration includes deletes and renames
796
 
        tree = self.make_branch_and_tree('parent')
797
 
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
798
 
        tree.add('file1')
799
 
        tree.commit('add file1')
800
 
        tree.add('file2')
801
 
        tree.commit('add file2')
802
 
        tree.add('file3')
803
 
        tree.commit('add file3')
804
 
        child_tree = tree.bzrdir.sprout('child').open_workingtree()
805
 
        self.build_tree_contents([('child/file2', 'hello')])
806
 
        child_tree.commit(message='branch 1')
807
 
        tree.merge_from_branch(child_tree.branch)
808
 
        tree.commit(message='merge child branch')
809
 
        if complex:
810
 
            tree.remove('file2')
811
 
            tree.commit('remove file2')
812
 
            tree.rename_one('file3', 'file4')
813
 
            tree.commit('file3 is now called file4')
814
 
            tree.remove('file1')
815
 
            tree.commit('remove file1')
816
 
        os.chdir('parent')
817
 
 
818
 
    def test_log_file(self):
819
 
        """The log for a particular file should only list revs for that file"""
820
 
        self.prepare_tree()
821
 
        log = self.run_bzr('log -n0 file1')[0]
822
 
        self.assertContainsRe(log, 'revno: 1\n')
823
 
        self.assertNotContainsRe(log, 'revno: 2\n')
824
 
        self.assertNotContainsRe(log, 'revno: 3\n')
825
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
826
 
        self.assertNotContainsRe(log, 'revno: 4 ')
827
 
        log = self.run_bzr('log -n0 file2')[0]
828
 
        self.assertNotContainsRe(log, 'revno: 1\n')
829
 
        self.assertContainsRe(log, 'revno: 2\n')
830
 
        self.assertNotContainsRe(log, 'revno: 3\n')
831
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
832
 
        self.assertContainsRe(log, 'revno: 4 ')
833
 
        log = self.run_bzr('log -n0 file3')[0]
834
 
        self.assertNotContainsRe(log, 'revno: 1\n')
835
 
        self.assertNotContainsRe(log, 'revno: 2\n')
836
 
        self.assertContainsRe(log, 'revno: 3\n')
837
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
838
 
        self.assertNotContainsRe(log, 'revno: 4 ')
839
 
        log = self.run_bzr('log -n0 -r3.1.1 file2')[0]
840
 
        self.assertNotContainsRe(log, 'revno: 1\n')
841
 
        self.assertNotContainsRe(log, 'revno: 2\n')
842
 
        self.assertNotContainsRe(log, 'revno: 3\n')
843
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
844
 
        self.assertNotContainsRe(log, 'revno: 4 ')
845
 
        log = self.run_bzr('log -n0 -r4 file2')[0]
846
 
        self.assertNotContainsRe(log, 'revno: 1\n')
847
 
        self.assertNotContainsRe(log, 'revno: 2\n')
848
 
        self.assertNotContainsRe(log, 'revno: 3\n')
849
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
850
 
        self.assertContainsRe(log, 'revno: 4 ')
851
 
        log = self.run_bzr('log -n0 -r3.. file2')[0]
852
 
        self.assertNotContainsRe(log, 'revno: 1\n')
853
 
        self.assertNotContainsRe(log, 'revno: 2\n')
854
 
        self.assertNotContainsRe(log, 'revno: 3\n')
855
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
856
 
        self.assertContainsRe(log, 'revno: 4 ')
857
 
        log = self.run_bzr('log -n0 -r..3 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.assertNotContainsRe(log, 'revno: 3.1.1\n')
862
 
        self.assertNotContainsRe(log, 'revno: 4 ')
863
 
 
864
 
    def test_log_file_historical_missing(self):
865
 
        # Check logging a deleted file gives an error if the
866
 
        # file isn't found at the end or start of the revision range
867
 
        self.prepare_tree(complex=True)
868
 
        err_msg = "Path unknown at end or start of revision range: file2"
869
 
        err = self.run_bzr('log file2', retcode=3)[1]
870
 
        self.assertContainsRe(err, err_msg)
871
 
 
872
 
    def test_log_file_historical_end(self):
873
 
        # Check logging a deleted file is ok if the file existed
874
 
        # at the end the revision range
875
 
        self.prepare_tree(complex=True)
876
 
        log, err = self.run_bzr('log -n0 -r..4 file2')
877
 
        self.assertEquals('', err)
878
 
        self.assertNotContainsRe(log, 'revno: 1\n')
879
 
        self.assertContainsRe(log, 'revno: 2\n')
880
 
        self.assertNotContainsRe(log, 'revno: 3\n')
881
 
        self.assertContainsRe(log, 'revno: 3.1.1\n')
882
 
        self.assertContainsRe(log, 'revno: 4 ')
883
 
 
884
 
    def test_log_file_historical_start(self):
885
 
        # Check logging a deleted file is ok if the file existed
886
 
        # at the start of the revision range
887
 
        self.prepare_tree(complex=True)
888
 
        log, err = self.run_bzr('log file1')
889
 
        self.assertEquals('', err)
890
 
        self.assertContainsRe(log, 'revno: 1\n')
891
 
        self.assertNotContainsRe(log, 'revno: 2\n')
892
 
        self.assertNotContainsRe(log, 'revno: 3\n')
893
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
894
 
        self.assertNotContainsRe(log, 'revno: 4 ')
895
 
 
896
 
    def test_log_file_renamed(self):
897
 
        """File matched against revision range, not current tree."""
898
 
        self.prepare_tree(complex=True)
899
 
 
900
 
        # Check logging a renamed file gives an error by default
901
 
        err_msg = "Path unknown at end or start of revision range: file3"
902
 
        err = self.run_bzr('log file3', retcode=3)[1]
903
 
        self.assertContainsRe(err, err_msg)
904
 
 
905
 
        # Check we can see a renamed file if we give the right end revision
906
 
        log, err = self.run_bzr('log -r..4 file3')
907
 
        self.assertEquals('', err)
908
 
        self.assertNotContainsRe(log, 'revno: 1\n')
909
 
        self.assertNotContainsRe(log, 'revno: 2\n')
910
 
        self.assertContainsRe(log, 'revno: 3\n')
911
 
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
912
 
        self.assertNotContainsRe(log, 'revno: 4 ')
913
 
 
914
 
    def test_line_log_file(self):
915
 
        """The line log for a file should only list relevant mainline revs"""
916
 
        # Note: this also implicitly  covers the short logging case.
917
 
        # We test using --line in preference to --short because matching
918
 
        # revnos in the output of --line is more reliable.
919
 
        self.prepare_tree()
920
 
 
921
 
        # full history of file1
922
 
        log = self.run_bzr('log --line file1')[0]
923
 
        self.assertContainsRe(log, '^1:', re.MULTILINE)
924
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
925
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
926
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
927
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
928
 
 
929
 
        # full history of file2
930
 
        log = self.run_bzr('log --line file2')[0]
931
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
932
 
        self.assertContainsRe(log, '^2:', re.MULTILINE)
933
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
934
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
935
 
        self.assertContainsRe(log, '^4:', re.MULTILINE)
936
 
 
937
 
        # full history of file3
938
 
        log = self.run_bzr('log --line file3')[0]
939
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
940
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
941
 
        self.assertContainsRe(log, '^3:', re.MULTILINE)
942
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
943
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
944
 
 
945
 
        # file in a merge revision
946
 
        log = self.run_bzr('log --line -r3.1.1 file2')[0]
947
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
948
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
949
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
950
 
        self.assertContainsRe(log, '^3.1.1:', re.MULTILINE)
951
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
952
 
 
953
 
        # file in a mainline revision
954
 
        log = self.run_bzr('log --line -r4 file2')[0]
955
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
956
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
957
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
958
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
959
 
        self.assertContainsRe(log, '^4:', re.MULTILINE)
960
 
 
961
 
        # file since a revision
962
 
        log = self.run_bzr('log --line -r3.. file2')[0]
963
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
964
 
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
965
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
966
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
967
 
        self.assertContainsRe(log, '^4:', re.MULTILINE)
968
 
 
969
 
        # file up to a revision
970
 
        log = self.run_bzr('log --line -r..3 file2')[0]
971
 
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
972
 
        self.assertContainsRe(log, '^2:', re.MULTILINE)
973
 
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
974
 
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
975
 
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
976
 
 
977
 
 
978
 
class TestLogMultiple(tests.TestCaseWithTransport):
979
 
 
980
 
    def prepare_tree(self):
981
 
        tree = self.make_branch_and_tree('parent')
982
 
        self.build_tree([
983
 
            'parent/file1',
984
 
            'parent/file2',
985
 
            'parent/dir1/',
986
 
            'parent/dir1/file5',
987
 
            'parent/dir1/dir2/',
988
 
            'parent/dir1/dir2/file3',
989
 
            'parent/file4'])
990
 
        tree.add('file1')
991
 
        tree.commit('add file1')
992
 
        tree.add('file2')
993
 
        tree.commit('add file2')
994
 
        tree.add(['dir1', 'dir1/dir2', 'dir1/dir2/file3'])
995
 
        tree.commit('add file3')
996
 
        tree.add('file4')
997
 
        tree.commit('add file4')
998
 
        tree.add('dir1/file5')
999
 
        tree.commit('add file5')
1000
 
        child_tree = tree.bzrdir.sprout('child').open_workingtree()
1001
 
        self.build_tree_contents([('child/file2', 'hello')])
1002
 
        child_tree.commit(message='branch 1')
1003
 
        tree.merge_from_branch(child_tree.branch)
1004
 
        tree.commit(message='merge child branch')
1005
 
        os.chdir('parent')
1006
 
 
1007
 
    def assertRevnos(self, paths_str, expected_revnos):
1008
 
        # confirm the revision numbers in log --line output are those expected
1009
 
        out, err = self.run_bzr('log --line -n0 %s' % (paths_str,))
1010
 
        self.assertEqual('', err)
1011
 
        revnos = [s.split(':', 1)[0].lstrip() for s in out.splitlines()]
1012
 
        self.assertEqual(expected_revnos, revnos)
1013
 
 
1014
 
    def test_log_files(self):
1015
 
        """The log for multiple file should only list revs for those files"""
1016
 
        self.prepare_tree()
1017
 
        self.assertRevnos('file1 file2 dir1/dir2/file3',
1018
 
            ['6', '5.1.1', '3', '2', '1'])
1019
 
 
1020
 
    def test_log_directory(self):
1021
 
        """The log for a directory should show all nested files."""
1022
 
        self.prepare_tree()
1023
 
        self.assertRevnos('dir1', ['5', '3'])
1024
 
 
1025
 
    def test_log_nested_directory(self):
1026
 
        """The log for a directory should show all nested files."""
1027
 
        self.prepare_tree()
1028
 
        self.assertRevnos('dir1/dir2', ['3'])
1029
 
 
1030
 
    def test_log_in_nested_directory(self):
1031
 
        """The log for a directory should show all nested files."""
1032
 
        self.prepare_tree()
1033
 
        os.chdir("dir1")
1034
 
        self.assertRevnos('.', ['5', '3'])
1035
 
 
1036
 
    def test_log_files_and_directories(self):
1037
 
        """Logging files and directories together should be fine."""
1038
 
        self.prepare_tree()
1039
 
        self.assertRevnos('file4 dir1/dir2', ['4', '3'])
1040
 
 
1041
 
    def test_log_files_and_dirs_in_nested_directory(self):
1042
 
        """The log for a directory should show all nested files."""
1043
 
        self.prepare_tree()
1044
 
        os.chdir("dir1")
1045
 
        self.assertRevnos('dir2 file5', ['5', '3'])