summaryrefslogtreecommitdiffstats
path: root/Lib/test/test_capi.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/test/test_capi.py')
-rw-r--r--Lib/test/test_capi.py139
1 files changed, 118 insertions, 21 deletions
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py
index 1c4c0f8..50c4bba 100644
--- a/Lib/test/test_capi.py
+++ b/Lib/test/test_capi.py
@@ -1,7 +1,6 @@
# Run the _testcapi module tests (tests for the Python/C API): by defn,
# these are all functions _testcapi exports whose name begins with 'test_'.
-from __future__ import with_statement
import os
import pickle
import random
@@ -15,12 +14,11 @@ try:
except ImportError:
_posixsubprocess = None
try:
- import _thread
import threading
except ImportError:
- _thread = None
threading = None
-import _testcapi
+# Skip this test if the _testcapi module isn't available.
+_testcapi = support.import_module('_testcapi')
def testfunction(self):
@@ -55,13 +53,36 @@ class CAPITest(unittest.TestCase):
(out, err) = p.communicate()
self.assertEqual(out, b'')
# This used to cause an infinite loop.
- self.assertEqual(err.rstrip(),
+ self.assertTrue(err.rstrip().startswith(
b'Fatal Python error:'
- b' PyThreadState_Get: no current thread')
+ b' PyThreadState_Get: no current thread'))
def test_memoryview_from_NULL_pointer(self):
self.assertRaises(ValueError, _testcapi.make_memoryview_from_NULL_pointer)
+ def test_exc_info(self):
+ raised_exception = ValueError("5")
+ new_exc = TypeError("TEST")
+ try:
+ raise raised_exception
+ except ValueError as e:
+ tb = e.__traceback__
+ orig_sys_exc_info = sys.exc_info()
+ orig_exc_info = _testcapi.set_exc_info(new_exc.__class__, new_exc, None)
+ new_sys_exc_info = sys.exc_info()
+ new_exc_info = _testcapi.set_exc_info(*orig_exc_info)
+ reset_sys_exc_info = sys.exc_info()
+
+ self.assertEqual(orig_exc_info[1], e)
+
+ self.assertSequenceEqual(orig_exc_info, (raised_exception.__class__, raised_exception, tb))
+ self.assertSequenceEqual(orig_sys_exc_info, orig_exc_info)
+ self.assertSequenceEqual(reset_sys_exc_info, orig_exc_info)
+ self.assertSequenceEqual(new_exc_info, (new_exc.__class__, new_exc, None))
+ self.assertSequenceEqual(new_sys_exc_info, new_exc_info)
+ else:
+ self.assertTrue(False)
+
@unittest.skipUnless(_posixsubprocess, '_posixsubprocess required for this test.')
def test_seq_bytes_to_charp_array(self):
# Issue #15732: crash in _PySequence_BytesToCharpArray()
@@ -224,8 +245,89 @@ class EmbeddingTest(unittest.TestCase):
finally:
os.chdir(oldcwd)
+class SkipitemTest(unittest.TestCase):
+
+ def test_skipitem(self):
+ """
+ If this test failed, you probably added a new "format unit"
+ in Python/getargs.c, but neglected to update our poor friend
+ skipitem() in the same file. (If so, shame on you!)
+
+ With a few exceptions**, this function brute-force tests all
+ printable ASCII*** characters (32 to 126 inclusive) as format units,
+ checking to see that PyArg_ParseTupleAndKeywords() return consistent
+ errors both when the unit is attempted to be used and when it is
+ skipped. If the format unit doesn't exist, we'll get one of two
+ specific error messages (one for used, one for skipped); if it does
+ exist we *won't* get that error--we'll get either no error or some
+ other error. If we get the specific "does not exist" error for one
+ test and not for the other, there's a mismatch, and the test fails.
+
+ ** Some format units have special funny semantics and it would
+ be difficult to accomodate them here. Since these are all
+ well-established and properly skipped in skipitem() we can
+ get away with not testing them--this test is really intended
+ to catch *new* format units.
+
+ *** Python C source files must be ASCII. Therefore it's impossible
+ to have non-ASCII format units.
+
+ """
+ empty_tuple = ()
+ tuple_1 = (0,)
+ dict_b = {'b':1}
+ keywords = ["a", "b"]
+
+ for i in range(32, 127):
+ c = chr(i)
+
+ # skip parentheses, the error reporting is inconsistent about them
+ # skip 'e', it's always a two-character code
+ # skip '|' and '$', they don't represent arguments anyway
+ if c in '()e|$':
+ continue
+
+ # test the format unit when not skipped
+ format = c + "i"
+ try:
+ # (note: the format string must be bytes!)
+ _testcapi.parse_tuple_and_keywords(tuple_1, dict_b,
+ format.encode("ascii"), keywords)
+ when_not_skipped = False
+ except TypeError as e:
+ s = "argument 1 must be impossible<bad format char>, not int"
+ when_not_skipped = (str(e) == s)
+ except RuntimeError as e:
+ when_not_skipped = False
+
+ # test the format unit when skipped
+ optional_format = "|" + format
+ try:
+ _testcapi.parse_tuple_and_keywords(empty_tuple, dict_b,
+ optional_format.encode("ascii"), keywords)
+ when_skipped = False
+ except RuntimeError as e:
+ s = "impossible<bad format char>: '{}'".format(format)
+ when_skipped = (str(e) == s)
+
+ message = ("test_skipitem_parity: "
+ "detected mismatch between convertsimple and skipitem "
+ "for format unit '{}' ({}), not skipped {}, skipped {}".format(
+ c, i, when_skipped, when_not_skipped))
+ self.assertIs(when_skipped, when_not_skipped, message)
+
+ def test_parse_tuple_and_keywords(self):
+ # parse_tuple_and_keywords error handling tests
+ self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords,
+ (), {}, 42, [])
+ self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
+ (), {}, b'', 42)
+ self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
+ (), {}, b'', [''] * 42)
+ self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
+ (), {}, b'', [42])
-@unittest.skipUnless(threading and _thread, 'Threading required for this test.')
+@unittest.skipUnless(threading, 'Threading required for this test.')
class TestThreadState(unittest.TestCase):
@support.reap_threads
@@ -235,13 +337,13 @@ class TestThreadState(unittest.TestCase):
idents = []
def callback():
- idents.append(_thread.get_ident())
+ idents.append(threading.get_ident())
_testcapi._test_thread_state(callback)
a = b = callback
time.sleep(1)
# Check our main thread is in the list exactly 3 times.
- self.assertEqual(idents.count(_thread.get_ident()), 3,
+ self.assertEqual(idents.count(threading.get_ident()), 3,
"Couldn't find main thread correctly in the list")
target()
@@ -249,17 +351,12 @@ class TestThreadState(unittest.TestCase):
t.start()
t.join()
-
-def test_main():
- support.run_unittest(CAPITest, TestPendingCalls, Test6012,
- EmbeddingTest, TestThreadState)
-
- for name in dir(_testcapi):
- if name.startswith('test_'):
- test = getattr(_testcapi, name)
- if support.verbose:
- print("internal", name)
- test()
+class Test_testcapi(unittest.TestCase):
+ def test__testcapi(self):
+ for name in dir(_testcapi):
+ if name.startswith('test_'):
+ test = getattr(_testcapi, name)
+ test()
if __name__ == "__main__":
- test_main()
+ unittest.main()