this repo has no description
at trunk 619 lines 22 kB view raw
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com) 2#include <cstdlib> 3#include <cstring> 4 5#include "Python.h" 6#include "gmock/gmock-matchers.h" 7#include "gtest/gtest.h" 8 9#include "capi-fixture.h" 10#include "capi-testing.h" 11 12namespace py { 13namespace testing { 14 15using PythonrunExtensionApiTest = ExtensionApi; 16 17TEST_F(PythonrunExtensionApiTest, CompileStringWithEmptyStrReturnsCode) { 18 PyObjectPtr result(Py_CompileString("", "<string>", Py_file_input)); 19 EXPECT_NE(result, nullptr); 20 EXPECT_EQ(PyErr_Occurred(), nullptr); 21 EXPECT_TRUE(PyCode_Check(result)); 22} 23 24TEST_F(PythonrunExtensionApiTest, CompileStringCompilesCode) { 25 PyObjectPtr result(Py_CompileString("a = 3", "<string>", Py_file_input)); 26 EXPECT_NE(result, nullptr); 27 EXPECT_EQ(PyErr_Occurred(), nullptr); 28 EXPECT_TRUE(PyCode_Check(result)); 29 PyObjectPtr locals(PyDict_New()); 30 PyObjectPtr globals(PyDict_New()); 31 EXPECT_NE(PyEval_EvalCode(result, globals, locals), nullptr); 32 33 EXPECT_EQ(PyDict_Size(locals), 1); 34 PyObjectPtr local(PyDict_GetItemString(locals, "a")); 35 EXPECT_TRUE(isLongEqualsLong(local, 3)); 36} 37 38TEST_F(PythonrunExtensionApiTest, 39 CompileStringWithInvalidCodeRaisesSyntaxError) { 40 PyObjectPtr result(Py_CompileString(";", "<string>", Py_file_input)); 41 EXPECT_EQ(result, nullptr); 42 ASSERT_NE(PyErr_Occurred(), nullptr); 43 EXPECT_EQ(PyErr_ExceptionMatches(PyExc_SyntaxError), 1); 44} 45 46TEST_F(PythonrunExtensionApiTest, CompileWithSourceIsUTF8RaisesValueError) { 47 int flags = PyCF_SOURCE_IS_UTF8; 48 EXPECT_EQ(0, moduleSet("__main__", "flags", PyLong_FromLong(flags))); 49 EXPECT_EQ(-1, PyRun_SimpleString(R"( 50try: 51 compile("1", "filename", "exec", flags=flags) 52 failed = False 53except ValueError: 54 failed = True 55 raise 56)")); 57 PyObjectPtr failed(mainModuleGet("failed")); 58 EXPECT_EQ(Py_True, failed); 59} 60 61TEST_F(PythonrunExtensionApiTest, PyRunAnyFileReturnsZero) { 62 CaptureStdStreams streams; 63 const char* buffer = R"(print(f"good morning by {__file__}"))"; 64 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 65 std::strlen(buffer), "r"); 66 int returncode = PyRun_AnyFile(fp, "test string"); 67 fclose(fp); 68 EXPECT_EQ(returncode, 0); 69 EXPECT_EQ(streams.out(), "good morning by test string\n"); 70} 71 72TEST_F(PythonrunExtensionApiTest, PyRunAnyFileExReturnsZero) { 73 CaptureStdStreams streams; 74 const char* buffer = R"(print(f"I am {__file__}"))"; 75 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 76 std::strlen(buffer), "r"); 77 int returncode = PyRun_AnyFileEx(fp, "test string", /*closeit=*/1); 78 EXPECT_EQ(returncode, 0); 79 EXPECT_EQ(streams.out(), "I am test string\n"); 80} 81 82TEST_F(PythonrunExtensionApiTest, PyRunAnyFileExFlagsReturnsZero) { 83 CaptureStdStreams streams; 84 const char* buffer = R"(x = 2 <> 3; print(f"{x} by {__file__}"))"; 85 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 86 std::strlen(buffer), "r"); 87 PyCompilerFlags flags = _PyCompilerFlags_INIT; 88 flags.cf_flags = CO_FUTURE_BARRY_AS_BDFL; 89 int returncode = PyRun_AnyFileExFlags(fp, nullptr, /*closeit=*/1, &flags); 90 EXPECT_EQ(returncode, 0); 91 EXPECT_EQ(streams.out(), "True by ???\n"); 92} 93 94TEST_F(PythonrunExtensionApiTest, PyRunAnyFileFlagsReturnsZero) { 95 CaptureStdStreams streams; 96 const char* buffer = R"(x = 4 <> 4; print(f"{x} by {__file__}"))"; 97 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 98 std::strlen(buffer), "r"); 99 PyCompilerFlags flags = _PyCompilerFlags_INIT; 100 flags.cf_flags = CO_FUTURE_BARRY_AS_BDFL; 101 int returncode = PyRun_AnyFileFlags(fp, "a test", &flags); 102 fclose(fp); 103 EXPECT_EQ(returncode, 0); 104 EXPECT_EQ(streams.out(), "False by a test\n"); 105} 106 107TEST_F(PythonrunExtensionApiTest, PyRunFileReturnsStr) { 108 PyObjectPtr module(PyModule_New("testmodule")); 109 PyModule_AddStringConstant(module, "shout", "ya!"); 110 PyObject* module_dict = PyModule_GetDict(module); 111 const char* buffer = R"("hey " + shout)"; 112 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 113 std::strlen(buffer), "r"); 114 PyObjectPtr result( 115 PyRun_File(fp, "a test", Py_eval_input, module_dict, module_dict)); 116 fclose(fp); 117 EXPECT_TRUE(isUnicodeEqualsCStr(result, "hey ya!")); 118} 119 120TEST_F(PythonrunExtensionApiTest, PyRunFileExReturnsStr) { 121 PyObjectPtr module(PyModule_New("testmodule")); 122 PyModule_AddStringConstant(module, "shout", "ya!"); 123 PyObject* module_dict = PyModule_GetDict(module); 124 const char* buffer = R"("hey " + shout)"; 125 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 126 std::strlen(buffer), "r"); 127 PyObjectPtr result(PyRun_FileEx(fp, "a test", Py_eval_input, module_dict, 128 module_dict, /*closeit=*/1)); 129 EXPECT_TRUE(isUnicodeEqualsCStr(result, "hey ya!")); 130} 131 132TEST_F(PythonrunExtensionApiTest, PyRunFileExFlagsReturnsTrue) { 133 PyObjectPtr module(PyModule_New("testmodule")); 134 PyModule_AddIntConstant(module, "number", 42); 135 PyObjectPtr module_dict(PyModule_GetDict(module)); 136 Py_INCREF(module_dict); 137 char buffer[] = R"(7 != number)"; 138 FILE* fp = 139 ::fmemopen(reinterpret_cast<void*>(buffer), std::strlen(buffer), "r"); 140 PyCompilerFlags flags = _PyCompilerFlags_INIT; 141 PyObjectPtr result(PyRun_FileExFlags(fp, "a test", Py_eval_input, 142 module_dict.get(), module_dict.get(), 143 /*closeit=*/1, &flags)); 144 EXPECT_EQ(result, Py_True); 145} 146 147TEST_F(PythonrunExtensionApiTest, PyRunFileExFlagsWithUserLocalsReturnsTrue) { 148 PyObjectPtr module(PyModule_New("testmodule")); 149 PyModule_AddIntConstant(module, "number", 42); 150 PyObjectPtr module_dict(PyModule_GetDict(module)); 151 Py_INCREF(module_dict); 152 char buffer[] = R"(7 != number)"; 153 FILE* fp = 154 ::fmemopen(reinterpret_cast<void*>(buffer), std::strlen(buffer), "r"); 155 PyCompilerFlags flags = _PyCompilerFlags_INIT; 156 PyObjectPtr locals(PyDict_New()); 157 PyObjectPtr result(PyRun_FileExFlags(fp, "a test", Py_eval_input, 158 module_dict.get(), locals.get(), 159 /*closeit=*/1, &flags)); 160 EXPECT_EQ(result, Py_True); 161} 162 163TEST_F(PythonrunExtensionApiTest, PyRunFileFlagsReturnsFalse) { 164 PyObjectPtr module(PyModule_New("testmodule")); 165 PyModule_AddIntConstant(module, "number", 9); 166 PyObject* module_dict = PyModule_GetDict(module); 167 const char* buffer = R"(number <> 9)"; 168 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 169 std::strlen(buffer), "r"); 170 PyCompilerFlags flags = _PyCompilerFlags_INIT; 171 flags.cf_flags = CO_FUTURE_BARRY_AS_BDFL; 172 PyObjectPtr result(PyRun_FileFlags(fp, "a test", Py_eval_input, module_dict, 173 module_dict, &flags)); 174 fclose(fp); 175 EXPECT_EQ(result, Py_False); 176} 177 178TEST_F(PythonrunExtensionApiTest, PyRunSimpleStringReturnsInt) { 179 EXPECT_EQ(PyRun_SimpleString("a = 42"), 0); 180 EXPECT_EQ(PyErr_Occurred(), nullptr); 181 PyObjectPtr value(mainModuleGet("a")); 182 EXPECT_TRUE(isLongEqualsLong(value, 42)); 183} 184 185TEST_F(PythonrunExtensionApiTest, PyRunSimpleStringPrintsSyntaxError) { 186 CaptureStdStreams streams; 187 EXPECT_EQ(PyRun_SimpleString(",,,"), -1); 188 EXPECT_EQ(PyErr_Occurred(), nullptr); 189 ASSERT_NE(streams.err().find("SyntaxError: invalid syntax\n"), 190 std::string::npos); 191} 192 193TEST_F(PythonrunExtensionApiTest, PyRunSimpleStringPrintsUncaughtException) { 194 CaptureStdStreams streams; 195 ASSERT_EQ(PyRun_SimpleString("raise RuntimeError('boom')"), -1); 196 EXPECT_EQ(streams.out(), ""); 197 EXPECT_EQ(streams.err(), R"(Traceback (most recent call last): 198 File "<string>", line 1, in <module> 199RuntimeError: boom 200)"); 201} 202 203TEST_F(PythonrunExtensionApiTest, PyRunSimpleStringFlagsReturnsTrue) { 204 PyCompilerFlags flags = _PyCompilerFlags_INIT; 205 flags.cf_flags = CO_FUTURE_BARRY_AS_BDFL; 206 EXPECT_EQ(PyRun_SimpleStringFlags("foo = 13 <> 42", &flags), 0); 207 EXPECT_EQ(PyErr_Occurred(), nullptr); 208 PyObjectPtr value(mainModuleGet("foo")); 209 EXPECT_EQ(value, Py_True); 210} 211 212TEST_F(PythonrunExtensionApiTest, PyRunStringReturnsString) { 213 PyObjectPtr module(PyModule_New("testmodule")); 214 PyModule_AddStringConstant(module, "name", "tester"); 215 PyObject* module_dict = PyModule_GetDict(module); 216 PyObjectPtr result(PyRun_String(R"(f"hello {name}")", Py_eval_input, 217 module_dict, module_dict)); 218 EXPECT_TRUE(isUnicodeEqualsCStr(result, "hello tester")); 219} 220 221TEST_F(PythonrunExtensionApiTest, PyRunStringFlagsReturnsResult) { 222 PyObject* module = PyImport_AddModule("__main__"); 223 ASSERT_NE(module, nullptr); 224 PyObject* module_proxy = PyModule_GetDict(module); 225 PyCompilerFlags flags = _PyCompilerFlags_INIT; 226 flags.cf_flags = CO_FUTURE_BARRY_AS_BDFL; 227 EXPECT_TRUE( 228 isLongEqualsLong(PyRun_StringFlags("(7 <> 7) + 3", Py_eval_input, 229 module_proxy, module_proxy, &flags), 230 3)); 231} 232 233TEST_F(PythonrunExtensionApiTest, 234 PyRunStringFlagsWithSourceIsUtf8FlagReturnsResult) { 235 PyObject* module = PyImport_AddModule("__main__"); 236 ASSERT_NE(module, nullptr); 237 PyObject* module_proxy = PyModule_GetDict(module); 238 PyCompilerFlags flags = _PyCompilerFlags_INIT; 239 flags.cf_flags = PyCF_SOURCE_IS_UTF8; 240 EXPECT_TRUE( 241 isLongEqualsLong(PyRun_StringFlags("1 + 2", Py_eval_input, module_proxy, 242 module_proxy, &flags), 243 3)); 244} 245TEST_F(PythonrunExtensionApiTest, PyErrDisplayPrintsException) { 246 PyErr_SetString(PyExc_RuntimeError, "oopsie"); 247 PyObject *exc, *value, *tb; 248 PyErr_Fetch(&exc, &value, &tb); 249 // PyErr_Display() expects a real exception in `value`. 250 PyErr_NormalizeException(&exc, &value, &tb); 251 252 CaptureStdStreams streams; 253 PyErr_Display(exc, value, tb); 254 ASSERT_EQ(streams.err(), "RuntimeError: oopsie\n"); 255 EXPECT_EQ(streams.out(), ""); 256 257 Py_DECREF(exc); 258 Py_DECREF(value); 259 Py_XDECREF(tb); 260} 261 262TEST_F(PythonrunExtensionApiTest, PyErrDisplayPrintsExceptionChain) { 263 // TODO(T77279778): Don't clear __traceback__ below. 264 ASSERT_EQ(PyRun_SimpleString(R"( 265try: 266 try: 267 raise RuntimeError("inner") 268 except Exception as e: 269 e.__traceback__ = None 270 e.__context__ = ValueError("non-raised inner") 271 raise RuntimeError("outer") from e 272except Exception as e: 273 e.__traceback__ = None 274 exc = e 275)"), 276 0); 277 PyObjectPtr exc(mainModuleGet("exc")); 278 279 CaptureStdStreams streams; 280 PyErr_Display(nullptr, exc, nullptr); 281 ASSERT_EQ(streams.err(), 282 "ValueError: non-raised inner\n\nDuring handling of the above " 283 "exception, another exception occurred:\n\nRuntimeError: " 284 "inner\n\nThe above exception was the direct cause " 285 "of the following exception:\n\nRuntimeError: outer\n"); 286 EXPECT_EQ(streams.out(), ""); 287} 288 289TEST_F(PythonrunExtensionApiTest, PyErrDisplayAvoidsCauseCycle) { 290 ASSERT_EQ(PyRun_SimpleString(R"( 291exc = RuntimeError("outer") 292exc.__cause__ = RuntimeError("inner") 293exc.__cause__.__cause__ = exc 294)"), 295 0); 296 PyObjectPtr exc(mainModuleGet("exc")); 297 298 CaptureStdStreams streams; 299 PyErr_Display(nullptr, exc, nullptr); 300 ASSERT_EQ(streams.err(), 301 "RuntimeError: inner\n\nThe above exception was the direct cause " 302 "of the following exception:\n\nRuntimeError: outer\n"); 303 EXPECT_EQ(streams.out(), ""); 304} 305 306TEST_F(PythonrunExtensionApiTest, PyErrDisplayAvoidsContextCycle) { 307 ASSERT_EQ(PyRun_SimpleString(R"( 308exc = RuntimeError("outer") 309exc.__context__ = RuntimeError("inner") 310exc.__context__.__context__ = exc 311)"), 312 0); 313 PyObjectPtr exc(mainModuleGet("exc")); 314 315 CaptureStdStreams streams; 316 PyErr_Display(nullptr, exc, nullptr); 317 ASSERT_EQ(streams.err(), 318 "RuntimeError: inner\n\nDuring handling of the above exception, " 319 "another exception occurred:\n\nRuntimeError: outer\n"); 320 EXPECT_EQ(streams.out(), ""); 321} 322 323TEST_F(PythonrunExtensionApiTest, 324 PyErrDisplayWithSuppressContextDoesntPrintContext) { 325 ASSERT_EQ(PyRun_SimpleString(R"( 326exc = RuntimeError("error") 327exc.__context__ = RuntimeError("inner error") 328exc.__suppress_context__ = True 329)"), 330 0); 331 PyObjectPtr exc(mainModuleGet("exc")); 332 333 CaptureStdStreams streams; 334 PyErr_Display(nullptr, exc, nullptr); 335 ASSERT_EQ(streams.err(), "RuntimeError: error\n"); 336 EXPECT_EQ(streams.out(), ""); 337} 338 339TEST_F(PythonrunExtensionApiTest, PyErrDisplayWithRaisingStr) { 340 ASSERT_EQ(PyRun_SimpleString(R"( 341class MyExc(Exception): 342 def __str__(self): 343 raise RuntimeError() 344exc = MyExc() 345)"), 346 0); 347 PyObjectPtr exc(mainModuleGet("exc")); 348 349 CaptureStdStreams streams; 350 PyErr_Display(nullptr, exc, nullptr); 351 ASSERT_EQ(streams.err(), "__main__.MyExc: <exception str() failed>\n"); 352 EXPECT_EQ(streams.out(), ""); 353} 354 355TEST_F(PythonrunExtensionApiTest, PyErrDisplayWithNoModule) { 356 ASSERT_EQ(PyRun_SimpleString(R"( 357class MyExc(Exception): 358 __module__ = None 359exc = MyExc("hi") 360)"), 361 0); 362 PyObjectPtr exc(mainModuleGet("exc")); 363 364 CaptureStdStreams streams; 365 PyErr_Display(nullptr, exc, nullptr); 366 ASSERT_EQ(streams.err(), "<unknown>MyExc: hi\n"); 367 EXPECT_EQ(streams.out(), ""); 368} 369 370TEST_F(PythonrunExtensionApiTest, PyErrDisplayWithNonException) { 371 PyObjectPtr value(PyFloat_FromDouble(123.0)); 372 373 CaptureStdStreams streams; 374 PyErr_Display(nullptr, value, nullptr); 375 ASSERT_EQ(streams.err(), 376 "TypeError: print_exception(): Exception expected for value, float " 377 "found\n"); 378 EXPECT_EQ(streams.out(), ""); 379} 380 381TEST_F(PythonrunExtensionApiTest, PyErrDisplayWithSyntaxError) { 382 ASSERT_EQ(PyRun_SimpleString(R"( 383se = SyntaxError() 384se.print_file_and_line = None 385se.msg = "bad syntax" 386se.filename = "some_file.py" 387se.lineno = 0 388se.offset = 31 389se.text = "this is fake source code\nthat is multiple lines long" 390)"), 391 0); 392 PyObjectPtr se(mainModuleGet("se")); 393 394 CaptureStdStreams streams; 395 PyErr_Display(nullptr, se, nullptr); 396 ASSERT_EQ(streams.err(), 397 R"( File "some_file.py", line 0 398 that is multiple lines long 399 ^ 400SyntaxError: bad syntax 401)"); 402 EXPECT_EQ(streams.out(), ""); 403} 404 405TEST_F(PythonrunExtensionApiTest, PyErrPrintExPrintsExceptionDoesntSetVars) { 406 PyErr_SetString(PyExc_RuntimeError, "abcd"); 407 408 CaptureStdStreams streams; 409 PyErr_PrintEx(0); 410 ASSERT_EQ(streams.err(), "RuntimeError: abcd\n"); 411 EXPECT_EQ(streams.out(), ""); 412 413 ASSERT_EQ(moduleGet("sys", "last_type"), nullptr); 414 PyErr_Clear(); 415 ASSERT_EQ(moduleGet("sys", "last_value"), nullptr); 416 PyErr_Clear(); 417 ASSERT_EQ(moduleGet("sys", "last_traceback"), nullptr); 418 PyErr_Clear(); 419} 420 421static void checkSysVars() { 422 PyObjectPtr type(moduleGet("sys", "last_type")); 423 ASSERT_EQ(PyErr_Occurred(), nullptr); 424 ASSERT_NE(type, nullptr); 425 EXPECT_EQ(type, PyExc_RuntimeError); 426 427 PyObjectPtr value(moduleGet("sys", "last_value")); 428 ASSERT_EQ(PyErr_Occurred(), nullptr); 429 ASSERT_NE(value, nullptr); 430 EXPECT_EQ(PyErr_GivenExceptionMatches(value, PyExc_RuntimeError), 1); 431 432 PyObjectPtr tb(moduleGet("sys", "last_traceback")); 433 ASSERT_EQ(PyErr_Occurred(), nullptr); 434 ASSERT_NE(tb, nullptr); 435 EXPECT_EQ(tb, Py_None); 436} 437 438TEST_F(PythonrunExtensionApiTest, PyErrPrintExWithArgSetsSysVars) { 439 PyErr_SetString(PyExc_RuntimeError, "critical error"); 440 441 CaptureStdStreams streams; 442 PyErr_PrintEx(1); 443 ASSERT_EQ(streams.err(), "RuntimeError: critical error\n"); 444 EXPECT_EQ(streams.out(), ""); 445 446 EXPECT_NO_FATAL_FAILURE(checkSysVars()); 447} 448 449TEST_F(PythonrunExtensionApiTest, PyErrPrintSetsSysVars) { 450 PyErr_SetString(PyExc_RuntimeError, "I don't hate you"); 451 452 CaptureStdStreams streams; 453 PyErr_Print(); 454 ASSERT_EQ(streams.err(), "RuntimeError: I don't hate you\n"); 455 EXPECT_EQ(streams.out(), ""); 456 457 EXPECT_NO_FATAL_FAILURE(checkSysVars()); 458} 459 460TEST_F(PythonrunExtensionApiTest, PyErrPrintExCallsCustomExcepthook) { 461 ASSERT_EQ(PyRun_SimpleString(R"( 462import sys 463def my_hook(type, value, tb): 464 print("What exception?", file=sys.stderr) 465 print("Everything is fine. Nothing is ruined.") 466sys.excepthook = my_hook 467)"), 468 0); 469 PyErr_SetString(PyExc_RuntimeError, "boop"); 470 471 CaptureStdStreams streams; 472 PyErr_PrintEx(0); 473 ASSERT_EQ(streams.err(), "What exception?\n"); 474 EXPECT_EQ(streams.out(), "Everything is fine. Nothing is ruined.\n"); 475} 476 477TEST_F(PythonrunExtensionApiTest, PyErrPrintExWithRaisingExcepthook) { 478 ASSERT_EQ(PyRun_SimpleString(R"( 479import sys 480def my_hook(type, value, tb): 481 raise RuntimeError("I'd rather not") 482sys.excepthook = my_hook 483)"), 484 0); 485 PyErr_SetString(PyExc_TypeError, "bad type"); 486 487 CaptureStdStreams streams; 488 PyErr_PrintEx(0); 489 ASSERT_EQ(streams.err(), R"(Error in sys.excepthook: 490Traceback (most recent call last): 491 File "<string>", line 4, in my_hook 492RuntimeError: I'd rather not 493 494Original exception was: 495TypeError: bad type 496)"); 497 EXPECT_EQ(streams.out(), ""); 498} 499 500TEST_F(PythonrunExtensionApiTest, PyErrPrintExWithNoExceptHookPrintsException) { 501 ASSERT_EQ(PyRun_SimpleString("import sys; del sys.excepthook"), 0); 502 PyErr_SetString(PyExc_RuntimeError, "something broke"); 503 504 CaptureStdStreams streams; 505 PyErr_PrintEx(0); 506 ASSERT_EQ(streams.err(), 507 "sys.excepthook is missing\nRuntimeError: something broke\n"); 508 EXPECT_EQ(streams.out(), ""); 509} 510 511TEST_F(PythonrunExtensionApiTest, PyErrPrintWithSystemExitExits) { 512 PyObject* zero = PyLong_FromLong(0); 513 PyErr_SetObject(PyExc_SystemExit, zero); 514 Py_DECREF(zero); 515 EXPECT_EXIT(PyErr_Print(), ::testing::ExitedWithCode(0), "^$"); 516 517 PyErr_Clear(); 518 PyObject* three = PyLong_FromLong(3); 519 PyErr_SetObject(PyExc_SystemExit, three); 520 Py_DECREF(three); 521 EXPECT_EXIT(PyErr_Print(), ::testing::ExitedWithCode(3), "^$"); 522} 523 524TEST_F(PythonrunExtensionApiTest, PyErrPrintWithSystemExitFromExcepthookExits) { 525 ASSERT_EQ(PyRun_SimpleString(R"( 526import sys 527def my_hook(type, value, tb): 528 raise SystemExit(123) 529sys.excepthook = my_hook 530)"), 531 0); 532 PyErr_SetObject(PyExc_RuntimeError, Py_None); 533 EXPECT_EXIT(PyErr_Print(), ::testing::ExitedWithCode(123), "^$"); 534} 535 536TEST_F(PythonrunExtensionApiTest, PyRunSimpleFileReturnsZero) { 537 CaptureStdStreams streams; 538 const char* buffer = R"(print(f"Greetings from {__file__}"))"; 539 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 540 std::strlen(buffer), "r"); 541 int returncode = PyRun_SimpleFile(fp, "test string"); 542 fclose(fp); 543 EXPECT_EQ(returncode, 0); 544 EXPECT_EQ(streams.out(), "Greetings from test string\n"); 545} 546 547TEST_F(PythonrunExtensionApiTest, PyRunSimpleFileExReturnsZero) { 548 CaptureStdStreams streams; 549 const char* buffer = R"(print(f"This is {__file__}"))"; 550 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 551 std::strlen(buffer), "r"); 552 int returncode = PyRun_SimpleFileEx(fp, "zombocom", /*closeit=*/1); 553 EXPECT_EQ(returncode, 0); 554 EXPECT_EQ(streams.out(), "This is zombocom\n"); 555} 556 557TEST_F(PythonrunExtensionApiTest, PyRunSimpleFileExFlagsWithPyFileReturnsZero) { 558 CaptureStdStreams streams; 559 const char* buffer = R"(print("pyhello"))"; 560 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 561 std::strlen(buffer), "r"); 562 PyCompilerFlags flags = _PyCompilerFlags_INIT; 563 int returncode = PyRun_SimpleFileExFlags(fp, "test.py", 1, &flags); 564 EXPECT_EQ(returncode, 0); 565 EXPECT_EQ(streams.out(), "pyhello\n"); 566} 567 568TEST_F(PythonrunExtensionApiTest, 569 PyRunSimpleFileExFlagsSetsAndUnsetsDunderFile) { 570 CaptureStdStreams streams; 571 const char* buffer = R"(print(__file__))"; 572 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 573 std::strlen(buffer), "r"); 574 PyCompilerFlags flags = _PyCompilerFlags_INIT; 575 int returncode = PyRun_SimpleFileExFlags(fp, "test.py", 1, &flags); 576 EXPECT_EQ(returncode, 0); 577 EXPECT_EQ(streams.out(), "test.py\n"); 578 PyObject* mods = PyImport_GetModuleDict(); 579 PyObject* dunder_main = PyUnicode_FromString("__main__"); 580 PyObject* main_mod = PyDict_GetItem(mods, dunder_main); 581 PyObject* dunder_file = PyUnicode_FromString("__file__"); 582 EXPECT_FALSE(PyObject_HasAttr(main_mod, dunder_file)); 583} 584 585TEST_F(PythonrunExtensionApiTest, PyRunSimpleFileExFlagsPrintsSyntaxError) { 586 CaptureStdStreams streams; 587 const char* buffer = ",,,"; 588 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 589 std::strlen(buffer), "r"); 590 PyCompilerFlags flags = _PyCompilerFlags_INIT; 591 int returncode = PyRun_SimpleFileExFlags(fp, "test.py", 1, &flags); 592 EXPECT_EQ(returncode, -1); 593 EXPECT_EQ(PyErr_Occurred(), nullptr); 594 EXPECT_NE(streams.err().find(R"( File "test.py", line 1 595 ,,, 596 ^ 597SyntaxError: invalid syntax 598)"), 599 std::string::npos); 600} 601 602TEST_F(PythonrunExtensionApiTest, 603 PyRunSimpleFileExFlagsPrintsUncaughtException) { 604 CaptureStdStreams streams; 605 const char* buffer = "raise RuntimeError('boom')"; 606 FILE* fp = ::fmemopen(reinterpret_cast<void*>(const_cast<char*>(buffer)), 607 std::strlen(buffer), "r"); 608 PyCompilerFlags flags = _PyCompilerFlags_INIT; 609 int returncode = PyRun_SimpleFileExFlags(fp, "test.py", 1, &flags); 610 EXPECT_EQ(returncode, -1); 611 EXPECT_EQ(streams.out(), ""); 612 EXPECT_EQ(streams.err(), R"(Traceback (most recent call last): 613 File "test.py", line 1, in <module> 614RuntimeError: boom 615)"); 616} 617 618} // namespace testing 619} // namespace py