1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
from .support import HPyTest
class TestBuildValue(HPyTest):
def make_tests_module(self, test_cases):
# Creates a module with function "f", that takes index of a test case
# to execute. Argument test_cases should be a tuple with first item
# being C code of the test case.
# Generates, e.g.: case 0: return HPy_BuildValue(...);
test_cases_c_code = ["case {}: {}; break;".format(i, case[0]) for i, case in enumerate(test_cases)]
return self.make_module("""
#include <limits.h>
HPyDef_METH(f, "f", HPyFunc_O)
static HPy f_impl(HPyContext *ctx, HPy self, HPy arg)
{{
switch (HPyLong_AsLong(ctx, arg)) {{
{test_cases}
default:
HPyErr_SetString(ctx, ctx->h_ValueError, "Wrong test case number");
return HPy_NULL;
}}
}}
@EXPORT(f)
@INIT
""".format(test_cases='\n'.join(test_cases_c_code)))
def test_formats(self):
test_cases = [
('return HPy_BuildValue(ctx, "");', None),
('return HPy_BuildValue(ctx, "i", 42);', 42),
('return HPy_BuildValue(ctx, "i", 0);', 0),
('return HPy_BuildValue(ctx, "i", -1);', -1),
('return HPy_BuildValue(ctx, "I", 33);', 33),
('return HPy_BuildValue(ctx, "k", 1);', 1),
('return HPy_BuildValue(ctx, "K", 6543);', 6543),
('return HPy_BuildValue(ctx, "n", 9876);', 9876),
('return HPy_BuildValue(ctx, "l", 345L);', 345),
('return HPy_BuildValue(ctx, "l", -876L);', -876),
('return HPy_BuildValue(ctx, "L", 545LL);', 545),
('return HPy_BuildValue(ctx, "L", -344LL);', -344),
('return HPy_BuildValue(ctx, "f", 0.25f);', 0.25),
('return HPy_BuildValue(ctx, "d", 0.25);', 0.25),
('return HPy_BuildValue(ctx, "ii", -1, 1);', (-1, 1)),
('return HPy_BuildValue(ctx, "(i)", -1);', (-1,)),
('return HPy_BuildValue(ctx, "(i,i)", -1, 1);', (-1, 1)),
('return HPy_BuildValue(ctx, "(ii)", -1, 1);', (-1, 1)),
('return HPy_BuildValue(ctx, "s", "test string");', 'test string'),
('return HPy_BuildValue(ctx, "[ii]", 4, 2);', [4, 2]),
('return HPy_BuildValue(ctx, "[i,i]", 4, 2);', [4, 2]),
('return HPy_BuildValue(ctx, "[is]", 4, "2");', [4, '2']),
('return HPy_BuildValue(ctx, "[]");', []),
('return HPy_BuildValue(ctx, "[(is)((f)[kk])i]", 4, "str", 0.25, 4, 2, 14267);',
[(4, 'str'), ((0.25,), [4, 2]), 14267]),
('return HPy_BuildValue(ctx, "{s:i, s:f}", "A", 4, "B", 0.25);',
{'A':4, "B":0.25}),
('return HPy_BuildValue(ctx, "{s:(i,i), s:f}", "A", 4, 4, "B", 0.25);',
{'A':(4, 4), "B":0.25}),
('return HPy_BuildValue(ctx, "[{s:(i,i), s:f},i]", "A", 4, 4, "B", 0.25, 42);',
[{'A':(4, 4), "B":0.25}, 42]),
('return HPy_BuildValue(ctx, "({s:(i,i), s:f},[i])", "A", 4, 4, "B", 0.25, 42);',
({'A':(4, 4), "B":0.25}, [42])),
]
mod = self.make_tests_module(test_cases)
for i, (code, expected) in enumerate(test_cases):
actual = mod.f(i)
assert actual == expected, code
def test_bad_formats(self):
test_cases = [
('return HPy_BuildValue(ctx, "(q)", 42);',
"bad format char 'q' in the format string passed to HPy_BuildValue"),
('return HPy_BuildValue(ctx, "(i", 42);',
"unmatched '(' in the format string passed to HPy_BuildValue"),
('return HPy_BuildValue(ctx, "[i", 42);',
"unmatched '[' in the format string passed to HPy_BuildValue"),
('return HPy_BuildValue(ctx, "([(i)k", 42);',
"unmatched '(' in the format string passed to HPy_BuildValue"),
('return HPy_BuildValue(ctx, "(i]", 42);',
"unmatched '(' in the format string passed to HPy_BuildValue"),
('return HPy_BuildValue(ctx, "[i)", 42);',
"unmatched '[' in the format string passed to HPy_BuildValue"),
('return HPy_BuildValue(ctx, "N", 42);',
"HPy_BuildValue does not support the 'N' formatting unit."),
('return HPy_BuildValue(ctx, "{i:i", "foo", 42);',
"unmatched '{' in the format string passed to HPy_BuildValue"),
('return HPy_BuildValue(ctx, "{i:i,,}", "foo", 42);',
"unexpected ',' in the format string passed to HPy_BuildValue"),
('return HPy_BuildValue(ctx, "{i:ii,}", "foo", 42, 42);',
"missing ',' in the format string passed to HPy_BuildValue"),
('return HPy_BuildValue(ctx, "{i}", 42);',
"missing ':' in the format string passed to HPy_BuildValue"),
]
import pytest
mod = self.make_tests_module(test_cases)
for i, (code, expected_error) in enumerate(test_cases):
with pytest.raises(SystemError) as e:
mod.f(i)
assert expected_error in str(e.value), code
def test_O_and_aliases(self):
mod = self.make_module("""
HPyDef_METH(fo, "fo", HPyFunc_O)
static HPy fo_impl(HPyContext *ctx, HPy self, HPy arg)
{
return HPy_BuildValue(ctx, "O", arg);
}
HPyDef_METH(fs, "fs", HPyFunc_O)
static HPy fs_impl(HPyContext *ctx, HPy self, HPy arg)
{
return HPy_BuildValue(ctx, "S", arg);
}
@EXPORT(fo)
@EXPORT(fs)
@INIT
""")
class Dummy:
pass
obj = Dummy()
assert mod.fo(obj) == obj
assert mod.fs(obj) == obj
def test_O_with_new_object(self):
# HPy_BuildValue does not steal the reference to the object passed as 'O',
# the caller still needs to close it, otherwise -> handle leak
mod = self.make_module("""
#include <stdio.h>
HPyDef_METH(f, "f", HPyFunc_O)
static HPy f_impl(HPyContext *ctx, HPy self, HPy arg)
{
HPy o = HPyLong_FromLong(ctx, 42);
HPy result;
if (HPyLong_AsLong(ctx, arg)) {
result = HPy_BuildValue(ctx, "O", o);
} else {
result = HPy_BuildValue(ctx, "(dO)", 0.25, o);
}
HPy_Close(ctx, o);
return result;
}
@EXPORT(f)
@INIT
""")
assert mod.f(0) == (0.25, 42)
assert mod.f(1) == 42
def test_O_with_null(self):
import pytest
mod = self.make_module("""
HPyDef_METH(no_msg, "no_msg", HPyFunc_O)
static HPy no_msg_impl(HPyContext *ctx, HPy self, HPy arg)
{
if (HPyLong_AsLong(ctx, arg)) {
return HPy_BuildValue(ctx, "O", HPy_NULL);
} else {
return HPy_BuildValue(ctx, "(iO)", 42, HPy_NULL);
}
}
HPyDef_METH(with_msg, "with_msg", HPyFunc_O)
static HPy with_msg_impl(HPyContext *ctx, HPy self, HPy arg)
{
HPyErr_SetString(ctx, ctx->h_ValueError, "Some err msg that will be asserted");
return no_msg_impl(ctx, self, arg);
}
@EXPORT(with_msg)
@EXPORT(no_msg)
@INIT
""")
for i in [0, 1]:
with pytest.raises(ValueError) as e:
mod.with_msg(i)
assert "Some err msg that will be asserted" in str(e.value)
for i in [0, 1]:
with pytest.raises(SystemError) as e:
mod.no_msg(i)
assert 'HPy_NULL object passed to HPy_BuildValue' in str(e.value)
def test_OO_pars_with_new_objects(self):
mod = self.make_module("""
#include <stdio.h>
HPyDef_METH(f, "f", HPyFunc_O)
static HPy f_impl(HPyContext *ctx, HPy self, HPy arg)
{
HPy o1 = HPyLong_FromLong(ctx, 1);
HPy o2 = HPyLong_FromLong(ctx, 2);
HPy result = HPy_BuildValue(ctx, "(OO)", o1, o2);
HPy_Close(ctx, o1);
HPy_Close(ctx, o2);
return result;
}
@EXPORT(f)
@INIT
""")
assert mod.f(None) == (1, 2)
def test_num_limits(self):
test_cases = [
('return HPy_BuildValue(ctx, "(ii)", INT_MIN, INT_MAX);',),
('return HPy_BuildValue(ctx, "(ll)", LONG_MIN, LONG_MAX);',),
('return HPy_BuildValue(ctx, "(LL)", LLONG_MIN, LLONG_MAX);',),
('return HPy_BuildValue(ctx, "(iI)", -1, UINT_MAX);',),
('return HPy_BuildValue(ctx, "(ik)", -1, ULONG_MAX);',),
('return HPy_BuildValue(ctx, "(iK)", -1, ULLONG_MAX);',),
('return HPy_BuildValue(ctx, "(nn)", HPY_SSIZE_T_MIN, HPY_SSIZE_T_MAX);',),
]
mod = self.make_tests_module(test_cases)
for i, (test,) in enumerate(test_cases):
result = mod.f(i)
assert result[0] < 0, test
assert result[1] > 0, test
|