Skip to content

Commit 00db139

Browse files
committed
[3.12] pythongh-114099: Add test exclusions to support running the test suite on iOS (python#114889)
Add test annotations required to run the test suite on iOS (PEP 730). The majority of the change involve annotating tests that use subprocess, but are skipped on Emscripten/WASI for other reasons, and including iOS/tvOS/watchOS under the same umbrella as macOS/darwin checks. `is_apple` and `is_apple_mobile` test helpers have been added to identify *any* Apple platform, and "any Apple platform except macOS", respectively.
1 parent 5476c08 commit 00db139

28 files changed

+143
-90
lines changed

Lib/test/support/os_helper.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@
2222

2323
# TESTFN_UNICODE is a non-ascii filename
2424
TESTFN_UNICODE = TESTFN_ASCII + "-\xe0\xf2\u0258\u0141\u011f"
25-
if sys.platform == 'darwin':
26-
# In Mac OS X's VFS API file names are, by definition, canonically
25+
if support.is_apple:
26+
# On Apple's VFS API file names are, by definition, canonically
2727
# decomposed Unicode, encoded using UTF-8. See QA1173:
2828
# http://developer.apple.com/mac/library/qa/qa2001/qa1173.html
2929
import unicodedata
@@ -48,8 +48,8 @@
4848
'encoding (%s). Unicode filename tests may not be effective'
4949
% (TESTFN_UNENCODABLE, sys.getfilesystemencoding()))
5050
TESTFN_UNENCODABLE = None
51-
# macOS and Emscripten deny unencodable filenames (invalid utf-8)
52-
elif sys.platform not in {'darwin', 'emscripten', 'wasi'}:
51+
# Apple and Emscripten deny unencodable filenames (invalid utf-8)
52+
elif not support.is_apple and sys.platform not in {"emscripten", "wasi"}:
5353
try:
5454
# ascii and utf-8 cannot encode the byte 0xff
5555
b'\xff'.decode(sys.getfilesystemencoding())

Lib/test/test_asyncio/test_events.py

+14
Original file line numberDiff line numberDiff line change
@@ -1894,6 +1894,7 @@ def check_killed(self, returncode):
18941894
else:
18951895
self.assertEqual(-signal.SIGKILL, returncode)
18961896

1897+
@support.requires_subprocess()
18971898
def test_subprocess_exec(self):
18981899
prog = os.path.join(os.path.dirname(__file__), 'echo.py')
18991900

@@ -1915,6 +1916,7 @@ def test_subprocess_exec(self):
19151916
self.check_killed(proto.returncode)
19161917
self.assertEqual(b'Python The Winner', proto.data[1])
19171918

1919+
@support.requires_subprocess()
19181920
def test_subprocess_interactive(self):
19191921
prog = os.path.join(os.path.dirname(__file__), 'echo.py')
19201922

@@ -1942,6 +1944,7 @@ def test_subprocess_interactive(self):
19421944
self.loop.run_until_complete(proto.completed)
19431945
self.check_killed(proto.returncode)
19441946

1947+
@support.requires_subprocess()
19451948
def test_subprocess_shell(self):
19461949
connect = self.loop.subprocess_shell(
19471950
functools.partial(MySubprocessProtocol, self.loop),
@@ -1958,6 +1961,7 @@ def test_subprocess_shell(self):
19581961
self.assertEqual(proto.data[2], b'')
19591962
transp.close()
19601963

1964+
@support.requires_subprocess()
19611965
def test_subprocess_exitcode(self):
19621966
connect = self.loop.subprocess_shell(
19631967
functools.partial(MySubprocessProtocol, self.loop),
@@ -1969,6 +1973,7 @@ def test_subprocess_exitcode(self):
19691973
self.assertEqual(7, proto.returncode)
19701974
transp.close()
19711975

1976+
@support.requires_subprocess()
19721977
def test_subprocess_close_after_finish(self):
19731978
connect = self.loop.subprocess_shell(
19741979
functools.partial(MySubprocessProtocol, self.loop),
@@ -1983,6 +1988,7 @@ def test_subprocess_close_after_finish(self):
19831988
self.assertEqual(7, proto.returncode)
19841989
self.assertIsNone(transp.close())
19851990

1991+
@support.requires_subprocess()
19861992
def test_subprocess_kill(self):
19871993
prog = os.path.join(os.path.dirname(__file__), 'echo.py')
19881994

@@ -1999,6 +2005,7 @@ def test_subprocess_kill(self):
19992005
self.check_killed(proto.returncode)
20002006
transp.close()
20012007

2008+
@support.requires_subprocess()
20022009
def test_subprocess_terminate(self):
20032010
prog = os.path.join(os.path.dirname(__file__), 'echo.py')
20042011

@@ -2016,6 +2023,7 @@ def test_subprocess_terminate(self):
20162023
transp.close()
20172024

20182025
@unittest.skipIf(sys.platform == 'win32', "Don't have SIGHUP")
2026+
@support.requires_subprocess()
20192027
def test_subprocess_send_signal(self):
20202028
# bpo-31034: Make sure that we get the default signal handler (killing
20212029
# the process). The parent process may have decided to ignore SIGHUP,
@@ -2040,6 +2048,7 @@ def test_subprocess_send_signal(self):
20402048
finally:
20412049
signal.signal(signal.SIGHUP, old_handler)
20422050

2051+
@support.requires_subprocess()
20432052
def test_subprocess_stderr(self):
20442053
prog = os.path.join(os.path.dirname(__file__), 'echo2.py')
20452054

@@ -2061,6 +2070,7 @@ def test_subprocess_stderr(self):
20612070
self.assertTrue(proto.data[2].startswith(b'ERR:test'), proto.data[2])
20622071
self.assertEqual(0, proto.returncode)
20632072

2073+
@support.requires_subprocess()
20642074
def test_subprocess_stderr_redirect_to_stdout(self):
20652075
prog = os.path.join(os.path.dirname(__file__), 'echo2.py')
20662076

@@ -2086,6 +2096,7 @@ def test_subprocess_stderr_redirect_to_stdout(self):
20862096
transp.close()
20872097
self.assertEqual(0, proto.returncode)
20882098

2099+
@support.requires_subprocess()
20892100
def test_subprocess_close_client_stream(self):
20902101
prog = os.path.join(os.path.dirname(__file__), 'echo3.py')
20912102

@@ -2120,6 +2131,7 @@ def test_subprocess_close_client_stream(self):
21202131
self.loop.run_until_complete(proto.completed)
21212132
self.check_killed(proto.returncode)
21222133

2134+
@support.requires_subprocess()
21232135
def test_subprocess_wait_no_same_group(self):
21242136
# start the new process in a new session
21252137
connect = self.loop.subprocess_shell(
@@ -2132,6 +2144,7 @@ def test_subprocess_wait_no_same_group(self):
21322144
self.assertEqual(7, proto.returncode)
21332145
transp.close()
21342146

2147+
@support.requires_subprocess()
21352148
def test_subprocess_exec_invalid_args(self):
21362149
async def connect(**kwds):
21372150
await self.loop.subprocess_exec(
@@ -2145,6 +2158,7 @@ async def connect(**kwds):
21452158
with self.assertRaises(ValueError):
21462159
self.loop.run_until_complete(connect(shell=True))
21472160

2161+
@support.requires_subprocess()
21482162
def test_subprocess_shell_invalid_args(self):
21492163

21502164
async def connect(cmd=None, **kwds):

Lib/test/test_asyncio/test_streams.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010
import unittest
1111
from unittest import mock
1212
import warnings
13-
from test.support import socket_helper
1413
try:
1514
import ssl
1615
except ImportError:
1716
ssl = None
1817

1918
import asyncio
2019
from test.test_asyncio import utils as test_utils
20+
from test.support import requires_subprocess, socket_helper
2121

2222

2323
def tearDownModule():
@@ -770,6 +770,7 @@ async def client(addr):
770770
self.assertEqual(msg2, b"hello world 2!\n")
771771

772772
@unittest.skipIf(sys.platform == 'win32', "Don't have pipes")
773+
@requires_subprocess()
773774
def test_read_all_from_pipe_reader(self):
774775
# See asyncio issue 168. This test is derived from the example
775776
# subprocess_attach_read_pipe.py, but we configure the

Lib/test/test_asyncio/test_subprocess.py

+2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def _start(self, *args, **kwargs):
4747
self._proc.pid = -1
4848

4949

50+
@support.requires_subprocess()
5051
class SubprocessTransportTests(test_utils.TestCase):
5152
def setUp(self):
5253
super().setUp()
@@ -110,6 +111,7 @@ def test_subprocess_repr(self):
110111
transport.close()
111112

112113

114+
@support.requires_subprocess()
113115
class SubprocessMixin:
114116

115117
def test_stdin_stdout(self):

Lib/test/test_asyncio/test_unix_events.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1873,7 +1873,7 @@ async def runner():
18731873
wsock.close()
18741874

18751875

1876-
@unittest.skipUnless(hasattr(os, 'fork'), 'requires os.fork()')
1876+
@support.requires_fork()
18771877
class TestFork(unittest.IsolatedAsyncioTestCase):
18781878

18791879
async def test_fork_not_share_event_loop(self):

Lib/test/test_cmd_line_script.py

+10-6
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414

1515
import textwrap
1616
from test import support
17-
from test.support import import_helper
18-
from test.support import os_helper
17+
from test.support import import_helper, is_apple, os_helper
1918
from test.support.script_helper import (
2019
make_pkg, make_script, make_zip_pkg, make_zip_script,
2120
assert_python_ok, assert_python_failure, spawn_python, kill_python)
@@ -555,12 +554,17 @@ def test_pep_409_verbiage(self):
555554
self.assertTrue(text[3].startswith('NameError'))
556555

557556
def test_non_ascii(self):
558-
# Mac OS X denies the creation of a file with an invalid UTF-8 name.
557+
# Apple platforms deny the creation of a file with an invalid UTF-8 name.
559558
# Windows allows creating a name with an arbitrary bytes name, but
560559
# Python cannot a undecodable bytes argument to a subprocess.
561-
# WASI does not permit invalid UTF-8 names.
562-
if (os_helper.TESTFN_UNDECODABLE
563-
and sys.platform not in ('win32', 'darwin', 'emscripten', 'wasi')):
560+
# Emscripten/WASI does not permit invalid UTF-8 names.
561+
if (
562+
os_helper.TESTFN_UNDECODABLE
563+
and sys.platform not in {
564+
"win32", "emscripten", "wasi"
565+
}
566+
and not is_apple
567+
):
564568
name = os.fsdecode(os_helper.TESTFN_UNDECODABLE)
565569
elif os_helper.TESTFN_NONASCII:
566570
name = os_helper.TESTFN_NONASCII

Lib/test/test_fcntl.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import struct
77
import sys
88
import unittest
9-
from test.support import verbose, cpython_only, get_pagesize
9+
from test.support import (
10+
cpython_only, get_pagesize, is_apple, requires_subprocess, verbose
11+
)
1012
from test.support.import_helper import import_module
1113
from test.support.os_helper import TESTFN, unlink
1214

@@ -56,8 +58,10 @@ def get_lockdata():
5658
else:
5759
start_len = "qq"
5860

59-
if (sys.platform.startswith(('netbsd', 'freebsd', 'openbsd'))
60-
or sys.platform == 'darwin'):
61+
if (
62+
sys.platform.startswith(('netbsd', 'freebsd', 'openbsd'))
63+
or is_apple
64+
):
6165
if struct.calcsize('l') == 8:
6266
off_t = 'l'
6367
pid_t = 'i'
@@ -157,6 +161,7 @@ def test_flock(self):
157161
self.assertRaises(TypeError, fcntl.flock, 'spam', fcntl.LOCK_SH)
158162

159163
@unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
164+
@requires_subprocess()
160165
def test_lockf_exclusive(self):
161166
self.f = open(TESTFN, 'wb+')
162167
cmd = fcntl.LOCK_EX | fcntl.LOCK_NB
@@ -169,6 +174,7 @@ def test_lockf_exclusive(self):
169174
self.assertEqual(p.exitcode, 0)
170175

171176
@unittest.skipIf(platform.system() == "AIX", "AIX returns PermissionError")
177+
@requires_subprocess()
172178
def test_lockf_share(self):
173179
self.f = open(TESTFN, 'wb+')
174180
cmd = fcntl.LOCK_SH | fcntl.LOCK_NB

Lib/test/test_ftplib.py

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
from unittest import TestCase, skipUnless
2020
from test import support
21+
from test.support import requires_subprocess
2122
from test.support import threading_helper
2223
from test.support import socket_helper
2324
from test.support import warnings_helper
@@ -900,6 +901,7 @@ def retr():
900901

901902

902903
@skipUnless(ssl, "SSL not available")
904+
@requires_subprocess()
903905
class TestTLS_FTPClassMixin(TestFTPClass):
904906
"""Repeat TestFTPClass tests starting the TLS layer for both control
905907
and data connections first.
@@ -916,6 +918,7 @@ def setUp(self, encoding=DEFAULT_ENCODING):
916918

917919

918920
@skipUnless(ssl, "SSL not available")
921+
@requires_subprocess()
919922
class TestTLS_FTPClass(TestCase):
920923
"""Specific TLS_FTP class tests."""
921924

Lib/test/test_genericpath.py

+13-9
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
import sys
88
import unittest
99
import warnings
10-
from test.support import is_emscripten
11-
from test.support import os_helper
12-
from test.support import warnings_helper
10+
from test.support import (
11+
is_apple, is_emscripten, os_helper, warnings_helper
12+
)
1313
from test.support.script_helper import assert_python_ok
1414
from test.support.os_helper import FakePath
1515

@@ -492,12 +492,16 @@ def test_abspath_issue3426(self):
492492
self.assertIsInstance(abspath(path), str)
493493

494494
def test_nonascii_abspath(self):
495-
if (os_helper.TESTFN_UNDECODABLE
496-
# macOS and Emscripten deny the creation of a directory with an
497-
# invalid UTF-8 name. Windows allows creating a directory with an
498-
# arbitrary bytes name, but fails to enter this directory
499-
# (when the bytes name is used).
500-
and sys.platform not in ('win32', 'darwin', 'emscripten', 'wasi')):
495+
if (
496+
os_helper.TESTFN_UNDECODABLE
497+
# Apple platforms and Emscripten/WASI deny the creation of a
498+
# directory with an invalid UTF-8 name. Windows allows creating a
499+
# directory with an arbitrary bytes name, but fails to enter this
500+
# directory (when the bytes name is used).
501+
and sys.platform not in {
502+
"win32", "emscripten", "wasi"
503+
} and not is_apple
504+
):
501505
name = os_helper.TESTFN_UNDECODABLE
502506
elif os_helper.TESTFN_NONASCII:
503507
name = os_helper.TESTFN_NONASCII

Lib/test/test_httpservers.py

+10-8
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@
3131

3232
import unittest
3333
from test import support
34-
from test.support import os_helper
35-
from test.support import threading_helper
34+
from test.support import (
35+
is_apple, os_helper, requires_subprocess, threading_helper
36+
)
3637

3738
support.requires_working_socket(module=True)
3839

@@ -411,8 +412,8 @@ def close_conn():
411412
reader.close()
412413
return body
413414

414-
@unittest.skipIf(sys.platform == 'darwin',
415-
'undecodable name cannot always be decoded on macOS')
415+
@unittest.skipIf(is_apple,
416+
'undecodable name cannot always be decoded on Apple platforms')
416417
@unittest.skipIf(sys.platform == 'win32',
417418
'undecodable name cannot be decoded on win32')
418419
@unittest.skipUnless(os_helper.TESTFN_UNDECODABLE,
@@ -423,11 +424,11 @@ def test_undecodable_filename(self):
423424
with open(os.path.join(self.tempdir, filename), 'wb') as f:
424425
f.write(os_helper.TESTFN_UNDECODABLE)
425426
response = self.request(self.base_url + '/')
426-
if sys.platform == 'darwin':
427-
# On Mac OS the HFS+ filesystem replaces bytes that aren't valid
428-
# UTF-8 into a percent-encoded value.
427+
if is_apple:
428+
# On Apple platforms the HFS+ filesystem replaces bytes that
429+
# aren't valid UTF-8 into a percent-encoded value.
429430
for name in os.listdir(self.tempdir):
430-
if name != 'test': # Ignore a filename created in setUp().
431+
if name != 'test': # Ignore a filename created in setUp().
431432
filename = name
432433
break
433434
body = self.check_status_and_reason(response, HTTPStatus.OK)
@@ -698,6 +699,7 @@ def test_html_escape_filename(self):
698699

699700
@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
700701
"This test can't be run reliably as root (issue #13308).")
702+
@requires_subprocess()
701703
class CGIHTTPServerTestCase(BaseTestCase):
702704
class request_handler(NoLogRequestHandler, CGIHTTPRequestHandler):
703705
def run_cgi(self):

Lib/test/test_io.py

+7-9
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,9 @@
3939
from test import support
4040
from test.support.script_helper import (
4141
assert_python_ok, assert_python_failure, run_python_until_end)
42-
from test.support import import_helper
43-
from test.support import os_helper
44-
from test.support import threading_helper
45-
from test.support import warnings_helper
46-
from test.support import skip_if_sanitizer
42+
from test.support import (
43+
import_helper, is_apple, os_helper, skip_if_sanitizer, threading_helper, warnings_helper
44+
)
4745
from test.support.os_helper import FakePath
4846

4947
import codecs
@@ -631,10 +629,10 @@ def test_raw_bytes_io(self):
631629
self.read_ops(f, True)
632630

633631
def test_large_file_ops(self):
634-
# On Windows and Mac OSX this test consumes large resources; It takes
635-
# a long time to build the >2 GiB file and takes >2 GiB of disk space
636-
# therefore the resource must be enabled to run this test.
637-
if sys.platform[:3] == 'win' or sys.platform == 'darwin':
632+
# On Windows and Apple platforms this test consumes large resources; It
633+
# takes a long time to build the >2 GiB file and takes >2 GiB of disk
634+
# space therefore the resource must be enabled to run this test.
635+
if sys.platform[:3] == 'win' or is_apple:
638636
support.requires(
639637
'largefile',
640638
'test requires %s bytes and a long time to run' % self.LARGE)

0 commit comments

Comments
 (0)