1"""Tests for distutils.util."""
2import os
3import sys
4import unittest
5from copy import copy
6from test.support import run_unittest
7from unittest import mock
8
9from distutils.errors import DistutilsPlatformError, DistutilsByteCompileError
10from distutils.util import (get_platform, convert_path, change_root,
11                            check_environ, split_quoted, strtobool,
12                            rfc822_escape, byte_compile,
13                            grok_environment_error)
14from distutils import util # used to patch _environ_checked
15from distutils.sysconfig import get_config_vars
16from distutils import sysconfig
17from distutils.tests import support
18import _osx_support
19
20class UtilTestCase(support.EnvironGuard, unittest.TestCase):
21
22    def setUp(self):
23        super(UtilTestCase, self).setUp()
24        # saving the environment
25        self.name = os.name
26        self.platform = sys.platform
27        self.version = sys.version
28        self.sep = os.sep
29        self.join = os.path.join
30        self.isabs = os.path.isabs
31        self.splitdrive = os.path.splitdrive
32        self._config_vars = copy(sysconfig._config_vars)
33
34        # patching os.uname
35        if hasattr(os, 'uname'):
36            self.uname = os.uname
37            self._uname = os.uname()
38        else:
39            self.uname = None
40            self._uname = None
41
42        os.uname = self._get_uname
43
44    def tearDown(self):
45        # getting back the environment
46        os.name = self.name
47        sys.platform = self.platform
48        sys.version = self.version
49        os.sep = self.sep
50        os.path.join = self.join
51        os.path.isabs = self.isabs
52        os.path.splitdrive = self.splitdrive
53        if self.uname is not None:
54            os.uname = self.uname
55        else:
56            del os.uname
57        sysconfig._config_vars = copy(self._config_vars)
58        super(UtilTestCase, self).tearDown()
59
60    def _set_uname(self, uname):
61        self._uname = uname
62
63    def _get_uname(self):
64        return self._uname
65
66    def test_get_platform(self):
67
68        # windows XP, 32bits
69        os.name = 'nt'
70        sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) '
71                       '[MSC v.1310 32 bit (Intel)]')
72        sys.platform = 'win32'
73        self.assertEqual(get_platform(), 'win32')
74
75        # windows XP, amd64
76        os.name = 'nt'
77        sys.version = ('2.4.4 (#71, Oct 18 2006, 08:34:43) '
78                       '[MSC v.1310 32 bit (Amd64)]')
79        sys.platform = 'win32'
80        self.assertEqual(get_platform(), 'win-amd64')
81
82        # macbook
83        os.name = 'posix'
84        sys.version = ('2.5 (r25:51918, Sep 19 2006, 08:49:13) '
85                       '\n[GCC 4.0.1 (Apple Computer, Inc. build 5341)]')
86        sys.platform = 'darwin'
87        self._set_uname(('Darwin', 'macziade', '8.11.1',
88                   ('Darwin Kernel Version 8.11.1: '
89                    'Wed Oct 10 18:23:28 PDT 2007; '
90                    'root:xnu-792.25.20~1/RELEASE_I386'), 'i386'))
91        _osx_support._remove_original_values(get_config_vars())
92        get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.3'
93
94        get_config_vars()['CFLAGS'] = ('-fno-strict-aliasing -DNDEBUG -g '
95                                       '-fwrapv -O3 -Wall -Wstrict-prototypes')
96
97        cursize = sys.maxsize
98        sys.maxsize = (2 ** 31)-1
99        try:
100            self.assertEqual(get_platform(), 'macosx-10.3-i386')
101        finally:
102            sys.maxsize = cursize
103
104        # macbook with fat binaries (fat, universal or fat64)
105        _osx_support._remove_original_values(get_config_vars())
106        get_config_vars()['MACOSX_DEPLOYMENT_TARGET'] = '10.4'
107        get_config_vars()['CFLAGS'] = ('-arch ppc -arch i386 -isysroot '
108                                       '/Developer/SDKs/MacOSX10.4u.sdk  '
109                                       '-fno-strict-aliasing -fno-common '
110                                       '-dynamic -DNDEBUG -g -O3')
111
112        self.assertEqual(get_platform(), 'macosx-10.4-fat')
113
114        _osx_support._remove_original_values(get_config_vars())
115        os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.1'
116        self.assertEqual(get_platform(), 'macosx-10.4-fat')
117
118
119        _osx_support._remove_original_values(get_config_vars())
120        get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch i386 -isysroot '
121                                       '/Developer/SDKs/MacOSX10.4u.sdk  '
122                                       '-fno-strict-aliasing -fno-common '
123                                       '-dynamic -DNDEBUG -g -O3')
124
125        self.assertEqual(get_platform(), 'macosx-10.4-intel')
126
127        _osx_support._remove_original_values(get_config_vars())
128        get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc -arch i386 -isysroot '
129                                       '/Developer/SDKs/MacOSX10.4u.sdk  '
130                                       '-fno-strict-aliasing -fno-common '
131                                       '-dynamic -DNDEBUG -g -O3')
132        self.assertEqual(get_platform(), 'macosx-10.4-fat3')
133
134        _osx_support._remove_original_values(get_config_vars())
135        get_config_vars()['CFLAGS'] = ('-arch ppc64 -arch x86_64 -arch ppc -arch i386 -isysroot '
136                                       '/Developer/SDKs/MacOSX10.4u.sdk  '
137                                       '-fno-strict-aliasing -fno-common '
138                                       '-dynamic -DNDEBUG -g -O3')
139        self.assertEqual(get_platform(), 'macosx-10.4-universal')
140
141        _osx_support._remove_original_values(get_config_vars())
142        get_config_vars()['CFLAGS'] = ('-arch x86_64 -arch ppc64 -isysroot '
143                                       '/Developer/SDKs/MacOSX10.4u.sdk  '
144                                       '-fno-strict-aliasing -fno-common '
145                                       '-dynamic -DNDEBUG -g -O3')
146
147        self.assertEqual(get_platform(), 'macosx-10.4-fat64')
148
149        for arch in ('ppc', 'i386', 'x86_64', 'ppc64'):
150            _osx_support._remove_original_values(get_config_vars())
151            get_config_vars()['CFLAGS'] = ('-arch %s -isysroot '
152                                           '/Developer/SDKs/MacOSX10.4u.sdk  '
153                                           '-fno-strict-aliasing -fno-common '
154                                           '-dynamic -DNDEBUG -g -O3'%(arch,))
155
156            self.assertEqual(get_platform(), 'macosx-10.4-%s'%(arch,))
157
158
159        # linux debian sarge
160        os.name = 'posix'
161        sys.version = ('2.3.5 (#1, Jul  4 2007, 17:28:59) '
162                       '\n[GCC 4.1.2 20061115 (prerelease) (Debian 4.1.1-21)]')
163        sys.platform = 'linux2'
164        self._set_uname(('Linux', 'aglae', '2.6.21.1dedibox-r7',
165                    '#1 Mon Apr 30 17:25:38 CEST 2007', 'i686'))
166
167        self.assertEqual(get_platform(), 'linux-i686')
168
169        # XXX more platforms to tests here
170
171    def test_convert_path(self):
172        # linux/mac
173        os.sep = '/'
174        def _join(path):
175            return '/'.join(path)
176        os.path.join = _join
177
178        self.assertEqual(convert_path('/home/to/my/stuff'),
179                         '/home/to/my/stuff')
180
181        # win
182        os.sep = '\\'
183        def _join(*path):
184            return '\\'.join(path)
185        os.path.join = _join
186
187        self.assertRaises(ValueError, convert_path, '/home/to/my/stuff')
188        self.assertRaises(ValueError, convert_path, 'home/to/my/stuff/')
189
190        self.assertEqual(convert_path('home/to/my/stuff'),
191                         'home\\to\\my\\stuff')
192        self.assertEqual(convert_path('.'),
193                         os.curdir)
194
195    def test_change_root(self):
196        # linux/mac
197        os.name = 'posix'
198        def _isabs(path):
199            return path[0] == '/'
200        os.path.isabs = _isabs
201        def _join(*path):
202            return '/'.join(path)
203        os.path.join = _join
204
205        self.assertEqual(change_root('/root', '/old/its/here'),
206                         '/root/old/its/here')
207        self.assertEqual(change_root('/root', 'its/here'),
208                         '/root/its/here')
209
210        # windows
211        os.name = 'nt'
212        def _isabs(path):
213            return path.startswith('c:\\')
214        os.path.isabs = _isabs
215        def _splitdrive(path):
216            if path.startswith('c:'):
217                return ('', path.replace('c:', ''))
218            return ('', path)
219        os.path.splitdrive = _splitdrive
220        def _join(*path):
221            return '\\'.join(path)
222        os.path.join = _join
223
224        self.assertEqual(change_root('c:\\root', 'c:\\old\\its\\here'),
225                         'c:\\root\\old\\its\\here')
226        self.assertEqual(change_root('c:\\root', 'its\\here'),
227                         'c:\\root\\its\\here')
228
229        # BugsBunny os (it's a great os)
230        os.name = 'BugsBunny'
231        self.assertRaises(DistutilsPlatformError,
232                          change_root, 'c:\\root', 'its\\here')
233
234        # XXX platforms to be covered: mac
235
236    def test_check_environ(self):
237        util._environ_checked = 0
238        os.environ.pop('HOME', None)
239
240        check_environ()
241
242        self.assertEqual(os.environ['PLAT'], get_platform())
243        self.assertEqual(util._environ_checked, 1)
244
245    @unittest.skipUnless(os.name == 'posix', 'specific to posix')
246    def test_check_environ_getpwuid(self):
247        util._environ_checked = 0
248        os.environ.pop('HOME', None)
249
250        import pwd
251
252        # only set pw_dir field, other fields are not used
253        result = pwd.struct_passwd((None, None, None, None, None,
254                                    '/home/distutils', None))
255        with mock.patch.object(pwd, 'getpwuid', return_value=result):
256            check_environ()
257            self.assertEqual(os.environ['HOME'], '/home/distutils')
258
259        util._environ_checked = 0
260        os.environ.pop('HOME', None)
261
262        # bpo-10496: Catch pwd.getpwuid() error
263        with mock.patch.object(pwd, 'getpwuid', side_effect=KeyError):
264            check_environ()
265            self.assertNotIn('HOME', os.environ)
266
267    def test_split_quoted(self):
268        self.assertEqual(split_quoted('""one"" "two" \'three\' \\four'),
269                         ['one', 'two', 'three', 'four'])
270
271    def test_strtobool(self):
272        yes = ('y', 'Y', 'yes', 'True', 't', 'true', 'True', 'On', 'on', '1')
273        no = ('n', 'no', 'f', 'false', 'off', '0', 'Off', 'No', 'N')
274
275        for y in yes:
276            self.assertTrue(strtobool(y))
277
278        for n in no:
279            self.assertFalse(strtobool(n))
280
281    def test_rfc822_escape(self):
282        header = 'I am a\npoor\nlonesome\nheader\n'
283        res = rfc822_escape(header)
284        wanted = ('I am a%(8s)spoor%(8s)slonesome%(8s)s'
285                  'header%(8s)s') % {'8s': '\n'+8*' '}
286        self.assertEqual(res, wanted)
287
288    def test_dont_write_bytecode(self):
289        # makes sure byte_compile raise a DistutilsError
290        # if sys.dont_write_bytecode is True
291        old_dont_write_bytecode = sys.dont_write_bytecode
292        sys.dont_write_bytecode = True
293        try:
294            self.assertRaises(DistutilsByteCompileError, byte_compile, [])
295        finally:
296            sys.dont_write_bytecode = old_dont_write_bytecode
297
298    def test_grok_environment_error(self):
299        # test obsolete function to ensure backward compat (#4931)
300        exc = IOError("Unable to find batch file")
301        msg = grok_environment_error(exc)
302        self.assertEqual(msg, "error: Unable to find batch file")
303
304
305def test_suite():
306    return unittest.makeSuite(UtilTestCase)
307
308if __name__ == "__main__":
309    run_unittest(test_suite())
310