blob: 8faa9fe87b53143abe8713927dd29488d7a1c700 [file] [log] [blame]
Victor Stinner23bace22019-04-18 11:37:26 +02001/*
2 * C Extension module to test Python internal C APIs (Include/internal).
3 */
4
5#if !defined(Py_BUILD_CORE_BUILTIN) && !defined(Py_BUILD_CORE_MODULE)
6# error "Py_BUILD_CORE_BUILTIN or Py_BUILD_CORE_MODULE must be defined"
7#endif
8
Hai Shi5dd21f52020-04-21 00:49:13 +08009/* Always enable assertions */
10#undef NDEBUG
11
Victor Stinner23bace22019-04-18 11:37:26 +020012#define PY_SSIZE_T_CLEAN
13
14#include "Python.h"
Victor Stinner1ae035b2020-04-17 17:47:20 +020015#include "pycore_byteswap.h" // _Py_bswap32()
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010016#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()
Victor Stinnera482dc52020-05-14 21:55:47 +020017#include "pycore_hashtable.h" // _Py_hashtable_new()
Victor Stinner01355982020-04-13 11:38:42 +020018#include "pycore_gc.h" // PyGC_Head
Victor Stinner23bace22019-04-18 11:37:26 +020019
20
21static PyObject *
22get_configs(PyObject *self, PyObject *Py_UNUSED(args))
23{
24 return _Py_GetConfigsAsDict();
25}
26
27
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010028static PyObject*
Victor Stinner1ae035b2020-04-17 17:47:20 +020029get_recursion_depth(PyObject *self, PyObject *Py_UNUSED(args))
Victor Stinner3f2f4fe2020-03-13 13:07:31 +010030{
31 PyThreadState *tstate = PyThreadState_Get();
32
33 /* subtract one to ignore the frame of the get_recursion_depth() call */
34 return PyLong_FromLong(tstate->recursion_depth - 1);
35}
36
37
Victor Stinner1ae035b2020-04-17 17:47:20 +020038static PyObject*
39test_bswap(PyObject *self, PyObject *Py_UNUSED(args))
40{
41 uint16_t u16 = _Py_bswap16(UINT16_C(0x3412));
42 if (u16 != UINT16_C(0x1234)) {
43 PyErr_Format(PyExc_AssertionError,
44 "_Py_bswap16(0x3412) returns %u", u16);
45 return NULL;
46 }
47
48 uint32_t u32 = _Py_bswap32(UINT32_C(0x78563412));
49 if (u32 != UINT32_C(0x12345678)) {
50 PyErr_Format(PyExc_AssertionError,
51 "_Py_bswap32(0x78563412) returns %lu", u32);
52 return NULL;
53 }
54
55 uint64_t u64 = _Py_bswap64(UINT64_C(0xEFCDAB9078563412));
56 if (u64 != UINT64_C(0x1234567890ABCDEF)) {
57 PyErr_Format(PyExc_AssertionError,
58 "_Py_bswap64(0xEFCDAB9078563412) returns %llu", u64);
59 return NULL;
60 }
61
62 Py_RETURN_NONE;
63}
64
65
Victor Stinnera482dc52020-05-14 21:55:47 +020066#define TO_PTR(ch) ((void*)(uintptr_t)ch)
67#define FROM_PTR(ptr) ((uintptr_t)ptr)
68#define VALUE(key) (1 + ((int)(key) - 'a'))
69
70static Py_uhash_t
71hash_char(const void *key)
72{
73 char ch = (char)FROM_PTR(key);
74 return ch;
75}
76
77
78static int
79hashtable_cb(_Py_hashtable_t *table,
80 const void *key_ptr, const void *value_ptr,
81 void *user_data)
82{
83 int *count = (int *)user_data;
84 char key = (char)FROM_PTR(key_ptr);
85 int value = (int)FROM_PTR(value_ptr);
86 assert(value == VALUE(key));
87 *count += 1;
88 return 0;
89}
90
91
92static PyObject*
93test_hashtable(PyObject *self, PyObject *Py_UNUSED(args))
94{
95 _Py_hashtable_t *table = _Py_hashtable_new(hash_char,
96 _Py_hashtable_compare_direct);
97 if (table == NULL) {
98 return PyErr_NoMemory();
99 }
100
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200101 // Using an newly allocated table must not crash
102 assert(table->nentries == 0);
103 assert(table->nbuckets > 0);
104 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
105
Victor Stinnera482dc52020-05-14 21:55:47 +0200106 // Test _Py_hashtable_set()
107 char key;
108 for (key='a'; key <= 'z'; key++) {
109 int value = VALUE(key);
110 if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) {
111 _Py_hashtable_destroy(table);
112 return PyErr_NoMemory();
113 }
114 }
115 assert(table->nentries == 26);
116 assert(table->nbuckets > table->nentries);
117
118 // Test _Py_hashtable_get_entry()
119 for (key='a'; key <= 'z'; key++) {
120 _Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key));
121 assert(entry != NULL);
Miss Islington (bot)f19ed6b2020-06-22 01:01:48 -0700122 assert(entry->key == TO_PTR(key));
123 assert(entry->value == TO_PTR(VALUE(key)));
Victor Stinnera482dc52020-05-14 21:55:47 +0200124 }
125
126 // Test _Py_hashtable_get()
127 for (key='a'; key <= 'z'; key++) {
128 void *value_ptr = _Py_hashtable_get(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200129 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200130 }
131
132 // Test _Py_hashtable_steal()
133 key = 'p';
134 void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key));
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200135 assert((int)FROM_PTR(value_ptr) == VALUE(key));
Victor Stinnera482dc52020-05-14 21:55:47 +0200136 assert(table->nentries == 25);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200137 assert(_Py_hashtable_get_entry(table, TO_PTR(key)) == NULL);
Victor Stinnera482dc52020-05-14 21:55:47 +0200138
139 // Test _Py_hashtable_foreach()
140 int count = 0;
141 int res = _Py_hashtable_foreach(table, hashtable_cb, &count);
142 assert(res == 0);
143 assert(count == 25);
144
145 // Test _Py_hashtable_clear()
146 _Py_hashtable_clear(table);
147 assert(table->nentries == 0);
Victor Stinnerd2dc8272020-05-14 22:44:32 +0200148 assert(table->nbuckets > 0);
Victor Stinnera482dc52020-05-14 21:55:47 +0200149 assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);
150
151 _Py_hashtable_destroy(table);
152 Py_RETURN_NONE;
153}
154
155
Victor Stinner23bace22019-04-18 11:37:26 +0200156static PyMethodDef TestMethods[] = {
157 {"get_configs", get_configs, METH_NOARGS},
Victor Stinner3f2f4fe2020-03-13 13:07:31 +0100158 {"get_recursion_depth", get_recursion_depth, METH_NOARGS},
Victor Stinner1ae035b2020-04-17 17:47:20 +0200159 {"test_bswap", test_bswap, METH_NOARGS},
Victor Stinnera482dc52020-05-14 21:55:47 +0200160 {"test_hashtable", test_hashtable, METH_NOARGS},
Victor Stinner23bace22019-04-18 11:37:26 +0200161 {NULL, NULL} /* sentinel */
162};
163
164
165static struct PyModuleDef _testcapimodule = {
166 PyModuleDef_HEAD_INIT,
167 "_testinternalcapi",
168 NULL,
169 -1,
170 TestMethods,
171 NULL,
172 NULL,
173 NULL,
174 NULL
175};
176
177
178PyMODINIT_FUNC
179PyInit__testinternalcapi(void)
180{
Victor Stinner01355982020-04-13 11:38:42 +0200181 PyObject *module = PyModule_Create(&_testcapimodule);
182 if (module == NULL) {
183 return NULL;
184 }
185
186 if (PyModule_AddObject(module, "SIZEOF_PYGC_HEAD",
187 PyLong_FromSsize_t(sizeof(PyGC_Head))) < 0) {
188 goto error;
189 }
190
191 return module;
192
193error:
194 Py_DECREF(module);
195 return NULL;
Victor Stinner23bace22019-04-18 11:37:26 +0200196}