this repo has no description
at trunk 5997 lines 205 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include "Python.h" 3#include "gtest/gtest.h" 4#include "structmember.h" 5 6#include "capi-fixture.h" 7#include "capi-testing.h" 8 9namespace py { 10namespace testing { 11 12using TypeExtensionApiTest = ExtensionApi; 13using TypeExtensionApiDeathTest = ExtensionApi; 14 15// Common deallocation function for types with only primitive members 16static void deallocLeafObject(PyObject* self) { 17 PyTypeObject* type = Py_TYPE(self); 18 PyObject_Del(self); 19 Py_DECREF(type); 20} 21 22TEST_F(TypeExtensionApiTest, PyTypeCheckOnLong) { 23 PyObjectPtr pylong(PyLong_FromLong(10)); 24 EXPECT_FALSE(PyType_Check(pylong)); 25 EXPECT_FALSE(PyType_CheckExact(pylong)); 26} 27 28TEST_F(TypeExtensionApiTest, PyTypeCheckOnType) { 29 PyObjectPtr pylong(PyLong_FromLong(10)); 30 PyObjectPtr pylong_type(PyObject_Type(pylong)); 31 EXPECT_TRUE(PyType_Check(pylong_type)); 32 EXPECT_TRUE(PyType_CheckExact(pylong_type)); 33} 34 35TEST_F(TypeExtensionApiTest, 36 PyTypeGenericNewWithTypeWithoutNativeDataReturnsPyObject) { 37 PyType_Slot slots[] = { 38 {Py_tp_new, reinterpret_cast<void*>(PyType_GenericNew)}, 39 {0, nullptr}, 40 }; 41 static PyType_Spec spec; 42 spec = { 43 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots, 44 }; 45 PyObjectPtr ext_type(PyType_FromSpec(&spec)); 46 ASSERT_NE(ext_type, nullptr); 47 ASSERT_TRUE(PyType_CheckExact(ext_type)); 48 EXPECT_EQ(PyType_GetSlot(ext_type.asTypeObject(), Py_tp_new), 49 reinterpret_cast<void*>(PyType_GenericNew)); 50 auto new_slot = reinterpret_cast<newfunc>( 51 PyType_GetSlot(ext_type.asTypeObject(), Py_tp_new)); 52 PyObjectPtr args(PyTuple_New(0)); 53 PyObjectPtr kwargs(PyDict_New()); 54 PyObjectPtr result(new_slot(ext_type.asTypeObject(), args, kwargs)); 55 ASSERT_NE(result, nullptr); 56 EXPECT_EQ(PyObject_IsInstance(result, ext_type), 1); 57 58 // Ensure that a managed subtype of the native type can be created 59 // via its __new__ function. 60 testing::moduleSet("__main__", "Bar", ext_type); 61 EXPECT_EQ(PyRun_SimpleString(R"( 62class SubBar(Bar): 63 pass 64 65s = SubBar() 66)"), 67 0); 68} 69 70TEST_F(TypeExtensionApiDeathTest, GetFlagsFromManagedTypePyro) { 71 PyRun_SimpleString(R"(class Foo: pass)"); 72 PyObjectPtr foo_type(testing::mainModuleGet("Foo")); 73 ASSERT_TRUE(PyType_CheckExact(foo_type)); 74 EXPECT_DEATH( 75 PyType_GetFlags(reinterpret_cast<PyTypeObject*>(foo_type.get())), 76 "unimplemented: GetFlags from types initialized through Python code"); 77} 78 79TEST_F(TypeExtensionApiTest, GetFlagsFromExtensionTypeReturnsSetFlags) { 80 PyType_Slot slots[] = { 81 {0, nullptr}, 82 }; 83 static PyType_Spec spec; 84 spec = { 85 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 86 }; 87 PyObjectPtr type(PyType_FromSpec(&spec)); 88 ASSERT_NE(type, nullptr); 89 ASSERT_TRUE(PyType_CheckExact(type)); 90 91 EXPECT_TRUE(PyType_GetFlags(reinterpret_cast<PyTypeObject*>(type.get())) & 92 Py_TPFLAGS_DEFAULT); 93 EXPECT_TRUE(PyType_GetFlags(reinterpret_cast<PyTypeObject*>(type.get())) & 94 Py_TPFLAGS_READY); 95 EXPECT_TRUE(PyType_GetFlags(reinterpret_cast<PyTypeObject*>(type.get())) & 96 Py_TPFLAGS_HEAPTYPE); 97} 98 99TEST_F(TypeExtensionApiTest, FromSpecCreatesRuntimeType) { 100 PyType_Slot slots[] = { 101 {0, nullptr}, 102 }; 103 static PyType_Spec spec; 104 spec = { 105 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 106 }; 107 PyObjectPtr type(PyType_FromSpec(&spec)); 108 ASSERT_NE(type, nullptr); 109 ASSERT_TRUE(PyType_CheckExact(type)); 110 111 testing::moduleSet("__main__", "Empty", type); 112 PyRun_SimpleString("x = Empty"); 113 PyObjectPtr result(testing::mainModuleGet("x")); 114 EXPECT_TRUE(PyType_CheckExact(result)); 115 PyObjectPtr module(PyObject_GetAttrString(result, "__module__")); 116 EXPECT_TRUE(isUnicodeEqualsCStr(module, "foo")); 117 PyObjectPtr name(PyObject_GetAttrString(result, "__name__")); 118 EXPECT_TRUE(isUnicodeEqualsCStr(name, "Bar")); 119 PyObjectPtr qualname(PyObject_GetAttrString(result, "__qualname__")); 120 EXPECT_TRUE(isUnicodeEqualsCStr(qualname, "Bar")); 121} 122 123TEST_F(TypeExtensionApiTest, FromSpecWithInvalidSlotRaisesError) { 124 PyType_Slot slots[] = { 125 {-1, nullptr}, 126 {0, nullptr}, 127 }; 128 static PyType_Spec spec; 129 spec = { 130 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 131 }; 132 ASSERT_EQ(PyType_FromSpec(&spec), nullptr); 133 ASSERT_NE(PyErr_Occurred(), nullptr); 134 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_RuntimeError)); 135 // TODO(eelizondo): Check that error matches with "invalid slot offset" 136} 137 138TEST_F(TypeExtensionApiTest, 139 FromSpecWithZeroBasicSizeAndItemSetsTpNewOfManagedTypePyro) { 140 PyType_Slot slots[] = { 141 {0, nullptr}, 142 }; 143 static PyType_Spec spec; 144 spec = { 145 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 146 }; 147 PyObjectPtr ext_type(PyType_FromSpec(&spec)); 148 ASSERT_NE(ext_type, nullptr); 149 ASSERT_TRUE(PyType_CheckExact(ext_type)); 150 151 PyRun_SimpleString(R"(class D: pass)"); 152 PyObjectPtr managed_type(mainModuleGet("D")); 153 ASSERT_NE(PyType_GetSlot(managed_type.asTypeObject(), Py_tp_new), nullptr); 154 155 // Instances of `ext_type` does not cause any memory leak. 156 auto new_slot = reinterpret_cast<newfunc>( 157 PyType_GetSlot(ext_type.asTypeObject(), Py_tp_new)); 158 PyObjectPtr args(PyTuple_New(0)); 159 PyObjectPtr kwargs(PyDict_New()); 160 PyObjectPtr result(new_slot(ext_type.asTypeObject(), args, kwargs)); 161 ASSERT_NE(result, nullptr); 162 EXPECT_EQ(PyObject_IsInstance(result, ext_type), 1); 163} 164 165TEST_F(TypeExtensionApiTest, 166 FromSpecWithNonZeroBasicSizeAndItemSetsCustomTpNewPyro) { 167 PyType_Slot slots[] = { 168 {0, nullptr}, 169 }; 170 struct BarState { 171 PyObject_HEAD 172 int foo; 173 }; 174 static PyType_Spec spec; 175 spec = { 176 "foo.Bar", sizeof(BarState), 0, Py_TPFLAGS_DEFAULT, slots, 177 }; 178 PyObjectPtr ext_type(PyType_FromSpec(&spec)); 179 ASSERT_NE(ext_type, nullptr); 180 ASSERT_TRUE(PyType_CheckExact(ext_type)); 181 182 PyRun_SimpleString(R"(class D: pass)"); 183 PyObjectPtr managed_type(mainModuleGet("D")); 184 ASSERT_NE(PyType_GetSlot(managed_type.asTypeObject(), Py_tp_new), nullptr); 185 EXPECT_NE(PyType_GetSlot(managed_type.asTypeObject(), Py_tp_new), 186 PyType_GetSlot(ext_type.asTypeObject(), Py_tp_new)); 187 188 // Instances of `ext_type` does not cause any memory leak. 189 auto new_slot = reinterpret_cast<newfunc>( 190 PyType_GetSlot(ext_type.asTypeObject(), Py_tp_new)); 191 PyObjectPtr args(PyTuple_New(0)); 192 PyObjectPtr kwargs(PyDict_New()); 193 PyObjectPtr result(new_slot(ext_type.asTypeObject(), args, kwargs)); 194 ASSERT_NE(result, nullptr); 195 EXPECT_EQ(PyObject_IsInstance(result, ext_type), 1); 196} 197 198TEST_F(TypeExtensionApiTest, CallExtensionTypeReturnsExtensionInstancePyro) { 199 struct BarObject { 200 PyObject_HEAD 201 int value; 202 }; 203 newfunc new_func = [](PyTypeObject* type, PyObject*, PyObject*) { 204 void* slot = PyType_GetSlot(type, Py_tp_alloc); 205 return reinterpret_cast<allocfunc>(slot)(type, 0); 206 }; 207 initproc init_func = [](PyObject* self, PyObject*, PyObject*) { 208 reinterpret_cast<BarObject*>(self)->value = 30; 209 return 0; 210 }; 211 PyType_Slot slots[] = { 212 {Py_tp_alloc, reinterpret_cast<void*>(PyType_GenericAlloc)}, 213 {Py_tp_new, reinterpret_cast<void*>(new_func)}, 214 {Py_tp_init, reinterpret_cast<void*>(init_func)}, 215 {Py_tp_dealloc, reinterpret_cast<void*>(deallocLeafObject)}, 216 {0, nullptr}, 217 }; 218 static PyType_Spec spec; 219 spec = { 220 "foo.Bar", sizeof(BarObject), 0, Py_TPFLAGS_DEFAULT, slots, 221 }; 222 PyObjectPtr type(PyType_FromSpec(&spec)); 223 ASSERT_NE(type, nullptr); 224 ASSERT_TRUE(PyType_CheckExact(type)); 225 226 testing::moduleSet("__main__", "Bar", type); 227 PyRun_SimpleString(R"( 228bar = Bar() 229)"); 230 231 PyObjectPtr bar(testing::mainModuleGet("bar")); 232 ASSERT_NE(bar, nullptr); 233 BarObject* barobj = reinterpret_cast<BarObject*>(bar.get()); 234 EXPECT_EQ(barobj->value, 30); 235} 236 237TEST_F(TypeExtensionApiTest, GenericAllocationReturnsMallocMemory) { 238 // These numbers determine the allocated size of the PyObject 239 // The values in this test are abitrary and are usally set with `sizeof(Foo)` 240 int basic_size = sizeof(PyObject) + 10; 241 int item_size = 5; 242 PyType_Slot slots[] = { 243 {Py_tp_dealloc, reinterpret_cast<void*>(deallocLeafObject)}, 244 {0, nullptr}, 245 }; 246 static PyType_Spec spec; 247 spec = { 248 "foo.Bar", basic_size, item_size, Py_TPFLAGS_DEFAULT, slots, 249 }; 250 PyObjectPtr type(PyType_FromSpec(&spec)); 251 ASSERT_NE(type, nullptr); 252 ASSERT_TRUE(PyType_CheckExact(type)); 253 254 PyObjectPtr result(PyType_GenericAlloc( 255 reinterpret_cast<PyTypeObject*>(type.get()), item_size)); 256 ASSERT_NE(result, nullptr); 257 ASSERT_GE(Py_REFCNT(result), 1); // CPython 258 ASSERT_LE(Py_REFCNT(result), 2); // Pyro 259 EXPECT_EQ(Py_SIZE(result.get()), item_size); 260} 261 262TEST_F(TypeExtensionApiTest, GetSlotTpNewOnManagedTypeReturnsSlot) { 263 ASSERT_EQ(PyRun_SimpleString(R"( 264class Foo: 265 def __new__(ty, a, b, c, d): 266 obj = super().__new__(ty) 267 obj.args = (a, b, c, d) 268 return obj 269)"), 270 0); 271 272 PyObjectPtr foo(mainModuleGet("Foo")); 273 auto new_slot = 274 reinterpret_cast<newfunc>(PyType_GetSlot(foo.asTypeObject(), Py_tp_new)); 275 ASSERT_NE(new_slot, nullptr); 276 PyObjectPtr one(PyLong_FromLong(1)); 277 PyObjectPtr two(PyLong_FromLong(2)); 278 PyObjectPtr cee(PyUnicode_FromString("cee")); 279 PyObjectPtr dee(PyUnicode_FromString("dee")); 280 PyObjectPtr args(PyTuple_Pack(2, one.get(), two.get())); 281 PyObjectPtr kwargs(PyDict_New()); 282 PyDict_SetItemString(kwargs, "d", dee); 283 PyDict_SetItemString(kwargs, "c", cee); 284 285 PyObjectPtr result(new_slot(foo.asTypeObject(), args, kwargs)); 286 ASSERT_NE(result, nullptr); 287 ASSERT_EQ(PyObject_IsInstance(result, foo), 1); 288 PyObjectPtr obj_args(PyObject_GetAttrString(result, "args")); 289 ASSERT_NE(obj_args, nullptr); 290 ASSERT_EQ(PyTuple_CheckExact(obj_args), 1); 291 ASSERT_EQ(PyTuple_Size(obj_args), 4); 292 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(obj_args, 0), 1)); 293 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(obj_args, 1), 2)); 294 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(obj_args, 2), "cee")); 295 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(obj_args, 3), "dee")); 296} 297 298TEST_F(TypeExtensionApiTest, IsSubtypeWithSameTypeReturnsTrue) { 299 PyObjectPtr pylong(PyLong_FromLong(10)); 300 PyObjectPtr pylong_type(PyObject_Type(pylong)); 301 EXPECT_TRUE( 302 PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(pylong_type.get()), 303 reinterpret_cast<PyTypeObject*>(pylong_type.get()))); 304} 305 306TEST_F(TypeExtensionApiTest, IsSubtypeWithSubtypeReturnsTrue) { 307 EXPECT_EQ(PyRun_SimpleString("class MyFloat(float): pass"), 0); 308 PyObjectPtr pyfloat(PyFloat_FromDouble(1.23)); 309 PyObjectPtr pyfloat_type(PyObject_Type(pyfloat)); 310 PyObjectPtr myfloat_type(mainModuleGet("MyFloat")); 311 EXPECT_TRUE( 312 PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(myfloat_type.get()), 313 reinterpret_cast<PyTypeObject*>(pyfloat_type.get()))); 314} 315 316TEST_F(TypeExtensionApiTest, IsSubtypeWithDifferentTypesReturnsFalse) { 317 PyObjectPtr pylong(PyLong_FromLong(10)); 318 PyObjectPtr pylong_type(PyObject_Type(pylong)); 319 PyObjectPtr pyuni(PyUnicode_FromString("string")); 320 PyObjectPtr pyuni_type(PyObject_Type(pyuni)); 321 EXPECT_FALSE( 322 PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(pylong_type.get()), 323 reinterpret_cast<PyTypeObject*>(pyuni_type.get()))); 324} 325 326TEST_F(TypeExtensionApiTest, PyTypeModifiedWithHeapTypeDoesNothing) { 327 PyRun_SimpleString(R"( 328class C: 329 pass 330)"); 331 PyObjectPtr c(mainModuleGet("C")); 332 PyType_Modified(c.asTypeObject()); 333} 334 335TEST_F(TypeExtensionApiTest, GetSlotFromBuiltinTypeRaisesSystemError) { 336 PyObjectPtr pylong(PyLong_FromLong(5)); 337 PyObjectPtr pylong_type(PyObject_Type(pylong)); 338 ASSERT_TRUE( 339 PyType_CheckExact(reinterpret_cast<PyTypeObject*>(pylong_type.get()))); 340 341 EXPECT_EQ(PyType_GetSlot(reinterpret_cast<PyTypeObject*>(pylong_type.get()), 342 Py_tp_init), 343 nullptr); 344 ASSERT_NE(PyErr_Occurred(), nullptr); 345 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 346} 347 348TEST_F(TypeExtensionApiDeathTest, 349 GetSlotFromManagedTypeReturnsFunctionPointerPyro) { 350 PyRun_SimpleString(R"( 351class Foo: 352 def __init__(self): 353 pass 354 )"); 355 356 PyObjectPtr foo_type(testing::mainModuleGet("Foo")); 357 ASSERT_TRUE(PyType_CheckExact(foo_type)); 358 EXPECT_DEATH(PyType_GetSlot(reinterpret_cast<PyTypeObject*>(foo_type.get()), 359 Py_tp_init), 360 "Unsupported default slot"); 361} 362 363TEST_F(TypeExtensionApiTest, GetUnsupportedSlotFromManagedTypeAbortsPyro) { 364 PyRun_SimpleString(R"( 365class Foo: pass 366 )"); 367 368 PyObjectPtr foo_type(testing::mainModuleGet("Foo")); 369 ASSERT_TRUE(PyType_CheckExact(foo_type)); 370 EXPECT_DEATH( 371 PyType_GetSlot(reinterpret_cast<PyTypeObject*>(foo_type.get()), Py_nb_or), 372 "Unsupported default slot"); 373} 374 375TEST_F(TypeExtensionApiTest, GetSetDescriptorTypeMatchesPyTpGetSet) { 376 struct BarObject { 377 PyObject_HEAD 378 long attribute; 379 }; 380 381 getter attribute_getter = [](PyObject* self, void*) { 382 return PyLong_FromLong(reinterpret_cast<BarObject*>(self)->attribute); 383 }; 384 385 setter attribute_setter = [](PyObject* self, PyObject* value, void*) { 386 reinterpret_cast<BarObject*>(self)->attribute = PyLong_AsLong(value); 387 return 0; 388 }; 389 390 static PyGetSetDef getsets[2]; 391 getsets[0] = {"attribute", attribute_getter, attribute_setter}; 392 getsets[1] = {nullptr}; 393 394 static PyType_Slot slots[2]; 395 slots[0] = {Py_tp_getset, reinterpret_cast<void*>(getsets)}; 396 slots[1] = {0, nullptr}; 397 static PyType_Spec spec; 398 spec = { 399 "__main__.Bar", sizeof(BarObject), 0, Py_TPFLAGS_DEFAULT, slots, 400 }; 401 PyObjectPtr type(PyType_FromSpec(&spec)); 402 ASSERT_EQ(PyType_CheckExact(type), 1); 403 ASSERT_EQ(moduleSet("__main__", "Bar", type), 0); 404 PyRun_SimpleString(R"( 405import types 406descrType = types.GetSetDescriptorType 407tpType = type(Bar.__dict__['attribute']) 408)"); 409 PyObjectPtr descr_type(testing::mainModuleGet("descrType")); 410 PyObjectPtr tp_type(testing::mainModuleGet("tpType")); 411 ASSERT_EQ(descr_type, tp_type); 412} 413 414TEST_F(TypeExtensionApiTest, GetSlotFromNegativeSlotRaisesSystemError) { 415 PyRun_SimpleString(R"( 416class Foo: pass 417 )"); 418 419 PyObjectPtr foo_type(testing::mainModuleGet("Foo")); 420 ASSERT_TRUE(PyType_CheckExact(foo_type)); 421 422 EXPECT_EQ(PyType_GetSlot(reinterpret_cast<PyTypeObject*>(foo_type.get()), -1), 423 nullptr); 424 425 ASSERT_NE(PyErr_Occurred(), nullptr); 426 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 427} 428 429TEST_F(TypeExtensionApiTest, GetSlotFromLargerThanMaxSlotReturnsNull) { 430 PyRun_SimpleString(R"( 431class Foo: pass 432 )"); 433 434 PyObjectPtr foo_type(testing::mainModuleGet("Foo")); 435 ASSERT_TRUE(PyType_CheckExact(foo_type)); 436 437 EXPECT_EQ( 438 PyType_GetSlot(reinterpret_cast<PyTypeObject*>(foo_type.get()), 1000), 439 nullptr); 440 EXPECT_EQ(PyErr_Occurred(), nullptr); 441} 442 443TEST_F(TypeExtensionApiTest, GetSlotFromExtensionType) { 444 newfunc new_func = [](PyTypeObject* type, PyObject*, PyObject*) { 445 void* slot = PyType_GetSlot(type, Py_tp_alloc); 446 return reinterpret_cast<allocfunc>(slot)(type, 0); 447 }; 448 initproc init_func = [](PyObject*, PyObject*, PyObject*) { return 0; }; 449 binaryfunc add_func = [](PyObject*, PyObject*) { return PyLong_FromLong(7); }; 450 PyType_Slot slots[] = { 451 {Py_tp_alloc, reinterpret_cast<void*>(PyType_GenericAlloc)}, 452 {Py_tp_new, reinterpret_cast<void*>(new_func)}, 453 {Py_tp_init, reinterpret_cast<void*>(init_func)}, 454 {Py_nb_add, reinterpret_cast<void*>(add_func)}, 455 {0, nullptr}, 456 }; 457 static PyType_Spec spec; 458 spec = { 459 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 460 }; 461 PyObjectPtr type(PyType_FromSpec(&spec)); 462 ASSERT_NE(type, nullptr); 463 ASSERT_TRUE(PyType_CheckExact(type)); 464 465 PyTypeObject* typeobj = reinterpret_cast<PyTypeObject*>(type.get()); 466 EXPECT_EQ(PyType_GetSlot(typeobj, Py_tp_alloc), 467 reinterpret_cast<void*>(PyType_GenericAlloc)); 468 EXPECT_EQ(PyType_GetSlot(typeobj, Py_tp_new), 469 reinterpret_cast<void*>(new_func)); 470 EXPECT_EQ(PyType_GetSlot(typeobj, Py_tp_init), 471 reinterpret_cast<void*>(init_func)); 472 EXPECT_EQ(PyType_GetSlot(typeobj, Py_nb_add), 473 reinterpret_cast<void*>(add_func)); 474 EXPECT_EQ(PyErr_Occurred(), nullptr); 475} 476 477TEST_F(TypeExtensionApiTest, DunderBasicsizeWithExtensionTypeReturnsBasicsize) { 478 PyType_Slot slots[] = { 479 {0, nullptr}, 480 }; 481 int size = sizeof(PyObject) + 13; 482 static PyType_Spec spec; 483 spec = { 484 "foo.Bar", size, 0, Py_TPFLAGS_DEFAULT, slots, 485 }; 486 PyObjectPtr type(PyType_FromSpec(&spec)); 487 ASSERT_NE(type, nullptr); 488 PyObjectPtr basicsize(PyObject_GetAttrString(type, "__basicsize__")); 489 ASSERT_NE(basicsize, nullptr); 490 EXPECT_TRUE(isLongEqualsLong(basicsize, size)); 491} 492 493TEST_F(TypeExtensionApiTest, 494 DunderBasicsizeExtensionTypeWithZeroSizeReturnsBasicsize) { 495 PyType_Slot slots[] = { 496 {0, nullptr}, 497 }; 498 static PyType_Spec spec; 499 spec = { 500 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 501 }; 502 PyObjectPtr type(PyType_FromSpec(&spec)); 503 ASSERT_NE(type, nullptr); 504 PyObjectPtr basicsize(PyObject_GetAttrString(type, "__basicsize__")); 505 ASSERT_NE(basicsize, nullptr); 506 EXPECT_TRUE(isLongEqualsLong(basicsize, sizeof(PyObject))); 507} 508 509TEST_F(TypeExtensionApiTest, 510 DunderBasicsizeExtensionTypeWithHeadSizeReturnsBasicsize) { 511 PyType_Slot slots[] = { 512 {0, nullptr}, 513 }; 514 static PyType_Spec spec; 515 spec = { 516 "foo.Bar", sizeof(PyObject), 0, Py_TPFLAGS_DEFAULT, slots, 517 }; 518 PyObjectPtr type(PyType_FromSpec(&spec)); 519 ASSERT_NE(type, nullptr); 520 PyObjectPtr basicsize(PyObject_GetAttrString(type, "__basicsize__")); 521 ASSERT_NE(basicsize, nullptr); 522 EXPECT_TRUE(isLongEqualsLong(basicsize, sizeof(PyObject))); 523} 524 525TEST_F(TypeExtensionApiTest, 526 MembersWithoutDunderDictoffsetReturnsTypeWithoutDunderDict) { 527 PyType_Slot slots[] = { 528 {0, nullptr}, 529 }; 530 static PyType_Spec spec; 531 spec = {"foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots}; 532 PyObjectPtr type(PyType_FromSpec(&spec)); 533 ASSERT_NE(type, nullptr); 534 535 // Cannot set arbitrary attributes on instances. 536 PyObjectPtr instance(PyObject_CallObject(type, nullptr)); 537 ASSERT_NE(instance, nullptr); 538 PyObjectPtr value(PyUnicode_FromString("world")); 539 EXPECT_EQ(PyObject_SetAttrString(instance, "hello", value), -1); 540 ASSERT_NE(PyErr_Occurred(), nullptr); 541 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError)); 542 PyErr_Clear(); 543 544 // Has no `__dict__`. 545 EXPECT_EQ(PyObject_GetAttrString(instance, "__dict__"), nullptr); 546 PyErr_Clear(); 547} 548 549TEST_F(TypeExtensionApiTest, 550 MembersWithDunderDictoffsetReturnsTypeWithDunderDict) { 551 struct BarObject { 552 PyObject_HEAD 553 PyObject* dict; 554 }; 555 static PyMemberDef members[2]; 556 members[0] = {"__dictoffset__", T_PYSSIZET, offsetof(BarObject, dict), 557 READONLY}; 558 members[1] = {nullptr}; 559 560 PyType_Slot slots[] = { 561 {Py_tp_members, members}, 562 {0, nullptr}, 563 }; 564 static PyType_Spec spec; 565 spec = {"foo.Bar", 0, sizeof(BarObject), Py_TPFLAGS_DEFAULT, slots}; 566 PyObjectPtr type(PyType_FromSpec(&spec)); 567 ASSERT_NE(type, nullptr); 568 569 // Can set arbitrary attributes on instances. 570 PyObjectPtr instance(PyObject_CallObject(type, nullptr)); 571 ASSERT_NE(instance, nullptr); 572 PyObjectPtr value(PyUnicode_FromString("world")); 573 EXPECT_EQ(PyObject_SetAttrString(instance, "hello", value), 0); 574 PyObjectPtr item(PyObject_GetAttrString(instance, "hello")); 575 EXPECT_TRUE(isUnicodeEqualsCStr(item, "world")); 576} 577 578TEST_F(TypeExtensionApiTest, MemberDescriptorTypeMatchesPyTpMembers) { 579 struct BarObject { 580 PyObject_HEAD 581 int value; 582 }; 583 584 static PyMemberDef members[2]; 585 members[0] = {"value", T_INT, offsetof(BarObject, value)}; 586 members[1] = {nullptr}; 587 588 static const PyType_Slot slots[] = { 589 {Py_tp_members, const_cast<PyMemberDef*>(members)}, 590 {0, nullptr}, 591 }; 592 static PyType_Spec spec = { 593 "__main__.Bar", 594 sizeof(BarObject), 595 0, 596 Py_TPFLAGS_DEFAULT, 597 const_cast<PyType_Slot*>(slots), 598 }; 599 PyObjectPtr type(PyType_FromSpec(&spec)); 600 testing::moduleSet("__main__", "Bar", type); 601 PyRun_SimpleString(R"( 602import types 603descrType = types.MemberDescriptorType 604tpType = type(Bar.__dict__['value']) 605)"); 606 PyObjectPtr descr_type(testing::mainModuleGet("descrType")); 607 PyObjectPtr tp_type(testing::mainModuleGet("tpType")); 608 ASSERT_EQ(descr_type, tp_type); 609} 610 611// METH_NOARGS and CALL_FUNCTION 612 613TEST_F(TypeExtensionApiTest, MethodsMethNoargsPosCall) { 614 binaryfunc meth = [](PyObject*, PyObject*) { return PyLong_FromLong(1234); }; 615 static PyMethodDef methods[] = {{"noargs", meth, METH_NOARGS}, {nullptr}}; 616 PyType_Slot slots[] = { 617 {Py_tp_methods, methods}, 618 {0, nullptr}, 619 }; 620 static PyType_Spec spec; 621 spec = { 622 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 623 }; 624 PyObjectPtr type(PyType_FromSpec(&spec)); 625 ASSERT_NE(type, nullptr); 626 testing::moduleSet("__main__", "C", type); 627 PyRun_SimpleString(R"( 628result = C().noargs() 629)"); 630 PyObjectPtr result(testing::mainModuleGet("result")); 631 ASSERT_NE(result, nullptr); 632 EXPECT_EQ(PyLong_AsLong(result), 1234); 633} 634 635// METH_NOARGS | METH_CLASS | METH_STATIC and CALL_FUNCTION 636 637TEST_F(TypeExtensionApiTest, MethodsClassAndStaticRaisesValueError) { 638 binaryfunc meth = [](PyObject*, PyObject*) { return PyLong_FromLong(1234); }; 639 static PyMethodDef methods[] = { 640 {"noargs", meth, METH_NOARGS | METH_CLASS | METH_STATIC}, {nullptr}}; 641 PyType_Slot slots[] = { 642 {Py_tp_methods, methods}, 643 {0, nullptr}, 644 }; 645 static PyType_Spec spec; 646 spec = { 647 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 648 }; 649 EXPECT_EQ(PyType_FromSpec(&spec), nullptr); 650 ASSERT_NE(PyErr_Occurred(), nullptr); 651 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError)); 652} 653 654TEST_F(TypeExtensionApiTest, 655 MethodsWithTypeSlotNameCoExistGetsResolvedForFunctionCall) { 656 newfunc new_func = [](PyTypeObject*, PyObject*, PyObject*) { 657 return PyLong_FromLong(100); 658 }; 659 binaryfunc meth = [](PyObject*, PyObject*) { return PyLong_FromLong(200); }; 660 static PyMethodDef methods[] = { 661 {"__new__", meth, METH_NOARGS | METH_STATIC | METH_COEXIST}, {nullptr}}; 662 PyType_Slot slots[] = { 663 {Py_tp_new, reinterpret_cast<void*>(new_func)}, 664 {Py_tp_methods, methods}, 665 {0, nullptr}, 666 }; 667 static PyType_Spec spec; 668 spec = { 669 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 670 }; 671 PyObjectPtr type(PyType_FromSpec(&spec)); 672 ASSERT_EQ(PyErr_Occurred(), nullptr); 673 EXPECT_EQ( 674 reinterpret_cast<newfunc>(PyType_GetSlot(type.asTypeObject(), Py_tp_new)), 675 new_func); 676 testing::moduleSet("__main__", "C", type); 677 PyRun_SimpleString(R"( 678result = C.__new__() 679)"); 680 PyObjectPtr result(testing::moduleGet("__main__", "result")); 681 ASSERT_NE(result, nullptr); 682 EXPECT_EQ(PyLong_AsLong(result), 200); 683} 684 685TEST_F(TypeExtensionApiTest, MethodsWithTypeSlotNameClassAndStaticGetsIgnored) { 686 newfunc new_func = [](PyTypeObject*, PyObject*, PyObject*) { 687 return PyLong_FromLong(100); 688 }; 689 binaryfunc meth = [](PyObject*, PyObject*) { return PyLong_FromLong(200); }; 690 static PyMethodDef methods[] = {{"__new__", meth, METH_NOARGS | METH_STATIC}, 691 {nullptr}}; 692 PyType_Slot slots[] = { 693 {Py_tp_new, reinterpret_cast<void*>(new_func)}, 694 {Py_tp_methods, methods}, 695 {0, nullptr}, 696 }; 697 static PyType_Spec spec; 698 spec = { 699 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 700 }; 701 PyObjectPtr type(PyType_FromSpec(&spec)); 702 ASSERT_EQ(PyErr_Occurred(), nullptr); 703 EXPECT_EQ( 704 reinterpret_cast<newfunc>(PyType_GetSlot(type.asTypeObject(), Py_tp_new)), 705 new_func); 706 testing::moduleSet("__main__", "C", type); 707 PyRun_SimpleString(R"( 708result = C.__new__(C) 709)"); 710 PyObjectPtr result(testing::moduleGet("__main__", "result")); 711 ASSERT_NE(result, nullptr); 712 EXPECT_EQ(PyLong_AsLong(result), 100); 713} 714 715// METH_NOARGS and CALL_FUNCTION_EX 716 717TEST_F(TypeExtensionApiTest, MethodsMethNoargsExCall) { 718 binaryfunc meth = [](PyObject*, PyObject*) { return PyLong_FromLong(1234); }; 719 static PyMethodDef methods[] = {{"noargs", meth, METH_NOARGS}, {nullptr}}; 720 PyType_Slot slots[] = { 721 {Py_tp_methods, methods}, 722 {0, nullptr}, 723 }; 724 static PyType_Spec spec; 725 spec = { 726 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 727 }; 728 PyObjectPtr type(PyType_FromSpec(&spec)); 729 ASSERT_NE(type, nullptr); 730 testing::moduleSet("__main__", "C", type); 731 PyRun_SimpleString(R"( 732result = C().noargs(*[]) 733)"); 734 PyObjectPtr result(testing::mainModuleGet("result")); 735 ASSERT_NE(result, nullptr); 736 EXPECT_EQ(PyLong_AsLong(result), 1234); 737} 738 739// METH_NOARGS and CALL_FUNCTION_EX with VARKEYWORDS 740 741TEST_F(TypeExtensionApiTest, MethodsMethNoargsExNoKwargsCall) { 742 binaryfunc meth = [](PyObject*, PyObject*) { return PyLong_FromLong(1234); }; 743 static PyMethodDef methods[] = {{"noargs", meth, METH_NOARGS}, {nullptr}}; 744 PyType_Slot slots[] = { 745 {Py_tp_methods, methods}, 746 {0, nullptr}, 747 }; 748 static PyType_Spec spec; 749 spec = { 750 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 751 }; 752 PyObjectPtr type(PyType_FromSpec(&spec)); 753 ASSERT_NE(type, nullptr); 754 testing::moduleSet("__main__", "C", type); 755 PyRun_SimpleString(R"( 756result = C().noargs(*[],**{}) 757)"); 758 PyObjectPtr result(testing::mainModuleGet("result")); 759 ASSERT_NE(result, nullptr); 760 EXPECT_EQ(PyLong_AsLong(result), 1234); 761} 762 763TEST_F(TypeExtensionApiTest, MethodsMethNoargsExHasKwargsRaisesTypeError) { 764 binaryfunc meth = [](PyObject*, PyObject*) { return PyLong_FromLong(1234); }; 765 static PyMethodDef methods[] = {{"noargs", meth, METH_NOARGS}, {nullptr}}; 766 PyType_Slot slots[] = { 767 {Py_tp_methods, methods}, 768 {0, nullptr}, 769 }; 770 static PyType_Spec spec; 771 spec = { 772 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 773 }; 774 PyObjectPtr type(PyType_FromSpec(&spec)); 775 ASSERT_NE(type, nullptr); 776 testing::moduleSet("__main__", "C", type); 777 PyRun_SimpleString(R"( 778self = C() 779result = False 780try: 781 self.noargs(*[],**{'foo': 'bar'}) 782except: 783 result = True 784)"); 785 PyObjectPtr result(testing::mainModuleGet("result")); 786 ASSERT_EQ(result, Py_True); 787} 788 789// METH_O and CALL_FUNCTION 790 791TEST_F(TypeExtensionApiTest, MethodsMethOneArgPosCall) { 792 binaryfunc meth = [](PyObject* self, PyObject* arg) { 793 return PyTuple_Pack(2, self, arg); 794 }; 795 static PyMethodDef methods[] = {{"onearg", meth, METH_O}, {nullptr}}; 796 PyType_Slot slots[] = { 797 {Py_tp_methods, methods}, 798 {0, nullptr}, 799 }; 800 static PyType_Spec spec; 801 spec = { 802 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 803 }; 804 PyObjectPtr type(PyType_FromSpec(&spec)); 805 ASSERT_NE(type, nullptr); 806 testing::moduleSet("__main__", "C", type); 807 PyRun_SimpleString(R"( 808self = C() 809result = self.onearg(1234) 810)"); 811 PyObjectPtr self(testing::mainModuleGet("self")); 812 PyObjectPtr result(testing::mainModuleGet("result")); 813 ASSERT_NE(result, nullptr); 814 ASSERT_EQ(PyTuple_CheckExact(result), 1); 815 ASSERT_EQ(PyTuple_Size(result), 2); 816 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 817 EXPECT_EQ(PyLong_AsLong(PyTuple_GetItem(result, 1)), 1234); 818} 819 820TEST_F(TypeExtensionApiTest, MethodsMethOneArgNoArgsRaisesTypeError) { 821 binaryfunc meth = [](PyObject*, PyObject*) { 822 ADD_FAILURE(); // unreachable 823 return Py_None; 824 }; 825 static PyMethodDef methods[] = {{"onearg", meth, METH_O}, {nullptr}}; 826 PyType_Slot slots[] = { 827 {Py_tp_methods, methods}, 828 {0, nullptr}, 829 }; 830 static PyType_Spec spec; 831 spec = { 832 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 833 }; 834 PyObjectPtr type(PyType_FromSpec(&spec)); 835 ASSERT_NE(type, nullptr); 836 testing::moduleSet("__main__", "C", type); 837 PyRun_SimpleString(R"( 838result = False 839self = C() 840try: 841 self.onearg() 842except TypeError: 843 result = True 844)"); 845 PyObjectPtr result(testing::mainModuleGet("result")); 846 ASSERT_NE(result, nullptr); 847 EXPECT_EQ(result, Py_True); 848} 849 850// METH_O | METH_CLASS and CALL_FUNCTION 851 852TEST_F(TypeExtensionApiTest, MethodsMethOneArgClassPosCallOnClass) { 853 binaryfunc meth = [](PyObject* cls, PyObject* arg) { 854 return PyTuple_Pack(2, cls, arg); 855 }; 856 static PyMethodDef methods[] = {{"onearg", meth, METH_O | METH_CLASS}, 857 {nullptr}}; 858 PyType_Slot slots[] = { 859 {Py_tp_methods, methods}, 860 {0, nullptr}, 861 }; 862 static PyType_Spec spec = { 863 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 864 }; 865 PyObjectPtr type(PyType_FromSpec(&spec)); 866 ASSERT_NE(type, nullptr); 867 testing::moduleSet("__main__", "C", type); 868 PyRun_SimpleString("result = C.onearg(1234)"); 869 PyObjectPtr result(testing::mainModuleGet("result")); 870 ASSERT_NE(result, nullptr); 871 ASSERT_EQ(PyTuple_CheckExact(result), 1); 872 ASSERT_EQ(PyTuple_Size(result), 2); 873 EXPECT_EQ(PyTuple_GetItem(result, 0), type); 874 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 1), 1234)); 875} 876 877TEST_F(TypeExtensionApiTest, MethodsMethOneArgClassPosCallOnInstance) { 878 binaryfunc meth = [](PyObject* cls, PyObject* arg) { 879 return PyTuple_Pack(2, cls, arg); 880 }; 881 static PyMethodDef methods[] = {{"onearg", meth, METH_O | METH_CLASS}, 882 {nullptr}}; 883 PyType_Slot slots[] = { 884 {Py_tp_methods, methods}, 885 {0, nullptr}, 886 }; 887 static PyType_Spec spec = { 888 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 889 }; 890 PyObjectPtr type(PyType_FromSpec(&spec)); 891 ASSERT_NE(type, nullptr); 892 testing::moduleSet("__main__", "C", type); 893 PyRun_SimpleString("result = C().onearg(1234)"); 894 PyObjectPtr result(testing::mainModuleGet("result")); 895 ASSERT_NE(result, nullptr); 896 ASSERT_EQ(PyTuple_CheckExact(result), 1); 897 ASSERT_EQ(PyTuple_Size(result), 2); 898 EXPECT_EQ(PyTuple_GetItem(result, 0), type); 899 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 1), 1234)); 900} 901 902TEST_F(TypeExtensionApiTest, MethodsMethOneArgClassPosCallOnSubclass) { 903 binaryfunc meth = [](PyObject* cls, PyObject* arg) { 904 return PyTuple_Pack(2, cls, arg); 905 }; 906 static PyMethodDef methods[] = {{"onearg", meth, METH_O | METH_CLASS}, 907 {nullptr}}; 908 PyType_Slot slots[] = { 909 {Py_tp_methods, methods}, 910 {0, nullptr}, 911 }; 912 static PyType_Spec spec = { 913 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots, 914 }; 915 PyObjectPtr type(PyType_FromSpec(&spec)); 916 ASSERT_NE(type, nullptr); 917 testing::moduleSet("__main__", "C", type); 918 PyRun_SimpleString(R"( 919class D(C): 920 pass 921result0 = D.onearg(1234) 922result1 = D().onearg(5678) 923)"); 924 PyObjectPtr d(testing::mainModuleGet("D")); 925 PyObjectPtr result0(testing::mainModuleGet("result0")); 926 ASSERT_NE(result0, nullptr); 927 ASSERT_EQ(PyTuple_CheckExact(result0), 1); 928 ASSERT_EQ(PyTuple_Size(result0), 2); 929 EXPECT_EQ(PyTuple_GetItem(result0, 0), d); 930 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result0, 1), 1234)); 931 PyObjectPtr result1(testing::mainModuleGet("result1")); 932 ASSERT_NE(result1, nullptr); 933 ASSERT_EQ(PyTuple_CheckExact(result1), 1); 934 ASSERT_EQ(PyTuple_Size(result1), 2); 935 EXPECT_EQ(PyTuple_GetItem(result1, 0), d); 936 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result1, 1), 5678)); 937} 938 939// METH_O | METH_STATIC 940 941TEST_F(TypeExtensionApiTest, MethodsMethOneArgStaticCalledOnClass) { 942 binaryfunc meth = [](PyObject* self, PyObject* arg) { 943 EXPECT_EQ(self, nullptr); 944 Py_INCREF(arg); 945 return arg; 946 }; 947 static PyMethodDef methods[] = {{"onearg", meth, METH_O | METH_STATIC}, 948 {nullptr}}; 949 PyType_Slot slots[] = { 950 {Py_tp_methods, methods}, 951 {0, nullptr}, 952 }; 953 static PyType_Spec spec = { 954 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 955 }; 956 PyObjectPtr type(PyType_FromSpec(&spec)); 957 ASSERT_NE(type, nullptr); 958 testing::moduleSet("__main__", "C", type); 959 PyRun_SimpleString("result = C.onearg(1234)"); 960 PyObjectPtr result(testing::mainModuleGet("result")); 961 EXPECT_TRUE(isLongEqualsLong(result, 1234)); 962} 963 964TEST_F(TypeExtensionApiTest, MethodsMethOneArgStaticCalledOnInstance) { 965 binaryfunc meth = [](PyObject* self, PyObject* arg) { 966 EXPECT_EQ(self, nullptr); 967 Py_INCREF(arg); 968 return arg; 969 }; 970 static PyMethodDef methods[] = {{"onearg", meth, METH_O | METH_STATIC}, 971 {nullptr}}; 972 PyType_Slot slots[] = { 973 {Py_tp_methods, methods}, 974 {0, nullptr}, 975 }; 976 static PyType_Spec spec = { 977 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 978 }; 979 PyObjectPtr type(PyType_FromSpec(&spec)); 980 ASSERT_NE(type, nullptr); 981 testing::moduleSet("__main__", "C", type); 982 PyRun_SimpleString("result = C().onearg(1234)"); 983 PyObjectPtr result(testing::mainModuleGet("result")); 984 EXPECT_TRUE(isLongEqualsLong(result, 1234)); 985} 986 987TEST_F(TypeExtensionApiTest, MethodsMethOneArgStaticCalledOnSubclass) { 988 binaryfunc meth = [](PyObject* self, PyObject* arg) { 989 EXPECT_EQ(self, nullptr); 990 Py_INCREF(arg); 991 return arg; 992 }; 993 static PyMethodDef methods[] = {{"onearg", meth, METH_O | METH_STATIC}, 994 {nullptr}}; 995 PyType_Slot slots[] = { 996 {Py_tp_methods, methods}, 997 {0, nullptr}, 998 }; 999 static PyType_Spec spec = { 1000 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots, 1001 }; 1002 PyObjectPtr type(PyType_FromSpec(&spec)); 1003 ASSERT_NE(type, nullptr); 1004 testing::moduleSet("__main__", "C", type); 1005 PyRun_SimpleString(R"( 1006class D(C): 1007 pass 1008result0 = D.onearg(1234) 1009result1 = D().onearg(5678) 1010)"); 1011 PyObjectPtr result0(testing::mainModuleGet("result0")); 1012 EXPECT_TRUE(isLongEqualsLong(result0, 1234)); 1013 PyObjectPtr result1(testing::mainModuleGet("result1")); 1014 EXPECT_TRUE(isLongEqualsLong(result1, 5678)); 1015} 1016 1017// METH_O and CALL_FUNCTION_KW 1018 1019TEST_F(TypeExtensionApiTest, MethodsMethOneArgKwCall) { 1020 binaryfunc meth = [](PyObject*, PyObject*) { 1021 ADD_FAILURE(); // unreachable 1022 return Py_None; 1023 }; 1024 static PyMethodDef methods[] = {{"onearg", meth, METH_O}, {nullptr}}; 1025 PyType_Slot slots[] = { 1026 {Py_tp_methods, methods}, 1027 {0, nullptr}, 1028 }; 1029 static PyType_Spec spec; 1030 spec = { 1031 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1032 }; 1033 PyObjectPtr type(PyType_FromSpec(&spec)); 1034 ASSERT_NE(type, nullptr); 1035 testing::moduleSet("__main__", "C", type); 1036 ASSERT_NO_FATAL_FAILURE(PyRun_SimpleString(R"( 1037try: 1038 obj = C().onearg(foo=1234) 1039 result = False 1040except TypeError: 1041 result = True 1042)")); 1043 PyObjectPtr result(testing::mainModuleGet("result")); 1044 EXPECT_EQ(result, Py_True); 1045} 1046 1047// METH_O and CALL_FUNCTION_EX 1048 1049TEST_F(TypeExtensionApiTest, MethodsMethOneArgExCall) { 1050 binaryfunc meth = [](PyObject* self, PyObject* arg) { 1051 return PyTuple_Pack(2, self, arg); 1052 }; 1053 static PyMethodDef methods[] = {{"onearg", meth, METH_O}, {nullptr}}; 1054 PyType_Slot slots[] = { 1055 {Py_tp_methods, methods}, 1056 {0, nullptr}, 1057 }; 1058 static PyType_Spec spec; 1059 spec = { 1060 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1061 }; 1062 PyObjectPtr type(PyType_FromSpec(&spec)); 1063 ASSERT_NE(type, nullptr); 1064 testing::moduleSet("__main__", "C", type); 1065 PyRun_SimpleString(R"( 1066obj = C() 1067result = obj.onearg(*[1234]) 1068)"); 1069 PyObjectPtr obj(testing::mainModuleGet("obj")); 1070 PyObjectPtr result(testing::mainModuleGet("result")); 1071 ASSERT_NE(result, nullptr); 1072 ASSERT_EQ(PyTuple_CheckExact(result), 1); 1073 ASSERT_EQ(PyTuple_Size(result), 2); 1074 EXPECT_EQ(PyTuple_GetItem(result, 0), obj); 1075 EXPECT_EQ(PyLong_AsLong(PyTuple_GetItem(result, 1)), 1234); 1076} 1077 1078// METH_VARARGS and CALL_FUNCTION 1079 1080TEST_F(TypeExtensionApiTest, MethodsVarargsArgPosCall) { 1081 binaryfunc meth = [](PyObject* self, PyObject* arg) { 1082 return PyTuple_Pack(2, self, arg); 1083 }; 1084 static PyMethodDef methods[] = {{"varargs", meth, METH_VARARGS}, {nullptr}}; 1085 PyType_Slot slots[] = { 1086 {Py_tp_methods, methods}, 1087 {0, nullptr}, 1088 }; 1089 static PyType_Spec spec; 1090 spec = { 1091 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1092 }; 1093 PyObjectPtr type(PyType_FromSpec(&spec)); 1094 ASSERT_NE(type, nullptr); 1095 testing::moduleSet("__main__", "C", type); 1096 PyRun_SimpleString(R"( 1097self = C() 1098result = self.varargs(1234) 1099)"); 1100 PyObjectPtr self(testing::mainModuleGet("self")); 1101 PyObjectPtr result(testing::mainModuleGet("result")); 1102 ASSERT_NE(result, nullptr); 1103 ASSERT_EQ(PyTuple_CheckExact(result), 1); 1104 ASSERT_EQ(PyTuple_Size(result), 2); 1105 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 1106 PyObject* args = PyTuple_GetItem(result, 1); 1107 EXPECT_TRUE(PyTuple_CheckExact(args)); 1108 EXPECT_EQ(PyLong_AsLong(PyTuple_GetItem(args, 0)), 1234); 1109} 1110 1111TEST_F(TypeExtensionApiTest, MethodsVarargsArgPosNoArgsCall) { 1112 binaryfunc meth = [](PyObject* self, PyObject* arg) { 1113 return PyTuple_Pack(2, self, arg); 1114 }; 1115 static PyMethodDef methods[] = {{"varargs", meth, METH_VARARGS}, {nullptr}}; 1116 PyType_Slot slots[] = { 1117 {Py_tp_methods, methods}, 1118 {0, nullptr}, 1119 }; 1120 static PyType_Spec spec; 1121 spec = { 1122 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1123 }; 1124 PyObjectPtr type(PyType_FromSpec(&spec)); 1125 ASSERT_NE(type, nullptr); 1126 testing::moduleSet("__main__", "C", type); 1127 PyRun_SimpleString(R"( 1128self = C() 1129result = self.varargs() 1130)"); 1131 PyObjectPtr self(testing::mainModuleGet("self")); 1132 PyObjectPtr result(testing::mainModuleGet("result")); 1133 ASSERT_NE(result, nullptr); 1134 ASSERT_EQ(PyTuple_CheckExact(result), 1); 1135 ASSERT_EQ(PyTuple_Size(result), 2); 1136 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 1137 PyObject* args = PyTuple_GetItem(result, 1); 1138 EXPECT_TRUE(PyTuple_CheckExact(args)); 1139 EXPECT_EQ(PyTuple_Size(args), 0); 1140} 1141 1142// METH_VARARGS and CALL_FUNCTION_KW 1143 1144TEST_F(TypeExtensionApiTest, MethodsVarargsArgKwCall) { 1145 binaryfunc meth = [](PyObject* self, PyObject* arg) { 1146 return PyTuple_Pack(2, self, arg); 1147 }; 1148 static PyMethodDef methods[] = {{"varargs", meth, METH_VARARGS}, {nullptr}}; 1149 PyType_Slot slots[] = { 1150 {Py_tp_methods, methods}, 1151 {0, nullptr}, 1152 }; 1153 static PyType_Spec spec; 1154 spec = { 1155 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1156 }; 1157 PyObjectPtr type(PyType_FromSpec(&spec)); 1158 ASSERT_NE(type, nullptr); 1159 testing::moduleSet("__main__", "C", type); 1160 PyRun_SimpleString(R"( 1161try: 1162 obj = C().varargs(foo=1234) 1163 result = False 1164except TypeError: 1165 result = True 1166)"); 1167 PyObjectPtr result(testing::mainModuleGet("result")); 1168 EXPECT_EQ(result, Py_True); 1169} 1170 1171// METH_VARARGS and CALL_FUNCTION_EX 1172 1173TEST_F(TypeExtensionApiTest, MethodsVarargsArgExCall) { 1174 binaryfunc meth = [](PyObject* self, PyObject* arg) { 1175 return PyTuple_Pack(2, self, arg); 1176 }; 1177 static PyMethodDef methods[] = {{"varargs", meth, METH_VARARGS}, {nullptr}}; 1178 PyType_Slot slots[] = { 1179 {Py_tp_methods, methods}, 1180 {0, nullptr}, 1181 }; 1182 static PyType_Spec spec; 1183 spec = { 1184 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1185 }; 1186 PyObjectPtr type(PyType_FromSpec(&spec)); 1187 ASSERT_NE(type, nullptr); 1188 testing::moduleSet("__main__", "C", type); 1189 PyRun_SimpleString(R"( 1190self = C() 1191result = self.varargs(*[1234]) 1192)"); 1193 PyObjectPtr self(testing::mainModuleGet("self")); 1194 PyObjectPtr result(testing::mainModuleGet("result")); 1195 ASSERT_NE(result, nullptr); 1196 ASSERT_EQ(PyTuple_CheckExact(result), 1); 1197 ASSERT_EQ(PyTuple_Size(result), 2); 1198 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 1199 PyObject* args = PyTuple_GetItem(result, 1); 1200 EXPECT_TRUE(PyTuple_CheckExact(args)); 1201 EXPECT_EQ(PyLong_AsLong(PyTuple_GetItem(args, 0)), 1234); 1202} 1203 1204TEST_F(TypeExtensionApiTest, MethodsVarargsArgExHasEmptyKwargsCall) { 1205 binaryfunc meth = [](PyObject* self, PyObject* arg) { 1206 return PyTuple_Pack(2, self, arg); 1207 }; 1208 static PyMethodDef methods[] = {{"varargs", meth, METH_VARARGS}, {nullptr}}; 1209 PyType_Slot slots[] = { 1210 {Py_tp_methods, methods}, 1211 {0, nullptr}, 1212 }; 1213 static PyType_Spec spec; 1214 spec = { 1215 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1216 }; 1217 PyObjectPtr type(PyType_FromSpec(&spec)); 1218 ASSERT_NE(type, nullptr); 1219 testing::moduleSet("__main__", "C", type); 1220 PyRun_SimpleString(R"( 1221self = C() 1222result = self.varargs(*[1234], **{}) 1223)"); 1224 PyObjectPtr self(testing::mainModuleGet("self")); 1225 PyObjectPtr result(testing::mainModuleGet("result")); 1226 ASSERT_NE(result, nullptr); 1227 ASSERT_EQ(PyTuple_CheckExact(result), 1); 1228 ASSERT_EQ(PyTuple_Size(result), 2); 1229 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 1230 PyObject* args = PyTuple_GetItem(result, 1); 1231 EXPECT_TRUE(PyTuple_CheckExact(args)); 1232 EXPECT_EQ(PyLong_AsLong(PyTuple_GetItem(args, 0)), 1234); 1233} 1234 1235// METH_KEYWORDS and CALL_FUNCTION 1236 1237TEST_F(TypeExtensionApiTest, MethodsMethKeywordsPosCall) { 1238 ternaryfunc meth = [](PyObject* self, PyObject* args, PyObject* kwargs) { 1239 if (kwargs == nullptr) return PyTuple_Pack(2, self, args); 1240 return PyTuple_Pack(3, self, args, kwargs); 1241 }; 1242 static PyMethodDef methods[] = { 1243 {"keywords", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 1244 METH_VARARGS | METH_KEYWORDS}, 1245 {nullptr}}; 1246 PyType_Slot slots[] = { 1247 {Py_tp_methods, methods}, 1248 {0, nullptr}, 1249 }; 1250 1251 static PyType_Spec spec; 1252 spec = { 1253 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1254 }; 1255 1256 PyObjectPtr type(PyType_FromSpec(&spec)); 1257 ASSERT_NE(type, nullptr); 1258 testing::moduleSet("__main__", "C", type); 1259 PyRun_SimpleString(R"( 1260self = C() 1261result = self.keywords(1234) 1262)"); 1263 1264 PyObjectPtr self(testing::mainModuleGet("self")); 1265 PyObjectPtr result(testing::mainModuleGet("result")); 1266 ASSERT_NE(result, nullptr); 1267 ASSERT_EQ(PyTuple_CheckExact(result), 1); 1268 ASSERT_EQ(PyTuple_Size(result), 2); 1269 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 1270 1271 PyObject* args = PyTuple_GetItem(result, 1); 1272 EXPECT_TRUE(PyTuple_CheckExact(args)); 1273 EXPECT_EQ(PyTuple_Size(args), 1); 1274 EXPECT_EQ(PyLong_AsLong(PyTuple_GetItem(args, 0)), 1234); 1275} 1276 1277// METH_KEYWORDS and CALL_FUNCTION_KW 1278 1279TEST_F(TypeExtensionApiTest, MethodsMethKeywordsKwCall) { 1280 ternaryfunc meth = [](PyObject* self, PyObject* args, PyObject* kwargs) { 1281 if (kwargs == nullptr) return PyTuple_Pack(2, self, args); 1282 return PyTuple_Pack(3, self, args, kwargs); 1283 }; 1284 static PyMethodDef methods[] = { 1285 {"keywords", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 1286 METH_VARARGS | METH_KEYWORDS}, 1287 {nullptr}}; 1288 PyType_Slot slots[] = { 1289 {Py_tp_methods, methods}, 1290 {0, nullptr}, 1291 }; 1292 1293 static PyType_Spec spec; 1294 spec = { 1295 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1296 }; 1297 1298 PyObjectPtr type(PyType_FromSpec(&spec)); 1299 ASSERT_NE(type, nullptr); 1300 testing::moduleSet("__main__", "C", type); 1301 PyRun_SimpleString(R"( 1302self = C() 1303result = self.keywords(1234, kwarg=5678) 1304)"); 1305 1306 PyObjectPtr self(testing::mainModuleGet("self")); 1307 PyObjectPtr result(testing::mainModuleGet("result")); 1308 ASSERT_NE(result, nullptr); 1309 ASSERT_EQ(PyTuple_CheckExact(result), 1); 1310 ASSERT_EQ(PyTuple_Size(result), 3); 1311 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 1312 1313 PyObject* args = PyTuple_GetItem(result, 1); 1314 EXPECT_TRUE(PyTuple_CheckExact(args)); 1315 EXPECT_EQ(PyTuple_Size(args), 1); 1316 EXPECT_EQ(PyLong_AsLong(PyTuple_GetItem(args, 0)), 1234); 1317 1318 PyObject* kwargs = PyTuple_GetItem(result, 2); 1319 EXPECT_TRUE(PyDict_CheckExact(kwargs)); 1320 ASSERT_EQ(PyDict_Size(kwargs), 1); 1321 PyObject* item = PyDict_GetItemString(kwargs, "kwarg"); 1322 EXPECT_TRUE(isLongEqualsLong(item, 5678)); 1323} 1324 1325// METH_KEYWORDS and CALL_FUNCTION_EX 1326 1327TEST_F(TypeExtensionApiTest, MethodsMethKeywordsExCall) { 1328 ternaryfunc meth = [](PyObject* self, PyObject* args, PyObject* kwargs) { 1329 return PyTuple_Pack(3, self, args, kwargs); 1330 }; 1331 static PyMethodDef methods[] = { 1332 {"keywords", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 1333 METH_VARARGS | METH_KEYWORDS}, 1334 {nullptr}}; 1335 PyType_Slot slots[] = { 1336 {Py_tp_methods, methods}, 1337 {0, nullptr}, 1338 }; 1339 1340 static PyType_Spec spec; 1341 spec = { 1342 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1343 }; 1344 1345 PyObjectPtr type(PyType_FromSpec(&spec)); 1346 ASSERT_NE(type, nullptr); 1347 testing::moduleSet("__main__", "C", type); 1348 PyRun_SimpleString(R"( 1349self = C() 1350result = self.keywords(*[1234], kwarg=5678) 1351)"); 1352 1353 PyObjectPtr self(testing::mainModuleGet("self")); 1354 PyObjectPtr result(testing::mainModuleGet("result")); 1355 ASSERT_NE(result, nullptr); 1356 ASSERT_EQ(PyTuple_CheckExact(result), 1); 1357 ASSERT_EQ(PyTuple_Size(result), 3); 1358 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 1359 1360 PyObject* args = PyTuple_GetItem(result, 1); 1361 EXPECT_TRUE(PyTuple_CheckExact(args)); 1362 EXPECT_EQ(PyTuple_Size(args), 1); 1363 EXPECT_EQ(PyLong_AsLong(PyTuple_GetItem(args, 0)), 1234); 1364 1365 PyObject* kwargs = PyTuple_GetItem(result, 2); 1366 EXPECT_TRUE(PyDict_CheckExact(kwargs)); 1367 ASSERT_EQ(PyDict_Size(kwargs), 1); 1368 PyObject* item = PyDict_GetItemString(kwargs, "kwarg"); 1369 EXPECT_TRUE(isLongEqualsLong(item, 5678)); 1370} 1371 1372TEST_F(TypeExtensionApiTest, MethodsMethKeywordsExEmptyKwargsCall) { 1373 ternaryfunc meth = [](PyObject* self, PyObject* args, PyObject* kwargs) { 1374 if (kwargs == nullptr) return PyTuple_Pack(2, self, args); 1375 return PyTuple_Pack(3, self, args, kwargs); 1376 }; 1377 static PyMethodDef methods[] = { 1378 {"keywords", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 1379 METH_VARARGS | METH_KEYWORDS}, 1380 {nullptr}}; 1381 PyType_Slot slots[] = { 1382 {Py_tp_methods, methods}, 1383 {0, nullptr}, 1384 }; 1385 1386 static PyType_Spec spec; 1387 spec = { 1388 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1389 }; 1390 1391 PyObjectPtr type(PyType_FromSpec(&spec)); 1392 ASSERT_NE(type, nullptr); 1393 testing::moduleSet("__main__", "C", type); 1394 PyRun_SimpleString(R"( 1395self = C() 1396result = self.keywords(*[1234], *{}) 1397)"); 1398 1399 PyObjectPtr self(testing::mainModuleGet("self")); 1400 PyObjectPtr result(testing::mainModuleGet("result")); 1401 ASSERT_NE(result, nullptr); 1402 ASSERT_EQ(PyTuple_CheckExact(result), 1); 1403 ASSERT_EQ(PyTuple_Size(result), 2); 1404 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 1405 1406 PyObject* args = PyTuple_GetItem(result, 1); 1407 EXPECT_TRUE(PyTuple_CheckExact(args)); 1408 EXPECT_EQ(PyTuple_Size(args), 1); 1409 EXPECT_EQ(PyLong_AsLong(PyTuple_GetItem(args, 0)), 1234); 1410} 1411 1412TEST_F(TypeExtensionApiTest, GetObjectCreatedInManagedCode) { 1413 static PyType_Slot slots[1]; 1414 slots[0] = {0, nullptr}; 1415 static PyType_Spec spec; 1416 spec = { 1417 "__main__.Foo", 0, 0, Py_TPFLAGS_DEFAULT, slots, 1418 }; 1419 PyObjectPtr type(PyType_FromSpec(&spec)); 1420 ASSERT_NE(type, nullptr); 1421 ASSERT_EQ(PyType_CheckExact(type), 1); 1422 ASSERT_EQ(moduleSet("__main__", "Foo", type), 0); 1423 1424 // This is similar to CallExtensionTypeReturnsExtensionInstancePyro, but it 1425 // tests the RawObject -> PyObject* path for objects that were created on the 1426 // managed heap and had no corresponding PyObject* before the call to 1427 // moduleGet(). 1428 ASSERT_EQ(PyRun_SimpleString("f = Foo()"), 0); 1429 PyObjectPtr foo(mainModuleGet("f")); 1430 EXPECT_NE(foo, nullptr); 1431} 1432 1433TEST_F(TypeExtensionApiTest, GenericNewReturnsExtensionInstance) { 1434 struct BarObject { 1435 PyObject_HEAD 1436 }; 1437 PyType_Slot slots[] = { 1438 {Py_tp_alloc, reinterpret_cast<void*>(PyType_GenericAlloc)}, 1439 {Py_tp_new, reinterpret_cast<void*>(PyType_GenericNew)}, 1440 {Py_tp_dealloc, reinterpret_cast<void*>(deallocLeafObject)}, 1441 {0, nullptr}, 1442 }; 1443 static PyType_Spec spec; 1444 spec = { 1445 "foo.Bar", sizeof(BarObject), 0, Py_TPFLAGS_DEFAULT, slots, 1446 }; 1447 PyObjectPtr type(PyType_FromSpec(&spec)); 1448 ASSERT_NE(type, nullptr); 1449 ASSERT_TRUE(PyType_CheckExact(type)); 1450 1451 auto new_func = reinterpret_cast<newfunc>( 1452 PyType_GetSlot(reinterpret_cast<PyTypeObject*>(type.get()), Py_tp_new)); 1453 PyObjectPtr bar( 1454 new_func(reinterpret_cast<PyTypeObject*>(type.get()), nullptr, nullptr)); 1455 EXPECT_NE(bar, nullptr); 1456} 1457 1458// Given one slot id and a function pointer to go with it, create a Bar type 1459// containing that slot. 1460template <typename T> 1461static void createTypeWithSlotAndBase(const char* type_name, int slot, T pfunc, 1462 PyObject* base) { 1463 static PyType_Slot slots[2]; 1464 slots[0] = {slot, reinterpret_cast<void*>(pfunc)}; 1465 slots[1] = {0, nullptr}; 1466 static PyType_Spec spec; 1467 static char qualname[100]; 1468 std::sprintf(qualname, "__main__.%s", type_name); 1469 unsigned int flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; 1470 spec = { 1471 qualname, 0, 0, flags, slots, 1472 }; 1473 PyObject* tp; 1474 if (base == nullptr) { 1475 tp = PyType_FromSpec(&spec); 1476 } else { 1477 PyObjectPtr bases(PyTuple_Pack(1, base)); 1478 tp = PyType_FromSpecWithBases(&spec, bases); 1479 } 1480 PyObjectPtr type(tp); 1481 ASSERT_NE(type, nullptr); 1482 ASSERT_EQ(PyType_CheckExact(type), 1); 1483 ASSERT_EQ(moduleSet("__main__", type_name, type), 0); 1484} 1485 1486template <typename T> 1487static void createTypeWithSlot(const char* type_name, int slot, T pfunc) { 1488 createTypeWithSlotAndBase(type_name, slot, pfunc, nullptr); 1489} 1490 1491TEST_F(TypeExtensionApiTest, CallReverseBinarySlotSwapsArguments) { 1492 binaryfunc add_func = [](PyObject* a, PyObject* b) { 1493 return PyTuple_Pack(2, a, b); 1494 }; 1495 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_nb_add, add_func)); 1496 1497 ASSERT_EQ(PyRun_SimpleString(R"( 1498instance = Bar() 1499left, right = instance.__radd__(12) 1500)"), 1501 0); 1502 1503 PyObjectPtr instance(mainModuleGet("instance")); 1504 PyObjectPtr left(mainModuleGet("left")); 1505 PyObjectPtr right(mainModuleGet("right")); 1506 EXPECT_TRUE(isLongEqualsLong(left, 12)); 1507 EXPECT_EQ(right, instance); 1508} 1509 1510TEST_F(TypeExtensionApiTest, CallBinarySlotFromManagedCode) { 1511 binaryfunc add_func = [](PyObject* a, PyObject* b) { 1512 PyObjectPtr num(PyLong_FromLong(24)); 1513 return PyLong_Check(a) ? PyNumber_Add(a, num) : PyNumber_Add(num, b); 1514 }; 1515 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_nb_add, add_func)); 1516 1517 ASSERT_EQ(PyRun_SimpleString(R"( 1518b = Bar() 1519r1 = b.__add__(12) 1520r2 = Bar.__add__(b, 24) 1521r3 = 1000 + b 1522args = (b, 42) 1523r4 = Bar.__add__(*args) 1524kwargs = {} 1525r5 = b.__add__(100, **kwargs) 1526b += -12 1527)"), 1528 0); 1529 1530 PyObjectPtr r1(mainModuleGet("r1")); 1531 EXPECT_TRUE(isLongEqualsLong(r1, 36)); 1532 1533 PyObjectPtr r2(mainModuleGet("r2")); 1534 EXPECT_TRUE(isLongEqualsLong(r2, 48)); 1535 1536 PyObjectPtr r3(mainModuleGet("r3")); 1537 EXPECT_TRUE(isLongEqualsLong(r3, 1024)); 1538 1539 PyObjectPtr r4(mainModuleGet("r4")); 1540 EXPECT_TRUE(isLongEqualsLong(r4, 66)); 1541 1542 PyObjectPtr r5(mainModuleGet("r5")); 1543 EXPECT_TRUE(isLongEqualsLong(r5, 124)); 1544 1545 PyObjectPtr b(mainModuleGet("b")); 1546 EXPECT_TRUE(isLongEqualsLong(b, 12)); 1547} 1548 1549TEST_F(TypeExtensionApiTest, CallBinarySlotWithKwargsRaisesTypeError) { 1550 binaryfunc dummy_add = [](PyObject*, PyObject*) -> PyObject* { 1551 EXPECT_TRUE(false) << "Shouldn't be called"; 1552 Py_RETURN_NONE; 1553 }; 1554 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_nb_add, dummy_add)); 1555 1556 // TODO(T40700664): Use PyRun_String() so we can directly inspect the thrown 1557 // exception(s). 1558 ASSERT_EQ(PyRun_SimpleString(R"( 1559b = Bar() 1560try: 1561 b.__add__(a=2) 1562 raise RuntimeError("call didn't throw") 1563except TypeError: 1564 pass 1565 1566try: 1567 kwargs = {'a': 2} 1568 b.__add__(**kwargs) 1569 raise RuntimeError("call didn't throw") 1570except TypeError: 1571 pass 1572)"), 1573 0); 1574} 1575 1576TEST_F(TypeExtensionApiTest, CallHashSlotFromManagedCode) { 1577 hashfunc hash_func = [](PyObject*) -> Py_hash_t { return 0xba5eba11; }; 1578 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_hash, hash_func)); 1579 1580 ASSERT_EQ(PyRun_SimpleString(R"( 1581b = Bar() 1582h1 = b.__hash__() 1583h2 = Bar.__hash__(b) 1584)"), 1585 0); 1586 1587 PyObjectPtr h1(mainModuleGet("h1")); 1588 EXPECT_TRUE(isLongEqualsLong(h1, 0xba5eba11)); 1589 1590 PyObjectPtr h2(mainModuleGet("h2")); 1591 EXPECT_TRUE(isLongEqualsLong(h2, 0xba5eba11)); 1592} 1593 1594static PyObject* abortingTernaryFunc(PyObject*, PyObject*, PyObject*) { 1595 std::fprintf(stderr, "%s should not have been called!\n", __func__); 1596 std::abort(); 1597} 1598 1599TEST_F(TypeExtensionApiTest, CallCallSlotWithMismatchedSelfRaisesTypeError) { 1600 ASSERT_NO_FATAL_FAILURE( 1601 createTypeWithSlot("MyType", Py_tp_call, &abortingTernaryFunc)); 1602 PyObjectPtr my_type(mainModuleGet("MyType")); 1603 PyObjectPtr dunder_call(PyObject_GetAttrString(my_type, "__call__")); 1604 PyObjectPtr arg(PyLong_FromLong(5)); 1605 PyObjectPtr call_result( 1606 PyObject_CallFunctionObjArgs(dunder_call, arg.get(), nullptr)); 1607 EXPECT_EQ(call_result, nullptr); 1608 ASSERT_NE(PyErr_Occurred(), nullptr); 1609 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 1610} 1611 1612TEST_F(TypeExtensionApiTest, CallNewSlotWithNonTypeClsRaisesTypeError) { 1613 ASSERT_NO_FATAL_FAILURE( 1614 createTypeWithSlot("MyType", Py_tp_new, &abortingTernaryFunc)); 1615 PyObjectPtr my_type(mainModuleGet("MyType")); 1616 PyObjectPtr dunder_call(PyObject_GetAttrString(my_type, "__new__")); 1617 PyObjectPtr arg(PyLong_FromLong(5)); 1618 PyObjectPtr call_result( 1619 PyObject_CallFunctionObjArgs(dunder_call, arg.get(), nullptr)); 1620 EXPECT_EQ(call_result, nullptr); 1621 ASSERT_NE(PyErr_Occurred(), nullptr); 1622 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 1623} 1624 1625TEST_F(TypeExtensionApiTest, CallNewSlotWithNonSubclassClsRaisesTypeError) { 1626 ASSERT_NO_FATAL_FAILURE( 1627 createTypeWithSlot("MyType", Py_tp_new, &abortingTernaryFunc)); 1628 PyObjectPtr my_type(mainModuleGet("MyType")); 1629 PyObjectPtr dunder_call(PyObject_GetAttrString(my_type, "__new__")); 1630 PyObjectPtr arg(borrow(reinterpret_cast<PyObject*>(&PyType_Type))); 1631 PyObjectPtr call_result( 1632 PyObject_CallFunctionObjArgs(dunder_call, arg.get(), nullptr)); 1633 EXPECT_EQ(call_result, nullptr); 1634 ASSERT_NE(PyErr_Occurred(), nullptr); 1635 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 1636} 1637 1638TEST_F(TypeExtensionApiTest, CallCallSlotFromManagedCode) { 1639 ternaryfunc call_func = [](PyObject* self, PyObject* args, PyObject* kwargs) { 1640 return PyTuple_Pack(3, self, args, kwargs ? kwargs : Py_None); 1641 }; 1642 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_call, call_func)); 1643 1644 ASSERT_EQ(PyRun_SimpleString(R"( 1645b = Bar() 1646r1 = b.__call__() 1647r2 = b.__call__('a', 'b', c='see') 1648r3 = b('hello!') 1649args=(b,"an argument") 1650r4 = Bar.__call__(*args) 1651)"), 1652 0); 1653 1654 PyObjectPtr b(mainModuleGet("b")); 1655 PyObjectPtr r1(mainModuleGet("r1")); 1656 ASSERT_EQ(PyTuple_Check(r1), 1); 1657 ASSERT_EQ(PyTuple_Size(r1), 3); 1658 EXPECT_EQ(PyTuple_GetItem(r1, 0), b); 1659 PyObject* tmp = PyTuple_GetItem(r1, 1); 1660 ASSERT_EQ(PyTuple_Check(tmp), 1); 1661 EXPECT_EQ(PyTuple_Size(tmp), 0); 1662 EXPECT_EQ(PyTuple_GetItem(r1, 2), Py_None); 1663 1664 PyObjectPtr r2(mainModuleGet("r2")); 1665 ASSERT_EQ(PyTuple_Check(r2), 1); 1666 ASSERT_EQ(PyTuple_Size(r2), 3); 1667 EXPECT_EQ(PyTuple_GetItem(r2, 0), b); 1668 tmp = PyTuple_GetItem(r2, 1); 1669 ASSERT_EQ(PyTuple_Check(tmp), 1); 1670 ASSERT_EQ(PyTuple_Size(tmp), 2); 1671 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(tmp, 0), "a")); 1672 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(tmp, 1), "b")); 1673 tmp = PyTuple_GetItem(r2, 2); 1674 ASSERT_EQ(PyDict_Check(tmp), 1); 1675 PyObjectPtr key(PyUnicode_FromString("c")); 1676 EXPECT_TRUE(isUnicodeEqualsCStr(PyDict_GetItem(tmp, key), "see")); 1677 1678 PyObjectPtr r3(mainModuleGet("r3")); 1679 ASSERT_EQ(PyTuple_Check(r3), 1); 1680 ASSERT_EQ(PyTuple_Size(r3), 3); 1681 EXPECT_EQ(PyTuple_GetItem(r3, 0), b); 1682 tmp = PyTuple_GetItem(r3, 1); 1683 ASSERT_EQ(PyTuple_Check(tmp), 1); 1684 ASSERT_EQ(PyTuple_Size(tmp), 1); 1685 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(tmp, 0), "hello!")); 1686 EXPECT_EQ(PyTuple_GetItem(r3, 2), Py_None); 1687 1688 PyObjectPtr r4(mainModuleGet("r4")); 1689 ASSERT_EQ(PyTuple_Check(r4), 1); 1690 ASSERT_EQ(PyTuple_Size(r4), 3); 1691 EXPECT_EQ(PyTuple_GetItem(r4, 0), b); 1692 tmp = PyTuple_GetItem(r4, 1); 1693 ASSERT_EQ(PyTuple_Check(tmp), 1); 1694 ASSERT_EQ(PyTuple_Size(tmp), 1); 1695 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(tmp, 0), "an argument")); 1696 EXPECT_EQ(PyTuple_GetItem(r4, 2), Py_None); 1697} 1698 1699TEST_F(TypeExtensionApiTest, CallGetattroSlotFromManagedCode) { 1700 getattrofunc getattr_func = [](PyObject* self, PyObject* name) { 1701 return PyTuple_Pack(2, name, self); 1702 }; 1703 ASSERT_NO_FATAL_FAILURE( 1704 createTypeWithSlot("Bar", Py_tp_getattro, getattr_func)); 1705 1706 ASSERT_EQ(PyRun_SimpleString(R"( 1707b = Bar() 1708r0 = b.foo_bar 1709 1710def foo(b): 1711 return b.bar_baz 1712r1 = foo(b) 1713)"), 1714 0); 1715 1716 PyObjectPtr b(mainModuleGet("b")); 1717 ASSERT_NE(b, nullptr); 1718 PyObjectPtr r0(mainModuleGet("r0")); 1719 ASSERT_NE(r0, nullptr); 1720 ASSERT_EQ(PyTuple_Check(r0), 1); 1721 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(r0, 0), "foo_bar")); 1722 EXPECT_EQ(PyTuple_GetItem(r0, 1), b); 1723 1724 PyObjectPtr r1(mainModuleGet("r1")); 1725 ASSERT_NE(r1, nullptr); 1726 ASSERT_EQ(PyTuple_Check(r1), 1); 1727 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(r1, 0), "bar_baz")); 1728 EXPECT_EQ(PyTuple_GetItem(r0, 1), b); 1729} 1730 1731// Pyro-only due to 1732// https://github.com/python/cpython/commit/4dcdb78c6ffd203c9d72ef41638cc4a0e3857adf 1733TEST_F(TypeExtensionApiTest, CallSetattroSlotFromManagedCodePyro) { 1734 setattrofunc setattr_func = [](PyObject* self, PyObject* name, 1735 PyObject* value) { 1736 PyObjectPtr tuple(value ? PyTuple_Pack(3, self, name, value) 1737 : PyTuple_Pack(2, self, name)); 1738 const char* var = value ? "set_attr" : "del_attr"; 1739 moduleSet("__main__", var, tuple); 1740 return 0; 1741 }; 1742 ASSERT_NO_FATAL_FAILURE( 1743 createTypeWithSlot("Bar", Py_tp_setattro, setattr_func)); 1744 1745 ASSERT_EQ(PyRun_SimpleString(R"( 1746b = Bar() 1747r1 = b.__setattr__("attr", 1234) 1748)"), 1749 0); 1750 1751 PyObjectPtr b(mainModuleGet("b")); 1752 PyObjectPtr r1(mainModuleGet("r1")); 1753 EXPECT_EQ(r1, Py_None); 1754 PyObjectPtr set_attr(mainModuleGet("set_attr")); 1755 ASSERT_EQ(PyTuple_Check(set_attr), 1); 1756 ASSERT_EQ(PyTuple_Size(set_attr), 3); 1757 EXPECT_EQ(PyTuple_GetItem(set_attr, 0), b); 1758 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(set_attr, 1), "attr")); 1759 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(set_attr, 2), 1234)); 1760 1761 ASSERT_EQ(PyRun_SimpleString(R"(r2 = b.__delattr__("other attr"))"), 0); 1762 PyObjectPtr r2(mainModuleGet("r2")); 1763 EXPECT_EQ(r2, Py_None); 1764 PyObjectPtr del_attr(mainModuleGet("del_attr")); 1765 ASSERT_EQ(PyTuple_Check(del_attr), 1); 1766 ASSERT_EQ(PyTuple_Size(del_attr), 2); 1767 EXPECT_EQ(PyTuple_GetItem(del_attr, 0), b); 1768 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(del_attr, 1), "other attr")); 1769} 1770 1771TEST_F(TypeExtensionApiTest, CallRichcompareSlotFromManagedCode) { 1772 richcmpfunc cmp_func = [](PyObject* self, PyObject* other, int op) { 1773 PyObjectPtr op_obj(PyLong_FromLong(op)); 1774 return PyTuple_Pack(3, self, other, op_obj.get()); 1775 }; 1776 ASSERT_NO_FATAL_FAILURE( 1777 createTypeWithSlot("Bar", Py_tp_richcompare, cmp_func)); 1778 1779 ASSERT_EQ(PyRun_SimpleString(R"( 1780b = Bar() 1781r1 = b.__eq__("equal") 1782r2 = b.__gt__(0xcafe) 1783)"), 1784 0); 1785 1786 PyObjectPtr b(mainModuleGet("b")); 1787 PyObjectPtr r1(mainModuleGet("r1")); 1788 ASSERT_EQ(PyTuple_Check(r1), 1); 1789 ASSERT_EQ(PyTuple_Size(r1), 3); 1790 EXPECT_EQ(PyTuple_GetItem(r1, 0), b); 1791 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(r1, 1), "equal")); 1792 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r1, 2), Py_EQ)); 1793 1794 PyObjectPtr r2(mainModuleGet("r2")); 1795 ASSERT_EQ(PyTuple_Check(r2), 1); 1796 ASSERT_EQ(PyTuple_Size(r2), 3); 1797 EXPECT_EQ(PyTuple_GetItem(r2, 0), b); 1798 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r2, 1), 0xcafe)); 1799 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r2, 2), Py_GT)); 1800} 1801 1802TEST_F(TypeExtensionApiTest, CallNextSlotFromManagedCode) { 1803 unaryfunc next_func = [](PyObject* self) { 1804 Py_INCREF(self); 1805 return self; 1806 }; 1807 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_iternext, next_func)); 1808 1809 ASSERT_EQ(PyRun_SimpleString(R"( 1810b = Bar() 1811r = b.__next__() 1812)"), 1813 0); 1814 1815 PyObjectPtr b(mainModuleGet("b")); 1816 PyObjectPtr r(mainModuleGet("r")); 1817 EXPECT_EQ(r, b); 1818} 1819 1820TEST_F(TypeExtensionApiTest, NextSlotReturningNullRaisesStopIteration) { 1821 unaryfunc next_func = [](PyObject*) -> PyObject* { return nullptr; }; 1822 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_iternext, next_func)); 1823 1824 ASSERT_EQ(PyRun_SimpleString(R"( 1825caught = False 1826try: 1827 Bar().__next__() 1828except StopIteration: 1829 caught = True 1830)"), 1831 0); 1832 1833 PyObjectPtr caught(mainModuleGet("caught")); 1834 EXPECT_EQ(caught, Py_True); 1835} 1836 1837TEST_F(TypeExtensionApiTest, CallDescrGetSlotFromManagedCode) { 1838 descrgetfunc get_func = [](PyObject* self, PyObject* instance, 1839 PyObject* owner) { 1840 return PyTuple_Pack(3, self, instance, owner); 1841 }; 1842 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_descr_get, get_func)); 1843 1844 ASSERT_EQ(PyRun_SimpleString(R"( 1845b = Bar() 1846b2 = Bar() 1847r = b.__get__(b2, Bar) 1848)"), 1849 0); 1850 1851 PyObjectPtr bar(mainModuleGet("Bar")); 1852 PyObjectPtr b(mainModuleGet("b")); 1853 PyObjectPtr b2(mainModuleGet("b2")); 1854 PyObjectPtr r(mainModuleGet("r")); 1855 ASSERT_EQ(PyTuple_Check(r), 1); 1856 ASSERT_EQ(PyTuple_Size(r), 3); 1857 EXPECT_EQ(PyTuple_GetItem(r, 0), b); 1858 EXPECT_EQ(PyTuple_GetItem(r, 1), b2); 1859 EXPECT_EQ(PyTuple_GetItem(r, 2), bar); 1860} 1861 1862TEST_F(TypeExtensionApiTest, DescrGetSlotWithNonesRaisesTypeError) { 1863 descrgetfunc get_func = [](PyObject*, PyObject*, PyObject*) -> PyObject* { 1864 EXPECT_TRUE(false) << "Shouldn't be called"; 1865 return nullptr; 1866 }; 1867 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_descr_get, get_func)); 1868 1869 // TODO(T40700664): Use PyRun_String() so we can inspect the exception more 1870 // directly. 1871 ASSERT_EQ(PyRun_SimpleString(R"( 1872b = Bar() 1873exc = None 1874try: 1875 b.__get__(None, None) 1876except TypeError as e: 1877 exc = e 1878)"), 1879 0); 1880 PyObjectPtr exc(mainModuleGet("exc")); 1881 EXPECT_EQ(PyErr_GivenExceptionMatches(exc, PyExc_TypeError), 1); 1882} 1883 1884TEST_F(TypeExtensionApiTest, CallDescrSetSlotFromManagedCode) { 1885 descrsetfunc set_func = [](PyObject* /* self */, PyObject* obj, 1886 PyObject* value) -> int { 1887 EXPECT_TRUE(isLongEqualsLong(obj, 123)); 1888 EXPECT_TRUE(isLongEqualsLong(value, 456)); 1889 return 0; 1890 }; 1891 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_descr_set, set_func)); 1892 1893 ASSERT_EQ(PyRun_SimpleString(R"( 1894b = Bar() 1895b.__set__(123, 456) 1896)"), 1897 0); 1898} 1899 1900TEST_F(TypeExtensionApiTest, CallDescrDeleteSlotFromManagedCode) { 1901 descrsetfunc set_func = [](PyObject* /* self */, PyObject* obj, 1902 PyObject* value) -> int { 1903 EXPECT_TRUE(isLongEqualsLong(obj, 24)); 1904 EXPECT_EQ(value, nullptr); 1905 return 0; 1906 }; 1907 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_descr_set, set_func)); 1908 1909 ASSERT_EQ(PyRun_SimpleString(R"( 1910b = Bar() 1911b.__delete__(24) 1912)"), 1913 0); 1914} 1915 1916TEST_F(TypeExtensionApiTest, CallInitSlotFromManagedCode) { 1917 initproc init_func = [](PyObject* /* self */, PyObject* args, 1918 PyObject* kwargs) -> int { 1919 moduleSet("__main__", "args", args); 1920 moduleSet("__main__", "kwargs", kwargs); 1921 return 0; 1922 }; 1923 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_init, init_func)); 1924 1925 ASSERT_EQ(PyRun_SimpleString(R"( 1926b = Bar.__new__(Bar) 1927b.__init__(123, four=4) 1928)"), 1929 0); 1930 1931 PyObjectPtr args(mainModuleGet("args")); 1932 ASSERT_NE(args, nullptr); 1933 ASSERT_EQ(PyTuple_Check(args), 1); 1934 ASSERT_EQ(PyTuple_Size(args), 1); 1935 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(args, 0), 123)); 1936 1937 PyObjectPtr kwargs(mainModuleGet("kwargs")); 1938 ASSERT_NE(kwargs, nullptr); 1939 ASSERT_EQ(PyDict_Check(kwargs), 1); 1940 ASSERT_EQ(PyDict_Size(kwargs), 1); 1941 EXPECT_TRUE(isLongEqualsLong(PyDict_GetItemString(kwargs, "four"), 4)); 1942} 1943 1944TEST_F(TypeExtensionApiTest, CallDelSlotFromManagedCode) { 1945 destructor del_func = [](PyObject* /* self */) { 1946 moduleSet("__main__", "called", Py_True); 1947 }; 1948 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_del, del_func)); 1949 1950 ASSERT_EQ(PyRun_SimpleString(R"( 1951bar = Bar() 1952)"), 1953 0); 1954 PyObjectPtr bar_type(mainModuleGet("Bar")); 1955 PyObject* bar = mainModuleGet("bar"); 1956 auto func = reinterpret_cast<destructor>(PyType_GetSlot( 1957 reinterpret_cast<PyTypeObject*>(bar_type.get()), Py_tp_dealloc)); 1958 (*func)(bar); 1959 PyObjectPtr called(mainModuleGet("called")); 1960 EXPECT_EQ(called, Py_True); 1961} 1962 1963TEST_F(TypeExtensionApiTest, CallTernarySlotFromManagedCode) { 1964 ternaryfunc pow_func = [](PyObject* self, PyObject* value, PyObject* mod) { 1965 return PyTuple_Pack(3, self, value, mod); 1966 }; 1967 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_nb_power, pow_func)); 1968 1969 ASSERT_EQ(PyRun_SimpleString(R"( 1970b = Bar() 1971r1 = b.__pow__(123, 456) 1972r2 = b.__pow__(789) 1973)"), 1974 0); 1975 PyObjectPtr b(mainModuleGet("b")); 1976 PyObjectPtr r1(mainModuleGet("r1")); 1977 ASSERT_EQ(PyTuple_Check(r1), 1); 1978 ASSERT_EQ(PyTuple_Size(r1), 3); 1979 EXPECT_EQ(PyTuple_GetItem(r1, 0), b); 1980 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r1, 1), 123)); 1981 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r1, 2), 456)); 1982 1983 PyObjectPtr r2(mainModuleGet("r2")); 1984 ASSERT_EQ(PyTuple_Check(r2), 1); 1985 ASSERT_EQ(PyTuple_Size(r1), 3); 1986 EXPECT_EQ(PyTuple_GetItem(r2, 0), b); 1987 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r2, 1), 789)); 1988 EXPECT_EQ(PyTuple_GetItem(r2, 2), Py_None); 1989} 1990 1991TEST_F(TypeExtensionApiTest, CallInquirySlotFromManagedCode) { 1992 inquiry bool_func = [](PyObject* self) { 1993 PyObjectPtr b(mainModuleGet("b")); 1994 EXPECT_EQ(self, b); 1995 return 1; 1996 }; 1997 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_nb_bool, bool_func)); 1998 1999 ASSERT_EQ(PyRun_SimpleString(R"( 2000b = Bar() 2001r = b.__bool__() 2002 )"), 2003 0); 2004 PyObjectPtr r(mainModuleGet("r")); 2005 EXPECT_EQ(r, Py_True); 2006} 2007 2008TEST_F(TypeExtensionApiTest, CallObjobjargSlotFromManagedCode) { 2009 objobjargproc set_func = [](PyObject* self, PyObject* key, PyObject* value) { 2010 PyObjectPtr b(mainModuleGet("b")); 2011 EXPECT_EQ(self, b); 2012 moduleSet("__main__", "key", key); 2013 moduleSet("__main__", "value", value); 2014 return 0; 2015 }; 2016 ASSERT_NO_FATAL_FAILURE( 2017 createTypeWithSlot("Bar", Py_mp_ass_subscript, set_func)); 2018 2019 ASSERT_EQ(PyRun_SimpleString(R"( 2020b = Bar() 2021r = b.__setitem__("some key", "a value") 2022)"), 2023 0); 2024 PyObjectPtr r(mainModuleGet("r")); 2025 EXPECT_EQ(r, Py_None); 2026 2027 PyObjectPtr key(mainModuleGet("key")); 2028 EXPECT_TRUE(isUnicodeEqualsCStr(key, "some key")); 2029 2030 PyObjectPtr value(mainModuleGet("value")); 2031 EXPECT_TRUE(isUnicodeEqualsCStr(value, "a value")); 2032} 2033 2034TEST_F(TypeExtensionApiTest, CallObjobjSlotFromManagedCode) { 2035 objobjproc contains_func = [](PyObject* self, PyObject* value) { 2036 PyObjectPtr b(mainModuleGet("b")); 2037 EXPECT_EQ(self, b); 2038 moduleSet("__main__", "value", value); 2039 return 123456; 2040 }; 2041 ASSERT_NO_FATAL_FAILURE( 2042 createTypeWithSlot("Bar", Py_sq_contains, contains_func)); 2043 2044 ASSERT_EQ(PyRun_SimpleString(R"( 2045b = Bar() 2046r = b.__contains__("a key") 2047)"), 2048 0); 2049 PyObjectPtr r(mainModuleGet("r")); 2050 EXPECT_EQ(r, Py_True); 2051 2052 PyObjectPtr value(mainModuleGet("value")); 2053 EXPECT_TRUE(isUnicodeEqualsCStr(value, "a key")); 2054} 2055 2056TEST_F(TypeExtensionApiTest, CallDelitemSlotFromManagedCode) { 2057 objobjargproc del_func = [](PyObject* self, PyObject* key, PyObject* value) { 2058 PyObjectPtr b(mainModuleGet("b")); 2059 EXPECT_EQ(self, b); 2060 EXPECT_EQ(value, nullptr); 2061 moduleSet("__main__", "key", key); 2062 return 0; 2063 }; 2064 ASSERT_NO_FATAL_FAILURE( 2065 createTypeWithSlot("Bar", Py_mp_ass_subscript, del_func)); 2066 2067 ASSERT_EQ(PyRun_SimpleString(R"( 2068b = Bar() 2069r = b.__delitem__("another key") 2070)"), 2071 0); 2072 PyObjectPtr r(mainModuleGet("r")); 2073 EXPECT_EQ(r, Py_None); 2074 2075 PyObjectPtr key(mainModuleGet("key")); 2076 EXPECT_TRUE(isUnicodeEqualsCStr(key, "another key")); 2077} 2078 2079TEST_F(TypeExtensionApiTest, CallLenSlotFromManagedCode) { 2080 lenfunc len_func = [](PyObject* self) -> Py_ssize_t { 2081 PyObjectPtr b(mainModuleGet("b")); 2082 EXPECT_EQ(self, b); 2083 return 0xdeadbeef; 2084 }; 2085 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_sq_length, len_func)); 2086 2087 ASSERT_EQ(PyRun_SimpleString(R"( 2088b = Bar() 2089r = b.__len__() 2090)"), 2091 0); 2092 PyObjectPtr r(mainModuleGet("r")); 2093 EXPECT_TRUE(isLongEqualsLong(r, 0xdeadbeef)); 2094} 2095 2096TEST_F(TypeExtensionApiTest, CallIndexargSlotFromManagedCode) { 2097 ssizeargfunc mul_func = [](PyObject* self, Py_ssize_t i) { 2098 PyObjectPtr b(mainModuleGet("b")); 2099 EXPECT_EQ(self, b); 2100 return PyLong_FromLong(i * 456); 2101 }; 2102 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_sq_repeat, mul_func)); 2103 2104 ASSERT_EQ(PyRun_SimpleString(R"( 2105b = Bar() 2106r = b.__mul__(123) 2107)"), 2108 0); 2109 PyObjectPtr r(mainModuleGet("r")); 2110 EXPECT_TRUE(isLongEqualsLong(r, 123 * 456)); 2111} 2112 2113TEST_F(TypeExtensionApiTest, CallSqItemSlotFromManagedCode) { 2114 ssizeargfunc item_func = [](PyObject* self, Py_ssize_t i) { 2115 PyObjectPtr b(mainModuleGet("b")); 2116 EXPECT_EQ(self, b); 2117 return PyLong_FromLong(i + 100); 2118 }; 2119 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_sq_item, item_func)); 2120 2121 ASSERT_EQ(PyRun_SimpleString(R"( 2122b = Bar() 2123r = b.__getitem__(1337) 2124)"), 2125 0); 2126 PyObjectPtr r(mainModuleGet("r")); 2127 EXPECT_TRUE(isLongEqualsLong(r, 1337 + 100)); 2128} 2129 2130TEST_F(TypeExtensionApiTest, CallSqSetitemSlotFromManagedCode) { 2131 ssizeobjargproc set_func = [](PyObject* self, Py_ssize_t i, PyObject* value) { 2132 PyObjectPtr b(mainModuleGet("b")); 2133 EXPECT_EQ(self, b); 2134 PyObjectPtr key(PyLong_FromLong(i)); 2135 moduleSet("__main__", "key", key); 2136 moduleSet("__main__", "value", value); 2137 return 0; 2138 }; 2139 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_sq_ass_item, set_func)); 2140 2141 ASSERT_EQ(PyRun_SimpleString(R"( 2142b = Bar() 2143r = b.__setitem__(123, 456) 2144)"), 2145 0); 2146 PyObjectPtr r(mainModuleGet("r")); 2147 EXPECT_EQ(r, Py_None); 2148 2149 PyObjectPtr key(mainModuleGet("key")); 2150 EXPECT_TRUE(isLongEqualsLong(key, 123)); 2151 2152 PyObjectPtr value(mainModuleGet("value")); 2153 EXPECT_TRUE(isLongEqualsLong(value, 456)); 2154} 2155 2156TEST_F(TypeExtensionApiTest, CallSqDelitemSlotFromManagedCode) { 2157 ssizeobjargproc del_func = [](PyObject* self, Py_ssize_t i, PyObject* value) { 2158 PyObjectPtr b(mainModuleGet("b")); 2159 EXPECT_EQ(self, b); 2160 PyObjectPtr key(PyLong_FromLong(i)); 2161 moduleSet("__main__", "key", key); 2162 EXPECT_EQ(value, nullptr); 2163 return 0; 2164 }; 2165 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_sq_ass_item, del_func)); 2166 2167 ASSERT_EQ(PyRun_SimpleString(R"( 2168b = Bar() 2169r = b.__delitem__(7890) 2170)"), 2171 0); 2172 PyObjectPtr r(mainModuleGet("r")); 2173 EXPECT_EQ(r, Py_None); 2174 2175 PyObjectPtr key(mainModuleGet("key")); 2176 EXPECT_TRUE(isLongEqualsLong(key, 7890)); 2177} 2178 2179TEST_F(TypeExtensionApiTest, HashNotImplementedSlotSetsNoneDunderHash) { 2180 ASSERT_NO_FATAL_FAILURE( 2181 createTypeWithSlot("Bar", Py_tp_hash, PyObject_HashNotImplemented)); 2182 PyObjectPtr bar(mainModuleGet("Bar")); 2183 PyObjectPtr hash(PyObject_GetAttrString(bar, "__hash__")); 2184 EXPECT_EQ(hash, Py_None); 2185} 2186 2187TEST_F(TypeExtensionApiTest, CallNewSlotFromManagedCode) { 2188 ternaryfunc new_func = [](PyObject* type, PyObject* args, PyObject* kwargs) { 2189 PyObjectPtr name(PyObject_GetAttrString(type, "__name__")); 2190 EXPECT_TRUE(isUnicodeEqualsCStr(name, "Bar")); 2191 EXPECT_EQ(PyTuple_Check(args), 1); 2192 EXPECT_EQ(kwargs, nullptr); 2193 Py_INCREF(args); 2194 return args; 2195 }; 2196 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_new, new_func)); 2197 2198 ASSERT_EQ(PyRun_SimpleString(R"( 2199r0 = Bar.__new__(Bar, 1, 2, 3) 2200r1 = Bar(1, 2, 3) 2201)"), 2202 0); 2203 PyObjectPtr r0(mainModuleGet("r0")); 2204 ASSERT_EQ(PyTuple_Check(r0), 1); 2205 ASSERT_EQ(PyTuple_Size(r0), 3); 2206 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r0, 0), 1)); 2207 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r0, 1), 2)); 2208 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r0, 2), 3)); 2209 2210 PyObjectPtr r1(mainModuleGet("r1")); 2211 ASSERT_EQ(PyTuple_Check(r1), 1); 2212 ASSERT_EQ(PyTuple_Size(r1), 3); 2213 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r1, 0), 1)); 2214 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r1, 1), 2)); 2215 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(r1, 2), 3)); 2216} 2217 2218TEST_F(TypeExtensionApiTest, NbAddSlotTakesPrecedenceOverSqConcatSlot) { 2219 binaryfunc add_func = [](PyObject* /* self */, PyObject* obj) { 2220 EXPECT_TRUE(isUnicodeEqualsCStr(obj, "foo")); 2221 return PyLong_FromLong(0xf00); 2222 }; 2223 binaryfunc concat_func = [](PyObject*, PyObject*) -> PyObject* { 2224 std::abort(); 2225 }; 2226 static PyType_Slot slots[3]; 2227 // Both of these slots map to __add__. nb_add appears in slotdefs first, so it 2228 // wins. 2229 slots[0] = {Py_nb_add, reinterpret_cast<void*>(add_func)}; 2230 slots[1] = {Py_sq_concat, reinterpret_cast<void*>(concat_func)}; 2231 slots[2] = {0, nullptr}; 2232 static PyType_Spec spec; 2233 spec = { 2234 "__main__.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 2235 }; 2236 PyObjectPtr type(PyType_FromSpec(&spec)); 2237 ASSERT_NE(type, nullptr); 2238 ASSERT_EQ(PyType_CheckExact(type), 1); 2239 ASSERT_EQ(moduleSet("__main__", "Bar", type), 0); 2240 2241 ASSERT_EQ(PyRun_SimpleString(R"( 2242b = Bar() 2243r = b.__add__("foo") 2244)"), 2245 0); 2246 PyObjectPtr r(mainModuleGet("r")); 2247 EXPECT_TRUE(isLongEqualsLong(r, 0xf00)); 2248} 2249 2250TEST_F(TypeExtensionApiTest, TypeSlotPropagatesException) { 2251 binaryfunc add_func = [](PyObject*, PyObject*) -> PyObject* { 2252 PyErr_SetString(PyExc_RuntimeError, "hello, there!"); 2253 return nullptr; 2254 }; 2255 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_nb_add, add_func)); 2256 2257 // TODO(T40700664): Use PyRun_String() so we can inspect the exception more 2258 // directly. 2259 EXPECT_EQ(PyRun_SimpleString(R"( 2260exc = None 2261try: 2262 Bar().__add__(1) 2263except RuntimeError as e: 2264 exc = e 2265)"), 2266 0); 2267 PyObjectPtr exc(mainModuleGet("exc")); 2268 EXPECT_EQ(PyErr_GivenExceptionMatches(exc, PyExc_RuntimeError), 1); 2269} 2270 2271typedef void (*verifyfunc)(PyObject*); 2272static verifyfunc createBarTypeWithMembers() { 2273 struct BarObject { 2274 PyObject_HEAD 2275 char t_bool; 2276 char t_byte; 2277 unsigned char t_ubyte; 2278 short t_short; 2279 unsigned short t_ushort; 2280 int t_int; 2281 unsigned int t_uint; 2282 long t_long; 2283 unsigned long t_ulong; 2284 Py_ssize_t t_pyssizet; 2285 float t_float; 2286 double t_double; 2287 const char* t_string; 2288 char t_char; 2289 PyObject* t_object; 2290 PyObject* t_object_null; 2291 long long t_longlong; 2292 unsigned long long t_ulonglong; 2293 }; 2294 2295 static const PyMemberDef members[] = { 2296 {"t_bool", T_BOOL, offsetof(BarObject, t_bool)}, 2297 {"t_byte", T_BYTE, offsetof(BarObject, t_byte)}, 2298 {"t_ubyte", T_UBYTE, offsetof(BarObject, t_ubyte)}, 2299 {"t_short", T_SHORT, offsetof(BarObject, t_short)}, 2300 {"t_ushort", T_USHORT, offsetof(BarObject, t_ushort)}, 2301 {"t_int", T_INT, offsetof(BarObject, t_int)}, 2302 {"t_uint", T_UINT, offsetof(BarObject, t_uint)}, 2303 {"t_long", T_LONG, offsetof(BarObject, t_long)}, 2304 {"t_ulong", T_ULONG, offsetof(BarObject, t_ulong)}, 2305 {"t_pyssize", T_PYSSIZET, offsetof(BarObject, t_pyssizet)}, 2306 {"t_float", T_FLOAT, offsetof(BarObject, t_float)}, 2307 {"t_double", T_DOUBLE, offsetof(BarObject, t_double)}, 2308 {"t_string", T_STRING, offsetof(BarObject, t_string)}, 2309 {"t_char", T_CHAR, offsetof(BarObject, t_char)}, 2310 {"t_object", T_OBJECT, offsetof(BarObject, t_object)}, 2311 {"t_object_null", T_OBJECT, offsetof(BarObject, t_object_null)}, 2312 {"t_objectex", T_OBJECT_EX, offsetof(BarObject, t_object)}, 2313 {"t_objectex_null", T_OBJECT_EX, offsetof(BarObject, t_object_null)}, 2314 {"t_longlong", T_LONGLONG, offsetof(BarObject, t_longlong)}, 2315 {"t_ulonglong", T_ULONGLONG, offsetof(BarObject, t_ulonglong)}, 2316 {"t_int_readonly", T_INT, offsetof(BarObject, t_int), READONLY}, 2317 {nullptr}, 2318 }; 2319 newfunc new_func = [](PyTypeObject* type, PyObject*, PyObject*) { 2320 void* slot = PyType_GetSlot(type, Py_tp_alloc); 2321 return reinterpret_cast<allocfunc>(slot)(type, 0); 2322 }; 2323 freefunc dealloc_func = [](void* self_ptr) { 2324 PyObject* self = static_cast<PyObject*>(self_ptr); 2325 BarObject* self_bar = static_cast<BarObject*>(self_ptr); 2326 // Guaranteed to be null or initialized by something 2327 Py_XDECREF(self_bar->t_object); 2328 PyTypeObject* type = Py_TYPE(self); 2329 // Since this object is subtypable (has Py_TPFLAGS_BASETYPE), we must pull 2330 // out tp_free slot instead of calling PyObject_Del. 2331 void* slot = PyType_GetSlot(type, Py_tp_free); 2332 assert(slot != nullptr); 2333 reinterpret_cast<freefunc>(slot)(self); 2334 Py_DECREF(type); 2335 }; 2336 initproc init_func = [](PyObject* self, PyObject*, PyObject*) { 2337 BarObject* bar_obj = reinterpret_cast<BarObject*>(self); 2338 bar_obj->t_bool = 1; 2339 bar_obj->t_byte = -12; 2340 bar_obj->t_ubyte = std::numeric_limits<unsigned char>::max(); 2341 bar_obj->t_short = -12; 2342 bar_obj->t_ushort = std::numeric_limits<unsigned short>::max(); 2343 bar_obj->t_int = -1234; 2344 bar_obj->t_uint = std::numeric_limits<unsigned int>::max(); 2345 bar_obj->t_long = -1234; 2346 bar_obj->t_ulong = std::numeric_limits<unsigned long>::max(); 2347 bar_obj->t_pyssizet = 1234; 2348 bar_obj->t_float = 1.0; 2349 bar_obj->t_double = 1.0; 2350 bar_obj->t_string = "foo"; 2351 bar_obj->t_char = 'a'; 2352 bar_obj->t_object = PyList_New(0); 2353 bar_obj->t_object_null = nullptr; 2354 bar_obj->t_longlong = std::numeric_limits<long long>::max(); 2355 bar_obj->t_ulonglong = std::numeric_limits<unsigned long long>::max(); 2356 return 0; 2357 }; 2358 static const PyType_Slot slots[] = { 2359 {Py_tp_new, reinterpret_cast<void*>(new_func)}, 2360 {Py_tp_init, reinterpret_cast<void*>(init_func)}, 2361 {Py_tp_dealloc, reinterpret_cast<void*>(dealloc_func)}, 2362 {Py_tp_members, const_cast<PyMemberDef*>(members)}, 2363 {0, nullptr}, 2364 }; 2365 static PyType_Spec spec = { 2366 "__main__.Bar", 2367 sizeof(BarObject), 2368 0, 2369 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 2370 const_cast<PyType_Slot*>(slots), 2371 }; 2372 PyObjectPtr type(PyType_FromSpec(&spec)); 2373 moduleSet("__main__", "Bar", type); 2374 2375 // Verifies the original values 2376 return [](PyObject* self) { 2377 BarObject* bar_obj = reinterpret_cast<BarObject*>(self); 2378 ASSERT_EQ(bar_obj->t_bool, 1); 2379 ASSERT_EQ(bar_obj->t_byte, -12); 2380 ASSERT_EQ(bar_obj->t_ubyte, std::numeric_limits<unsigned char>::max()); 2381 ASSERT_EQ(bar_obj->t_short, -12); 2382 ASSERT_EQ(bar_obj->t_ushort, std::numeric_limits<unsigned short>::max()); 2383 ASSERT_EQ(bar_obj->t_int, -1234); 2384 ASSERT_EQ(bar_obj->t_uint, std::numeric_limits<unsigned int>::max()); 2385 ASSERT_EQ(bar_obj->t_long, -1234); 2386 ASSERT_EQ(bar_obj->t_ulong, std::numeric_limits<unsigned long>::max()); 2387 ASSERT_EQ(bar_obj->t_pyssizet, 1234); 2388 ASSERT_EQ(bar_obj->t_float, 1.0); 2389 ASSERT_EQ(bar_obj->t_double, 1.0); 2390 ASSERT_EQ(bar_obj->t_string, "foo"); 2391 ASSERT_EQ(bar_obj->t_char, 'a'); 2392 ASSERT_TRUE(PyList_CheckExact(bar_obj->t_object)); 2393 ASSERT_EQ(PyList_Size(bar_obj->t_object), 0); 2394 ASSERT_EQ(bar_obj->t_object_null, nullptr); 2395 ASSERT_EQ(bar_obj->t_longlong, std::numeric_limits<long long>::max()); 2396 ASSERT_EQ(bar_obj->t_ulonglong, 2397 std::numeric_limits<unsigned long long>::max()); 2398 }; 2399} 2400 2401TEST_F(TypeExtensionApiTest, MemberBool) { 2402 auto verify_func = createBarTypeWithMembers(); 2403 ASSERT_EQ(PyRun_SimpleString(R"( 2404b = Bar() 2405r1 = b.t_bool 2406b.t_bool = False 2407r2 = b.t_bool 2408b.t_bool = r1 2409)"), 2410 0); 2411 PyObjectPtr r1(mainModuleGet("r1")); 2412 ASSERT_EQ(PyBool_Check(r1), 1); 2413 EXPECT_EQ(r1, Py_True); 2414 PyObjectPtr r2(mainModuleGet("r2")); 2415 ASSERT_EQ(PyBool_Check(r2), 1); 2416 EXPECT_EQ(r2, Py_False); 2417 PyObjectPtr b(mainModuleGet("b")); 2418 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2419} 2420 2421TEST_F(TypeExtensionApiTest, MemberByte) { 2422 auto verify_func = createBarTypeWithMembers(); 2423 ASSERT_EQ(PyRun_SimpleString(R"( 2424b = Bar() 2425r1 = b.t_byte 2426b.t_byte = 21 2427r2 = b.t_byte 2428b.t_byte = r1 2429)"), 2430 0); 2431 PyObjectPtr r1(mainModuleGet("r1")); 2432 ASSERT_EQ(PyLong_Check(r1), 1); 2433 EXPECT_TRUE(isLongEqualsLong(r1, -12)); 2434 PyObjectPtr r2(mainModuleGet("r2")); 2435 ASSERT_EQ(PyLong_Check(r2), 1); 2436 EXPECT_TRUE(isLongEqualsLong(r2, 21)); 2437 PyObjectPtr b(mainModuleGet("b")); 2438 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2439} 2440 2441TEST_F(TypeExtensionApiTest, MemberUByte) { 2442 auto verify_func = createBarTypeWithMembers(); 2443 ASSERT_EQ(PyRun_SimpleString(R"( 2444b = Bar() 2445r1 = b.t_ubyte 2446b.t_ubyte = 21 2447r2 = b.t_ubyte 2448b.t_ubyte = r1 2449)"), 2450 0); 2451 PyObjectPtr r1(mainModuleGet("r1")); 2452 ASSERT_EQ(PyLong_Check(r1), 1); 2453 EXPECT_TRUE(isLongEqualsLong(r1, std::numeric_limits<unsigned char>::max())); 2454 PyObjectPtr r2(mainModuleGet("r2")); 2455 ASSERT_EQ(PyLong_Check(r2), 1); 2456 EXPECT_TRUE(isLongEqualsLong(r2, 21)); 2457 PyObjectPtr b(mainModuleGet("b")); 2458 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2459} 2460 2461TEST_F(TypeExtensionApiTest, MemberShort) { 2462 auto verify_func = createBarTypeWithMembers(); 2463 ASSERT_EQ(PyRun_SimpleString(R"( 2464b = Bar() 2465r1 = b.t_short 2466b.t_short = 21 2467r2 = b.t_short 2468b.t_short = r1 2469)"), 2470 0); 2471 PyObjectPtr r1(mainModuleGet("r1")); 2472 ASSERT_EQ(PyLong_Check(r1), 1); 2473 EXPECT_TRUE(isLongEqualsLong(r1, -12)); 2474 PyObjectPtr r2(mainModuleGet("r2")); 2475 ASSERT_EQ(PyLong_Check(r2), 1); 2476 EXPECT_TRUE(isLongEqualsLong(r2, 21)); 2477 PyObjectPtr b(mainModuleGet("b")); 2478 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2479} 2480 2481TEST_F(TypeExtensionApiTest, MemberUShort) { 2482 auto verify_func = createBarTypeWithMembers(); 2483 ASSERT_EQ(PyRun_SimpleString(R"( 2484b = Bar() 2485r1 = b.t_ushort 2486b.t_ushort = 21 2487r2 = b.t_ushort 2488b.t_ushort = r1 2489)"), 2490 0); 2491 PyObjectPtr r1(mainModuleGet("r1")); 2492 ASSERT_EQ(PyLong_Check(r1), 1); 2493 EXPECT_TRUE(isLongEqualsLong(r1, std::numeric_limits<unsigned short>::max())); 2494 PyObjectPtr r2(mainModuleGet("r2")); 2495 ASSERT_EQ(PyLong_Check(r2), 1); 2496 EXPECT_TRUE(isLongEqualsLong(r2, 21)); 2497 PyObjectPtr b(mainModuleGet("b")); 2498 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2499} 2500 2501TEST_F(TypeExtensionApiTest, MemberInt) { 2502 auto verify_func = createBarTypeWithMembers(); 2503 ASSERT_EQ(PyRun_SimpleString(R"( 2504b = Bar() 2505r1 = b.t_int 2506b.t_int = 4321 2507r2 = b.t_int 2508b.t_int = r1 2509)"), 2510 0); 2511 PyObjectPtr r1(mainModuleGet("r1")); 2512 ASSERT_EQ(PyLong_Check(r1), 1); 2513 EXPECT_TRUE(isLongEqualsLong(r1, -1234)); 2514 PyObjectPtr r2(mainModuleGet("r2")); 2515 ASSERT_EQ(PyLong_Check(r2), 1); 2516 EXPECT_TRUE(isLongEqualsLong(r2, 4321)); 2517 PyObjectPtr b(mainModuleGet("b")); 2518 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2519} 2520 2521TEST_F(TypeExtensionApiTest, MemberUInt) { 2522 auto verify_func = createBarTypeWithMembers(); 2523 ASSERT_EQ(PyRun_SimpleString(R"( 2524b = Bar() 2525r1 = b.t_uint 2526b.t_uint = 4321 2527r2 = b.t_uint 2528b.t_uint = r1 2529)"), 2530 0); 2531 PyObjectPtr r1(mainModuleGet("r1")); 2532 ASSERT_EQ(PyLong_Check(r1), 1); 2533 EXPECT_EQ(PyLong_AsUnsignedLong(r1), 2534 std::numeric_limits<unsigned int>::max()); 2535 PyObjectPtr r2(mainModuleGet("r2")); 2536 ASSERT_EQ(PyLong_Check(r2), 1); 2537 EXPECT_EQ(PyLong_AsUnsignedLong(r2), 4321UL); 2538 PyObjectPtr b(mainModuleGet("b")); 2539 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2540} 2541 2542TEST_F(TypeExtensionApiTest, MemberLong) { 2543 auto verify_func = createBarTypeWithMembers(); 2544 ASSERT_EQ(PyRun_SimpleString(R"( 2545b = Bar() 2546r1 = b.t_long 2547b.t_long = 4321 2548r2 = b.t_long 2549b.t_long = r1 2550)"), 2551 0); 2552 PyObjectPtr r1(mainModuleGet("r1")); 2553 ASSERT_EQ(PyLong_Check(r1), 1); 2554 EXPECT_TRUE(isLongEqualsLong(r1, -1234)); 2555 PyObjectPtr r2(mainModuleGet("r2")); 2556 ASSERT_EQ(PyLong_Check(r2), 1); 2557 EXPECT_TRUE(isLongEqualsLong(r2, 4321)); 2558 PyObjectPtr b(mainModuleGet("b")); 2559 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2560} 2561 2562TEST_F(TypeExtensionApiTest, MemberULong) { 2563 auto verify_func = createBarTypeWithMembers(); 2564 ASSERT_EQ(PyRun_SimpleString(R"( 2565b = Bar() 2566r1 = b.t_ulong 2567b.t_ulong = 4321 2568r2 = b.t_ulong 2569b.t_ulong = r1 2570)"), 2571 0); 2572 PyObjectPtr r1(mainModuleGet("r1")); 2573 ASSERT_EQ(PyLong_Check(r1), 1); 2574 EXPECT_EQ(PyLong_AsUnsignedLong(r1), 2575 std::numeric_limits<unsigned long>::max()); 2576 PyObjectPtr r2(mainModuleGet("r2")); 2577 ASSERT_EQ(PyLong_Check(r2), 1); 2578 EXPECT_EQ(PyLong_AsUnsignedLong(r2), 4321UL); 2579 PyObjectPtr b(mainModuleGet("b")); 2580 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2581} 2582 2583TEST_F(TypeExtensionApiTest, MemberLongLong) { 2584 auto verify_func = createBarTypeWithMembers(); 2585 ASSERT_EQ(PyRun_SimpleString(R"( 2586b = Bar() 2587r1 = b.t_longlong 2588b.t_longlong = -4321 2589r2 = b.t_longlong 2590b.t_longlong = r1 2591)"), 2592 0); 2593 PyObjectPtr r1(mainModuleGet("r1")); 2594 ASSERT_EQ(PyLong_Check(r1), 1); 2595 EXPECT_EQ(PyLong_AsLongLong(r1), std::numeric_limits<long long>::max()); 2596 PyObjectPtr r2(mainModuleGet("r2")); 2597 ASSERT_EQ(PyLong_Check(r2), 1); 2598 EXPECT_TRUE(isLongEqualsLong(r2, -4321)); 2599 PyObjectPtr b(mainModuleGet("b")); 2600 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2601} 2602 2603TEST_F(TypeExtensionApiTest, MemberULongLong) { 2604 auto verify_func = createBarTypeWithMembers(); 2605 ASSERT_EQ(PyRun_SimpleString(R"( 2606b = Bar() 2607r1 = b.t_ulonglong 2608b.t_ulonglong = 4321 2609r2 = b.t_ulonglong 2610b.t_ulonglong = r1 2611)"), 2612 0); 2613 PyObjectPtr r1(mainModuleGet("r1")); 2614 ASSERT_EQ(PyLong_Check(r1), 1); 2615 EXPECT_EQ(PyLong_AsUnsignedLongLong(r1), 2616 std::numeric_limits<unsigned long long>::max()); 2617 PyObjectPtr r2(mainModuleGet("r2")); 2618 ASSERT_EQ(PyLong_Check(r2), 1); 2619 EXPECT_EQ(PyLong_AsUnsignedLongLong(r2), 4321UL); 2620 PyObjectPtr b(mainModuleGet("b")); 2621 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2622} 2623 2624TEST_F(TypeExtensionApiTest, MemberFloat) { 2625 auto verify_func = createBarTypeWithMembers(); 2626 ASSERT_EQ(PyRun_SimpleString(R"( 2627b = Bar() 2628r1 = b.t_float 2629b.t_float = 1.5 2630r2 = b.t_float 2631b.t_float = r1 2632)"), 2633 0); 2634 PyObjectPtr r1(mainModuleGet("r1")); 2635 ASSERT_EQ(PyFloat_Check(r1), 1); 2636 EXPECT_EQ(PyFloat_AsDouble(r1), 1.0); 2637 PyObjectPtr r2(mainModuleGet("r2")); 2638 ASSERT_EQ(PyFloat_Check(r2), 1); 2639 EXPECT_EQ(PyFloat_AsDouble(r2), 1.5); 2640 PyObjectPtr b(mainModuleGet("b")); 2641 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2642} 2643 2644TEST_F(TypeExtensionApiTest, MemberDouble) { 2645 auto verify_func = createBarTypeWithMembers(); 2646 ASSERT_EQ(PyRun_SimpleString(R"( 2647b = Bar() 2648r1 = b.t_double 2649b.t_double = 1.5 2650r2 = b.t_double 2651b.t_double = r1 2652)"), 2653 0); 2654 PyObjectPtr r1(mainModuleGet("r1")); 2655 ASSERT_EQ(PyFloat_Check(r1), 1); 2656 EXPECT_EQ(PyFloat_AsDouble(r1), 1.0); 2657 PyObjectPtr r2(mainModuleGet("r2")); 2658 ASSERT_EQ(PyFloat_Check(r2), 1); 2659 EXPECT_EQ(PyFloat_AsDouble(r2), 1.5); 2660 PyObjectPtr b(mainModuleGet("b")); 2661 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2662} 2663 2664TEST_F(TypeExtensionApiTest, MemberChar) { 2665 auto verify_func = createBarTypeWithMembers(); 2666 ASSERT_EQ(PyRun_SimpleString(R"( 2667b = Bar() 2668r1 = b.t_char 2669b.t_char = 'b' 2670r2 = b.t_char 2671b.t_char = r1 2672)"), 2673 0); 2674 PyObjectPtr r1(mainModuleGet("r1")); 2675 ASSERT_EQ(PyUnicode_Check(r1), 1); 2676 EXPECT_TRUE(isUnicodeEqualsCStr(r1, "a")); 2677 PyObjectPtr r2(mainModuleGet("r2")); 2678 ASSERT_EQ(PyUnicode_Check(r2), 1); 2679 EXPECT_TRUE(isUnicodeEqualsCStr(r2, "b")); 2680 PyObjectPtr b(mainModuleGet("b")); 2681 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2682} 2683 2684TEST_F(TypeExtensionApiTest, MemberString) { 2685 // T_STRING is read-only 2686 ASSERT_NO_FATAL_FAILURE(createBarTypeWithMembers()); 2687 ASSERT_EQ(PyRun_SimpleString(R"( 2688b = Bar() 2689r1 = b.t_string 2690)"), 2691 0); 2692 PyObjectPtr r1(mainModuleGet("r1")); 2693 ASSERT_EQ(PyUnicode_Check(r1), 1); 2694 EXPECT_TRUE(isUnicodeEqualsCStr(r1, "foo")); 2695} 2696 2697TEST_F(TypeExtensionApiTest, MemberStringWithNullReturnsNone) { 2698 struct BarObject { 2699 PyObject_HEAD 2700 char* name; 2701 }; 2702 static const PyMemberDef members[] = { 2703 {"name", T_STRING, offsetof(BarObject, name), 0, nullptr}, 2704 {nullptr}, 2705 }; 2706 static const PyType_Slot slots[] = { 2707 {Py_tp_members, const_cast<PyMemberDef*>(members)}, 2708 {0, nullptr}, 2709 }; 2710 static PyType_Spec spec = { 2711 "__main__.Bar", 2712 sizeof(BarObject), 2713 0, 2714 Py_TPFLAGS_DEFAULT, 2715 const_cast<PyType_Slot*>(slots), 2716 }; 2717 PyObjectPtr type(PyType_FromSpec(&spec)); 2718 ASSERT_TRUE(PyType_Check(type)); 2719 ASSERT_EQ(PyErr_Occurred(), nullptr); 2720 ASSERT_EQ(moduleSet("__main__", "Bar", type), 0); 2721 2722 ASSERT_EQ(PyRun_SimpleString(R"( 2723b = Bar() 2724none = b.name 2725)"), 2726 0); 2727 PyObjectPtr none(mainModuleGet("none")); 2728 ASSERT_EQ(none, Py_None); 2729} // namespace testing 2730 2731TEST_F(TypeExtensionApiTest, MemberStringRaisesTypeError) { 2732 auto verify_func = createBarTypeWithMembers(); 2733 ASSERT_EQ(PyRun_SimpleString(R"( 2734b = Bar() 2735raised = False 2736try: 2737 b.t_string = "bar" 2738 raise RuntimeError("call didn't throw") 2739except TypeError: 2740 raised = True 2741r1 = b.t_string 2742)"), 2743 0); 2744 PyObjectPtr r1(mainModuleGet("r1")); 2745 PyObjectPtr raised(mainModuleGet("raised")); 2746 EXPECT_EQ(raised, Py_True); 2747 ASSERT_EQ(PyUnicode_Check(r1), 1); 2748 EXPECT_TRUE(isUnicodeEqualsCStr(r1, "foo")); 2749 PyObjectPtr b(mainModuleGet("b")); 2750 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2751} 2752 2753TEST_F(TypeExtensionApiTest, MemberObject) { 2754 auto verify_func = createBarTypeWithMembers(); 2755 ASSERT_EQ(PyRun_SimpleString(R"( 2756b = Bar() 2757r1 = b.t_object 2758b.t_object = (1, "a", 2, "b", 3, "c") 2759r2 = b.t_object 2760b.t_object = r1 2761)"), 2762 0); 2763 PyObjectPtr r1(mainModuleGet("r1")); 2764 ASSERT_EQ(PyList_Check(r1), 1); 2765 EXPECT_EQ(PyList_Size(r1), 0); 2766 PyObjectPtr r2(mainModuleGet("r2")); 2767 ASSERT_EQ(PyTuple_Check(r2), 1); 2768 EXPECT_EQ(PyTuple_Size(r2), 6); 2769 PyObjectPtr b(mainModuleGet("b")); 2770 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2771} 2772 2773TEST_F(TypeExtensionApiTest, MemberObjectWithNull) { 2774 auto verify_func = createBarTypeWithMembers(); 2775 ASSERT_EQ(PyRun_SimpleString(R"( 2776b = Bar() 2777r1 = b.t_object_null 2778)"), 2779 0); 2780 PyObjectPtr r1(mainModuleGet("r1")); 2781 EXPECT_EQ(r1, Py_None); 2782 PyObjectPtr b(mainModuleGet("b")); 2783 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2784} 2785 2786TEST_F(TypeExtensionApiTest, MemberObjectEx) { 2787 auto verify_func = createBarTypeWithMembers(); 2788 ASSERT_EQ(PyRun_SimpleString(R"( 2789b = Bar() 2790r1 = b.t_objectex 2791b.t_objectex = tuple() 2792r2 = b.t_objectex 2793b.t_objectex = r1 2794)"), 2795 0); 2796 PyObjectPtr r1(mainModuleGet("r1")); 2797 ASSERT_EQ(PyList_Check(r1), 1); 2798 EXPECT_EQ(PyList_Size(r1), 0); 2799 PyObjectPtr r2(mainModuleGet("r2")); 2800 ASSERT_EQ(PyTuple_Check(r2), 1); 2801 EXPECT_EQ(PyTuple_Size(r2), 0); 2802 PyObjectPtr b(mainModuleGet("b")); 2803 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2804} 2805 2806TEST_F(TypeExtensionApiTest, MemberObjectExWithNullRaisesAttributeError) { 2807 auto verify_func = createBarTypeWithMembers(); 2808 ASSERT_EQ(PyRun_SimpleString(R"( 2809b = Bar() 2810raised = False 2811try: 2812 b.t_objectex_null 2813 raise RuntimeError("call didn't throw") 2814except AttributeError: 2815 raised = True 2816)"), 2817 0); 2818 PyObjectPtr raised(mainModuleGet("raised")); 2819 EXPECT_EQ(raised, Py_True); 2820 PyObjectPtr b(mainModuleGet("b")); 2821 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2822} 2823 2824TEST_F(TypeExtensionApiTest, MemberPySsizeT) { 2825 auto verify_func = createBarTypeWithMembers(); 2826 ASSERT_EQ(PyRun_SimpleString(R"( 2827b = Bar() 2828r1 = b.t_pyssize 2829b.t_pyssize = 4321 2830r2 = b.t_pyssize 2831b.t_pyssize = r1 2832)"), 2833 0); 2834 PyObjectPtr r1(mainModuleGet("r1")); 2835 ASSERT_EQ(PyLong_Check(r1), 1); 2836 EXPECT_EQ(PyLong_AsSsize_t(r1), 1234); 2837 PyObjectPtr r2(mainModuleGet("r2")); 2838 ASSERT_EQ(PyLong_Check(r2), 1); 2839 EXPECT_EQ(PyLong_AsSsize_t(r2), 4321); 2840 PyObjectPtr b(mainModuleGet("b")); 2841 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2842} 2843 2844TEST_F(TypeExtensionApiTest, MemberReadOnlyRaisesAttributeError) { 2845 auto verify_func = createBarTypeWithMembers(); 2846 ASSERT_EQ(PyRun_SimpleString(R"( 2847b = Bar() 2848r1 = b.t_int_readonly 2849raised = False 2850try: 2851 b.t_int_readonly = 4321 2852 raise RuntimeError("call didn't throw") 2853except AttributeError: 2854 raised = True 2855)"), 2856 0); 2857 PyObjectPtr r1(mainModuleGet("r1")); 2858 ASSERT_EQ(PyLong_Check(r1), 1); 2859 EXPECT_TRUE(isLongEqualsLong(r1, -1234)); 2860 PyObjectPtr raised(mainModuleGet("raised")); 2861 EXPECT_EQ(raised, Py_True); 2862 PyObjectPtr b(mainModuleGet("b")); 2863 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2864} 2865 2866TEST_F(TypeExtensionApiTest, MemberIntSetIncorrectTypeRaisesTypeError) { 2867 auto verify_func = createBarTypeWithMembers(); 2868 ASSERT_EQ(PyRun_SimpleString(R"( 2869b = Bar() 2870raised = False 2871try: 2872 b.t_int = "foo" 2873 raise RuntimeError("call didn't throw") 2874except TypeError: 2875 raised = True 2876r1 = b.t_int 2877)"), 2878 0); 2879 PyObjectPtr r1(mainModuleGet("r1")); 2880 PyObjectPtr raised(mainModuleGet("raised")); 2881 EXPECT_EQ(raised, Py_True); 2882 ASSERT_EQ(PyLong_Check(r1), 1); 2883 EXPECT_TRUE(isLongEqualsLong(r1, -1234)); 2884 PyObjectPtr b(mainModuleGet("b")); 2885 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2886} 2887 2888TEST_F(TypeExtensionApiTest, MemberCharIncorrectSizeRaisesTypeError) { 2889 auto verify_func = createBarTypeWithMembers(); 2890 ASSERT_EQ(PyRun_SimpleString(R"( 2891b = Bar() 2892raised = False 2893try: 2894 b.t_char = "foo" 2895 raise RuntimeError("call didn't throw") 2896except TypeError: 2897 raised = True 2898r1 = b.t_char 2899)"), 2900 0); 2901 PyObjectPtr r1(mainModuleGet("r1")); 2902 PyObjectPtr raised(mainModuleGet("raised")); 2903 EXPECT_EQ(raised, Py_True); 2904 ASSERT_EQ(PyUnicode_Check(r1), 1); 2905 EXPECT_TRUE(isUnicodeEqualsCStr(r1, "a")); 2906 PyObjectPtr b(mainModuleGet("b")); 2907 ASSERT_NO_FATAL_FAILURE(verify_func(b)); 2908} 2909 2910// Pyro raises a SystemError but CPython returns a new type. 2911// TODO(T56634824): Figure out why Pyro differs from CPython. 2912TEST_F(TypeExtensionApiTest, MemberUnknownRaisesSystemErrorPyro) { 2913 int unknown_type = -1; 2914 struct BarObject { 2915 PyObject_HEAD 2916 int value; 2917 }; 2918 static const PyMemberDef members[] = { 2919 {"value", unknown_type, offsetof(BarObject, value), 0, nullptr}, 2920 {nullptr}, 2921 }; 2922 static const PyType_Slot slots[] = { 2923 {Py_tp_members, const_cast<PyMemberDef*>(members)}, 2924 {0, nullptr}, 2925 }; 2926 static PyType_Spec spec = { 2927 "__main__.Bar", 2928 sizeof(BarObject), 2929 0, 2930 Py_TPFLAGS_DEFAULT, 2931 const_cast<PyType_Slot*>(slots), 2932 }; 2933 PyObjectPtr type(PyType_FromSpec(&spec)); 2934 ASSERT_EQ(type, nullptr); 2935 ASSERT_NE(PyErr_Occurred(), nullptr); 2936 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 2937} 2938 2939static void createBarTypeWithGetSetObject() { 2940 struct BarObject { 2941 PyObject_HEAD 2942 long attribute; 2943 long readonly_attribute; 2944 }; 2945 2946 getter attribute_getter = [](PyObject* self, void*) { 2947 return PyLong_FromLong(reinterpret_cast<BarObject*>(self)->attribute); 2948 }; 2949 2950 setter attribute_setter = [](PyObject* self, PyObject* value, void*) { 2951 reinterpret_cast<BarObject*>(self)->attribute = PyLong_AsLong(value); 2952 return 0; 2953 }; 2954 2955 getter readonly_attribute_getter = [](PyObject* self, void*) { 2956 return PyLong_FromLong( 2957 reinterpret_cast<BarObject*>(self)->readonly_attribute); 2958 }; 2959 2960 setter raise_attribute_setter = [](PyObject*, PyObject*, void*) { 2961 PyErr_BadArgument(); 2962 return -1; 2963 }; 2964 2965 static PyGetSetDef getsets[4]; 2966 getsets[0] = {"attribute", attribute_getter, attribute_setter}; 2967 getsets[1] = {"readonly_attribute", readonly_attribute_getter, nullptr}; 2968 getsets[2] = {"raise_attribute", attribute_getter, raise_attribute_setter}; 2969 getsets[3] = {nullptr}; 2970 2971 newfunc new_func = [](PyTypeObject* type, PyObject*, PyObject*) { 2972 void* slot = PyType_GetSlot(type, Py_tp_alloc); 2973 return reinterpret_cast<allocfunc>(slot)(type, 0); 2974 }; 2975 initproc init_func = [](PyObject* self, PyObject*, PyObject*) { 2976 reinterpret_cast<BarObject*>(self)->attribute = 123; 2977 reinterpret_cast<BarObject*>(self)->readonly_attribute = 456; 2978 return 0; 2979 }; 2980 static PyType_Slot slots[6]; 2981 // TODO(T40540469): Most of functions should be inherited from object. 2982 // However, inheritance is not supported yet. For now, just set them manually. 2983 slots[0] = {Py_tp_new, reinterpret_cast<void*>(new_func)}; 2984 slots[1] = {Py_tp_init, reinterpret_cast<void*>(init_func)}; 2985 slots[2] = {Py_tp_alloc, reinterpret_cast<void*>(PyType_GenericAlloc)}, 2986 slots[3] = {Py_tp_dealloc, reinterpret_cast<void*>(deallocLeafObject)}; 2987 slots[4] = {Py_tp_getset, reinterpret_cast<void*>(getsets)}; 2988 slots[5] = {0, nullptr}; 2989 static PyType_Spec spec; 2990 spec = { 2991 "__main__.Bar", sizeof(BarObject), 0, Py_TPFLAGS_DEFAULT, slots, 2992 }; 2993 PyObjectPtr type(PyType_FromSpec(&spec)); 2994 ASSERT_NE(type, nullptr); 2995 ASSERT_EQ(PyType_CheckExact(type), 1); 2996 ASSERT_EQ(moduleSet("__main__", "Bar", type), 0); 2997} 2998 2999TEST_F(TypeExtensionApiTest, GetSetAttributePyro) { 3000 ASSERT_NO_FATAL_FAILURE(createBarTypeWithGetSetObject()); 3001 ASSERT_EQ(PyRun_SimpleString(R"( 3002b = Bar() 3003r1 = b.attribute 3004b.attribute = 321 3005r2 = b.attribute 3006)"), 3007 0); 3008 PyObjectPtr r1(mainModuleGet("r1")); 3009 ASSERT_EQ(PyLong_Check(r1), 1); 3010 EXPECT_EQ(PyLong_AsLong(r1), 123); 3011 PyObjectPtr r2(mainModuleGet("r2")); 3012 ASSERT_EQ(PyLong_Check(r2), 1); 3013 EXPECT_EQ(PyLong_AsLong(r2), 321); 3014} 3015 3016TEST_F(TypeExtensionApiTest, GetSetReadonlyAttributePyro) { 3017 ASSERT_NO_FATAL_FAILURE(createBarTypeWithGetSetObject()); 3018 ASSERT_EQ(PyRun_SimpleString(R"( 3019b = Bar() 3020raised = False 3021try: 3022 b.readonly_attribute = 321 3023 raise RuntimeError("call didn't throw") 3024except AttributeError: 3025 raised = True 3026r1 = b.readonly_attribute 3027)"), 3028 0); 3029 PyObjectPtr r1(mainModuleGet("r1")); 3030 PyObjectPtr raised(mainModuleGet("raised")); 3031 EXPECT_EQ(raised, Py_True); 3032 ASSERT_EQ(PyLong_Check(r1), 1); 3033 EXPECT_EQ(PyLong_AsLong(r1), 456); 3034} 3035 3036TEST_F(TypeExtensionApiTest, GetSetRaiseAttributePyro) { 3037 ASSERT_NO_FATAL_FAILURE(createBarTypeWithGetSetObject()); 3038 ASSERT_EQ(PyRun_SimpleString(R"( 3039b = Bar() 3040raised = False 3041try: 3042 b.raise_attribute = 321 3043 raise SystemError("call didn't throw") 3044except TypeError: 3045 raised = True 3046r1 = b.raise_attribute 3047)"), 3048 0); 3049 PyObjectPtr r1(mainModuleGet("r1")); 3050 PyObjectPtr raised(mainModuleGet("raised")); 3051 EXPECT_EQ(raised, Py_True); 3052 ASSERT_EQ(PyLong_Check(r1), 1); 3053 EXPECT_EQ(PyLong_AsLong(r1), 123); 3054} 3055 3056TEST_F(TypeExtensionApiTest, PyTypeNameWithNullTypeRaisesSystemErrorPyro) { 3057 EXPECT_EQ(_PyType_Name(nullptr), nullptr); 3058 ASSERT_NE(PyErr_Occurred(), nullptr); 3059 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 3060} 3061 3062TEST_F(TypeExtensionApiTest, PyTypeNameWithNonTypeRaisesSystemErrorPyro) { 3063 PyObjectPtr long_obj(PyLong_FromLong(5)); 3064 EXPECT_EQ(_PyType_Name(reinterpret_cast<PyTypeObject*>(long_obj.get())), 3065 nullptr); 3066 ASSERT_NE(PyErr_Occurred(), nullptr); 3067 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 3068} 3069 3070TEST_F(TypeExtensionApiTest, PyTypeNameWithBuiltinTypeReturnsName) { 3071 PyObjectPtr long_obj(PyLong_FromLong(5)); 3072 const char* name = _PyType_Name(Py_TYPE(long_obj)); 3073 EXPECT_STREQ(name, "int"); 3074} 3075 3076TEST_F(TypeExtensionApiTest, PyTypeNameReturnsSamePointerEachCall) { 3077 PyObjectPtr long_obj(PyLong_FromLong(5)); 3078 const char* name = _PyType_Name(Py_TYPE(long_obj)); 3079 EXPECT_STREQ(name, "int"); 3080 const char* name2 = _PyType_Name(Py_TYPE(long_obj)); 3081 EXPECT_EQ(name, name2); 3082} 3083 3084TEST_F(TypeExtensionApiTest, PyTypeNameWithUserDefinedTypeReturnsName) { 3085 PyRun_SimpleString(R"( 3086class FooBarTheBaz: 3087 pass 3088)"); 3089 PyObjectPtr c(mainModuleGet("FooBarTheBaz")); 3090 const char* name = _PyType_Name(reinterpret_cast<PyTypeObject*>(c.get())); 3091 EXPECT_STREQ(name, "FooBarTheBaz"); 3092} 3093 3094static PyObject* emptyBinaryFunc(PyObject*, PyObject*) { return Py_None; } 3095 3096static void emptyDestructorFunc(PyObject*) { return; } 3097 3098static Py_ssize_t emptyLenFunc(PyObject*) { return Py_ssize_t{0}; } 3099 3100static PyObject* emptyCompareFunc(PyObject*, PyObject*, int) { return Py_None; } 3101 3102static int emptySetattroFunc(PyObject*, PyObject*, PyObject*) { return 0; } 3103 3104static PyObject* emptyTernaryFunc(PyObject*, PyObject*, PyObject*) { 3105 return Py_None; 3106} 3107 3108static PyObject* emptyUnaryFunc(PyObject*) { return Py_None; } 3109 3110TEST_F(TypeExtensionApiTest, 3111 GetSlotFromExceptionWithTpNewReturnsConstructorPyro) { 3112 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3113 "Subclass", Py_tp_init, &emptyUnaryFunc, PyExc_Exception)); 3114 PyObjectPtr subclass(mainModuleGet("Subclass")); 3115 ASSERT_NE(subclass, nullptr); 3116 newfunc dunder_new = reinterpret_cast<newfunc>(PyType_GetSlot( 3117 reinterpret_cast<PyTypeObject*>(PyExc_Exception), Py_tp_new)); 3118 ASSERT_EQ(PyErr_Occurred(), nullptr); 3119 ASSERT_NE(dunder_new, nullptr); 3120 PyObjectPtr instance(dunder_new( 3121 reinterpret_cast<PyTypeObject*>(subclass.get()), nullptr, nullptr)); 3122 ASSERT_NE(instance, nullptr); 3123 EXPECT_TRUE(PyErr_GivenExceptionMatches(instance, subclass)); 3124} 3125 3126TEST_F(TypeExtensionApiTest, 3127 GetSlotFromExceptionWithNonZeroSizeWithTpNewReturnsConstructorPyro) { 3128 PyType_Slot slots[] = { 3129 {0, nullptr}, 3130 }; 3131 static PyType_Spec spec; 3132 spec = { 3133 "foo.Foo", sizeof(PyObject), 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 3134 slots, 3135 }; 3136 PyObjectPtr bases(PyTuple_Pack(1, PyExc_Exception)); 3137 PyObjectPtr subclass(PyType_FromSpecWithBases(&spec, bases)); 3138 3139 ASSERT_NE(subclass, nullptr); 3140 newfunc dunder_new = reinterpret_cast<newfunc>(PyType_GetSlot( 3141 reinterpret_cast<PyTypeObject*>(PyExc_Exception), Py_tp_new)); 3142 ASSERT_EQ(PyErr_Occurred(), nullptr); 3143 ASSERT_NE(dunder_new, nullptr); 3144 PyObjectPtr instance(dunder_new( 3145 reinterpret_cast<PyTypeObject*>(subclass.get()), nullptr, nullptr)); 3146 ASSERT_NE(instance, nullptr); 3147 EXPECT_TRUE(PyErr_GivenExceptionMatches(instance, subclass)); 3148} 3149 3150TEST_F(TypeExtensionApiTest, 3151 ExceptionSubclassWithNonZeroConstructorCreatesExceptionSubclass) { 3152 PyObjectPtr basicsize( 3153 PyObject_GetAttrString(PyExc_Exception, "__basicsize__")); 3154 ASSERT_TRUE(PyLong_Check(basicsize)); 3155 int size = _PyLong_AsInt(basicsize); 3156 3157 PyType_Slot slots[] = { 3158 {0, nullptr}, 3159 }; 3160 static PyType_Spec spec; 3161 spec = { 3162 "foo.Foo", size, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots, 3163 }; 3164 PyObjectPtr bases(PyTuple_Pack(1, PyExc_Exception)); 3165 PyObjectPtr subclass(PyType_FromSpecWithBases(&spec, bases)); 3166 3167 ASSERT_NE(subclass, nullptr); 3168 newfunc dunder_new = reinterpret_cast<newfunc>(PyType_GetSlot( 3169 reinterpret_cast<PyTypeObject*>(subclass.get()), Py_tp_new)); 3170 ASSERT_EQ(PyErr_Occurred(), nullptr); 3171 ASSERT_NE(dunder_new, nullptr); 3172 PyObjectPtr empty_tuple(PyTuple_New(0)); 3173 PyObjectPtr instance(dunder_new( 3174 reinterpret_cast<PyTypeObject*>(subclass.get()), empty_tuple, nullptr)); 3175 ASSERT_NE(instance, nullptr); 3176 EXPECT_TRUE(PyErr_GivenExceptionMatches(instance, subclass)); 3177} 3178 3179TEST_F(TypeExtensionApiTest, GetSlotFromTypeWithTpNewReturnsConstructorPyro) { 3180 ASSERT_NO_FATAL_FAILURE( 3181 createTypeWithSlotAndBase("Subclass", Py_tp_init, &emptyUnaryFunc, 3182 reinterpret_cast<PyObject*>(&PyType_Type))); 3183 PyObjectPtr subclass(mainModuleGet("Subclass")); 3184 ASSERT_NE(subclass, nullptr); 3185 newfunc dunder_new = 3186 reinterpret_cast<newfunc>(PyType_GetSlot(&PyType_Type, Py_tp_new)); 3187 ASSERT_EQ(PyErr_Occurred(), nullptr); 3188 ASSERT_NE(dunder_new, nullptr); 3189 3190 PyObjectPtr args(PyTuple_New(3)); 3191 ASSERT_EQ(PyTuple_SetItem(args, 0, PyUnicode_FromString("Subclass")), 0); 3192 ASSERT_EQ(PyTuple_SetItem(args, 1, PyTuple_Pack(1, &PyType_Type)), 0); 3193 ASSERT_EQ(PyTuple_SetItem(args, 2, PyDict_New()), 0); 3194 3195 PyObjectPtr instance(dunder_new( 3196 reinterpret_cast<PyTypeObject*>(subclass.get()), args, nullptr)); 3197 ASSERT_NE(instance, nullptr); 3198 EXPECT_TRUE(PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(instance.get()), 3199 &PyType_Type)); 3200} 3201 3202TEST_F(TypeExtensionApiTest, GetDestructorSlotsFromExceptionReturnsNoOpsPyro) { 3203 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3204 "Subclass", Py_tp_new, &emptyBinaryFunc, PyExc_Exception)); 3205 PyObject* subclass = mainModuleGet("Subclass"); 3206 PyTypeObject* exception = reinterpret_cast<PyTypeObject*>(PyExc_Exception); 3207 3208 inquiry tp_clear = 3209 reinterpret_cast<inquiry>(PyType_GetSlot(exception, Py_tp_clear)); 3210 ASSERT_EQ(PyErr_Occurred(), nullptr); 3211 ASSERT_NE(tp_clear, nullptr); 3212 EXPECT_EQ(tp_clear(subclass), 0); 3213 3214 destructor tp_dealloc = 3215 reinterpret_cast<destructor>(PyType_GetSlot(exception, Py_tp_dealloc)); 3216 ASSERT_EQ(PyErr_Occurred(), nullptr); 3217 ASSERT_NE(tp_dealloc, nullptr); 3218 tp_dealloc(subclass); 3219 ASSERT_EQ(PyErr_Occurred(), nullptr); 3220 3221 traverseproc tp_traverse = 3222 reinterpret_cast<traverseproc>(PyType_GetSlot(exception, Py_tp_traverse)); 3223 ASSERT_EQ(PyErr_Occurred(), nullptr); 3224 ASSERT_NE(tp_traverse, nullptr); 3225 EXPECT_EQ(tp_traverse( 3226 subclass, [](PyObject*, void*) { return 0; }, nullptr), 3227 0); 3228} 3229 3230TEST_F(TypeExtensionApiTest, FromSpecWithBasesSetsBaseSlots) { 3231 ASSERT_NO_FATAL_FAILURE( 3232 createTypeWithSlot("BaseType", Py_nb_add, &emptyBinaryFunc)); 3233 PyObjectPtr base_type(mainModuleGet("BaseType")); 3234 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3235 "SubclassedType", Py_nb_add, &emptyBinaryFunc, base_type)); 3236 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3237 3238 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3239 PyObject* bases = static_cast<PyObject*>(PyType_GetSlot(tp, Py_tp_bases)); 3240 ASSERT_NE(bases, nullptr); 3241 EXPECT_EQ(PyTuple_Check(bases), 1); 3242 EXPECT_EQ(PyTuple_Size(bases), 1); 3243 EXPECT_EQ(static_cast<PyObject*>(PyType_GetSlot(tp, Py_tp_base)), 3244 base_type.get()); 3245} 3246 3247TEST_F(TypeExtensionApiTest, FromSpecWithBasesWithBuiltinBase) { 3248 static PyType_Slot slots[] = { 3249 {0, nullptr}, 3250 }; 3251 static PyType_Spec spec; 3252 spec = { 3253 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots, 3254 }; 3255 PyObjectPtr bases(PyTuple_Pack(1, &PyType_Type)); 3256 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 3257 ASSERT_NE(type.get(), nullptr); 3258 ASSERT_TRUE(PyType_CheckExact(type.get())); 3259 EXPECT_TRUE(PyObject_IsInstance(reinterpret_cast<PyObject*>(type.get()), 3260 reinterpret_cast<PyObject*>(&PyType_Type))); 3261 3262 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 3263 PyObject* tp_bases = static_cast<PyObject*>(PyType_GetSlot(tp, Py_tp_bases)); 3264 ASSERT_NE(tp_bases, nullptr); 3265 EXPECT_EQ(PyTuple_Check(tp_bases), 1); 3266 EXPECT_EQ(PyTuple_Size(tp_bases), 1); 3267 EXPECT_EQ(static_cast<PyTypeObject*>(PyType_GetSlot(tp, Py_tp_base)), 3268 &PyType_Type); 3269} 3270 3271TEST_F(TypeExtensionApiTest, 3272 FromSpecWithBasesWithTypeObjectAsBaseInheritsTpSetAttro) { 3273 static PyType_Slot slots[] = { 3274 {0, nullptr}, 3275 }; 3276 static PyType_Spec spec; 3277 spec = { 3278 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots, 3279 }; 3280 PyObjectPtr bases(PyTuple_Pack(1, &PyType_Type)); 3281 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 3282 ASSERT_NE(type.get(), nullptr); 3283 ASSERT_TRUE(PyType_CheckExact(type.get())); 3284 EXPECT_TRUE(PyObject_IsInstance(reinterpret_cast<PyObject*>(type.get()), 3285 reinterpret_cast<PyObject*>(&PyType_Type))); 3286 3287 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 3288 ASSERT_NE(PyType_GetSlot(tp, Py_tp_setattro), nullptr); 3289 setattrofunc set_attrofunc = 3290 reinterpret_cast<setattrofunc>(PyType_GetSlot(tp, Py_tp_setattro)); 3291 PyObjectPtr name(PyUnicode_FromString("foo")); 3292 PyObjectPtr value(PyUnicode_FromString("foo_value")); 3293 EXPECT_EQ(set_attrofunc(type.get(), name.get(), value.get()), 0); 3294 3295 PyObjectPtr foo_value(PyObject_GetAttrString(type.get(), "foo")); 3296 EXPECT_EQ(value.get(), foo_value.get()); 3297 3298 PyObjectPtr non_str_name(PyLong_FromLong(10)); 3299 EXPECT_NE(set_attrofunc(type.get(), non_str_name.get(), value.get()), 0); 3300 ASSERT_NE(PyErr_Occurred(), nullptr); 3301 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 3302 PyErr_Clear(); 3303} 3304 3305TEST_F(TypeExtensionApiTest, FromSpecWithBasesWithoutBasetypeIsRejectedAsBase) { 3306 static PyType_Slot slots[] = { 3307 {0, nullptr}, 3308 }; 3309 static PyType_Spec spec; 3310 spec = { 3311 "Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 3312 }; 3313 PyObjectPtr bases(PyTuple_Pack(1, &PyType_Type)); 3314 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 3315 ASSERT_NE(type.get(), nullptr); 3316 PyObjectPtr main(Borrowed(PyImport_AddModule("__main__"))); 3317 Py_INCREF(type.get()); 3318 PyModule_AddObject(main, "Bar", type); 3319 PyObjectPtr main_dict(Borrowed(PyModule_GetDict(main))); 3320 EXPECT_EQ( 3321 PyRun_String("class C(Bar): pass", Py_file_input, main_dict, main_dict), 3322 nullptr); 3323 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 3324 PyObject* exc_type; 3325 PyObject* exc_value; 3326 PyObject* exc_traceback; 3327 PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); 3328 EXPECT_TRUE(isUnicodeEqualsCStr(exc_value, 3329 "type 'Bar' is not an acceptable base type")); 3330} 3331 3332TEST_F( 3333 TypeExtensionApiTest, 3334 FromSpecWithBasesWithNonZeroSizeBaseAndZeroBasicSizeAndItemSetsCustomTpNewPyro) { 3335 PyType_Slot base_slots[] = { 3336 {0, nullptr}, 3337 }; 3338 static PyType_Spec base_spec; 3339 base_spec = { 3340 "foo.Foo", 16, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, base_slots, 3341 }; 3342 PyObjectPtr base_type(PyType_FromSpec(&base_spec)); 3343 3344 PyType_Slot slots[] = { 3345 {0, nullptr}, 3346 }; 3347 static PyType_Spec spec; 3348 spec = { 3349 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots, 3350 }; 3351 PyObjectPtr bases(PyTuple_Pack(1, base_type.get())); 3352 PyObjectPtr ext_type(PyType_FromSpecWithBases(&spec, bases)); 3353 ASSERT_NE(ext_type, nullptr); 3354 ASSERT_TRUE(PyType_CheckExact(ext_type)); 3355 3356 PyRun_SimpleString(R"(class D: pass)"); 3357 PyObjectPtr managed_type(mainModuleGet("D")); 3358 ASSERT_NE(PyType_GetSlot(managed_type.asTypeObject(), Py_tp_new), nullptr); 3359 EXPECT_NE(PyType_GetSlot(managed_type.asTypeObject(), Py_tp_new), 3360 PyType_GetSlot(ext_type.asTypeObject(), Py_tp_new)); 3361 3362 // Instances of `ext_type` does not cause any memory leak. 3363 auto new_slot = reinterpret_cast<newfunc>( 3364 PyType_GetSlot(ext_type.asTypeObject(), Py_tp_new)); 3365 PyObjectPtr args(PyTuple_New(0)); 3366 PyObjectPtr kwargs(PyDict_New()); 3367 PyObjectPtr result(new_slot(ext_type.asTypeObject(), args, kwargs)); 3368 ASSERT_NE(result, nullptr); 3369 EXPECT_EQ(PyObject_IsInstance(result, ext_type), 1); 3370} 3371 3372TEST_F(TypeExtensionApiTest, 3373 FromSpecWithBasesWithoutBaseTypeFlagsRaisesTypeError) { 3374 static PyType_Slot base_slots[1]; 3375 base_slots[0] = {0, nullptr}; 3376 static PyType_Spec base_spec; 3377 base_spec = { 3378 "__main__.BaseType", 0, 0, Py_TPFLAGS_DEFAULT, base_slots, 3379 }; 3380 PyObjectPtr base_type(PyType_FromSpec(&base_spec)); 3381 ASSERT_NE(base_type, nullptr); 3382 ASSERT_EQ(PyType_CheckExact(base_type), 1); 3383 3384 static PyType_Slot slots[1]; 3385 slots[0] = {0, nullptr}; 3386 static PyType_Spec spec; 3387 spec = { 3388 "__main__.SubclassedType", 0, 0, Py_TPFLAGS_DEFAULT, slots, 3389 }; 3390 PyObjectPtr bases(PyTuple_Pack(1, base_type.get())); 3391 ASSERT_EQ(PyType_FromSpecWithBases(&spec, bases), nullptr); 3392 ASSERT_NE(PyErr_Occurred(), nullptr); 3393 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 3394} 3395 3396TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsNumberSlots) { 3397 binaryfunc empty_binary_func2 = [](PyObject*, PyObject*) { return Py_None; }; 3398 ASSERT_NO_FATAL_FAILURE( 3399 createTypeWithSlot("BaseType", Py_nb_add, &emptyBinaryFunc)); 3400 PyObjectPtr base_type(mainModuleGet("BaseType")); 3401 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3402 "SubclassedType", Py_nb_subtract, empty_binary_func2, base_type)); 3403 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3404 3405 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3406 EXPECT_EQ(reinterpret_cast<binaryfunc>(PyType_GetSlot(tp, Py_nb_add)), 3407 &emptyBinaryFunc); 3408 EXPECT_EQ(reinterpret_cast<binaryfunc>(PyType_GetSlot(tp, Py_nb_subtract)), 3409 empty_binary_func2); 3410} 3411 3412TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsAsyncSlots) { 3413 unaryfunc empty_unary_func2 = [](PyObject*) { return Py_None; }; 3414 ASSERT_NO_FATAL_FAILURE( 3415 createTypeWithSlot("BaseType", Py_am_await, &emptyUnaryFunc)); 3416 PyObjectPtr base_type(mainModuleGet("BaseType")); 3417 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3418 "SubclassedType", Py_am_aiter, empty_unary_func2, base_type)); 3419 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3420 3421 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3422 EXPECT_EQ(reinterpret_cast<unaryfunc>(PyType_GetSlot(tp, Py_am_await)), 3423 &emptyUnaryFunc); 3424 EXPECT_EQ(reinterpret_cast<unaryfunc>(PyType_GetSlot(tp, Py_am_aiter)), 3425 empty_unary_func2); 3426} 3427 3428TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsSequenceSlots) { 3429 ssizeargfunc empty_sizearg_func = [](PyObject*, Py_ssize_t) { 3430 return Py_None; 3431 }; 3432 ASSERT_NO_FATAL_FAILURE( 3433 createTypeWithSlot("BaseType", Py_sq_concat, &emptyBinaryFunc)); 3434 PyObjectPtr base_type(mainModuleGet("BaseType")); 3435 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3436 "SubclassedType", Py_sq_repeat, empty_sizearg_func, base_type)); 3437 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3438 3439 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3440 EXPECT_EQ(reinterpret_cast<binaryfunc>(PyType_GetSlot(tp, Py_sq_concat)), 3441 &emptyBinaryFunc); 3442 EXPECT_EQ(reinterpret_cast<ssizeargfunc>(PyType_GetSlot(tp, Py_sq_repeat)), 3443 empty_sizearg_func); 3444} 3445 3446TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsMappingSlots) { 3447 ASSERT_NO_FATAL_FAILURE( 3448 createTypeWithSlot("BaseType", Py_mp_subscript, &emptyBinaryFunc)); 3449 PyObjectPtr base_type(mainModuleGet("BaseType")); 3450 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3451 "SubclassedType", Py_mp_length, &emptyLenFunc, base_type)); 3452 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3453 3454 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3455 EXPECT_EQ(reinterpret_cast<binaryfunc>(PyType_GetSlot(tp, Py_mp_subscript)), 3456 &emptyBinaryFunc); 3457 EXPECT_EQ(reinterpret_cast<lenfunc>(PyType_GetSlot(tp, Py_mp_length)), 3458 &emptyLenFunc); 3459} 3460 3461TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsTypeSlots) { 3462 ASSERT_NO_FATAL_FAILURE( 3463 createTypeWithSlot("BaseType", Py_tp_call, &emptyTernaryFunc)); 3464 PyObjectPtr base_type(mainModuleGet("BaseType")); 3465 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3466 "SubclassedType", Py_nb_add, &emptyBinaryFunc, base_type)); 3467 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3468 3469 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3470 EXPECT_EQ(reinterpret_cast<ternaryfunc>(PyType_GetSlot(tp, Py_tp_call)), 3471 &emptyTernaryFunc); 3472} 3473 3474TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsMixedSlots) { 3475 ASSERT_NO_FATAL_FAILURE( 3476 createTypeWithSlot("BaseType", Py_nb_add, &emptyBinaryFunc)); 3477 PyObjectPtr base_type(mainModuleGet("BaseType")); 3478 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3479 "SubclassedType", Py_mp_length, &emptyLenFunc, base_type)); 3480 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3481 3482 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3483 EXPECT_EQ(reinterpret_cast<binaryfunc>(PyType_GetSlot(tp, Py_nb_add)), 3484 &emptyBinaryFunc); 3485 EXPECT_EQ(reinterpret_cast<lenfunc>(PyType_GetSlot(tp, Py_mp_length)), 3486 &emptyLenFunc); 3487} 3488 3489TEST_F(TypeExtensionApiTest, FromSpecWithBasesDoesNotInheritGetAttrIfDefined) { 3490 getattrfunc empty_getattr_func = [](PyObject*, char*) { return Py_None; }; 3491 ASSERT_NO_FATAL_FAILURE( 3492 createTypeWithSlot("BaseType", Py_tp_getattro, &emptyBinaryFunc)); 3493 PyObjectPtr base_type(mainModuleGet("BaseType")); 3494 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3495 "SubclassedType", Py_tp_getattr, empty_getattr_func, base_type)); 3496 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3497 3498 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3499 EXPECT_EQ(PyType_GetSlot(tp, Py_tp_getattro), nullptr); 3500 EXPECT_EQ(reinterpret_cast<getattrfunc>(PyType_GetSlot(tp, Py_tp_getattr)), 3501 empty_getattr_func); 3502} 3503 3504TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsGetAttrIfNotDefined) { 3505 ASSERT_NO_FATAL_FAILURE( 3506 createTypeWithSlot("BaseType", Py_tp_getattro, &emptyBinaryFunc)); 3507 PyObjectPtr base_type(mainModuleGet("BaseType")); 3508 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3509 "SubclassedType", Py_nb_add, &emptyBinaryFunc, base_type)); 3510 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3511 3512 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3513 EXPECT_EQ(reinterpret_cast<getattrofunc>(PyType_GetSlot(tp, Py_tp_getattro)), 3514 &emptyBinaryFunc); 3515 EXPECT_EQ(PyType_GetSlot(tp, Py_tp_getattr), nullptr); 3516} 3517 3518TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsSetAttrIfNotDefined) { 3519 ASSERT_NO_FATAL_FAILURE( 3520 createTypeWithSlot("BaseType", Py_tp_setattro, &emptySetattroFunc)); 3521 PyObjectPtr base_type(mainModuleGet("BaseType")); 3522 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3523 "SubclassedType", Py_nb_add, &emptyBinaryFunc, base_type)); 3524 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3525 3526 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3527 EXPECT_EQ(reinterpret_cast<setattrofunc>(PyType_GetSlot(tp, Py_tp_setattro)), 3528 &emptySetattroFunc); 3529 EXPECT_EQ(PyType_GetSlot(tp, Py_tp_setattr), nullptr); 3530} 3531 3532TEST_F(TypeExtensionApiTest, 3533 FromSpecWithBasesDoesNotInheritCompareAndHashIfDefined) { 3534 hashfunc empty_hash_func = [](PyObject*) { return Py_hash_t{0}; }; 3535 ASSERT_NO_FATAL_FAILURE( 3536 createTypeWithSlot("BaseType", Py_tp_richcompare, &emptyCompareFunc)); 3537 PyObjectPtr base_type(mainModuleGet("BaseType")); 3538 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3539 "SubclassedType", Py_tp_hash, empty_hash_func, base_type)); 3540 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3541 3542 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3543 EXPECT_EQ(PyType_GetSlot(tp, Py_tp_richcompare), nullptr); 3544 EXPECT_EQ(reinterpret_cast<hashfunc>(PyType_GetSlot(tp, Py_tp_hash)), 3545 empty_hash_func); 3546} 3547 3548TEST_F(TypeExtensionApiTest, 3549 FromSpecWithBasesInheritsCompareAndHashIfNotDefined) { 3550 ASSERT_NO_FATAL_FAILURE( 3551 createTypeWithSlot("BaseType", Py_tp_richcompare, &emptyCompareFunc)); 3552 PyObjectPtr base_type(mainModuleGet("BaseType")); 3553 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3554 "SubclassedType", Py_nb_add, &emptyBinaryFunc, base_type)); 3555 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3556 3557 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3558 EXPECT_EQ( 3559 reinterpret_cast<richcmpfunc>(PyType_GetSlot(tp, Py_tp_richcompare)), 3560 &emptyCompareFunc); 3561} 3562 3563TEST_F(TypeExtensionApiTest, 3564 FromSpecWithBasesInheritsFinalizeRegardlessOfFlag) { 3565 static PyType_Slot base_slots[2]; 3566 base_slots[0] = {Py_tp_finalize, 3567 reinterpret_cast<void*>(&emptyDestructorFunc)}; 3568 base_slots[1] = {0, nullptr}; 3569 static PyType_Spec base_spec; 3570 base_spec = { 3571 "__main__.BaseType", 3572 0, 3573 0, 3574 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE, 3575 base_slots, 3576 }; 3577 PyObjectPtr base_type(PyType_FromSpec(&base_spec)); 3578 ASSERT_NE(base_type, nullptr); 3579 ASSERT_EQ(PyType_CheckExact(base_type), 1); 3580 3581 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3582 "SubclassedType", Py_nb_add, &emptyBinaryFunc, base_type)); 3583 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3584 3585 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3586 EXPECT_EQ(PyType_GetSlot(tp, Py_tp_finalize), 3587 reinterpret_cast<void*>(&emptyDestructorFunc)); 3588} 3589 3590TEST_F(TypeExtensionApiTest, 3591 FromSpecWithBasesInheritsFinalizeWhenWhateverFlagSet) { 3592 static PyType_Slot base_slots[2]; 3593 base_slots[0] = {Py_tp_finalize, 3594 reinterpret_cast<void*>(&emptyDestructorFunc)}; 3595 base_slots[1] = {0, nullptr}; 3596 static PyType_Spec base_spec; 3597 base_spec = { 3598 "__main__.BaseType", 3599 0, 3600 0, 3601 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_FINALIZE, 3602 base_slots, 3603 }; 3604 PyObjectPtr base_type(PyType_FromSpec(&base_spec)); 3605 ASSERT_NE(base_type, nullptr); 3606 ASSERT_EQ(PyType_CheckExact(base_type), 1); 3607 3608 static PyType_Slot slots[1]; 3609 slots[0] = {0, nullptr}; 3610 static PyType_Spec spec; 3611 spec = { 3612 "__main__.SubclassedType", 3613 0, 3614 0, 3615 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE, 3616 slots, 3617 }; 3618 PyObjectPtr bases(PyTuple_Pack(1, base_type.get())); 3619 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 3620 ASSERT_NE(type, nullptr); 3621 ASSERT_EQ(PyType_CheckExact(type), 1); 3622 3623 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 3624 EXPECT_EQ(reinterpret_cast<destructor>(PyType_GetSlot(tp, Py_tp_finalize)), 3625 &emptyDestructorFunc); 3626} 3627 3628TEST_F(TypeExtensionApiTest, 3629 FromSpecWithBasesDoesNotInheritFreeIfHaveGCUnsetInBase) { 3630 freefunc empty_free_func = [](void*) { return; }; 3631 ASSERT_NO_FATAL_FAILURE( 3632 createTypeWithSlot("BaseType", Py_tp_free, empty_free_func)); 3633 PyObjectPtr base_type(mainModuleGet("BaseType")); 3634 3635 static PyType_Slot slots[1]; 3636 slots[0] = {0, nullptr}; 3637 static PyType_Spec spec; 3638 spec = { 3639 "__main__.SubclassedType", 3640 0, 3641 0, 3642 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, 3643 slots, 3644 }; 3645 PyObjectPtr bases(PyTuple_Pack(1, base_type.get())); 3646 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 3647 ASSERT_NE(type, nullptr); 3648 ASSERT_EQ(PyType_CheckExact(type), 1); 3649 3650 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 3651 EXPECT_NE(reinterpret_cast<freefunc>(PyType_GetSlot(tp, Py_tp_free)), 3652 empty_free_func); 3653} 3654 3655TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsFreeIfBothHaveGCFlagSet) { 3656 freefunc empty_free_func = PyObject_Free; 3657 ASSERT_NO_FATAL_FAILURE( 3658 createTypeWithSlot("BaseType", Py_tp_free, empty_free_func)); 3659 PyObjectPtr base_type(mainModuleGet("BaseType")); 3660 3661 static PyType_Slot slots[1]; 3662 slots[0] = {0, nullptr}; 3663 static PyType_Spec spec; 3664 spec = { 3665 "__main__.SubclassedType", 3666 0, 3667 0, 3668 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, 3669 slots, 3670 }; 3671 PyObjectPtr bases(PyTuple_Pack(1, base_type.get())); 3672 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 3673 ASSERT_NE(type, nullptr); 3674 ASSERT_EQ(PyType_CheckExact(type), 1); 3675 3676 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 3677 EXPECT_EQ(PyType_GetSlot(tp, Py_tp_free), 3678 reinterpret_cast<void*>(PyObject_GC_Del)); 3679} 3680 3681TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsIfGcFlagIsPresentOnBoth) { 3682 freefunc empty_free_func = [](void*) { return; }; 3683 static PyType_Slot base_slots[2]; 3684 base_slots[0] = {Py_tp_free, reinterpret_cast<void*>(empty_free_func)}; 3685 base_slots[1] = {0, nullptr}; 3686 static PyType_Spec base_spec; 3687 base_spec = { 3688 "__main__.BaseType", 3689 0, 3690 0, 3691 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, 3692 base_slots, 3693 }; 3694 PyObjectPtr base_type(PyType_FromSpec(&base_spec)); 3695 ASSERT_NE(base_type, nullptr); 3696 ASSERT_EQ(PyType_CheckExact(base_type), 1); 3697 3698 static PyType_Slot slots[1]; 3699 slots[0] = {0, nullptr}; 3700 static PyType_Spec spec; 3701 spec = { 3702 "__main__.SubclassedType", 3703 0, 3704 0, 3705 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, 3706 slots, 3707 }; 3708 PyObjectPtr bases(PyTuple_Pack(1, base_type.get())); 3709 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 3710 ASSERT_NE(type, nullptr); 3711 ASSERT_EQ(PyType_CheckExact(type), 1); 3712 3713 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 3714 EXPECT_EQ(reinterpret_cast<freefunc>(PyType_GetSlot(tp, Py_tp_free)), 3715 empty_free_func); 3716} 3717 3718TEST_F(TypeExtensionApiTest, FromSpecWithBasesPopulatesTpDeallocIfNotDefined) { 3719 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3720 "SubclassedType", Py_nb_add, &emptyBinaryFunc, /*base=*/nullptr)); 3721 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3722 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3723 auto dealloc_func = 3724 reinterpret_cast<destructor>(PyType_GetSlot(tp, Py_tp_dealloc)); 3725 EXPECT_NE(dealloc_func, nullptr); 3726} 3727 3728TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsObjectReprIfNotDefined) { 3729 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3730 "SubclassedType", Py_nb_add, &emptyBinaryFunc, /*base=*/nullptr)); 3731 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3732 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3733 auto repr_func = reinterpret_cast<reprfunc>(PyType_GetSlot(tp, Py_tp_repr)); 3734 ASSERT_NE(repr_func, nullptr); 3735 3736 PyObjectPtr instance(_PyObject_CallNoArg(subclassed_type)); 3737 PyObjectPtr slot_result(repr_func(instance)); 3738 ASSERT_EQ(PyErr_Occurred(), nullptr); 3739 PyObjectPtr repr_result(PyObject_Repr(instance)); 3740 ASSERT_EQ(PyErr_Occurred(), nullptr); 3741 EXPECT_EQ(PyUnicode_Compare(slot_result, repr_result), 0); 3742} 3743 3744TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsObjectStrIfNotDefined) { 3745 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3746 "SubclassedType", Py_nb_add, &emptyBinaryFunc, /*base=*/nullptr)); 3747 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3748 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3749 auto str_func = reinterpret_cast<reprfunc>(PyType_GetSlot(tp, Py_tp_str)); 3750 ASSERT_NE(str_func, nullptr); 3751 3752 PyObjectPtr instance(_PyObject_CallNoArg(subclassed_type)); 3753 PyObjectPtr slot_result(str_func(instance)); 3754 ASSERT_EQ(PyErr_Occurred(), nullptr); 3755 PyObjectPtr str_result(PyObject_Str(instance)); 3756 ASSERT_EQ(PyErr_Occurred(), nullptr); 3757 EXPECT_EQ(PyUnicode_Compare(slot_result, str_result), 0); 3758} 3759 3760TEST_F(TypeExtensionApiTest, FromSpecWithBasesPopulatesTpInitIfNotDefined) { 3761 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3762 "SubclassedType", Py_nb_add, &emptyBinaryFunc, /*base=*/nullptr)); 3763 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3764 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3765 auto init_proc = reinterpret_cast<initproc>(PyType_GetSlot(tp, Py_tp_init)); 3766 ASSERT_NE(init_proc, nullptr); 3767} 3768 3769TEST_F(TypeExtensionApiTest, 3770 FromSpecWithBasesInheritsPyTypeGenericAllocIfNotDefined) { 3771 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3772 "SubclassedType", Py_nb_add, &emptyBinaryFunc, /*base=*/nullptr)); 3773 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3774 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3775 auto alloc_func = 3776 reinterpret_cast<allocfunc>(PyType_GetSlot(tp, Py_tp_alloc)); 3777 EXPECT_EQ(alloc_func, &PyType_GenericAlloc); 3778} 3779 3780TEST_F(TypeExtensionApiTest, FromSpecWithBasesPopulatesTpNewIfNotDefined) { 3781 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3782 "SubclassedType", Py_nb_add, &emptyBinaryFunc, /*base=*/nullptr)); 3783 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3784 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3785 auto new_func = reinterpret_cast<newfunc>(PyType_GetSlot(tp, Py_tp_init)); 3786 EXPECT_NE(new_func, nullptr); 3787} 3788 3789TEST_F(TypeExtensionApiTest, 3790 FromSpecWithBasesWithoutGcFlagInheritsObjectDelIfNotDefined) { 3791 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3792 "SubclassedType", Py_nb_add, &emptyBinaryFunc, /*base=*/nullptr)); 3793 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3794 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3795 auto free_func = reinterpret_cast<freefunc>(PyType_GetSlot(tp, Py_tp_free)); 3796 EXPECT_EQ(free_func, &PyObject_Del); 3797} 3798 3799TEST_F(TypeExtensionApiTest, 3800 FromSpecWithBasesWithGcFlagInheritsObjectGcDelIfNotDefined) { 3801 static PyType_Slot slots[1]; 3802 slots[0] = {0, nullptr}; 3803 static PyType_Spec spec; 3804 spec = { 3805 "__main__.SubclassedType", 3806 0, 3807 0, 3808 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, 3809 slots, 3810 }; 3811 PyObjectPtr type(PyType_FromSpecWithBases(&spec, /*bases=*/nullptr)); 3812 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 3813 auto free_func = reinterpret_cast<freefunc>(PyType_GetSlot(tp, Py_tp_free)); 3814 EXPECT_EQ(free_func, &PyObject_GC_Del); 3815} 3816 3817TEST_F(TypeExtensionApiTest, MethodIsInheirtedFromClassFromWinningParent) { 3818 // class C: 3819 // def __int__(self): 3820 // return 11 3821 unaryfunc c_int_func = [](PyObject*) { return PyLong_FromLong(11); }; 3822 static PyType_Slot c_slots[2]; 3823 c_slots[0] = {Py_nb_int, reinterpret_cast<void*>(c_int_func)}; 3824 c_slots[1] = {0, nullptr}; 3825 static PyType_Spec c_spec; 3826 c_spec = { 3827 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, c_slots, 3828 }; 3829 PyObjectPtr c_type(PyType_FromSpec(&c_spec)); 3830 ASSERT_NE(c_type, nullptr); 3831 ASSERT_EQ(PyType_CheckExact(c_type), 1); 3832 3833 // class D(C): 3834 // def __int__(self): 3835 // return 22 3836 unaryfunc d_int_func = [](PyObject*) { return PyLong_FromLong(22); }; 3837 static PyType_Slot d_slots[2]; 3838 d_slots[0] = {Py_nb_int, reinterpret_cast<void*>(d_int_func)}; 3839 d_slots[1] = {0, nullptr}; 3840 static PyType_Spec d_spec; 3841 d_spec = { 3842 "__main__.D", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, d_slots, 3843 }; 3844 PyObjectPtr d_bases(PyTuple_Pack(1, c_type.get())); 3845 PyObjectPtr d_type(PyType_FromSpecWithBases(&d_spec, d_bases)); 3846 ASSERT_NE(d_type, nullptr); 3847 ASSERT_EQ(PyType_CheckExact(d_type), 1); 3848 3849 // class B(C): pass 3850 static PyType_Slot b_slots[1]; 3851 b_slots[0] = {0, nullptr}; 3852 static PyType_Spec b_spec; 3853 b_spec = { 3854 "__main__.B", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, d_slots, 3855 }; 3856 PyObjectPtr b_bases(PyTuple_Pack(1, c_type.get())); 3857 PyObjectPtr b_type(PyType_FromSpecWithBases(&b_spec, b_bases)); 3858 ASSERT_NE(b_type, nullptr); 3859 ASSERT_EQ(PyType_CheckExact(b_type), 1); 3860 3861 // class A(B, C): pass 3862 static PyType_Slot a_slots[1]; 3863 a_slots[0] = {0, nullptr}; 3864 static PyType_Spec a_spec; 3865 a_spec = { 3866 "__main__.A", 0, 0, Py_TPFLAGS_DEFAULT, a_slots, 3867 }; 3868 PyObjectPtr a_bases(PyTuple_Pack(2, b_type.get(), d_type.get())); 3869 PyObjectPtr a_type(PyType_FromSpecWithBases(&a_spec, a_bases)); 3870 ASSERT_NE(a_type, nullptr); 3871 ASSERT_EQ(PyType_CheckExact(a_type), 1); 3872 3873 // MRO is (A, B, D, C, object) 3874 ASSERT_EQ(moduleSet("__main__", "A", a_type), 0); 3875 PyRun_SimpleString(R"( 3876a_mro = A.__mro__ 3877)"); 3878 PyObjectPtr a_mro(mainModuleGet("a_mro")); 3879 ASSERT_EQ(PyTuple_Check(a_mro), 1); 3880 ASSERT_EQ(PyTuple_GetItem(a_mro, 0), a_type); 3881 ASSERT_EQ(PyTuple_GetItem(a_mro, 1), b_type); 3882 ASSERT_EQ(PyTuple_GetItem(a_mro, 2), d_type); 3883 ASSERT_EQ(PyTuple_GetItem(a_mro, 3), c_type); 3884 3885 // Even though B inherited Py_tp_int from C, A should inherit it until 3886 // the first concrete definition, which is in D. 3887 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(a_type.get()); 3888 void* int_slot = PyType_GetSlot(tp, Py_nb_int); 3889 ASSERT_NE(int_slot, nullptr); 3890 EXPECT_NE(reinterpret_cast<unaryfunc>(int_slot), c_int_func); 3891 EXPECT_EQ(reinterpret_cast<unaryfunc>(int_slot), d_int_func); 3892} 3893 3894TEST_F(TypeExtensionApiTest, 3895 FromSpecWithBasesInheritsGcFlagAndTraverseClearSlots) { 3896 traverseproc empty_traverse_func = [](PyObject*, visitproc, void*) { 3897 return 0; 3898 }; 3899 inquiry empty_clear_func = [](PyObject*) { return 0; }; 3900 static PyType_Slot base_slots[3]; 3901 base_slots[0] = {Py_tp_traverse, 3902 reinterpret_cast<void*>(empty_traverse_func)}; 3903 base_slots[1] = {Py_tp_clear, reinterpret_cast<void*>(empty_clear_func)}; 3904 base_slots[2] = {0, nullptr}; 3905 static PyType_Spec base_spec; 3906 base_spec = { 3907 "__main__.BaseType", 3908 0, 3909 0, 3910 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, 3911 base_slots, 3912 }; 3913 PyObjectPtr base_type(PyType_FromSpec(&base_spec)); 3914 ASSERT_NE(base_type, nullptr); 3915 ASSERT_EQ(PyType_CheckExact(base_type), 1); 3916 3917 static PyType_Slot slots[1]; 3918 slots[0] = {0, nullptr}; 3919 static PyType_Spec spec; 3920 spec = { 3921 "__main__.SubclassedType", 0, 0, Py_TPFLAGS_DEFAULT, slots, 3922 }; 3923 PyObjectPtr bases(PyTuple_Pack(1, base_type.get())); 3924 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 3925 ASSERT_NE(type, nullptr); 3926 ASSERT_EQ(PyType_CheckExact(type), 1); 3927 3928 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(base_type.get()); 3929 EXPECT_NE(PyType_GetFlags(tp) & Py_TPFLAGS_HAVE_GC, 0UL); 3930 EXPECT_EQ(reinterpret_cast<traverseproc>(PyType_GetSlot(tp, Py_tp_traverse)), 3931 empty_traverse_func); 3932 EXPECT_EQ(reinterpret_cast<inquiry>(PyType_GetSlot(tp, Py_tp_clear)), 3933 empty_clear_func); 3934} 3935 3936TEST_F(TypeExtensionApiTest, FromSpecWithBasesInheritsNew) { 3937 newfunc empty_new_func = [](PyTypeObject*, PyObject*, PyObject*) { 3938 return Py_None; 3939 }; 3940 ASSERT_NO_FATAL_FAILURE( 3941 createTypeWithSlot("BaseType", Py_tp_new, empty_new_func)); 3942 PyObjectPtr base_type(mainModuleGet("BaseType")); 3943 ASSERT_NO_FATAL_FAILURE(createTypeWithSlotAndBase( 3944 "SubclassedType", Py_nb_add, &emptyBinaryFunc, base_type)); 3945 PyObjectPtr subclassed_type(mainModuleGet("SubclassedType")); 3946 3947 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(subclassed_type.get()); 3948 EXPECT_EQ(reinterpret_cast<newfunc>(PyType_GetSlot(tp, Py_tp_new)), 3949 empty_new_func); 3950} 3951 3952TEST_F(TypeExtensionApiTest, 3953 FromSpecWithMixedBasesSetsExtensionAsDominantBase) { 3954 struct ExtensionObject { 3955 PyObject_HEAD 3956 int native_data; 3957 }; 3958 3959 static PyType_Slot extension_slots[2]; 3960 extension_slots[0] = {0, nullptr}; 3961 3962 unsigned int flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; 3963 static PyType_Spec extension_spec = { 3964 "__main__.ExtensionBaseClass", 3965 sizeof(ExtensionObject), 3966 0, 3967 flags, 3968 extension_slots, 3969 }; 3970 PyObjectPtr extension_basetype(PyType_FromSpec(&extension_spec)); 3971 ASSERT_EQ(PyType_CheckExact(extension_basetype), 1); 3972 ASSERT_EQ(moduleSet("__main__", "ExtensionBaseClass", extension_basetype), 0); 3973 3974 PyRun_SimpleString(R"( 3975class SimpleManagedBaseClass: pass 3976 3977class Base(ExtensionBaseClass): pass 3978 3979class SubClass(SimpleManagedBaseClass, Base): pass 3980)"); 3981 3982 PyObjectPtr base(mainModuleGet("Base")); 3983 ASSERT_NE(base, nullptr); 3984 PyObjectPtr subclass(mainModuleGet("SubClass")); 3985 ASSERT_NE(subclass, nullptr); 3986 PyObjectPtr subclass_base(PyObject_GetAttrString(subclass, "__base__")); 3987 EXPECT_EQ(subclass_base.get(), base.get()); 3988} 3989 3990TEST_F(TypeExtensionApiTest, FromSpecWithoutBasicSizeInheritsDefaultBasicSize) { 3991 static PyType_Slot slots[1]; 3992 slots[0] = {0, nullptr}; 3993 static PyType_Spec spec; 3994 spec = { 3995 "__main__.Foo", 0, 0, Py_TPFLAGS_DEFAULT, slots, 3996 }; 3997 PyObjectPtr type(PyType_FromSpec(&spec)); 3998 ASSERT_NE(type, nullptr); 3999 ASSERT_EQ(PyType_CheckExact(type), 1); 4000 4001 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 4002 EXPECT_EQ(_PyObject_SIZE(tp), static_cast<Py_ssize_t>(sizeof(PyObject))); 4003} 4004 4005TEST_F(TypeExtensionApiTest, FromSpecWithoutAllocInheritsDefaultAlloc) { 4006 static PyType_Slot slots[1]; 4007 slots[0] = {0, nullptr}; 4008 static PyType_Spec spec; 4009 spec = { 4010 "__main__.Foo", sizeof(PyObject), 0, Py_TPFLAGS_DEFAULT, slots, 4011 }; 4012 PyObjectPtr type(PyType_FromSpec(&spec)); 4013 ASSERT_NE(type, nullptr); 4014 ASSERT_EQ(PyType_CheckExact(type), 1); 4015 4016 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 4017 ASSERT_EQ(reinterpret_cast<allocfunc>(PyType_GetSlot(tp, Py_tp_alloc)), 4018 &PyType_GenericAlloc); 4019} 4020 4021TEST_F(TypeExtensionApiTest, FromSpecWithoutNewInheritsDefaultNew) { 4022 static PyType_Slot slots[1]; 4023 slots[0] = {0, nullptr}; 4024 static PyType_Spec spec; 4025 spec = { 4026 "__main__.Foo", sizeof(PyObject), 0, Py_TPFLAGS_DEFAULT, slots, 4027 }; 4028 PyObjectPtr type(PyType_FromSpec(&spec)); 4029 ASSERT_NE(type, nullptr); 4030 ASSERT_EQ(PyType_CheckExact(type), 1); 4031 ASSERT_EQ(moduleSet("__main__", "Foo", type), 0); 4032 4033 // In Pyro tp_new = PyType_GenericNew, in CPython tp_new = object_new 4034 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 4035 ASSERT_NE(PyType_GetSlot(tp, Py_tp_new), nullptr); 4036} 4037 4038TEST_F(TypeExtensionApiTest, FromSpecWithoutDeallocInheritsDefaultDealloc) { 4039 struct FooObject { 4040 PyObject_HEAD 4041 int native_data; 4042 }; 4043 static PyType_Slot slots[1]; 4044 slots[0] = {0, nullptr}; 4045 static PyType_Spec spec; 4046 spec = { 4047 "__main__.Foo", sizeof(FooObject), 0, Py_TPFLAGS_DEFAULT, slots, 4048 }; 4049 PyObjectPtr type(PyType_FromSpec(&spec)); 4050 ASSERT_NE(type, nullptr); 4051 ASSERT_EQ(PyType_CheckExact(type), 1); 4052 4053 // type inherited subclassDealloc 4054 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 4055 ASSERT_NE(PyType_GetSlot(tp, Py_tp_dealloc), nullptr); 4056 Py_ssize_t type_refcnt = Py_REFCNT(tp); 4057 4058 // Create an instance 4059 FooObject* instance = PyObject_New(FooObject, tp); 4060 ASSERT_GE(Py_REFCNT(instance), 1); // CPython 4061 ASSERT_LE(Py_REFCNT(instance), 2); // Pyro 4062 ASSERT_EQ(Py_REFCNT(tp), type_refcnt + 1); 4063 4064 // Trigger a tp_dealloc 4065 Py_DECREF(instance); 4066 collectGarbage(); 4067 ASSERT_EQ(Py_REFCNT(tp), type_refcnt); 4068} 4069 4070TEST_F(TypeExtensionApiTest, DefaultDeallocCallsDelAndFinalize) { 4071 struct FooObject { 4072 PyObject_HEAD 4073 }; 4074 destructor del_func = [](PyObject*) { 4075 moduleSet("__main__", "called_del", Py_True); 4076 }; 4077 static PyType_Slot slots[2]; 4078 slots[0] = {Py_tp_del, reinterpret_cast<void*>(del_func)}; 4079 slots[1] = {0, nullptr}; 4080 static PyType_Spec spec; 4081 spec = { 4082 "__main__.Foo", sizeof(FooObject), 0, Py_TPFLAGS_DEFAULT, slots, 4083 }; 4084 PyObjectPtr type(PyType_FromSpec(&spec)); 4085 ASSERT_NE(type, nullptr); 4086 ASSERT_EQ(PyType_CheckExact(type), 1); 4087 4088 // type inherited subclassDealloc 4089 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 4090 ASSERT_NE(PyType_GetSlot(tp, Py_tp_dealloc), nullptr); 4091 Py_ssize_t type_refcnt = Py_REFCNT(tp); 4092 4093 // Create an instance 4094 FooObject* instance = PyObject_New(FooObject, tp); 4095 ASSERT_GE(Py_REFCNT(instance), 1); // CPython 4096 ASSERT_LE(Py_REFCNT(instance), 2); // Pyro 4097 ASSERT_EQ(Py_REFCNT(tp), type_refcnt + 1); 4098 4099 // Trigger a tp_dealloc 4100 Py_DECREF(instance); 4101 collectGarbage(); 4102 ASSERT_EQ(Py_REFCNT(tp), type_refcnt); 4103 PyObjectPtr called_del(testing::mainModuleGet("called_del")); 4104 EXPECT_EQ(called_del, Py_True); 4105} 4106 4107TEST_F(TypeExtensionApiTest, FromSpecWithBasesSubclassInheritsParentDealloc) { 4108 struct FooObject { 4109 PyObject_HEAD 4110 }; 4111 struct FooSubclassObject { 4112 FooObject base; 4113 }; 4114 destructor dealloc_func = [](PyObject* self) { 4115 PyTypeObject* tp = Py_TYPE(self); 4116 PyObject_Del(self); 4117 Py_DECREF(tp); 4118 }; 4119 static PyType_Slot base_slots[2]; 4120 base_slots[0] = {Py_tp_dealloc, reinterpret_cast<void*>(dealloc_func)}; 4121 base_slots[1] = {0, nullptr}; 4122 static PyType_Spec base_spec; 4123 base_spec = { 4124 "__main__.BaseType", 4125 sizeof(FooObject), 4126 0, 4127 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 4128 base_slots, 4129 }; 4130 PyObjectPtr base_type(PyType_FromSpec(&base_spec)); 4131 ASSERT_NE(base_type, nullptr); 4132 ASSERT_EQ(PyType_CheckExact(base_type), 1); 4133 4134 static PyType_Slot slots[1]; 4135 slots[0] = {0, nullptr}; 4136 static PyType_Spec spec; 4137 spec = { 4138 "__main__.SubclassedType", 4139 sizeof(FooSubclassObject), 4140 0, 4141 Py_TPFLAGS_DEFAULT, 4142 slots, 4143 }; 4144 PyObjectPtr bases(PyTuple_Pack(1, base_type.get())); 4145 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 4146 ASSERT_NE(type, nullptr); 4147 ASSERT_EQ(PyType_CheckExact(type), 1); 4148 4149 // type inherited subclassDealloc 4150 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 4151 ASSERT_NE(PyType_GetSlot(tp, Py_tp_dealloc), nullptr); 4152 Py_ssize_t type_refcnt = Py_REFCNT(tp); 4153 4154 // Create an instance 4155 FooObject* instance = PyObject_New(FooObject, tp); 4156 ASSERT_GE(Py_REFCNT(instance), 1); // CPython 4157 ASSERT_LE(Py_REFCNT(instance), 2); // Pyro 4158 ASSERT_EQ(Py_REFCNT(tp), type_refcnt + 1); 4159 4160 // Trigger a tp_dealloc 4161 Py_DECREF(instance); 4162 collectGarbage(); 4163 ASSERT_EQ(Py_REFCNT(tp), type_refcnt); 4164} 4165 4166TEST_F(TypeExtensionApiTest, FromSpecWithBasesSubclassInheritsDefaultDealloc) { 4167 struct FooObject { 4168 PyObject_HEAD 4169 int native_data; 4170 }; 4171 struct FooSubclassObject { 4172 FooObject base; 4173 }; 4174 static PyType_Slot base_slots[1]; 4175 base_slots[0] = {0, nullptr}; 4176 static PyType_Spec base_spec; 4177 base_spec = { 4178 "__main__.BaseType", 4179 sizeof(FooObject), 4180 0, 4181 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 4182 base_slots, 4183 }; 4184 PyObjectPtr base_type(PyType_FromSpec(&base_spec)); 4185 ASSERT_NE(base_type, nullptr); 4186 ASSERT_EQ(PyType_CheckExact(base_type), 1); 4187 4188 static PyType_Slot slots[1]; 4189 slots[0] = {0, nullptr}; 4190 static PyType_Spec spec; 4191 spec = { 4192 "__main__.SubclassedType", 4193 sizeof(FooSubclassObject), 4194 0, 4195 Py_TPFLAGS_DEFAULT, 4196 slots, 4197 }; 4198 PyObjectPtr bases(PyTuple_Pack(1, base_type.get())); 4199 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 4200 ASSERT_NE(type, nullptr); 4201 ASSERT_EQ(PyType_CheckExact(type), 1); 4202 4203 // type inherited subclassDealloc 4204 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 4205 ASSERT_NE(PyType_GetSlot(tp, Py_tp_dealloc), nullptr); 4206 Py_ssize_t type_refcnt = Py_REFCNT(tp); 4207 4208 // Create an instance 4209 FooObject* instance = PyObject_New(FooObject, tp); 4210 ASSERT_GE(Py_REFCNT(instance), 1); // CPython 4211 ASSERT_LE(Py_REFCNT(instance), 2); // Pyro 4212 ASSERT_EQ(Py_REFCNT(tp), type_refcnt + 1); 4213 4214 // Trigger a tp_dealloc 4215 Py_DECREF(instance); 4216 collectGarbage(); 4217 ASSERT_EQ(Py_REFCNT(tp), type_refcnt); 4218} 4219 4220TEST_F(TypeExtensionApiTest, TypeLookupSkipsInstanceDictionary) { 4221 PyRun_SimpleString(R"( 4222class Foo: 4223 bar = 2 4224 4225foo = Foo() 4226foo.bar = 1 4227)"); 4228 PyObjectPtr foo(mainModuleGet("foo")); 4229 PyObjectPtr foo_type(PyObject_Type(foo)); 4230 PyObjectPtr bar_str(PyUnicode_FromString("bar")); 4231 PyObject* res = 4232 _PyType_Lookup(reinterpret_cast<PyTypeObject*>(foo_type.get()), bar_str); 4233 ASSERT_EQ(PyErr_Occurred(), nullptr); 4234 ASSERT_NE(res, nullptr); 4235 EXPECT_TRUE(isLongEqualsLong(res, 2)); 4236} 4237 4238TEST_F(TypeExtensionApiTest, TypeLookupWithoutMatchDoesNotRaise) { 4239 PyRun_SimpleString(R"( 4240class Foo: pass 4241)"); 4242 PyObjectPtr foo_type(mainModuleGet("Foo")); 4243 PyObjectPtr bar_str(PyUnicode_FromString("bar")); 4244 PyObjectPtr res( 4245 _PyType_Lookup(reinterpret_cast<PyTypeObject*>(foo_type.get()), bar_str)); 4246 ASSERT_EQ(PyErr_Occurred(), nullptr); 4247 EXPECT_EQ(res, nullptr); 4248} 4249 4250TEST_F(TypeExtensionApiTest, TypeLookupWithNonStrDoesNotRaise) { 4251 PyRun_SimpleString(R"( 4252class Foo: pass 4253)"); 4254 PyObjectPtr foo_type(mainModuleGet("Foo")); 4255 PyObjectPtr res( 4256 _PyType_Lookup(reinterpret_cast<PyTypeObject*>(foo_type.get()), Py_None)); 4257 ASSERT_EQ(PyErr_Occurred(), nullptr); 4258 EXPECT_EQ(res, nullptr); 4259} 4260 4261TEST_F(TypeExtensionApiTest, FromSpecWithGCFlagCallsDealloc) { 4262 destructor dealloc_func = [](PyObject* self) { 4263 moduleSet("__main__", "called_del", Py_True); 4264 PyTypeObject* type = Py_TYPE(self); 4265 PyObject_GC_UnTrack(self); 4266 PyObject_GC_Del(self); 4267 Py_DECREF(type); 4268 }; 4269 static PyType_Slot slots[2]; 4270 slots[0] = {Py_tp_dealloc, reinterpret_cast<void*>(dealloc_func)}; 4271 slots[1] = {0, nullptr}; 4272 static PyType_Spec spec; 4273 spec = { 4274 "__main__.Foo", 4275 sizeof(PyObject), 4276 0, 4277 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, 4278 slots, 4279 }; 4280 PyObjectPtr type(PyType_FromSpec(&spec)); 4281 ASSERT_NE(type, nullptr); 4282 ASSERT_EQ(PyType_CheckExact(type), 1); 4283 4284 PyTypeObject* tp = reinterpret_cast<PyTypeObject*>(type.get()); 4285 ASSERT_NE(PyType_GetSlot(tp, Py_tp_dealloc), nullptr); 4286 Py_ssize_t type_refcnt = Py_REFCNT(tp); 4287 4288 // Create an instance 4289 PyObject* instance = PyObject_GC_New(PyObject, tp); 4290 PyObject_GC_Track(instance); 4291 ASSERT_GE(Py_REFCNT(instance), 1); // CPython 4292 ASSERT_LE(Py_REFCNT(instance), 2); // Pyro 4293 ASSERT_EQ(Py_REFCNT(tp), type_refcnt + 1); 4294 4295 // Trigger a tp_dealloc 4296 Py_DECREF(instance); 4297 collectGarbage(); 4298 ASSERT_EQ(Py_REFCNT(tp), type_refcnt); 4299 PyObjectPtr called_del(testing::mainModuleGet("called_del")); 4300 EXPECT_EQ(called_del, Py_True); 4301} 4302 4303TEST_F(TypeExtensionApiTest, ManagedTypeInheritsTpFlagsFromCType) { 4304 ASSERT_NO_FATAL_FAILURE(createBarTypeWithMembers()); 4305 ASSERT_EQ(PyRun_SimpleString(R"( 4306class Baz(Bar): pass 4307)"), 4308 0); 4309 PyObjectPtr baz_type(mainModuleGet("Baz")); 4310 EXPECT_TRUE(PyType_GetFlags(reinterpret_cast<PyTypeObject*>(baz_type.get())) & 4311 Py_TPFLAGS_HEAPTYPE); 4312} 4313 4314TEST_F(TypeExtensionApiTest, ManagedTypeInheritsFromCType) { 4315 ASSERT_NO_FATAL_FAILURE(createBarTypeWithMembers()); 4316 ASSERT_EQ(PyRun_SimpleString(R"( 4317r1 = Bar().t_bool 4318class Baz(Bar): pass 4319r2 = Baz().t_bool 4320r3 = Baz().t_object 4321)"), 4322 0); 4323 PyObjectPtr r1(mainModuleGet("r1")); 4324 ASSERT_EQ(PyBool_Check(r1), 1); 4325 EXPECT_EQ(r1, Py_True); 4326 PyObjectPtr r2(mainModuleGet("r2")); 4327 ASSERT_EQ(PyBool_Check(r2), 1); 4328 EXPECT_EQ(r2, Py_True); 4329 PyObjectPtr r3(mainModuleGet("r3")); 4330 ASSERT_EQ(PyList_Check(r3), 1); 4331 EXPECT_EQ(PyList_Size(r3), 0); 4332} 4333 4334TEST_F(TypeExtensionApiTest, ManagedTypeWithLayoutInheritsFromCType) { 4335 ASSERT_NO_FATAL_FAILURE(createBarTypeWithMembers()); 4336 ASSERT_EQ(PyRun_SimpleString(R"( 4337class Baz(Bar): 4338 def __init__(self): 4339 self.value = 123 4340baz = Baz() 4341r1 = baz.t_bool 4342r2 = baz.value 4343r3 = baz.t_object 4344)"), 4345 0); 4346 PyObjectPtr baz(mainModuleGet("baz")); 4347 ASSERT_NE(baz, nullptr); 4348 PyObjectPtr r1(mainModuleGet("r1")); 4349 ASSERT_EQ(PyBool_Check(r1), 1); 4350 EXPECT_EQ(r1, Py_False); 4351 PyObjectPtr r2(mainModuleGet("r2")); 4352 EXPECT_TRUE(isLongEqualsLong(r2, 123)); 4353 PyObjectPtr r3(mainModuleGet("r3")); 4354 EXPECT_FALSE(PyList_Check(r3)); 4355} 4356 4357TEST_F(TypeExtensionApiTest, CTypeWithSlotsBuiltinBaseTpNewCreatesNewInstance) { 4358 static PyType_Slot base_slots[1]; 4359 base_slots[0] = {0, nullptr}; 4360 static PyType_Spec base_spec; 4361 base_spec = { 4362 "__main__.BaseType", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, 4363 base_slots, 4364 }; 4365 PyObjectPtr base_bases(PyTuple_Pack(1, PyExc_Exception)); 4366 PyObjectPtr base_type(PyType_FromSpecWithBases(&base_spec, base_bases)); 4367 ASSERT_NE(base_type, nullptr); 4368 ASSERT_EQ(PyType_CheckExact(base_type), 1); 4369 ASSERT_EQ(moduleSet("__main__", "BaseType", base_type), 0); 4370 4371 newfunc new_func = [](PyTypeObject* t, PyObject* a, PyObject* k) { 4372 PyObjectPtr base(mainModuleGet("BaseType")); 4373 4374 newfunc base_tp_new = reinterpret_cast<newfunc>( 4375 PyType_GetSlot(base.asTypeObject(), Py_tp_new)); 4376 return base_tp_new(t, a, k); 4377 }; 4378 4379 static PyType_Slot slots[2]; 4380 slots[0] = {Py_tp_new, reinterpret_cast<void*>(new_func)}; 4381 slots[1] = {0, nullptr}; 4382 static PyType_Spec spec; 4383 spec = { 4384 "__main__.SubclassedType", 0, 0, Py_TPFLAGS_DEFAULT, slots, 4385 }; 4386 PyObjectPtr bases(PyTuple_Pack(1, base_type.get())); 4387 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 4388 ASSERT_NE(type, nullptr); 4389 ASSERT_EQ(PyType_CheckExact(type), 1); 4390 PyObjectPtr instance(_PyObject_CallNoArg(type)); 4391 ASSERT_NE(instance, nullptr); 4392 ASSERT_EQ(Py_TYPE(instance.get()), type.asTypeObject()); 4393} 4394 4395TEST_F(TypeExtensionApiTest, 4396 CTypeWithSlotsBuiltinBaseTpDeallocFreesInstancePyro) { 4397 destructor dealloc_func = [](PyObject* o) { 4398 PyTypeObject* tp = Py_TYPE(o); 4399 // Call the base type Py_tp_dealloc slot 4400 destructor base_dealloc = reinterpret_cast<destructor>(PyType_GetSlot( 4401 reinterpret_cast<PyTypeObject*>(PyExc_Exception), Py_tp_dealloc)); 4402 (*base_dealloc)(o); 4403 Py_DECREF(tp); 4404 }; 4405 4406 static PyType_Slot slots[2]; 4407 slots[0] = {Py_tp_dealloc, reinterpret_cast<void*>(dealloc_func)}; 4408 slots[1] = {0, nullptr}; 4409 static PyType_Spec spec; 4410 spec = { 4411 "__main__.SubclassedType", 0, 0, Py_TPFLAGS_DEFAULT, slots, 4412 }; 4413 PyObjectPtr bases(PyTuple_Pack(1, PyExc_Exception)); 4414 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 4415 ASSERT_NE(type, nullptr); 4416 ASSERT_EQ(PyType_CheckExact(type), 1); 4417 Py_ssize_t type_refcnt = Py_REFCNT(type); 4418 PyObject* instance = _PyObject_CallNoArg(type); 4419 ASSERT_NE(instance, nullptr); 4420 ASSERT_EQ(Py_TYPE(instance), type.asTypeObject()); 4421 ASSERT_EQ(Py_REFCNT(type), type_refcnt + 1); 4422 Py_DECREF(instance); 4423 collectGarbage(); 4424 ASSERT_EQ(Py_REFCNT(type), type_refcnt); 4425} 4426 4427TEST_F(TypeExtensionApiTest, CTypeInheritsFromManagedType) { 4428 ASSERT_EQ(PyRun_SimpleString(R"( 4429class Foo: 4430 def foo(self): 4431 return 123 4432)"), 4433 0); 4434 PyObjectPtr foo_type(mainModuleGet("Foo")); 4435 4436 struct FooObject { 4437 PyObject_HEAD 4438 PyObject* dict; 4439 int t_int; 4440 }; 4441 static PyMemberDef members[2]; 4442 members[0] = {"t_int", T_INT, offsetof(FooObject, t_int)}; 4443 members[1] = {nullptr}; 4444 initproc init_func = [](PyObject* self, PyObject*, PyObject*) { 4445 reinterpret_cast<FooObject*>(self)->t_int = 321; 4446 return 0; 4447 }; 4448 destructor dealloc_func = [](PyObject* self) { 4449 PyTypeObject* type = Py_TYPE(self); 4450 PyObject_GC_UnTrack(self); 4451 PyObject_GC_Del(self); 4452 Py_DECREF(type); 4453 }; 4454 static PyType_Slot slots[4]; 4455 slots[0] = {Py_tp_init, reinterpret_cast<void*>(init_func)}; 4456 slots[1] = {Py_tp_members, reinterpret_cast<void*>(members)}; 4457 slots[2] = {Py_tp_dealloc, reinterpret_cast<void*>(dealloc_func)}, 4458 slots[3] = {0, nullptr}; 4459 static PyType_Spec spec; 4460 spec = { 4461 "__main__.FooSubclass", 4462 sizeof(FooObject), 4463 0, 4464 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, 4465 slots, 4466 }; 4467 4468 PyObjectPtr bases(PyTuple_Pack(1, foo_type.get())); 4469 PyObjectPtr type(PyType_FromSpecWithBases(&spec, bases)); 4470 ASSERT_NE(type, nullptr); 4471 ASSERT_EQ(PyType_CheckExact(type), 1); 4472 ASSERT_EQ(moduleSet("__main__", "FooSubclass", type), 0); 4473 4474 ASSERT_EQ(PyRun_SimpleString(R"( 4475r1 = FooSubclass().foo() 4476r2 = FooSubclass().t_int 4477)"), 4478 0); 4479 PyObjectPtr r1(mainModuleGet("r1")); 4480 EXPECT_TRUE(isLongEqualsLong(r1, 123)); 4481 PyObjectPtr r2(mainModuleGet("r2")); 4482 EXPECT_TRUE(isLongEqualsLong(r2, 321)); 4483} 4484 4485TEST_F(TypeExtensionApiTest, MethodsMethFastWithKeywordsCallNoArg) { 4486 _PyCFunctionFastWithKeywords meth = [](PyObject* self, PyObject* const*, 4487 Py_ssize_t nargs, PyObject* kwnames) { 4488 EXPECT_EQ(kwnames, nullptr); 4489 PyObjectPtr nargs_obj(PyLong_FromSsize_t(nargs)); 4490 return PyTuple_Pack(2, self, nargs_obj.get()); 4491 }; 4492 static PyMethodDef methods[] = { 4493 {"fastcall", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 4494 METH_FASTCALL | METH_KEYWORDS}, 4495 {nullptr}}; 4496 PyType_Slot slots[] = { 4497 {Py_tp_methods, methods}, 4498 {0, nullptr}, 4499 }; 4500 static PyType_Spec spec; 4501 spec = { 4502 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 4503 }; 4504 4505 PyObjectPtr type(PyType_FromSpec(&spec)); 4506 ASSERT_NE(type, nullptr); 4507 testing::moduleSet("__main__", "C", type); 4508 4509 PyRun_SimpleString(R"( 4510self = C() 4511result = self.fastcall() 4512)"); 4513 PyObjectPtr self(testing::mainModuleGet("self")); 4514 PyObjectPtr result(testing::mainModuleGet("result")); 4515 ASSERT_NE(result, nullptr); 4516 ASSERT_EQ(PyTuple_CheckExact(result), 1); 4517 ASSERT_EQ(PyTuple_Size(result), 2); 4518 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 4519 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 1), 0)); 4520} 4521 4522TEST_F(TypeExtensionApiTest, MethodsMethFastWithKeywordsCallPosCall) { 4523 _PyCFunctionFastWithKeywords meth = [](PyObject* self, PyObject* const* args, 4524 Py_ssize_t nargs, PyObject* kwnames) { 4525 EXPECT_EQ(kwnames, nullptr); 4526 PyObjectPtr nargs_obj(PyLong_FromSsize_t(nargs)); 4527 return PyTuple_Pack(3, self, args[0], nargs_obj.get()); 4528 }; 4529 static PyMethodDef methods[] = { 4530 {"fastcall", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 4531 METH_FASTCALL | METH_KEYWORDS}, 4532 {nullptr}}; 4533 PyType_Slot slots[] = { 4534 {Py_tp_methods, methods}, 4535 {0, nullptr}, 4536 }; 4537 static PyType_Spec spec; 4538 spec = { 4539 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 4540 }; 4541 4542 PyObjectPtr type(PyType_FromSpec(&spec)); 4543 ASSERT_NE(type, nullptr); 4544 testing::moduleSet("__main__", "C", type); 4545 4546 PyRun_SimpleString(R"( 4547self = C() 4548result = self.fastcall(1234) 4549)"); 4550 PyObjectPtr self(testing::mainModuleGet("self")); 4551 PyObjectPtr result(testing::mainModuleGet("result")); 4552 ASSERT_NE(result, nullptr); 4553 ASSERT_EQ(PyTuple_CheckExact(result), 1); 4554 ASSERT_EQ(PyTuple_Size(result), 3); 4555 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 4556 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 1), 1234)); 4557 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 2), 1)); 4558} 4559 4560TEST_F(TypeExtensionApiTest, MethodsMethFastCallWithKeywordsPosCallMultiArgs) { 4561 _PyCFunctionFastWithKeywords meth = [](PyObject* self, PyObject* const* args, 4562 Py_ssize_t nargs, PyObject* kwnames) { 4563 EXPECT_EQ(kwnames, nullptr); 4564 PyObjectPtr nargs_obj(PyLong_FromSsize_t(nargs)); 4565 return PyTuple_Pack(4, self, args[0], args[1], nargs_obj.get()); 4566 }; 4567 static PyMethodDef methods[] = { 4568 {"fastcall", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 4569 METH_FASTCALL | METH_KEYWORDS}, 4570 {nullptr}}; 4571 PyType_Slot slots[] = { 4572 {Py_tp_methods, methods}, 4573 {0, nullptr}, 4574 }; 4575 static PyType_Spec spec; 4576 spec = { 4577 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 4578 }; 4579 4580 PyObjectPtr type(PyType_FromSpec(&spec)); 4581 ASSERT_NE(type, nullptr); 4582 testing::moduleSet("__main__", "C", type); 4583 4584 PyRun_SimpleString(R"( 4585self = C() 4586result = self.fastcall(1234, 5678) 4587)"); 4588 PyObjectPtr self(testing::mainModuleGet("self")); 4589 PyObjectPtr result(testing::mainModuleGet("result")); 4590 ASSERT_NE(result, nullptr); 4591 ASSERT_EQ(PyTuple_CheckExact(result), 1); 4592 ASSERT_EQ(PyTuple_Size(result), 4); 4593 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 4594 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 1), 1234)); 4595 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 2), 5678)); 4596 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 3), 2)); 4597} 4598 4599TEST_F(TypeExtensionApiTest, MethodsMethFastCallWithKeywordsKwCall) { 4600 _PyCFunctionFastWithKeywords meth = [](PyObject* self, PyObject* const* args, 4601 Py_ssize_t nargs, PyObject* kwnames) { 4602 PyObjectPtr nargs_obj(PyLong_FromSsize_t(nargs)); 4603 return PyTuple_Pack(5, self, args[0], args[1], nargs_obj.get(), kwnames); 4604 }; 4605 static PyMethodDef methods[] = { 4606 {"fastcall", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 4607 METH_FASTCALL | METH_KEYWORDS}, 4608 {nullptr}}; 4609 PyType_Slot slots[] = { 4610 {Py_tp_methods, methods}, 4611 {0, nullptr}, 4612 }; 4613 static PyType_Spec spec; 4614 spec = { 4615 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 4616 }; 4617 4618 PyObjectPtr type(PyType_FromSpec(&spec)); 4619 ASSERT_NE(type, nullptr); 4620 testing::moduleSet("__main__", "C", type); 4621 4622 PyRun_SimpleString(R"( 4623self = C() 4624result = self.fastcall(1234, kwarg=5678) 4625)"); 4626 PyObjectPtr self(testing::mainModuleGet("self")); 4627 PyObjectPtr result(testing::mainModuleGet("result")); 4628 ASSERT_NE(result, nullptr); 4629 ASSERT_EQ(PyTuple_CheckExact(result), 1); 4630 ASSERT_EQ(PyTuple_Size(result), 5); 4631 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 4632 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 1), 1234)); 4633 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 2), 5678)); 4634 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 3), 1)); 4635 4636 PyObject* kwnames = PyTuple_GetItem(result, 4); 4637 ASSERT_EQ(PyTuple_CheckExact(kwnames), 1); 4638 ASSERT_EQ(PyTuple_Size(kwnames), 1); 4639 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(kwnames, 0), "kwarg")); 4640} 4641 4642TEST_F(TypeExtensionApiTest, MethodsMethFastCallWithKeywordsKwCallMultiArg) { 4643 _PyCFunctionFastWithKeywords meth = [](PyObject* self, PyObject* const* args, 4644 Py_ssize_t nargs, PyObject* kwnames) { 4645 PyObjectPtr nargs_obj(PyLong_FromSsize_t(nargs)); 4646 return PyTuple_Pack(7, self, args[0], args[1], args[2], args[3], 4647 nargs_obj.get(), kwnames); 4648 }; 4649 static PyMethodDef methods[] = { 4650 {"fastcall", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 4651 METH_FASTCALL | METH_KEYWORDS}, 4652 {nullptr}}; 4653 PyType_Slot slots[] = { 4654 {Py_tp_methods, methods}, 4655 {0, nullptr}, 4656 }; 4657 static PyType_Spec spec; 4658 spec = { 4659 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 4660 }; 4661 4662 PyObjectPtr type(PyType_FromSpec(&spec)); 4663 ASSERT_NE(type, nullptr); 4664 testing::moduleSet("__main__", "C", type); 4665 4666 PyRun_SimpleString(R"( 4667self = C() 4668result = self.fastcall(1234, 99, kwarg=5678, kwdos=22) 4669)"); 4670 PyObjectPtr self(testing::mainModuleGet("self")); 4671 PyObjectPtr result(testing::mainModuleGet("result")); 4672 ASSERT_NE(result, nullptr); 4673 ASSERT_EQ(PyTuple_CheckExact(result), 1); 4674 ASSERT_EQ(PyTuple_Size(result), 7); 4675 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 4676 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 1), 1234)); 4677 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 2), 99)); 4678 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 3), 5678)); 4679 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 4), 22)); 4680 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 5), 2)); 4681 4682 PyObject* kwnames = PyTuple_GetItem(result, 6); 4683 ASSERT_EQ(PyTuple_CheckExact(kwnames), 1); 4684 ASSERT_EQ(PyTuple_Size(kwnames), 2); 4685 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(kwnames, 0), "kwarg")); 4686 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(kwnames, 1), "kwdos")); 4687} 4688 4689TEST_F(TypeExtensionApiTest, MethodsMethFastCallWithKeywordsExCall) { 4690 _PyCFunctionFastWithKeywords meth = [](PyObject* self, PyObject* const* args, 4691 Py_ssize_t nargs, PyObject* kwnames) { 4692 PyObjectPtr nargs_obj(PyLong_FromLong(nargs)); 4693 return PyTuple_Pack(5, self, args[0], args[1], nargs_obj.get(), kwnames); 4694 }; 4695 static PyMethodDef methods[] = { 4696 {"fastcall", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 4697 METH_FASTCALL | METH_KEYWORDS}, 4698 {nullptr}}; 4699 PyType_Slot slots[] = { 4700 {Py_tp_methods, methods}, 4701 {0, nullptr}, 4702 }; 4703 static PyType_Spec spec; 4704 spec = { 4705 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 4706 }; 4707 4708 PyObjectPtr type(PyType_FromSpec(&spec)); 4709 ASSERT_NE(type, nullptr); 4710 testing::moduleSet("__main__", "C", type); 4711 4712 PyRun_SimpleString(R"( 4713self = C() 4714result = self.fastcall(*[1234], kwarg=5678) 4715)"); 4716 PyObjectPtr self(testing::mainModuleGet("self")); 4717 PyObjectPtr result(testing::mainModuleGet("result")); 4718 ASSERT_NE(result, nullptr); 4719 ASSERT_EQ(PyTuple_CheckExact(result), 1); 4720 ASSERT_EQ(PyTuple_Size(result), 5); 4721 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 4722 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 1), 1234)); 4723 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 2), 5678)); 4724 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 3), 1)); 4725 4726 PyObject* kwnames = PyTuple_GetItem(result, 4); 4727 ASSERT_EQ(PyTuple_CheckExact(kwnames), 1); 4728 ASSERT_EQ(PyTuple_Size(kwnames), 1); 4729 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(kwnames, 0), "kwarg")); 4730} 4731 4732TEST_F(TypeExtensionApiTest, MethodsMethFastCallWithKeywordsExCallMultiArg) { 4733 _PyCFunctionFastWithKeywords meth = [](PyObject* self, PyObject* const* args, 4734 Py_ssize_t nargs, PyObject* kwnames) { 4735 PyObjectPtr nargs_obj(PyLong_FromSsize_t(nargs)); 4736 return PyTuple_Pack(7, self, args[0], args[1], args[2], args[3], 4737 nargs_obj.get(), kwnames); 4738 }; 4739 static PyMethodDef methods[] = { 4740 {"fastcall", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 4741 METH_FASTCALL | METH_KEYWORDS}, 4742 {nullptr}}; 4743 PyType_Slot slots[] = { 4744 {Py_tp_methods, methods}, 4745 {0, nullptr}, 4746 }; 4747 static PyType_Spec spec; 4748 spec = { 4749 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 4750 }; 4751 4752 PyObjectPtr type(PyType_FromSpec(&spec)); 4753 ASSERT_NE(type, nullptr); 4754 testing::moduleSet("__main__", "C", type); 4755 4756 PyRun_SimpleString(R"( 4757self = C() 4758result = self.fastcall(*[1234, 99], kwarg=5678, kwdos=22) 4759)"); 4760 PyObjectPtr self(testing::mainModuleGet("self")); 4761 PyObjectPtr result(testing::mainModuleGet("result")); 4762 ASSERT_NE(result, nullptr); 4763 ASSERT_EQ(PyTuple_CheckExact(result), 1); 4764 ASSERT_EQ(PyTuple_Size(result), 7); 4765 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 4766 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 1), 1234)); 4767 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 2), 99)); 4768 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 3), 5678)); 4769 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 4), 22)); 4770 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 5), 2)); 4771 4772 PyObject* kwnames = PyTuple_GetItem(result, 6); 4773 ASSERT_EQ(PyTuple_CheckExact(kwnames), 1); 4774 ASSERT_EQ(PyTuple_Size(kwnames), 2); 4775 4776 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(kwnames, 0), "kwarg")); 4777 EXPECT_TRUE(isUnicodeEqualsCStr(PyTuple_GetItem(kwnames, 1), "kwdos")); 4778} 4779 4780TEST_F(TypeExtensionApiTest, MethodsMethFastCallWithKeywordsExEmptyKwargsCall) { 4781 _PyCFunctionFastWithKeywords meth = [](PyObject* self, PyObject* const* args, 4782 Py_ssize_t nargs, PyObject* kwnames) { 4783 EXPECT_EQ(kwnames, nullptr); 4784 PyObjectPtr nargs_obj(PyLong_FromSsize_t(nargs)); 4785 return PyTuple_Pack(3, self, args[0], nargs_obj.get()); 4786 }; 4787 static PyMethodDef methods[] = { 4788 {"fastcall", reinterpret_cast<PyCFunction>(reinterpret_cast<void*>(meth)), 4789 METH_FASTCALL | METH_KEYWORDS}, 4790 {nullptr}}; 4791 PyType_Slot slots[] = { 4792 {Py_tp_methods, methods}, 4793 {0, nullptr}, 4794 }; 4795 static PyType_Spec spec; 4796 spec = { 4797 "__main__.C", 0, 0, Py_TPFLAGS_DEFAULT, slots, 4798 }; 4799 4800 PyObjectPtr type(PyType_FromSpec(&spec)); 4801 ASSERT_NE(type, nullptr); 4802 testing::moduleSet("__main__", "C", type); 4803 4804 PyRun_SimpleString(R"( 4805self = C() 4806result = self.fastcall(*[1234], *{}) 4807)"); 4808 PyObjectPtr self(testing::mainModuleGet("self")); 4809 PyObjectPtr result(testing::mainModuleGet("result")); 4810 ASSERT_NE(result, nullptr); 4811 ASSERT_EQ(PyTuple_CheckExact(result), 1); 4812 ASSERT_EQ(PyTuple_Size(result), 3); 4813 EXPECT_EQ(PyTuple_GetItem(result, 0), self); 4814 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 1), 1234)); 4815 EXPECT_TRUE(isLongEqualsLong(PyTuple_GetItem(result, 2), 1)); 4816} 4817 4818TEST(TypeExtensionApiTestNoFixture, DeallocSlotCalledDuringFinalize) { 4819 resetPythonEnv(); 4820 Py_Initialize(); 4821 4822 static bool destroyed; 4823 destroyed = false; 4824 destructor dealloc = [](PyObject* self) { 4825 PyTypeObject* type = Py_TYPE(self); 4826 destroyed = true; 4827 PyObject_Del(self); 4828 Py_DECREF(type); 4829 }; 4830 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_dealloc, dealloc)); 4831 4832 PyTypeObject* type = reinterpret_cast<PyTypeObject*>(mainModuleGet("Bar")); 4833 PyObject* obj = PyObject_New(PyObject, type); 4834 Py_DECREF(type); 4835 ASSERT_EQ(moduleSet("__main__", "bar_obj", obj), 0); 4836 Py_DECREF(obj); 4837 4838 ASSERT_FALSE(destroyed); 4839 Py_FinalizeEx(); 4840 ASSERT_TRUE(destroyed); 4841} 4842 4843TEST_F(TypeExtensionApiTest, CallIterSlotFromManagedCode) { 4844 unaryfunc iter_func = [](PyObject* self) { 4845 Py_INCREF(self); 4846 return self; 4847 }; 4848 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Foo", Py_tp_iter, iter_func)); 4849 4850 ASSERT_EQ(PyRun_SimpleString(R"( 4851f = Foo() 4852itr = f.__iter__() 4853)"), 4854 0); 4855 4856 PyObjectPtr f(mainModuleGet("f")); 4857 PyObjectPtr itr(mainModuleGet("itr")); 4858 EXPECT_EQ(f, itr); 4859} 4860 4861TEST_F(TypeExtensionApiTest, TypeCheckWithSameTypeReturnsTrue) { 4862 PyObjectPtr pylong(PyLong_FromLong(10)); 4863 PyObjectPtr pylong_type(PyObject_Type(pylong)); 4864 EXPECT_EQ(PyObject_TypeCheck( 4865 pylong, reinterpret_cast<PyTypeObject*>(pylong_type.get())), 4866 1); 4867} 4868 4869TEST_F(TypeExtensionApiTest, TypeCheckWithSubtypeReturnsTrue) { 4870 ASSERT_EQ(PyRun_SimpleString(R"( 4871class MyFloat(float): pass 4872myflt = MyFloat(1.23) 4873)"), 4874 0); 4875 PyObjectPtr myfloat(mainModuleGet("myflt")); 4876 PyObjectPtr pyfloat(PyFloat_FromDouble(3.21)); 4877 PyObjectPtr pyfloat_type(PyObject_Type(pyfloat)); 4878 EXPECT_EQ(PyObject_TypeCheck( 4879 myfloat, reinterpret_cast<PyTypeObject*>(pyfloat_type.get())), 4880 1); 4881} 4882 4883TEST_F(TypeExtensionApiTest, TypeCheckWithDifferentTypesReturnsFalse) { 4884 PyObjectPtr pylong(PyLong_FromLong(10)); 4885 PyObjectPtr pyuni(PyUnicode_FromString("string")); 4886 PyObjectPtr pyuni_type(PyObject_Type(pyuni)); 4887 EXPECT_EQ(PyObject_TypeCheck( 4888 pylong, reinterpret_cast<PyTypeObject*>(pyuni_type.get())), 4889 0); 4890} 4891 4892TEST_F(TypeExtensionApiTest, SetDunderClassWithExtensionTypeRaisesTypeError) { 4893 destructor dealloc = [](PyObject* self) { 4894 PyTypeObject* type = Py_TYPE(self); 4895 PyObject_Del(self); 4896 Py_DECREF(type); 4897 }; 4898 ASSERT_NO_FATAL_FAILURE(createTypeWithSlot("Bar", Py_tp_dealloc, dealloc)); 4899 4900 CaptureStdStreams streams; 4901 PyRun_SimpleString(R"( 4902bar = Bar() 4903class C: pass 4904bar.__class__ = C 4905)"); 4906 std::string err = streams.err(); 4907 EXPECT_NE(err.find("TypeError:"), std::string::npos); 4908 EXPECT_NE(err.find("__class__"), std::string::npos); 4909 EXPECT_NE(err.find("differs"), std::string::npos); 4910} 4911 4912TEST_F(TypeExtensionApiTest, TpDeallocWithoutFreeingMemoryUntracksNativeProxy) { 4913 // We test this indirectly with a typical freelist pattern; `PyObject_Init` 4914 // only works on memory that has been untracked before. 4915 static const int max_free = 4; 4916 static int numfree = 0; 4917 static PyObject* freelist[max_free]; 4918 4919 newfunc new_func = [](PyTypeObject* type, PyObject*, PyObject*) { 4920 PyObject* object; 4921 if (numfree > 0) { 4922 object = freelist[--numfree]; 4923 PyObject_Init(object, type); 4924 } else { 4925 object = PyObject_New(PyObject, type); 4926 } 4927 return object; 4928 }; 4929 destructor dealloc = [](PyObject* self) { 4930 PyTypeObject* type = Py_TYPE(self); 4931 Py_DECREF(type); 4932 if (numfree + 1 < max_free) { 4933 freelist[numfree++] = self; 4934 } else { 4935 freefunc tp_free = 4936 reinterpret_cast<freefunc>(PyType_GetSlot(type, Py_tp_free)); 4937 tp_free(self); 4938 } 4939 }; 4940 4941 static const PyType_Slot slots[] = { 4942 {Py_tp_new, reinterpret_cast<void*>(new_func)}, 4943 {Py_tp_dealloc, reinterpret_cast<void*>(dealloc)}, 4944 {0, nullptr}, 4945 }; 4946 static const PyType_Spec spec = { 4947 "foo", 0, 0, Py_TPFLAGS_DEFAULT, const_cast<PyType_Slot*>(slots), 4948 }; 4949 PyObjectPtr type(PyType_FromSpec(const_cast<PyType_Spec*>(&spec))); 4950 ASSERT_NE(type, nullptr); 4951 4952 PyObject* o0 = _PyObject_CallNoArg(type); 4953 PyObject* o1 = _PyObject_CallNoArg(type); 4954 Py_DECREF(o0); 4955 collectGarbage(); 4956 PyObject* o2 = _PyObject_CallNoArg(type); 4957 EXPECT_EQ(o0, o2); 4958 Py_DECREF(o1); 4959 collectGarbage(); 4960 PyObject* o3 = _PyObject_CallNoArg(type); 4961 EXPECT_EQ(o1, o3); 4962 PyObject* o4 = _PyObject_CallNoArg(type); 4963 Py_DECREF(o3); 4964 Py_DECREF(o2); 4965 Py_DECREF(o4); 4966} 4967 4968struct TpSlotTestObject { 4969 PyObject_HEAD 4970 int val0; 4971 int val1; 4972}; 4973static PyObject* makeTestInstanceWithSlots(const PyType_Slot* slots) { 4974 const PyType_Spec spec = { 4975 "foo", 4976 sizeof(TpSlotTestObject), 4977 0, 4978 Py_TPFLAGS_DEFAULT, 4979 const_cast<PyType_Slot*>(slots), 4980 }; 4981 PyObjectPtr type(PyType_FromSpec(const_cast<PyType_Spec*>(&spec))); 4982 if (type == nullptr) return nullptr; 4983 PyObject* instance(PyObject_CallFunction(type, nullptr)); 4984 if (instance == nullptr) return nullptr; 4985 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(instance); 4986 data->val0 = 42; 4987 data->val1 = 128077; 4988 return instance; 4989} 4990 4991TEST_F(TypeExtensionApiTest, CallDunderStrReturnsStr) { 4992 reprfunc func = [](PyObject* obj) -> PyObject* { 4993 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 4994 return PyUnicode_FromFormat("<str %d %c>", data->val0, data->val1); 4995 }; 4996 static const PyType_Slot slots[] = { 4997 {Py_tp_str, reinterpret_cast<void*>(func)}, 4998 {0, nullptr}, 4999 }; 5000 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5001 ASSERT_NE(instance, nullptr); 5002 PyObjectPtr result(PyObject_CallMethod(instance, "__str__", nullptr)); 5003 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<str 42 \xf0\x9f\x91\x8d>")); 5004} 5005 5006TEST_F(TypeExtensionApiTest, CallDunderReprReturnsStr) { 5007 reprfunc func = [](PyObject* obj) -> PyObject* { 5008 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5009 return PyUnicode_FromFormat("<repr %d %c>", data->val0, data->val1); 5010 }; 5011 static const PyType_Slot slots[] = { 5012 {Py_tp_repr, reinterpret_cast<void*>(func)}, 5013 {0, nullptr}, 5014 }; 5015 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5016 ASSERT_NE(instance, nullptr); 5017 PyObjectPtr result(PyObject_CallMethod(instance, "__repr__", nullptr)); 5018 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<repr 42 \xf0\x9f\x91\x8d>")); 5019} 5020 5021TEST_F(TypeExtensionApiTest, CallDunderIterReturnsStr) { 5022 getiterfunc func = [](PyObject* obj) -> PyObject* { 5023 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5024 return PyUnicode_FromFormat("<iter %d %c>", data->val0, data->val1); 5025 }; 5026 static const PyType_Slot slots[] = { 5027 {Py_tp_iter, reinterpret_cast<void*>(func)}, 5028 {0, nullptr}, 5029 }; 5030 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5031 ASSERT_NE(instance, nullptr); 5032 PyObjectPtr result(PyObject_CallMethod(instance, "__iter__", nullptr)); 5033 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<iter 42 \xf0\x9f\x91\x8d>")); 5034} 5035 5036TEST_F(TypeExtensionApiTest, CallDunderAwaitReturnsStr) { 5037 reprfunc func = [](PyObject* obj) -> PyObject* { 5038 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5039 return PyUnicode_FromFormat("<await %d %c>", data->val0, data->val1); 5040 }; 5041 static const PyType_Slot slots[] = { 5042 {Py_am_await, reinterpret_cast<void*>(func)}, 5043 {0, nullptr}, 5044 }; 5045 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5046 ASSERT_NE(instance, nullptr); 5047 PyObjectPtr result(PyObject_CallMethod(instance, "__await__", nullptr)); 5048 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<await 42 \xf0\x9f\x91\x8d>")); 5049} 5050 5051TEST_F(TypeExtensionApiTest, CallDunderAiterReturnsStr) { 5052 reprfunc func = [](PyObject* obj) -> PyObject* { 5053 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5054 return PyUnicode_FromFormat("<aiter %d %c>", data->val0, data->val1); 5055 }; 5056 static const PyType_Slot slots[] = { 5057 {Py_am_aiter, reinterpret_cast<void*>(func)}, 5058 {0, nullptr}, 5059 }; 5060 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5061 ASSERT_NE(instance, nullptr); 5062 PyObjectPtr result(PyObject_CallMethod(instance, "__aiter__", nullptr)); 5063 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<aiter 42 \xf0\x9f\x91\x8d>")); 5064} 5065 5066TEST_F(TypeExtensionApiTest, CallDunderAnextReturnsStr) { 5067 reprfunc func = [](PyObject* obj) -> PyObject* { 5068 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5069 return PyUnicode_FromFormat("<aiter %d %c>", data->val0, data->val1); 5070 }; 5071 static const PyType_Slot slots[] = { 5072 {Py_am_anext, reinterpret_cast<void*>(func)}, 5073 {0, nullptr}, 5074 }; 5075 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5076 ASSERT_NE(instance, nullptr); 5077 PyObjectPtr result(PyObject_CallMethod(instance, "__anext__", nullptr)); 5078 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<aiter 42 \xf0\x9f\x91\x8d>")); 5079} 5080 5081TEST_F(TypeExtensionApiTest, CallDunderNegReturnsStr) { 5082 reprfunc func = [](PyObject* obj) -> PyObject* { 5083 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5084 return PyUnicode_FromFormat("<neg %d %c>", data->val0, data->val1); 5085 }; 5086 static const PyType_Slot slots[] = { 5087 {Py_nb_negative, reinterpret_cast<void*>(func)}, 5088 {0, nullptr}, 5089 }; 5090 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5091 ASSERT_NE(instance, nullptr); 5092 PyObjectPtr result(PyObject_CallMethod(instance, "__neg__", nullptr)); 5093 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<neg 42 \xf0\x9f\x91\x8d>")); 5094} 5095 5096TEST_F(TypeExtensionApiTest, CallDunderPosReturnsStr) { 5097 reprfunc func = [](PyObject* obj) -> PyObject* { 5098 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5099 return PyUnicode_FromFormat("<pos %d %c>", data->val0, data->val1); 5100 }; 5101 static const PyType_Slot slots[] = { 5102 {Py_nb_positive, reinterpret_cast<void*>(func)}, 5103 {0, nullptr}, 5104 }; 5105 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5106 ASSERT_NE(instance, nullptr); 5107 PyObjectPtr result(PyObject_CallMethod(instance, "__pos__", nullptr)); 5108 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<pos 42 \xf0\x9f\x91\x8d>")); 5109} 5110 5111TEST_F(TypeExtensionApiTest, CallDunderAbsReturnsStr) { 5112 reprfunc func = [](PyObject* obj) -> PyObject* { 5113 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5114 return PyUnicode_FromFormat("<abs %d %c>", data->val0, data->val1); 5115 }; 5116 static const PyType_Slot slots[] = { 5117 {Py_nb_absolute, reinterpret_cast<void*>(func)}, 5118 {0, nullptr}, 5119 }; 5120 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5121 ASSERT_NE(instance, nullptr); 5122 PyObjectPtr result(PyObject_CallMethod(instance, "__abs__", nullptr)); 5123 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<abs 42 \xf0\x9f\x91\x8d>")); 5124} 5125 5126TEST_F(TypeExtensionApiTest, CallDunderInvertReturnsStr) { 5127 reprfunc func = [](PyObject* obj) -> PyObject* { 5128 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5129 return PyUnicode_FromFormat("<invert %d %c>", data->val0, data->val1); 5130 }; 5131 static const PyType_Slot slots[] = { 5132 {Py_nb_invert, reinterpret_cast<void*>(func)}, 5133 {0, nullptr}, 5134 }; 5135 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5136 ASSERT_NE(instance, nullptr); 5137 PyObjectPtr result(PyObject_CallMethod(instance, "__invert__", nullptr)); 5138 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<invert 42 \xf0\x9f\x91\x8d>")); 5139} 5140 5141TEST_F(TypeExtensionApiTest, CallDunderIntReturnsStr) { 5142 reprfunc func = [](PyObject* obj) -> PyObject* { 5143 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5144 return PyUnicode_FromFormat("<int %d %c>", data->val0, data->val1); 5145 }; 5146 static const PyType_Slot slots[] = { 5147 {Py_nb_int, reinterpret_cast<void*>(func)}, 5148 {0, nullptr}, 5149 }; 5150 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5151 ASSERT_NE(instance, nullptr); 5152 PyObjectPtr result(PyObject_CallMethod(instance, "__int__", nullptr)); 5153 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<int 42 \xf0\x9f\x91\x8d>")); 5154} 5155 5156TEST_F(TypeExtensionApiTest, CallDunderFloatReturnsStr) { 5157 reprfunc func = [](PyObject* obj) -> PyObject* { 5158 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5159 return PyUnicode_FromFormat("<float %d %c>", data->val0, data->val1); 5160 }; 5161 static const PyType_Slot slots[] = { 5162 {Py_nb_float, reinterpret_cast<void*>(func)}, 5163 {0, nullptr}, 5164 }; 5165 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5166 ASSERT_NE(instance, nullptr); 5167 PyObjectPtr result(PyObject_CallMethod(instance, "__float__", nullptr)); 5168 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<float 42 \xf0\x9f\x91\x8d>")); 5169} 5170 5171TEST_F(TypeExtensionApiTest, CallDunderIndexReturnsStr) { 5172 reprfunc func = [](PyObject* obj) -> PyObject* { 5173 TpSlotTestObject* data = reinterpret_cast<TpSlotTestObject*>(obj); 5174 return PyUnicode_FromFormat("<index %d %c>", data->val0, data->val1); 5175 }; 5176 static const PyType_Slot slots[] = { 5177 {Py_nb_index, reinterpret_cast<void*>(func)}, 5178 {0, nullptr}, 5179 }; 5180 PyObjectPtr instance(makeTestInstanceWithSlots(slots)); 5181 ASSERT_NE(instance, nullptr); 5182 PyObjectPtr result(PyObject_CallMethod(instance, "__index__", nullptr)); 5183 EXPECT_TRUE(isUnicodeEqualsCStr(result, "<index 42 \xf0\x9f\x91\x8d>")); 5184} 5185 5186TEST_F(TypeExtensionApiTest, MultipleInheritanceWithBaseWithoutSlotsWorks) { 5187 PyType_Slot slots[] = { 5188 {0, nullptr}, 5189 }; 5190 static PyType_Spec spec; 5191 int size = sizeof(PyObject) + 17; 5192 spec = { 5193 "foo.N", size, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots, 5194 }; 5195 PyObjectPtr ext_type(PyType_FromSpec(&spec)); 5196 moduleSet("__main__", "N", ext_type); 5197 EXPECT_EQ(PyRun_SimpleString(R"( 5198class A: 5199 pass 5200class C(A, N): 5201 pass 5202class D(C): 5203 pass 5204c = C() 5205d = D() 5206 )"), 5207 0); 5208 PyObjectPtr a(mainModuleGet("A")); 5209 PyObjectPtr c(mainModuleGet("C")); 5210 EXPECT_TRUE(PyType_GetFlags(reinterpret_cast<PyTypeObject*>(c.get())) & 5211 Py_TPFLAGS_DEFAULT); 5212 EXPECT_TRUE(PyType_GetFlags(reinterpret_cast<PyTypeObject*>(c.get())) & 5213 Py_TPFLAGS_BASETYPE); 5214 PyObjectPtr c_size(PyObject_GetAttrString(c.get(), "__basicsize__")); 5215 EXPECT_TRUE(PyLong_AsLong(c_size) >= size); 5216 5217 PyObjectPtr mro(PyObject_GetAttrString(c.get(), "__mro__")); 5218 EXPECT_TRUE(PyTuple_Check(mro)); 5219 EXPECT_EQ(PyTuple_GetItem(mro, 0), c.get()); 5220 EXPECT_EQ(PyTuple_GetItem(mro, 1), a.get()); 5221 EXPECT_EQ(PyTuple_GetItem(mro, 2), ext_type.get()); 5222 5223 PyObjectPtr base(PyObject_GetAttrString(c.get(), "__base__")); 5224 EXPECT_EQ(base.get(), ext_type.get()); 5225} 5226 5227struct TpSlotRefcntTestObject { 5228 PyObject_HEAD 5229 Py_ssize_t initial_refcnt; 5230}; 5231 5232static PyObject* makeTestRefcntInstanceWithSlots(const PyType_Slot* slots) { 5233 const PyType_Spec spec = { 5234 "foo", 5235 sizeof(TpSlotRefcntTestObject), 5236 0, 5237 Py_TPFLAGS_DEFAULT, 5238 const_cast<PyType_Slot*>(slots), 5239 }; 5240 PyObjectPtr type(PyType_FromSpec(const_cast<PyType_Spec*>(&spec))); 5241 if (type == nullptr) return nullptr; 5242 PyObject* instance = PyObject_CallFunction(type, nullptr); 5243 if (instance == nullptr) return nullptr; 5244 reinterpret_cast<TpSlotRefcntTestObject*>(instance)->initial_refcnt = 5245 Py_REFCNT(instance); 5246 return instance; 5247} 5248 5249TEST_F(TypeExtensionApiTest, IntegralSlotOwnsReference) { 5250 lenfunc len_func = [](PyObject* self) -> Py_ssize_t { 5251 // We expect a refcount of 1 greater than the inital refcount since the 5252 // method is called with a new reference. 5253 EXPECT_EQ( 5254 Py_REFCNT(self), 5255 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5256 return 0xdeadbeef; 5257 }; 5258 // __len__ is created as an integral slot 5259 static const PyType_Slot slots[] = { 5260 {Py_sq_length, reinterpret_cast<void*>(len_func)}, 5261 {0, nullptr}, 5262 }; 5263 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5264 ASSERT_NE(instance, nullptr); 5265 PyObjectPtr result(PyObject_CallMethod(instance, "__len__", nullptr)); 5266 // Once the call is complete the wrapper should decref the arg so we expect to 5267 // see the original refcount. 5268 EXPECT_EQ(Py_REFCNT(instance), 5269 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5270 ->initial_refcnt); 5271 EXPECT_TRUE(isLongEqualsLong(result, 0xdeadbeef)); 5272} 5273 5274TEST_F(TypeExtensionApiTest, UnarySlotOwnsReference) { 5275 reprfunc func = [](PyObject* obj) -> PyObject* { 5276 // We expect a refcount of 1 greater than the inital refcount since the 5277 // method is called with a new reference. 5278 EXPECT_EQ( 5279 Py_REFCNT(obj), 5280 reinterpret_cast<TpSlotRefcntTestObject*>(obj)->initial_refcnt + 1); 5281 Py_RETURN_NONE; 5282 }; 5283 // __repr__ is created as a unary slot 5284 static const PyType_Slot slots[] = { 5285 {Py_tp_repr, reinterpret_cast<void*>(func)}, 5286 {0, nullptr}, 5287 }; 5288 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5289 ASSERT_NE(instance, nullptr); 5290 PyObjectPtr result(PyObject_CallMethod(instance, "__repr__", nullptr)); 5291 // Once the call is complete the wrapper should decref the arg so we expect to 5292 // see the original refcount. 5293 EXPECT_EQ(Py_REFCNT(instance), 5294 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5295 ->initial_refcnt); 5296 EXPECT_EQ(result, Py_None); 5297} 5298 5299TEST_F(TypeExtensionApiTest, BinarySlotOwnsReference) { 5300 binaryfunc func = [](PyObject* self, PyObject* other) -> PyObject* { 5301 // We expect a refcount of 1 greater than the inital refcount since the 5302 // method is called with a new reference. 5303 EXPECT_EQ( 5304 Py_REFCNT(self), 5305 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5306 // TODO(T89073278): Revert to EQ(other, initial+1). 5307 EXPECT_GE( 5308 Py_REFCNT(other), 5309 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5310 Py_RETURN_NONE; 5311 }; 5312 // __add__ is created as a binary slot 5313 static const PyType_Slot slots[] = { 5314 {Py_nb_add, reinterpret_cast<void*>(func)}, 5315 {0, nullptr}, 5316 }; 5317 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5318 ASSERT_NE(instance, nullptr); 5319 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5320 ASSERT_NE(other, nullptr); 5321 PyObjectPtr result( 5322 PyObject_CallMethod(instance, "__add__", "O", other.get())); 5323 // Once the call is complete the wrapper should decref the arg so we expect to 5324 // see the original refcount. 5325 EXPECT_EQ(Py_REFCNT(instance), 5326 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5327 ->initial_refcnt); 5328 EXPECT_EQ( 5329 Py_REFCNT(other), 5330 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5331 EXPECT_EQ(result, Py_None); 5332} 5333 5334TEST_F(TypeExtensionApiTest, BinarySwappedSlotOwnsReference) { 5335 binaryfunc func = [](PyObject* self, PyObject* other) -> PyObject* { 5336 // We expect a refcount of 1 greater than the inital refcount since the 5337 // method is called with a new reference. 5338 // TODO(T89073278): Revert to EQ(other, initial+1). 5339 EXPECT_GE( 5340 Py_REFCNT(self), 5341 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5342 EXPECT_EQ( 5343 Py_REFCNT(other), 5344 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5345 Py_RETURN_NONE; 5346 }; 5347 // __add__ is created as a binary slot 5348 static const PyType_Slot slots[] = { 5349 {Py_nb_add, reinterpret_cast<void*>(func)}, 5350 {0, nullptr}, 5351 }; 5352 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5353 ASSERT_NE(instance, nullptr); 5354 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5355 ASSERT_NE(other, nullptr); 5356 PyObjectPtr result( 5357 PyObject_CallMethod(instance, "__radd__", "O", other.get())); 5358 // Once the call is complete the wrapper should decref the arg so we expect to 5359 // see the original refcount. 5360 EXPECT_EQ(Py_REFCNT(instance), 5361 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5362 ->initial_refcnt); 5363 EXPECT_EQ( 5364 Py_REFCNT(other), 5365 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5366 EXPECT_EQ(result, Py_None); 5367} 5368 5369TEST_F(TypeExtensionApiTest, TernarySlotOwnsReference) { 5370 ternaryfunc func = [](PyObject* self, PyObject* other, 5371 PyObject* third) -> PyObject* { 5372 // We expect a refcount of 1 greater than the inital refcount since the 5373 // method is called with a new reference. 5374 EXPECT_EQ( 5375 Py_REFCNT(self), 5376 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5377 // TODO(T89073278): Revert to EQ(other, initial+1). 5378 EXPECT_GE( 5379 Py_REFCNT(other), 5380 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5381 // TODO(T89073278): Revert to EQ(other, initial+1). 5382 EXPECT_GE( 5383 Py_REFCNT(third), 5384 reinterpret_cast<TpSlotRefcntTestObject*>(third)->initial_refcnt + 1); 5385 Py_RETURN_NONE; 5386 }; 5387 // __pow__ is created as a ternary slot 5388 static const PyType_Slot slots[] = { 5389 {Py_nb_power, reinterpret_cast<void*>(func)}, 5390 {0, nullptr}, 5391 }; 5392 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5393 ASSERT_NE(instance, nullptr); 5394 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5395 ASSERT_NE(other, nullptr); 5396 PyObjectPtr third(makeTestRefcntInstanceWithSlots(slots)); 5397 ASSERT_NE(third, nullptr); 5398 PyObjectPtr result( 5399 PyObject_CallMethod(instance, "__pow__", "OO", other.get(), third.get())); 5400 // Once the call is complete the wrapper should decref the arg so we expect to 5401 // see the original refcount. 5402 EXPECT_EQ(Py_REFCNT(instance), 5403 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5404 ->initial_refcnt); 5405 EXPECT_EQ( 5406 Py_REFCNT(other), 5407 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5408 EXPECT_EQ( 5409 Py_REFCNT(third), 5410 reinterpret_cast<TpSlotRefcntTestObject*>(third.get())->initial_refcnt); 5411 EXPECT_EQ(result, Py_None); 5412} 5413 5414TEST_F(TypeExtensionApiTest, TernarySwappedSlotOwnsReference) { 5415 ternaryfunc func = [](PyObject* self, PyObject* other, 5416 PyObject* third) -> PyObject* { 5417 // We expect a refcount of 1 greater than the inital refcount since the 5418 // method is called with a new reference. 5419 // TODO(T89073278): Revert to EQ(other, initial+1). 5420 EXPECT_GE( 5421 Py_REFCNT(self), 5422 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5423 EXPECT_EQ( 5424 Py_REFCNT(other), 5425 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5426 // TODO(T89073278): Revert to EQ(other, initial+1). 5427 EXPECT_GE( 5428 Py_REFCNT(third), 5429 reinterpret_cast<TpSlotRefcntTestObject*>(third)->initial_refcnt + 1); 5430 Py_RETURN_NONE; 5431 }; 5432 // __pow__ is created as a ternary slot 5433 static const PyType_Slot slots[] = { 5434 {Py_nb_power, reinterpret_cast<void*>(func)}, 5435 {0, nullptr}, 5436 }; 5437 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5438 ASSERT_NE(instance, nullptr); 5439 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5440 ASSERT_NE(other, nullptr); 5441 PyObjectPtr third(makeTestRefcntInstanceWithSlots(slots)); 5442 ASSERT_NE(third, nullptr); 5443 PyObjectPtr result(PyObject_CallMethod(instance, "__rpow__", "OO", 5444 other.get(), third.get())); 5445 // Once the call is complete the wrapper should decref the arg so we expect to 5446 // see the original refcount. 5447 EXPECT_EQ(Py_REFCNT(instance), 5448 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5449 ->initial_refcnt); 5450 EXPECT_EQ( 5451 Py_REFCNT(other), 5452 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5453 EXPECT_EQ( 5454 Py_REFCNT(third), 5455 reinterpret_cast<TpSlotRefcntTestObject*>(third.get())->initial_refcnt); 5456 EXPECT_EQ(result, Py_None); 5457} 5458 5459TEST_F(TypeExtensionApiTest, TernaryVarKwSlotOwnsReference) { 5460 ternaryfunc func = [](PyObject* self, PyObject* other, 5461 PyObject* third) -> PyObject* { 5462 // We expect a refcount of 1 greater than the inital refcount since the 5463 // method is called with a new reference. 5464 EXPECT_EQ( 5465 Py_REFCNT(self), 5466 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5467 EXPECT_EQ( 5468 Py_REFCNT(other), 5469 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5470 EXPECT_EQ( 5471 Py_REFCNT(third), 5472 reinterpret_cast<TpSlotRefcntTestObject*>(third)->initial_refcnt + 1); 5473 Py_RETURN_NONE; 5474 }; 5475 // __pow__ is created as a ternary slot 5476 static const PyType_Slot slots[] = { 5477 {Py_nb_power, reinterpret_cast<void*>(func)}, 5478 {0, nullptr}, 5479 }; 5480 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5481 ASSERT_NE(instance, nullptr); 5482 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5483 ASSERT_NE(other, nullptr); 5484 PyObjectPtr third(makeTestRefcntInstanceWithSlots(slots)); 5485 ASSERT_NE(third, nullptr); 5486 PyObjectPtr args(PyTuple_Pack(2, other.get(), third.get())); 5487 PyObjectPtr pow(PyObject_GetAttrString(instance, "__pow__")); 5488 PyObjectPtr result(PyObject_Call(pow, args, nullptr)); 5489 // Once the call is complete the wrapper should decref the arg so we expect to 5490 // see the original refcount. 5491 // TODO(T89073278): Revert to EQ(other, initial+1). 5492 EXPECT_GE(Py_REFCNT(instance), 5493 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5494 ->initial_refcnt); 5495 // TODO(T89073278): Revert to EQ(other, initial+1). 5496 EXPECT_GE( 5497 Py_REFCNT(other), 5498 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5499 // TODO(T89073278): Revert to EQ(other, initial+1). 5500 EXPECT_GE( 5501 Py_REFCNT(third), 5502 reinterpret_cast<TpSlotRefcntTestObject*>(third.get())->initial_refcnt); 5503 EXPECT_EQ(result, Py_None); 5504} 5505 5506TEST_F(TypeExtensionApiTest, SetattrWrapperOwnsReference) { 5507 setattrofunc func = [](PyObject* self, PyObject*, PyObject* third) -> int { 5508 // We expect a refcount of 1 greater than the inital refcount since the 5509 // method is called with a new reference. 5510 // TODO(T89073278): Revert to EQ(other, initial+1). 5511 EXPECT_LE( 5512 Py_REFCNT(self), 5513 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5514 // The middle arg is not checked because it needs to be a string, not 5515 // whatever object we use to hold a refcount. 5516 // TODO(T89073278): Revert to EQ(other, initial+1). 5517 EXPECT_LE( 5518 Py_REFCNT(third), 5519 reinterpret_cast<TpSlotRefcntTestObject*>(third)->initial_refcnt + 1); 5520 return 0; 5521 }; 5522 static const PyType_Slot slots[] = { 5523 {Py_tp_setattro, reinterpret_cast<void*>(func)}, 5524 {0, nullptr}, 5525 }; 5526 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5527 ASSERT_NE(instance, nullptr); 5528 PyObjectPtr other(PyUnicode_FromString("name")); 5529 ASSERT_NE(other, nullptr); 5530 PyObjectPtr third(makeTestRefcntInstanceWithSlots(slots)); 5531 ASSERT_NE(third, nullptr); 5532 int result = PyObject_SetAttr(instance, other, third); 5533 EXPECT_EQ(result, 0); 5534 // Once the call is complete the wrapper should decref the arg so we expect to 5535 // see the original refcount. 5536 EXPECT_EQ(Py_REFCNT(instance), 5537 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5538 ->initial_refcnt); 5539 // The middle arg is not checked because it needs to be a string, not 5540 // whatever object we use to hold a refcount. 5541 EXPECT_EQ( 5542 Py_REFCNT(third), 5543 reinterpret_cast<TpSlotRefcntTestObject*>(third.get())->initial_refcnt); 5544} 5545 5546TEST_F(TypeExtensionApiTest, DelattrWrapperOwnsReference) { 5547 setattrofunc func = [](PyObject* self, PyObject*, PyObject*) -> int { 5548 // We expect a refcount of 1 greater than the inital refcount since the 5549 // method is called with a new reference. 5550 // TODO(T89073278): Revert to EQ(other, initial+1). 5551 EXPECT_LE( 5552 Py_REFCNT(self), 5553 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5554 // The second arg is not checked because it needs to be a string, not 5555 // whatever object we use to hold a refcount. 5556 return 0; 5557 }; 5558 static const PyType_Slot slots[] = { 5559 {Py_tp_setattro, reinterpret_cast<void*>(func)}, 5560 {0, nullptr}, 5561 }; 5562 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5563 ASSERT_NE(instance, nullptr); 5564 PyObjectPtr other(PyUnicode_FromString("name")); 5565 ASSERT_NE(other, nullptr); 5566 // Need to set attribute before we can delete it. 5567 PyObjectPtr value(PyLong_FromLong(5)); 5568 int result = PyObject_SetAttr(instance, other, value); 5569 EXPECT_EQ(result, 0); 5570 result = PyObject_DelAttr(instance, other); 5571 EXPECT_EQ(result, 0); 5572 // Once the call is complete the wrapper should decref the arg so we expect to 5573 // see the original refcount. 5574 EXPECT_EQ(Py_REFCNT(instance), 5575 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5576 ->initial_refcnt); 5577 // The second arg is not checked because it needs to be a string, not 5578 // whatever object we use to hold a refcount. 5579} 5580 5581TEST_F(TypeExtensionApiTest, RichCmpSlotOwnsReference) { 5582 richcmpfunc func = [](PyObject* self, PyObject* other, int) -> PyObject* { 5583 // We expect a refcount of 1 greater than the inital refcount since the 5584 // method is called with a new reference. 5585 EXPECT_EQ( 5586 Py_REFCNT(self), 5587 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5588 // TODO(T89073278): Revert to EQ(other, initial+1). 5589 EXPECT_GE( 5590 Py_REFCNT(other), 5591 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5592 Py_RETURN_TRUE; 5593 }; 5594 static const PyType_Slot slots[] = { 5595 {Py_tp_richcompare, reinterpret_cast<void*>(func)}, 5596 {0, nullptr}, 5597 }; 5598 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5599 ASSERT_NE(instance, nullptr); 5600 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5601 ASSERT_NE(other, nullptr); 5602 PyObjectPtr result(PyObject_CallMethod(instance, "__eq__", "O", other.get())); 5603 // Once the call is complete the wrapper should decref the arg so we expect to 5604 // see the original refcount. 5605 EXPECT_EQ(Py_REFCNT(instance), 5606 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5607 ->initial_refcnt); 5608 EXPECT_EQ( 5609 Py_REFCNT(other), 5610 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5611 EXPECT_EQ(result, Py_True); 5612} 5613 5614TEST_F(TypeExtensionApiTest, NextSlotOwnsReference) { 5615 unaryfunc func = [](PyObject* obj) -> PyObject* { 5616 // We expect a refcount of 1 greater than the inital refcount since the 5617 // method is called with a new reference. 5618 EXPECT_EQ( 5619 Py_REFCNT(obj), 5620 reinterpret_cast<TpSlotRefcntTestObject*>(obj)->initial_refcnt + 1); 5621 Py_RETURN_NONE; 5622 }; 5623 static const PyType_Slot slots[] = { 5624 {Py_tp_iternext, reinterpret_cast<void*>(func)}, 5625 {0, nullptr}, 5626 }; 5627 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5628 ASSERT_NE(instance, nullptr); 5629 PyObjectPtr result(PyObject_CallMethod(instance, "__next__", nullptr)); 5630 // Once the call is complete the wrapper should decref the arg so we expect to 5631 // see the original refcount. 5632 EXPECT_EQ(Py_REFCNT(instance), 5633 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5634 ->initial_refcnt); 5635 EXPECT_EQ(result, Py_None); 5636} 5637 5638TEST_F(TypeExtensionApiTest, DescrGetSlotOwnsReference) { 5639 descrgetfunc func = [](PyObject* self, PyObject* other, 5640 PyObject* third) -> PyObject* { 5641 // We expect a refcount of 1 greater than the inital refcount since the 5642 // method is called with a new reference. 5643 EXPECT_EQ( 5644 Py_REFCNT(self), 5645 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5646 // TODO(T89073278): Revert to EQ(other, initial+1). 5647 EXPECT_GE( 5648 Py_REFCNT(other), 5649 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5650 // TODO(T89073278): Revert to EQ(other, initial+1). 5651 EXPECT_GE( 5652 Py_REFCNT(third), 5653 reinterpret_cast<TpSlotRefcntTestObject*>(third)->initial_refcnt + 1); 5654 Py_RETURN_NONE; 5655 }; 5656 static const PyType_Slot slots[] = { 5657 {Py_tp_descr_get, reinterpret_cast<void*>(func)}, 5658 {0, nullptr}, 5659 }; 5660 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5661 ASSERT_NE(instance, nullptr); 5662 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5663 ASSERT_NE(other, nullptr); 5664 PyObjectPtr third(makeTestRefcntInstanceWithSlots(slots)); 5665 ASSERT_NE(third, nullptr); 5666 PyObjectPtr result( 5667 PyObject_CallMethod(instance, "__get__", "OO", other.get(), third.get())); 5668 // Once the call is complete the wrapper should decref the arg so we expect to 5669 // see the original refcount. 5670 EXPECT_EQ(Py_REFCNT(instance), 5671 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5672 ->initial_refcnt); 5673 EXPECT_EQ( 5674 Py_REFCNT(other), 5675 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5676 EXPECT_EQ( 5677 Py_REFCNT(third), 5678 reinterpret_cast<TpSlotRefcntTestObject*>(third.get())->initial_refcnt); 5679 EXPECT_EQ(result, Py_None); 5680} 5681 5682TEST_F(TypeExtensionApiTest, DescrSetSlotOwnsReference) { 5683 descrsetfunc func = [](PyObject* self, PyObject* other, 5684 PyObject* third) -> int { 5685 // We expect a refcount of 1 greater than the inital refcount since the 5686 // method is called with a new reference. 5687 EXPECT_EQ( 5688 Py_REFCNT(self), 5689 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5690 // TODO(T89073278): Revert to EQ(other, initial+1). 5691 EXPECT_GE( 5692 Py_REFCNT(other), 5693 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5694 // TODO(T89073278): Revert to EQ(other, initial+1). 5695 EXPECT_GE( 5696 Py_REFCNT(third), 5697 reinterpret_cast<TpSlotRefcntTestObject*>(third)->initial_refcnt + 1); 5698 return 0; 5699 }; 5700 static const PyType_Slot slots[] = { 5701 {Py_tp_descr_set, reinterpret_cast<void*>(func)}, 5702 {0, nullptr}, 5703 }; 5704 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5705 ASSERT_NE(instance, nullptr); 5706 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5707 ASSERT_NE(other, nullptr); 5708 PyObjectPtr third(makeTestRefcntInstanceWithSlots(slots)); 5709 ASSERT_NE(third, nullptr); 5710 PyObjectPtr result( 5711 PyObject_CallMethod(instance, "__set__", "OO", other.get(), third.get())); 5712 // Once the call is complete the wrapper should decref the arg so we expect to 5713 // see the original refcount. 5714 EXPECT_EQ(Py_REFCNT(instance), 5715 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5716 ->initial_refcnt); 5717 EXPECT_EQ( 5718 Py_REFCNT(other), 5719 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5720 EXPECT_EQ( 5721 Py_REFCNT(third), 5722 reinterpret_cast<TpSlotRefcntTestObject*>(third.get())->initial_refcnt); 5723 EXPECT_EQ(result, Py_None); 5724} 5725 5726TEST_F(TypeExtensionApiTest, DescrDeleteSlotOwnsReference) { 5727 descrsetfunc func = [](PyObject* self, PyObject* other, 5728 PyObject* third) -> int { 5729 // We expect a refcount of 1 greater than the inital refcount since the 5730 // method is called with a new reference. 5731 EXPECT_EQ( 5732 Py_REFCNT(self), 5733 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5734 // TODO(T89073278): Revert to EQ(other, initial+1). 5735 EXPECT_GE( 5736 Py_REFCNT(other), 5737 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5738 EXPECT_EQ(third, nullptr); 5739 return 0; 5740 }; 5741 static const PyType_Slot slots[] = { 5742 {Py_tp_descr_set, reinterpret_cast<void*>(func)}, 5743 {0, nullptr}, 5744 }; 5745 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5746 ASSERT_NE(instance, nullptr); 5747 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5748 ASSERT_NE(other, nullptr); 5749 PyObjectPtr result( 5750 PyObject_CallMethod(instance, "__delete__", "O", other.get())); 5751 EXPECT_EQ(result, Py_None); 5752 // Once the call is complete the wrapper should decref the arg so we expect to 5753 // see the original refcount. 5754 EXPECT_EQ(Py_REFCNT(instance), 5755 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5756 ->initial_refcnt); 5757 EXPECT_EQ( 5758 Py_REFCNT(other), 5759 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5760} 5761 5762TEST_F(TypeExtensionApiTest, SetitemSlotOwnsReference) { 5763 objobjargproc func = [](PyObject* self, PyObject* other, 5764 PyObject* third) -> int { 5765 // We expect a refcount of 1 greater than the inital refcount since the 5766 // method is called with a new reference. 5767 EXPECT_EQ( 5768 Py_REFCNT(self), 5769 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5770 // TODO(T89073278): Revert to EQ(other, initial+1). 5771 EXPECT_GE( 5772 Py_REFCNT(other), 5773 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5774 // TODO(T89073278): Revert to EQ(other, initial+1). 5775 EXPECT_GE( 5776 Py_REFCNT(third), 5777 reinterpret_cast<TpSlotRefcntTestObject*>(third)->initial_refcnt + 1); 5778 return 0; 5779 }; 5780 static const PyType_Slot slots[] = { 5781 {Py_mp_ass_subscript, reinterpret_cast<void*>(func)}, 5782 {0, nullptr}, 5783 }; 5784 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5785 ASSERT_NE(instance, nullptr); 5786 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5787 ASSERT_NE(other, nullptr); 5788 PyObjectPtr third(makeTestRefcntInstanceWithSlots(slots)); 5789 ASSERT_NE(third, nullptr); 5790 PyObjectPtr result(PyObject_CallMethod(instance, "__setitem__", "OO", 5791 other.get(), third.get())); 5792 EXPECT_EQ(result, Py_None); 5793 // Once the call is complete the wrapper should decref the arg so we expect to 5794 // see the original refcount. 5795 EXPECT_EQ(Py_REFCNT(instance), 5796 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5797 ->initial_refcnt); 5798 EXPECT_EQ( 5799 Py_REFCNT(other), 5800 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5801 EXPECT_EQ( 5802 Py_REFCNT(third), 5803 reinterpret_cast<TpSlotRefcntTestObject*>(third.get())->initial_refcnt); 5804} 5805 5806TEST_F(TypeExtensionApiTest, DelitemSlotOwnsReference) { 5807 objobjargproc func = [](PyObject* self, PyObject* other, 5808 PyObject* third) -> int { 5809 // We expect a refcount of 1 greater than the inital refcount since the 5810 // method is called with a new reference. 5811 EXPECT_EQ( 5812 Py_REFCNT(self), 5813 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5814 // TODO(T89073278): Revert to EQ(other, initial+1). 5815 EXPECT_GE( 5816 Py_REFCNT(other), 5817 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5818 EXPECT_EQ(third, nullptr); 5819 return 0; 5820 }; 5821 static const PyType_Slot slots[] = { 5822 {Py_mp_ass_subscript, reinterpret_cast<void*>(func)}, 5823 {0, nullptr}, 5824 }; 5825 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5826 ASSERT_NE(instance, nullptr); 5827 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5828 ASSERT_NE(other, nullptr); 5829 PyObjectPtr result( 5830 PyObject_CallMethod(instance, "__delitem__", "O", other.get())); 5831 EXPECT_EQ(result, Py_None); 5832 // Once the call is complete the wrapper should decref the arg so we expect to 5833 // see the original refcount. 5834 EXPECT_EQ(Py_REFCNT(instance), 5835 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5836 ->initial_refcnt); 5837 EXPECT_EQ( 5838 Py_REFCNT(other), 5839 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5840} 5841 5842TEST_F(TypeExtensionApiTest, ContainsSlotOwnsReference) { 5843 objobjproc func = [](PyObject* self, PyObject* other) -> int { 5844 // We expect a refcount of 1 greater than the inital refcount since the 5845 // method is called with a new reference. 5846 EXPECT_EQ( 5847 Py_REFCNT(self), 5848 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5849 // TODO(T89073278): Revert to EQ(other, initial+1). 5850 EXPECT_GE( 5851 Py_REFCNT(other), 5852 reinterpret_cast<TpSlotRefcntTestObject*>(other)->initial_refcnt + 1); 5853 return 1; 5854 }; 5855 static const PyType_Slot slots[] = { 5856 {Py_sq_contains, reinterpret_cast<void*>(func)}, 5857 {0, nullptr}, 5858 }; 5859 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5860 ASSERT_NE(instance, nullptr); 5861 PyObjectPtr other(makeTestRefcntInstanceWithSlots(slots)); 5862 ASSERT_NE(other, nullptr); 5863 PyObjectPtr result( 5864 PyObject_CallMethod(instance, "__contains__", "O", other.get())); 5865 EXPECT_EQ(result, Py_True); 5866 // Once the call is complete the wrapper should decref the arg so we expect to 5867 // see the original refcount. 5868 EXPECT_EQ(Py_REFCNT(instance), 5869 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5870 ->initial_refcnt); 5871 EXPECT_EQ( 5872 Py_REFCNT(other), 5873 reinterpret_cast<TpSlotRefcntTestObject*>(other.get())->initial_refcnt); 5874} 5875 5876TEST_F(TypeExtensionApiTest, MulSlotOwnsReference) { 5877 ssizeargfunc func = [](PyObject* self, Py_ssize_t) -> PyObject* { 5878 // We expect a refcount of 1 greater than the inital refcount since the 5879 // method is called with a new reference. 5880 EXPECT_EQ( 5881 Py_REFCNT(self), 5882 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5883 Py_RETURN_NONE; 5884 }; 5885 static const PyType_Slot slots[] = { 5886 {Py_sq_repeat, reinterpret_cast<void*>(func)}, 5887 {0, nullptr}, 5888 }; 5889 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5890 ASSERT_NE(instance, nullptr); 5891 PyObjectPtr other(PyLong_FromLong(5)); 5892 ASSERT_NE(other, nullptr); 5893 PyObjectPtr result( 5894 PyObject_CallMethod(instance, "__mul__", "O", other.get())); 5895 EXPECT_EQ(result, Py_None); 5896 // Once the call is complete the wrapper should decref the arg so we expect to 5897 // see the original refcount. 5898 EXPECT_EQ(Py_REFCNT(instance), 5899 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5900 ->initial_refcnt); 5901} 5902 5903TEST_F(TypeExtensionApiTest, SequenceItemSlotOwnsReference) { 5904 ssizeargfunc func = [](PyObject* self, Py_ssize_t) -> PyObject* { 5905 // We expect a refcount of 1 greater than the inital refcount since the 5906 // method is called with a new reference. 5907 EXPECT_EQ( 5908 Py_REFCNT(self), 5909 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5910 Py_RETURN_NONE; 5911 }; 5912 static const PyType_Slot slots[] = { 5913 {Py_sq_item, reinterpret_cast<void*>(func)}, 5914 {0, nullptr}, 5915 }; 5916 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5917 ASSERT_NE(instance, nullptr); 5918 PyObjectPtr other(PyLong_FromLong(5)); 5919 ASSERT_NE(other, nullptr); 5920 PyObjectPtr result( 5921 PyObject_CallMethod(instance, "__getitem__", "O", other.get())); 5922 EXPECT_EQ(result, Py_None); 5923 // Once the call is complete the wrapper should decref the arg so we expect to 5924 // see the original refcount. 5925 EXPECT_EQ(Py_REFCNT(instance), 5926 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5927 ->initial_refcnt); 5928} 5929 5930TEST_F(TypeExtensionApiTest, SequenceSetItemSlotOwnsReference) { 5931 ssizeobjargproc func = [](PyObject* self, Py_ssize_t, 5932 PyObject* third) -> int { 5933 // We expect a refcount of 1 greater than the inital refcount since the 5934 // method is called with a new reference. 5935 EXPECT_EQ( 5936 Py_REFCNT(self), 5937 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5938 // TODO(T89073278): Revert to EQ(other, initial+1). 5939 EXPECT_GE( 5940 Py_REFCNT(third), 5941 reinterpret_cast<TpSlotRefcntTestObject*>(third)->initial_refcnt + 1); 5942 return 0; 5943 }; 5944 static const PyType_Slot slots[] = { 5945 {Py_sq_ass_item, reinterpret_cast<void*>(func)}, 5946 {0, nullptr}, 5947 }; 5948 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5949 ASSERT_NE(instance, nullptr); 5950 PyObjectPtr other(PyLong_FromLong(5)); 5951 ASSERT_NE(other, nullptr); 5952 PyObjectPtr third(makeTestRefcntInstanceWithSlots(slots)); 5953 ASSERT_NE(third, nullptr); 5954 PyObjectPtr result(PyObject_CallMethod(instance, "__setitem__", "OO", 5955 other.get(), third.get())); 5956 EXPECT_EQ(result, Py_None); 5957 // Once the call is complete the wrapper should decref the arg so we expect to 5958 // see the original refcount. 5959 EXPECT_EQ(Py_REFCNT(instance), 5960 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5961 ->initial_refcnt); 5962 EXPECT_EQ( 5963 Py_REFCNT(third), 5964 reinterpret_cast<TpSlotRefcntTestObject*>(third.get())->initial_refcnt); 5965} 5966 5967TEST_F(TypeExtensionApiTest, SequenceDelItemSlotOwnsReference) { 5968 ssizeobjargproc func = [](PyObject* self, Py_ssize_t, 5969 PyObject* third) -> int { 5970 // We expect a refcount of 1 greater than the inital refcount since the 5971 // method is called with a new reference. 5972 EXPECT_EQ( 5973 Py_REFCNT(self), 5974 reinterpret_cast<TpSlotRefcntTestObject*>(self)->initial_refcnt + 1); 5975 EXPECT_EQ(third, nullptr); 5976 return 0; 5977 }; 5978 static const PyType_Slot slots[] = { 5979 {Py_sq_ass_item, reinterpret_cast<void*>(func)}, 5980 {0, nullptr}, 5981 }; 5982 PyObjectPtr instance(makeTestRefcntInstanceWithSlots(slots)); 5983 ASSERT_NE(instance, nullptr); 5984 PyObjectPtr other(PyLong_FromLong(5)); 5985 ASSERT_NE(other, nullptr); 5986 PyObjectPtr result( 5987 PyObject_CallMethod(instance, "__delitem__", "O", other.get())); 5988 EXPECT_EQ(result, Py_None); 5989 // Once the call is complete the wrapper should decref the arg so we expect to 5990 // see the original refcount. 5991 EXPECT_EQ(Py_REFCNT(instance), 5992 reinterpret_cast<TpSlotRefcntTestObject*>(instance.get()) 5993 ->initial_refcnt); 5994} 5995 5996} // namespace testing 5997} // namespace py