~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_msgeditor.py

  • Committer: Vincent Ladeuil
  • Date: 2012-01-18 14:09:19 UTC
  • mto: This revision was merged to the branch mainline in revision 6468.
  • Revision ID: v.ladeuil+lp@free.fr-20120118140919-rlvdrhpc0nq1lbwi
Change set/remove to require a lock for the branch config files.

This means that tests (or any plugin for that matter) do not requires an
explicit lock on the branch anymore to change a single option. This also
means the optimisation becomes "opt-in" and as such won't be as
spectacular as it may be and/or harder to get right (nothing fails
anymore).

This reduces the diff by ~300 lines.

Code/tests that were updating more than one config option is still taking
a lock to at least avoid some IOs and demonstrate the benefits through
the decreased number of hpss calls.

The duplication between BranchStack and BranchOnlyStack will be removed
once the same sharing is in place for local config files, at which point
the Stack class itself may be able to host the changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2010 Canonical Ltd
 
1
# Copyright (C) 2005-2011 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
22
22
 
23
23
from bzrlib import (
24
24
    commit,
 
25
    config,
25
26
    errors,
26
27
    msgeditor,
27
28
    osutils,
28
29
    tests,
29
30
    trace,
30
31
    )
31
 
from bzrlib.branch import Branch
32
 
from bzrlib.config import ensure_config_dir_exists, config_filename
33
32
from bzrlib.msgeditor import (
34
33
    make_commit_message_template_encoded,
35
34
    edit_commit_message_encoded
36
35
)
37
36
from bzrlib.tests import (
 
37
    features,
38
38
    TestCaseInTempDir,
39
39
    TestCaseWithTransport,
40
40
    TestNotApplicable,
142
142
  hell\u00d8
143
143
""".encode('utf8') in template)
144
144
 
145
 
    def make_do_nothing_editor(self):
 
145
    def make_do_nothing_editor(self, basename='fed'):
146
146
        if sys.platform == "win32":
147
 
            f = file('fed.bat', 'w')
 
147
            name = basename + '.bat'
 
148
            f = file(name, 'w')
148
149
            f.write('@rem dummy fed')
149
150
            f.close()
150
 
            return 'fed.bat'
 
151
            return name
151
152
        else:
152
 
            f = file('fed.sh', 'wb')
 
153
            name = basename + '.sh'
 
154
            f = file(name, 'wb')
153
155
            f.write('#!/bin/sh\n')
154
156
            f.close()
155
 
            os.chmod('fed.sh', 0755)
156
 
            return './fed.sh'
 
157
            os.chmod(name, 0755)
 
158
            return './' + name
157
159
 
158
160
    def test_run_editor(self):
159
 
        os.environ['BZR_EDITOR'] = self.make_do_nothing_editor()
 
161
        self.overrideEnv('BZR_EDITOR', self.make_do_nothing_editor())
160
162
        self.assertEqual(True, msgeditor._run_editor(''),
161
163
                         'Unable to run dummy fake editor')
162
164
 
 
165
    def test_parse_editor_name(self):
 
166
        """Correctly interpret names with spaces.
 
167
 
 
168
        See <https://bugs.launchpad.net/bzr/+bug/220331>
 
169
        """
 
170
        self.overrideEnv('BZR_EDITOR',
 
171
            '"%s"' % self.make_do_nothing_editor('name with spaces'))
 
172
        self.assertEqual(True, msgeditor._run_editor('a_filename'))    
 
173
 
163
174
    def make_fake_editor(self, message='test message from fed\\n'):
164
175
        """Set up environment so that an editor will be a known script.
165
176
 
190
201
"%s" fed.py %%1
191
202
""" % sys.executable)
192
203
            f.close()
193
 
            os.environ['BZR_EDITOR'] = 'fed.bat'
 
204
            self.overrideEnv('BZR_EDITOR', 'fed.bat')
194
205
        else:
195
206
            # [non-win32] make python script executable and set BZR_EDITOR
196
207
            os.chmod('fed.py', 0755)
197
 
            os.environ['BZR_EDITOR'] = './fed.py'
 
208
            self.overrideEnv('BZR_EDITOR', './fed.py')
198
209
 
199
210
    def test_edit_commit_message(self):
200
211
        working_tree = self.make_uncommitted_tree()
229
240
        working_tree = self.make_uncommitted_tree()
230
241
 
231
242
        if sys.platform == 'win32':
232
 
            os.environ['BZR_EDITOR'] = 'cmd.exe /c del'
 
243
            editor = 'cmd.exe /c del'
233
244
        else:
234
 
            os.environ['BZR_EDITOR'] = 'rm'
 
245
            editor = 'rm'
 
246
        self.overrideEnv('BZR_EDITOR', editor)
235
247
 
236
248
        self.assertRaises((IOError, OSError), msgeditor.edit_commit_message, '')
237
249
 
238
250
    def test__get_editor(self):
239
 
        # Test that _get_editor can return a decent list of items
240
 
        bzr_editor = os.environ.get('BZR_EDITOR')
241
 
        visual = os.environ.get('VISUAL')
242
 
        editor = os.environ.get('EDITOR')
243
 
        try:
244
 
            os.environ['BZR_EDITOR'] = 'bzr_editor'
245
 
            os.environ['VISUAL'] = 'visual'
246
 
            os.environ['EDITOR'] = 'editor'
247
 
 
248
 
            ensure_config_dir_exists()
249
 
            f = open(config_filename(), 'wb')
250
 
            f.write('editor = config_editor\n')
251
 
            f.close()
252
 
 
253
 
            editors = list(msgeditor._get_editor())
254
 
            editors = [editor for (editor, cfg_src) in editors]
255
 
 
256
 
            self.assertEqual(['bzr_editor', 'config_editor', 'visual',
257
 
                              'editor'], editors[:4])
258
 
 
259
 
            if sys.platform == 'win32':
260
 
                self.assertEqual(['wordpad.exe', 'notepad.exe'], editors[4:])
261
 
            else:
262
 
                self.assertEqual(['/usr/bin/editor', 'vi', 'pico', 'nano',
263
 
                                  'joe'], editors[4:])
264
 
 
265
 
        finally:
266
 
            # Restore the environment
267
 
            if bzr_editor is None:
268
 
                del os.environ['BZR_EDITOR']
269
 
            else:
270
 
                os.environ['BZR_EDITOR'] = bzr_editor
271
 
            if visual is None:
272
 
                del os.environ['VISUAL']
273
 
            else:
274
 
                os.environ['VISUAL'] = visual
275
 
            if editor is None:
276
 
                del os.environ['EDITOR']
277
 
            else:
278
 
                os.environ['EDITOR'] = editor
 
251
        self.overrideEnv('BZR_EDITOR', 'bzr_editor')
 
252
        self.overrideEnv('VISUAL', 'visual')
 
253
        self.overrideEnv('EDITOR', 'editor')
 
254
 
 
255
        conf = config.GlobalStack()
 
256
        conf.store._load_from_string('[DEFAULT]\neditor = config_editor\n')
 
257
        conf.store.save()
 
258
        editors = list(msgeditor._get_editor())
 
259
        editors = [editor for (editor, cfg_src) in editors]
 
260
 
 
261
        self.assertEqual(['bzr_editor', 'config_editor', 'visual', 'editor'],
 
262
                         editors[:4])
 
263
 
 
264
        if sys.platform == 'win32':
 
265
            self.assertEqual(['wordpad.exe', 'notepad.exe'], editors[4:])
 
266
        else:
 
267
            self.assertEqual(['/usr/bin/editor', 'vi', 'pico', 'nano', 'joe'],
 
268
                             editors[4:])
 
269
 
279
270
 
280
271
    def test__run_editor_EACCES(self):
281
272
        """If running a configured editor raises EACESS, the user is warned."""
282
 
        os.environ['BZR_EDITOR'] = 'eacces.py'
 
273
        self.overrideEnv('BZR_EDITOR', 'eacces.py')
283
274
        f = file('eacces.py', 'wb')
284
275
        f.write('# Not a real editor')
285
276
        f.close()
287
278
        os.chmod('eacces.py', 0)
288
279
        # Set $EDITOR so that _run_editor will terminate before trying real
289
280
        # editors.
290
 
        os.environ['EDITOR'] = self.make_do_nothing_editor()
 
281
        self.overrideEnv('EDITOR', self.make_do_nothing_editor())
291
282
        # Call _run_editor, capturing mutter.warning calls.
292
283
        warnings = []
293
284
        def warning(*args):
319
310
        self.assertFileEqual(expected, msgfilename)
320
311
 
321
312
    def test__create_temp_file_with_commit_template_in_unicode_dir(self):
322
 
        self.requireFeature(tests.UnicodeFilenameFeature)
 
313
        self.requireFeature(features.UnicodeFilenameFeature)
323
314
        if hasattr(self, 'info'):
324
 
            os.mkdir(self.info['directory'])
325
 
            os.chdir(self.info['directory'])
326
 
            msgeditor._create_temp_file_with_commit_template('infotext')
 
315
            tmpdir = self.info['directory']
 
316
            os.mkdir(tmpdir)
 
317
            # Force the creation of temp file in a directory whose name
 
318
            # requires some encoding support
 
319
            msgeditor._create_temp_file_with_commit_template('infotext',
 
320
                                                             tmpdir=tmpdir)
327
321
        else:
328
322
            raise TestNotApplicable('Test run elsewhere with non-ascii data.')
329
323
 
336
330
        self.assertFileEqual('', msgfilename)
337
331
 
338
332
    def test_unsupported_encoding_commit_message(self):
339
 
        old_env = osutils.set_or_unset_env('LANG', 'C')
340
 
        try:
341
 
            # LANG env variable has no effect on Windows
342
 
            # but some characters anyway cannot be represented
343
 
            # in default user encoding
344
 
            char = probe_bad_non_ascii(osutils.get_user_encoding())
345
 
            if char is None:
346
 
                raise TestSkipped('Cannot find suitable non-ascii character '
347
 
                    'for user_encoding (%s)' % osutils.get_user_encoding())
348
 
 
349
 
            self.make_fake_editor(message=char)
350
 
 
351
 
            working_tree = self.make_uncommitted_tree()
352
 
            self.assertRaises(errors.BadCommitMessageEncoding,
353
 
                              msgeditor.edit_commit_message, '')
354
 
        finally:
355
 
            osutils.set_or_unset_env('LANG', old_env)
 
333
        self.overrideEnv('LANG', 'C')
 
334
        # LANG env variable has no effect on Windows
 
335
        # but some characters anyway cannot be represented
 
336
        # in default user encoding
 
337
        char = probe_bad_non_ascii(osutils.get_user_encoding())
 
338
        if char is None:
 
339
            raise TestSkipped('Cannot find suitable non-ascii character '
 
340
                'for user_encoding (%s)' % osutils.get_user_encoding())
 
341
 
 
342
        self.make_fake_editor(message=char)
 
343
 
 
344
        working_tree = self.make_uncommitted_tree()
 
345
        self.assertRaises(errors.BadCommitMessageEncoding,
 
346
                          msgeditor.edit_commit_message, '')
 
347
 
 
348
    def test_set_commit_message_no_hooks(self):
 
349
        commit_obj = commit.Commit()
 
350
        self.assertIs(None,
 
351
            msgeditor.set_commit_message(commit_obj))
 
352
 
 
353
    def test_set_commit_message_hook(self):
 
354
        msgeditor.hooks.install_named_hook("set_commit_message",
 
355
                lambda commit_obj, existing_message: "save me some typing\n", None)
 
356
        commit_obj = commit.Commit()
 
357
        self.assertEquals("save me some typing\n",
 
358
            msgeditor.set_commit_message(commit_obj))
356
359
 
357
360
    def test_generate_commit_message_template_no_hooks(self):
358
361
        commit_obj = commit.Commit()
378
381
        ERROR_BAD_EXE_FORMAT = 193
379
382
        file("textfile.txt", "w").close()
380
383
        e = self.assertRaises(WindowsError, subprocess.call, "textfile.txt")
381
 
        # Python2.4 used the 'winerror' as the errno, which confuses a lot of
382
 
        # our error trapping code. Make sure that we understand the mapping
383
 
        # correctly.
384
 
        if sys.version_info >= (2, 5):
385
 
            self.assertEqual(e.errno, errno.ENOEXEC)
386
 
            self.assertEqual(e.winerror, ERROR_BAD_EXE_FORMAT)
387
 
        else:
388
 
            self.assertEqual(e.errno, ERROR_BAD_EXE_FORMAT)
 
384
        self.assertEqual(e.errno, errno.ENOEXEC)
 
385
        self.assertEqual(e.winerror, ERROR_BAD_EXE_FORMAT)