~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Martin Pool
  • Date: 2005-05-17 07:51:51 UTC
  • Revision ID: mbp@sourcefrog.net-20050517075151-b64853a6a38a6225
- export bzrlib.find_branch

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