/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: Ian Clatworthy
  • Date: 2009-03-25 05:33:40 UTC
  • mto: (4205.1.1 ianc-integration)
  • mto: This revision was merged to the branch mainline in revision 4206.
  • Revision ID: ian.clatworthy@canonical.com-20090325053340-86gbo7fh0dk09d32
get directory logging working again

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 -r-1")[0]
 
217
        self.assertContainsRe(log, r'    tags: tag1')
 
218
        log = self.run_bzr("log -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')
 
340
        self.assertEqual('', err)
 
341
        log = normalize_log(out)
 
342
        self.assertEqualDiff(log, """\
 
343
------------------------------------------------------------
 
344
revno: 2
 
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
 
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
 
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
 
 
402
    def test_force_merge_revisions_on(self):
 
403
        self._prepare_short()
 
404
        out,err = self.run_bzr('log --short -n0')
 
405
        self.assertEqual('', err)
 
406
        log = normalize_log(out)
 
407
        self.assertEqualDiff(log, """\
 
408
    2 Joe Foo\t2005-11-22 [merge]
 
409
      merge branch 1
 
410
 
 
411
          1.1.2 Joe Foo\t2005-11-22 [merge]
 
412
                merge branch 2
 
413
 
 
414
              1.2.1 Joe Foo\t2005-11-22
 
415
                    branch 2
 
416
 
 
417
          1.1.1 Joe Foo\t2005-11-22
 
418
                branch 1
 
419
 
 
420
    1 Joe Foo\t2005-11-22
 
421
      first post
 
422
 
 
423
""")
 
424
 
 
425
    def test_force_merge_revisions_N(self):
 
426
        self._prepare_short()
 
427
        out,err = self.run_bzr('log --short -n2')
 
428
        self.assertEqual('', err)
 
429
        log = normalize_log(out)
 
430
        self.assertEqualDiff(log, """\
 
431
    2 Joe Foo\t2005-11-22 [merge]
 
432
      merge branch 1
 
433
 
 
434
          1.1.2 Joe Foo\t2005-11-22 [merge]
 
435
                merge branch 2
 
436
 
 
437
          1.1.1 Joe Foo\t2005-11-22
 
438
                branch 1
 
439
 
 
440
    1 Joe Foo\t2005-11-22
 
441
      first post
 
442
 
 
443
""")
 
444
 
 
445
    def test_merges_single_merge_rev(self):
 
446
        self._prepare()
 
447
        out,err = self.run_bzr('log -r1.1.2')
 
448
        self.assertEqual('', err)
 
449
        log = normalize_log(out)
 
450
        self.assertEqualDiff(log, """\
 
451
------------------------------------------------------------
 
452
revno: 1.1.2
 
453
committer: Lorem Ipsum <test@example.com>
 
454
branch nick: child
 
455
timestamp: Just now
 
456
message:
 
457
  merge branch 2
 
458
    ------------------------------------------------------------
 
459
    revno: 1.2.1
 
460
    committer: Lorem Ipsum <test@example.com>
 
461
    branch nick: smallerchild
 
462
    timestamp: Just now
 
463
    message:
 
464
      branch 2
 
465
""")
 
466
 
 
467
    def test_merges_partial_range(self):
 
468
        self._prepare()
 
469
        out, err = self.run_bzr('log -r1.1.1..1.1.2')
 
470
        self.assertEqual('', err)
 
471
        log = normalize_log(out)
 
472
        self.assertEqualDiff(log, """\
 
473
------------------------------------------------------------
 
474
revno: 1.1.2
 
475
committer: Lorem Ipsum <test@example.com>
 
476
branch nick: child
 
477
timestamp: Just now
 
478
message:
 
479
  merge branch 2
 
480
    ------------------------------------------------------------
 
481
    revno: 1.2.1
 
482
    committer: Lorem Ipsum <test@example.com>
 
483
    branch nick: smallerchild
 
484
    timestamp: Just now
 
485
    message:
 
486
      branch 2
 
487
------------------------------------------------------------
 
488
revno: 1.1.1
 
489
committer: Lorem Ipsum <test@example.com>
 
490
branch nick: child
 
491
timestamp: Just now
 
492
message:
 
493
  branch 1
 
494
""")
 
495
 
 
496
    def test_merges_nonsupporting_formatter(self):
 
497
        # This "feature" of log formatters is madness. If a log
 
498
        # formatter cannot display a dotted-revno, it ought to ignore it.
 
499
        # Otherwise, a linear sequence is always expected to be handled now.
 
500
        raise KnownFailure('log formatters must support linear sequences now')
 
501
        self._prepare()
 
502
        err_msg = 'Selected log formatter only supports mainline revisions.'
 
503
        # The single revision case is tested in the core tests
 
504
        # since all standard formatters support single merge revisions.
 
505
        out,err = self.run_bzr('log --short -r1..1.1.2', retcode=3)
 
506
        self.assertContainsRe(err, err_msg)
 
507
        out,err = self.run_bzr('log --short -r1.1.1..1.1.2', retcode=3)
 
508
        self.assertContainsRe(err, err_msg)
 
509
 
 
510
 
 
511
def subst_dates(string):
 
512
    """Replace date strings with constant values."""
 
513
    return re.sub(r'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} [-\+]\d{4}',
 
514
                  'YYYY-MM-DD HH:MM:SS +ZZZZ', string)
 
515
 
 
516
 
 
517
def subst_short_dates(string):
 
518
    """Replace date strings (without time or timezone) with constant values."""
 
519
    return re.sub(r'\d{4}-\d{2}-\d{2}',
 
520
                  'YYYY-MM-DD', string)
 
521
 
 
522
 
 
523
class TestLogDiff(TestCaseWithoutPropsHandler):
 
524
 
 
525
    def _prepare(self):
 
526
        parent_tree = self.make_branch_and_tree('parent')
 
527
        self.build_tree(['parent/file1', 'parent/file2'])
 
528
        parent_tree.add('file1')
 
529
        parent_tree.add('file2')
 
530
        parent_tree.commit(message='first post',
 
531
            timestamp=1132586655, timezone=36000,
 
532
            committer='Lorem Ipsum <test@example.com>')
 
533
        child_tree = parent_tree.bzrdir.sprout('child').open_workingtree()
 
534
        self.build_tree_contents([('child/file2', 'hello\n')])
 
535
        child_tree.commit(message='branch 1',
 
536
            timestamp=1132586700, timezone=36000,
 
537
            committer='Lorem Ipsum <test@example.com>')
 
538
        parent_tree.merge_from_branch(child_tree.branch)
 
539
        parent_tree.commit(message='merge branch 1',
 
540
            timestamp=1132586800, timezone=36000,
 
541
            committer='Lorem Ipsum <test@example.com>')
 
542
        os.chdir('parent')
 
543
 
 
544
    def test_log_show_diff_long(self):
 
545
        self._prepare()
 
546
        out,err = self.run_bzr('log -p')
 
547
        self.assertEqual('', err)
 
548
        log = normalize_log(out)
 
549
        self.assertEqualDiff(subst_dates(log), """\
 
550
------------------------------------------------------------
 
551
revno: 2
 
552
committer: Lorem Ipsum <test@example.com>
 
553
branch nick: parent
 
554
timestamp: Just now
 
555
message:
 
556
  merge branch 1
 
557
diff:
 
558
=== modified file 'file2'
 
559
--- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
560
+++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
561
@@ -1,1 +1,1 @@
 
562
-contents of parent/file2
 
563
+hello
 
564
    ------------------------------------------------------------
 
565
    revno: 1.1.1
 
566
    committer: Lorem Ipsum <test@example.com>
 
567
    branch nick: child
 
568
    timestamp: Just now
 
569
    message:
 
570
      branch 1
 
571
    diff:
 
572
    === modified file 'file2'
 
573
    --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
574
    +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
575
    @@ -1,1 +1,1 @@
 
576
    -contents of parent/file2
 
577
    +hello
 
578
------------------------------------------------------------
 
579
revno: 1
 
580
committer: Lorem Ipsum <test@example.com>
 
581
branch nick: parent
 
582
timestamp: Just now
 
583
message:
 
584
  first post
 
585
diff:
 
586
=== added file 'file1'
 
587
--- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
588
+++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
589
@@ -0,0 +1,1 @@
 
590
+contents of parent/file1
 
591
 
 
592
=== added file 'file2'
 
593
--- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
594
+++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
595
@@ -0,0 +1,1 @@
 
596
+contents of parent/file2
 
597
""")
 
598
 
 
599
    def test_log_show_diff_short(self):
 
600
        self._prepare()
 
601
        out,err = self.run_bzr('log -p --short')
 
602
        self.assertEqual('', err)
 
603
        log = normalize_log(out)
 
604
        self.assertEqualDiff(subst_dates(log), """\
 
605
    2 Lorem Ipsum\t2005-11-22 [merge]
 
606
      merge branch 1
 
607
      === modified file 'file2'
 
608
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
609
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
610
      @@ -1,1 +1,1 @@
 
611
      -contents of parent/file2
 
612
      +hello
 
613
 
 
614
    1 Lorem Ipsum\t2005-11-22
 
615
      first post
 
616
      === added file 'file1'
 
617
      --- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
618
      +++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
619
      @@ -0,0 +1,1 @@
 
620
      +contents of parent/file1
 
621
\x20\x20\x20\x20\x20\x20
 
622
      === added file 'file2'
 
623
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
624
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
625
      @@ -0,0 +1,1 @@
 
626
      +contents of parent/file2
 
627
 
 
628
""")
 
629
 
 
630
    def test_log_show_diff_line(self):
 
631
        self._prepare()
 
632
        out,err = self.run_bzr('log -p --line')
 
633
        self.assertEqual('', err)
 
634
        log = normalize_log(out)
 
635
        # Not supported by this formatter so expect plain output
 
636
        self.assertEqualDiff(subst_dates(log), """\
 
637
2: Lorem Ipsum 2005-11-22 [merge] merge branch 1
 
638
1: Lorem Ipsum 2005-11-22 first post
 
639
""")
 
640
 
 
641
    def test_log_show_diff_file(self):
 
642
        """Only the diffs for the given file are to be shown"""
 
643
        self._prepare()
 
644
        out,err = self.run_bzr('log -p --short file2')
 
645
        self.assertEqual('', err)
 
646
        log = normalize_log(out)
 
647
        self.assertEqualDiff(subst_dates(log), """\
 
648
    2 Lorem Ipsum\t2005-11-22 [merge]
 
649
      merge branch 1
 
650
      === modified file 'file2'
 
651
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
652
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
653
      @@ -1,1 +1,1 @@
 
654
      -contents of parent/file2
 
655
      +hello
 
656
 
 
657
    1 Lorem Ipsum\t2005-11-22
 
658
      first post
 
659
      === added file 'file2'
 
660
      --- file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
661
      +++ file2\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
662
      @@ -0,0 +1,1 @@
 
663
      +contents of parent/file2
 
664
 
 
665
""")
 
666
        out,err = self.run_bzr('log -p --short file1')
 
667
        self.assertEqual('', err)
 
668
        log = normalize_log(out)
 
669
        self.assertEqualDiff(subst_dates(log), """\
 
670
    1 Lorem Ipsum\t2005-11-22
 
671
      first post
 
672
      === added file 'file1'
 
673
      --- file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
674
      +++ file1\tYYYY-MM-DD HH:MM:SS +ZZZZ
 
675
      @@ -0,0 +1,1 @@
 
676
      +contents of parent/file1
 
677
 
 
678
""")
 
679
 
 
680
    def test_log_show_diff_non_ascii(self):
 
681
        # Smoke test for bug #328007 UnicodeDecodeError on 'log -p'
 
682
        message = u'Message with \xb5'
 
683
        body = 'Body with \xb5\n'
 
684
        wt = self.make_branch_and_tree('.')
 
685
        self.build_tree_contents([('foo', body)])
 
686
        wt.add('foo')
 
687
        wt.commit(message=message)
 
688
        # check that command won't fail with unicode error
 
689
        # don't care about exact output because we have other tests for this
 
690
        out,err = self.run_bzr('log -p --long')
 
691
        self.assertNotEqual('', out)
 
692
        self.assertEqual('', err)
 
693
        out,err = self.run_bzr('log -p --short')
 
694
        self.assertNotEqual('', out)
 
695
        self.assertEqual('', err)
 
696
        out,err = self.run_bzr('log -p --line')
 
697
        self.assertNotEqual('', out)
 
698
        self.assertEqual('', err)
 
699
 
 
700
 
 
701
class TestLogEncodings(TestCaseInTempDir):
 
702
 
 
703
    _mu = u'\xb5'
 
704
    _message = u'Message with \xb5'
 
705
 
 
706
    # Encodings which can encode mu
 
707
    good_encodings = [
 
708
        'utf-8',
 
709
        'latin-1',
 
710
        'iso-8859-1',
 
711
        'cp437', # Common windows encoding
 
712
        'cp1251', # Russian windows encoding
 
713
        'cp1258', # Common windows encoding
 
714
    ]
 
715
    # Encodings which cannot encode mu
 
716
    bad_encodings = [
 
717
        'ascii',
 
718
        'iso-8859-2',
 
719
        'koi8_r',
 
720
    ]
 
721
 
 
722
    def setUp(self):
 
723
        TestCaseInTempDir.setUp(self)
 
724
        self.user_encoding = osutils._cached_user_encoding
 
725
 
 
726
    def tearDown(self):
 
727
        osutils._cached_user_encoding = self.user_encoding
 
728
        TestCaseInTempDir.tearDown(self)
 
729
 
 
730
    def create_branch(self):
 
731
        bzr = self.run_bzr
 
732
        bzr('init')
 
733
        open('a', 'wb').write('some stuff\n')
 
734
        bzr('add a')
 
735
        bzr(['commit', '-m', self._message])
 
736
 
 
737
    def try_encoding(self, encoding, fail=False):
 
738
        bzr = self.run_bzr
 
739
        if fail:
 
740
            self.assertRaises(UnicodeEncodeError,
 
741
                self._mu.encode, encoding)
 
742
            encoded_msg = self._message.encode(encoding, 'replace')
 
743
        else:
 
744
            encoded_msg = self._message.encode(encoding)
 
745
 
 
746
        old_encoding = osutils._cached_user_encoding
 
747
        # This test requires that 'run_bzr' uses the current
 
748
        # bzrlib, because we override user_encoding, and expect
 
749
        # it to be used
 
750
        try:
 
751
            osutils._cached_user_encoding = 'ascii'
 
752
            # We should be able to handle any encoding
 
753
            out, err = bzr('log', encoding=encoding)
 
754
            if not fail:
 
755
                # Make sure we wrote mu as we expected it to exist
 
756
                self.assertNotEqual(-1, out.find(encoded_msg))
 
757
                out_unicode = out.decode(encoding)
 
758
                self.assertNotEqual(-1, out_unicode.find(self._message))
 
759
            else:
 
760
                self.assertNotEqual(-1, out.find('Message with ?'))
 
761
        finally:
 
762
            osutils._cached_user_encoding = old_encoding
 
763
 
 
764
    def test_log_handles_encoding(self):
 
765
        self.create_branch()
 
766
 
 
767
        for encoding in self.good_encodings:
 
768
            self.try_encoding(encoding)
 
769
 
 
770
    def test_log_handles_bad_encoding(self):
 
771
        self.create_branch()
 
772
 
 
773
        for encoding in self.bad_encodings:
 
774
            self.try_encoding(encoding, fail=True)
 
775
 
 
776
    def test_stdout_encoding(self):
 
777
        bzr = self.run_bzr
 
778
        osutils._cached_user_encoding = "cp1251"
 
779
 
 
780
        bzr('init')
 
781
        self.build_tree(['a'])
 
782
        bzr('add a')
 
783
        bzr(['commit', '-m', u'\u0422\u0435\u0441\u0442'])
 
784
        stdout, stderr = self.run_bzr('log', encoding='cp866')
 
785
 
 
786
        message = stdout.splitlines()[-1]
 
787
 
 
788
        # explanation of the check:
 
789
        # u'\u0422\u0435\u0441\u0442' is word 'Test' in russian
 
790
        # in cp866  encoding this is string '\x92\xa5\xe1\xe2'
 
791
        # in cp1251 encoding this is string '\xd2\xe5\xf1\xf2'
 
792
        # This test should check that output of log command
 
793
        # encoded to sys.stdout.encoding
 
794
        test_in_cp866 = '\x92\xa5\xe1\xe2'
 
795
        test_in_cp1251 = '\xd2\xe5\xf1\xf2'
 
796
        # Make sure the log string is encoded in cp866
 
797
        self.assertEquals(test_in_cp866, message[2:])
 
798
        # Make sure the cp1251 string is not found anywhere
 
799
        self.assertEquals(-1, stdout.find(test_in_cp1251))
 
800
 
 
801
 
 
802
class TestLogFile(TestCaseWithTransport):
 
803
 
 
804
    def test_log_local_branch_file(self):
 
805
        """We should be able to log files in local treeless branches"""
 
806
        tree = self.make_branch_and_tree('tree')
 
807
        self.build_tree(['tree/file'])
 
808
        tree.add('file')
 
809
        tree.commit('revision 1')
 
810
        tree.bzrdir.destroy_workingtree()
 
811
        self.run_bzr('log tree/file')
 
812
 
 
813
    def prepare_tree(self, complex=False):
 
814
        # The complex configuration includes deletes and renames
 
815
        tree = self.make_branch_and_tree('parent')
 
816
        self.build_tree(['parent/file1', 'parent/file2', 'parent/file3'])
 
817
        tree.add('file1')
 
818
        tree.commit('add file1')
 
819
        tree.add('file2')
 
820
        tree.commit('add file2')
 
821
        tree.add('file3')
 
822
        tree.commit('add file3')
 
823
        child_tree = tree.bzrdir.sprout('child').open_workingtree()
 
824
        self.build_tree_contents([('child/file2', 'hello')])
 
825
        child_tree.commit(message='branch 1')
 
826
        tree.merge_from_branch(child_tree.branch)
 
827
        tree.commit(message='merge child branch')
 
828
        if complex:
 
829
            tree.remove('file2')
 
830
            tree.commit('remove file2')
 
831
            tree.rename_one('file3', 'file4')
 
832
            tree.commit('file3 is now called file4')
 
833
            tree.remove('file1')
 
834
            tree.commit('remove file1')
 
835
        os.chdir('parent')
 
836
 
 
837
    def test_log_file(self):
 
838
        """The log for a particular file should only list revs for that file"""
 
839
        self.prepare_tree()
 
840
        log = self.run_bzr('log file1')[0]
 
841
        self.assertContainsRe(log, 'revno: 1\n')
 
842
        self.assertNotContainsRe(log, 'revno: 2\n')
 
843
        self.assertNotContainsRe(log, 'revno: 3\n')
 
844
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
845
        self.assertNotContainsRe(log, 'revno: 4\n')
 
846
        log = self.run_bzr('log file2')[0]
 
847
        self.assertNotContainsRe(log, 'revno: 1\n')
 
848
        self.assertContainsRe(log, 'revno: 2\n')
 
849
        self.assertNotContainsRe(log, 'revno: 3\n')
 
850
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
851
        self.assertContainsRe(log, 'revno: 4\n')
 
852
        log = self.run_bzr('log file3')[0]
 
853
        self.assertNotContainsRe(log, 'revno: 1\n')
 
854
        self.assertNotContainsRe(log, 'revno: 2\n')
 
855
        self.assertContainsRe(log, 'revno: 3\n')
 
856
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
857
        self.assertNotContainsRe(log, 'revno: 4\n')
 
858
        log = self.run_bzr('log -r3.1.1 file2')[0]
 
859
        self.assertNotContainsRe(log, 'revno: 1\n')
 
860
        self.assertNotContainsRe(log, 'revno: 2\n')
 
861
        self.assertNotContainsRe(log, 'revno: 3\n')
 
862
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
863
        self.assertNotContainsRe(log, 'revno: 4\n')
 
864
        log = self.run_bzr('log -r4 file2')[0]
 
865
        self.assertNotContainsRe(log, 'revno: 1\n')
 
866
        self.assertNotContainsRe(log, 'revno: 2\n')
 
867
        self.assertNotContainsRe(log, 'revno: 3\n')
 
868
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
869
        self.assertContainsRe(log, 'revno: 4\n')
 
870
        log = self.run_bzr('log -r3.. file2')[0]
 
871
        self.assertNotContainsRe(log, 'revno: 1\n')
 
872
        self.assertNotContainsRe(log, 'revno: 2\n')
 
873
        self.assertNotContainsRe(log, 'revno: 3\n')
 
874
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
875
        self.assertContainsRe(log, 'revno: 4\n')
 
876
        log = self.run_bzr('log -r..3 file2')[0]
 
877
        self.assertNotContainsRe(log, 'revno: 1\n')
 
878
        self.assertContainsRe(log, 'revno: 2\n')
 
879
        self.assertNotContainsRe(log, 'revno: 3\n')
 
880
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
881
        self.assertNotContainsRe(log, 'revno: 4\n')
 
882
 
 
883
    def test_log_file_historical_missing(self):
 
884
        # Check logging a deleted file gives an error if the
 
885
        # file isn't found at the end or start of the revision range
 
886
        self.prepare_tree(complex=True)
 
887
        err_msg = "Path unknown at end or start of revision range: file2"
 
888
        err = self.run_bzr('log file2', retcode=3)[1]
 
889
        self.assertContainsRe(err, err_msg)
 
890
 
 
891
    def test_log_file_historical_end(self):
 
892
        # Check logging a deleted file is ok if the file existed
 
893
        # at the end the revision range
 
894
        self.prepare_tree(complex=True)
 
895
        log, err = self.run_bzr('log -r..4 file2')
 
896
        self.assertEquals('', err)
 
897
        self.assertNotContainsRe(log, 'revno: 1\n')
 
898
        self.assertContainsRe(log, 'revno: 2\n')
 
899
        self.assertNotContainsRe(log, 'revno: 3\n')
 
900
        self.assertContainsRe(log, 'revno: 3.1.1\n')
 
901
        self.assertContainsRe(log, 'revno: 4\n')
 
902
 
 
903
    def test_log_file_historical_start(self):
 
904
        # Check logging a deleted file is ok if the file existed
 
905
        # at the start of the revision range
 
906
        self.prepare_tree(complex=True)
 
907
        log, err = self.run_bzr('log file1')
 
908
        self.assertEquals('', err)
 
909
        self.assertContainsRe(log, 'revno: 1\n')
 
910
        self.assertNotContainsRe(log, 'revno: 2\n')
 
911
        self.assertNotContainsRe(log, 'revno: 3\n')
 
912
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
913
        self.assertNotContainsRe(log, 'revno: 4\n')
 
914
 
 
915
    def test_log_file_renamed(self):
 
916
        """File matched against revision range, not current tree."""
 
917
        self.prepare_tree(complex=True)
 
918
 
 
919
        # Check logging a renamed file gives an error by default
 
920
        err_msg = "Path unknown at end or start of revision range: file3"
 
921
        err = self.run_bzr('log file3', retcode=3)[1]
 
922
        self.assertContainsRe(err, err_msg)
 
923
 
 
924
        # Check we can see a renamed file if we give the right end revision
 
925
        log, err = self.run_bzr('log -r..4 file3')
 
926
        self.assertEquals('', err)
 
927
        self.assertNotContainsRe(log, 'revno: 1\n')
 
928
        self.assertNotContainsRe(log, 'revno: 2\n')
 
929
        self.assertContainsRe(log, 'revno: 3\n')
 
930
        self.assertNotContainsRe(log, 'revno: 3.1.1\n')
 
931
        self.assertNotContainsRe(log, 'revno: 4\n')
 
932
 
 
933
    def test_line_log_file(self):
 
934
        """The line log for a file should only list relevant mainline revs"""
 
935
        # Note: this also implicitly  covers the short logging case.
 
936
        # We test using --line in preference to --short because matching
 
937
        # revnos in the output of --line is more reliable.
 
938
        self.prepare_tree()
 
939
 
 
940
        # full history of file1
 
941
        log = self.run_bzr('log --line file1')[0]
 
942
        self.assertContainsRe(log, '^1:', re.MULTILINE)
 
943
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
 
944
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
 
945
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
 
946
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
 
947
 
 
948
        # full history of file2
 
949
        log = self.run_bzr('log --line file2')[0]
 
950
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
 
951
        self.assertContainsRe(log, '^2:', re.MULTILINE)
 
952
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
 
953
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
 
954
        self.assertContainsRe(log, '^4:', re.MULTILINE)
 
955
 
 
956
        # full history of file3
 
957
        log = self.run_bzr('log --line file3')[0]
 
958
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
 
959
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
 
960
        self.assertContainsRe(log, '^3:', re.MULTILINE)
 
961
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
 
962
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
 
963
 
 
964
        # file in a merge revision
 
965
        log = self.run_bzr('log --line -r3.1.1 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.assertContainsRe(log, '^3.1.1:', re.MULTILINE)
 
970
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
 
971
 
 
972
        # file in a mainline revision
 
973
        log = self.run_bzr('log --line -r4 file2')[0]
 
974
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
 
975
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
 
976
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
 
977
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
 
978
        self.assertContainsRe(log, '^4:', re.MULTILINE)
 
979
 
 
980
        # file since a revision
 
981
        log = self.run_bzr('log --line -r3.. file2')[0]
 
982
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
 
983
        self.assertNotContainsRe(log, '^2:', re.MULTILINE)
 
984
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
 
985
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
 
986
        self.assertContainsRe(log, '^4:', re.MULTILINE)
 
987
 
 
988
        # file up to a revision
 
989
        log = self.run_bzr('log --line -r..3 file2')[0]
 
990
        self.assertNotContainsRe(log, '^1:', re.MULTILINE)
 
991
        self.assertContainsRe(log, '^2:', re.MULTILINE)
 
992
        self.assertNotContainsRe(log, '^3:', re.MULTILINE)
 
993
        self.assertNotContainsRe(log, '^3.1.1:', re.MULTILINE)
 
994
        self.assertNotContainsRe(log, '^4:', re.MULTILINE)
 
995
 
 
996
 
 
997
class TestLogMultiple(TestCaseWithTransport):
 
998
 
 
999
    def prepare_tree(self):
 
1000
        tree = self.make_branch_and_tree('parent')
 
1001
        self.build_tree([
 
1002
            'parent/file1',
 
1003
            'parent/file2',
 
1004
            'parent/dir1/',
 
1005
            'parent/dir1/file5',
 
1006
            'parent/dir1/dir2/',
 
1007
            'parent/dir1/dir2/file3',
 
1008
            'parent/file4'])
 
1009
        tree.add('file1')
 
1010
        tree.commit('add file1', committer='Lorem Ipsum <test@example.com>')
 
1011
        tree.add('file2')
 
1012
        tree.commit('add file2', committer='Lorem Ipsum <test@example.com>')
 
1013
        tree.add(['dir1', 'dir1/dir2', 'dir1/dir2/file3'])
 
1014
        tree.commit('add file3', committer='Lorem Ipsum <test@example.com>')
 
1015
        tree.add('file4')
 
1016
        tree.commit('add file4', committer='Lorem Ipsum <test@example.com>')
 
1017
        tree.add('dir1/file5')
 
1018
        tree.commit('add file5', committer='Lorem Ipsum <test@example.com>')
 
1019
        child_tree = tree.bzrdir.sprout('child').open_workingtree()
 
1020
        self.build_tree_contents([('child/file2', 'hello')])
 
1021
        child_tree.commit(message='branch 1',
 
1022
            committer='Lorem Ipsum <test@example.com>')
 
1023
        tree.merge_from_branch(child_tree.branch)
 
1024
        tree.commit(message='merge child branch',
 
1025
            committer='Lorem Ipsum <test@example.com>')
 
1026
        os.chdir('parent')
 
1027
 
 
1028
    def test_log_files(self):
 
1029
        """The log for multiple file should only list revs for those files"""
 
1030
        self.prepare_tree()
 
1031
        out, err = self.run_bzr('log --line -n0 file1 file2 dir1/dir2/file3')
 
1032
        self.assertEqual('', err)
 
1033
        log = normalize_log(out)
 
1034
        self.assertEqualDiff(subst_short_dates(log), """\
 
1035
6: Lorem Ipsum YYYY-MM-DD [merge] merge child branch
 
1036
  5.1.1: Lorem Ipsum YYYY-MM-DD branch 1
 
1037
3: Lorem Ipsum YYYY-MM-DD add file3
 
1038
2: Lorem Ipsum YYYY-MM-DD add file2
 
1039
1: Lorem Ipsum YYYY-MM-DD add file1
 
1040
""")
 
1041
 
 
1042
    def test_log_directory(self):
 
1043
        """The log for a directory should show all nested files."""
 
1044
        self.prepare_tree()
 
1045
        out, err = self.run_bzr('log --line -n0 dir1')
 
1046
        self.assertEqual('', err)
 
1047
        log = normalize_log(out)
 
1048
        self.assertEqualDiff(subst_short_dates(log), """\
 
1049
5: Lorem Ipsum YYYY-MM-DD add file5
 
1050
3: Lorem Ipsum YYYY-MM-DD add file3
 
1051
""")
 
1052
 
 
1053
    def test_log_nested_directory(self):
 
1054
        """The log for a directory should show all nested files."""
 
1055
        self.prepare_tree()
 
1056
        out, err = self.run_bzr('log --line -n0 dir1/dir2')
 
1057
        self.assertEqual('', err)
 
1058
        log = normalize_log(out)
 
1059
        self.assertEqualDiff(subst_short_dates(log), """\
 
1060
3: Lorem Ipsum YYYY-MM-DD add file3
 
1061
""")
 
1062
 
 
1063
    def test_log_in_nested_directory(self):
 
1064
        """The log for a directory should show all nested files."""
 
1065
        self.prepare_tree()
 
1066
        os.chdir("dir1")
 
1067
        out, err = self.run_bzr('log --line -n0 .')
 
1068
        self.assertEqual('', err)
 
1069
        log = normalize_log(out)
 
1070
        self.assertEqualDiff(subst_short_dates(log), """\
 
1071
5: Lorem Ipsum YYYY-MM-DD add file5
 
1072
3: Lorem Ipsum YYYY-MM-DD add file3
 
1073
""")
 
1074
 
 
1075
    def test_log_files_and_directories(self):
 
1076
        """Logging files and directories together should be fine."""
 
1077
        self.prepare_tree()
 
1078
        out, err = self.run_bzr('log --line -n0 file4 dir1/dir2')
 
1079
        self.assertEqual('', err)
 
1080
        log = normalize_log(out)
 
1081
        self.assertEqualDiff(subst_short_dates(log), """\
 
1082
4: Lorem Ipsum YYYY-MM-DD add file4
 
1083
3: Lorem Ipsum YYYY-MM-DD add file3
 
1084
""")
 
1085
 
 
1086
    def test_log_files_and_dirs_in_nested_directory(self):
 
1087
        """The log for a directory should show all nested files."""
 
1088
        self.prepare_tree()
 
1089
        os.chdir("dir1")
 
1090
        out, err = self.run_bzr('log --line -n0 dir2 file5')
 
1091
        self.assertEqual('', err)
 
1092
        log = normalize_log(out)
 
1093
        self.assertEqualDiff(subst_short_dates(log), """\
 
1094
5: Lorem Ipsum YYYY-MM-DD add file5
 
1095
3: Lorem Ipsum YYYY-MM-DD add file3
 
1096
""")