diff options
Diffstat (limited to 'Lib/test/test_capi.py')
-rw-r--r-- | Lib/test/test_capi.py | 118 |
1 files changed, 110 insertions, 8 deletions
diff --git a/Lib/test/test_capi.py b/Lib/test/test_capi.py index 1c4c0f8..f1ea5a9 100644 --- a/Lib/test/test_capi.py +++ b/Lib/test/test_capi.py @@ -15,10 +15,8 @@ try: except ImportError: _posixsubprocess = None try: - import _thread import threading except ImportError: - _thread = None threading = None import _testcapi @@ -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 -@unittest.skipUnless(threading and _thread, 'Threading required for this test.') + # 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, '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() @@ -252,7 +354,7 @@ class TestThreadState(unittest.TestCase): def test_main(): support.run_unittest(CAPITest, TestPendingCalls, Test6012, - EmbeddingTest, TestThreadState) + EmbeddingTest, SkipitemTest, TestThreadState) for name in dir(_testcapi): if name.startswith('test_'): |