~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

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

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2010-01-20 17:19:44 UTC
  • mfrom: (4973.1.1 integration)
  • Revision ID: pqm@pqm.ubuntu.com-20100120171944-8gkub20gotjcye67
(spiv) Implement a per-file merge hook

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2009 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
17
17
 
18
18
"""Tests for the commit CLI of bzr."""
19
19
 
20
 
import doctest
21
20
import os
22
 
import re
23
21
import sys
24
22
 
25
 
from testtools.matchers import DocTestMatches
26
 
 
27
23
from bzrlib import (
28
 
    config,
29
24
    osutils,
30
25
    ignores,
31
26
    msgeditor,
 
27
    osutils,
32
28
    tests,
33
29
    )
34
30
from bzrlib.bzrdir import BzrDir
35
31
from bzrlib.tests import (
36
32
    probe_bad_non_ascii,
37
 
    test_foreign,
38
33
    TestSkipped,
39
 
    features,
40
34
    )
41
 
from bzrlib.tests import TestCaseWithTransport
42
 
 
43
 
 
44
 
class TestCommit(TestCaseWithTransport):
 
35
from bzrlib.tests.blackbox import ExternalBase
 
36
 
 
37
 
 
38
class TestCommit(ExternalBase):
45
39
 
46
40
    def test_05_empty_commit(self):
47
41
        """Commit of tree with no versioned files should fail"""
50
44
        self.build_tree(['hello.txt'])
51
45
        out,err = self.run_bzr('commit -m empty', retcode=3)
52
46
        self.assertEqual('', out)
53
 
        # Two ugly bits here.
54
 
        # 1) We really don't want 'aborting commit write group' anymore.
55
 
        # 2) bzr: ERROR: is a really long line, so we wrap it with '\'
56
 
        self.assertThat(
57
 
            err,
58
 
            DocTestMatches("""\
59
 
Committing to: ...
60
 
bzr: ERROR: No changes to commit.\
61
 
 Please 'bzr add' the files you want to commit,\
62
 
 or use --unchanged to force an empty commit.
63
 
""", flags=doctest.ELLIPSIS|doctest.REPORT_UDIFF))
 
47
        self.assertContainsRe(err, 'bzr: ERROR: No changes to commit\.'
 
48
                                  ' Use --unchanged to commit anyhow.\n')
64
49
 
65
50
    def test_commit_success(self):
66
51
        """Successful commit should not leave behind a bzr-commit-* file"""
72
57
        self.run_bzr(["commit", "--unchanged", "-m", u'foo\xb5'])
73
58
        self.assertEqual('', self.run_bzr('unknowns')[0])
74
59
 
75
 
    def test_commit_lossy_native(self):
76
 
        """A --lossy option to commit is supported."""
77
 
        self.make_branch_and_tree('.')
78
 
        self.run_bzr('commit --lossy --unchanged -m message')
79
 
        self.assertEqual('', self.run_bzr('unknowns')[0])
80
 
 
81
 
    def test_commit_lossy_foreign(self):
82
 
        test_foreign.register_dummy_foreign_for_test(self)
83
 
        self.make_branch_and_tree('.',
84
 
            format=test_foreign.DummyForeignVcsDirFormat())
85
 
        self.run_bzr('commit --lossy --unchanged -m message')
86
 
        output = self.run_bzr('revision-info')[0]
87
 
        self.assertTrue(output.startswith('1 dummy-'))
88
 
 
89
60
    def test_commit_with_path(self):
90
61
        """Commit tree with path of root specified"""
91
62
        a_tree = self.make_branch_and_tree('a')
105
76
        self.run_bzr('resolved b/a_file')
106
77
        self.run_bzr(['commit', '-m', 'merge into b', 'b'])
107
78
 
 
79
 
108
80
    def test_10_verbose_commit(self):
109
81
        """Add one file and examine verbose commit output"""
110
82
        tree = self.make_branch_and_tree('.')
135
107
                              'modified hello\.txt\n'
136
108
                              'Committed revision 2\.\n$')
137
109
 
138
 
    def test_unicode_commit_message_is_filename(self):
139
 
        """Unicode commit message same as a filename (Bug #563646).
140
 
        """
141
 
        self.requireFeature(features.UnicodeFilenameFeature)
142
 
        file_name = u'\N{euro sign}'
143
 
        self.run_bzr(['init'])
144
 
        open(file_name, 'w').write('hello world')
145
 
        self.run_bzr(['add'])
146
 
        out, err = self.run_bzr(['commit', '-m', file_name])
147
 
        reflags = re.MULTILINE|re.DOTALL|re.UNICODE
148
 
        te = osutils.get_terminal_encoding()
149
 
        self.assertContainsRe(err.decode(te),
150
 
            u'The commit message is a file name:',
151
 
            flags=reflags)
152
 
 
153
 
        # Run same test with a filename that causes encode
154
 
        # error for the terminal encoding. We do this
155
 
        # by forcing terminal encoding of ascii for
156
 
        # osutils.get_terminal_encoding which is used
157
 
        # by ui.text.show_warning
158
 
        default_get_terminal_enc = osutils.get_terminal_encoding
159
 
        try:
160
 
            osutils.get_terminal_encoding = lambda trace=None: 'ascii'
161
 
            file_name = u'foo\u1234'
162
 
            open(file_name, 'w').write('hello world')
163
 
            self.run_bzr(['add'])
164
 
            out, err = self.run_bzr(['commit', '-m', file_name])
165
 
            reflags = re.MULTILINE|re.DOTALL|re.UNICODE
166
 
            te = osutils.get_terminal_encoding()
167
 
            self.assertContainsRe(err.decode(te, 'replace'),
168
 
                u'The commit message is a file name:',
169
 
                flags=reflags)
170
 
        finally:
171
 
            osutils.get_terminal_encoding = default_get_terminal_enc
172
 
 
173
110
    def test_warn_about_forgotten_commit_message(self):
174
111
        """Test that the lack of -m parameter is caught"""
175
112
        wt = self.make_branch_and_tree('.')
334
271
        tree.add('foo.c')
335
272
        self.run_bzr('commit -m ""', retcode=3)
336
273
 
 
274
    def test_unsupported_encoding_commit_message(self):
 
275
        if sys.platform == 'win32':
 
276
            raise tests.TestNotApplicable('Win32 parses arguments directly'
 
277
                ' as Unicode, so we can\'t pass invalid non-ascii')
 
278
        tree = self.make_branch_and_tree('.')
 
279
        self.build_tree_contents([('foo.c', 'int main() {}')])
 
280
        tree.add('foo.c')
 
281
        # LANG env variable has no effect on Windows
 
282
        # but some characters anyway cannot be represented
 
283
        # in default user encoding
 
284
        char = probe_bad_non_ascii(osutils.get_user_encoding())
 
285
        if char is None:
 
286
            raise TestSkipped('Cannot find suitable non-ascii character'
 
287
                'for user_encoding (%s)' % osutils.get_user_encoding())
 
288
        out,err = self.run_bzr_subprocess('commit -m "%s"' % char,
 
289
                                          retcode=1,
 
290
                                          env_changes={'LANG': 'C'})
 
291
        self.assertContainsRe(err, r'bzrlib.errors.BzrError: Parameter.*is '
 
292
                                    'unsupported by the current encoding.')
 
293
 
337
294
    def test_other_branch_commit(self):
338
295
        # this branch is to ensure consistent behaviour, whether we're run
339
296
        # inside a branch, or not.
386
343
        trunk = self.make_branch_and_tree('trunk')
387
344
 
388
345
        u1 = trunk.branch.create_checkout('u1')
389
 
        self.build_tree_contents([('u1/hosts', 'initial contents\n')])
 
346
        self.build_tree_contents([('u1/hosts', 'initial contents')])
390
347
        u1.add('hosts')
391
348
        self.run_bzr('commit -m add-hosts u1')
392
349
 
393
350
        u2 = trunk.branch.create_checkout('u2')
394
 
        self.build_tree_contents([('u2/hosts', 'altered in u2\n')])
 
351
        self.build_tree_contents([('u2/hosts', 'altered in u2')])
395
352
        self.run_bzr('commit -m checkin-from-u2 u2')
396
353
 
397
354
        # make an offline commits
398
 
        self.build_tree_contents([('u1/hosts', 'first offline change in u1\n')])
 
355
        self.build_tree_contents([('u1/hosts', 'first offline change in u1')])
399
356
        self.run_bzr('commit -m checkin-offline --local u1')
400
357
 
401
358
        # now try to pull in online work from u2, and then commit our offline
402
359
        # work as a merge
403
360
        # retcode 1 as we expect a text conflict
404
361
        self.run_bzr('update u1', retcode=1)
405
 
        self.assertFileEqual('''\
406
 
<<<<<<< TREE
407
 
first offline change in u1
408
 
=======
409
 
altered in u2
410
 
>>>>>>> MERGE-SOURCE
411
 
''',
412
 
                             'u1/hosts')
413
 
 
414
362
        self.run_bzr('resolved u1/hosts')
415
363
        # add a text change here to represent resolving the merge conflicts in
416
364
        # favour of a new version of the file not identical to either the u1
706
654
        self.assertContainsRe(err, r'modified test\nCommitted revision 2.')
707
655
 
708
656
    def test_commit_readonly_checkout(self):
709
 
        # https://bugs.launchpad.net/bzr/+bug/129701
 
657
        # https://bugs.edge.launchpad.net/bzr/+bug/129701
710
658
        # "UnlockableTransport error trying to commit in checkout of readonly
711
659
        # branch"
712
660
        self.make_branch('master')
718
666
        self.assertContainsRe(err,
719
667
            r'^bzr: ERROR: Cannot lock.*readonly transport')
720
668
 
721
 
    def setup_editor(self):
 
669
    def test_commit_hook_template(self):
722
670
        # Test that commit template hooks work
 
671
        def restoreDefaults():
 
672
            msgeditor.hooks['commit_message_template'] = []
 
673
            osutils.set_or_unset_env('BZR_EDITOR', default_editor)
723
674
        if sys.platform == "win32":
724
675
            f = file('fed.bat', 'w')
725
676
            f.write('@rem dummy fed')
726
677
            f.close()
727
 
            self.overrideEnv('BZR_EDITOR', "fed.bat")
 
678
            default_editor = osutils.set_or_unset_env('BZR_EDITOR', "fed.bat")
728
679
        else:
729
680
            f = file('fed.sh', 'wb')
730
681
            f.write('#!/bin/sh\n')
731
682
            f.close()
732
683
            os.chmod('fed.sh', 0755)
733
 
            self.overrideEnv('BZR_EDITOR', "./fed.sh")
734
 
 
735
 
    def setup_commit_with_template(self):
736
 
        self.setup_editor()
 
684
            default_editor = osutils.set_or_unset_env('BZR_EDITOR', "./fed.sh")
 
685
        self.addCleanup(restoreDefaults)
737
686
        msgeditor.hooks.install_named_hook("commit_message_template",
738
687
                lambda commit_obj, msg: "save me some typing\n", None)
739
688
        tree = self.make_branch_and_tree('tree')
740
689
        self.build_tree(['tree/hello.txt'])
741
690
        tree.add('hello.txt')
742
 
        return tree
743
 
 
744
 
    def test_commit_hook_template_accepted(self):
745
 
        tree = self.setup_commit_with_template()
746
 
        out, err = self.run_bzr("commit tree/hello.txt", stdin="y\n")
747
 
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
748
 
        self.assertEqual('save me some typing\n', last_rev.message)
749
 
 
750
 
    def test_commit_hook_template_rejected(self):
751
 
        tree = self.setup_commit_with_template()
752
 
        expected = tree.last_revision()
753
 
        out, err = self.run_bzr_error(["empty commit message"],
754
 
            "commit tree/hello.txt", stdin="n\n")
755
 
        self.assertEqual(expected, tree.last_revision())
756
 
 
757
 
    def test_set_commit_message(self):
758
 
        msgeditor.hooks.install_named_hook("set_commit_message",
759
 
                lambda commit_obj, msg: "save me some typing\n", None)
760
 
        tree = self.make_branch_and_tree('tree')
761
 
        self.build_tree(['tree/hello.txt'])
762
 
        tree.add('hello.txt')
763
691
        out, err = self.run_bzr("commit tree/hello.txt")
764
692
        last_rev = tree.branch.repository.get_revision(tree.last_revision())
765
693
        self.assertEqual('save me some typing\n', last_rev.message)
766
 
 
767
 
    def test_commit_without_username(self):
768
 
        """Ensure commit error if username is not set.
769
 
        """
770
 
        self.run_bzr(['init', 'foo'])
771
 
        os.chdir('foo')
772
 
        open('foo.txt', 'w').write('hello')
773
 
        self.run_bzr(['add'])
774
 
        self.overrideEnv('EMAIL', None)
775
 
        self.overrideEnv('BZR_EMAIL', None)
776
 
        # Also, make sure that it's not inferred from mailname.
777
 
        self.overrideAttr(config, '_auto_user_id',
778
 
            lambda: (None, None))
779
 
        out, err = self.run_bzr(['commit', '-m', 'initial'], 3)
780
 
        self.assertContainsRe(err, 'Unable to determine your name')
781
 
 
782
 
    def test_commit_recursive_checkout(self):
783
 
        """Ensure that a commit to a recursive checkout fails cleanly.
784
 
        """
785
 
        self.run_bzr(['init', 'test_branch'])
786
 
        self.run_bzr(['checkout', 'test_branch', 'test_checkout'])
787
 
        os.chdir('test_checkout')
788
 
        self.run_bzr(['bind', '.']) # bind to self
789
 
        open('foo.txt', 'w').write('hello')
790
 
        self.run_bzr(['add'])
791
 
        out, err = self.run_bzr(['commit', '-m', 'addedfoo'], 3)
792
 
        self.assertEqual(out, '')
793
 
        self.assertContainsRe(err,
794
 
            'Branch.*test_checkout.*appears to be bound to itself')