this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include <cerrno>
3
4#include "Python.h"
5#include "gmock/gmock-matchers.h"
6#include "gtest/gtest.h"
7
8#include "capi-fixture.h"
9#include "capi-testing.h"
10
11namespace py {
12namespace testing {
13using ErrorsExtensionApiTest = ExtensionApi;
14
15TEST_F(ErrorsExtensionApiTest, CompareErrorMessageOnThread) {
16 ASSERT_EQ(nullptr, PyErr_Occurred());
17
18 PyErr_SetString(PyExc_Exception, "An exception occured");
19 ASSERT_EQ(PyExc_Exception, PyErr_Occurred());
20}
21
22TEST_F(ErrorsExtensionApiTest, SetObjectSetsTypeAndValue) {
23 PyObject* type = nullptr;
24 PyObject* value = nullptr;
25 PyObject* traceback = nullptr;
26 PyErr_Fetch(&type, &value, &traceback);
27 EXPECT_EQ(type, nullptr);
28 EXPECT_EQ(value, nullptr);
29 EXPECT_EQ(traceback, nullptr);
30
31 PyErr_SetObject(PyExc_Exception, Py_True);
32 PyErr_Fetch(&type, &value, &traceback);
33 EXPECT_EQ(type, PyExc_Exception);
34 EXPECT_EQ(value, Py_True);
35 EXPECT_EQ(traceback, nullptr);
36
37 Py_DECREF(type);
38 Py_DECREF(value);
39}
40
41TEST_F(ErrorsExtensionApiTest, SetObjectWithNonExceptionTypeRaisesSystemError) {
42 PyObjectPtr bool_type(PyObject_Type(Py_True));
43 PyErr_SetObject(bool_type, Py_None);
44 EXPECT_EQ(PyErr_Occurred(), PyExc_SystemError);
45}
46
47TEST_F(ErrorsExtensionApiTest, SetObjectWithNonTypeRaisesSystemError) {
48 PyErr_SetObject(Py_True, Py_None);
49 EXPECT_EQ(PyErr_Occurred(), PyExc_SystemError);
50}
51
52TEST_F(ErrorsExtensionApiTest, SetObjectWithPendingExceptionDoesNotAbort) {
53 ASSERT_EQ(PyErr_Occurred(), nullptr);
54 PyErr_SetObject(PyExc_TypeError, Py_True);
55 PyErr_SetObject(PyExc_UserWarning, Py_False);
56
57 PyObject* type = nullptr;
58 PyObject* value = nullptr;
59 PyObject* traceback = nullptr;
60 PyErr_Fetch(&type, &value, &traceback);
61 EXPECT_EQ(type, PyExc_UserWarning);
62 EXPECT_EQ(value, Py_False);
63 EXPECT_EQ(traceback, nullptr);
64
65 Py_DECREF(type);
66 Py_DECREF(value);
67}
68
69TEST_F(ErrorsExtensionApiTest, ClearClearsExceptionState) {
70 // Set the exception state
71 Py_INCREF(PyExc_Exception);
72 Py_INCREF(Py_True);
73 PyErr_Restore(PyExc_Exception, Py_True, nullptr);
74
75 // Check that an exception is pending
76 EXPECT_EQ(PyErr_Occurred(), PyExc_Exception);
77
78 // Clear the exception
79 PyErr_Clear();
80
81 // Read the exception state again and check for null
82 PyObject* type = nullptr;
83 PyObject* value = nullptr;
84 PyObject* traceback = nullptr;
85 PyErr_Fetch(&type, &value, &traceback);
86 EXPECT_EQ(type, nullptr);
87 EXPECT_EQ(value, nullptr);
88 EXPECT_EQ(traceback, nullptr);
89}
90
91TEST_F(ErrorsExtensionApiTest, BadArgumentRaisesTypeError) {
92 ASSERT_EQ(PyErr_Occurred(), nullptr);
93 EXPECT_EQ(PyErr_BadArgument(), 0);
94
95 PyObject* type = nullptr;
96 PyObject* value = nullptr;
97 PyObject* traceback = nullptr;
98 PyErr_Fetch(&type, &value, &traceback);
99 EXPECT_EQ(type, PyExc_TypeError);
100
101 PyObjectPtr message(
102 PyUnicode_FromString("bad argument type for built-in operation"));
103 ASSERT_TRUE(PyUnicode_Check(message));
104 EXPECT_EQ(_PyUnicode_EQ(value, message), 1);
105
106 // TODO(T42241510): Traceback support isn't implemented yet. Once it's ready,
107 // inspect the traceback here.
108
109 Py_DECREF(type);
110 Py_DECREF(value);
111}
112
113TEST_F(ErrorsExtensionApiTest, NewExceptionWithBadNameRaisesSystemError) {
114 EXPECT_EQ(PyErr_NewException("NameWithoutADot", nullptr, nullptr), nullptr);
115 ASSERT_NE(PyErr_Occurred(), nullptr);
116 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
117}
118
119TEST_F(ErrorsExtensionApiTest, NewExceptionWithoutDictOrBaseReturnsType) {
120 PyObjectPtr type(PyErr_NewException("Module.Name", nullptr, nullptr));
121 ASSERT_EQ(PyErr_Occurred(), nullptr);
122 ASSERT_TRUE(PyType_CheckExact(type));
123 EXPECT_TRUE(
124 PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(type.get()),
125 reinterpret_cast<PyTypeObject*>(PyExc_Exception)));
126
127 PyObjectPtr name(PyObject_GetAttrString(type, "__name__"));
128 ASSERT_TRUE(PyUnicode_CheckExact(name));
129 EXPECT_TRUE(isUnicodeEqualsCStr(name, "Name"));
130 PyObjectPtr module_name(PyObject_GetAttrString(type, "__module__"));
131 ASSERT_TRUE(PyUnicode_CheckExact(module_name));
132 EXPECT_TRUE(isUnicodeEqualsCStr(module_name, "Module"));
133}
134
135TEST_F(ErrorsExtensionApiTest, NewExceptionWithSingleBaseCreatesBasesTuple) {
136 PyObjectPtr type(
137 PyErr_NewException("Module.Name", PyExc_ValueError, nullptr));
138 ASSERT_EQ(PyErr_Occurred(), nullptr);
139 ASSERT_TRUE(PyType_CheckExact(type));
140 EXPECT_TRUE(
141 PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(type.get()),
142 reinterpret_cast<PyTypeObject*>(PyExc_ValueError)));
143
144 PyObjectPtr bases(PyObject_GetAttrString(type, "__bases__"));
145 ASSERT_TRUE(PyTuple_CheckExact(bases));
146 EXPECT_EQ(PyTuple_GetItem(bases, 0), PyExc_ValueError);
147}
148
149TEST_F(ErrorsExtensionApiTest, NewExceptionWithBaseTupleStoresTuple) {
150 PyObjectPtr bases(PyTuple_New(2));
151 Py_INCREF(PyExc_SystemError);
152 ASSERT_EQ(PyTuple_SetItem(bases, 0, PyExc_SystemError), 0);
153 Py_INCREF(PyExc_ValueError);
154 ASSERT_EQ(PyTuple_SetItem(bases, 1, PyExc_ValueError), 0);
155 PyObjectPtr type(PyErr_NewException("Module.Name", bases, nullptr));
156 ASSERT_EQ(PyErr_Occurred(), nullptr);
157 ASSERT_TRUE(PyType_CheckExact(type));
158 EXPECT_TRUE(
159 PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(type.get()),
160 reinterpret_cast<PyTypeObject*>(PyExc_ValueError)));
161 EXPECT_TRUE(
162 PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(type.get()),
163 reinterpret_cast<PyTypeObject*>(PyExc_SystemError)));
164
165 PyObjectPtr type_bases(PyObject_GetAttrString(type, "__bases__"));
166 EXPECT_EQ(type_bases, bases);
167}
168
169TEST_F(ErrorsExtensionApiTest, NewExceptionWithEmptyDictAddsModuleName) {
170 PyObjectPtr dict(PyDict_New());
171 PyObjectPtr type(PyErr_NewException("Module.Name", nullptr, dict));
172 ASSERT_EQ(PyErr_Occurred(), nullptr);
173 ASSERT_TRUE(PyType_CheckExact(type));
174
175 PyObjectPtr module_name(PyObject_GetAttrString(type, "__module__"));
176 ASSERT_TRUE(PyUnicode_CheckExact(module_name));
177 EXPECT_TRUE(isUnicodeEqualsCStr(module_name, "Module"));
178}
179
180TEST_F(ErrorsExtensionApiTest,
181 NewExceptionWithDocWithNullDocReturnsTypeWithNoneDoc) {
182 PyObjectPtr type(
183 PyErr_NewExceptionWithDoc("Module.Name", nullptr, nullptr, nullptr));
184 ASSERT_EQ(PyErr_Occurred(), nullptr);
185 ASSERT_TRUE(PyType_CheckExact(type));
186 EXPECT_TRUE(
187 PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(type.get()),
188 reinterpret_cast<PyTypeObject*>(PyExc_Exception)));
189
190 PyObjectPtr name(PyObject_GetAttrString(type, "__name__"));
191 PyObjectPtr module_name(PyObject_GetAttrString(type, "__module__"));
192 PyObjectPtr doc_string(PyObject_GetAttrString(type, "__doc__"));
193 EXPECT_TRUE(isUnicodeEqualsCStr(name, "Name"));
194 EXPECT_TRUE(isUnicodeEqualsCStr(module_name, "Module"));
195 EXPECT_EQ(doc_string, Py_None);
196}
197
198TEST_F(ErrorsExtensionApiTest,
199 NewExceptionWithDocWithNonDictRaisesSystemError) {
200 PyObjectPtr not_dict(PyList_New(0));
201 EXPECT_EQ(PyErr_NewExceptionWithDoc("Module.Name", "DOC", nullptr, not_dict),
202 nullptr);
203 ASSERT_NE(PyErr_Occurred(), nullptr);
204 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
205}
206
207TEST_F(ErrorsExtensionApiTest, NewExceptionWithDocWithStrReturnsType) {
208 PyObjectPtr type(
209 PyErr_NewExceptionWithDoc("Module.Name", "DOC", nullptr, nullptr));
210 ASSERT_EQ(PyErr_Occurred(), nullptr);
211 ASSERT_TRUE(PyType_CheckExact(type));
212 EXPECT_TRUE(
213 PyType_IsSubtype(reinterpret_cast<PyTypeObject*>(type.get()),
214 reinterpret_cast<PyTypeObject*>(PyExc_Exception)));
215
216 PyObjectPtr name(PyObject_GetAttrString(type, "__name__"));
217 PyObjectPtr module_name(PyObject_GetAttrString(type, "__module__"));
218 PyObjectPtr doc_string(PyObject_GetAttrString(type, "__doc__"));
219 EXPECT_TRUE(isUnicodeEqualsCStr(name, "Name"));
220 EXPECT_TRUE(isUnicodeEqualsCStr(module_name, "Module"));
221 EXPECT_TRUE(isUnicodeEqualsCStr(doc_string, "DOC"));
222}
223
224TEST_F(ErrorsExtensionApiTest, NoMemoryRaisesMemoryError) {
225 ASSERT_EQ(PyErr_Occurred(), nullptr);
226 EXPECT_EQ(PyErr_NoMemory(), nullptr);
227
228 PyObject* type = nullptr;
229 PyObject* value = nullptr;
230 PyObject* traceback = nullptr;
231 PyErr_Fetch(&type, &value, &traceback);
232 EXPECT_EQ(type, PyExc_MemoryError);
233 EXPECT_EQ(value, nullptr);
234 // TODO(T42241510): Traceback support isn't implemented yet. Once it's ready,
235 // inspect the traceback here.
236
237 Py_DECREF(type);
238}
239
240#pragma push_macro("PyErr_BadInternalCall")
241#undef PyErr_BadInternalCall
242// PyErr_BadInternalCall() has an assert(0) in CPython.
243TEST_F(ErrorsExtensionApiTest, BadInternalCallRaisesSystemErrorPyro) {
244 ASSERT_EQ(PyErr_Occurred(), nullptr);
245 PyErr_BadInternalCall();
246
247 PyObject* type = nullptr;
248 PyObject* value = nullptr;
249 PyObject* traceback = nullptr;
250 PyErr_Fetch(&type, &value, &traceback);
251 EXPECT_EQ(type, PyExc_SystemError);
252
253 PyObjectPtr message(
254 PyUnicode_FromString("bad argument to internal function"));
255 ASSERT_TRUE(PyUnicode_Check(message));
256 EXPECT_EQ(_PyUnicode_EQ(value, message), 1);
257
258 // TODO(T42241510): Traceback support isn't implemented yet. Once it's ready,
259 // inspect the traceback here.
260
261 Py_DECREF(type);
262 Py_DECREF(value);
263}
264#pragma pop_macro("PyErr_BadInternalCall")
265
266TEST_F(ErrorsExtensionApiTest, UnderBadInternalCallRaisesSystemError) {
267 ASSERT_EQ(PyErr_Occurred(), nullptr);
268 _PyErr_BadInternalCall("abc", 123);
269
270 PyObject* type = nullptr;
271 PyObject* value = nullptr;
272 PyObject* traceback = nullptr;
273 PyErr_Fetch(&type, &value, &traceback);
274 EXPECT_EQ(type, PyExc_SystemError);
275
276 PyObjectPtr message(
277 PyUnicode_FromString("abc:123: bad argument to internal function"));
278 ASSERT_TRUE(PyUnicode_Check(message));
279 EXPECT_EQ(_PyUnicode_EQ(value, message), 1);
280
281 // TODO(T42241510): Traceback support isn't implemented yet. Once it's ready,
282 // inspect the traceback here.
283
284 Py_DECREF(type);
285 Py_DECREF(value);
286}
287
288TEST_F(ErrorsExtensionApiTest, ExceptionMatches) {
289 ASSERT_EQ(PyErr_Occurred(), nullptr);
290 PyErr_NoMemory();
291 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_MemoryError));
292 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_Exception));
293 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_BaseException));
294}
295
296TEST_F(ErrorsExtensionApiTest, Fetch) {
297 PyErr_SetObject(PyExc_Exception, Py_True);
298
299 PyObject* type = nullptr;
300 PyObject* value = nullptr;
301 PyObject* traceback = nullptr;
302 PyErr_Fetch(&type, &value, &traceback);
303 EXPECT_EQ(type, PyExc_Exception);
304 EXPECT_EQ(value, Py_True);
305 EXPECT_EQ(traceback, nullptr);
306
307 Py_DECREF(type);
308 Py_DECREF(value);
309}
310
311TEST_F(ErrorsExtensionApiTest, GetExcInfoWhenNoCaughtException) {
312 PyObject* p_type;
313 PyObject* p_value;
314 PyObject* p_traceback;
315 PyErr_SetExcInfo(nullptr, nullptr, nullptr);
316 PyErr_GetExcInfo(&p_type, &p_value, &p_traceback);
317 EXPECT_EQ(p_type, nullptr);
318 EXPECT_EQ(p_value, nullptr);
319 EXPECT_EQ(p_traceback, nullptr);
320}
321
322TEST_F(ErrorsExtensionApiTest, GetExcInfoWhenCaughtException) {
323 binaryfunc func = [](PyObject*, PyObject*) {
324 PyObject* p_type;
325 PyObject* p_value;
326 PyObject* p_traceback;
327 PyErr_GetExcInfo(&p_type, &p_value, &p_traceback);
328 EXPECT_EQ(p_type, PyExc_Exception);
329 PyObjectPtr args(PyObject_GetAttrString(p_value, "args"));
330 PyObject* first_arg = PyTuple_GetItem(args, 0);
331 EXPECT_TRUE(isUnicodeEqualsCStr(first_arg, "some str"));
332 EXPECT_TRUE(PyTraceBack_Check(p_traceback));
333 Py_INCREF(Py_None);
334 Py_XDECREF(p_type);
335 Py_XDECREF(p_value);
336 Py_XDECREF(p_traceback);
337 return Py_None;
338 };
339 PyMethodDef foo_methods[] = {{"noargs", func, METH_NOARGS}, {nullptr}};
340 static PyModuleDef def;
341 def = {
342 PyModuleDef_HEAD_INIT, "foo", nullptr, 0, foo_methods,
343 };
344 PyObjectPtr module(PyModule_Create(&def));
345 moduleSet("__main__", "foo", module);
346 ASSERT_TRUE(PyModule_CheckExact(module));
347 EXPECT_EQ(PyErr_Occurred(), nullptr);
348 PyRun_SimpleString(R"(
349try:
350 raise Exception('some str')
351except:
352 foo.noargs()
353)");
354}
355
356TEST_F(ErrorsExtensionApiTest, GivenExceptionMatches) {
357 // An exception matches itself and all of its super types up to and including
358 // BaseException.
359 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_MemoryError, PyExc_MemoryError),
360 1);
361 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_MemoryError, PyExc_Exception), 1);
362 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_MemoryError, PyExc_BaseException),
363 1);
364
365 // An exception should not match a disjoint exception type.
366 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_MemoryError, PyExc_IOError), 0);
367
368 // If the objects are not exceptions or exception classes, the matching falls
369 // back to an identity comparison.
370 EXPECT_TRUE(PyErr_GivenExceptionMatches(Py_True, Py_True));
371}
372
373TEST_F(ErrorsExtensionApiTest, GivenExceptionMatchesWithNullptr) {
374 // If any argument is a null pointer zero is returned.
375 EXPECT_EQ(PyErr_GivenExceptionMatches(nullptr, nullptr), 0);
376 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_SystemError, nullptr), 0);
377 EXPECT_EQ(PyErr_GivenExceptionMatches(nullptr, PyExc_SystemError), 0);
378}
379
380TEST_F(ErrorsExtensionApiTest, GivenExceptionMatchesWithTuple) {
381 PyObject* exc1 = PyTuple_Pack(1, PyExc_Exception);
382 ASSERT_NE(exc1, nullptr);
383 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_MemoryError, exc1), 1);
384 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_SystemExit, exc1), 0);
385 Py_DECREF(exc1);
386
387 // Linear search
388 PyObject* exc2 = PyTuple_Pack(2, PyExc_Warning, PyExc_Exception);
389 ASSERT_NE(exc2, nullptr);
390 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_MemoryError, exc2), 1);
391 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_SystemExit, exc2), 0);
392 Py_DECREF(exc2);
393
394 // Recursion
395 PyObjectPtr inner(PyTuple_Pack(1, PyExc_Exception));
396 PyObject* exc3 = PyTuple_Pack(2, inner.get(), PyExc_Warning);
397 ASSERT_NE(exc3, nullptr);
398 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_MemoryError, exc3), 1);
399 EXPECT_EQ(PyErr_GivenExceptionMatches(PyExc_SystemExit, exc3), 0);
400 Py_DECREF(exc3);
401}
402
403TEST_F(ErrorsExtensionApiTest, Restore) {
404 ASSERT_EQ(PyErr_Occurred(), nullptr);
405 Py_INCREF(PyExc_Exception);
406 Py_INCREF(Py_True);
407 PyErr_Restore(PyExc_Exception, Py_True, nullptr);
408
409 PyObject* type = nullptr;
410 PyObject* value = nullptr;
411 PyObject* traceback = nullptr;
412 PyErr_Fetch(&type, &value, &traceback);
413 EXPECT_EQ(type, PyExc_Exception);
414 EXPECT_EQ(value, Py_True);
415 EXPECT_EQ(traceback, nullptr);
416
417 Py_DECREF(type);
418 Py_DECREF(value);
419}
420
421TEST_F(ErrorsExtensionApiTest, ChainExceptionsSetsContext) {
422 // First, set an exception.
423 PyErr_SetString(PyExc_RuntimeError, "whoops");
424
425 // Next, attempt to restore a different exception. It should be chained to the
426 // existing RuntimeError.
427 PyObject* exc = PyExc_TypeError;
428 Py_INCREF(exc);
429 PyObject* val = Py_None;
430 Py_INCREF(val);
431 PyObject* tb = Py_None;
432 Py_INCREF(tb);
433 _PyErr_ChainExceptions(exc, val, tb);
434 ASSERT_NE(PyErr_Occurred(), nullptr);
435
436 // Make sure the RuntimeError has the new TypeError as its context attribute.
437 PyErr_Fetch(&exc, &val, &tb);
438 ASSERT_EQ(PyErr_GivenExceptionMatches(exc, PyExc_RuntimeError), 1);
439 ASSERT_EQ(PyErr_GivenExceptionMatches(val, PyExc_RuntimeError), 1);
440
441 PyObjectPtr ctx(PyException_GetContext(val));
442 EXPECT_EQ(PyErr_GivenExceptionMatches(ctx, PyExc_TypeError), 1);
443
444 EXPECT_EQ(tb, nullptr);
445
446 Py_DECREF(exc);
447 Py_DECREF(val);
448}
449
450TEST_F(ErrorsExtensionApiTest, NormalizeCreatesException) {
451 PyObject* exc = PyExc_RuntimeError;
452 PyObject* val = PyUnicode_FromString("something went wrong!");
453 PyObjectPtr val_orig(val);
454 Py_INCREF(val_orig);
455 PyObject* tb = nullptr;
456 PyErr_NormalizeException(&exc, &val, &tb);
457 ASSERT_EQ(PyErr_Occurred(), nullptr);
458 EXPECT_TRUE(PyErr_GivenExceptionMatches(exc, PyExc_RuntimeError));
459 ASSERT_TRUE(PyErr_GivenExceptionMatches(val, PyExc_RuntimeError));
460 PyObjectPtr args(PyObject_GetAttrString(val, "args"));
461 ASSERT_TRUE(PyTuple_CheckExact(args));
462 ASSERT_EQ(PyTuple_Size(args), 1);
463 EXPECT_EQ(PyTuple_GetItem(args, 0), val_orig);
464
465 Py_DECREF(val);
466}
467
468TEST_F(ErrorsExtensionApiTest, NormalizeWithNullTypeDoesNothing) {
469 PyObject* exc = nullptr;
470 PyObject* val = nullptr;
471 PyObject* tb = nullptr;
472 PyErr_NormalizeException(&exc, &val, &tb);
473 EXPECT_EQ(PyErr_Occurred(), nullptr);
474 EXPECT_EQ(exc, nullptr);
475 EXPECT_EQ(val, nullptr);
476 EXPECT_EQ(tb, nullptr);
477}
478
479TEST_F(ErrorsExtensionApiTest, NormalizeWithNullValueUsesNone) {
480 PyObject* exc = PyExc_TypeError;
481 PyObject* val = Py_None;
482 Py_INCREF(val);
483 PyObject* tb = nullptr;
484 PyErr_NormalizeException(&exc, &val, &tb);
485 ASSERT_EQ(PyErr_Occurred(), nullptr);
486 EXPECT_TRUE(PyErr_GivenExceptionMatches(exc, PyExc_TypeError));
487 ASSERT_TRUE(PyErr_GivenExceptionMatches(val, PyExc_TypeError));
488 PyObjectPtr args(PyObject_GetAttrString(val, "args"));
489 ASSERT_TRUE(PyTuple_CheckExact(args));
490 EXPECT_EQ(PyTuple_Size(args), 0);
491
492 Py_DECREF(val);
493}
494
495TEST_F(ErrorsExtensionApiTest, NormalizeWithTupleUsesArgs) {
496 PyObject* exc = PyExc_Exception;
497 PyObject* val = PyTuple_New(2);
498 PyObjectPtr t0(PyLong_FromLong(111));
499 PyObjectPtr t1(PyUnicode_FromString("hello"));
500 Py_INCREF(t0);
501 PyTuple_SET_ITEM(val, 0, t0);
502 Py_INCREF(t1);
503 PyTuple_SET_ITEM(val, 1, t1);
504 PyObject* tb = nullptr;
505 PyErr_NormalizeException(&exc, &val, &tb);
506 ASSERT_EQ(PyErr_Occurred(), nullptr);
507 EXPECT_TRUE(PyErr_GivenExceptionMatches(exc, PyExc_Exception));
508 ASSERT_TRUE(PyErr_GivenExceptionMatches(val, PyExc_Exception));
509 PyObjectPtr args(PyObject_GetAttrString(val, "args"));
510 ASSERT_TRUE(PyTuple_CheckExact(args));
511 ASSERT_EQ(PyTuple_Size(args), 2);
512 EXPECT_EQ(PyTuple_GetItem(args, 0), t0);
513 EXPECT_EQ(PyTuple_GetItem(args, 1), t1);
514
515 Py_DECREF(val);
516}
517
518TEST_F(ErrorsExtensionApiTest, NormalizeWithNonExceptionDoesNothing) {
519 PyObject *exc = PyLong_FromLong(123), *exc_orig = exc;
520 PyObject *val = PyLong_FromLong(456), *val_orig = val;
521 PyObject* tb = nullptr;
522 PyErr_NormalizeException(&exc, &val, &tb);
523 ASSERT_EQ(PyErr_Occurred(), nullptr);
524 EXPECT_EQ(exc, exc_orig);
525 EXPECT_EQ(val, val_orig);
526 EXPECT_EQ(tb, nullptr);
527
528 Py_DECREF(val);
529 Py_DECREF(exc);
530}
531
532TEST_F(ErrorsExtensionApiTest, NormalizeWithFailingConstructorReturnsNewError) {
533 // TODO(bsimmers): Once we have PyType_FromSpec() (or PyType_Ready() can
534 // handle base classes), add a similar test to ensure that
535 // PyErr_NormalizeException() doesn't loop infinintely when normalization
536 // keeps failing.
537
538 ASSERT_EQ(PyRun_SimpleString(R"(
539class BadException(Exception):
540 def __init__(self, arg):
541 raise RuntimeError(arg)
542)"),
543 0);
544 PyObject* exc = mainModuleGet("BadException");
545 ASSERT_TRUE(PyType_Check(exc));
546
547 const char* msg = "couldn't construct BadException";
548 PyObject* val = PyUnicode_FromString(msg);
549 PyObject* tb = nullptr;
550 PyErr_NormalizeException(&exc, &val, &tb);
551 ASSERT_EQ(PyErr_Occurred(), nullptr);
552 EXPECT_TRUE(PyErr_GivenExceptionMatches(exc, PyExc_RuntimeError));
553 ASSERT_TRUE(PyErr_GivenExceptionMatches(val, PyExc_RuntimeError));
554 PyObjectPtr args(PyObject_GetAttrString(val, "args"));
555 ASSERT_TRUE(PyTuple_CheckExact(args));
556 ASSERT_EQ(PyTuple_Size(args), 1);
557 PyObject* str = PyTuple_GetItem(args, 0);
558 EXPECT_TRUE(isUnicodeEqualsCStr(str, msg));
559
560 Py_XDECREF(val);
561 Py_XDECREF(exc);
562 Py_XDECREF(tb);
563}
564
565TEST_F(ErrorsExtensionApiTest, ProgramTextObjectWithNullFilenameReturnsNull) {
566 EXPECT_EQ(PyErr_ProgramTextObject(nullptr, 5), nullptr);
567 EXPECT_EQ(PyErr_Occurred(), nullptr);
568}
569
570TEST_F(ErrorsExtensionApiTest,
571 ProgramTextObjectWithNonPositiveLinenoReturnsNull) {
572 PyObjectPtr filename(PyUnicode_FromString("filename"));
573 EXPECT_EQ(PyErr_ProgramTextObject(filename, -5), nullptr);
574 EXPECT_EQ(PyErr_Occurred(), nullptr);
575}
576
577TEST_F(ErrorsExtensionApiTest,
578 ProgramTextObjectWithNonExistentFileReturnsNull) {
579 PyObjectPtr filename(PyUnicode_FromString("foobarbazquux"));
580 EXPECT_EQ(PyErr_ProgramTextObject(filename, 5), nullptr);
581 EXPECT_EQ(PyErr_Occurred(), nullptr);
582}
583
584TEST_F(ErrorsExtensionApiTest, SetExcInfoValuesRetrievedByGetExcInfo) {
585 PyObjectPtr type(PyExc_TypeError);
586 Py_INCREF(type);
587 PyObjectPtr val(PyUnicode_FromString("some str"));
588 PyObject* traceback = nullptr;
589 PyErr_SetExcInfo(type, val, traceback);
590
591 PyObject* p_type;
592 PyObject* p_value;
593 PyObject* p_traceback;
594 PyErr_GetExcInfo(&p_type, &p_value, &p_traceback);
595 EXPECT_EQ(p_type, type);
596 EXPECT_EQ(p_value, val);
597 // TODO(T77866913): EXPECT_EQ(p_traceback, traceback);
598}
599
600TEST_F(ErrorsExtensionApiTest, SetFromErrnoWithZeroSetsError) {
601 errno = 0;
602 ASSERT_EQ(PyErr_SetFromErrno(PyExc_TypeError), nullptr);
603 ASSERT_NE(PyErr_Occurred(), nullptr);
604 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
605}
606
607TEST_F(ErrorsExtensionApiTest, SetFromErrnoWithNonZeroSetsError) {
608 errno = 1;
609 ASSERT_EQ(PyErr_SetFromErrno(PyExc_SystemError), nullptr);
610 ASSERT_NE(PyErr_Occurred(), nullptr);
611 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
612}
613
614TEST_F(ErrorsExtensionApiTest,
615 SetFromErrnoWithInterruptRaisesKeyboardInterrupt) {
616 PyErr_SetInterrupt();
617 errno = EINTR;
618 ASSERT_EQ(PyErr_SetFromErrno(PyExc_SystemError), nullptr);
619 ASSERT_NE(PyErr_Occurred(), nullptr);
620 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_KeyboardInterrupt));
621}
622
623TEST_F(ErrorsExtensionApiTest, SetFromErrnoWithFilenameSetsError) {
624 errno = 1;
625 ASSERT_EQ(PyErr_SetFromErrnoWithFilename(PyExc_NameError, "foo"), nullptr);
626 ASSERT_NE(PyErr_Occurred(), nullptr);
627 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_NameError));
628}
629
630TEST_F(ErrorsExtensionApiTest, SetFromErrnoWithFilenameObjectSetsError) {
631 errno = 1;
632 PyObjectPtr foo(PyUnicode_FromString("foo"));
633 ASSERT_EQ(PyErr_SetFromErrnoWithFilenameObject(PyExc_KeyError, foo), nullptr);
634 ASSERT_NE(PyErr_Occurred(), nullptr);
635 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_KeyError));
636}
637
638TEST_F(ErrorsExtensionApiTest, SetFromErrnoWithFilenameObjectsSetsError) {
639 errno = 1;
640 PyObjectPtr foo(PyUnicode_FromString("foo"));
641 PyObjectPtr bar(PyUnicode_FromString("bar"));
642 ASSERT_EQ(
643 PyErr_SetFromErrnoWithFilenameObjects(PyExc_ChildProcessError, foo, bar),
644 nullptr);
645 ASSERT_NE(PyErr_Occurred(), nullptr);
646 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ChildProcessError));
647}
648
649TEST_F(ErrorsExtensionApiTest, SetNoneCreatesExceptionWithNoArgs) {
650 PyErr_SetNone(PyExc_Exception);
651
652 ASSERT_NE(PyErr_Occurred(), nullptr);
653 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_Exception));
654 PyObject* type = nullptr;
655 PyObject* value = nullptr;
656 PyObject* traceback = nullptr;
657 // Fetch the non-normalized error
658 PyErr_Fetch(&type, &value, &traceback);
659 EXPECT_EQ(type, PyExc_Exception);
660 ASSERT_EQ(value, nullptr);
661 // Normalize the exception
662 PyErr_NormalizeException(&type, &value, &traceback);
663 EXPECT_EQ(type, PyExc_Exception);
664 PyObjectPtr args(PyObject_GetAttrString(value, "args"));
665 ASSERT_TRUE(PyTuple_CheckExact(args));
666 ASSERT_EQ(PyTuple_Size(args), 0);
667 Py_DECREF(type);
668 Py_DECREF(value);
669}
670
671TEST_F(ErrorsExtensionApiTest, SetStringSetsValue) {
672 PyErr_SetString(PyExc_Exception, "An exception occured");
673 PyObject* type = nullptr;
674 PyObject* value = nullptr;
675 PyObject* traceback = nullptr;
676 PyErr_Fetch(&type, &value, &traceback);
677 EXPECT_EQ(traceback, nullptr);
678 EXPECT_EQ(type, PyExc_Exception);
679 EXPECT_TRUE(isUnicodeEqualsCStr(value, "An exception occured"));
680
681 Py_DECREF(type);
682 Py_DECREF(value);
683}
684
685TEST_F(ErrorsExtensionApiTest, FormatWithNoArgsSetsAppropriateFields) {
686 ASSERT_EQ(PyErr_Format(PyExc_TypeError, "hello error"), nullptr);
687 PyObject* type = nullptr;
688 PyObject* value = nullptr;
689 PyObject* traceback = nullptr;
690 PyErr_Fetch(&type, &value, &traceback);
691 EXPECT_EQ(type, PyExc_TypeError);
692 EXPECT_TRUE(isUnicodeEqualsCStr(value, "hello error"));
693 EXPECT_EQ(traceback, nullptr);
694
695 Py_DECREF(type);
696 Py_DECREF(value);
697}
698
699TEST_F(ErrorsExtensionApiTest, FormatWithManyArgsSetsAppropriateFields) {
700 ASSERT_EQ(PyErr_Format(PyExc_MemoryError, "h%c%s", 'e', "llo world"),
701 nullptr);
702 PyObject* type = nullptr;
703 PyObject* value = nullptr;
704 PyObject* traceback = nullptr;
705 PyErr_Fetch(&type, &value, &traceback);
706 EXPECT_EQ(type, PyExc_MemoryError);
707 EXPECT_TRUE(isUnicodeEqualsCStr(value, "hello world"));
708 EXPECT_EQ(traceback, nullptr);
709
710 Py_DECREF(type);
711 Py_DECREF(value);
712}
713
714TEST_F(ErrorsExtensionApiTest, FormatFromCauseWithoutExceptionFailsDeathTest) {
715 EXPECT_DEATH(_PyErr_FormatFromCause(PyExc_TypeError, ""), "");
716}
717
718TEST_F(ErrorsExtensionApiTest, FormatFromCauseSetsCauseAndContext) {
719 ASSERT_EQ(PyErr_Format(PyExc_MemoryError, "%s", "original cause"), nullptr);
720 ASSERT_EQ(_PyErr_FormatFromCause(PyExc_TypeError, "%s", "new error"),
721 nullptr);
722 PyObject* type = nullptr;
723 PyObject* value = nullptr;
724 PyObject* traceback = nullptr;
725 PyErr_Fetch(&type, &value, &traceback);
726 EXPECT_EQ(type, PyExc_TypeError);
727 Py_XDECREF(type);
728 EXPECT_EQ(traceback, nullptr);
729 Py_XDECREF(traceback);
730 PyObjectPtr cause(PyException_GetCause(value));
731 PyObjectPtr context(PyException_GetContext(value));
732 EXPECT_TRUE(PyErr_GivenExceptionMatches(cause, PyExc_MemoryError));
733 EXPECT_TRUE(PyErr_GivenExceptionMatches(context, PyExc_MemoryError));
734 Py_XDECREF(value);
735}
736
737TEST_F(ErrorsExtensionApiTest, WriteUnraisableClearsException) {
738 PyErr_SetString(PyExc_MemoryError, "original cause");
739 PyErr_WriteUnraisable(Py_None);
740 EXPECT_EQ(PyErr_Occurred(), nullptr);
741}
742
743TEST_F(ErrorsExtensionApiTest, WriteUnraisableCallsDunderRepr) {
744 PyRun_SimpleString(R"(
745class C:
746 def __repr__(self):
747 return "foo"
748c = C()
749)");
750 PyObjectPtr c(mainModuleGet("c"));
751 PyErr_SetString(PyExc_MemoryError, "original cause");
752 CaptureStdStreams streams;
753 PyErr_WriteUnraisable(c);
754 EXPECT_EQ(PyErr_Occurred(), nullptr);
755 EXPECT_THAT(streams.err(),
756 ::testing::StartsWith("Exception ignored in: foo"));
757 EXPECT_EQ(streams.out(), "");
758}
759
760TEST_F(ErrorsExtensionApiTest,
761 WriteUnraisableDoesNotFailWithNonCallableDunderRepr) {
762 PyRun_SimpleString(R"(
763class C:
764 __repr__ = 5
765c = C()
766)");
767 PyObjectPtr c(mainModuleGet("c"));
768 PyErr_SetString(PyExc_MemoryError, "original cause");
769 CaptureStdStreams streams;
770 PyErr_WriteUnraisable(c);
771 EXPECT_EQ(PyErr_Occurred(), nullptr);
772 EXPECT_THAT(
773 streams.err(),
774 ::testing::StartsWith("Exception ignored in: <object repr() failed>"));
775 EXPECT_EQ(streams.out(), "");
776}
777
778TEST_F(ErrorsExtensionApiTest,
779 WriteUnraisableWithNonStrDunderModuleWritesUnknown) {
780 PyRun_SimpleString(R"(
781class C(BaseException):
782 pass
783C.__module__ = 5
784c = C()
785)");
786 PyObjectPtr c(mainModuleGet("c"));
787 PyObjectPtr ctype(mainModuleGet("C"));
788 PyErr_SetString(ctype, "original cause");
789 CaptureStdStreams streams;
790 PyErr_WriteUnraisable(c);
791 EXPECT_EQ(PyErr_Occurred(), nullptr);
792 EXPECT_THAT(streams.err(),
793 ::testing::EndsWith("<unknown>C: original cause\n"));
794 EXPECT_EQ(streams.out(), "");
795}
796
797TEST_F(ErrorsExtensionApiTest, WriteUnraisableWritesModuleName) {
798 PyRun_SimpleString(R"(
799class C(BaseException):
800 pass
801C.__module__ = "foo"
802c = C()
803)");
804 PyObjectPtr c(mainModuleGet("c"));
805 PyObjectPtr ctype(mainModuleGet("C"));
806 PyErr_SetString(ctype, "original cause");
807 CaptureStdStreams streams;
808 PyErr_WriteUnraisable(c);
809 EXPECT_EQ(PyErr_Occurred(), nullptr);
810 EXPECT_THAT(streams.err(), ::testing::EndsWith("foo.C: original cause\n"));
811 EXPECT_EQ(streams.out(), "");
812}
813
814TEST_F(ErrorsExtensionApiTest, WriteUnraisableCallsDunderStrOnVal) {
815 PyRun_SimpleString(R"(
816class C:
817 def __str__(self):
818 return "bar"
819C.__module__ = "foo"
820c = C()
821)");
822 PyObjectPtr c(mainModuleGet("c"));
823 PyErr_SetObject(PyExc_MemoryError, c);
824 CaptureStdStreams streams;
825 PyErr_WriteUnraisable(Py_None);
826 EXPECT_EQ(PyErr_Occurred(), nullptr);
827 EXPECT_THAT(streams.err(), ::testing::EndsWith("MemoryError: bar\n"));
828 EXPECT_EQ(streams.out(), "");
829}
830
831TEST_F(ErrorsExtensionApiTest,
832 WriteUnraisableDoesNotFailWithNonCallableDunderStr) {
833 PyRun_SimpleString(R"(
834class C:
835 __str__ = 5
836C.__module__ = "foo"
837c = C()
838)");
839 PyObjectPtr c(mainModuleGet("c"));
840 PyErr_SetObject(PyExc_MemoryError, c);
841 CaptureStdStreams streams;
842 PyErr_WriteUnraisable(Py_None);
843 EXPECT_EQ(PyErr_Occurred(), nullptr);
844 EXPECT_THAT(streams.err(),
845 ::testing::EndsWith("MemoryError: <exception str() failed>\n"));
846 EXPECT_EQ(streams.out(), "");
847}
848
849TEST_F(ErrorsExtensionApiTest, SetObjectWithCaughtExceptionSetsContext) {
850 PyCFunction test_set_object = [](PyObject*, PyObject*) -> PyObject* {
851 PyErr_SetString(PyExc_ValueError, "something went wrong");
852 return nullptr;
853 };
854 static PyMethodDef methods[2];
855 methods[0] = {
856 "test_set_object",
857 test_set_object,
858 METH_NOARGS,
859 "doc",
860 };
861 methods[1] = {nullptr};
862 static PyModuleDef mod_def;
863 mod_def = {
864 PyModuleDef_HEAD_INIT,
865 "errors_test", // m_name
866 "doc", // m_doc
867 0, // m_size
868 methods, // m_methods
869 nullptr, // m_slots
870 nullptr, // m_traverse
871 nullptr, // m_clear
872 nullptr, // m_free
873 };
874
875 PyObjectPtr module(PyModule_Create(&mod_def));
876 ASSERT_NE(module, nullptr);
877 ASSERT_EQ(moduleSet("__main__", "errors_test", module), 0);
878 ASSERT_EQ(PyRun_SimpleString(R"(
879try:
880 try:
881 raise RuntimeError("blorp")
882 except RuntimeError as exc:
883 inner_exc = exc
884 errors_test.test_set_object()
885except ValueError as exc:
886 outer_exc = exc
887)"),
888 0);
889
890 PyObjectPtr inner_exc(mainModuleGet("inner_exc"));
891 ASSERT_NE(inner_exc, nullptr);
892 PyObjectPtr outer_exc(mainModuleGet("outer_exc"));
893 ASSERT_NE(outer_exc, nullptr);
894 PyObjectPtr outer_ctx(PyException_GetContext(outer_exc));
895 EXPECT_EQ(outer_ctx, inner_exc);
896 EXPECT_EQ(PyException_GetContext(inner_exc), nullptr);
897}
898
899} // namespace testing
900} // namespace py