~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/tests/test_osutils_encodings.py

(jelmer) Convert bzrlib.smtp_connection to use config stacks. (Jelmer
 Vernooij)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (C) 2006-2011 Canonical Ltd
 
2
#
 
3
# This program is free software; you can redistribute it and/or modify
 
4
# it under the terms of the GNU General Public License as published by
 
5
# the Free Software Foundation; either version 2 of the License, or
 
6
# (at your option) any later version.
 
7
#
 
8
# This program is distributed in the hope that it will be useful,
 
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
# GNU General Public License for more details.
 
12
#
 
13
# You should have received a copy of the GNU General Public License
 
14
# along with this program; if not, write to the Free Software
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
16
 
 
17
"""Tests for the osutils wrapper."""
 
18
 
 
19
import codecs
 
20
import errno
 
21
import locale
 
22
import os
 
23
import sys
 
24
 
 
25
from bzrlib import (
 
26
    osutils,
 
27
    )
 
28
from bzrlib.tests import (
 
29
        StringIOWrapper,
 
30
        TestCase,
 
31
        )
 
32
 
 
33
 
 
34
class FakeCodec(object):
 
35
    """Special class that helps testing over several non-existed encodings.
 
36
 
 
37
    Clients can add new encoding names, but because of how codecs is
 
38
    implemented they cannot be removed. Be careful with naming to avoid
 
39
    collisions between tests.
 
40
    """
 
41
    _registered = False
 
42
    _enabled_encodings = set()
 
43
 
 
44
    def add(self, encoding_name):
 
45
        """Adding encoding name to fake.
 
46
 
 
47
        :type   encoding_name:  lowercase plain string
 
48
        """
 
49
        if not self._registered:
 
50
            codecs.register(self)
 
51
            self._registered = True
 
52
        if encoding_name is not None:
 
53
            self._enabled_encodings.add(encoding_name)
 
54
 
 
55
    def __call__(self, encoding_name):
 
56
        """Called indirectly by codecs module during lookup"""
 
57
        if encoding_name in self._enabled_encodings:
 
58
            return codecs.lookup('latin-1')
 
59
 
 
60
 
 
61
fake_codec = FakeCodec()
 
62
 
 
63
 
 
64
class TestFakeCodec(TestCase):
 
65
 
 
66
    def test_fake_codec(self):
 
67
        self.assertRaises(LookupError, codecs.lookup, 'fake')
 
68
 
 
69
        fake_codec.add('fake')
 
70
        codecs.lookup('fake')
 
71
 
 
72
 
 
73
class TestTerminalEncoding(TestCase):
 
74
    """Test the auto-detection of proper terminal encoding."""
 
75
 
 
76
    def setUp(self):
 
77
        TestCase.setUp(self)
 
78
        self.overrideAttr(sys, 'stdin')
 
79
        self.overrideAttr(sys, 'stdout')
 
80
        self.overrideAttr(sys, 'stderr')
 
81
        self.overrideAttr(osutils, '_cached_user_encoding')
 
82
 
 
83
    def make_wrapped_streams(self,
 
84
                             stdout_encoding,
 
85
                             stderr_encoding,
 
86
                             stdin_encoding,
 
87
                             user_encoding='user_encoding',
 
88
                             enable_fake_encodings=True):
 
89
        sys.stdout = StringIOWrapper()
 
90
        sys.stdout.encoding = stdout_encoding
 
91
        sys.stderr = StringIOWrapper()
 
92
        sys.stderr.encoding = stderr_encoding
 
93
        sys.stdin = StringIOWrapper()
 
94
        sys.stdin.encoding = stdin_encoding
 
95
        osutils._cached_user_encoding = user_encoding
 
96
        if enable_fake_encodings:
 
97
            fake_codec.add(stdout_encoding)
 
98
            fake_codec.add(stderr_encoding)
 
99
            fake_codec.add(stdin_encoding)
 
100
 
 
101
    def test_get_terminal_encoding(self):
 
102
        self.make_wrapped_streams('stdout_encoding',
 
103
                                  'stderr_encoding',
 
104
                                  'stdin_encoding')
 
105
 
 
106
        # first preference is stdout encoding
 
107
        self.assertEqual('stdout_encoding', osutils.get_terminal_encoding())
 
108
 
 
109
        sys.stdout.encoding = None
 
110
        # if sys.stdout is None, fall back to sys.stdin
 
111
        self.assertEqual('stdin_encoding', osutils.get_terminal_encoding())
 
112
 
 
113
        sys.stdin.encoding = None
 
114
        # and in the worst case, use osutils.get_user_encoding()
 
115
        self.assertEqual('user_encoding', osutils.get_terminal_encoding())
 
116
 
 
117
    def test_get_terminal_encoding_silent(self):
 
118
        self.make_wrapped_streams('stdout_encoding',
 
119
                                  'stderr_encoding',
 
120
                                  'stdin_encoding')
 
121
        # Calling get_terminal_encoding should not mutter when silent=True is
 
122
        # passed.
 
123
        log = self.get_log()
 
124
        osutils.get_terminal_encoding()
 
125
        self.assertEqual(log, self.get_log())
 
126
 
 
127
    def test_get_terminal_encoding_trace(self):
 
128
        self.make_wrapped_streams('stdout_encoding',
 
129
                                  'stderr_encoding',
 
130
                                  'stdin_encoding')
 
131
        # Calling get_terminal_encoding should not mutter when silent=True is
 
132
        # passed.
 
133
        log = self.get_log()
 
134
        osutils.get_terminal_encoding(trace=True)
 
135
        self.assertNotEqual(log, self.get_log())
 
136
 
 
137
    def test_terminal_cp0(self):
 
138
        # test cp0 encoding (Windows returns cp0 when there is no encoding)
 
139
        self.make_wrapped_streams('cp0',
 
140
                                  'cp0',
 
141
                                  'cp0',
 
142
                                  user_encoding='latin-1',
 
143
                                  enable_fake_encodings=False)
 
144
 
 
145
        # cp0 is invalid encoding. We should fall back to user_encoding
 
146
        self.assertEqual('latin-1', osutils.get_terminal_encoding())
 
147
 
 
148
        # check stderr
 
149
        self.assertEquals('', sys.stderr.getvalue())
 
150
 
 
151
    def test_terminal_cp_unknown(self):
 
152
        # test against really unknown encoding
 
153
        # catch warning at stderr
 
154
        self.make_wrapped_streams('cp-unknown',
 
155
                                  'cp-unknown',
 
156
                                  'cp-unknown',
 
157
                                  user_encoding='latin-1',
 
158
                                  enable_fake_encodings=False)
 
159
 
 
160
        self.assertEqual('latin-1', osutils.get_terminal_encoding())
 
161
 
 
162
        # check stderr
 
163
        self.assertEquals('bzr: warning: unknown terminal encoding cp-unknown.\n'
 
164
                          '  Using encoding latin-1 instead.\n',
 
165
                          sys.stderr.getvalue())
 
166
 
 
167
 
 
168
class TestUserEncoding(TestCase):
 
169
    """Test detection of default user encoding."""
 
170
 
 
171
    def setUp(self):
 
172
        TestCase.setUp(self)
 
173
        self.overrideAttr(locale, 'getpreferredencoding')
 
174
        self.overrideAttr(sys, 'stderr', StringIOWrapper())
 
175
 
 
176
    def test_get_user_encoding(self):
 
177
        def f():
 
178
            return 'user_encoding'
 
179
 
 
180
        locale.getpreferredencoding = f
 
181
        fake_codec.add('user_encoding')
 
182
        self.assertEquals('user_encoding',
 
183
                          osutils.get_user_encoding(use_cache=False))
 
184
        self.assertEquals('', sys.stderr.getvalue())
 
185
 
 
186
    def test_user_cp0(self):
 
187
        def f():
 
188
            return 'cp0'
 
189
 
 
190
        locale.getpreferredencoding = f
 
191
        self.assertEquals('ascii', osutils.get_user_encoding(use_cache=False))
 
192
        self.assertEquals('', sys.stderr.getvalue())
 
193
 
 
194
    def test_user_cp_unknown(self):
 
195
        def f():
 
196
            return 'cp-unknown'
 
197
 
 
198
        locale.getpreferredencoding = f
 
199
        self.assertEquals('ascii', osutils.get_user_encoding(use_cache=False))
 
200
        self.assertEquals('bzr: warning: unknown encoding cp-unknown.'
 
201
                          ' Continuing with ascii encoding.\n',
 
202
                          sys.stderr.getvalue())
 
203
 
 
204
    def test_user_empty(self):
 
205
        """Running bzr from a vim script gives '' for a preferred locale"""
 
206
        def f():
 
207
            return ''
 
208
 
 
209
        locale.getpreferredencoding = f
 
210
        self.assertEquals('ascii', osutils.get_user_encoding(use_cache=False))
 
211
        self.assertEquals('', sys.stderr.getvalue())
 
212
 
 
213
    def test_user_locale_error(self):
 
214
        def f():
 
215
            raise locale.Error, 'unsupported locale'
 
216
 
 
217
        locale.getpreferredencoding = f
 
218
        self.overrideEnv('LANG', 'BOGUS')
 
219
        self.assertEquals('ascii', osutils.get_user_encoding(use_cache=False))
 
220
        self.assertEquals('bzr: warning: unsupported locale\n'
 
221
                          '  Could not determine what text encoding to use.\n'
 
222
                          '  This error usually means your Python interpreter\n'
 
223
                          '  doesn\'t support the locale set by $LANG (BOGUS)\n'
 
224
                          '  Continuing with ascii encoding.\n',
 
225
                          sys.stderr.getvalue())
 
226
 
 
227
 
 
228
class TestMessageEncoding(TestCase):
 
229
    """Tests for getting the encoding used by system messages"""
 
230
 
 
231
    def test_get_message_encoding(self):
 
232
        encoding_name = osutils.get_message_encoding()
 
233
        "".decode(encoding_name) # should be a valid encoding name
 
234
 
 
235
    def test_get_message_encoding_decodes_strerror(self):
 
236
        encoding_name = osutils.get_message_encoding()
 
237
        for number, name in errno.errorcode.iteritems():
 
238
            string = os.strerror(number)
 
239
            string.decode(encoding_name)