blob: d281be61649d1ce5e1ef4b444b470e62d6d539fd [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
Serhiy Storchakaef19fd22018-07-11 19:49:17 +0300105# Bug #6012
106class Test6012(unittest.TestCase):
107 def test(self):
108 self.assertEqual(_testcapi.argparsing("Hello", "World"), 1)
109
110
111class SkipitemTest(unittest.TestCase):
112
113 def test_skipitem(self):
114 """
115 If this test failed, you probably added a new "format unit"
116 in Python/getargs.c, but neglected to update our poor friend
117 skipitem() in the same file. (If so, shame on you!)
118
119 With a few exceptions**, this function brute-force tests all
120 printable ASCII*** characters (32 to 126 inclusive) as format units,
121 checking to see that PyArg_ParseTupleAndKeywords() return consistent
122 errors both when the unit is attempted to be used and when it is
123 skipped. If the format unit doesn't exist, we'll get one of two
124 specific error messages (one for used, one for skipped); if it does
125 exist we *won't* get that error--we'll get either no error or some
126 other error. If we get the specific "does not exist" error for one
127 test and not for the other, there's a mismatch, and the test fails.
128
129 ** Some format units have special funny semantics and it would
130 be difficult to accommodate them here. Since these are all
131 well-established and properly skipped in skipitem() we can
132 get away with not testing them--this test is really intended
133 to catch *new* format units.
134
135 *** Python C source files must be ASCII. Therefore it's impossible
136 to have non-ASCII format units.
137
138 """
139 empty_tuple = ()
140 tuple_1 = (0,)
141 dict_b = {'b':1}
142 keywords = ["a", "b"]
143
144 for i in range(32, 127):
145 c = chr(i)
146
147 # skip parentheses, the error reporting is inconsistent about them
148 # skip 'e', it's always a two-character code
149 # skip '|', it doesn't represent arguments anyway
150 if c in '()e|':
151 continue
152
153 # test the format unit when not skipped
154 format = c + "i"
155 try:
156 _testcapi.parse_tuple_and_keywords(tuple_1, dict_b,
157 format, keywords)
158 when_not_skipped = False
159 except TypeError as e:
160 s = "argument 1 (impossible<bad format char>)"
161 when_not_skipped = (str(e) == s)
162 except RuntimeError:
163 when_not_skipped = False
164
165 # test the format unit when skipped
166 optional_format = "|" + format
167 try:
168 _testcapi.parse_tuple_and_keywords(empty_tuple, dict_b,
169 optional_format, keywords)
170 when_skipped = False
171 except RuntimeError as e:
172 s = "impossible<bad format char>: '{}'".format(format)
173 when_skipped = (str(e) == s)
174
175 message = ("test_skipitem_parity: "
176 "detected mismatch between convertsimple and skipitem "
177 "for format unit '{}' ({}), not skipped {}, skipped {}".format(
178 c, i, when_skipped, when_not_skipped))
179 self.assertIs(when_skipped, when_not_skipped, message)
180
181 def test_skipitem_with_suffix(self):
182 parse = _testcapi.parse_tuple_and_keywords
183 empty_tuple = ()
184 tuple_1 = (0,)
185 dict_b = {'b':1}
186 keywords = ["a", "b"]
187
188 supported = ('s#', 's*', 'z#', 'z*', 'u#', 't#', 'w#', 'w*')
189 for c in string.ascii_letters:
190 for c2 in '#*':
191 f = c + c2
192 optional_format = "|" + f + "i"
193 if f in supported:
194 parse(empty_tuple, dict_b, optional_format, keywords)
195 else:
196 with self.assertRaisesRegexp((RuntimeError, TypeError),
197 'impossible<bad format char>'):
198 parse(empty_tuple, dict_b, optional_format, keywords)
199
200 for c in map(chr, range(32, 128)):
201 f = 'e' + c
202 optional_format = "|" + f + "i"
203 if c in 'st':
204 parse(empty_tuple, dict_b, optional_format, keywords)
205 else:
206 with self.assertRaisesRegexp(RuntimeError,
207 'impossible<bad format char>'):
208 parse(empty_tuple, dict_b, optional_format, keywords)
209
210 def test_parse_tuple_and_keywords(self):
211 # Test handling errors in the parse_tuple_and_keywords helper itself
212 self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords,
213 (), {}, 42, [])
214 self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
215 (), {}, '', 42)
216 self.assertRaises(ValueError, _testcapi.parse_tuple_and_keywords,
217 (), {}, '', [''] * 42)
218 self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords,
219 (), {}, '', [42])
220
221 def test_bad_use(self):
222 # Test handling invalid format and keywords in
223 # PyArg_ParseTupleAndKeywords()
224 self.assertRaises(TypeError, _testcapi.parse_tuple_and_keywords,
225 (1,), {}, '||O', ['a'])
226 self.assertRaises(RuntimeError, _testcapi.parse_tuple_and_keywords,
227 (1,), {}, '|O', ['a', 'b'])
228 self.assertRaises(RuntimeError, _testcapi.parse_tuple_and_keywords,
229 (1,), {}, '|OO', ['a'])
230
231
Ezio Melottief1db542013-02-23 06:33:51 +0200232@unittest.skipUnless(threading and thread, 'Threading required for this test.')
Ezio Melotti2fddfd82013-02-23 05:45:37 +0200233class TestThreadState(unittest.TestCase):
Tim Peters59b96c12006-03-21 03:58:41 +0000234
Serhiy Storchakabd8c6292015-04-01 12:56:39 +0300235 @support.reap_threads
Ezio Melotti2fddfd82013-02-23 05:45:37 +0200236 def test_thread_state(self):
237 # some extra thread-state tests driven via _testcapi
238 def target():
239 idents = []
240
241 def callback():
242 idents.append(thread.get_ident())
243
244 _testcapi._test_thread_state(callback)
245 a = b = callback
246 time.sleep(1)
247 # Check our main thread is in the list exactly 3 times.
248 self.assertEqual(idents.count(thread.get_ident()), 3,
249 "Couldn't find main thread correctly in the list")
250
251 target()
252 t = threading.Thread(target=target)
253 t.start()
254 t.join()
255
256
257def test_main():
Tim Peters59b96c12006-03-21 03:58:41 +0000258 for name in dir(_testcapi):
259 if name.startswith('test_'):
260 test = getattr(_testcapi, name)
Serhiy Storchakabd8c6292015-04-01 12:56:39 +0300261 if support.verbose:
Tim Peters59b96c12006-03-21 03:58:41 +0000262 print "internal", name
263 try:
264 test()
265 except _testcapi.error:
Serhiy Storchakabd8c6292015-04-01 12:56:39 +0300266 raise support.TestFailed, sys.exc_info()[1]
Tim Peters59b96c12006-03-21 03:58:41 +0000267
Serhiy Storchakaef19fd22018-07-11 19:49:17 +0300268 support.run_unittest(CAPITest, TestPendingCalls, SkipitemTest,
269 TestThreadState)
Kristján Valur Jónsson0e2d8c32009-01-09 21:35:16 +0000270
Tim Peters59b96c12006-03-21 03:58:41 +0000271if __name__ == "__main__":
272 test_main()