this repo has no description
at trunk 365 lines 11 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include <unistd.h> 3 4#include <climits> 5#include <cstdlib> 6#include <string> 7 8#include "Python.h" 9#include "gtest/gtest.h" 10 11#include "capi-fixture.h" 12#include "capi-testing.h" 13 14namespace py { 15namespace testing { 16 17using SysModuleExtensionApiTest = ExtensionApi; 18 19TEST_F(SysModuleExtensionApiTest, GetObjectWithNonExistentNameReturnsNull) { 20 EXPECT_EQ(PySys_GetObject("foo_bar_not_a_real_name"), nullptr); 21 EXPECT_EQ(PyErr_Occurred(), nullptr); 22} 23 24TEST_F(SysModuleExtensionApiTest, GetObjectReturnsValueFromSysModule) { 25 PyRun_SimpleString(R"( 26import sys 27sys.foo = 'bar' 28)"); 29 PyObject* result = PySys_GetObject("foo"); // borrowed reference 30 EXPECT_EQ(PyErr_Occurred(), nullptr); 31 EXPECT_TRUE(isUnicodeEqualsCStr(result, "bar")); 32} 33 34TEST_F(SysModuleExtensionApiTest, GetSizeOfPropagatesException) { 35 PyRun_SimpleString(R"( 36class C: 37 def __sizeof__(self): raise Exception() 38o = C() 39)"); 40 PyObjectPtr object(mainModuleGet("o")); 41 EXPECT_EQ(_PySys_GetSizeOf(object), static_cast<size_t>(-1)); 42 ASSERT_NE(PyErr_Occurred(), nullptr); 43 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_Exception)); 44} 45 46TEST_F(SysModuleExtensionApiTest, GetSizeOfReturnsDunderSizeOfPyro) { 47 PyRun_SimpleString(R"( 48class C: 49 def __sizeof__(self): return 10 50o = C() 51)"); 52 PyObjectPtr object(mainModuleGet("o")); 53 EXPECT_EQ(_PySys_GetSizeOf(object), size_t{10}); 54 EXPECT_EQ(PyErr_Occurred(), nullptr); 55} 56 57TEST_F(SysModuleExtensionApiTest, GetSizeOfWithIntSubclassReturnsIntPyro) { 58 PyRun_SimpleString(R"( 59class N(int): pass 60class C: 61 def __sizeof__(self): return N(10) 62o = C() 63)"); 64 PyObjectPtr object(mainModuleGet("o")); 65 EXPECT_EQ(_PySys_GetSizeOf(object), size_t{10}); 66 EXPECT_EQ(PyErr_Occurred(), nullptr); 67} 68 69TEST_F(SysModuleExtensionApiTest, WriteStdout) { 70 CaptureStdStreams streams; 71 PySys_WriteStdout("Hello, %s!", "World"); 72 EXPECT_EQ(streams.out(), "Hello, World!"); 73 EXPECT_EQ(streams.err(), ""); 74} 75 76TEST_F( 77 SysModuleExtensionApiTest, 78 WriteStdoutCallsSysStdoutWriteOnExceptionWritesToFallbackAndClearsError) { 79 PyRun_SimpleString(R"( 80import sys 81x = 7 82class C: 83 def write(self, text): 84 global x 85 x = 42 86 raise UserWarning() 87 88sys.stdout = C() 89)"); 90 CaptureStdStreams streams; 91 PySys_WriteStdout("a"); 92 EXPECT_EQ(streams.out(), "a"); 93 EXPECT_EQ(streams.err(), ""); 94 ASSERT_EQ(PyErr_Occurred(), nullptr); 95 PyObjectPtr x(mainModuleGet("x")); 96 EXPECT_EQ(PyLong_AsLong(x), 42); 97} 98 99TEST_F(SysModuleExtensionApiTest, WriteStdoutWithSysStdoutNoneWritesToStdout) { 100 PyRun_SimpleString(R"( 101import sys 102sys.stdout = None 103)"); 104 CaptureStdStreams streams; 105 PySys_WriteStdout("Hello"); 106 EXPECT_EQ(streams.out(), "Hello"); 107 EXPECT_EQ(streams.err(), ""); 108} 109 110TEST_F(SysModuleExtensionApiTest, WriteStdoutWithoutSysStdoutWritesToStdout) { 111 PyRun_SimpleString(R"( 112import sys 113del sys.stdout 114)"); 115 CaptureStdStreams streams; 116 PySys_WriteStdout("Konnichiwa\n"); 117 EXPECT_EQ(streams.out(), "Konnichiwa\n"); 118 EXPECT_EQ(streams.err(), ""); 119} 120 121TEST_F(SysModuleExtensionApiTest, WriteStdoutTruncatesLongOutput) { 122 const size_t max_out_len = 1000; 123 std::string long_str; 124 for (int i = 0; i < 100; i++) { 125 long_str += "0123456789"; 126 } 127 ASSERT_EQ(long_str.size(), max_out_len); 128 129 CaptureStdStreams streams; 130 PySys_WriteStdout("%s hello", long_str.c_str()); 131 EXPECT_EQ(streams.out(), long_str + "... truncated"); 132 EXPECT_EQ(streams.err(), ""); 133} 134 135TEST_F(SysModuleExtensionApiTest, WriteStderr) { 136 CaptureStdStreams streams; 137 PySys_WriteStderr("2 + 2 = %d", 4); 138 EXPECT_EQ(streams.out(), ""); 139 EXPECT_EQ(streams.err(), "2 + 2 = 4"); 140} 141 142TEST_F(SysModuleExtensionApiTest, 143 SetArgvWithEmptyArgvPopulatesSysArgvAndSysPathWithEmptyString) { 144 wchar_t arg0[] = L"python"; 145 wchar_t* wargv[] = {arg0}; 146 PySys_SetArgv(0, wargv + 1); 147 148 PyObject* argv = PySys_GetObject("argv"); 149 EXPECT_EQ(PyList_Size(argv), 1); 150 EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(argv, 0), "")); 151 PyObject* sys_path = PySys_GetObject("path"); 152 PyObject* sys_path0 = PyList_GetItem(sys_path, 0); 153 EXPECT_TRUE(isUnicodeEqualsCStr(sys_path0, "")); 154} 155 156TEST_F(SysModuleExtensionApiTest, 157 SetArgvWithScriptAndArgsPopulatesSysArgvWithScriptAndArgs) { 158 wchar_t arg0[] = L"script.py"; 159 wchar_t arg1[] = L"3"; 160 wchar_t arg2[] = L"2"; 161 wchar_t* wargv[] = {arg0, arg1, arg2}; 162 PySys_SetArgv(3, wargv); 163 PyObject* argv = PySys_GetObject("argv"); 164 EXPECT_EQ(PyList_Size(argv), 3); 165 EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(argv, 0), "script.py")); 166 EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(argv, 1), "3")); 167 EXPECT_TRUE(isUnicodeEqualsCStr(PyList_GetItem(argv, 2), "2")); 168} 169 170TEST_F(SysModuleExtensionApiTest, 171 SetArgvWithModuleArgInsertsWorkingDirectoryIntoSysPath) { 172 wchar_t arg0[] = L"-m"; 173 wchar_t* wargv[] = {arg0}; 174 PySys_SetArgv(1, wargv); 175 176 char cwd[PATH_MAX] = {0}; 177 ASSERT_NE(::getcwd(cwd, PATH_MAX), nullptr); 178 179 PyObject* sys_path = PySys_GetObject("path"); 180 PyObject* sys_path0 = PyList_GetItem(sys_path, 0); 181 EXPECT_TRUE(isUnicodeEqualsCStr(sys_path0, cwd)); 182} 183 184TEST_F(SysModuleExtensionApiTest, 185 SetArgvWithCommandArgInsertsEmptyStringIntoSysPath) { 186 wchar_t arg0[] = L"-c"; 187 wchar_t* wargv[] = {arg0}; 188 PySys_SetArgv(1, wargv); 189 190 PyObject* sys_path = PySys_GetObject("path"); 191 PyObject* sys_path0 = PyList_GetItem(sys_path, 0); 192 EXPECT_TRUE(isUnicodeEqualsCStr(sys_path0, "")); 193} 194 195TEST_F(SysModuleExtensionApiTest, 196 SetArgvWithAbsolutePathInsertsPathIntoSysPath) { 197 TempDirectory tmpdir; 198 std::string tmpfile = tmpdir.path() + "scriptfile.py"; 199 std::string touch = "touch " + tmpfile; 200 int result = std::system(touch.c_str()); 201 ASSERT_EQ(result, 0); 202 203 wchar_t arg0[] = L"python"; 204 wchar_t* arg1 = Py_DecodeLocale(tmpfile.c_str(), nullptr); 205 wchar_t* wargv[] = {arg0, arg1}; 206 PySys_SetArgv(1, wargv + 1); 207 208 PyObject* sys_path = PySys_GetObject("path"); 209 PyObject* sys_path0 = PyList_GetItem(sys_path, 0); 210 char* abs_realpath = ::realpath(tmpdir.path().c_str(), nullptr); 211 EXPECT_TRUE(isUnicodeEqualsCStr(sys_path0, abs_realpath)); 212 213 PyMem_RawFree(arg1); 214 std::free(abs_realpath); 215} 216 217TEST_F(SysModuleExtensionApiTest, SetArgvWithLocalPathAddsPathStringToSysPath) { 218 TempDirectory tmpdir; 219 char* cwd = ::getcwd(nullptr, 0); 220 int result = ::chdir(tmpdir.path().c_str()); 221 ASSERT_EQ(result, 0); 222 223 std::string tmpfile = "scriptfile.py"; 224 std::string touch = "touch " + tmpfile; 225 result = std::system(touch.c_str()); 226 ASSERT_EQ(result, 0); 227 228 wchar_t arg0[] = L"python"; 229 wchar_t* arg1 = Py_DecodeLocale(tmpfile.c_str(), nullptr); 230 wchar_t* wargv[] = {arg0, arg1}; 231 PySys_SetArgv(1, wargv + 1); 232 233 PyObject* sys_path = PySys_GetObject("path"); 234 PyObject* sys_path0 = PyList_GetItem(sys_path, 0); 235 char* abs_path = ::realpath(tmpdir.path().c_str(), nullptr); 236 EXPECT_TRUE(isUnicodeEqualsCStr(sys_path0, abs_path)); 237 238 result = ::chdir(cwd); 239 ASSERT_EQ(result, 0); 240 PyMem_RawFree(arg1); 241 std::free(abs_path); 242 std::free(cwd); 243} 244 245TEST_F(SysModuleExtensionApiTest, SetArgvWithRelativePathAddsPathToSysPath) { 246 TempDirectory tmpdir; 247 char* cwd = ::getcwd(nullptr, 0); 248 int result = ::chdir(tmpdir.path().c_str()); 249 ASSERT_EQ(result, 0); 250 251 std::string relative_path = "./"; 252 std::string tmpfile = relative_path + "scriptfile.py"; 253 std::string touch = "touch " + tmpfile; 254 result = std::system(touch.c_str()); 255 ASSERT_EQ(result, 0); 256 257 wchar_t arg0[] = L"python"; 258 wchar_t* arg1 = Py_DecodeLocale(tmpfile.c_str(), nullptr); 259 wchar_t* wargv[] = {arg0, arg1}; 260 PySys_SetArgv(1, wargv + 1); 261 262 PyObject* sys_path = PySys_GetObject("path"); 263 PyObject* sys_path0 = PyList_GetItem(sys_path, 0); 264 char* abs_path = ::realpath(relative_path.c_str(), nullptr); 265 EXPECT_TRUE(isUnicodeEqualsCStr(sys_path0, abs_path)); 266 267 result = ::chdir(cwd); 268 ASSERT_EQ(result, 0); 269 PyMem_RawFree(arg1); 270 std::free(cwd); 271 std::free(abs_path); 272} 273 274TEST_F(SysModuleExtensionApiTest, SetArgvWithRootPathInsertsRootIntoSysPath) { 275 wchar_t arg0[] = L"python"; 276 wchar_t arg1[] = L"/root_script.py"; 277 wchar_t* wargv[] = {arg0, arg1}; 278 PySys_SetArgv(1, wargv + 1); 279 280 PyObject* sys_path = PySys_GetObject("path"); 281 PyObject* sys_path0 = PyList_GetItem(sys_path, 0); 282 EXPECT_TRUE(isUnicodeEqualsCStr(sys_path0, "/")); 283} 284 285TEST_F(SysModuleExtensionApiTest, 286 SetArgvWithLocalSymlinkInsertsPathIntoSysPath) { 287 TempDirectory tmpdir; 288 std::string tmpfile = tmpdir.path() + "scriptfile.py"; 289 std::string linkfile = tmpdir.path() + "scriptlink.py"; 290 std::string touch = "touch " + tmpfile; 291 int result = std::system(touch.c_str()); 292 ASSERT_EQ(result, 0); 293 std::string ln = "ln -s scriptfile.py " + linkfile; 294 result = std::system(ln.c_str()); 295 ASSERT_EQ(result, 0); 296 297 wchar_t arg0[] = L"python"; 298 wchar_t* arg1 = Py_DecodeLocale(linkfile.c_str(), nullptr); 299 wchar_t* wargv[] = {arg0, arg1}; 300 PySys_SetArgv(1, wargv + 1); 301 302 PyObject* sys_path = PySys_GetObject("path"); 303 PyObject* sys_path0 = PyList_GetItem(sys_path, 0); 304 char* abs_realpath = ::realpath(tmpdir.path().c_str(), nullptr); 305 EXPECT_TRUE(isUnicodeEqualsCStr(sys_path0, abs_realpath)); 306 307 PyMem_RawFree(arg1); 308 std::free(abs_realpath); 309} 310 311TEST_F(SysModuleExtensionApiTest, 312 SetArgvWithAbsoluteSymlinkInsertsPathIntoSysPath) { 313 TempDirectory tmpdir1; 314 TempDirectory tmpdir2; 315 std::string tmpfile = tmpdir1.path() + "scriptfile.py"; 316 std::string linkfile = tmpdir2.path() + "scriptlink.py"; 317 std::string touch = "touch " + tmpfile; 318 int result = std::system(touch.c_str()); 319 ASSERT_EQ(result, 0); 320 std::string ln = "ln -s " + tmpfile + " " + linkfile; 321 result = std::system(ln.c_str()); 322 ASSERT_EQ(result, 0); 323 324 wchar_t arg0[] = L"python"; 325 wchar_t* arg1 = Py_DecodeLocale(linkfile.c_str(), nullptr); 326 wchar_t* wargv[] = {arg0, arg1}; 327 PySys_SetArgv(1, wargv + 1); 328 329 PyObject* sys_path = PySys_GetObject("path"); 330 PyObject* sys_path0 = PyList_GetItem(sys_path, 0); 331 char* abs_realpath = ::realpath(tmpdir1.path().c_str(), nullptr); 332 EXPECT_TRUE(isUnicodeEqualsCStr(sys_path0, abs_realpath)); 333 334 PyMem_RawFree(arg1); 335 std::free(abs_realpath); 336} 337 338TEST_F(SysModuleExtensionApiTest, 339 SetArgvWithRelativeSymlinkInsertsPathIntoSysPath) { 340 TempDirectory tmpdir; 341 std::string tmpfile = tmpdir.path() + "scriptfile.py"; 342 std::string linkfile = tmpdir.path() + "scriptlink.py"; 343 std::string touch = "touch " + tmpfile; 344 int result = std::system(touch.c_str()); 345 ASSERT_EQ(result, 0); 346 std::string ln = "ln -s ./scriptfile.py " + linkfile; 347 result = std::system(ln.c_str()); 348 ASSERT_EQ(result, 0); 349 350 wchar_t arg0[] = L"python"; 351 wchar_t* arg1 = Py_DecodeLocale(linkfile.c_str(), nullptr); 352 wchar_t* wargv[] = {arg0, arg1}; 353 PySys_SetArgv(1, wargv + 1); 354 355 PyObject* sys_path = PySys_GetObject("path"); 356 PyObject* sys_path0 = PyList_GetItem(sys_path, 0); 357 char* abs_realpath = ::realpath(tmpdir.path().c_str(), nullptr); 358 EXPECT_TRUE(isUnicodeEqualsCStr(sys_path0, abs_realpath)); 359 360 PyMem_RawFree(arg1); 361 std::free(abs_realpath); 362} 363 364} // namespace testing 365} // namespace py