1"Test posix functions"
2
3from test import test_support
4
5# Skip these tests if there is no posix module.
6posix = test_support.import_module('posix')
7
8import errno
9import sys
10import time
11import os
12import platform
13import pwd
14import shutil
15import stat
16import sys
17import tempfile
18import unittest
19import warnings
20
21_DUMMY_SYMLINK = os.path.join(tempfile.gettempdir(),
22                              test_support.TESTFN + '-dummy-symlink')
23
24warnings.filterwarnings('ignore', '.* potential security risk .*',
25                        RuntimeWarning)
26
27class PosixTester(unittest.TestCase):
28
29    def setUp(self):
30        # create empty file
31        fp = open(test_support.TESTFN, 'w+')
32        fp.close()
33        self.teardown_files = [ test_support.TESTFN ]
34
35    def tearDown(self):
36        for teardown_file in self.teardown_files:
37            os.unlink(teardown_file)
38
39    def testNoArgFunctions(self):
40        # test posix functions which take no arguments and have
41        # no side-effects which we need to cleanup (e.g., fork, wait, abort)
42        NO_ARG_FUNCTIONS = [ "ctermid", "getcwd", "getcwdu", "uname",
43                             "times", "getloadavg", "tmpnam",
44                             "getegid", "geteuid", "getgid", "getgroups",
45                             "getpid", "getpgrp", "getppid", "getuid",
46                           ]
47
48        with warnings.catch_warnings():
49            warnings.filterwarnings("ignore", "", DeprecationWarning)
50            for name in NO_ARG_FUNCTIONS:
51                posix_func = getattr(posix, name, None)
52                if posix_func is not None:
53                    posix_func()
54                    self.assertRaises(TypeError, posix_func, 1)
55
56    @unittest.skipUnless(hasattr(posix, 'getresuid'),
57                         'test needs posix.getresuid()')
58    def test_getresuid(self):
59        user_ids = posix.getresuid()
60        self.assertEqual(len(user_ids), 3)
61        for val in user_ids:
62            self.assertGreaterEqual(val, 0)
63
64    @unittest.skipUnless(hasattr(posix, 'getresgid'),
65                         'test needs posix.getresgid()')
66    def test_getresgid(self):
67        group_ids = posix.getresgid()
68        self.assertEqual(len(group_ids), 3)
69        for val in group_ids:
70            self.assertGreaterEqual(val, 0)
71
72    @unittest.skipUnless(hasattr(posix, 'setresuid'),
73                         'test needs posix.setresuid()')
74    def test_setresuid(self):
75        current_user_ids = posix.getresuid()
76        self.assertIsNone(posix.setresuid(*current_user_ids))
77        # -1 means don't change that value.
78        self.assertIsNone(posix.setresuid(-1, -1, -1))
79
80    @unittest.skipUnless(hasattr(posix, 'setresuid'),
81                         'test needs posix.setresuid()')
82    def test_setresuid_exception(self):
83        # Don't do this test if someone is silly enough to run us as root.
84        current_user_ids = posix.getresuid()
85        if 0 not in current_user_ids:
86            new_user_ids = (current_user_ids[0]+1, -1, -1)
87            self.assertRaises(OSError, posix.setresuid, *new_user_ids)
88
89    @unittest.skipUnless(hasattr(posix, 'setresgid'),
90                         'test needs posix.setresgid()')
91    def test_setresgid(self):
92        current_group_ids = posix.getresgid()
93        self.assertIsNone(posix.setresgid(*current_group_ids))
94        # -1 means don't change that value.
95        self.assertIsNone(posix.setresgid(-1, -1, -1))
96
97    @unittest.skipUnless(hasattr(posix, 'setresgid'),
98                         'test needs posix.setresgid()')
99    def test_setresgid_exception(self):
100        # Don't do this test if someone is silly enough to run us as root.
101        current_group_ids = posix.getresgid()
102        if 0 not in current_group_ids:
103            new_group_ids = (current_group_ids[0]+1, -1, -1)
104            self.assertRaises(OSError, posix.setresgid, *new_group_ids)
105
106    @unittest.skipUnless(hasattr(posix, 'initgroups'),
107                         "test needs os.initgroups()")
108    def test_initgroups(self):
109        # It takes a string and an integer; check that it raises a TypeError
110        # for other argument lists.
111        self.assertRaises(TypeError, posix.initgroups)
112        self.assertRaises(TypeError, posix.initgroups, None)
113        self.assertRaises(TypeError, posix.initgroups, 3, "foo")
114        self.assertRaises(TypeError, posix.initgroups, "foo", 3, object())
115
116        # If a non-privileged user invokes it, it should fail with OSError
117        # EPERM.
118        if os.getuid() != 0:
119            try:
120                name = pwd.getpwuid(posix.getuid()).pw_name
121            except KeyError:
122                # the current UID may not have a pwd entry
123                raise unittest.SkipTest("need a pwd entry")
124            try:
125                posix.initgroups(name, 13)
126            except OSError as e:
127                self.assertEqual(e.errno, errno.EPERM)
128            else:
129                self.fail("Expected OSError to be raised by initgroups")
130
131    @unittest.skipUnless(hasattr(posix, 'statvfs'),
132                         'test needs posix.statvfs()')
133    def test_statvfs(self):
134        self.assertTrue(posix.statvfs(os.curdir))
135
136    @unittest.skipUnless(hasattr(posix, 'fstatvfs'),
137                         'test needs posix.fstatvfs()')
138    def test_fstatvfs(self):
139        fp = open(test_support.TESTFN)
140        try:
141            self.assertTrue(posix.fstatvfs(fp.fileno()))
142        finally:
143            fp.close()
144
145    @unittest.skipUnless(hasattr(posix, 'ftruncate'),
146                         'test needs posix.ftruncate()')
147    def test_ftruncate(self):
148        fp = open(test_support.TESTFN, 'w+')
149        try:
150            # we need to have some data to truncate
151            fp.write('test')
152            fp.flush()
153            posix.ftruncate(fp.fileno(), 0)
154        finally:
155            fp.close()
156
157    @unittest.skipUnless(hasattr(posix, 'dup'),
158                         'test needs posix.dup()')
159    def test_dup(self):
160        fp = open(test_support.TESTFN)
161        try:
162            fd = posix.dup(fp.fileno())
163            self.assertIsInstance(fd, int)
164            os.close(fd)
165        finally:
166            fp.close()
167
168    @unittest.skipUnless(hasattr(posix, 'confstr'),
169                         'test needs posix.confstr()')
170    def test_confstr(self):
171        self.assertRaises(ValueError, posix.confstr, "CS_garbage")
172        self.assertEqual(len(posix.confstr("CS_PATH")) > 0, True)
173
174    @unittest.skipUnless(hasattr(posix, 'dup2'),
175                         'test needs posix.dup2()')
176    def test_dup2(self):
177        fp1 = open(test_support.TESTFN)
178        fp2 = open(test_support.TESTFN)
179        try:
180            posix.dup2(fp1.fileno(), fp2.fileno())
181        finally:
182            fp1.close()
183            fp2.close()
184
185    def fdopen_helper(self, *args):
186        fd = os.open(test_support.TESTFN, os.O_RDONLY)
187        fp2 = posix.fdopen(fd, *args)
188        fp2.close()
189
190    @unittest.skipUnless(hasattr(posix, 'fdopen'),
191                         'test needs posix.fdopen()')
192    def test_fdopen(self):
193        self.fdopen_helper()
194        self.fdopen_helper('r')
195        self.fdopen_helper('r', 100)
196
197    @unittest.skipUnless(hasattr(posix, 'fdopen'),
198                         'test needs posix.fdopen()')
199    def test_fdopen_directory(self):
200        try:
201            fd = os.open('.', os.O_RDONLY)
202        except OSError as e:
203            self.assertEqual(e.errno, errno.EACCES)
204            self.skipTest("system cannot open directories")
205        with self.assertRaises(IOError) as cm:
206            os.fdopen(fd, 'r')
207        self.assertEqual(cm.exception.errno, errno.EISDIR)
208
209    @unittest.skipUnless(hasattr(posix, 'fdopen') and
210                         not sys.platform.startswith("sunos"),
211                         'test needs posix.fdopen()')
212    def test_fdopen_keeps_fd_open_on_errors(self):
213        fd = os.open(test_support.TESTFN, os.O_RDONLY)
214        self.assertRaises(OSError, posix.fdopen, fd, 'w')
215        os.close(fd) # fd should not be closed.
216
217    @unittest.skipUnless(hasattr(posix, 'O_EXLOCK'),
218                         'test needs posix.O_EXLOCK')
219    def test_osexlock(self):
220        fd = os.open(test_support.TESTFN,
221                     os.O_WRONLY|os.O_EXLOCK|os.O_CREAT)
222        self.assertRaises(OSError, os.open, test_support.TESTFN,
223                          os.O_WRONLY|os.O_EXLOCK|os.O_NONBLOCK)
224        os.close(fd)
225
226        if hasattr(posix, "O_SHLOCK"):
227            fd = os.open(test_support.TESTFN,
228                         os.O_WRONLY|os.O_SHLOCK|os.O_CREAT)
229            self.assertRaises(OSError, os.open, test_support.TESTFN,
230                              os.O_WRONLY|os.O_EXLOCK|os.O_NONBLOCK)
231            os.close(fd)
232
233    @unittest.skipUnless(hasattr(posix, 'O_SHLOCK'),
234                         'test needs posix.O_SHLOCK')
235    def test_osshlock(self):
236        fd1 = os.open(test_support.TESTFN,
237                      os.O_WRONLY|os.O_SHLOCK|os.O_CREAT)
238        fd2 = os.open(test_support.TESTFN,
239                      os.O_WRONLY|os.O_SHLOCK|os.O_CREAT)
240        os.close(fd2)
241        os.close(fd1)
242
243        if hasattr(posix, "O_EXLOCK"):
244            fd = os.open(test_support.TESTFN,
245                         os.O_WRONLY|os.O_SHLOCK|os.O_CREAT)
246            self.assertRaises(OSError, os.open, test_support.TESTFN,
247                              os.O_RDONLY|os.O_EXLOCK|os.O_NONBLOCK)
248            os.close(fd)
249
250    @unittest.skipUnless(hasattr(posix, 'fstat'),
251                         'test needs posix.fstat()')
252    def test_fstat(self):
253        fp = open(test_support.TESTFN)
254        try:
255            self.assertTrue(posix.fstat(fp.fileno()))
256        finally:
257            fp.close()
258
259    @unittest.skipUnless(hasattr(posix, 'stat'),
260                         'test needs posix.stat()')
261    def test_stat(self):
262        self.assertTrue(posix.stat(test_support.TESTFN))
263
264    @unittest.skipUnless(hasattr(posix, 'stat'), 'test needs posix.stat()')
265    @unittest.skipUnless(hasattr(posix, 'makedev'), 'test needs posix.makedev()')
266    def test_makedev(self):
267        st = posix.stat(test_support.TESTFN)
268        dev = st.st_dev
269        self.assertIsInstance(dev, (int, long))
270        self.assertGreaterEqual(dev, 0)
271
272        major = posix.major(dev)
273        self.assertIsInstance(major, (int, long))
274        self.assertGreaterEqual(major, 0)
275        self.assertEqual(posix.major(int(dev)), major)
276        self.assertEqual(posix.major(long(dev)), major)
277        self.assertRaises(TypeError, posix.major, float(dev))
278        self.assertRaises(TypeError, posix.major)
279        self.assertRaises((ValueError, OverflowError), posix.major, -1)
280
281        minor = posix.minor(dev)
282        self.assertIsInstance(minor, (int, long))
283        self.assertGreaterEqual(minor, 0)
284        self.assertEqual(posix.minor(int(dev)), minor)
285        self.assertEqual(posix.minor(long(dev)), minor)
286        self.assertRaises(TypeError, posix.minor, float(dev))
287        self.assertRaises(TypeError, posix.minor)
288        self.assertRaises((ValueError, OverflowError), posix.minor, -1)
289
290        self.assertEqual(posix.makedev(major, minor), dev)
291        self.assertEqual(posix.makedev(int(major), int(minor)), dev)
292        self.assertEqual(posix.makedev(long(major), long(minor)), dev)
293        self.assertRaises(TypeError, posix.makedev, float(major), minor)
294        self.assertRaises(TypeError, posix.makedev, major, float(minor))
295        self.assertRaises(TypeError, posix.makedev, major)
296        self.assertRaises(TypeError, posix.makedev)
297
298    def _test_all_chown_common(self, chown_func, first_param, stat_func):
299        """Common code for chown, fchown and lchown tests."""
300        def check_stat(uid, gid):
301            if stat_func is not None:
302                stat = stat_func(first_param)
303                self.assertEqual(stat.st_uid, uid)
304                self.assertEqual(stat.st_gid, gid)
305        uid = os.getuid()
306        gid = os.getgid()
307        # test a successful chown call
308        chown_func(first_param, uid, gid)
309        check_stat(uid, gid)
310        chown_func(first_param, -1, gid)
311        check_stat(uid, gid)
312        chown_func(first_param, uid, -1)
313        check_stat(uid, gid)
314
315        if uid == 0:
316            # Try an amusingly large uid/gid to make sure we handle
317            # large unsigned values.  (chown lets you use any
318            # uid/gid you like, even if they aren't defined.)
319            #
320            # This problem keeps coming up:
321            #   http://bugs.python.org/issue1747858
322            #   http://bugs.python.org/issue4591
323            #   http://bugs.python.org/issue15301
324            # Hopefully the fix in 4591 fixes it for good!
325            #
326            # This part of the test only runs when run as root.
327            # Only scary people run their tests as root.
328
329            big_value = 2**31
330            chown_func(first_param, big_value, big_value)
331            check_stat(big_value, big_value)
332            chown_func(first_param, -1, -1)
333            check_stat(big_value, big_value)
334            chown_func(first_param, uid, gid)
335            check_stat(uid, gid)
336        elif platform.system() in ('HP-UX', 'SunOS'):
337            # HP-UX and Solaris can allow a non-root user to chown() to root
338            # (issue #5113)
339            raise unittest.SkipTest("Skipping because of non-standard chown() "
340                                    "behavior")
341        else:
342            # non-root cannot chown to root, raises OSError
343            self.assertRaises(OSError, chown_func, first_param, 0, 0)
344            check_stat(uid, gid)
345            self.assertRaises(OSError, chown_func, first_param, 0, -1)
346            check_stat(uid, gid)
347            if 0 not in os.getgroups():
348                self.assertRaises(OSError, chown_func, first_param, -1, 0)
349                check_stat(uid, gid)
350        # test illegal types
351        for t in str, float:
352            self.assertRaises(TypeError, chown_func, first_param, t(uid), gid)
353            check_stat(uid, gid)
354            self.assertRaises(TypeError, chown_func, first_param, uid, t(gid))
355            check_stat(uid, gid)
356
357    @unittest.skipUnless(hasattr(posix, 'chown'), "test needs os.chown()")
358    def test_chown(self):
359        # raise an OSError if the file does not exist
360        os.unlink(test_support.TESTFN)
361        self.assertRaises(OSError, posix.chown, test_support.TESTFN, -1, -1)
362
363        # re-create the file
364        open(test_support.TESTFN, 'w').close()
365        self._test_all_chown_common(posix.chown, test_support.TESTFN,
366                                    getattr(posix, 'stat', None))
367
368    @unittest.skipUnless(hasattr(posix, 'fchown'), "test needs os.fchown()")
369    def test_fchown(self):
370        os.unlink(test_support.TESTFN)
371
372        # re-create the file
373        test_file = open(test_support.TESTFN, 'w')
374        try:
375            fd = test_file.fileno()
376            self._test_all_chown_common(posix.fchown, fd,
377                                        getattr(posix, 'fstat', None))
378        finally:
379            test_file.close()
380
381    @unittest.skipUnless(hasattr(posix, 'lchown'), "test needs os.lchown()")
382    def test_lchown(self):
383        os.unlink(test_support.TESTFN)
384        # create a symlink
385        os.symlink(_DUMMY_SYMLINK, test_support.TESTFN)
386        self._test_all_chown_common(posix.lchown, test_support.TESTFN,
387                                    getattr(posix, 'lstat', None))
388
389    @unittest.skipUnless(hasattr(posix, 'chdir'), 'test needs posix.chdir()')
390    def test_chdir(self):
391        posix.chdir(os.curdir)
392        self.assertRaises(OSError, posix.chdir, test_support.TESTFN)
393
394    @unittest.skipUnless(hasattr(posix, 'lsdir'), 'test needs posix.lsdir()')
395    def test_lsdir(self):
396        self.assertIn(test_support.TESTFN, posix.lsdir(os.curdir))
397
398    @unittest.skipUnless(hasattr(posix, 'access'), 'test needs posix.access()')
399    def test_access(self):
400        self.assertTrue(posix.access(test_support.TESTFN, os.R_OK))
401
402    @unittest.skipUnless(hasattr(posix, 'umask'), 'test needs posix.umask()')
403    def test_umask(self):
404        old_mask = posix.umask(0)
405        self.assertIsInstance(old_mask, int)
406        posix.umask(old_mask)
407
408    @unittest.skipUnless(hasattr(posix, 'strerror'),
409                         'test needs posix.strerror()')
410    def test_strerror(self):
411        self.assertTrue(posix.strerror(0))
412
413    @unittest.skipUnless(hasattr(posix, 'pipe'), 'test needs posix.pipe()')
414    def test_pipe(self):
415        reader, writer = posix.pipe()
416        os.close(reader)
417        os.close(writer)
418
419    @unittest.skipUnless(hasattr(posix, 'tempnam'),
420                         'test needs posix.tempnam()')
421    def test_tempnam(self):
422        with warnings.catch_warnings():
423            warnings.filterwarnings("ignore", "tempnam", DeprecationWarning)
424            self.assertTrue(posix.tempnam())
425            self.assertTrue(posix.tempnam(os.curdir))
426            self.assertTrue(posix.tempnam(os.curdir, 'blah'))
427
428    @unittest.skipUnless(hasattr(posix, 'tmpfile'),
429                         'test needs posix.tmpfile()')
430    def test_tmpfile(self):
431        with warnings.catch_warnings():
432            warnings.filterwarnings("ignore", "tmpfile", DeprecationWarning)
433            fp = posix.tmpfile()
434            fp.close()
435
436    @unittest.skipUnless(hasattr(posix, 'utime'), 'test needs posix.utime()')
437    def test_utime(self):
438        now = time.time()
439        posix.utime(test_support.TESTFN, None)
440        self.assertRaises(TypeError, posix.utime, test_support.TESTFN, (None, None))
441        self.assertRaises(TypeError, posix.utime, test_support.TESTFN, (now, None))
442        self.assertRaises(TypeError, posix.utime, test_support.TESTFN, (None, now))
443        posix.utime(test_support.TESTFN, (int(now), int(now)))
444        posix.utime(test_support.TESTFN, (now, now))
445
446    def _test_chflags_regular_file(self, chflags_func, target_file):
447        st = os.stat(target_file)
448        self.assertTrue(hasattr(st, 'st_flags'))
449
450        # ZFS returns EOPNOTSUPP when attempting to set flag UF_IMMUTABLE.
451        try:
452            chflags_func(target_file, st.st_flags | stat.UF_IMMUTABLE)
453        except OSError as err:
454            if err.errno != errno.EOPNOTSUPP:
455                raise
456            msg = 'chflag UF_IMMUTABLE not supported by underlying fs'
457            self.skipTest(msg)
458
459        try:
460            new_st = os.stat(target_file)
461            self.assertEqual(st.st_flags | stat.UF_IMMUTABLE, new_st.st_flags)
462            try:
463                fd = open(target_file, 'w+')
464            except IOError as e:
465                self.assertEqual(e.errno, errno.EPERM)
466        finally:
467            posix.chflags(target_file, st.st_flags)
468
469    @unittest.skipUnless(hasattr(posix, 'chflags'), 'test needs os.chflags()')
470    def test_chflags(self):
471        self._test_chflags_regular_file(posix.chflags, test_support.TESTFN)
472
473    @unittest.skipUnless(hasattr(posix, 'lchflags'), 'test needs os.lchflags()')
474    def test_lchflags_regular_file(self):
475        self._test_chflags_regular_file(posix.lchflags, test_support.TESTFN)
476
477    @unittest.skipUnless(hasattr(posix, 'lchflags'), 'test needs os.lchflags()')
478    def test_lchflags_symlink(self):
479        testfn_st = os.stat(test_support.TESTFN)
480
481        self.assertTrue(hasattr(testfn_st, 'st_flags'))
482
483        os.symlink(test_support.TESTFN, _DUMMY_SYMLINK)
484        self.teardown_files.append(_DUMMY_SYMLINK)
485        dummy_symlink_st = os.lstat(_DUMMY_SYMLINK)
486
487        # ZFS returns EOPNOTSUPP when attempting to set flag UF_IMMUTABLE.
488        try:
489            posix.lchflags(_DUMMY_SYMLINK,
490                           dummy_symlink_st.st_flags | stat.UF_IMMUTABLE)
491        except OSError as err:
492            if err.errno != errno.EOPNOTSUPP:
493                raise
494            msg = 'chflag UF_IMMUTABLE not supported by underlying fs'
495            self.skipTest(msg)
496
497        try:
498            new_testfn_st = os.stat(test_support.TESTFN)
499            new_dummy_symlink_st = os.lstat(_DUMMY_SYMLINK)
500
501            self.assertEqual(testfn_st.st_flags, new_testfn_st.st_flags)
502            self.assertEqual(dummy_symlink_st.st_flags | stat.UF_IMMUTABLE,
503                             new_dummy_symlink_st.st_flags)
504        finally:
505            posix.lchflags(_DUMMY_SYMLINK, dummy_symlink_st.st_flags)
506
507    @unittest.skipUnless(hasattr(posix, 'getcwd'),
508                         'test needs posix.getcwd()')
509    def test_getcwd_long_pathnames(self):
510        dirname = 'getcwd-test-directory-0123456789abcdef-01234567890abcdef'
511        curdir = os.getcwd()
512        base_path = os.path.abspath(test_support.TESTFN) + '.getcwd'
513
514        try:
515            os.mkdir(base_path)
516            os.chdir(base_path)
517        except:
518            self.skipTest("cannot create directory for testing")
519
520        try:
521            def _create_and_do_getcwd(dirname, current_path_length = 0):
522                try:
523                    os.mkdir(dirname)
524                except:
525                    self.skipTest("mkdir cannot create directory sufficiently "
526                                  "deep for getcwd test")
527
528                os.chdir(dirname)
529                try:
530                    os.getcwd()
531                    if current_path_length < 4099:
532                        _create_and_do_getcwd(dirname, current_path_length + len(dirname) + 1)
533                except OSError as e:
534                    expected_errno = errno.ENAMETOOLONG
535                    # The following platforms have quirky getcwd()
536                    # behaviour -- see issue 9185 and 15765 for
537                    # more information.
538                    quirky_platform = (
539                        'sunos' in sys.platform or
540                        'netbsd' in sys.platform or
541                        'openbsd' in sys.platform
542                    )
543                    if quirky_platform:
544                        expected_errno = errno.ERANGE
545                    self.assertEqual(e.errno, expected_errno)
546                finally:
547                    os.chdir('..')
548                    os.rmdir(dirname)
549
550            _create_and_do_getcwd(dirname)
551
552        finally:
553            os.chdir(curdir)
554            shutil.rmtree(base_path)
555
556    @unittest.skipUnless(hasattr(os, 'getegid'), "test needs os.getegid()")
557    def test_getgroups(self):
558        with os.popen('id -G 2>/dev/null') as idg:
559            groups = idg.read().strip()
560            ret = idg.close()
561
562        if ret != None or not groups:
563            raise unittest.SkipTest("need working 'id -G'")
564
565        # Issues 16698: OS X ABIs prior to 10.6 have limits on getgroups()
566        if sys.platform == 'darwin':
567            import sysconfig
568            dt = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') or '10.0'
569            if tuple(int(n) for n in dt.split('.')[0:2]) < (10, 6):
570                raise unittest.SkipTest("getgroups(2) is broken prior to 10.6")
571
572        # 'id -G' and 'os.getgroups()' should return the same
573        # groups, ignoring order and duplicates.
574        # #10822 - it is implementation defined whether posix.getgroups()
575        # includes the effective gid so we include it anyway, since id -G does
576        self.assertEqual(
577                set([int(x) for x in groups.split()]),
578                set(posix.getgroups() + [posix.getegid()]))
579
580    @test_support.requires_unicode
581    def test_path_with_null_unicode(self):
582        fn = test_support.TESTFN_UNICODE
583        try:
584            fn.encode(test_support.TESTFN_ENCODING)
585        except (UnicodeError, TypeError):
586            self.skipTest("Requires unicode filenames support")
587        fn_with_NUL = fn + u'\0'
588        self.addCleanup(test_support.unlink, fn)
589        test_support.unlink(fn)
590        fd = None
591        try:
592            with self.assertRaises(TypeError):
593                fd = os.open(fn_with_NUL, os.O_WRONLY | os.O_CREAT) # raises
594        finally:
595            if fd is not None:
596                os.close(fd)
597        self.assertFalse(os.path.exists(fn))
598        self.assertRaises(TypeError, os.mkdir, fn_with_NUL)
599        self.assertFalse(os.path.exists(fn))
600        open(fn, 'wb').close()
601        self.assertRaises(TypeError, os.stat, fn_with_NUL)
602
603    def test_path_with_null_byte(self):
604        fn = test_support.TESTFN
605        fn_with_NUL = fn + '\0'
606        self.addCleanup(test_support.unlink, fn)
607        test_support.unlink(fn)
608        fd = None
609        try:
610            with self.assertRaises(TypeError):
611                fd = os.open(fn_with_NUL, os.O_WRONLY | os.O_CREAT) # raises
612        finally:
613            if fd is not None:
614                os.close(fd)
615        self.assertFalse(os.path.exists(fn))
616        self.assertRaises(TypeError, os.mkdir, fn_with_NUL)
617        self.assertFalse(os.path.exists(fn))
618        open(fn, 'wb').close()
619        self.assertRaises(TypeError, os.stat, fn_with_NUL)
620
621
622class PosixGroupsTester(unittest.TestCase):
623
624    def setUp(self):
625        if posix.getuid() != 0:
626            raise unittest.SkipTest("not enough privileges")
627        if not hasattr(posix, 'getgroups'):
628            raise unittest.SkipTest("need posix.getgroups")
629        if sys.platform == 'darwin':
630            raise unittest.SkipTest("getgroups(2) is broken on OSX")
631        self.saved_groups = posix.getgroups()
632
633    def tearDown(self):
634        if hasattr(posix, 'setgroups'):
635            posix.setgroups(self.saved_groups)
636        elif hasattr(posix, 'initgroups'):
637            name = pwd.getpwuid(posix.getuid()).pw_name
638            posix.initgroups(name, self.saved_groups[0])
639
640    @unittest.skipUnless(hasattr(posix, 'initgroups'),
641                         'test needs posix.initgroups()')
642    def test_initgroups(self):
643        # find missing group
644
645        g = max(self.saved_groups or [0]) + 1
646        name = pwd.getpwuid(posix.getuid()).pw_name
647        posix.initgroups(name, g)
648        self.assertIn(g, posix.getgroups())
649
650    @unittest.skipUnless(hasattr(posix, 'setgroups'),
651                         'test needs posix.setgroups()')
652    def test_setgroups(self):
653        for groups in [[0], range(16)]:
654            posix.setgroups(groups)
655            self.assertListEqual(groups, posix.getgroups())
656
657
658def test_main():
659    test_support.run_unittest(PosixTester, PosixGroupsTester)
660
661if __name__ == '__main__':
662    test_main()
663