~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_msgeditor.py

  • Committer: Jelmer Vernooij
  • Date: 2010-12-20 11:57:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5577.
  • Revision ID: jelmer@samba.org-20101220115714-2ru3hfappjweeg7q
Don't use no-plugins.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005 Canonical Ltd
 
1
# Copyright (C) 2005-2010 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Test commit message editor.
18
18
"""
20
20
import os
21
21
import sys
22
22
 
23
 
import bzrlib
24
23
from bzrlib import (
 
24
    commit,
 
25
    config,
25
26
    errors,
26
27
    msgeditor,
27
28
    osutils,
 
29
    tests,
 
30
    trace,
28
31
    )
29
32
from bzrlib.branch import Branch
30
33
from bzrlib.config import ensure_config_dir_exists, config_filename
33
36
    edit_commit_message_encoded
34
37
)
35
38
from bzrlib.tests import (
36
 
    probe_bad_non_ascii,
 
39
    TestCaseInTempDir,
37
40
    TestCaseWithTransport,
38
41
    TestNotApplicable,
39
42
    TestSkipped,
 
43
    multiply_tests,
 
44
    probe_bad_non_ascii,
 
45
    split_suite_by_re,
40
46
    )
 
47
from bzrlib.tests.EncodingAdapter import encoding_scenarios
41
48
from bzrlib.trace import mutter
42
49
 
43
50
 
 
51
def load_tests(standard_tests, module, loader):
 
52
    """Parameterize the test for tempfile creation with different encodings."""
 
53
    to_adapt, result = split_suite_by_re(standard_tests,
 
54
        "test__create_temp_file_with_commit_template_in_unicode_dir")
 
55
    return multiply_tests(to_adapt, encoding_scenarios, result)
 
56
 
 
57
 
44
58
class MsgEditorTest(TestCaseWithTransport):
45
59
 
46
60
    def make_uncommitted_tree(self):
55
69
                "filesystem encoding %s" % sys.getfilesystemencoding())
56
70
        working_tree.add(filename)
57
71
        return working_tree
58
 
    
 
72
 
59
73
    def test_commit_template(self):
60
74
        """Test building a commit message template"""
61
75
        working_tree = self.make_uncommitted_tree()
67
81
  hell\u00d8
68
82
""")
69
83
 
 
84
    def make_multiple_pending_tree(self):
 
85
        from bzrlib import config
 
86
        config.GlobalConfig().set_user_option('email',
 
87
                                              'Bilbo Baggins <bb@hobbit.net>')
 
88
        tree = self.make_branch_and_tree('a')
 
89
        tree.commit('Initial checkin.', timestamp=1230912900, timezone=0)
 
90
        tree2 = tree.bzrdir.clone('b').open_workingtree()
 
91
        tree.commit('Minor tweak.', timestamp=1231977840, timezone=0)
 
92
        tree2.commit('Feature X work.', timestamp=1233186240, timezone=0)
 
93
        tree3 = tree2.bzrdir.clone('c').open_workingtree()
 
94
        tree2.commit('Feature X finished.', timestamp=1233187680, timezone=0)
 
95
        tree3.commit('Feature Y, based on initial X work.',
 
96
                     timestamp=1233285960, timezone=0)
 
97
        tree.merge_from_branch(tree2.branch)
 
98
        tree.merge_from_branch(tree3.branch, force=True)
 
99
        return tree
 
100
 
 
101
    def test_commit_template_pending_merges(self):
 
102
        """Test building a commit message template when there are pending
 
103
        merges.  The commit message should show all pending merge revisions,
 
104
        as does 'status -v', not only the merge tips.
 
105
        """
 
106
        working_tree = self.make_multiple_pending_tree()
 
107
        template = msgeditor.make_commit_message_template(working_tree, None)
 
108
        self.assertEqualDiff(template,
 
109
u"""\
 
110
pending merges:
 
111
  Bilbo Baggins 2009-01-29 Feature X finished.
 
112
    Bilbo Baggins 2009-01-28 Feature X work.
 
113
  Bilbo Baggins 2009-01-30 Feature Y, based on initial X work.
 
114
""")
 
115
 
70
116
    def test_commit_template_encoded(self):
71
117
        """Test building a commit message template"""
72
118
        working_tree = self.make_uncommitted_tree()
97
143
  hell\u00d8
98
144
""".encode('utf8') in template)
99
145
 
100
 
    def test_run_editor(self):
 
146
    def make_do_nothing_editor(self):
101
147
        if sys.platform == "win32":
102
148
            f = file('fed.bat', 'w')
103
149
            f.write('@rem dummy fed')
104
150
            f.close()
105
 
            os.environ['BZR_EDITOR'] = 'fed.bat'
 
151
            return 'fed.bat'
106
152
        else:
107
153
            f = file('fed.sh', 'wb')
108
154
            f.write('#!/bin/sh\n')
109
155
            f.close()
110
156
            os.chmod('fed.sh', 0755)
111
 
            os.environ['BZR_EDITOR'] = './fed.sh'
 
157
            return './fed.sh'
112
158
 
 
159
    def test_run_editor(self):
 
160
        os.environ['BZR_EDITOR'] = self.make_do_nothing_editor()
113
161
        self.assertEqual(True, msgeditor._run_editor(''),
114
162
                         'Unable to run dummy fake editor')
115
163
 
189
237
        self.assertRaises((IOError, OSError), msgeditor.edit_commit_message, '')
190
238
 
191
239
    def test__get_editor(self):
192
 
        # Test that _get_editor can return a decent list of items
193
 
        bzr_editor = os.environ.get('BZR_EDITOR')
194
 
        visual = os.environ.get('VISUAL')
195
 
        editor = os.environ.get('EDITOR')
 
240
        os.environ['BZR_EDITOR'] = 'bzr_editor'
 
241
        os.environ['VISUAL'] = 'visual'
 
242
        os.environ['EDITOR'] = 'editor'
 
243
 
 
244
        conf = config.GlobalConfig.from_string('editor = config_editor\n',
 
245
                                               save=True)
 
246
 
 
247
        editors = list(msgeditor._get_editor())
 
248
        editors = [editor for (editor, cfg_src) in editors]
 
249
 
 
250
        self.assertEqual(['bzr_editor', 'config_editor', 'visual', 'editor'],
 
251
                         editors[:4])
 
252
 
 
253
        if sys.platform == 'win32':
 
254
            self.assertEqual(['wordpad.exe', 'notepad.exe'], editors[4:])
 
255
        else:
 
256
            self.assertEqual(['/usr/bin/editor', 'vi', 'pico', 'nano', 'joe'],
 
257
                             editors[4:])
 
258
 
 
259
 
 
260
    def test__run_editor_EACCES(self):
 
261
        """If running a configured editor raises EACESS, the user is warned."""
 
262
        os.environ['BZR_EDITOR'] = 'eacces.py'
 
263
        f = file('eacces.py', 'wb')
 
264
        f.write('# Not a real editor')
 
265
        f.close()
 
266
        # Make the fake editor unreadable (and unexecutable)
 
267
        os.chmod('eacces.py', 0)
 
268
        # Set $EDITOR so that _run_editor will terminate before trying real
 
269
        # editors.
 
270
        os.environ['EDITOR'] = self.make_do_nothing_editor()
 
271
        # Call _run_editor, capturing mutter.warning calls.
 
272
        warnings = []
 
273
        def warning(*args):
 
274
            if len(args) > 1:
 
275
                warnings.append(args[0] % args[1:])
 
276
            else:
 
277
                warnings.append(args[0])
 
278
        _warning = trace.warning
 
279
        trace.warning = warning
196
280
        try:
197
 
            os.environ['BZR_EDITOR'] = 'bzr_editor'
198
 
            os.environ['VISUAL'] = 'visual'
199
 
            os.environ['EDITOR'] = 'editor'
200
 
 
201
 
            ensure_config_dir_exists()
202
 
            f = open(config_filename(), 'wb')
203
 
            f.write('editor = config_editor\n')
204
 
            f.close()
205
 
 
206
 
            editors = list(msgeditor._get_editor())
207
 
 
208
 
            self.assertEqual(['bzr_editor', 'config_editor', 'visual',
209
 
                              'editor'], editors[:4])
210
 
 
211
 
            if sys.platform == 'win32':
212
 
                self.assertEqual(['wordpad.exe', 'notepad.exe'], editors[4:])
213
 
            else:
214
 
                self.assertEqual(['/usr/bin/editor', 'vi', 'pico', 'nano',
215
 
                                  'joe'], editors[4:])
216
 
 
 
281
            msgeditor._run_editor('')
217
282
        finally:
218
 
            # Restore the environment
219
 
            if bzr_editor is None:
220
 
                del os.environ['BZR_EDITOR']
221
 
            else:
222
 
                os.environ['BZR_EDITOR'] = bzr_editor
223
 
            if visual is None:
224
 
                del os.environ['VISUAL']
225
 
            else:
226
 
                os.environ['VISUAL'] = visual
227
 
            if editor is None:
228
 
                del os.environ['EDITOR']
229
 
            else:
230
 
                os.environ['EDITOR'] = editor
 
283
            trace.warning = _warning
 
284
        self.assertStartsWith(warnings[0], 'Could not start editor "eacces.py"')
231
285
 
232
286
    def test__create_temp_file_with_commit_template(self):
233
287
        # check that commit template written properly
245
299
        self.assertFileEqual(expected, msgfilename)
246
300
 
247
301
    def test__create_temp_file_with_commit_template_in_unicode_dir(self):
 
302
        self.requireFeature(tests.UnicodeFilenameFeature)
248
303
        if hasattr(self, 'info'):
249
 
            os.mkdir(self.info['directory'])
250
 
            os.chdir(self.info['directory'])
251
 
            msgeditor._create_temp_file_with_commit_template('infotext')
 
304
            tmpdir = self.info['directory']
 
305
            os.mkdir(tmpdir)
 
306
            # Force the creation of temp file in a directory whose name
 
307
            # requires some encoding support
 
308
            msgeditor._create_temp_file_with_commit_template('infotext',
 
309
                                                             tmpdir=tmpdir)
252
310
        else:
253
311
            raise TestNotApplicable('Test run elsewhere with non-ascii data.')
254
312
 
266
324
            # LANG env variable has no effect on Windows
267
325
            # but some characters anyway cannot be represented
268
326
            # in default user encoding
269
 
            char = probe_bad_non_ascii(bzrlib.user_encoding)
 
327
            char = probe_bad_non_ascii(osutils.get_user_encoding())
270
328
            if char is None:
271
329
                raise TestSkipped('Cannot find suitable non-ascii character '
272
 
                    'for user_encoding (%s)' % bzrlib.user_encoding)
 
330
                    'for user_encoding (%s)' % osutils.get_user_encoding())
273
331
 
274
332
            self.make_fake_editor(message=char)
275
333
 
278
336
                              msgeditor.edit_commit_message, '')
279
337
        finally:
280
338
            osutils.set_or_unset_env('LANG', old_env)
 
339
 
 
340
    def test_generate_commit_message_template_no_hooks(self):
 
341
        commit_obj = commit.Commit()
 
342
        self.assertIs(None,
 
343
            msgeditor.generate_commit_message_template(commit_obj))
 
344
 
 
345
    def test_generate_commit_message_template_hook(self):
 
346
        msgeditor.hooks.install_named_hook("commit_message_template",
 
347
                lambda commit_obj, msg: "save me some typing\n", None)
 
348
        commit_obj = commit.Commit()
 
349
        self.assertEquals("save me some typing\n",
 
350
            msgeditor.generate_commit_message_template(commit_obj))
 
351
 
 
352
 
 
353
# GZ 2009-11-17: This wants moving to osutils when the errno checking code is
 
354
class TestPlatformErrnoWorkarounds(TestCaseInTempDir):
 
355
    """Ensuring workarounds enshrined in code actually serve a purpose"""
 
356
 
 
357
    def test_subprocess_call_bad_file(self):
 
358
        if sys.platform != "win32":
 
359
            raise TestNotApplicable("Workarounds for windows only")
 
360
        import subprocess, errno
 
361
        ERROR_BAD_EXE_FORMAT = 193
 
362
        file("textfile.txt", "w").close()
 
363
        e = self.assertRaises(WindowsError, subprocess.call, "textfile.txt")
 
364
        # Python2.4 used the 'winerror' as the errno, which confuses a lot of
 
365
        # our error trapping code. Make sure that we understand the mapping
 
366
        # correctly.
 
367
        if sys.version_info >= (2, 5):
 
368
            self.assertEqual(e.errno, errno.ENOEXEC)
 
369
            self.assertEqual(e.winerror, ERROR_BAD_EXE_FORMAT)
 
370
        else:
 
371
            self.assertEqual(e.errno, ERROR_BAD_EXE_FORMAT)