/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: Jelmer Vernooij
  • Date: 2009-05-26 07:48:03 UTC
  • mto: This revision was merged to the branch mainline in revision 4381.
  • Revision ID: jelmer@samba.org-20090526074803-fx1cdhcfcuxux8pf
Review feedback from Ian.

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'])