/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 breezy/tests/test_log.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2018-09-22 02:38:35 UTC
  • mfrom: (7058.5.4 upload-symlin)
  • Revision ID: breezy.the.bot@gmail.com-20180922023835-wb9nczxp63jpeudb
Add symlink support to 'brz upload'.

Merged from https://code.launchpad.net/~jelmer/brz/upload-symlinks/+merge/355061

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2013, 2016 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
import os
18
 
from cStringIO import StringIO
19
18
 
20
 
from bzrlib import (
 
19
from .. import (
21
20
    branchbuilder,
22
21
    errors,
23
22
    log,
24
23
    registry,
25
24
    revision,
26
25
    revisionspec,
27
 
    symbol_versioning,
28
26
    tests,
 
27
    gpg,
 
28
    trace,
 
29
    )
 
30
from ..sixish import (
 
31
    BytesIO,
 
32
    StringIO,
 
33
    unichr,
29
34
    )
30
35
 
31
36
 
88
93
        """Helper method for LogFormatter tests"""
89
94
        b = wt.branch
90
95
        b.nick = 'test'
91
 
        self.build_tree_contents([('a', 'hello moto\n')])
92
 
        self.wt_commit(wt, 'simple log message', rev_id='a1')
93
 
        self.build_tree_contents([('b', 'goodbye\n')])
 
96
        self.build_tree_contents([('a', b'hello moto\n')])
 
97
        self.wt_commit(wt, 'simple log message', rev_id=b'a1')
 
98
        self.build_tree_contents([('b', b'goodbye\n')])
94
99
        wt.add('b')
95
 
        self.wt_commit(wt, 'multiline\nlog\nmessage\n', rev_id='a2')
 
100
        self.wt_commit(wt, 'multiline\nlog\nmessage\n', rev_id=b'a2')
96
101
 
97
 
        self.build_tree_contents([('c', 'just another manic monday\n')])
 
102
        self.build_tree_contents([('c', b'just another manic monday\n')])
98
103
        wt.add('c')
99
 
        self.wt_commit(wt, 'single line with trailing newline\n', rev_id='a3')
 
104
        self.wt_commit(wt, 'single line with trailing newline\n', rev_id=b'a3')
100
105
        return b
101
106
 
102
107
    def _prepare_tree_with_merges(self, with_tags=False):
104
109
        wt.lock_write()
105
110
        self.addCleanup(wt.unlock)
106
111
        wt.add('')
107
 
        self.wt_commit(wt, 'rev-1', rev_id='rev-1')
108
 
        self.wt_commit(wt, 'rev-merged', rev_id='rev-2a')
109
 
        wt.set_parent_ids(['rev-1', 'rev-2a'])
110
 
        wt.branch.set_last_revision_info(1, 'rev-1')
111
 
        self.wt_commit(wt, 'rev-2', rev_id='rev-2b')
 
112
        self.wt_commit(wt, 'rev-1', rev_id=b'rev-1')
 
113
        self.wt_commit(wt, 'rev-merged', rev_id=b'rev-2a')
 
114
        wt.set_parent_ids([b'rev-1', b'rev-2a'])
 
115
        wt.branch.set_last_revision_info(1, b'rev-1')
 
116
        self.wt_commit(wt, 'rev-2', rev_id=b'rev-2b')
112
117
        if with_tags:
113
118
            branch = wt.branch
114
 
            branch.tags.set_tag('v0.2', 'rev-2b')
115
 
            self.wt_commit(wt, 'rev-3', rev_id='rev-3')
116
 
            branch.tags.set_tag('v1.0rc1', 'rev-3')
117
 
            branch.tags.set_tag('v1.0', 'rev-3')
 
119
            branch.tags.set_tag('v0.2', b'rev-2b')
 
120
            self.wt_commit(wt, 'rev-3', rev_id=b'rev-3')
 
121
            branch.tags.set_tag('v1.0rc1', b'rev-3')
 
122
            branch.tags.set_tag('v1.0', b'rev-3')
118
123
        return wt
119
124
 
 
125
 
120
126
class LogCatcher(log.LogFormatter):
121
127
    """Pull log messages into a list rather than displaying them.
122
128
 
173
179
        self.assertInvalidRevisonNumber(b, 2, 1)
174
180
        self.assertInvalidRevisonNumber(b, 1, 2)
175
181
        self.assertInvalidRevisonNumber(b, 0, 2)
176
 
        self.assertInvalidRevisonNumber(b, 1, 0)
177
182
        self.assertInvalidRevisonNumber(b, -1, 1)
178
183
        self.assertInvalidRevisonNumber(b, 1, -1)
 
184
        self.assertInvalidRevisonNumber(b, 1, 0)
179
185
 
180
186
    def test_empty_branch(self):
181
187
        wt = self.make_branch_and_tree('.')
250
256
        wt.commit(message='add file1 and file2')
251
257
        self.run_bzr('branch parent child')
252
258
        os.unlink('child/file1')
253
 
        file('child/file2', 'wb').write('hello\n')
 
259
        with open('child/file2', 'wb') as f: f.write(b'hello\n')
254
260
        self.run_bzr(['commit', '-m', 'remove file1 and modify file2',
255
261
            'child'])
256
262
        os.chdir('parent')
280
286
        self.assertEqual('add file1 and file2', logentry.rev.message)
281
287
        self.checkDelta(logentry.delta, added=['file1', 'file2'])
282
288
 
 
289
    def test_bug_842695_log_restricted_to_dir(self):
 
290
        # Comments here indicate revision numbers in trunk  # VVVVV
 
291
        trunk = self.make_branch_and_tree('this')
 
292
        trunk.commit('initial trunk')                       # 1
 
293
        adder = trunk.controldir.sprout('adder').open_workingtree()
 
294
        merger = trunk.controldir.sprout('merger').open_workingtree()
 
295
        self.build_tree_contents([
 
296
            ('adder/dir/',),
 
297
            ('adder/dir/file', b'foo'),
 
298
            ])
 
299
        adder.add(['dir', 'dir/file'])
 
300
        adder.commit('added dir')                           # 1.1.1
 
301
        trunk.merge_from_branch(adder.branch)
 
302
        trunk.commit('merged adder into trunk')             # 2
 
303
        merger.merge_from_branch(trunk.branch)
 
304
        merger.commit('merged trunk into merger')           # 1.2.1
 
305
        # Commits are processed in increments of 200 revisions, so
 
306
        # make sure the two merges into trunk are in different chunks.
 
307
        for i in range(200):
 
308
            trunk.commit('intermediate commit %d' % i)      # 3-202
 
309
        trunk.merge_from_branch(merger.branch)
 
310
        trunk.commit('merged merger into trunk')            # 203
 
311
        file_id = trunk.path2id('dir')
 
312
        lf = LogCatcher()
 
313
        lf.supports_merge_revisions = True
 
314
        log.show_log(trunk.branch, lf, file_id)
 
315
        try:
 
316
            self.assertEqual(['2', '1.1.1'], [r.revno for r in lf.revisions])
 
317
        except AssertionError:
 
318
            raise tests.KnownFailure("bug #842695")
 
319
 
 
320
 
 
321
class TestFormatSignatureValidity(tests.TestCaseWithTransport):
 
322
 
 
323
    def verify_revision_signature(self, revid, gpg_strategy):
 
324
        return (gpg.SIGNATURE_VALID,
 
325
            u'UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>')
 
326
 
 
327
    def test_format_signature_validity_utf(self):
 
328
        """Check that GPG signatures containing UTF-8 names are formatted
 
329
        correctly."""
 
330
        wt = self.make_branch_and_tree('.')
 
331
        revid = wt.commit('empty commit')
 
332
        repo = wt.branch.repository
 
333
        # Monkey patch out checking if this rev is actually signed, since we
 
334
        # can't sign it without a heavier TestCase and LoopbackGPGStrategy
 
335
        # doesn't care anyways.
 
336
        self.overrideAttr(repo, 'verify_revision_signature',
 
337
                self.verify_revision_signature)
 
338
        out = log.format_signature_validity(revid, wt.branch)
 
339
        self.assertEqual(
 
340
u'valid signature from UTF8 Test \xa1\xb1\xc1\xd1\xe1\xf1 <jrandom@example.com>',
 
341
                out)
 
342
 
283
343
 
284
344
class TestShortLogFormatter(TestCaseForLogFormatter):
285
345
 
286
346
    def test_trailing_newlines(self):
287
347
        wt = self.make_branch_and_tree('.')
288
348
        b = self.make_commits_with_trailing_newlines(wt)
289
 
        self.assertFormatterResult("""\
 
349
        self.assertFormatterResult(b"""\
290
350
    3 Joe Foo\t2005-11-22
291
351
      single line with trailing newline
292
352
 
303
363
 
304
364
    def test_short_log_with_merges(self):
305
365
        wt = self._prepare_tree_with_merges()
306
 
        self.assertFormatterResult("""\
 
366
        self.assertFormatterResult(b"""\
307
367
    2 Joe Foo\t2005-11-22 [merge]
308
368
      rev-2
309
369
 
315
375
 
316
376
    def test_short_log_with_merges_and_advice(self):
317
377
        wt = self._prepare_tree_with_merges()
318
 
        self.assertFormatterResult("""\
 
378
        self.assertFormatterResult(b"""\
319
379
    2 Joe Foo\t2005-11-22 [merge]
320
380
      rev-2
321
381
 
322
382
    1 Joe Foo\t2005-11-22
323
383
      rev-1
324
384
 
325
 
Use --include-merges or -n0 to see merged revisions.
 
385
Use --include-merged or -n0 to see merged revisions.
326
386
""",
327
387
            wt.branch, log.ShortLogFormatter,
328
388
            formatter_kwargs=dict(show_advice=True))
329
389
 
330
390
    def test_short_log_with_merges_and_range(self):
331
391
        wt = self._prepare_tree_with_merges()
332
 
        self.wt_commit(wt, 'rev-3a', rev_id='rev-3a')
333
 
        wt.branch.set_last_revision_info(2, 'rev-2b')
334
 
        wt.set_parent_ids(['rev-2b', 'rev-3a'])
335
 
        self.wt_commit(wt, 'rev-3b', rev_id='rev-3b')
336
 
        self.assertFormatterResult("""\
 
392
        self.wt_commit(wt, 'rev-3a', rev_id=b'rev-3a')
 
393
        wt.branch.set_last_revision_info(2, b'rev-2b')
 
394
        wt.set_parent_ids([b'rev-2b', b'rev-3a'])
 
395
        self.wt_commit(wt, 'rev-3b', rev_id=b'rev-3b')
 
396
        self.assertFormatterResult(b"""\
337
397
    3 Joe Foo\t2005-11-22 [merge]
338
398
      rev-3b
339
399
 
346
406
 
347
407
    def test_short_log_with_tags(self):
348
408
        wt = self._prepare_tree_with_merges(with_tags=True)
349
 
        self.assertFormatterResult("""\
 
409
        self.assertFormatterResult(b"""\
350
410
    3 Joe Foo\t2005-11-22 {v1.0, v1.0rc1}
351
411
      rev-3
352
412
 
363
423
        wt = self._prepare_tree_with_merges()
364
424
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
365
425
        rev = revspec.in_history(wt.branch)
366
 
        self.assertFormatterResult("""\
 
426
        self.assertFormatterResult(b"""\
367
427
      1.1.1 Joe Foo\t2005-11-22
368
428
            rev-merged
369
429
 
371
431
            wt.branch, log.ShortLogFormatter,
372
432
            show_log_kwargs=dict(start_revision=rev, end_revision=rev))
373
433
 
 
434
    def test_show_ids(self):
 
435
        wt = self.make_branch_and_tree('parent')
 
436
        self.build_tree(['parent/f1', 'parent/f2'])
 
437
        wt.add(['f1', 'f2'])
 
438
        self.wt_commit(wt, 'first post', rev_id=b'a')
 
439
        child_wt = wt.controldir.sprout('child').open_workingtree()
 
440
        self.wt_commit(child_wt, 'branch 1 changes', rev_id=b'b')
 
441
        wt.merge_from_branch(child_wt.branch)
 
442
        self.wt_commit(wt, 'merge branch 1', rev_id=b'c')
 
443
        self.assertFormatterResult(b"""\
 
444
    2 Joe Foo\t2005-11-22 [merge]
 
445
      revision-id:c
 
446
      merge branch 1
 
447
 
 
448
          1.1.1 Joe Foo\t2005-11-22
 
449
                revision-id:b
 
450
                branch 1 changes
 
451
 
 
452
    1 Joe Foo\t2005-11-22
 
453
      revision-id:a
 
454
      first post
 
455
 
 
456
""",
 
457
            wt.branch, log.ShortLogFormatter,
 
458
            formatter_kwargs=dict(levels=0, show_ids=True))
 
459
 
374
460
 
375
461
class TestShortLogFormatterWithMergeRevisions(TestCaseForLogFormatter):
376
462
 
379
465
        # Note that the 1.1.1 indenting is in fact correct given that
380
466
        # the revision numbers are right justified within 5 characters
381
467
        # for mainline revnos and 9 characters for dotted revnos.
382
 
        self.assertFormatterResult("""\
 
468
        self.assertFormatterResult(b"""\
383
469
    2 Joe Foo\t2005-11-22 [merge]
384
470
      rev-2
385
471
 
397
483
        wt = self._prepare_tree_with_merges()
398
484
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
399
485
        rev = revspec.in_history(wt.branch)
400
 
        self.assertFormatterResult("""\
 
486
        self.assertFormatterResult(b"""\
401
487
      1.1.1 Joe Foo\t2005-11-22
402
488
            rev-merged
403
489
 
415
501
        bug #4676
416
502
        """
417
503
        wt = self.make_standard_commit('test_verbose_log', authors=[])
418
 
        self.assertFormatterResult('''\
 
504
        self.assertFormatterResult(b'''\
419
505
------------------------------------------------------------
420
506
revno: 1
421
507
committer: Lorem Ipsum <test@example.com>
432
518
    def test_merges_are_indented_by_level(self):
433
519
        wt = self.make_branch_and_tree('parent')
434
520
        self.wt_commit(wt, 'first post')
435
 
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
 
521
        child_wt = wt.controldir.sprout('child').open_workingtree()
436
522
        self.wt_commit(child_wt, 'branch 1')
437
 
        smallerchild_wt = wt.bzrdir.sprout('smallerchild').open_workingtree()
 
523
        smallerchild_wt = wt.controldir.sprout('smallerchild').open_workingtree()
438
524
        self.wt_commit(smallerchild_wt, 'branch 2')
439
525
        child_wt.merge_from_branch(smallerchild_wt.branch)
440
526
        self.wt_commit(child_wt, 'merge branch 2')
441
527
        wt.merge_from_branch(child_wt.branch)
442
528
        self.wt_commit(wt, 'merge branch 1')
443
 
        self.assertFormatterResult("""\
 
529
        self.assertFormatterResult(b"""\
444
530
------------------------------------------------------------
445
531
revno: 2 [merge]
446
532
committer: Joe Foo <joe@foo.com>
484
570
    def test_verbose_merge_revisions_contain_deltas(self):
485
571
        wt = self.make_branch_and_tree('parent')
486
572
        self.build_tree(['parent/f1', 'parent/f2'])
487
 
        wt.add(['f1','f2'])
 
573
        wt.add(['f1', 'f2'])
488
574
        self.wt_commit(wt, 'first post')
489
 
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
 
575
        child_wt = wt.controldir.sprout('child').open_workingtree()
490
576
        os.unlink('child/f1')
491
 
        self.build_tree_contents([('child/f2', 'hello\n')])
 
577
        self.build_tree_contents([('child/f2', b'hello\n')])
492
578
        self.wt_commit(child_wt, 'removed f1 and modified f2')
493
579
        wt.merge_from_branch(child_wt.branch)
494
580
        self.wt_commit(wt, 'merge branch 1')
495
 
        self.assertFormatterResult("""\
 
581
        self.assertFormatterResult(b"""\
496
582
------------------------------------------------------------
497
583
revno: 2 [merge]
498
584
committer: Joe Foo <joe@foo.com>
533
619
    def test_trailing_newlines(self):
534
620
        wt = self.make_branch_and_tree('.')
535
621
        b = self.make_commits_with_trailing_newlines(wt)
536
 
        self.assertFormatterResult("""\
 
622
        self.assertFormatterResult(b"""\
537
623
------------------------------------------------------------
538
624
revno: 3
539
625
committer: Joe Foo <joe@foo.com>
567
653
        wt = self.make_standard_commit('test_author_log',
568
654
            authors=['John Doe <jdoe@example.com>',
569
655
                     'Jane Rey <jrey@example.com>'])
570
 
        self.assertFormatterResult("""\
 
656
        self.assertFormatterResult(b"""\
571
657
------------------------------------------------------------
572
658
revno: 1
573
659
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
591
677
        log.properties_handler_registry.register(
592
678
            'trivial_custom_prop_handler',
593
679
            trivial_custom_prop_handler)
594
 
        self.assertFormatterResult("""\
 
680
        self.assertFormatterResult(b"""\
595
681
------------------------------------------------------------
596
682
revno: 1
597
683
test_prop: test_value
615
701
        log.properties_handler_registry.register(
616
702
            'trivial_custom_prop_handler',
617
703
            trivial_custom_prop_handler)
618
 
        self.assertFormatterResult("""\
 
704
        self.assertFormatterResult(b"""\
619
705
    1 John Doe\t2005-11-22
620
706
      test_prop: test_value
621
707
      add a
628
714
        handlers.
629
715
        """
630
716
        wt = self.make_standard_commit('error_in_properties_handler',
631
 
            revprops={'first_prop':'first_value'})
 
717
            revprops={u'first_prop':'first_value'})
632
718
        sio = self.make_utf8_encoded_stringio()
633
719
        formatter = log.LongLogFormatter(to_file=sio)
634
720
        def trivial_custom_prop_handler(revision):
635
 
            raise StandardError("a test error")
 
721
            raise Exception("a test error")
636
722
 
637
723
        log.properties_handler_registry.register(
638
724
            'trivial_custom_prop_handler',
639
725
            trivial_custom_prop_handler)
640
 
        self.assertRaises(StandardError, log.show_log, wt.branch, formatter,)
 
726
        self.assertRaises(Exception, log.show_log, wt.branch, formatter,)
641
727
 
642
728
    def test_properties_handler_bad_argument(self):
643
729
        wt = self.make_standard_commit('bad_argument',
644
 
              revprops={'a_prop':'test_value'})
 
730
              revprops={u'a_prop':'test_value'})
645
731
        sio = self.make_utf8_encoded_stringio()
646
732
        formatter = log.LongLogFormatter(to_file=sio)
647
733
        def bad_argument_prop_handler(revision):
656
742
 
657
743
        revision = wt.branch.repository.get_revision(wt.branch.last_revision())
658
744
        formatter.show_properties(revision, '')
659
 
        self.assertEqualDiff('''custom_prop_name: test_value\n''',
 
745
        self.assertEqualDiff(b'''custom_prop_name: test_value\n''',
660
746
                             sio.getvalue())
661
747
 
 
748
    def test_show_ids(self):
 
749
        wt = self.make_branch_and_tree('parent')
 
750
        self.build_tree(['parent/f1', 'parent/f2'])
 
751
        wt.add(['f1', 'f2'])
 
752
        self.wt_commit(wt, 'first post', rev_id=b'a')
 
753
        child_wt = wt.controldir.sprout('child').open_workingtree()
 
754
        self.wt_commit(child_wt, 'branch 1 changes', rev_id=b'b')
 
755
        wt.merge_from_branch(child_wt.branch)
 
756
        self.wt_commit(wt, 'merge branch 1', rev_id=b'c')
 
757
        self.assertFormatterResult(b"""\
 
758
------------------------------------------------------------
 
759
revno: 2 [merge]
 
760
revision-id: c
 
761
parent: a
 
762
parent: b
 
763
committer: Joe Foo <joe@foo.com>
 
764
branch nick: parent
 
765
timestamp: Tue 2005-11-22 00:00:02 +0000
 
766
message:
 
767
  merge branch 1
 
768
    ------------------------------------------------------------
 
769
    revno: 1.1.1
 
770
    revision-id: b
 
771
    parent: a
 
772
    committer: Joe Foo <joe@foo.com>
 
773
    branch nick: child
 
774
    timestamp: Tue 2005-11-22 00:00:01 +0000
 
775
    message:
 
776
      branch 1 changes
 
777
------------------------------------------------------------
 
778
revno: 1
 
779
revision-id: a
 
780
committer: Joe Foo <joe@foo.com>
 
781
branch nick: parent
 
782
timestamp: Tue 2005-11-22 00:00:00 +0000
 
783
message:
 
784
  first post
 
785
""",
 
786
            wt.branch, log.LongLogFormatter,
 
787
            formatter_kwargs=dict(levels=0, show_ids=True))
 
788
 
662
789
 
663
790
class TestLongLogFormatterWithoutMergeRevisions(TestCaseForLogFormatter):
664
791
 
668
795
        bug #4676
669
796
        """
670
797
        wt = self.make_standard_commit('test_long_verbose_log', authors=[])
671
 
        self.assertFormatterResult("""\
 
798
        self.assertFormatterResult(b"""\
672
799
------------------------------------------------------------
673
800
revno: 1
674
801
committer: Lorem Ipsum <test@example.com>
686
813
    def test_long_verbose_contain_deltas(self):
687
814
        wt = self.make_branch_and_tree('parent')
688
815
        self.build_tree(['parent/f1', 'parent/f2'])
689
 
        wt.add(['f1','f2'])
 
816
        wt.add(['f1', 'f2'])
690
817
        self.wt_commit(wt, 'first post')
691
 
        child_wt = wt.bzrdir.sprout('child').open_workingtree()
 
818
        child_wt = wt.controldir.sprout('child').open_workingtree()
692
819
        os.unlink('child/f1')
693
 
        self.build_tree_contents([('child/f2', 'hello\n')])
 
820
        self.build_tree_contents([('child/f2', b'hello\n')])
694
821
        self.wt_commit(child_wt, 'removed f1 and modified f2')
695
822
        wt.merge_from_branch(child_wt.branch)
696
823
        self.wt_commit(wt, 'merge branch 1')
697
 
        self.assertFormatterResult("""\
 
824
        self.assertFormatterResult(b"""\
698
825
------------------------------------------------------------
699
826
revno: 2 [merge]
700
827
committer: Joe Foo <joe@foo.com>
724
851
    def test_long_trailing_newlines(self):
725
852
        wt = self.make_branch_and_tree('.')
726
853
        b = self.make_commits_with_trailing_newlines(wt)
727
 
        self.assertFormatterResult("""\
 
854
        self.assertFormatterResult(b"""\
728
855
------------------------------------------------------------
729
856
revno: 3
730
857
committer: Joe Foo <joe@foo.com>
757
884
        the revision properties
758
885
        """
759
886
        wt = self.make_standard_commit('test_author_log')
760
 
        self.assertFormatterResult("""\
 
887
        self.assertFormatterResult(b"""\
761
888
------------------------------------------------------------
762
889
revno: 1
763
890
author: John Doe <jdoe@example.com>
781
908
        log.properties_handler_registry.register(
782
909
            'trivial_custom_prop_handler',
783
910
            trivial_custom_prop_handler)
784
 
        self.assertFormatterResult("""\
 
911
        self.assertFormatterResult(b"""\
785
912
------------------------------------------------------------
786
913
revno: 1
787
914
test_prop: test_value
806
933
        wt = self.make_standard_commit('test-line-log',
807
934
                committer='Line-Log-Formatter Tester <test@line.log>',
808
935
                authors=[])
809
 
        self.assertFormatterResult("""\
 
936
        self.assertFormatterResult(b"""\
810
937
1: Line-Log-Formatte... 2005-11-22 add a
811
938
""",
812
939
            wt.branch, log.LineLogFormatter)
814
941
    def test_trailing_newlines(self):
815
942
        wt = self.make_branch_and_tree('.')
816
943
        b = self.make_commits_with_trailing_newlines(wt)
817
 
        self.assertFormatterResult("""\
 
944
        self.assertFormatterResult(b"""\
818
945
3: Joe Foo 2005-11-22 single line with trailing newline
819
946
2: Joe Foo 2005-11-22 multiline
820
947
1: Joe Foo 2005-11-22 simple log message
825
952
        wt = self._prepare_tree_with_merges()
826
953
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
827
954
        rev = revspec.in_history(wt.branch)
828
 
        self.assertFormatterResult("""\
 
955
        self.assertFormatterResult(b"""\
829
956
1.1.1: Joe Foo 2005-11-22 rev-merged
830
957
""",
831
958
            wt.branch, log.LineLogFormatter,
833
960
 
834
961
    def test_line_log_with_tags(self):
835
962
        wt = self._prepare_tree_with_merges(with_tags=True)
836
 
        self.assertFormatterResult("""\
 
963
        self.assertFormatterResult(b"""\
837
964
3: Joe Foo 2005-11-22 {v1.0, v1.0rc1} rev-3
838
965
2: Joe Foo 2005-11-22 [merge] {v0.2} rev-2
839
966
1: Joe Foo 2005-11-22 rev-1
851
978
        wt = self.make_standard_commit('test-line-log',
852
979
                committer='Line-Log-Formatter Tester <test@line.log>',
853
980
                authors=[])
854
 
        self.assertFormatterResult("""\
 
981
        self.assertFormatterResult(b"""\
855
982
1: Line-Log-Formatte... 2005-11-22 add a
856
983
""",
857
984
            wt.branch, log.LineLogFormatter)
860
987
        wt = self._prepare_tree_with_merges()
861
988
        revspec = revisionspec.RevisionSpec.from_string('1.1.1')
862
989
        rev = revspec.in_history(wt.branch)
863
 
        self.assertFormatterResult("""\
 
990
        self.assertFormatterResult(b"""\
864
991
1.1.1: Joe Foo 2005-11-22 rev-merged
865
992
""",
866
993
            wt.branch, log.LineLogFormatter,
869
996
 
870
997
    def test_line_merge_revs_log_with_merges(self):
871
998
        wt = self._prepare_tree_with_merges()
872
 
        self.assertFormatterResult("""\
 
999
        self.assertFormatterResult(b"""\
873
1000
2: Joe Foo 2005-11-22 [merge] rev-2
874
1001
  1.1.1: Joe Foo 2005-11-22 rev-merged
875
1002
1: Joe Foo 2005-11-22 rev-1
882
1009
 
883
1010
    def test_gnu_changelog(self):
884
1011
        wt = self.make_standard_commit('nicky', authors=[])
885
 
        self.assertFormatterResult('''\
 
1012
        self.assertFormatterResult(b'''\
886
1013
2005-11-22  Lorem Ipsum  <test@example.com>
887
1014
 
888
1015
\tadd a
894
1021
        wt = self.make_standard_commit('nicky',
895
1022
            authors=['Fooa Fooz <foo@example.com>',
896
1023
                     'Bari Baro <bar@example.com>'])
897
 
        self.assertFormatterResult('''\
 
1024
        self.assertFormatterResult(b'''\
898
1025
2005-11-22  Fooa Fooz  <foo@example.com>
899
1026
 
900
1027
\tadd a
904
1031
 
905
1032
    def test_verbose(self):
906
1033
        wt = self.make_standard_commit('nicky')
907
 
        self.assertFormatterResult('''\
 
1034
        self.assertFormatterResult(b'''\
908
1035
2005-11-22  John Doe  <jdoe@example.com>
909
1036
 
910
1037
\t* a:
915
1042
            wt.branch, log.GnuChangelogLogFormatter,
916
1043
            show_log_kwargs=dict(verbose=True))
917
1044
 
918
 
class TestGetViewRevisions(tests.TestCaseWithTransport, TestLogMixin):
919
 
 
920
 
    def _get_view_revisions(self, *args, **kwargs):
921
 
        return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
922
 
                                    log.get_view_revisions, *args, **kwargs)
923
 
 
924
 
    def make_tree_with_commits(self):
925
 
        """Create a tree with well-known revision ids"""
926
 
        wt = self.make_branch_and_tree('tree1')
927
 
        self.wt_commit(wt, 'commit one', rev_id='1')
928
 
        self.wt_commit(wt, 'commit two', rev_id='2')
929
 
        self.wt_commit(wt, 'commit three', rev_id='3')
930
 
        mainline_revs = [None, '1', '2', '3']
931
 
        rev_nos = {'1': 1, '2': 2, '3': 3}
932
 
        return mainline_revs, rev_nos, wt
933
 
 
934
 
    def make_tree_with_merges(self):
935
 
        """Create a tree with well-known revision ids and a merge"""
936
 
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
937
 
        tree2 = wt.bzrdir.sprout('tree2').open_workingtree()
938
 
        self.wt_commit(tree2, 'four-a', rev_id='4a')
939
 
        wt.merge_from_branch(tree2.branch)
940
 
        self.wt_commit(wt, 'four-b', rev_id='4b')
941
 
        mainline_revs.append('4b')
942
 
        rev_nos['4b'] = 4
943
 
        # 4a: 3.1.1
944
 
        return mainline_revs, rev_nos, wt
945
 
 
946
 
    def make_branch_with_many_merges(self):
947
 
        """Create a tree with well-known revision ids"""
948
 
        builder = self.make_branch_builder('tree1')
949
 
        builder.start_series()
950
 
        builder.build_snapshot('1', None, [
951
 
            ('add', ('', 'TREE_ROOT', 'directory', '')),
952
 
            ('add', ('f', 'f-id', 'file', '1\n'))])
953
 
        builder.build_snapshot('2', ['1'], [])
954
 
        builder.build_snapshot('3a', ['2'], [
955
 
            ('modify', ('f-id', '1\n2\n3a\n'))])
956
 
        builder.build_snapshot('3b', ['2', '3a'], [
957
 
            ('modify', ('f-id', '1\n2\n3a\n'))])
958
 
        builder.build_snapshot('3c', ['2', '3b'], [
959
 
            ('modify', ('f-id', '1\n2\n3a\n'))])
960
 
        builder.build_snapshot('4a', ['3b'], [])
961
 
        builder.build_snapshot('4b', ['3c', '4a'], [])
962
 
        builder.finish_series()
963
 
 
964
 
        # 1
965
 
        # |
966
 
        # 2-.
967
 
        # |\ \
968
 
        # | | 3a
969
 
        # | |/
970
 
        # | 3b
971
 
        # |/|
972
 
        # 3c4a
973
 
        # |/
974
 
        # 4b
975
 
 
976
 
        mainline_revs = [None, '1', '2', '3c', '4b']
977
 
        rev_nos = {'1':1, '2':2, '3c': 3, '4b':4}
978
 
        full_rev_nos_for_reference = {
979
 
            '1': '1',
980
 
            '2': '2',
981
 
            '3a': '2.1.1', #first commit tree 3
982
 
            '3b': '2.2.1', # first commit tree 2
983
 
            '3c': '3', #merges 3b to main
984
 
            '4a': '2.2.2', # second commit tree 2
985
 
            '4b': '4', # merges 4a to main
986
 
            }
987
 
        return mainline_revs, rev_nos, builder.get_branch()
988
 
 
989
 
    def test_get_view_revisions_forward(self):
990
 
        """Test the get_view_revisions method"""
991
 
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
992
 
        wt.lock_read()
993
 
        self.addCleanup(wt.unlock)
994
 
        revisions = list(self._get_view_revisions(
995
 
                mainline_revs, rev_nos, wt.branch, 'forward'))
996
 
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0)],
997
 
                         revisions)
998
 
        revisions2 = list(self._get_view_revisions(
999
 
                mainline_revs, rev_nos, wt.branch, 'forward',
1000
 
                include_merges=False))
1001
 
        self.assertEqual(revisions, revisions2)
1002
 
 
1003
 
    def test_get_view_revisions_reverse(self):
1004
 
        """Test the get_view_revisions with reverse"""
1005
 
        mainline_revs, rev_nos, wt = self.make_tree_with_commits()
1006
 
        wt.lock_read()
1007
 
        self.addCleanup(wt.unlock)
1008
 
        revisions = list(self._get_view_revisions(
1009
 
                mainline_revs, rev_nos, wt.branch, 'reverse'))
1010
 
        self.assertEqual([('3', '3', 0), ('2', '2', 0), ('1', '1', 0), ],
1011
 
                         revisions)
1012
 
        revisions2 = list(self._get_view_revisions(
1013
 
                mainline_revs, rev_nos, wt.branch, 'reverse',
1014
 
                include_merges=False))
1015
 
        self.assertEqual(revisions, revisions2)
1016
 
 
1017
 
    def test_get_view_revisions_merge(self):
1018
 
        """Test get_view_revisions when there are merges"""
1019
 
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1020
 
        wt.lock_read()
1021
 
        self.addCleanup(wt.unlock)
1022
 
        revisions = list(self._get_view_revisions(
1023
 
                mainline_revs, rev_nos, wt.branch, 'forward'))
1024
 
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1025
 
                          ('4b', '4', 0), ('4a', '3.1.1', 1)],
1026
 
                         revisions)
1027
 
        revisions = list(self._get_view_revisions(
1028
 
                mainline_revs, rev_nos, wt.branch, 'forward',
1029
 
                include_merges=False))
1030
 
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3', '3', 0),
1031
 
                          ('4b', '4', 0)],
1032
 
                         revisions)
1033
 
 
1034
 
    def test_get_view_revisions_merge_reverse(self):
1035
 
        """Test get_view_revisions in reverse when there are merges"""
1036
 
        mainline_revs, rev_nos, wt = self.make_tree_with_merges()
1037
 
        wt.lock_read()
1038
 
        self.addCleanup(wt.unlock)
1039
 
        revisions = list(self._get_view_revisions(
1040
 
                mainline_revs, rev_nos, wt.branch, 'reverse'))
1041
 
        self.assertEqual([('4b', '4', 0), ('4a', '3.1.1', 1),
1042
 
                          ('3', '3', 0), ('2', '2', 0), ('1', '1', 0)],
1043
 
                         revisions)
1044
 
        revisions = list(self._get_view_revisions(
1045
 
                mainline_revs, rev_nos, wt.branch, 'reverse',
1046
 
                include_merges=False))
1047
 
        self.assertEqual([('4b', '4', 0), ('3', '3', 0), ('2', '2', 0),
1048
 
                          ('1', '1', 0)],
1049
 
                         revisions)
1050
 
 
1051
 
    def test_get_view_revisions_merge2(self):
1052
 
        """Test get_view_revisions when there are merges"""
1053
 
        mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1054
 
        b.lock_read()
1055
 
        self.addCleanup(b.unlock)
1056
 
        revisions = list(self._get_view_revisions(
1057
 
                mainline_revs, rev_nos, b, 'forward'))
1058
 
        expected = [('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1059
 
                    ('3b', '2.2.1', 1), ('3a', '2.1.1', 2), ('4b', '4', 0),
1060
 
                    ('4a', '2.2.2', 1)]
1061
 
        self.assertEqual(expected, revisions)
1062
 
        revisions = list(self._get_view_revisions(
1063
 
                mainline_revs, rev_nos, b, 'forward',
1064
 
                include_merges=False))
1065
 
        self.assertEqual([('1', '1', 0), ('2', '2', 0), ('3c', '3', 0),
1066
 
                          ('4b', '4', 0)],
1067
 
                         revisions)
1068
 
 
1069
 
    def test_file_id_for_range(self):
1070
 
        mainline_revs, rev_nos, b = self.make_branch_with_many_merges()
1071
 
        b.lock_read()
1072
 
        self.addCleanup(b.unlock)
1073
 
 
1074
 
        def rev_from_rev_id(revid, branch):
1075
 
            revspec = revisionspec.RevisionSpec.from_string('revid:%s' % revid)
1076
 
            return revspec.in_history(branch)
1077
 
 
1078
 
        def view_revs(start_rev, end_rev, file_id, direction):
1079
 
            revs = self.applyDeprecated(
1080
 
                symbol_versioning.deprecated_in((2, 2, 0)),
1081
 
                log.calculate_view_revisions,
1082
 
                b,
1083
 
                start_rev, # start_revision
1084
 
                end_rev, # end_revision
1085
 
                direction, # direction
1086
 
                file_id, # specific_fileid
1087
 
                True, # generate_merge_revisions
1088
 
                )
1089
 
            return revs
1090
 
 
1091
 
        rev_3a = rev_from_rev_id('3a', b)
1092
 
        rev_4b = rev_from_rev_id('4b', b)
1093
 
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
1094
 
                          ('3a', '2.1.1', 2)],
1095
 
                          view_revs(rev_3a, rev_4b, 'f-id', 'reverse'))
1096
 
        # Note: 3c still appears before 3a here because of depth-based sorting
1097
 
        self.assertEqual([('3c', '3', 0), ('3b', '2.2.1', 1),
1098
 
                          ('3a', '2.1.1', 2)],
1099
 
                          view_revs(rev_3a, rev_4b, 'f-id', 'forward'))
1100
 
 
1101
 
 
1102
 
class TestGetRevisionsTouchingFileID(tests.TestCaseWithTransport):
1103
 
 
1104
 
    def get_view_revisions(self, *args):
1105
 
        return self.applyDeprecated(symbol_versioning.deprecated_in((2, 2, 0)),
1106
 
                                    log.get_view_revisions, *args)
1107
 
 
1108
 
    def create_tree_with_single_merge(self):
1109
 
        """Create a branch with a moderate layout.
1110
 
 
1111
 
        The revision graph looks like:
1112
 
 
1113
 
           A
1114
 
           |\
1115
 
           B C
1116
 
           |/
1117
 
           D
1118
 
 
1119
 
        In this graph, A introduced files f1 and f2 and f3.
1120
 
        B modifies f1 and f3, and C modifies f2 and f3.
1121
 
        D merges the changes from B and C and resolves the conflict for f3.
1122
 
        """
1123
 
        # TODO: jam 20070218 This seems like it could really be done
1124
 
        #       with make_branch_and_memory_tree() if we could just
1125
 
        #       create the content of those files.
1126
 
        # TODO: jam 20070218 Another alternative is that we would really
1127
 
        #       like to only create this tree 1 time for all tests that
1128
 
        #       use it. Since 'log' only uses the tree in a readonly
1129
 
        #       fashion, it seems a shame to regenerate an identical
1130
 
        #       tree for each test.
1131
 
        # TODO: vila 20100122 One way to address the shame above will be to
1132
 
        #       create a memory tree during test parametrization and give a
1133
 
        #       *copy* of this tree to each test. Copying a memory tree ought
1134
 
        #       to be cheap, at least cheaper than creating them with such
1135
 
        #       complex setups.
1136
 
        tree = self.make_branch_and_tree('tree')
1137
 
        tree.lock_write()
1138
 
        self.addCleanup(tree.unlock)
1139
 
 
1140
 
        self.build_tree_contents([('tree/f1', 'A\n'),
1141
 
                                  ('tree/f2', 'A\n'),
1142
 
                                  ('tree/f3', 'A\n'),
1143
 
                                 ])
1144
 
        tree.add(['f1', 'f2', 'f3'], ['f1-id', 'f2-id', 'f3-id'])
1145
 
        tree.commit('A', rev_id='A')
1146
 
 
1147
 
        self.build_tree_contents([('tree/f2', 'A\nC\n'),
1148
 
                                  ('tree/f3', 'A\nC\n'),
1149
 
                                 ])
1150
 
        tree.commit('C', rev_id='C')
1151
 
        # Revert back to A to build the other history.
1152
 
        tree.set_last_revision('A')
1153
 
        tree.branch.set_last_revision_info(1, 'A')
1154
 
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
1155
 
                                  ('tree/f2', 'A\n'),
1156
 
                                  ('tree/f3', 'A\nB\n'),
1157
 
                                 ])
1158
 
        tree.commit('B', rev_id='B')
1159
 
        tree.set_parent_ids(['B', 'C'])
1160
 
        self.build_tree_contents([('tree/f1', 'A\nB\n'),
1161
 
                                  ('tree/f2', 'A\nC\n'),
1162
 
                                  ('tree/f3', 'A\nB\nC\n'),
1163
 
                                 ])
1164
 
        tree.commit('D', rev_id='D')
1165
 
 
1166
 
        # Switch to a read lock for this tree.
1167
 
        # We still have an addCleanup(tree.unlock) pending
1168
 
        tree.unlock()
1169
 
        tree.lock_read()
1170
 
        return tree
1171
 
 
1172
 
    def check_delta(self, delta, **kw):
1173
 
        """Check the filenames touched by a delta are as expected.
1174
 
 
1175
 
        Caller only have to pass in the list of files for each part, all
1176
 
        unspecified parts are considered empty (and checked as such).
1177
 
        """
1178
 
        for n in 'added', 'removed', 'renamed', 'modified', 'unchanged':
1179
 
            # By default we expect an empty list
1180
 
            expected = kw.get(n, [])
1181
 
            # strip out only the path components
1182
 
            got = [x[0] for x in getattr(delta, n)]
1183
 
            self.assertEqual(expected, got)
1184
 
 
1185
 
    def test_tree_with_single_merge(self):
1186
 
        """Make sure the tree layout is correct."""
1187
 
        tree = self.create_tree_with_single_merge()
1188
 
        rev_A_tree = tree.branch.repository.revision_tree('A')
1189
 
        rev_B_tree = tree.branch.repository.revision_tree('B')
1190
 
        rev_C_tree = tree.branch.repository.revision_tree('C')
1191
 
        rev_D_tree = tree.branch.repository.revision_tree('D')
1192
 
 
1193
 
        self.check_delta(rev_B_tree.changes_from(rev_A_tree),
1194
 
                         modified=['f1', 'f3'])
1195
 
 
1196
 
        self.check_delta(rev_C_tree.changes_from(rev_A_tree),
1197
 
                         modified=['f2', 'f3'])
1198
 
 
1199
 
        self.check_delta(rev_D_tree.changes_from(rev_B_tree),
1200
 
                         modified=['f2', 'f3'])
1201
 
 
1202
 
        self.check_delta(rev_D_tree.changes_from(rev_C_tree),
1203
 
                         modified=['f1', 'f3'])
1204
 
 
1205
 
    def assertAllRevisionsForFileID(self, tree, file_id, revisions):
1206
 
        """Ensure _filter_revisions_touching_file_id returns the right values.
1207
 
 
1208
 
        Get the return value from _filter_revisions_touching_file_id and make
1209
 
        sure they are correct.
1210
 
        """
1211
 
        # The api for _filter_revisions_touching_file_id is a little crazy.
1212
 
        # So we do the setup here.
1213
 
        mainline = tree.branch.revision_history()
1214
 
        mainline.insert(0, None)
1215
 
        revnos = dict((rev, idx+1) for idx, rev in enumerate(mainline))
1216
 
        view_revs_iter = self.get_view_revisions(
1217
 
            mainline, revnos, tree.branch, 'reverse', True)
1218
 
        actual_revs = log._filter_revisions_touching_file_id(
1219
 
            tree.branch, file_id, list(view_revs_iter))
1220
 
        self.assertEqual(revisions, [r for r, revno, depth in actual_revs])
1221
 
 
1222
 
    def test_file_id_f1(self):
1223
 
        tree = self.create_tree_with_single_merge()
1224
 
        # f1 should be marked as modified by revisions A and B
1225
 
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['B', 'A'])
1226
 
 
1227
 
    def test_file_id_f2(self):
1228
 
        tree = self.create_tree_with_single_merge()
1229
 
        # f2 should be marked as modified by revisions A, C, and D
1230
 
        # because D merged the changes from C.
1231
 
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1232
 
 
1233
 
    def test_file_id_f3(self):
1234
 
        tree = self.create_tree_with_single_merge()
1235
 
        # f3 should be marked as modified by revisions A, B, C, and D
1236
 
        self.assertAllRevisionsForFileID(tree, 'f3-id', ['D', 'C', 'B', 'A'])
1237
 
 
1238
 
    def test_file_id_with_ghosts(self):
1239
 
        # This is testing bug #209948, where having a ghost would cause
1240
 
        # _filter_revisions_touching_file_id() to fail.
1241
 
        tree = self.create_tree_with_single_merge()
1242
 
        # We need to add a revision, so switch back to a write-locked tree
1243
 
        # (still a single addCleanup(tree.unlock) pending).
1244
 
        tree.unlock()
1245
 
        tree.lock_write()
1246
 
        first_parent = tree.last_revision()
1247
 
        tree.set_parent_ids([first_parent, 'ghost-revision-id'])
1248
 
        self.build_tree_contents([('tree/f1', 'A\nB\nXX\n')])
1249
 
        tree.commit('commit with a ghost', rev_id='XX')
1250
 
        self.assertAllRevisionsForFileID(tree, 'f1-id', ['XX', 'B', 'A'])
1251
 
        self.assertAllRevisionsForFileID(tree, 'f2-id', ['D', 'C', 'A'])
1252
 
 
1253
 
    def test_unknown_file_id(self):
1254
 
        tree = self.create_tree_with_single_merge()
1255
 
        self.assertAllRevisionsForFileID(tree, 'unknown', [])
1256
 
 
1257
 
    def test_empty_branch_unknown_file_id(self):
1258
 
        tree = self.make_branch_and_tree('tree')
1259
 
        self.assertAllRevisionsForFileID(tree, 'unknown', [])
1260
 
 
1261
1045
 
1262
1046
class TestShowChangedRevisions(tests.TestCaseWithTransport):
1263
1047
 
1265
1049
        tree = self.make_branch_and_tree('tree_a')
1266
1050
        self.build_tree(['tree_a/foo'])
1267
1051
        tree.add('foo')
1268
 
        tree.commit('bar', rev_id='bar-id')
 
1052
        tree.commit('bar', rev_id=b'bar-id')
1269
1053
        s = self.make_utf8_encoded_stringio()
1270
 
        log.show_changed_revisions(tree.branch, [], ['bar-id'], s)
1271
 
        self.assertContainsRe(s.getvalue(), 'bar')
1272
 
        self.assertNotContainsRe(s.getvalue(), 'foo')
 
1054
        log.show_changed_revisions(tree.branch, [], [b'bar-id'], s)
 
1055
        self.assertContainsRe(s.getvalue(), b'bar')
 
1056
        self.assertNotContainsRe(s.getvalue(), b'foo')
1273
1057
 
1274
1058
 
1275
1059
class TestLogFormatter(tests.TestCase):
1276
1060
 
1277
1061
    def setUp(self):
1278
1062
        super(TestLogFormatter, self).setUp()
1279
 
        self.rev = revision.Revision('a-id')
 
1063
        self.rev = revision.Revision(b'a-id')
1280
1064
        self.lf = log.LogFormatter(None)
1281
1065
 
1282
1066
    def test_short_committer(self):
1372
1156
        tree = self.make_branch_and_tree('tree')
1373
1157
        tree.lock_write()
1374
1158
        self.addCleanup(tree.unlock)
1375
 
        tree.commit('1a', rev_id='1a')
1376
 
        tree.commit('2a', rev_id='2a')
1377
 
        tree.commit('3a', rev_id='3a')
 
1159
        tree.commit('1a', rev_id=b'1a')
 
1160
        tree.commit('2a', rev_id=b'2a')
 
1161
        tree.commit('3a', rev_id=b'3a')
1378
1162
        return tree
1379
1163
 
1380
1164
    def setup_ab_tree(self):
1381
1165
        tree = self.setup_a_tree()
1382
 
        tree.set_last_revision('1a')
1383
 
        tree.branch.set_last_revision_info(1, '1a')
1384
 
        tree.commit('2b', rev_id='2b')
1385
 
        tree.commit('3b', rev_id='3b')
 
1166
        tree.set_last_revision(b'1a')
 
1167
        tree.branch.set_last_revision_info(1, b'1a')
 
1168
        tree.commit('2b', rev_id=b'2b')
 
1169
        tree.commit('3b', rev_id=b'3b')
1386
1170
        return tree
1387
1171
 
1388
1172
    def setup_ac_tree(self):
1389
1173
        tree = self.setup_a_tree()
1390
1174
        tree.set_last_revision(revision.NULL_REVISION)
1391
1175
        tree.branch.set_last_revision_info(0, revision.NULL_REVISION)
1392
 
        tree.commit('1c', rev_id='1c')
1393
 
        tree.commit('2c', rev_id='2c')
1394
 
        tree.commit('3c', rev_id='3c')
 
1176
        tree.commit('1c', rev_id=b'1c')
 
1177
        tree.commit('2c', rev_id=b'2c')
 
1178
        tree.commit('3c', rev_id=b'3c')
1395
1179
        return tree
1396
1180
 
1397
1181
    def test_all_new(self):
1398
1182
        tree = self.setup_ab_tree()
1399
 
        old, new = log.get_history_change('1a', '3a', tree.branch.repository)
 
1183
        old, new = log.get_history_change(b'1a', b'3a', tree.branch.repository)
1400
1184
        self.assertEqual([], old)
1401
 
        self.assertEqual(['2a', '3a'], new)
 
1185
        self.assertEqual([b'2a', b'3a'], new)
1402
1186
 
1403
1187
    def test_all_old(self):
1404
1188
        tree = self.setup_ab_tree()
1405
 
        old, new = log.get_history_change('3a', '1a', tree.branch.repository)
 
1189
        old, new = log.get_history_change(b'3a', b'1a', tree.branch.repository)
1406
1190
        self.assertEqual([], new)
1407
 
        self.assertEqual(['2a', '3a'], old)
 
1191
        self.assertEqual([b'2a', b'3a'], old)
1408
1192
 
1409
1193
    def test_null_old(self):
1410
1194
        tree = self.setup_ab_tree()
1411
1195
        old, new = log.get_history_change(revision.NULL_REVISION,
1412
 
                                          '3a', tree.branch.repository)
 
1196
                                          b'3a', tree.branch.repository)
1413
1197
        self.assertEqual([], old)
1414
 
        self.assertEqual(['1a', '2a', '3a'], new)
 
1198
        self.assertEqual([b'1a', b'2a', b'3a'], new)
1415
1199
 
1416
1200
    def test_null_new(self):
1417
1201
        tree = self.setup_ab_tree()
1418
 
        old, new = log.get_history_change('3a', revision.NULL_REVISION,
 
1202
        old, new = log.get_history_change(b'3a', revision.NULL_REVISION,
1419
1203
                                          tree.branch.repository)
1420
1204
        self.assertEqual([], new)
1421
 
        self.assertEqual(['1a', '2a', '3a'], old)
 
1205
        self.assertEqual([b'1a', b'2a', b'3a'], old)
1422
1206
 
1423
1207
    def test_diverged(self):
1424
1208
        tree = self.setup_ab_tree()
1425
 
        old, new = log.get_history_change('3a', '3b', tree.branch.repository)
1426
 
        self.assertEqual(old, ['2a', '3a'])
1427
 
        self.assertEqual(new, ['2b', '3b'])
 
1209
        old, new = log.get_history_change(b'3a', b'3b', tree.branch.repository)
 
1210
        self.assertEqual(old, [b'2a', b'3a'])
 
1211
        self.assertEqual(new, [b'2b', b'3b'])
1428
1212
 
1429
1213
    def test_unrelated(self):
1430
1214
        tree = self.setup_ac_tree()
1431
 
        old, new = log.get_history_change('3a', '3c', tree.branch.repository)
1432
 
        self.assertEqual(old, ['1a', '2a', '3a'])
1433
 
        self.assertEqual(new, ['1c', '2c', '3c'])
 
1215
        old, new = log.get_history_change(b'3a', b'3c', tree.branch.repository)
 
1216
        self.assertEqual(old, [b'1a', b'2a', b'3a'])
 
1217
        self.assertEqual(new, [b'1c', b'2c', b'3c'])
1434
1218
 
1435
1219
    def test_show_branch_change(self):
1436
1220
        tree = self.setup_ab_tree()
1437
1221
        s = StringIO()
1438
 
        log.show_branch_change(tree.branch, s, 3, '3a')
 
1222
        log.show_branch_change(tree.branch, s, 3, b'3a')
1439
1223
        self.assertContainsRe(s.getvalue(),
1440
1224
            '[*]{60}\nRemoved Revisions:\n(.|\n)*2a(.|\n)*3a(.|\n)*'
1441
1225
            '[*]{60}\n\nAdded Revisions:\n(.|\n)*2b(.|\n)*3b')
1443
1227
    def test_show_branch_change_no_change(self):
1444
1228
        tree = self.setup_ab_tree()
1445
1229
        s = StringIO()
1446
 
        log.show_branch_change(tree.branch, s, 3, '3b')
 
1230
        log.show_branch_change(tree.branch, s, 3, b'3b')
1447
1231
        self.assertEqual(s.getvalue(),
1448
1232
            'Nothing seems to have changed\n')
1449
1233
 
1450
1234
    def test_show_branch_change_no_old(self):
1451
1235
        tree = self.setup_ab_tree()
1452
1236
        s = StringIO()
1453
 
        log.show_branch_change(tree.branch, s, 2, '2b')
 
1237
        log.show_branch_change(tree.branch, s, 2, b'2b')
1454
1238
        self.assertContainsRe(s.getvalue(), 'Added Revisions:')
1455
1239
        self.assertNotContainsRe(s.getvalue(), 'Removed Revisions:')
1456
1240
 
1457
1241
    def test_show_branch_change_no_new(self):
1458
1242
        tree = self.setup_ab_tree()
1459
 
        tree.branch.set_last_revision_info(2, '2b')
 
1243
        tree.branch.set_last_revision_info(2, b'2b')
1460
1244
        s = StringIO()
1461
 
        log.show_branch_change(tree.branch, s, 3, '3b')
 
1245
        log.show_branch_change(tree.branch, s, 3, b'3b')
1462
1246
        self.assertContainsRe(s.getvalue(), 'Removed Revisions:')
1463
1247
        self.assertNotContainsRe(s.getvalue(), 'Added Revisions:')
1464
1248
 
1465
1249
 
 
1250
class TestRevisionNotInBranch(TestCaseForLogFormatter):
 
1251
 
 
1252
    def setup_a_tree(self):
 
1253
        tree = self.make_branch_and_tree('tree')
 
1254
        tree.lock_write()
 
1255
        self.addCleanup(tree.unlock)
 
1256
        kwargs = {
 
1257
            'committer': 'Joe Foo <joe@foo.com>',
 
1258
            'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
 
1259
            'timezone': 0, # UTC
 
1260
        }
 
1261
        tree.commit('commit 1a', rev_id=b'1a', **kwargs)
 
1262
        tree.commit('commit 2a', rev_id=b'2a', **kwargs)
 
1263
        tree.commit('commit 3a', rev_id=b'3a', **kwargs)
 
1264
        return tree
 
1265
 
 
1266
    def setup_ab_tree(self):
 
1267
        tree = self.setup_a_tree()
 
1268
        tree.set_last_revision(b'1a')
 
1269
        tree.branch.set_last_revision_info(1, b'1a')
 
1270
        kwargs = {
 
1271
            'committer': 'Joe Foo <joe@foo.com>',
 
1272
            'timestamp': 1132617600, # Mon 2005-11-22 00:00:00 +0000
 
1273
            'timezone': 0, # UTC
 
1274
        }
 
1275
        tree.commit('commit 2b', rev_id=b'2b', **kwargs)
 
1276
        tree.commit('commit 3b', rev_id=b'3b', **kwargs)
 
1277
        return tree
 
1278
 
 
1279
    def test_one_revision(self):
 
1280
        tree = self.setup_ab_tree()
 
1281
        lf = LogCatcher()
 
1282
        rev = revisionspec.RevisionInfo(tree.branch, None, b'3a')
 
1283
        log.show_log(tree.branch, lf, verbose=True, start_revision=rev,
 
1284
                     end_revision=rev)
 
1285
        self.assertEqual(1, len(lf.revisions))
 
1286
        self.assertEqual(None, lf.revisions[0].revno)   # Out-of-branch
 
1287
        self.assertEqual(b'3a', lf.revisions[0].rev.revision_id)
 
1288
 
 
1289
    def test_many_revisions(self):
 
1290
        tree = self.setup_ab_tree()
 
1291
        lf = LogCatcher()
 
1292
        start_rev = revisionspec.RevisionInfo(tree.branch, None, b'1a')
 
1293
        end_rev = revisionspec.RevisionInfo(tree.branch, None, b'3a')
 
1294
        log.show_log(tree.branch, lf, verbose=True, start_revision=start_rev,
 
1295
                     end_revision=end_rev)
 
1296
        self.assertEqual(3, len(lf.revisions))
 
1297
        self.assertEqual(None, lf.revisions[0].revno)   # Out-of-branch
 
1298
        self.assertEqual(b'3a', lf.revisions[0].rev.revision_id)
 
1299
        self.assertEqual(None, lf.revisions[1].revno)   # Out-of-branch
 
1300
        self.assertEqual(b'2a', lf.revisions[1].rev.revision_id)
 
1301
        self.assertEqual('1', lf.revisions[2].revno)    # In-branch
 
1302
 
 
1303
    def test_long_format(self):
 
1304
        tree = self.setup_ab_tree()
 
1305
        start_rev = revisionspec.RevisionInfo(tree.branch, None, b'1a')
 
1306
        end_rev = revisionspec.RevisionInfo(tree.branch, None, b'3a')
 
1307
        self.assertFormatterResult(b"""\
 
1308
------------------------------------------------------------
 
1309
revision-id: 3a
 
1310
committer: Joe Foo <joe@foo.com>
 
1311
branch nick: tree
 
1312
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1313
message:
 
1314
  commit 3a
 
1315
------------------------------------------------------------
 
1316
revision-id: 2a
 
1317
committer: Joe Foo <joe@foo.com>
 
1318
branch nick: tree
 
1319
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1320
message:
 
1321
  commit 2a
 
1322
------------------------------------------------------------
 
1323
revno: 1
 
1324
committer: Joe Foo <joe@foo.com>
 
1325
branch nick: tree
 
1326
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1327
message:
 
1328
  commit 1a
 
1329
""",
 
1330
            tree.branch, log.LongLogFormatter, show_log_kwargs={
 
1331
                'start_revision': start_rev, 'end_revision': end_rev
 
1332
            })
 
1333
 
 
1334
    def test_short_format(self):
 
1335
        tree = self.setup_ab_tree()
 
1336
        start_rev = revisionspec.RevisionInfo(tree.branch, None, b'1a')
 
1337
        end_rev = revisionspec.RevisionInfo(tree.branch, None, b'3a')
 
1338
        self.assertFormatterResult(b"""\
 
1339
      Joe Foo\t2005-11-22
 
1340
      revision-id:3a
 
1341
      commit 3a
 
1342
 
 
1343
      Joe Foo\t2005-11-22
 
1344
      revision-id:2a
 
1345
      commit 2a
 
1346
 
 
1347
    1 Joe Foo\t2005-11-22
 
1348
      commit 1a
 
1349
 
 
1350
""",
 
1351
            tree.branch, log.ShortLogFormatter, show_log_kwargs={
 
1352
                'start_revision': start_rev, 'end_revision': end_rev
 
1353
            })
 
1354
 
 
1355
    def test_line_format(self):
 
1356
        tree = self.setup_ab_tree()
 
1357
        start_rev = revisionspec.RevisionInfo(tree.branch, None, b'1a')
 
1358
        end_rev = revisionspec.RevisionInfo(tree.branch, None, b'3a')
 
1359
        self.assertFormatterResult(b"""\
 
1360
Joe Foo 2005-11-22 commit 3a
 
1361
Joe Foo 2005-11-22 commit 2a
 
1362
1: Joe Foo 2005-11-22 commit 1a
 
1363
""",
 
1364
            tree.branch, log.LineLogFormatter, show_log_kwargs={
 
1365
                'start_revision': start_rev, 'end_revision': end_rev
 
1366
            })
 
1367
 
1466
1368
 
1467
1369
class TestLogWithBugs(TestCaseForLogFormatter, TestLogMixin):
1468
1370
 
1469
1371
    def setUp(self):
1470
 
        TestCaseForLogFormatter.setUp(self)
 
1372
        super(TestLogWithBugs, self).setUp()
1471
1373
        log.properties_handler_registry.register(
1472
1374
            'bugs_properties_handler',
1473
1375
            log._bugs_properties_handler)
1477
1379
        tree = self.make_branch_and_tree(u'.')
1478
1380
        self.build_tree(['a', 'b'])
1479
1381
        tree.add('a')
1480
 
        self.wt_commit(tree, 'simple log message', rev_id='a1',
1481
 
                       revprops={'bugs': 'test://bug/id fixed'})
 
1382
        self.wt_commit(tree, 'simple log message', rev_id=b'a1',
 
1383
                       revprops={u'bugs': 'test://bug/id fixed'})
1482
1384
        tree.add('b')
1483
 
        self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id='a2',
 
1385
        self.wt_commit(tree, 'multiline\nlog\nmessage\n', rev_id=b'a2',
1484
1386
                       authors=['Joe Bar <joe@bar.com>'],
1485
 
                       revprops={'bugs': 'test://bug/id fixed\n'
 
1387
                       revprops={u'bugs': 'test://bug/id fixed\n'
1486
1388
                                 'test://bug/2 fixed'})
1487
1389
        return tree
1488
1390
 
1489
1391
 
1490
1392
    def test_long_bugs(self):
1491
1393
        tree = self.make_commits_with_bugs()
1492
 
        self.assertFormatterResult("""\
 
1394
        self.assertFormatterResult(b"""\
1493
1395
------------------------------------------------------------
1494
1396
revno: 2
1495
 
fixes bug(s): test://bug/id test://bug/2
 
1397
fixes bugs: test://bug/id test://bug/2
1496
1398
author: Joe Bar <joe@bar.com>
1497
1399
committer: Joe Foo <joe@foo.com>
1498
1400
branch nick: work
1503
1405
  message
1504
1406
------------------------------------------------------------
1505
1407
revno: 1
1506
 
fixes bug(s): test://bug/id
 
1408
fixes bug: test://bug/id
1507
1409
committer: Joe Foo <joe@foo.com>
1508
1410
branch nick: work
1509
1411
timestamp: Tue 2005-11-22 00:00:00 +0000
1514
1416
 
1515
1417
    def test_short_bugs(self):
1516
1418
        tree = self.make_commits_with_bugs()
1517
 
        self.assertFormatterResult("""\
 
1419
        self.assertFormatterResult(b"""\
1518
1420
    2 Joe Bar\t2005-11-22
1519
 
      fixes bug(s): test://bug/id test://bug/2
 
1421
      fixes bugs: test://bug/id test://bug/2
1520
1422
      multiline
1521
1423
      log
1522
1424
      message
1523
1425
 
1524
1426
    1 Joe Foo\t2005-11-22
1525
 
      fixes bug(s): test://bug/id
 
1427
      fixes bug: test://bug/id
1526
1428
      simple log message
1527
1429
 
1528
1430
""",
1531
1433
    def test_wrong_bugs_property(self):
1532
1434
        tree = self.make_branch_and_tree(u'.')
1533
1435
        self.build_tree(['foo'])
1534
 
        self.wt_commit(tree, 'simple log message', rev_id='a1',
1535
 
                       revprops={'bugs': 'test://bug/id invalid_value'})
1536
 
        self.assertFormatterResult("""\
 
1436
        self.wt_commit(tree, 'simple log message', rev_id=b'a1',
 
1437
                       revprops={u'bugs': 'test://bug/id invalid_value'})
 
1438
        self.assertFormatterResult(b"""\
1537
1439
    1 Joe Foo\t2005-11-22
1538
1440
      simple log message
1539
1441
 
1543
1445
    def test_bugs_handler_present(self):
1544
1446
        self.properties_handler_registry.get('bugs_properties_handler')
1545
1447
 
 
1448
 
 
1449
class TestLogForAuthors(TestCaseForLogFormatter):
 
1450
 
 
1451
    def setUp(self):
 
1452
        super(TestLogForAuthors, self).setUp()
 
1453
        self.wt = self.make_standard_commit('nicky',
 
1454
            authors=['John Doe <jdoe@example.com>',
 
1455
                     'Jane Rey <jrey@example.com>'])
 
1456
 
 
1457
    def assertFormatterResult(self, formatter, who, result):
 
1458
        formatter_kwargs = dict()
 
1459
        if who is not None:
 
1460
            author_list_handler = log.author_list_registry.get(who)
 
1461
            formatter_kwargs['author_list_handler'] = author_list_handler
 
1462
        TestCaseForLogFormatter.assertFormatterResult(self, result,
 
1463
            self.wt.branch, formatter, formatter_kwargs=formatter_kwargs)
 
1464
 
 
1465
    def test_line_default(self):
 
1466
        self.assertFormatterResult(log.LineLogFormatter, None, b"""\
 
1467
1: John Doe 2005-11-22 add a
 
1468
""")
 
1469
 
 
1470
    def test_line_committer(self):
 
1471
        self.assertFormatterResult(log.LineLogFormatter, 'committer', b"""\
 
1472
1: Lorem Ipsum 2005-11-22 add a
 
1473
""")
 
1474
 
 
1475
    def test_line_first(self):
 
1476
        self.assertFormatterResult(log.LineLogFormatter, 'first', b"""\
 
1477
1: John Doe 2005-11-22 add a
 
1478
""")
 
1479
 
 
1480
    def test_line_all(self):
 
1481
        self.assertFormatterResult(log.LineLogFormatter, 'all', b"""\
 
1482
1: John Doe, Jane Rey 2005-11-22 add a
 
1483
""")
 
1484
 
 
1485
 
 
1486
    def test_short_default(self):
 
1487
        self.assertFormatterResult(log.ShortLogFormatter, None, b"""\
 
1488
    1 John Doe\t2005-11-22
 
1489
      add a
 
1490
 
 
1491
""")
 
1492
 
 
1493
    def test_short_committer(self):
 
1494
        self.assertFormatterResult(log.ShortLogFormatter, 'committer', b"""\
 
1495
    1 Lorem Ipsum\t2005-11-22
 
1496
      add a
 
1497
 
 
1498
""")
 
1499
 
 
1500
    def test_short_first(self):
 
1501
        self.assertFormatterResult(log.ShortLogFormatter, 'first', b"""\
 
1502
    1 John Doe\t2005-11-22
 
1503
      add a
 
1504
 
 
1505
""")
 
1506
 
 
1507
    def test_short_all(self):
 
1508
        self.assertFormatterResult(log.ShortLogFormatter, 'all', b"""\
 
1509
    1 John Doe, Jane Rey\t2005-11-22
 
1510
      add a
 
1511
 
 
1512
""")
 
1513
 
 
1514
    def test_long_default(self):
 
1515
        self.assertFormatterResult(log.LongLogFormatter, None, b"""\
 
1516
------------------------------------------------------------
 
1517
revno: 1
 
1518
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
 
1519
committer: Lorem Ipsum <test@example.com>
 
1520
branch nick: nicky
 
1521
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1522
message:
 
1523
  add a
 
1524
""")
 
1525
 
 
1526
    def test_long_committer(self):
 
1527
        self.assertFormatterResult(log.LongLogFormatter, 'committer', b"""\
 
1528
------------------------------------------------------------
 
1529
revno: 1
 
1530
committer: Lorem Ipsum <test@example.com>
 
1531
branch nick: nicky
 
1532
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1533
message:
 
1534
  add a
 
1535
""")
 
1536
 
 
1537
    def test_long_first(self):
 
1538
        self.assertFormatterResult(log.LongLogFormatter, 'first', b"""\
 
1539
------------------------------------------------------------
 
1540
revno: 1
 
1541
author: John Doe <jdoe@example.com>
 
1542
committer: Lorem Ipsum <test@example.com>
 
1543
branch nick: nicky
 
1544
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1545
message:
 
1546
  add a
 
1547
""")
 
1548
 
 
1549
    def test_long_all(self):
 
1550
        self.assertFormatterResult(log.LongLogFormatter, 'all', b"""\
 
1551
------------------------------------------------------------
 
1552
revno: 1
 
1553
author: John Doe <jdoe@example.com>, Jane Rey <jrey@example.com>
 
1554
committer: Lorem Ipsum <test@example.com>
 
1555
branch nick: nicky
 
1556
timestamp: Tue 2005-11-22 00:00:00 +0000
 
1557
message:
 
1558
  add a
 
1559
""")
 
1560
 
 
1561
    def test_gnu_changelog_default(self):
 
1562
        self.assertFormatterResult(log.GnuChangelogLogFormatter, None, b"""\
 
1563
2005-11-22  John Doe  <jdoe@example.com>
 
1564
 
 
1565
\tadd a
 
1566
 
 
1567
""")
 
1568
 
 
1569
    def test_gnu_changelog_committer(self):
 
1570
        self.assertFormatterResult(log.GnuChangelogLogFormatter, 'committer', b"""\
 
1571
2005-11-22  Lorem Ipsum  <test@example.com>
 
1572
 
 
1573
\tadd a
 
1574
 
 
1575
""")
 
1576
 
 
1577
    def test_gnu_changelog_first(self):
 
1578
        self.assertFormatterResult(log.GnuChangelogLogFormatter, 'first', b"""\
 
1579
2005-11-22  John Doe  <jdoe@example.com>
 
1580
 
 
1581
\tadd a
 
1582
 
 
1583
""")
 
1584
 
 
1585
    def test_gnu_changelog_all(self):
 
1586
        self.assertFormatterResult(log.GnuChangelogLogFormatter, 'all', b"""\
 
1587
2005-11-22  John Doe  <jdoe@example.com>, Jane Rey  <jrey@example.com>
 
1588
 
 
1589
\tadd a
 
1590
 
 
1591
""")
 
1592
 
 
1593
 
1546
1594
class TestLogExcludeAncestry(tests.TestCaseWithTransport):
1547
1595
 
1548
1596
    def make_branch_with_alternate_ancestries(self, relpath='.'):
1549
1597
        # See test_merge_sorted_exclude_ancestry below for the difference with
1550
1598
        # bt.per_branch.test_iter_merge_sorted_revision.
1551
 
        # TestIterMergeSortedRevisionsBushyGraph. 
 
1599
        # TestIterMergeSortedRevisionsBushyGraph.
1552
1600
        # make_branch_with_alternate_ancestries
1553
1601
        # and test_merge_sorted_exclude_ancestry
1554
1602
        # See the FIXME in assertLogRevnos too.
1565
1613
        # | /
1566
1614
        # 3
1567
1615
        builder.start_series()
1568
 
        builder.build_snapshot('1', None, [
1569
 
            ('add', ('', 'TREE_ROOT', 'directory', '')),])
1570
 
        builder.build_snapshot('1.1.1', ['1'], [])
1571
 
        builder.build_snapshot('2', ['1'], [])
1572
 
        builder.build_snapshot('1.2.1', ['1.1.1'], [])
1573
 
        builder.build_snapshot('1.1.2', ['1.1.1', '1.2.1'], [])
1574
 
        builder.build_snapshot('3', ['2', '1.1.2'], [])
 
1616
        builder.build_snapshot(None, [
 
1617
            ('add', ('', b'TREE_ROOT', 'directory', '')),],
 
1618
            revision_id=b'1')
 
1619
        builder.build_snapshot([b'1'], [], revision_id=b'1.1.1')
 
1620
        builder.build_snapshot([b'1'], [], revision_id=b'2')
 
1621
        builder.build_snapshot([b'1.1.1'], [], revision_id=b'1.2.1')
 
1622
        builder.build_snapshot([b'1.1.1', b'1.2.1'], [], revision_id=b'1.1.2')
 
1623
        builder.build_snapshot([b'2', b'1.1.2'], [], revision_id=b'3')
1575
1624
        builder.finish_series()
1576
1625
        br = builder.get_branch()
1577
1626
        br.lock_read()
1579
1628
        return br
1580
1629
 
1581
1630
    def assertLogRevnos(self, expected_revnos, b, start, end,
1582
 
                        exclude_common_ancestry):
 
1631
                        exclude_common_ancestry, generate_merge_revisions=True):
1583
1632
        # FIXME: the layering in log makes it hard to test intermediate levels,
1584
 
        # I wish adding filters with their parameters were easier...
 
1633
        # I wish adding filters with their parameters was easier...
1585
1634
        # -- vila 20100413
1586
1635
        iter_revs = log._calc_view_revisions(
1587
1636
            b, start, end, direction='reverse',
1588
 
            generate_merge_revisions=True,
 
1637
            generate_merge_revisions=generate_merge_revisions,
1589
1638
            exclude_common_ancestry=exclude_common_ancestry)
1590
1639
        self.assertEqual(expected_revnos,
1591
1640
                         [revid for revid, revno, depth in iter_revs])
1592
1641
 
1593
1642
    def test_merge_sorted_exclude_ancestry(self):
1594
1643
        b = self.make_branch_with_alternate_ancestries()
1595
 
        self.assertLogRevnos(['3', '1.1.2', '1.2.1', '1.1.1', '2', '1'],
1596
 
                             b, '1', '3', False)
 
1644
        self.assertLogRevnos([b'3', b'1.1.2', b'1.2.1', b'1.1.1', b'2', b'1'],
 
1645
                             b, b'1', b'3', exclude_common_ancestry=False)
1597
1646
        # '2' is part of the '3' ancestry but not part of '1.1.1' ancestry so
1598
1647
        # it should be mentioned even if merge_sort order will make it appear
1599
1648
        # after 1.1.1
1600
 
        self.assertLogRevnos(['3', '1.1.2', '1.2.1', '2'],
1601
 
                             b, '1.1.1', '3', True)
1602
 
 
 
1649
        self.assertLogRevnos([b'3', b'1.1.2', b'1.2.1', b'2'],
 
1650
                             b, b'1.1.1', b'3', exclude_common_ancestry=True)
 
1651
 
 
1652
    def test_merge_sorted_simple_revnos_exclude_ancestry(self):
 
1653
        b = self.make_branch_with_alternate_ancestries()
 
1654
        self.assertLogRevnos([b'3', b'2'],
 
1655
                             b, b'1', b'3', exclude_common_ancestry=True,
 
1656
                             generate_merge_revisions=False)
 
1657
        self.assertLogRevnos([b'3', b'1.1.2', b'1.2.1', b'1.1.1', b'2'],
 
1658
                             b, b'1', b'3', exclude_common_ancestry=True,
 
1659
                             generate_merge_revisions=True)
 
1660
 
 
1661
 
 
1662
class TestLogDefaults(TestCaseForLogFormatter):
 
1663
    def test_default_log_level(self):
 
1664
        """
 
1665
        Test to ensure that specifying 'levels=1' to make_log_request_dict
 
1666
        doesn't get overwritten when using a LogFormatter that supports more
 
1667
        detail.
 
1668
        Fixes bug #747958.
 
1669
        """
 
1670
        wt = self._prepare_tree_with_merges()
 
1671
        b = wt.branch
 
1672
 
 
1673
        class CustomLogFormatter(log.LogFormatter):
 
1674
            def __init__(self, *args, **kwargs):
 
1675
                super(CustomLogFormatter, self).__init__(*args, **kwargs)
 
1676
                self.revisions = []
 
1677
            def get_levels(self):
 
1678
                # log formatter supports all levels:
 
1679
                return 0
 
1680
            def log_revision(self, revision):
 
1681
                self.revisions.append(revision)
 
1682
 
 
1683
        log_formatter = LogCatcher()
 
1684
        # First request we don't specify number of levels, we should get a
 
1685
        # sensible default (whatever the LogFormatter handles - which in this
 
1686
        # case is 0/everything):
 
1687
        request = log.make_log_request_dict(limit=10)
 
1688
        log.Logger(b, request).show(log_formatter)
 
1689
        # should have all three revisions:
 
1690
        self.assertEqual(len(log_formatter.revisions), 3)
 
1691
 
 
1692
        del log_formatter
 
1693
        log_formatter = LogCatcher()
 
1694
        # now explicitly request mainline revisions only:
 
1695
        request = log.make_log_request_dict(limit=10, levels=1)
 
1696
        log.Logger(b, request).show(log_formatter)
 
1697
        # should now only have 2 revisions:
 
1698
        self.assertEqual(len(log_formatter.revisions), 2)
1603
1699