bpo-40602: Write unit tests for _Py_hashtable_t (GH-20091) · python/cpython@a482dc5

@@ -14,6 +14,7 @@

1414

#include "Python.h"

1515

#include "pycore_byteswap.h" // _Py_bswap32()

1616

#include "pycore_initconfig.h" // _Py_GetConfigsAsDict()

17+

#include "pycore_hashtable.h" // _Py_hashtable_new()

1718

#include "pycore_gc.h" // PyGC_Head

18191920

@@ -62,10 +63,97 @@ test_bswap(PyObject *self, PyObject *Py_UNUSED(args))

6263

}

6364646566+

#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+70+

static Py_uhash_t

71+

hash_char(const void *key)

72+

{

73+

char ch = (char)FROM_PTR(key);

74+

return ch;

75+

}

76+77+78+

static int

79+

hashtable_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+92+

static PyObject*

93+

test_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+101+

// Test _Py_hashtable_set()

102+

char key;

103+

for (key='a'; key <= 'z'; key++) {

104+

int value = VALUE(key);

105+

if (_Py_hashtable_set(table, TO_PTR(key), TO_PTR(value)) < 0) {

106+

_Py_hashtable_destroy(table);

107+

return PyErr_NoMemory();

108+

}

109+

}

110+

assert(table->nentries == 26);

111+

assert(table->nbuckets > table->nentries);

112+113+

// Test _Py_hashtable_get_entry()

114+

for (key='a'; key <= 'z'; key++) {

115+

_Py_hashtable_entry_t *entry = _Py_hashtable_get_entry(table, TO_PTR(key));

116+

assert(entry != NULL);

117+

assert(entry->key = TO_PTR(key));

118+

assert(entry->value = TO_PTR(VALUE(key)));

119+

}

120+121+

// Test _Py_hashtable_get()

122+

for (key='a'; key <= 'z'; key++) {

123+

void *value_ptr = _Py_hashtable_get(table, TO_PTR(key));

124+

int value = (int)FROM_PTR(value_ptr);

125+

assert(value == VALUE(key));

126+

}

127+128+

// Test _Py_hashtable_steal()

129+

key = 'p';

130+

void *value_ptr = _Py_hashtable_steal(table, TO_PTR(key));

131+

int value = (int)FROM_PTR(value_ptr);

132+

assert(value == VALUE(key));

133+134+

assert(table->nentries == 25);

135+136+

// Test _Py_hashtable_foreach()

137+

int count = 0;

138+

int res = _Py_hashtable_foreach(table, hashtable_cb, &count);

139+

assert(res == 0);

140+

assert(count == 25);

141+142+

// Test _Py_hashtable_clear()

143+

_Py_hashtable_clear(table);

144+

assert(table->nentries == 0);

145+

assert(_Py_hashtable_get(table, TO_PTR('x')) == NULL);

146+147+

_Py_hashtable_destroy(table);

148+

Py_RETURN_NONE;

149+

}

150+151+65152

static PyMethodDef TestMethods[] = {

66153

{"get_configs", get_configs, METH_NOARGS},

67154

{"get_recursion_depth", get_recursion_depth, METH_NOARGS},

68155

{"test_bswap", test_bswap, METH_NOARGS},

156+

{"test_hashtable", test_hashtable, METH_NOARGS},

69157

{NULL, NULL} /* sentinel */

70158

};

71159