15
15
import time
16
16
import os
17
17
import platform
18
- import pwd
19
18
import stat
20
19
import tempfile
21
20
import unittest
22
21
import warnings
23
22
import textwrap
24
23
from contextlib import contextmanager
25
24
25
+ try :
26
+ import pwd
27
+ except ImportError :
28
+ pwd = None
29
+
26
30
_DUMMY_SYMLINK = os .path .join (tempfile .gettempdir (),
27
31
os_helper .TESTFN + '-dummy-symlink' )
28
32
29
- requires_32b = unittest .skipUnless (sys .maxsize < 2 ** 32 ,
30
- 'test is only meaningful on 32-bit builds' )
33
+ requires_32b = unittest .skipUnless (
34
+ # Emscripten/WASI have 32 bits pointers, but support 64 bits syscall args.
35
+ sys .maxsize < 2 ** 32 and not (support .is_emscripten or support .is_wasi ),
36
+ 'test is only meaningful on 32-bit builds'
37
+ )
31
38
32
39
def _supports_sched ():
33
40
if not hasattr (posix , 'sched_getscheduler' ):
@@ -46,19 +53,13 @@ class PosixTester(unittest.TestCase):
46
53
47
54
def setUp (self ):
48
55
# create empty file
56
+ self .addCleanup (os_helper .unlink , os_helper .TESTFN )
49
57
with open (os_helper .TESTFN , "wb" ):
50
58
pass
51
- self .teardown_files = [ os_helper .TESTFN ]
52
- self ._warnings_manager = warnings_helper .check_warnings ()
53
- self ._warnings_manager .__enter__ ()
59
+ self .enterContext (warnings_helper .check_warnings ())
54
60
warnings .filterwarnings ('ignore' , '.* potential security risk .*' ,
55
61
RuntimeWarning )
56
62
57
- def tearDown (self ):
58
- for teardown_file in self .teardown_files :
59
- os_helper .unlink (teardown_file )
60
- self ._warnings_manager .__exit__ (None , None , None )
61
-
62
63
def testNoArgFunctions (self ):
63
64
# test posix functions which take no arguments and have
64
65
# no side-effects which we need to cleanup (e.g., fork, wait, abort)
@@ -71,8 +72,9 @@ def testNoArgFunctions(self):
71
72
for name in NO_ARG_FUNCTIONS :
72
73
posix_func = getattr (posix , name , None )
73
74
if posix_func is not None :
74
- posix_func ()
75
- self .assertRaises (TypeError , posix_func , 1 )
75
+ with self .subTest (name ):
76
+ posix_func ()
77
+ self .assertRaises (TypeError , posix_func , 1 )
76
78
77
79
@unittest .skipUnless (hasattr (posix , 'getresuid' ),
78
80
'test needs posix.getresuid()' )
@@ -126,6 +128,7 @@ def test_setresgid_exception(self):
126
128
127
129
@unittest .skipUnless (hasattr (posix , 'initgroups' ),
128
130
"test needs os.initgroups()" )
131
+ @unittest .skipUnless (hasattr (pwd , 'getpwuid' ), "test needs pwd.getpwuid()" )
129
132
def test_initgroups (self ):
130
133
# It takes a string and an integer; check that it raises a TypeError
131
134
# for other argument lists.
@@ -184,7 +187,7 @@ def test_truncate(self):
184
187
posix .truncate (os_helper .TESTFN , 0 )
185
188
186
189
@unittest .skipUnless (getattr (os , 'execve' , None ) in os .supports_fd , "test needs execve() to support the fd parameter" )
187
- @unittest . skipUnless ( hasattr ( os , 'fork' ), "test needs os.fork()" )
190
+ @support . requires_fork ( )
188
191
def test_fexecve (self ):
189
192
fp = os .open (sys .executable , os .O_RDONLY )
190
193
try :
@@ -199,7 +202,7 @@ def test_fexecve(self):
199
202
200
203
201
204
@unittest .skipUnless (hasattr (posix , 'waitid' ), "test needs posix.waitid()" )
202
- @unittest . skipUnless ( hasattr ( os , 'fork' ), "test needs os.fork()" )
205
+ @support . requires_fork ( )
203
206
def test_waitid (self ):
204
207
pid = os .fork ()
205
208
if pid == 0 :
@@ -209,7 +212,7 @@ def test_waitid(self):
209
212
res = posix .waitid (posix .P_PID , pid , posix .WEXITED )
210
213
self .assertEqual (pid , res .si_pid )
211
214
212
- @unittest . skipUnless ( hasattr ( os , 'fork' ), "test needs os.fork()" )
215
+ @support . requires_fork ( )
213
216
def test_register_at_fork (self ):
214
217
with self .assertRaises (TypeError , msg = "Positional args not allowed" ):
215
218
os .register_at_fork (lambda : None )
@@ -544,6 +547,7 @@ def test_readv_overflow_32bits(self):
544
547
545
548
@unittest .skipUnless (hasattr (posix , 'dup' ),
546
549
'test needs posix.dup()' )
550
+ @unittest .skipIf (support .is_wasi , "WASI does not have dup()" )
547
551
def test_dup (self ):
548
552
fp = open (os_helper .TESTFN )
549
553
try :
@@ -561,6 +565,7 @@ def test_confstr(self):
561
565
562
566
@unittest .skipUnless (hasattr (posix , 'dup2' ),
563
567
'test needs posix.dup2()' )
568
+ @unittest .skipIf (support .is_wasi , "WASI does not have dup2()" )
564
569
def test_dup2 (self ):
565
570
fp1 = open (os_helper .TESTFN )
566
571
fp2 = open (os_helper .TESTFN )
@@ -572,6 +577,7 @@ def test_dup2(self):
572
577
573
578
@unittest .skipUnless (hasattr (os , 'O_CLOEXEC' ), "needs os.O_CLOEXEC" )
574
579
@support .requires_linux_version (2 , 6 , 23 )
580
+ @support .requires_subprocess ()
575
581
def test_oscloexec (self ):
576
582
fd = os .open (os_helper .TESTFN , os .O_RDONLY | os .O_CLOEXEC )
577
583
self .addCleanup (os .close , fd )
@@ -733,7 +739,11 @@ def check_stat(uid, gid):
733
739
is_root = (uid in (0 , 1 ))
734
740
else :
735
741
is_root = (uid == 0 )
736
- if is_root :
742
+ if support .is_emscripten :
743
+ # Emscripten getuid() / geteuid() always return 0 (root), but
744
+ # cannot chown uid/gid to random value.
745
+ pass
746
+ elif is_root :
737
747
# Try an amusingly large uid/gid to make sure we handle
738
748
# large unsigned values. (chown lets you use any
739
749
# uid/gid you like, even if they aren't defined.)
@@ -778,7 +788,8 @@ def check_stat(uid, gid):
778
788
self .assertRaises (TypeError , chown_func , first_param , uid , t (gid ))
779
789
check_stat (uid , gid )
780
790
781
- @unittest .skipUnless (hasattr (posix , 'chown' ), "test needs os.chown()" )
791
+ @os_helper .skip_unless_working_chmod
792
+ @unittest .skipIf (support .is_emscripten , "getgid() is a stub" )
782
793
def test_chown (self ):
783
794
# raise an OSError if the file does not exist
784
795
os .unlink (os_helper .TESTFN )
@@ -788,7 +799,9 @@ def test_chown(self):
788
799
os_helper .create_empty_file (os_helper .TESTFN )
789
800
self ._test_all_chown_common (posix .chown , os_helper .TESTFN , posix .stat )
790
801
802
+ @os_helper .skip_unless_working_chmod
791
803
@unittest .skipUnless (hasattr (posix , 'fchown' ), "test needs os.fchown()" )
804
+ @unittest .skipIf (support .is_emscripten , "getgid() is a stub" )
792
805
def test_fchown (self ):
793
806
os .unlink (os_helper .TESTFN )
794
807
@@ -801,6 +814,7 @@ def test_fchown(self):
801
814
finally :
802
815
test_file .close ()
803
816
817
+ @os_helper .skip_unless_working_chmod
804
818
@unittest .skipUnless (hasattr (posix , 'lchown' ), "test needs os.lchown()" )
805
819
def test_lchown (self ):
806
820
os .unlink (os_helper .TESTFN )
@@ -963,8 +977,8 @@ def test_lchflags_symlink(self):
963
977
964
978
self .assertTrue (hasattr (testfn_st , 'st_flags' ))
965
979
980
+ self .addCleanup (os_helper .unlink , _DUMMY_SYMLINK )
966
981
os .symlink (os_helper .TESTFN , _DUMMY_SYMLINK )
967
- self .teardown_files .append (_DUMMY_SYMLINK )
968
982
dummy_symlink_st = os .lstat (_DUMMY_SYMLINK )
969
983
970
984
def chflags_nofollow (path , flags ):
@@ -1060,6 +1074,7 @@ def test_getgrouplist(self):
1060
1074
1061
1075
@unittest .skipUnless (hasattr (os , 'getegid' ), "test needs os.getegid()" )
1062
1076
@unittest .skipUnless (hasattr (os , 'popen' ), "test needs os.popen()" )
1077
+ @support .requires_subprocess ()
1063
1078
def test_getgroups (self ):
1064
1079
with os .popen ('id -G 2>/dev/null' ) as idg :
1065
1080
groups = idg .read ().strip ()
@@ -1207,6 +1222,7 @@ def test_sched_setaffinity(self):
1207
1222
# bpo-47205: does not raise OSError on FreeBSD
1208
1223
self .assertRaises (OSError , posix .sched_setaffinity , - 1 , mask )
1209
1224
1225
+ @unittest .skipIf (support .is_wasi , "No dynamic linking on WASI" )
1210
1226
def test_rtld_constants (self ):
1211
1227
# check presence of major RTLD_* constants
1212
1228
posix .RTLD_LAZY
@@ -1346,6 +1362,7 @@ def test_chmod_dir_fd(self):
1346
1362
1347
1363
@unittest .skipUnless (hasattr (os , 'chown' ) and (os .chown in os .supports_dir_fd ),
1348
1364
"test needs dir_fd support in os.chown()" )
1365
+ @unittest .skipIf (support .is_emscripten , "getgid() is a stub" )
1349
1366
def test_chown_dir_fd (self ):
1350
1367
with self .prepare_file () as (dir_fd , name , fullname ):
1351
1368
posix .chown (name , os .getuid (), os .getgid (), dir_fd = dir_fd )
@@ -1401,7 +1418,14 @@ def test_utime_dir_fd(self):
1401
1418
# whoops! using both together not supported on this platform.
1402
1419
pass
1403
1420
1404
- @unittest .skipUnless (os .link in os .supports_dir_fd , "test needs dir_fd support in os.link()" )
1421
+ @unittest .skipIf (
1422
+ support .is_wasi ,
1423
+ "WASI: symlink following on path_link is not supported"
1424
+ )
1425
+ @unittest .skipUnless (
1426
+ hasattr (os , "link" ) and os .link in os .supports_dir_fd ,
1427
+ "test needs dir_fd support in os.link()"
1428
+ )
1405
1429
def test_link_dir_fd (self ):
1406
1430
with self .prepare_file () as (dir_fd , name , fullname ), \
1407
1431
self .prepare () as (dir_fd2 , linkname , fulllinkname ):
@@ -1489,8 +1513,7 @@ def test_unlink_dir_fd(self):
1489
1513
self .addCleanup (posix .unlink , fullname )
1490
1514
raise
1491
1515
1492
- @unittest .skip ("TODO: RUSTPYTHON; no os.mkfifo" )
1493
- # @unittest.skipUnless(os.mkfifo in os.supports_dir_fd, "test needs dir_fd support in os.mkfifo()")
1516
+ @unittest .skipUnless (hasattr (os , 'mkfifo' ) and os .mkfifo in os .supports_dir_fd , "test needs dir_fd support in os.mkfifo()" )
1494
1517
def test_mkfifo_dir_fd (self ):
1495
1518
with self .prepare () as (dir_fd , name , fullname ):
1496
1519
try :
@@ -2089,6 +2112,28 @@ def test_mkdir(self):
2089
2112
with self .assertRaisesRegex (NotImplementedError , "dir_fd unavailable" ):
2090
2113
os .mkdir ("dir" , dir_fd = 0 )
2091
2114
2115
+ def test_mkfifo (self ):
2116
+ self ._verify_available ("HAVE_MKFIFOAT" )
2117
+ if self .mac_ver >= (13 , 0 ):
2118
+ self .assertIn ("HAVE_MKFIFOAT" , posix ._have_functions )
2119
+
2120
+ else :
2121
+ self .assertNotIn ("HAVE_MKFIFOAT" , posix ._have_functions )
2122
+
2123
+ with self .assertRaisesRegex (NotImplementedError , "dir_fd unavailable" ):
2124
+ os .mkfifo ("path" , dir_fd = 0 )
2125
+
2126
+ def test_mknod (self ):
2127
+ self ._verify_available ("HAVE_MKNODAT" )
2128
+ if self .mac_ver >= (13 , 0 ):
2129
+ self .assertIn ("HAVE_MKNODAT" , posix ._have_functions )
2130
+
2131
+ else :
2132
+ self .assertNotIn ("HAVE_MKNODAT" , posix ._have_functions )
2133
+
2134
+ with self .assertRaisesRegex (NotImplementedError , "dir_fd unavailable" ):
2135
+ os .mknod ("path" , dir_fd = 0 )
2136
+
2092
2137
def test_rename_replace (self ):
2093
2138
self ._verify_available ("HAVE_RENAMEAT" )
2094
2139
if self .mac_ver >= (10 , 10 ):
0 commit comments