ext/Objects/moduleobject-test.cpp (631 lines of code) (raw):

// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) #include "Python.h" #include "gtest/gtest.h" #include "capi-fixture.h" #include "capi-testing.h" namespace py { namespace testing { using ModuleExtensionApiTest = ExtensionApi; // Used to convert non-capturing closures into function pointers. using slot_func = int (*)(PyObject*); TEST_F(ModuleExtensionApiTest, SpamModule) { static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "spam", }; // PyInit_spam const long val = 5; { PyObjectPtr m(PyModule_Create(&def)); PyObject* de = PyDict_New(); PyModule_AddObject(m, "constants", de); const char* c = "CONST"; PyObjectPtr u(PyUnicode_FromString(c)); PyObjectPtr v(PyLong_FromLong(val)); PyModule_AddIntConstant(m, c, val); PyDict_SetItem(de, v, u); ASSERT_EQ(testing::moduleSet("__main__", "spam", m), 0); } PyRun_SimpleString("x = spam.CONST"); PyObjectPtr x(testing::mainModuleGet("x")); long result = PyLong_AsLong(x); ASSERT_EQ(result, val); } TEST_F(ModuleExtensionApiTest, GetDictReturnsMapping) { PyRun_SimpleString(R"( foo = 42 )"); PyObjectPtr name(PyUnicode_FromString("__main__")); PyObjectPtr main(importGetModule(name)); ASSERT_TRUE(PyModule_Check(main)); PyObject* module_dict = PyModule_GetDict(main); PyObjectPtr value(PyMapping_GetItemString(module_dict, "foo")); EXPECT_TRUE(isLongEqualsLong(value, 42)); } TEST_F(ModuleExtensionApiTest, NewObjectWithNonStringNameReturnsModule) { testing::PyObjectPtr long_name(PyLong_FromLong(2)); testing::PyObjectPtr module(PyModule_NewObject(long_name)); ASSERT_TRUE(PyModule_CheckExact(module)); testing::PyObjectPtr mod_name(PyObject_GetAttrString(module, "__name__")); EXPECT_EQ(mod_name, long_name); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, NewObjectDoesNotAddModuleToModuleDict) { testing::PyObjectPtr name(PyUnicode_FromString("mymodule")); testing::PyObjectPtr module(PyModule_NewObject(name)); ASSERT_TRUE(PyModule_CheckExact(module)); PyObject* mods = PyImport_GetModuleDict(); PyObject* item = PyDict_GetItem(mods, name); EXPECT_EQ(item, nullptr); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, NewWithEmptyStringReturnsModule) { testing::PyObjectPtr module(PyModule_New("")); ASSERT_TRUE(PyModule_CheckExact(module)); testing::PyObjectPtr mod_name(PyObject_GetAttrString(module, "__name__")); EXPECT_TRUE(isUnicodeEqualsCStr(mod_name, "")); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, NewDoesNotAddModuleToModuleDict) { testing::PyObjectPtr module(PyModule_New("mymodule")); ASSERT_TRUE(PyModule_CheckExact(module)); PyObject* mods = PyImport_GetModuleDict(); testing::PyObjectPtr name(PyUnicode_FromString("mymodule")); PyObject* item = PyDict_GetItem(mods, name); EXPECT_EQ(item, nullptr); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, CreateAddsDocstring) { const char* mod_doc = "documentation for spam"; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", mod_doc, }; PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__")); EXPECT_TRUE(isUnicodeEqualsCStr(doc, mod_doc)); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, CreateSetsStateNull) { static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); ASSERT_EQ(PyModule_GetState(module), nullptr); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, GetStateAllocatesAndAllowsMutation) { struct MyState { char letter; int number; double big_number; PyObject* object; }; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", "doc", sizeof(MyState), }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); ASSERT_EQ(PyState_AddModule(module, &def), 0); EXPECT_TRUE(PyModule_CheckExact(module)); void* state = PyModule_GetState(module); ASSERT_NE(state, nullptr); MyState* mod_state = static_cast<MyState*>(state); mod_state->letter = 'a'; mod_state->number = 2; mod_state->big_number = 2.1; testing::PyObjectPtr unique_obj(PyTuple_New(0)); mod_state->object = unique_obj; ASSERT_EQ(PyModule_GetState(module), state); EXPECT_EQ(mod_state->letter, 'a'); EXPECT_EQ(mod_state->number, 2); EXPECT_EQ(mod_state->big_number, 2.1); EXPECT_EQ(mod_state->object, unique_obj); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, GetStateFailsOnNonModule) { testing::PyObjectPtr not_a_module(PyLong_FromLong(0)); EXPECT_EQ(PyModule_GetState(not_a_module), nullptr); ASSERT_NE(PyErr_Occurred(), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); } TEST_F(ModuleExtensionApiTest, GetStateReturnsValidStateAfterGarbageCollected) { struct MyState { char letter; }; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", "doc", sizeof(MyState), }; PyObject* module = PyModule_Create(&def); ASSERT_NE(module, nullptr); ASSERT_EQ(PyState_AddModule(module, &def), 0); EXPECT_TRUE(PyModule_CheckExact(module)); void* state = PyModule_GetState(module); ASSERT_NE(state, nullptr); MyState* mod_state = static_cast<MyState*>(state); mod_state->letter = 'a'; // Decrease the reference count to zero. Py_DECREF(module); // Trigger GC to remove the module object from the handle table. collectGarbage(); // Verify that the module still retains the state. module = PyState_FindModule(&def); ASSERT_NE(module, nullptr); ASSERT_EQ(PyModule_GetState(module), state); mod_state = static_cast<MyState*>(state); EXPECT_EQ(mod_state->letter, 'a'); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, GetDefWithExtensionModuleRetunsNonNull) { static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", "mydoc", }; PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); PyModuleDef* result = PyModule_GetDef(module); EXPECT_EQ(result, &def); } TEST_F(ModuleExtensionApiTest, GetDefWithNonModuleRetunsNull) { PyObject* integer = PyBool_FromLong(0); PyModuleDef* result = PyModule_GetDef(integer); EXPECT_EQ(result, nullptr); } TEST_F(ModuleExtensionApiTest, GetDefWithNonExtensionModuleReturnsNull) { PyRun_SimpleString(""); PyObjectPtr module_name(PyUnicode_FromString("__main__")); PyObjectPtr main_module(testing::importGetModule(module_name)); PyModuleDef* result = PyModule_GetDef(main_module); EXPECT_EQ(result, nullptr); } TEST_F(ModuleExtensionApiTest, CheckTypeOnNonModuleReturnsZero) { PyObjectPtr pylong(PyLong_FromLong(10)); EXPECT_FALSE(PyModule_Check(pylong)); EXPECT_FALSE(PyModule_CheckExact(pylong)); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, CheckTypeOnModuleReturnsOne) { static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", }; PyObjectPtr module(PyModule_Create(&def)); EXPECT_TRUE(PyModule_Check(module)); EXPECT_TRUE(PyModule_CheckExact(module)); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, SetDocStringChangesDoc) { const char* mod_doc = "mymodule doc"; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", mod_doc, }; PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); PyObjectPtr orig_doc(PyObject_GetAttrString(module, "__doc__")); EXPECT_TRUE(isUnicodeEqualsCStr(orig_doc, mod_doc)); EXPECT_EQ(PyErr_Occurred(), nullptr); const char* edit_mod_doc = "edited doc"; int result = PyModule_SetDocString(module, edit_mod_doc); ASSERT_EQ(result, 0); PyObjectPtr edit_doc(PyObject_GetAttrString(module, "__doc__")); EXPECT_TRUE(isUnicodeEqualsCStr(edit_doc, edit_mod_doc)); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, SetDocStringCreatesDoc) { static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", }; PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); const char* edit_mod_doc = "edited doc"; ASSERT_EQ(PyModule_SetDocString(module, edit_mod_doc), 0); PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__")); EXPECT_TRUE(isUnicodeEqualsCStr(doc, edit_mod_doc)); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, SetDocStringSetsObjectAttribute) { PyRun_SimpleString(R"( class C: pass not_a_module = C() )"); PyObjectPtr not_a_module(mainModuleGet("not_a_module")); EXPECT_EQ(PyModule_SetDocString(not_a_module, "baz"), 0); PyObjectPtr value(PyObject_GetAttrString(not_a_module, "__doc__")); EXPECT_TRUE(isUnicodeEqualsCStr(value, "baz")); } TEST_F(ModuleExtensionApiTest, ModuleCreateDoesNotAddToModuleDict) { const char* name = "mymodule"; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, name, }; PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); PyObject* mods = PyImport_GetModuleDict(); PyObjectPtr name_obj(PyUnicode_FromString(name)); EXPECT_EQ(PyDict_GetItem(mods, name_obj), nullptr); } TEST_F(ModuleExtensionApiTest, GetNameObjectGetsName) { const char* mod_name = "mymodule"; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, mod_name, }; PyObject* module = PyModule_Create(&def); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_Check(module)); PyObject* result = PyModule_GetNameObject(module); EXPECT_TRUE(isUnicodeEqualsCStr(result, mod_name)); EXPECT_EQ(PyErr_Occurred(), nullptr); Py_DECREF(result); Py_DECREF(module); } TEST_F(ModuleExtensionApiTest, GetNameObjectFailsIfNotModule) { PyObject* not_a_module = PyTuple_New(10); PyObject* result = PyModule_GetNameObject(not_a_module); EXPECT_EQ(result, nullptr); ASSERT_NE(PyErr_Occurred(), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); Py_DECREF(not_a_module); } TEST_F(ModuleExtensionApiTest, GetNameObjectFailsIfNotString) { static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", }; PyObject* module = PyModule_Create(&def); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); PyObject* not_a_module = PyTuple_New(10); PyObject_SetAttrString(module, "__name__", not_a_module); PyObject* result = PyModule_GetNameObject(module); EXPECT_EQ(result, nullptr); ASSERT_NE(PyErr_Occurred(), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); Py_DECREF(module); Py_DECREF(not_a_module); } TEST_F(ModuleExtensionApiTest, GetNameObjectWithModuleSubclassReturnsString) { PyRun_SimpleString(R"( import builtins ModuleType = type(builtins) class C(ModuleType): pass module = C("foo") )"); PyObjectPtr module(mainModuleGet("module")); PyObjectPtr result(PyModule_GetNameObject(module)); EXPECT_TRUE(isUnicodeEqualsCStr(result, "foo")); } TEST_F(ModuleExtensionApiTest, GetFilenameObjectReturnsFilename) { static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_Check(module)); const char* filename = "file"; PyModule_AddObject(module, "__file__", PyUnicode_FromString(filename)); testing::PyObjectPtr result(PyModule_GetFilenameObject(module)); EXPECT_TRUE(isUnicodeEqualsCStr(result, filename)); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, GetFilenameObjectWithSubclassReturnsFilename) { PyRun_SimpleString(R"( import builtins ModuleType = type(builtins) class C(ModuleType): __file__ = "bar" module = C("foo") module.__file__ = "baz" )"); PyObjectPtr module(mainModuleGet("module")); PyObjectPtr result(PyModule_GetFilenameObject(module)); EXPECT_TRUE(isUnicodeEqualsCStr(result, "baz")); } TEST_F(ModuleExtensionApiTest, GetFilenameObjectFailsIfNotModule) { testing::PyObjectPtr not_a_module(PyLong_FromLong(1)); testing::PyObjectPtr result(PyModule_GetFilenameObject(not_a_module)); EXPECT_EQ(result, nullptr); ASSERT_NE(PyErr_Occurred(), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); } TEST_F(ModuleExtensionApiTest, GetFilenameObjectFailsIfFilenameNotString) { static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", }; PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); PyObject* not_a_string = PyLong_FromLong(1); PyModule_AddObject(module, "__file__", not_a_string); testing::PyObjectPtr result(PyModule_GetFilenameObject(module)); EXPECT_EQ(result, nullptr); ASSERT_NE(PyErr_Occurred(), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); } TEST_F(ModuleExtensionApiTest, ExecDefReturnsZeroWithNoSlots) { static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); EXPECT_EQ(PyModule_ExecDef(module, &def), 0); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, ExecDefFailsIfPassedNamelessModule) { static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", }; testing::PyObjectPtr module(PyModule_NewObject(Py_None)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); EXPECT_EQ(PyModule_ExecDef(module, &def), -1); EXPECT_NE(PyErr_Occurred(), nullptr); } // TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython TEST_F(ModuleExtensionApiTest, ExecDefFailsIfDefHasUnknownSlotPyro) { slot_func mod_exec = [](PyObject* module) { PyModule_SetDocString(module, "testing"); return 0; }; static PyModuleDef_Slot slots[] = { {-1, reinterpret_cast<void*>(mod_exec)}, {0, nullptr}, }; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots, }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); EXPECT_EQ(PyModule_ExecDef(module, &def), -1); ASSERT_NE(PyErr_Occurred(), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); } // TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython TEST_F(ModuleExtensionApiTest, ExecDefRunsCorrectSingleSlotPyro) { slot_func mod_exec = [](PyObject* module) { PyModule_SetDocString(module, "testing"); return 0; }; static PyModuleDef_Slot slots[] = { {Py_mod_exec, reinterpret_cast<void*>(mod_exec)}, {0, nullptr}, }; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots, }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); EXPECT_EQ(PyModule_ExecDef(module, &def), 0); testing::PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__")); EXPECT_TRUE(isUnicodeEqualsCStr(doc, "testing")); EXPECT_EQ(PyErr_Occurred(), nullptr); } // TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython TEST_F(ModuleExtensionApiTest, ExecDefRunsMultipleSlotsInOrderPyro) { slot_func mod_exec = [](PyObject* module) { PyModule_SetDocString(module, "doc test"); return 0; }; slot_func mod_exec_second = [](PyObject* module) { PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__")); if (doc != nullptr) { PyObjectPtr attr(PyUnicode_FromString("testing1")); PyObject_SetAttrString(module, "test1", attr); } return 0; }; slot_func mod_exec_third = [](PyObject* module) { PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__")); if (doc != nullptr) { PyObjectPtr attr(PyUnicode_FromString("testing2")); PyObject_SetAttrString(module, "test2", attr); } return 0; }; static PyModuleDef_Slot slots[] = { {Py_mod_exec, reinterpret_cast<void*>(mod_exec)}, {Py_mod_exec, reinterpret_cast<void*>(mod_exec_second)}, {Py_mod_exec, reinterpret_cast<void*>(mod_exec_third)}, {0, nullptr}, }; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots, }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); EXPECT_EQ(PyModule_ExecDef(module, &def), 0); testing::PyObjectPtr doc(PyObject_GetAttrString(module, "__doc__")); EXPECT_TRUE(isUnicodeEqualsCStr(doc, "doc test")); testing::PyObjectPtr test_attr_one(PyObject_GetAttrString(module, "test1")); EXPECT_TRUE(isUnicodeEqualsCStr(test_attr_one, "testing1")); testing::PyObjectPtr test_attr_two(PyObject_GetAttrString(module, "test2")); EXPECT_TRUE(isUnicodeEqualsCStr(test_attr_two, "testing2")); EXPECT_EQ(PyErr_Occurred(), nullptr); } // TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython TEST_F(ModuleExtensionApiTest, ExecDefFailsIfSlotHasErrorButReturnsZeroPyro) { slot_func mod_exec_fail_silently = [](PyObject* module) { testing::PyObjectPtr attr(PyObject_GetAttrString(module, "non-existent")); static_cast<void>(attr); return 0; }; static PyModuleDef_Slot slots[] = { {Py_mod_exec, reinterpret_cast<void*>(mod_exec_fail_silently)}, {0, nullptr}, }; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots, }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); EXPECT_EQ(PyModule_ExecDef(module, &def), -1); ASSERT_NE(PyErr_Occurred(), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); } // TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython TEST_F(ModuleExtensionApiTest, ExecDefFailsIfSlotFailsButDoesntSetErrorPyro) { slot_func mod_exec_fail_no_error = [](PyObject* module) { testing::PyObjectPtr attr(PyObject_GetAttrString(module, "non-existent")); static_cast<void>(attr); PyErr_Clear(); return -1; }; static PyModuleDef_Slot slots[] = { {Py_mod_exec, reinterpret_cast<void*>(mod_exec_fail_no_error)}, {0, nullptr}, }; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots, }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); EXPECT_EQ(PyModule_ExecDef(module, &def), -1); ASSERT_NE(PyErr_Occurred(), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); } // TODO(T37048769): Replace _Create with _FromDefAndSpec and run with CPython TEST_F(ModuleExtensionApiTest, ExecDefFailsIfSlotFailsAndPropogatesErrorPyro) { slot_func mod_exec_fail = [](PyObject* module) { testing::PyObjectPtr attr(PyObject_GetAttrString(module, "non-existent")); static_cast<void>(attr); return -1; }; static PyModuleDef_Slot slots[] = { {Py_mod_exec, reinterpret_cast<void*>(mod_exec_fail)}, {0, nullptr}, }; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "mymodule", nullptr, 0, nullptr, slots, }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_CheckExact(module)); EXPECT_EQ(PyModule_ExecDef(module, &def), -1); ASSERT_NE(PyErr_Occurred(), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError)); } TEST_F(ModuleExtensionApiTest, GetNameGetsName) { const char* mod_name = "mymodule"; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, mod_name, }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_Check(module)); EXPECT_STREQ(PyModule_GetName(module), mod_name); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, GetNameReturnsNullIfNoName) { testing::PyObjectPtr not_a_module(PyLong_FromLong(1)); EXPECT_EQ(PyModule_GetName(not_a_module), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); } TEST_F(ModuleExtensionApiTest, GetNameDoesNotIncrementModuleNameRefcount) { const char* mod_name = "mymodule"; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, mod_name, }; testing::PyObjectPtr module(PyModule_Create(&def)); ASSERT_NE(module, nullptr); EXPECT_TRUE(PyModule_Check(module)); PyObjectPtr name(PyModule_GetNameObject(module)); EXPECT_TRUE(isUnicodeEqualsCStr(name, mod_name)); Py_ssize_t name_count = Py_REFCNT(name); EXPECT_STREQ(PyModule_GetName(module), mod_name); EXPECT_EQ(Py_REFCNT(name), name_count); EXPECT_EQ(PyErr_Occurred(), nullptr); } TEST_F(ModuleExtensionApiTest, MethodWithClassFlagRaisesException) { binaryfunc foo_func = [](PyObject*, PyObject*) { return PyLong_FromLong(10); }; PyMethodDef foo_methods[] = { {"longValue", foo_func, METH_NOARGS | METH_CLASS}, {nullptr}}; static PyModuleDef def; def = { PyModuleDef_HEAD_INIT, "foo", nullptr, 0, foo_methods, }; PyObjectPtr module(PyModule_Create(&def)); EXPECT_EQ(module, nullptr); EXPECT_NE(PyErr_Occurred(), nullptr); EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError)); } static PyObject* init_extra_builtin_module(void) { static PyModuleDef def; def = {PyModuleDef_HEAD_INIT, "extra_builtin"}; return PyModule_Create(&def); } static PyObject* init_extra_extra_builtin_module(void) { static PyModuleDef def; def = {PyModuleDef_HEAD_INIT, "extra_extra_builtin"}; return PyModule_Create(&def); } TEST(ModuleExtensionApiTestNoFixture, PyImportAppendInittabExtendInittab) { resetPythonEnv(); PyImport_AppendInittab("extra_builtin", init_extra_builtin_module); PyImport_AppendInittab("extra_extra_builtin", init_extra_extra_builtin_module); Py_Initialize(); PyRun_SimpleString(R"( import sys a = "extra_builtin" in sys.builtin_module_names b = "extra_extra_builtin" in sys.builtin_module_names c = "not_added" in sys.builtin_module_names )"); ASSERT_EQ(PyErr_Occurred(), nullptr); PyObjectPtr pybool_true(PyBool_FromLong(1)); PyObjectPtr pybool_false(PyBool_FromLong(0)); PyObjectPtr a(mainModuleGet("a")); PyObjectPtr b(mainModuleGet("b")); PyObjectPtr c(mainModuleGet("c")); ASSERT_EQ(pybool_true, a); ASSERT_EQ(pybool_true, b); ASSERT_EQ(pybool_false, c); Py_FinalizeEx(); } } // namespace testing } // namespace py