blob: 4393e3ce9a11660a3adddb95455178c3cad05e5c [file] [log] [blame]
Tim Petersd66595f2001-02-04 03:09:53 +00001# Run the _testcapi module tests (tests for the Python/C API): by defn,
Guido van Rossum361c5352001-04-13 17:03:04 +00002# these are all functions _testcapi exports whose name begins with 'test_'.
Tim Peters9ea17ac2001-02-02 05:57:15 +00003
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +00004from __future__ import with_statement
Serhiy Storchakaef19fd22018-07-11 19:49:17 +03005import string
Martin v. Löwis6ce7ed22005-03-03 12:26:35 +00006import sys
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +00007import time
8import random
9import unittest
Serhiy Storchakabd8c6292015-04-01 12:56:39 +030010from test import test_support as support
Victor Stinnerbe595d32010-04-27 23:01:29 +000011try:
Ezio Melottief1db542013-02-23 06:33:51 +020012 import thread
Victor Stinnerbe595d32010-04-27 23:01:29 +000013 import threading
14except ImportError:
Ezio Melottief1db542013-02-23 06:33:51 +020015 thread = None
Victor Stinnerbe595d32010-04-27 23:01:29 +000016 threading = None
Serhiy Storchaka76249ea2014-02-07 10:06:05 +020017# Skip this test if the _testcapi module isn't available.
Serhiy Storchakabd8c6292015-04-01 12:56:39 +030018_testcapi = support.import_module('_testcapi')
Serhiy Storchaka76249ea2014-02-07 10:06:05 +020019
Serhiy Storchaka12cf60c2016-05-20 22:31:24 +030020class CAPITest(unittest.TestCase):
21
22 def test_buildvalue_N(self):
23 _testcapi.test_buildvalue_N()
24
Tim Peters9ea17ac2001-02-02 05:57:15 +000025
Victor Stinnerbe595d32010-04-27 23:01:29 +000026@unittest.skipUnless(threading, 'Threading required for this test.')
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000027class TestPendingCalls(unittest.TestCase):
28
29 def pendingcalls_submit(self, l, n):
30 def callback():
31 #this function can be interrupted by thread switching so let's
32 #use an atomic operation
33 l.append(None)
34
35 for i in range(n):
36 time.sleep(random.random()*0.02) #0.01 secs on average
37 #try submitting callback until successful.
38 #rely on regular interrupt to flush queue if we are
39 #unsuccessful.
40 while True:
41 if _testcapi._pending_threadfunc(callback):
42 break;
43
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000044 def pendingcalls_wait(self, l, n, context = None):
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000045 #now, stick around until l[0] has grown to 10
46 count = 0;
47 while len(l) != n:
48 #this busy loop is where we expect to be interrupted to
49 #run our callbacks. Note that callbacks are only run on the
50 #main thread
Serhiy Storchakabd8c6292015-04-01 12:56:39 +030051 if False and support.verbose:
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000052 print "(%i)"%(len(l),),
53 for i in xrange(1000):
54 a = i*i
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000055 if context and not context.event.is_set():
56 continue
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000057 count += 1
Benjamin Peterson5c8da862009-06-30 22:57:08 +000058 self.assertTrue(count < 10000,
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000059 "timeout waiting for %i callbacks, got %i"%(n, len(l)))
Serhiy Storchakabd8c6292015-04-01 12:56:39 +030060 if False and support.verbose:
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000061 print "(%i)"%(len(l),)
62
63 def test_pendingcalls_threaded(self):
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000064 #do every callback on a separate thread
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000065 n = 32 #total callbacks
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000066 threads = []
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000067 class foo(object):pass
68 context = foo()
69 context.l = []
70 context.n = 2 #submits per thread
Ezio Melottidde5b942010-02-03 05:37:26 +000071 context.nThreads = n // context.n
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000072 context.nFinished = 0
73 context.lock = threading.Lock()
74 context.event = threading.Event()
75
Serhiy Storchakabd8c6292015-04-01 12:56:39 +030076 threads = [threading.Thread(target=self.pendingcalls_thread,
77 args=(context,))
78 for i in range(context.nThreads)]
79 with support.start_threads(threads):
80 self.pendingcalls_wait(context.l, n, context)
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000081
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000082 def pendingcalls_thread(self, context):
83 try:
84 self.pendingcalls_submit(context.l, context.n)
85 finally:
86 with context.lock:
87 context.nFinished += 1
88 nFinished = context.nFinished
Serhiy Storchakabd8c6292015-04-01 12:56:39 +030089 if False and support.verbose:
Kristján Valur Jónsson60e79ce2009-01-18 10:58:44 +000090 print "finished threads: ", nFinished
91 if nFinished == context.nThreads:
92 context.event.set()
93
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000094 def test_pendingcalls_non_threaded(self):
Ezio Melottic2077b02011-03-16 12:34:31 +020095 #again, just using the main thread, likely they will all be dispatched at
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +000096 #once. It is ok to ask for too many, because we loop until we find a slot.
97 #the loop can be interrupted to dispatch.
98 #there are only 32 dispatch slots, so we go for twice that!
99 l = []
100 n = 64
101 self.pendingcalls_submit(l, n)
102 self.pendingcalls_wait(l, n)
103
104
Xtreak2bea7712018-07-26 21:50:34 +0530105class TestGetIndices(unittest.TestCase):
106
107 def test_get_indices(self):
108 self.assertEqual(_testcapi.get_indices(slice(10L, 20, 1), 100), (0, 10, 20, 1))
109 self.assertEqual(_testcapi.get_indices(slice(10.1, 20, 1), 100), None)
110 self.assertEqual(_testcapi.get_indices(slice(10, 20L, 1), 100), (0, 10, 20, 1))
111 self.assertEqual(_testcapi.get_indices(slice(10, 20.1, 1), 100), None)
112
113 self.assertEqual(_testcapi.get_indices(slice(10L, 20, 1L), 100), (0, 10, 20, 1))
114 self.assertEqual(_testcapi.get_indices(slice(10.1, 20, 1L), 100), None)
115 self.assertEqual(_testcapi.get_indices(slice(10, 20L, 1L), 100), (0, 10, 20, 1))
116 self.assertEqual(_testcapi.get_indices(slice(10, 20.1, 1L), 100), None)
117
118
Serhiy Storchakaef19fd22018-07-11 19:49:17 +0300119class SkipitemTest(unittest.TestCase):
120
121 def test_skipitem(self):
122 """
123 If this test failed, you probably added a new "format unit"
124 in Python/getargs.c, but neglected to update our poor friend
125 skipitem() in the same file. (If so, shame on you!)
126
127 With a few exceptions**, this function brute-force tests all
128 printable ASCII*** characters (32 to 126 inclusive) as format units,
129 checking to see that PyArg_ParseTupleAndKeywords() return consistent
130 errors both when the unit is attempted to be used and when it is
131 skipped. If the format unit doesn't exist, we'll get one of two
132 specific error messages (one for used, one for skipped); if it does
133 exist we *won't* get that error--we'll get either no error or some
134 other error. If we get the specific "does not exist" error for one
135 test and not for the other, there's a mismatch, and the test fails.
136
137 ** Some format units have special funny semantics and it would
138 be difficult to accommodate them here. Since these are all
139 well-established and properly skipped in skipitem() we can
140 get away with not testing them--this test is really intended
141 to catch *new* format units.
142
143 *** Python C source files must be ASCII. Therefore it's impossible
144 to have non-ASCII format units.
145
146 """
147 empty_tuple = ()
148 tuple_1 = (0,)
149 dict_b = {'b':1}
150 keywords = ["a", "b"]
151
152 for i in range(32, 127):
153 c = chr(i)
154
155 # skip parentheses, the error reporting is inconsistent about them
156 # skip 'e', it's always a two-character code
157 # skip '|', it doesn't represent arguments anyway
158 if c in '()e|':
159 continue
160
161 # test the format unit when not skipped
162 format = c + "i"
163 try:
164 _testcapi.parse_tuple_and_keywords(tuple_1, dict_b,
165 format, keywords)
166 when_not_skipped = False
167 except TypeError as e:
168 s = "argument 1 (impossible<bad format char>)"
169 when_not_skipped = (str(e) == s)
170 except RuntimeError:
171 when_not_skipped = False
172
173 # test the format unit when skipped
174 optional_format = "|" + format
175 try:
176 _testcapi.parse_tuple_and_keywords(empty_tuple, dict_b,
177 optional_format, keywords)
178 when_skipped = False
179 except RuntimeError as e:
180 s = "impossible<bad format char>: '{}'".format(format)
181 when_skipped = (str(e) == s)
182
183 message = ("test_skipitem_parity: "
184 "detected mismatch between convertsimple and skipitem "
185 "for format unit '{}' ({}), not skipped {}, skipped {}".format(
186 c, i, when_skipped, when_not_skipped))
187 self.assertIs(when_skipped, when_not_skipped, message)
188
189 def test_skipitem_with_suffix(self):
190 parse = _testcapi.parse_tuple_and_keywords
191 empty_tuple = ()
192 tuple_1 = (0,)
193 dict_b = {'b':1}
194 keywords = ["a", "b"]
195
196 supported = ('s#', 's*', 'z#', 'z*', 'u#', 't#', 'w#', 'w*')
197 for c in string.ascii_letters:
198 for c2 in '#*':
199 f = c + c2
200 optional_format = "|" + f + "i"
201 if f in supported:
202 parse(empty_tuple, dict_b, optional_format, keywords)
203 else:
204 with self.assertRaisesRegexp((RuntimeError, TypeError),
205 'impossible<bad format char>'):
206 parse(empty_tuple, dict_b, optional_format, keywords)
207
208 for c in map(chr, range(32, 128)):
209 f = 'e' + c
210 optional_format = "|" + f + "i"
211 if c in 'st':
212 parse(empty_tuple, dict_b, optional_format, keywords)
213 else:
214 with self.assertRaisesRegexp(RuntimeError,
215 'impossible<bad format char>'):
216 parse(empty_tuple, dict_b, optional_format, keywords)
217
218 def test_parse_tuple_and_keywords(self):
219 # Test handling errors in the parse_tuple_and_keywords helper itself
220 self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords,
221 (), {}, 42, [])
222 self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
223 (), {}, '', 42)
224 self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
225 (), {}, '', [''] * 42)
226 self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords,
227 (), {}, '', [42])
228
229 def test_bad_use(self):
230 # Test handling invalid format and keywords in
231 # PyArg_ParseTupleAndKeywords()
232 self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords,
233 (1,), {}, '||O', ['a'])
234 self.assertRaises(RuntimeError, _testcapi.parse_tuple_and_keywords,
235 (1,), {}, '|O', ['a', 'b'])
236 self.assertRaises(RuntimeError, _testcapi.parse_tuple_and_keywords,
237 (1,), {}, '|OO', ['a'])
238
239
Ezio Melottief1db542013-02-23 06:33:51 +0200240@unittest.skipUnless(threading and thread, 'Threading required for this test.')
Ezio Melotti2fddfd82013-02-23 05:45:37 +0200241class TestThreadState(unittest.TestCase):
Tim Peters59b96c12006-03-21 03:58:41 +0000242
Serhiy Storchakabd8c6292015-04-01 12:56:39 +0300243 @support.reap_threads
Ezio Melotti2fddfd82013-02-23 05:45:37 +0200244 def test_thread_state(self):
245 # some extra thread-state tests driven via _testcapi
246 def target():
247 idents = []
248
249 def callback():
250 idents.append(thread.get_ident())
251
252 _testcapi._test_thread_state(callback)
253 a = b = callback
254 time.sleep(1)
255 # Check our main thread is in the list exactly 3 times.
256 self.assertEqual(idents.count(thread.get_ident()), 3,
257 "Couldn't find main thread correctly in the list")
258
259 target()
260 t = threading.Thread(target=target)
261 t.start()
262 t.join()
263
264
265def test_main():
Tim Peters59b96c12006-03-21 03:58:41 +0000266 for name in dir(_testcapi):
267 if name.startswith('test_'):
268 test = getattr(_testcapi, name)
Serhiy Storchakabd8c6292015-04-01 12:56:39 +0300269 if support.verbose:
Tim Peters59b96c12006-03-21 03:58:41 +0000270 print "internal", name
271 try:
272 test()
273 except _testcapi.error:
Serhiy Storchakabd8c6292015-04-01 12:56:39 +0300274 raise support.TestFailed, sys.exc_info()[1]
Tim Peters59b96c12006-03-21 03:58:41 +0000275
Serhiy Storchakaef19fd22018-07-11 19:49:17 +0300276 support.run_unittest(CAPITest, TestPendingCalls, SkipitemTest,
Xtreak2bea7712018-07-26 21:50:34 +0530277 TestThreadState, TestGetIndices)
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +0000278
Tim Peters59b96c12006-03-21 03:58:41 +0000279if __name__ == "__main__":
280 test_main()