|
15 | 15 | c_long, c_ulong, |
16 | 16 | c_longlong, c_ulonglong, |
17 | 17 | c_float, c_double, c_longdouble) |
| 18 | +from ctypes.util import struct |
18 | 19 | from test.support import import_helper |
19 | 20 | _ctypes_test = import_helper.import_module("_ctypes_test") |
20 | 21 |
|
@@ -168,6 +169,71 @@ def test_array_pointers(self): |
168 | 169 | self.assertRaises(TypeError, LPINT.from_param, c_long*3) |
169 | 170 | self.assertRaises(TypeError, LPINT.from_param, c_uint*3) |
170 | 171 |
|
| 172 | + def test_pointer_as_parameter(self): |
| 173 | + class Wrapper: |
| 174 | + def __init__(self, param): |
| 175 | + self._as_parameter_ = param |
| 176 | + |
| 177 | + p_int = POINTER(c_int) |
| 178 | + |
| 179 | + # Implicit byref() of a wrapped instance |
| 180 | + v = c_int(42) |
| 181 | + x = p_int.from_param(Wrapper(v)) |
| 182 | + self.assertIs(x._obj, v) |
| 183 | + |
| 184 | + # Wrapped pointer |
| 185 | + p = pointer(c_int(99)) |
| 186 | + self.assertIs(p_int.from_param(Wrapper(p)), p) |
| 187 | + |
| 188 | + # Wrapped byref() |
| 189 | + p_int.from_param(Wrapper(byref(c_int(7)))) |
| 190 | + |
| 191 | + # Wrapped array |
| 192 | + a = (c_int * 3)() |
| 193 | + self.assertIs(p_int.from_param(Wrapper(a)), a) |
| 194 | + |
| 195 | + @struct |
| 196 | + class Base: |
| 197 | + x: c_int |
| 198 | + |
| 199 | + class Derived(Base): |
| 200 | + pass |
| 201 | + |
| 202 | + p_base = POINTER(Base) |
| 203 | + |
| 204 | + # Pointer upcast of a wrapped pointer and a wrapped instance. |
| 205 | + d = Derived() |
| 206 | + pd = pointer(d) |
| 207 | + self.assertIs(p_base.from_param(Wrapper(pd)), pd) |
| 208 | + self.assertIs(p_base.from_param(Wrapper(d))._obj, d) |
| 209 | + |
| 210 | + # Nested _as_parameter_. |
| 211 | + self.assertIs(p_int.from_param(Wrapper(Wrapper(Wrapper(v))))._obj, v) |
| 212 | + |
| 213 | + # None is still accepted. |
| 214 | + self.assertIsNone(p_int.from_param(Wrapper(None))) |
| 215 | + |
| 216 | + # Type mismatches are still rejected. |
| 217 | + with self.assertRaises(TypeError): |
| 218 | + p_int.from_param(Wrapper(c_short(1))) |
| 219 | + with self.assertRaises(TypeError): |
| 220 | + p_int.from_param(Wrapper(pointer(c_short(1)))) |
| 221 | + with self.assertRaises(TypeError): |
| 222 | + p_int.from_param(Wrapper(byref(c_short(1)))) |
| 223 | + with self.assertRaises(TypeError): |
| 224 | + p_int.from_param(Wrapper((c_short * 3)())) |
| 225 | + with self.assertRaises(TypeError): |
| 226 | + p_int.from_param(Wrapper(object())) |
| 227 | + |
| 228 | + # End-to-end through a function call. The c_int must stay alive |
| 229 | + # while the returned pointer is used. |
| 230 | + func = CDLL(_ctypes_test.__file__)._testfunc_p_p |
| 231 | + func.restype = p_int |
| 232 | + func.argtypes = [p_int] |
| 233 | + v = c_int(123) |
| 234 | + result = func(Wrapper(v)) |
| 235 | + self.assertEqual(result.contents.value, 123) |
| 236 | + |
171 | 237 | def test_noctypes_argtype(self): |
172 | 238 | func = CDLL(_ctypes_test.__file__)._testfunc_p_p |
173 | 239 | func.restype = c_void_p |
|
0 commit comments