this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2#include "Python.h"
3#include "gtest/gtest.h"
4
5#include "capi-fixture.h"
6#include "capi-testing.h"
7
8namespace py {
9namespace testing {
10
11using ObjectExtensionApiTest = ExtensionApi;
12
13TEST_F(ObjectExtensionApiTest, PyNoneIdentityIsEqual) {
14 // Test Identitiy
15 PyObject* none1 = Py_None;
16 PyObject* none2 = Py_None;
17 EXPECT_EQ(none1, none2);
18}
19
20TEST_F(ObjectExtensionApiTest, PyNotImplementedIdentityIsEqual) {
21 // Test Identitiy
22 PyObject* not_impl1 = Py_NotImplemented;
23 PyObject* not_impl2 = Py_NotImplemented;
24 EXPECT_EQ(not_impl1, not_impl2);
25}
26
27TEST_F(ObjectExtensionApiTest, BytesWithNullReturnsBytes) {
28 PyObjectPtr result(PyObject_Bytes(nullptr));
29 ASSERT_EQ(PyErr_Occurred(), nullptr);
30 EXPECT_STREQ(PyBytes_AsString(result), "<NULL>");
31}
32
33TEST_F(ObjectExtensionApiTest, BytesWithBytesReturnsSameObject) {
34 PyObjectPtr bytes(PyBytes_FromString("hello"));
35 PyObjectPtr result(PyObject_Bytes(bytes));
36 ASSERT_EQ(PyErr_Occurred(), nullptr);
37 EXPECT_EQ(result, bytes);
38}
39
40TEST_F(ObjectExtensionApiTest, BytesWithBadDunderBytesRaisesTypeError) {
41 PyRun_SimpleString(R"(
42class Foo:
43 def __bytes__(self):
44 return 1
45obj = Foo()
46)");
47 PyObjectPtr obj(mainModuleGet("obj"));
48 ASSERT_EQ(PyObject_Bytes(obj), nullptr);
49 ASSERT_NE(PyErr_Occurred(), nullptr);
50 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
51}
52
53TEST_F(ObjectExtensionApiTest, BytesWithDunderBytesReturnsBytes) {
54 PyRun_SimpleString(R"(
55class Foo:
56 def __bytes__(self):
57 return b'123'
58obj = Foo()
59)");
60 PyObjectPtr obj(mainModuleGet("obj"));
61 PyObjectPtr result(PyObject_Bytes(obj));
62 ASSERT_EQ(PyErr_Occurred(), nullptr);
63 EXPECT_STREQ(PyBytes_AsString(result), "123");
64}
65
66TEST_F(ObjectExtensionApiTest, BytesWithDunderBytesErrorRaisesValueError) {
67 PyRun_SimpleString(R"(
68class Foo:
69 def __bytes__(self):
70 raise ValueError
71obj = Foo()
72)");
73 PyObjectPtr obj(mainModuleGet("obj"));
74 ASSERT_EQ(PyObject_Bytes(obj), nullptr);
75 ASSERT_NE(PyErr_Occurred(), nullptr);
76 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
77}
78
79TEST_F(ObjectExtensionApiTest, BytesWithListOfByteReturnsBytes) {
80 PyObjectPtr list(PyList_New(2));
81 ASSERT_EQ(PyList_SetItem(list, 0, PyLong_FromLong('h')), 0);
82 ASSERT_EQ(PyList_SetItem(list, 1, PyLong_FromLong('i')), 0);
83 PyObjectPtr result(PyObject_Bytes(list));
84 ASSERT_EQ(PyErr_Occurred(), nullptr);
85 EXPECT_STREQ(PyBytes_AsString(result), "hi");
86}
87
88TEST_F(ObjectExtensionApiTest, BytesWithTupleOfByteReturnsBytes) {
89 PyObjectPtr tuple(PyTuple_New(2));
90 ASSERT_EQ(PyTuple_SetItem(tuple, 0, PyLong_FromLong('h')), 0);
91 ASSERT_EQ(PyTuple_SetItem(tuple, 1, PyLong_FromLong('i')), 0);
92 PyObjectPtr result(PyObject_Bytes(tuple));
93 ASSERT_EQ(PyErr_Occurred(), nullptr);
94 EXPECT_STREQ(PyBytes_AsString(result), "hi");
95}
96
97TEST_F(ObjectExtensionApiTest, BytesWithStringRaisesTypeError) {
98 PyObjectPtr str(PyUnicode_FromString("hello"));
99 EXPECT_EQ(PyObject_Bytes(str), nullptr);
100 ASSERT_NE(PyErr_Occurred(), nullptr);
101 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
102}
103
104TEST_F(ObjectExtensionApiTest, CallableCheckWithNullReturnsZero) {
105 EXPECT_EQ(PyCallable_Check(nullptr), 0);
106 EXPECT_EQ(PyErr_Occurred(), nullptr);
107}
108
109TEST_F(ObjectExtensionApiTest, CallableCheckWithNoneDunderCallReturnsOne) {
110 PyRun_SimpleString(R"(
111class C:
112 __call__ = None
113c = C()
114)");
115 PyObjectPtr c(mainModuleGet("c"));
116 EXPECT_EQ(PyCallable_Check(c), 1);
117 EXPECT_EQ(PyErr_Occurred(), nullptr);
118}
119
120TEST_F(ObjectExtensionApiTest,
121 CallableCheckWithNonCallableDunderCallReturnsOne) {
122 PyRun_SimpleString(R"(
123class C:
124 __call__ = 5
125c = C()
126)");
127 PyObjectPtr c(mainModuleGet("c"));
128 EXPECT_EQ(PyCallable_Check(c), 1);
129 EXPECT_EQ(PyErr_Occurred(), nullptr);
130}
131
132TEST_F(ObjectExtensionApiTest, DelAttrStringRemovesAttribute) {
133 PyRun_SimpleString(R"(
134class C:
135 pass
136obj = C()
137obj.a = 42
138obj.b = 13
139)");
140 PyObjectPtr obj(mainModuleGet("obj"));
141 ASSERT_TRUE(PyObject_HasAttrString(obj, "a"));
142 ASSERT_TRUE(PyObject_HasAttrString(obj, "b"));
143 EXPECT_EQ(PyObject_DelAttrString(obj, "a"), 0);
144 EXPECT_FALSE(PyObject_HasAttrString(obj, "a"));
145 EXPECT_TRUE(PyObject_HasAttrString(obj, "b"));
146}
147
148TEST_F(ObjectExtensionApiTest, DelAttrRemovesAttribute) {
149 PyRun_SimpleString(R"(
150class C:
151 pass
152obj = C()
153obj.a = 42
154obj.b = 13
155)");
156 PyObjectPtr obj(mainModuleGet("obj"));
157 ASSERT_TRUE(PyObject_HasAttrString(obj, "a"));
158 ASSERT_TRUE(PyObject_HasAttrString(obj, "b"));
159 PyObjectPtr name(PyUnicode_FromString("a"));
160 EXPECT_EQ(PyObject_DelAttr(obj, name), 0);
161 EXPECT_FALSE(PyObject_HasAttrString(obj, "a"));
162 EXPECT_TRUE(PyObject_HasAttrString(obj, "b"));
163}
164
165TEST_F(ObjectExtensionApiTest, DelAttrRaisesAttributeError) {
166 PyObjectPtr obj(borrow(Py_None));
167 EXPECT_EQ(PyObject_DelAttrString(obj, "does_not_exist"), -1);
168 EXPECT_NE(PyErr_Occurred(), nullptr);
169 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError));
170}
171
172TEST_F(ObjectExtensionApiTest, LookupAttrWithNonStrNameRaisesTypeError) {
173 PyObjectPtr obj(borrow(Py_None));
174 PyObjectPtr name(borrow(Py_None));
175 PyObject* result = name.get(); // some non-NULL value
176 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), -1);
177 ASSERT_NE(PyErr_Occurred(), nullptr);
178 EXPECT_EQ(result, nullptr);
179 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
180}
181
182TEST_F(ObjectExtensionApiTest, LookupAttrWithExtantAttrReturnsOne) {
183 PyRun_SimpleString(R"(
184class C:
185 pass
186obj = C()
187obj.a = 42
188)");
189 PyObjectPtr obj(mainModuleGet("obj"));
190 PyObjectPtr name(PyUnicode_FromString("a"));
191 ASSERT_TRUE(PyObject_HasAttr(obj, name));
192 PyObject* result = nullptr;
193 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), 1);
194 EXPECT_EQ(PyErr_Occurred(), nullptr);
195 ASSERT_NE(result, nullptr);
196 EXPECT_EQ(PyLong_AsLong(result), 42);
197 Py_DECREF(result);
198}
199
200TEST_F(ObjectExtensionApiTest, LookupAttrWithNonexistentAttrReturnsZero) {
201 PyObjectPtr obj(borrow(Py_None));
202 PyObjectPtr name(PyUnicode_FromString("a"));
203 ASSERT_FALSE(PyObject_HasAttr(obj, name));
204 PyObject* result = name.get(); // some non-NULL value
205 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), 0);
206 EXPECT_EQ(PyErr_Occurred(), nullptr);
207 EXPECT_EQ(result, nullptr);
208}
209
210TEST_F(ObjectExtensionApiTest,
211 LookupAttrWithSuccessfulDunderGetAttributeReturnsOne) {
212 PyRun_SimpleString(R"(
213class C:
214 def __getattribute__(self, key):
215 return 42
216obj = C()
217)");
218 PyObjectPtr obj(mainModuleGet("obj"));
219 PyObjectPtr name(PyUnicode_FromString("a"));
220 PyObject* result = nullptr;
221 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), 1);
222 EXPECT_EQ(PyErr_Occurred(), nullptr);
223 ASSERT_NE(result, nullptr);
224 EXPECT_EQ(PyLong_AsLong(result), 42);
225 Py_DECREF(result);
226}
227
228TEST_F(ObjectExtensionApiTest,
229 LookupAttrWithRaisingDunderGetAttributeReturnsNegativeOne) {
230 PyRun_SimpleString(R"(
231class C:
232 def __getattribute__(self, key):
233 raise TypeError("foo")
234obj = C()
235)");
236 PyObjectPtr obj(mainModuleGet("obj"));
237 PyObjectPtr name(PyUnicode_FromString("a"));
238 PyObject* result = name.get(); // some non-NULL value
239 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), -1);
240 ASSERT_NE(PyErr_Occurred(), nullptr);
241 EXPECT_EQ(result, nullptr);
242 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
243}
244
245TEST_F(ObjectExtensionApiTest,
246 LookupAttrWithAttributeErrorRaisingDunderGetAttributeReturnsZero) {
247 PyRun_SimpleString(R"(
248class C:
249 def __getattribute__(self, key):
250 raise AttributeError("foo")
251obj = C()
252)");
253 PyObjectPtr obj(mainModuleGet("obj"));
254 PyObjectPtr name(PyUnicode_FromString("a"));
255 PyObject* result = name.get(); // some non-NULL value
256 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), 0);
257 EXPECT_EQ(PyErr_Occurred(), nullptr);
258 EXPECT_EQ(result, nullptr);
259}
260
261TEST_F(ObjectExtensionApiTest,
262 LookupAttrWithSuccessfulDunderGetAttrReturnsOne) {
263 PyRun_SimpleString(R"(
264class C:
265 def __getattr__(self, key):
266 return 42
267obj = C()
268)");
269 PyObjectPtr obj(mainModuleGet("obj"));
270 PyObjectPtr name(PyUnicode_FromString("a"));
271 PyObject* result = nullptr;
272 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), 1);
273 EXPECT_EQ(PyErr_Occurred(), nullptr);
274 ASSERT_NE(result, nullptr);
275 EXPECT_EQ(PyLong_AsLong(result), 42);
276 Py_DECREF(result);
277}
278
279TEST_F(ObjectExtensionApiTest,
280 LookupAttrWithRaisingDunderGetAttrReturnsNegativeOne) {
281 PyRun_SimpleString(R"(
282class C:
283 def __getattr__(self, key):
284 raise TypeError("foo")
285obj = C()
286)");
287 PyObjectPtr obj(mainModuleGet("obj"));
288 PyObjectPtr name(PyUnicode_FromString("a"));
289 PyObject* result = name.get(); // some non-NULL value
290 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), -1);
291 ASSERT_NE(PyErr_Occurred(), nullptr);
292 EXPECT_EQ(result, nullptr);
293 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
294}
295
296TEST_F(ObjectExtensionApiTest,
297 LookupAttrWithAttributeErrorRaisingDunderGetAttrReturnsZero) {
298 PyRun_SimpleString(R"(
299class C:
300 def __getattr__(self, key):
301 raise AttributeError("foo")
302obj = C()
303)");
304 PyObjectPtr obj(mainModuleGet("obj"));
305 PyObjectPtr name(PyUnicode_FromString("a"));
306 PyObject* result = name.get(); // some non-NULL value
307 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), 0);
308 EXPECT_EQ(PyErr_Occurred(), nullptr);
309 EXPECT_EQ(result, nullptr);
310}
311
312TEST_F(
313 ObjectExtensionApiTest,
314 LookupAttrWithDunderGetAttributeAndDunderGetAttrCallsDunderGetAttribute) {
315 PyRun_SimpleString(R"(
316class C:
317 def __getattr__(self, key):
318 return 5
319 def __getattribute__(self, key):
320 return 10
321obj = C()
322)");
323 PyObjectPtr obj(mainModuleGet("obj"));
324 PyObjectPtr name(PyUnicode_FromString("a"));
325 PyObject* result = nullptr;
326 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), 1);
327 EXPECT_EQ(PyErr_Occurred(), nullptr);
328 ASSERT_NE(result, nullptr);
329 EXPECT_EQ(PyLong_AsLong(result), 10);
330 Py_DECREF(result);
331}
332
333TEST_F(
334 ObjectExtensionApiTest,
335 LookupAttrWithRaisingDunderGetAttributeAndDunderGetAttrCallsDunderGetAttr) {
336 PyRun_SimpleString(R"(
337class C:
338 def __getattr__(self, key):
339 return 5
340 def __getattribute__(self, key):
341 raise AttributeError("foo")
342obj = C()
343)");
344 PyObjectPtr obj(mainModuleGet("obj"));
345 PyObjectPtr name(PyUnicode_FromString("a"));
346 PyObject* result = nullptr;
347 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), 1);
348 EXPECT_EQ(PyErr_Occurred(), nullptr);
349 ASSERT_NE(result, nullptr);
350 EXPECT_EQ(PyLong_AsLong(result), 5);
351 Py_DECREF(result);
352}
353
354TEST_F(ObjectExtensionApiTest,
355 LookupAttrWithRaisingDescrAttrReturnsNegativeOne) {
356 PyRun_SimpleString(R"(
357class Desc:
358 def __get__(self, instance, owner):
359 raise TypeError("foo")
360
361class C:
362 a = Desc()
363
364obj = C()
365)");
366 PyObjectPtr obj(mainModuleGet("obj"));
367 PyObjectPtr name(PyUnicode_FromString("a"));
368 PyObject* result = name.get(); // some non-NULL value
369 EXPECT_EQ(_PyObject_LookupAttr(obj, name, &result), -1);
370 ASSERT_NE(PyErr_Occurred(), nullptr);
371 EXPECT_EQ(result, nullptr);
372 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
373}
374
375TEST_F(ObjectExtensionApiTest, PySizeReturnsLvalue) {
376 PyType_Slot slots[] = {
377 {0, nullptr},
378 };
379 static PyType_Spec spec;
380 spec = {
381 "foo.Bar", sizeof(PyObject) + 10, 5, Py_TPFLAGS_DEFAULT, slots,
382 };
383 PyObjectPtr type(PyType_FromSpec(&spec));
384 ASSERT_NE(type, nullptr);
385 ASSERT_TRUE(PyType_CheckExact(type));
386
387 PyObjectPtr result(
388 PyType_GenericAlloc(reinterpret_cast<PyTypeObject*>(type.get()), 5));
389 EXPECT_EQ(Py_SIZE(result.get()), 5);
390
391 Py_SIZE(result.get()) = 4;
392 EXPECT_EQ(Py_SIZE(result.get()), 4);
393}
394
395TEST_F(ObjectExtensionApiTest, SetAttrWithInvalidTypeReturnsNegative) {
396 PyObjectPtr key(PyUnicode_FromString("a_key"));
397 PyObjectPtr value(PyLong_FromLong(5));
398 EXPECT_EQ(PyObject_SetAttr(Py_None, key, value), -1);
399}
400
401TEST_F(ObjectExtensionApiTest, SetAttrWithInvalidKeyReturnsNegative) {
402 static PyModuleDef def;
403 def = {
404 PyModuleDef_HEAD_INIT,
405 "test",
406 };
407 PyObjectPtr module(PyModule_Create(&def));
408 PyObjectPtr value(PyLong_FromLong(5));
409 EXPECT_EQ(PyObject_SetAttr(module, Py_None, value), -1);
410}
411
412TEST_F(ObjectExtensionApiTest, SetAttrReturnsZero) {
413 static PyModuleDef def;
414 def = {
415 PyModuleDef_HEAD_INIT,
416 "test",
417 };
418 PyObjectPtr module(PyModule_Create(&def));
419 PyObjectPtr key(PyUnicode_FromString("a_key"));
420 PyObjectPtr value(PyLong_FromLong(5));
421 EXPECT_EQ(PyObject_SetAttr(module, key, value), 0);
422}
423
424TEST_F(ObjectExtensionApiTest, SetAttrStringWithNullRemovesAttribute) {
425 PyRun_SimpleString(R"(
426class C:
427 pass
428obj = C()
429obj.a = 42
430obj.b = 13
431)");
432 PyObjectPtr obj(mainModuleGet("obj"));
433 ASSERT_TRUE(PyObject_HasAttrString(obj, "a"));
434 ASSERT_TRUE(PyObject_HasAttrString(obj, "b"));
435 EXPECT_EQ(PyObject_SetAttrString(obj, "a", nullptr), 0);
436 EXPECT_FALSE(PyObject_HasAttrString(obj, "a"));
437 EXPECT_TRUE(PyObject_HasAttrString(obj, "b"));
438}
439
440TEST_F(ObjectExtensionApiTest, SetAttrWithNullRemovesAttribute) {
441 PyRun_SimpleString(R"(
442class C:
443 pass
444obj = C()
445obj.a = 42
446obj.b = 13
447)");
448 PyObjectPtr obj(mainModuleGet("obj"));
449 ASSERT_TRUE(PyObject_HasAttrString(obj, "a"));
450 ASSERT_TRUE(PyObject_HasAttrString(obj, "b"));
451 PyObjectPtr name(PyUnicode_FromString("a"));
452 EXPECT_EQ(PyObject_SetAttr(obj, name, nullptr), 0);
453 EXPECT_FALSE(PyObject_HasAttrString(obj, "a"));
454 EXPECT_TRUE(PyObject_HasAttrString(obj, "b"));
455}
456
457TEST_F(ObjectExtensionApiTest, GetAttrWithNoneExistingKeyReturnsNull) {
458 static PyModuleDef def;
459 def = {
460 PyModuleDef_HEAD_INIT,
461 "test",
462 };
463 PyObjectPtr module(PyModule_Create(&def));
464
465 PyObjectPtr key(PyUnicode_FromString("a_key"));
466 EXPECT_EQ(PyObject_GetAttr(module, key), nullptr);
467}
468
469TEST_F(ObjectExtensionApiTest, GetAttrWithInvalidTypeReturnsNull) {
470 static PyModuleDef def;
471 def = {
472 PyModuleDef_HEAD_INIT,
473 "test",
474 };
475 int expected_int = 5;
476 PyObjectPtr module(PyModule_Create(&def));
477 PyObjectPtr key(PyUnicode_FromString("a_key"));
478 PyObjectPtr value(PyLong_FromLong(expected_int));
479 ASSERT_EQ(PyObject_SetAttr(module, key, value), 0);
480
481 EXPECT_EQ(PyObject_GetAttr(Py_None, key), nullptr);
482}
483
484TEST_F(ObjectExtensionApiTest, GetAttrWithInvalidKeyReturnsNull) {
485 static PyModuleDef def;
486 def = {
487 PyModuleDef_HEAD_INIT,
488 "test",
489 };
490 int expected_int = 5;
491 PyObjectPtr module(PyModule_Create(&def));
492 PyObjectPtr key(PyUnicode_FromString("a_key"));
493 PyObjectPtr value(PyLong_FromLong(expected_int));
494 ASSERT_EQ(PyObject_SetAttr(module, key, value), 0);
495
496 EXPECT_EQ(PyObject_GetAttr(module, Py_None), nullptr);
497}
498
499TEST_F(ObjectExtensionApiTest, GetAttrReturnsCorrectValue) {
500 static PyModuleDef def;
501 def = {
502 PyModuleDef_HEAD_INIT,
503 "test",
504 };
505 int expected_int = 5;
506 PyObjectPtr module(PyModule_Create(&def));
507 PyObjectPtr key(PyUnicode_FromString("a_key"));
508 PyObjectPtr value(PyLong_FromLong(expected_int));
509 ASSERT_EQ(PyObject_SetAttr(module, key, value), 0);
510
511 PyObjectPtr dict_result(PyObject_GetAttr(module, key));
512 ASSERT_NE(dict_result, nullptr);
513 EXPECT_EQ(PyLong_AsLong(dict_result), expected_int);
514}
515
516TEST_F(ObjectExtensionApiTest, GetAttrStringReturnsCorrectValue) {
517 static PyModuleDef def;
518 def = {
519 PyModuleDef_HEAD_INIT,
520 "test",
521 };
522 const char* key = "a_key";
523 int expected_int = 5;
524 PyObjectPtr module(PyModule_Create(&def));
525 PyObjectPtr value(PyLong_FromLong(expected_int));
526 ASSERT_EQ(PyObject_SetAttrString(module, key, value), 0);
527
528 PyObjectPtr dict_result(PyObject_GetAttrString(module, key));
529 ASSERT_NE(dict_result, nullptr);
530 EXPECT_EQ(PyLong_AsLong(dict_result), expected_int);
531}
532
533TEST_F(ObjectExtensionApiTest, HasAttrWithImmediateWithAttributeReturnsTrue) {
534 PyObjectPtr num(PyLong_FromLong(6));
535 PyObjectPtr name(PyUnicode_FromString("__int__"));
536 EXPECT_TRUE(PyObject_HasAttr(num, name));
537}
538
539TEST_F(ObjectExtensionApiTest,
540 HasAttrStringWithImmediateWithoutAttributeReturnsFalse) {
541 PyObjectPtr str(PyUnicode_FromString(""));
542 EXPECT_FALSE(PyObject_HasAttrString(str, "foo"));
543}
544
545TEST_F(ObjectExtensionApiTest, HasAttrWithNonStringAttrReturnsFalse) {
546 PyObjectPtr set(PySet_New(nullptr));
547 PyObjectPtr num(PyLong_FromLong(1));
548 EXPECT_FALSE(PyObject_HasAttr(set, num));
549 ASSERT_EQ(PyErr_Occurred(), nullptr);
550}
551
552TEST_F(ObjectExtensionApiTest, HasAttrWithoutAttrReturnsFalse) {
553 static PyModuleDef def;
554 def = {
555 PyModuleDef_HEAD_INIT,
556 "test",
557 };
558 PyObjectPtr module(PyModule_Create(&def));
559 PyObjectPtr name(PyUnicode_FromString("foo"));
560 EXPECT_FALSE(PyObject_HasAttr(module, name));
561}
562
563TEST_F(ObjectExtensionApiTest, HasAttrStringWithoutAttrReturnsFalse) {
564 static PyModuleDef def;
565 def = {
566 PyModuleDef_HEAD_INIT,
567 "test",
568 };
569 PyObjectPtr module(PyModule_Create(&def));
570 EXPECT_FALSE(PyObject_HasAttrString(module, "foo"));
571}
572
573TEST_F(ObjectExtensionApiTest, HasAttrWithAttrReturnsTrue) {
574 static PyModuleDef def;
575 def = {
576 PyModuleDef_HEAD_INIT,
577 "test",
578 };
579 PyObjectPtr module(PyModule_Create(&def));
580 PyObjectPtr name(PyUnicode_FromString("foo"));
581 PyObjectPtr val(PyLong_FromLong(2));
582 ASSERT_EQ(PyObject_SetAttr(module, name, val), 0);
583 EXPECT_TRUE(PyObject_HasAttr(module, name));
584}
585
586TEST_F(ObjectExtensionApiTest, HasAttrStringWithAttrReturnsTrue) {
587 static PyModuleDef def;
588 def = {
589 PyModuleDef_HEAD_INIT,
590 "test",
591 };
592 PyObjectPtr module(PyModule_Create(&def));
593 PyObjectPtr name(PyUnicode_FromString("foo"));
594 PyObjectPtr val(PyLong_FromLong(2));
595 ASSERT_EQ(PyObject_SetAttr(module, name, val), 0);
596 EXPECT_TRUE(PyObject_HasAttrString(module, "foo"));
597}
598
599TEST_F(ObjectExtensionApiTest, PrintWithNullObjPrintsNil) {
600 CaptureStdStreams streams;
601 int result = PyObject_Print(nullptr, stdout, 0);
602 EXPECT_EQ(result, 0);
603 EXPECT_EQ(streams.out(), "<nil>");
604}
605
606TEST_F(ObjectExtensionApiTest, PrintWithZeroFlagsCallsDunderRepr) {
607 ASSERT_EQ(PyRun_SimpleString(R"(
608class C:
609 def __repr__(self):
610 return "foo"
611 def __str__(self):
612 return "bar"
613obj = C()
614 )"),
615 0);
616 CaptureStdStreams streams;
617 PyObjectPtr obj(mainModuleGet("obj"));
618 int result = PyObject_Print(obj, stdout, 0);
619 EXPECT_EQ(result, 0);
620 EXPECT_EQ(streams.out(), "foo");
621}
622
623TEST_F(ObjectExtensionApiTest, PrintWithRawFlagsCallsDunderStr) {
624 ASSERT_EQ(PyRun_SimpleString(R"(
625class C:
626 def __repr__(self):
627 return "foo"
628 def __str__(self):
629 return "bar"
630obj = C()
631 )"),
632 0);
633 CaptureStdStreams streams;
634 PyObjectPtr obj(mainModuleGet("obj"));
635 int result = PyObject_Print(obj, stdout, Py_PRINT_RAW);
636 EXPECT_EQ(result, 0);
637 EXPECT_EQ(streams.out(), "bar");
638}
639
640TEST_F(ObjectExtensionApiTest, PrintReplacesBackslashes) {
641 ASSERT_EQ(PyRun_SimpleString(R"(
642class C:
643 def __repr__(self):
644 return r"foo\bar"
645obj = C()
646 )"),
647 0);
648 CaptureStdStreams streams;
649 PyObjectPtr obj(mainModuleGet("obj"));
650 int result = PyObject_Print(obj, stdout, 0);
651 EXPECT_EQ(result, 0);
652 EXPECT_EQ(streams.out(), "foo\\bar");
653}
654
655TEST_F(ObjectExtensionApiTest, RefCountDecreaseDeallocsHandle) {
656 long value = 10;
657 PyObject* o = PyLong_FromLong(value);
658 Py_DECREF(o);
659}
660
661TEST_F(ObjectExtensionApiTest, IncrementDecrementRefCount) {
662 PyObject* o = PyTuple_New(1);
663 long refcnt = Py_REFCNT(o);
664 EXPECT_GE(Py_REFCNT(o), 1);
665 Py_INCREF(o);
666 EXPECT_EQ(Py_REFCNT(o), refcnt + 1);
667 Py_DECREF(o);
668 EXPECT_EQ(Py_REFCNT(o), refcnt);
669 Py_DECREF(o);
670}
671
672TEST_F(ObjectExtensionApiTest, IncrementDecrementRefCountWithPyObjectPtr) {
673 PyObject* o = PyTuple_New(1);
674 long refcnt = Py_REFCNT(o);
675 {
676 Py_INCREF(o);
677 EXPECT_EQ(Py_REFCNT(o), refcnt + 1);
678 testing::PyObjectPtr h(o);
679 static_cast<void>(h);
680 }
681 EXPECT_EQ(Py_REFCNT(o), refcnt);
682 {
683 Py_INCREF(o);
684 EXPECT_EQ(Py_REFCNT(o), refcnt + 1);
685 testing::PyObjectPtr h(o);
686 h = nullptr;
687 static_cast<void>(h);
688 EXPECT_EQ(Py_REFCNT(o), refcnt);
689 }
690 Py_DECREF(o);
691}
692
693TEST_F(ObjectExtensionApiTest, CallFinalizerFromDeallocWithNonZeroRefcntDies) {
694 PyObject* obj = Py_None;
695 Py_INCREF(obj); // definitely has a non-zero refcount
696 EXPECT_DEATH(PyObject_CallFinalizerFromDealloc(obj),
697 "PyObject_CallFinalizerFromDealloc called on object with a "
698 "non-zero refcount");
699}
700
701TEST_F(ObjectExtensionApiTest,
702 CallFinalizerFromDeallocWithoutTpFinalizeFlagCallsTpFinalize) {
703 static bool dealloc_called;
704 static bool finalizer_called;
705 dealloc_called = false;
706 finalizer_called = false;
707 destructor dealloc_func = [](PyObject* self) {
708 dealloc_called = true;
709 if (PyObject_CallFinalizerFromDealloc(self) < 0) return;
710 PyTypeObject* type = Py_TYPE(self);
711 PyObject_Del(self);
712 Py_DECREF(type);
713 };
714 destructor finalizer_func = [](PyObject*) { finalizer_called = true; };
715 PyType_Slot slots[] = {
716 {Py_tp_dealloc, reinterpret_cast<void*>(dealloc_func)},
717 {Py_tp_finalize, reinterpret_cast<void*>(finalizer_func)},
718 {0, nullptr},
719 };
720 static PyType_Spec spec;
721 spec = {
722 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots,
723 };
724 PyObjectPtr type(PyType_FromSpec(&spec));
725 ASSERT_NE(type, nullptr);
726 allocfunc func = reinterpret_cast<allocfunc>(
727 PyType_GetSlot(type.asTypeObject(), Py_tp_alloc));
728 ASSERT_NE(func, nullptr);
729 PyObject* obj = (*func)(type.asTypeObject(), 0);
730 ASSERT_NE(obj, nullptr);
731 EXPECT_GE(Py_REFCNT(obj), 1);
732 Py_DECREF(obj); // Drop the reference to it
733 // Trigger a GC. PyObject_CallFinalizerFromDealloc is called during GC in
734 // Pyro and immmediately in the decref in CPython.
735 collectGarbage();
736 EXPECT_TRUE(dealloc_called);
737 EXPECT_TRUE(finalizer_called);
738}
739
740TEST_F(ObjectExtensionApiTest,
741 CallFinalizerFromDeallocWithTpFinalizeFlagCallsTpFinalize) {
742 static bool dealloc_called;
743 static bool finalizer_called;
744 dealloc_called = false;
745 finalizer_called = false;
746 destructor dealloc_func = [](PyObject* self) {
747 dealloc_called = true;
748 if (PyObject_CallFinalizerFromDealloc(self) < 0) return;
749 PyTypeObject* type = Py_TYPE(self);
750 PyObject_Del(self);
751 Py_DECREF(type);
752 };
753 destructor finalizer_func = [](PyObject*) { finalizer_called = true; };
754 PyType_Slot slots[] = {
755 {Py_tp_dealloc, reinterpret_cast<void*>(dealloc_func)},
756 {Py_tp_finalize, reinterpret_cast<void*>(finalizer_func)},
757 {0, nullptr},
758 };
759 static PyType_Spec spec;
760 spec = {
761 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE, slots,
762 };
763 PyObjectPtr type(PyType_FromSpec(&spec));
764 ASSERT_NE(type, nullptr);
765 allocfunc func = reinterpret_cast<allocfunc>(
766 PyType_GetSlot(type.asTypeObject(), Py_tp_alloc));
767 ASSERT_NE(func, nullptr);
768 PyObject* obj = (*func)(type.asTypeObject(), 0);
769 ASSERT_NE(obj, nullptr);
770 EXPECT_GE(Py_REFCNT(obj), 1);
771 Py_DECREF(obj); // Drop the reference to it
772 // Trigger a GC. PyObject_CallFinalizerFromDealloc is called during GC in
773 // Pyro and immmediately in the decref in CPython.
774 collectGarbage();
775 EXPECT_TRUE(dealloc_called);
776 EXPECT_TRUE(finalizer_called);
777}
778
779TEST_F(
780 ObjectExtensionApiTest,
781 CallFinalizerFromDeallocWithTpFinalizeResurrectingObjectDoesNotGCObject) {
782 static bool dealloc_called;
783 static bool finalizer_called;
784 dealloc_called = false;
785 finalizer_called = false;
786 destructor dealloc_func = [](PyObject* self) {
787 dealloc_called = true;
788 if (PyObject_CallFinalizerFromDealloc(self) < 0) return;
789 PyTypeObject* type = Py_TYPE(self);
790 PyObject_Del(self);
791 Py_DECREF(type);
792 };
793 destructor finalizer_func = [](PyObject* self) {
794 finalizer_called = true;
795 Py_INCREF(self);
796 };
797 PyType_Slot slots[] = {
798 {Py_tp_dealloc, reinterpret_cast<void*>(dealloc_func)},
799 {Py_tp_finalize, reinterpret_cast<void*>(finalizer_func)},
800 {0, nullptr},
801 };
802 static PyType_Spec spec;
803 spec = {
804 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE, slots,
805 };
806 PyObjectPtr type(PyType_FromSpec(&spec));
807 ASSERT_NE(type, nullptr);
808 allocfunc func = reinterpret_cast<allocfunc>(
809 PyType_GetSlot(type.asTypeObject(), Py_tp_alloc));
810 ASSERT_NE(func, nullptr);
811 PyObject* obj = (*func)(type.asTypeObject(), 0);
812 ASSERT_NE(obj, nullptr);
813 EXPECT_GE(Py_REFCNT(obj), 1);
814 Py_DECREF(obj); // Drop the reference to it
815 // Trigger a GC. PyObject_CallFinalizerFromDealloc is called during GC in
816 // Pyro and immmediately in the decref in CPython.
817 collectGarbage();
818 EXPECT_TRUE(dealloc_called);
819 EXPECT_TRUE(finalizer_called);
820 EXPECT_GE(Py_REFCNT(obj), 1);
821}
822
823TEST_F(ObjectExtensionApiTest, PyDeallocCallsDeallocTypeSlot) {
824 static bool dealloc_called;
825 dealloc_called = false;
826 destructor dealloc_func = [](PyObject* self) {
827 dealloc_called = true;
828 PyTypeObject* type = Py_TYPE(self);
829 PyObject_Del(self);
830 Py_DECREF(type);
831 };
832 PyType_Slot slots[] = {
833 {Py_tp_dealloc, reinterpret_cast<void*>(dealloc_func)},
834 {0, nullptr},
835 };
836 static PyType_Spec spec;
837 spec = {
838 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE, slots,
839 };
840 PyObjectPtr type(PyType_FromSpec(&spec));
841 ASSERT_NE(type, nullptr);
842 allocfunc func = reinterpret_cast<allocfunc>(
843 PyType_GetSlot(type.asTypeObject(), Py_tp_alloc));
844 ASSERT_NE(func, nullptr);
845 PyObject* obj = (*func)(type.asTypeObject(), 0);
846 ASSERT_NE(obj, nullptr);
847 EXPECT_GE(Py_REFCNT(obj), 1);
848 _Py_Dealloc(obj);
849 EXPECT_TRUE(dealloc_called);
850}
851
852TEST_F(ObjectExtensionApiTest, GenericGetAttrFindsCorrectlySetValue) {
853 ASSERT_EQ(PyRun_SimpleString(R"(
854class C: pass
855i = C()
856)"),
857 0);
858
859 PyObjectPtr i(mainModuleGet("i"));
860 ASSERT_NE(i, nullptr);
861 PyObjectPtr key(PyUnicode_FromString("key"));
862 PyObjectPtr value(PyUnicode_FromString("value"));
863 EXPECT_EQ(PyObject_GenericSetAttr(i, key, value), 0);
864 PyObjectPtr get_val(PyObject_GenericGetAttr(i, key));
865 EXPECT_TRUE(isUnicodeEqualsCStr(get_val, "value"));
866}
867
868TEST_F(ObjectExtensionApiTest, GenericSetAttrWithSealedTypeReturnsNegOne) {
869 ASSERT_EQ(PyRun_SimpleString(R"(
870i = 3
871)"),
872 0);
873
874 PyObjectPtr i(mainModuleGet("i"));
875 ASSERT_NE(i, nullptr);
876 PyObjectPtr key(PyUnicode_FromString("key"));
877 PyObjectPtr value(PyUnicode_FromString("value"));
878 EXPECT_EQ(PyObject_GenericSetAttr(i, key, value), -1);
879 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError));
880}
881
882TEST_F(ObjectExtensionApiTest, GetAttrIncrementsReferenceCount) {
883 static PyModuleDef def;
884 def = {
885 PyModuleDef_HEAD_INIT,
886 "test",
887 };
888 PyObjectPtr module(PyModule_Create(&def));
889 PyObjectPtr key(PyUnicode_FromString("test"));
890 PyObject* value = PyTuple_New(1);
891 ASSERT_EQ(PyObject_SetAttr(module, key, value), 0);
892
893 long refcnt = Py_REFCNT(value);
894 PyObject* result = PyObject_GetAttr(module, key);
895 EXPECT_EQ(Py_REFCNT(result), refcnt + 1);
896 Py_DECREF(result);
897 result = PyObject_GetAttr(module, key);
898 EXPECT_EQ(result, value);
899 EXPECT_EQ(Py_REFCNT(result), refcnt + 1);
900 Py_DECREF(result);
901 Py_DECREF(result);
902}
903
904TEST_F(ObjectExtensionApiTest, ReprOnNullReturnsSpecialNullString) {
905 PyObjectPtr repr(PyObject_Repr(nullptr));
906 ASSERT_EQ(PyErr_Occurred(), nullptr);
907 EXPECT_TRUE(isUnicodeEqualsCStr(repr, "<NULL>"));
908}
909
910TEST_F(ObjectExtensionApiTest, ReprWithObjectWithBadDunderReprRaisesTypeError) {
911 PyRun_SimpleString(R"(
912class C:
913 __repr__ = None
914c = C()
915)");
916 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
917 EXPECT_EQ(PyObject_Repr(pyc), nullptr);
918 ASSERT_NE(PyErr_Occurred(), nullptr);
919 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
920}
921
922TEST_F(ObjectExtensionApiTest, ReprIsCorrectForObjectWithDunderRepr) {
923 PyRun_SimpleString(R"(
924class C:
925 def __repr__(self):
926 return "bongo"
927c = C()
928)");
929 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
930 PyObjectPtr repr(PyObject_Repr(pyc));
931 ASSERT_EQ(PyErr_Occurred(), nullptr);
932 EXPECT_TRUE(isUnicodeEqualsCStr(repr, "bongo"));
933}
934
935TEST_F(ObjectExtensionApiTest,
936 ReprWithRecursiveObjectDoesNotInfinitelyRecurse) {
937 PyRun_SimpleString(R"(
938a = []
939a.append(a)
940)");
941 PyObjectPtr a(PyObject_GetAttrString(PyImport_AddModule("__main__"), "a"));
942 PyObjectPtr repr(PyObject_Repr(a));
943 ASSERT_EQ(PyErr_Occurred(), nullptr);
944 EXPECT_TRUE(isUnicodeEqualsCStr(repr, "[[...]]"));
945}
946
947TEST_F(ObjectExtensionApiTest, StrOnNullReturnsSpecialNullString) {
948 PyObjectPtr str(PyObject_Str(nullptr));
949 ASSERT_EQ(PyErr_Occurred(), nullptr);
950 ASSERT_TRUE(isUnicodeEqualsCStr(str, "<NULL>"));
951}
952
953TEST_F(ObjectExtensionApiTest, StrCallsClassDunderReprWhenProvided) {
954 PyRun_SimpleString(R"(
955class C:
956 def __repr__(self):
957 return "bongo"
958c = C()
959)");
960 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
961 PyObjectPtr str(PyObject_Str(pyc));
962 ASSERT_EQ(PyErr_Occurred(), nullptr);
963 EXPECT_TRUE(isUnicodeEqualsCStr(str, "bongo"));
964}
965
966TEST_F(ObjectExtensionApiTest, StrWithObjectWithBadDunderStrRaisesTypeError) {
967 PyRun_SimpleString(R"(
968class C:
969 __str__ = None
970c = C()
971)");
972 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
973 EXPECT_EQ(PyObject_Str(pyc), nullptr);
974 ASSERT_NE(PyErr_Occurred(), nullptr);
975 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
976}
977
978TEST_F(ObjectExtensionApiTest, StrCallsClassDunderStrWhenProvided) {
979 PyRun_SimpleString(R"(
980class C:
981 def __str__(self):
982 return "bongo"
983c = C()
984)");
985 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
986 PyObjectPtr str(PyObject_Str(pyc));
987 ASSERT_EQ(PyErr_Occurred(), nullptr);
988 EXPECT_TRUE(isUnicodeEqualsCStr(str, "bongo"));
989}
990
991TEST_F(ObjectExtensionApiTest, RichCompareWithNullLhsRaisesSystemError) {
992 ASSERT_EQ(PyObject_RichCompare(nullptr, Py_None, 0), nullptr);
993 ASSERT_NE(PyErr_Occurred(), nullptr);
994 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
995}
996
997TEST_F(ObjectExtensionApiTest, RichCompareWithNullRhsRaisesSystemError) {
998 ASSERT_EQ(PyObject_RichCompare(Py_None, nullptr, 0), nullptr);
999 ASSERT_NE(PyErr_Occurred(), nullptr);
1000 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError));
1001}
1002
1003TEST_F(ObjectExtensionApiTest, RichCompareWithSameType) {
1004 PyObjectPtr left(PyLong_FromLong(2));
1005 PyObjectPtr right(PyLong_FromLong(3));
1006 PyObjectPtr result(PyObject_RichCompare(left, right, Py_LT));
1007 ASSERT_EQ(PyErr_Occurred(), nullptr);
1008 ASSERT_EQ(result, Py_True);
1009}
1010
1011TEST_F(ObjectExtensionApiTest, RichCompareNotComparableRaisesTypeError) {
1012 PyObjectPtr left(PyLong_FromLong(2));
1013 PyObjectPtr right(PyUnicode_FromString("hello"));
1014 EXPECT_EQ(PyObject_RichCompare(left, right, Py_LT), nullptr);
1015 ASSERT_NE(PyErr_Occurred(), nullptr);
1016 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1017}
1018
1019TEST_F(ObjectExtensionApiTest, IsTrueReturnsTrueOnTrue) {
1020 EXPECT_EQ(PyObject_IsTrue(Py_True), 1);
1021 EXPECT_EQ(PyErr_Occurred(), nullptr);
1022}
1023
1024TEST_F(ObjectExtensionApiTest, IsTrueReturnsFalseOnFalse) {
1025 EXPECT_EQ(PyObject_IsTrue(Py_False), 0);
1026 EXPECT_EQ(PyErr_Occurred(), nullptr);
1027}
1028
1029TEST_F(ObjectExtensionApiTest, IsTrueReturnsFalseOnNone) {
1030 EXPECT_EQ(PyObject_IsTrue(Py_None), 0);
1031 EXPECT_EQ(PyErr_Occurred(), nullptr);
1032}
1033
1034TEST_F(ObjectExtensionApiTest,
1035 IsTrueWithObjectWithNonCallableDunderBoolRaisesTypeError) {
1036 PyRun_SimpleString(R"(
1037class C:
1038 __bool__ = 4
1039c = C()
1040)");
1041 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
1042 ASSERT_EQ(PyObject_IsTrue(pyc), -1);
1043 ASSERT_NE(PyErr_Occurred(), nullptr);
1044 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1045}
1046
1047TEST_F(ObjectExtensionApiTest,
1048 IsTrueWithObjectWithNonCallableDunderLenRaisesTypeError) {
1049 PyRun_SimpleString(R"(
1050class C:
1051 __len__ = 4
1052c = C()
1053)");
1054 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
1055 ASSERT_EQ(PyObject_IsTrue(pyc), -1);
1056 ASSERT_NE(PyErr_Occurred(), nullptr);
1057 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1058}
1059
1060TEST_F(ObjectExtensionApiTest,
1061 IsTrueWithObjectWithDunderBoolThatReturnsNonIntRaisesTypeError) {
1062 PyRun_SimpleString(R"(
1063class C:
1064 def __bool__(self):
1065 return "bongo"
1066c = C()
1067)");
1068 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
1069 ASSERT_EQ(PyObject_IsTrue(pyc), -1);
1070 ASSERT_NE(PyErr_Occurred(), nullptr);
1071 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1072}
1073
1074TEST_F(ObjectExtensionApiTest,
1075 IsTrueWithDunderLenThatReturnsNonIntRaisesTypeError) {
1076 PyRun_SimpleString(R"(
1077class C:
1078 def __len__(self):
1079 return "bongo"
1080c = C()
1081)");
1082 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
1083 ASSERT_EQ(PyObject_IsTrue(pyc), -1);
1084 ASSERT_NE(PyErr_Occurred(), nullptr);
1085 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1086}
1087
1088TEST_F(ObjectExtensionApiTest, IsTrueWithEmptyListReturnsFalse) {
1089 PyObjectPtr empty_list(PyList_New(0));
1090 ASSERT_EQ(PyObject_IsTrue(empty_list), 0);
1091 EXPECT_EQ(PyErr_Occurred(), nullptr);
1092}
1093
1094TEST_F(ObjectExtensionApiTest, IsTrueWithNonEmptyListReturnsTrue) {
1095 PyObjectPtr list(PyList_New(0));
1096 PyList_Append(list, Py_None);
1097
1098 ASSERT_EQ(PyObject_IsTrue(list), 1);
1099 EXPECT_EQ(PyErr_Occurred(), nullptr);
1100}
1101
1102TEST_F(ObjectExtensionApiTest,
1103 IsTrueWithObjectWithDunderLenReturningNegativeOneRaisesValueError) {
1104 PyRun_SimpleString(R"(
1105class C:
1106 def __len__(self):
1107 return -1
1108c = C()
1109)");
1110 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
1111 ASSERT_EQ(PyObject_IsTrue(pyc), -1);
1112 ASSERT_NE(PyErr_Occurred(), nullptr);
1113 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError));
1114}
1115
1116TEST_F(ObjectExtensionApiTest, ClearWithNullDoesNotRaise) {
1117 PyObject* null = nullptr;
1118 Py_CLEAR(null);
1119 ASSERT_EQ(PyErr_Occurred(), nullptr);
1120 EXPECT_EQ(null, nullptr);
1121}
1122
1123TEST_F(ObjectExtensionApiTest, ClearWithObjectSetsNull) {
1124 PyObject* num = PyLong_FromLong(1);
1125 Py_CLEAR(num);
1126 ASSERT_EQ(PyErr_Occurred(), nullptr);
1127 EXPECT_EQ(num, nullptr);
1128}
1129
1130TEST_F(ObjectExtensionApiTest, ClearWithObjectDecrefsObject) {
1131 PyObject* original = PyTuple_New(1);
1132 PyObject* num = original;
1133 Py_ssize_t original_count = Py_REFCNT(original);
1134 Py_CLEAR(num);
1135 ASSERT_EQ(PyErr_Occurred(), nullptr);
1136 EXPECT_EQ(num, nullptr);
1137 EXPECT_LT(Py_REFCNT(original), original_count);
1138}
1139
1140TEST_F(ObjectExtensionApiTest, ASCIIOnNullReturnsSpecialNullString) {
1141 PyObjectPtr ascii(PyObject_ASCII(nullptr));
1142 ASSERT_EQ(PyErr_Occurred(), nullptr);
1143 EXPECT_TRUE(isUnicodeEqualsCStr(ascii, "<NULL>"));
1144}
1145
1146TEST_F(ObjectExtensionApiTest,
1147 ASCIIWithObjectWithBadDunderReprRaisesTypeError) {
1148 PyRun_SimpleString(R"(
1149class C:
1150 __repr__ = None
1151c = C()
1152)");
1153 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
1154 EXPECT_EQ(PyObject_ASCII(pyc), nullptr);
1155 ASSERT_NE(PyErr_Occurred(), nullptr);
1156 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1157}
1158
1159TEST_F(ObjectExtensionApiTest, ASCIIcallsDunderRepr) {
1160 PyRun_SimpleString(R"(
1161class C:
1162 def __repr__(self):
1163 return "bongo"
1164c = C()
1165)");
1166 PyObjectPtr pyc(PyObject_GetAttrString(PyImport_AddModule("__main__"), "c"));
1167 PyObjectPtr ascii(PyObject_ASCII(pyc));
1168 ASSERT_EQ(PyErr_Occurred(), nullptr);
1169 EXPECT_TRUE(isUnicodeEqualsCStr(ascii, "bongo"));
1170}
1171
1172TEST_F(ObjectExtensionApiTest, SelfIterIncrementsRefcount) {
1173 PyObject* o = PyTuple_New(1);
1174 long refcnt = Py_REFCNT(o);
1175 EXPECT_GE(Py_REFCNT(o), 1);
1176 PyObject* o2 = PyObject_SelfIter(o);
1177 EXPECT_EQ(PyErr_Occurred(), nullptr);
1178 EXPECT_EQ(Py_REFCNT(o2), refcnt + 1);
1179 Py_DECREF(o);
1180 Py_DECREF(o);
1181}
1182
1183TEST_F(ObjectExtensionApiTest, NotWithTrueReturnsFalse) {
1184 EXPECT_EQ(PyObject_Not(Py_True), 0);
1185 EXPECT_EQ(PyErr_Occurred(), nullptr);
1186}
1187
1188TEST_F(ObjectExtensionApiTest, NotWithFalseReturnsTrue) {
1189 EXPECT_EQ(PyObject_Not(Py_False), 1);
1190 EXPECT_EQ(PyErr_Occurred(), nullptr);
1191}
1192
1193TEST_F(ObjectExtensionApiTest, NotWithNoneReturnsTrue) {
1194 EXPECT_EQ(PyObject_Not(Py_None), 1);
1195 EXPECT_EQ(PyErr_Occurred(), nullptr);
1196}
1197
1198TEST_F(ObjectExtensionApiTest, NotCallsDunderBool) {
1199 PyRun_SimpleString(R"(
1200sideeffect = 0
1201class C:
1202 def __bool__(self):
1203 global sideeffect
1204 sideeffect = 10
1205 return False
1206c = C()
1207)");
1208 PyObjectPtr c(mainModuleGet("c"));
1209 EXPECT_EQ(PyObject_Not(c), 1);
1210 EXPECT_EQ(PyErr_Occurred(), nullptr);
1211 PyObjectPtr sideeffect(mainModuleGet("sideeffect"));
1212 EXPECT_EQ(PyLong_AsLong(sideeffect), 10);
1213}
1214
1215TEST_F(ObjectExtensionApiTest,
1216 NotWithDunderBoolRaisingExceptionRaisesTypeError) {
1217 PyRun_SimpleString(R"(
1218class C:
1219 def __bool__(self):
1220 return -10
1221c = C()
1222)");
1223 PyObjectPtr c(mainModuleGet("c"));
1224 EXPECT_EQ(PyObject_Not(c), -1);
1225 EXPECT_NE(PyErr_Occurred(), nullptr);
1226 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1227}
1228
1229TEST_F(ObjectExtensionApiTest, HashWithUncallableDunderHashRaisesTypeError) {
1230 PyRun_SimpleString(R"(
1231class C:
1232 __hash__ = None
1233c = C()
1234)");
1235 PyObjectPtr c(mainModuleGet("c"));
1236 EXPECT_EQ(PyObject_Hash(c), -1);
1237 EXPECT_NE(PyErr_Occurred(), nullptr);
1238 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1239}
1240
1241TEST_F(ObjectExtensionApiTest, HashCallsDunderHash) {
1242 PyRun_SimpleString(R"(
1243class C:
1244 def __hash__(self):
1245 return 7
1246c = C()
1247)");
1248 PyObjectPtr c(mainModuleGet("c"));
1249 EXPECT_EQ(PyObject_Hash(c), 7);
1250 EXPECT_EQ(PyErr_Occurred(), nullptr);
1251}
1252
1253TEST_F(ObjectExtensionApiTest, HashPropagatesRaisedException) {
1254 PyRun_SimpleString(R"(
1255class C:
1256 def __hash__(self):
1257 raise IndexError
1258c = C()
1259)");
1260 PyObjectPtr c(mainModuleGet("c"));
1261 EXPECT_EQ(PyObject_Hash(c), -1);
1262 EXPECT_NE(PyErr_Occurred(), nullptr);
1263 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_IndexError));
1264}
1265
1266TEST_F(ObjectExtensionApiTest, HashNotImplementedRaisesTypeError) {
1267 EXPECT_EQ(PyObject_HashNotImplemented(Py_None), -1);
1268 EXPECT_NE(PyErr_Occurred(), nullptr);
1269 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1270}
1271
1272TEST_F(ObjectExtensionApiTest,
1273 RichCompareBoolEqWithLeftEqualsRightReturnsTrue) {
1274 EXPECT_EQ(PyObject_RichCompareBool(Py_None, Py_None, Py_EQ), 1);
1275 EXPECT_EQ(PyErr_Occurred(), nullptr);
1276}
1277
1278TEST_F(ObjectExtensionApiTest,
1279 RichCompareBoolNeWithLeftEqualsRightReturnsFalse) {
1280 EXPECT_EQ(PyObject_RichCompareBool(Py_None, Py_None, Py_NE), 0);
1281 EXPECT_EQ(PyErr_Occurred(), nullptr);
1282}
1283
1284TEST_F(ObjectExtensionApiTest, RichCompareBoolWithSameTypeReturnsTrue) {
1285 PyObjectPtr left(PyLong_FromLong(2));
1286 PyObjectPtr right(PyLong_FromLong(3));
1287 EXPECT_EQ(PyObject_RichCompareBool(left, right, Py_LT), 1);
1288 ASSERT_EQ(PyErr_Occurred(), nullptr);
1289}
1290
1291TEST_F(ObjectExtensionApiTest, RichCompareBoolNotComparableRaisesTypeError) {
1292 PyObjectPtr left(PyLong_FromLong(2));
1293 PyObjectPtr right(PyUnicode_FromString("hello"));
1294 EXPECT_EQ(PyObject_RichCompareBool(left, right, Py_LT), -1);
1295 ASSERT_NE(PyErr_Occurred(), nullptr);
1296 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1297}
1298
1299TEST_F(ObjectExtensionApiTest, ReprEnterOnceReturnsZero) {
1300 PyObjectPtr obj(PyLong_FromLong(7));
1301 EXPECT_EQ(Py_ReprEnter(obj), 0);
1302 EXPECT_EQ(PyErr_Occurred(), nullptr);
1303}
1304
1305TEST_F(ObjectExtensionApiTest, ReprEnterSecondTimeReturnsOne) {
1306 PyObjectPtr obj(PyLong_FromLong(7));
1307 ASSERT_EQ(Py_ReprEnter(obj), 0);
1308 ASSERT_EQ(PyErr_Occurred(), nullptr);
1309 EXPECT_EQ(Py_ReprEnter(obj), 1);
1310 EXPECT_EQ(PyErr_Occurred(), nullptr);
1311}
1312
1313TEST_F(ObjectExtensionApiTest, ReprEnterThenLeaveRemovesFromSet) {
1314 PyObjectPtr obj(PyLong_FromLong(7));
1315 ASSERT_EQ(Py_ReprEnter(obj), 0);
1316 ASSERT_EQ(PyErr_Occurred(), nullptr);
1317 ASSERT_EQ(Py_ReprEnter(obj), 1);
1318 ASSERT_EQ(PyErr_Occurred(), nullptr);
1319 Py_ReprLeave(obj);
1320 ASSERT_EQ(Py_ReprEnter(obj), 0);
1321 ASSERT_EQ(PyErr_Occurred(), nullptr);
1322}
1323
1324TEST_F(ObjectExtensionApiTest, InitWithNullRaisesNoMemoryError) {
1325 PyType_Slot slots[] = {
1326 {0, nullptr},
1327 };
1328 static PyType_Spec spec;
1329 spec = {
1330 "foo.Bar", 0, 0, Py_TPFLAGS_DEFAULT, slots,
1331 };
1332 PyObjectPtr type(PyType_FromSpec(&spec));
1333 ASSERT_NE(type, nullptr);
1334 ASSERT_TRUE(PyType_CheckExact(type));
1335 PyObject_Init(nullptr, reinterpret_cast<PyTypeObject*>(type.get()));
1336 ASSERT_NE(PyErr_Occurred(), nullptr);
1337 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_MemoryError));
1338}
1339
1340TEST_F(ObjectExtensionApiTest, NewReturnsAllocatedObject) {
1341 struct BarObject {
1342 PyObject_HEAD
1343 int value;
1344 };
1345 PyType_Slot slots[] = {
1346 {0, nullptr},
1347 };
1348 static PyType_Spec spec;
1349 spec = {
1350 "foo.Bar", sizeof(BarObject), 0, Py_TPFLAGS_DEFAULT, slots,
1351 };
1352 PyObjectPtr type(PyType_FromSpec(&spec));
1353 Py_ssize_t refcnt = Py_REFCNT(type.get());
1354 PyObjectPtr instance(reinterpret_cast<PyObject*>(
1355 PyObject_New(BarObject, type.asTypeObject())));
1356 ASSERT_NE(instance, nullptr);
1357 EXPECT_EQ(PyErr_Occurred(), nullptr);
1358 // TODO(T53456038): Switch back to EXPECT_EQ, once initial refcount is fixed
1359 EXPECT_GE(Py_REFCNT(instance), 1);
1360 EXPECT_EQ(Py_REFCNT(type), refcnt + 1);
1361}
1362
1363TEST_F(ObjectExtensionApiTest, NewVarReturnsAllocatedObject) {
1364 struct BarObject {
1365 PyObject_HEAD
1366 int value;
1367 };
1368 struct BarContainer {
1369 PyObject_VAR_HEAD
1370 BarObject* items[1];
1371 };
1372 PyType_Slot slots[] = {
1373 {0, nullptr},
1374 };
1375 static PyType_Spec spec;
1376 spec = {
1377 "foo.Bar", sizeof(BarContainer), sizeof(BarObject), Py_TPFLAGS_DEFAULT,
1378 slots,
1379 };
1380 PyObjectPtr type(PyType_FromSpec(&spec));
1381 PyObjectPtr instance(reinterpret_cast<PyObject*>(
1382 PyObject_NewVar(BarContainer, type.asTypeObject(), 5)));
1383 ASSERT_NE(instance, nullptr);
1384 EXPECT_EQ(PyErr_Occurred(), nullptr);
1385 // TODO(T53456038): Switch back to EXPECT_EQ, once initial refcount is fixed
1386 EXPECT_GE(Py_REFCNT(instance), 1);
1387 EXPECT_EQ(Py_SIZE(instance.get()), 5);
1388}
1389
1390TEST_F(ObjectExtensionApiTest, PyEllipsisIdentityIsEqual) {
1391 // Test Identitiy
1392 PyObject* ellipsis1 = Py_Ellipsis;
1393 PyObject* ellipsis2 = Py_Ellipsis;
1394 EXPECT_EQ(ellipsis1, ellipsis2);
1395}
1396
1397TEST_F(ObjectExtensionApiTest, DirWithoutExecutionFrameReturnsNull) {
1398 EXPECT_EQ(PyObject_Dir(nullptr), nullptr);
1399}
1400
1401TEST_F(ObjectExtensionApiTest, DirReturnsLocals) {
1402 PyRun_SimpleString(R"(
1403class C: pass
1404)");
1405 PyObjectPtr c_type(mainModuleGet("C"));
1406 binaryfunc meth = [](PyObject*, PyObject*) { return PyObject_Dir(nullptr); };
1407 static PyMethodDef foo_func = {"foo", meth, METH_NOARGS};
1408 PyObjectPtr func(PyCFunction_NewEx(&foo_func, c_type, nullptr));
1409 ASSERT_NE(func, nullptr);
1410 PyObject_SetAttrString(c_type, "foo", func);
1411
1412 PyRun_SimpleString(R"(
1413foo = 123
1414c = C()
1415obj = c.foo()
1416)");
1417 PyObjectPtr obj(mainModuleGet("obj"));
1418 ASSERT_EQ(PyList_Check(obj), 1);
1419 PyObjectPtr foo(PyUnicode_FromString("foo"));
1420 EXPECT_EQ(PySequence_Contains(obj, foo), 1);
1421}
1422
1423TEST_F(ObjectExtensionApiTest, DirOnInstanceReturnsListOfAttributes) {
1424 PyRun_SimpleString(R"(
1425class C:
1426 def __init__(self):
1427 self.foo = 123
1428obj = C()
1429)");
1430 PyObjectPtr obj(mainModuleGet("obj"));
1431 ASSERT_EQ(PyErr_Occurred(), nullptr);
1432 PyObjectPtr result(PyObject_Dir(obj));
1433 ASSERT_EQ(PyList_Check(result), 1);
1434 PyObjectPtr foo(PyUnicode_FromString("foo"));
1435 EXPECT_EQ(PySequence_Contains(result, foo), 1);
1436}
1437
1438TEST_F(ObjectExtensionApiTest, DirOnInstanceWithDunderDirRaisingReturnsNull) {
1439 PyRun_SimpleString(R"(
1440class C:
1441 def __init__(self):
1442 self.foo = 123
1443 def __dir__(self):
1444 raise TypeError("no dir on this type")
1445obj = C()
1446)");
1447 PyObjectPtr obj(mainModuleGet("obj"));
1448 ASSERT_EQ(PyErr_Occurred(), nullptr);
1449 PyObjectPtr result(PyObject_Dir(obj));
1450 ASSERT_EQ(result, nullptr);
1451 ASSERT_NE(PyErr_Occurred(), nullptr);
1452 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1453}
1454
1455TEST_F(ObjectExtensionApiTest,
1456 DirOnInstanceWithNonIterableDunderDirReturnsNull) {
1457 PyRun_SimpleString(R"(
1458class C:
1459 def __init__(self):
1460 self.foo = 123
1461 def __dir__(self):
1462 return 123
1463obj = C()
1464)");
1465 PyObjectPtr obj(mainModuleGet("obj"));
1466 ASSERT_EQ(PyErr_Occurred(), nullptr);
1467 PyObjectPtr result(PyObject_Dir(obj));
1468 ASSERT_EQ(result, nullptr);
1469 ASSERT_NE(PyErr_Occurred(), nullptr);
1470 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError));
1471}
1472
1473TEST_F(ObjectExtensionApiTest, DirOnInstanceIgnoresInstanceDictionary) {
1474 PyRun_SimpleString(R"(
1475class C:
1476 def __init__(self):
1477 self.foo = 123
1478
1479def new_dir(self):
1480 return ("bar")
1481
1482obj = C()
1483obj.__dir__ = new_dir.__get__(obj, C)
1484)");
1485 PyObjectPtr obj(mainModuleGet("obj"));
1486 ASSERT_EQ(PyErr_Occurred(), nullptr);
1487 PyObjectPtr result(PyObject_Dir(obj));
1488 ASSERT_EQ(PyList_Check(result), 1);
1489 PyObjectPtr foo(PyUnicode_FromString("foo"));
1490 EXPECT_EQ(PySequence_Contains(result, foo), 1);
1491}
1492
1493TEST_F(ObjectExtensionApiTest, PyReturnNoneReturnsNone) {
1494 PyObjectPtr module(PyModule_New("mod"));
1495 binaryfunc meth = [](PyObject*, PyObject*) { Py_RETURN_NONE; };
1496 static PyMethodDef foo_func = {"foo", meth, METH_NOARGS};
1497 PyObjectPtr func(PyCFunction_NewEx(&foo_func, nullptr, module));
1498 PyObjectPtr result(_PyObject_CallNoArg(func));
1499 EXPECT_EQ(result, Py_None);
1500}
1501
1502TEST_F(ObjectExtensionApiTest, PyReturnNotImplementedReturnsNotImplemented) {
1503 PyObjectPtr module(PyModule_New("mod"));
1504 binaryfunc meth = [](PyObject*, PyObject*) { Py_RETURN_NOTIMPLEMENTED; };
1505 static PyMethodDef foo_func = {"foo", meth, METH_NOARGS};
1506 PyObjectPtr func(PyCFunction_NewEx(&foo_func, nullptr, module));
1507 PyObjectPtr result(_PyObject_CallNoArg(func));
1508 EXPECT_EQ(result, Py_NotImplemented);
1509}
1510
1511TEST_F(ObjectExtensionApiTest, PyEnumTypeIdentityIsEqual) {
1512 // Test Identitiy
1513 PyTypeObject* type1 = &PyEnum_Type;
1514 PyTypeObject* type2 = &PyEnum_Type;
1515 EXPECT_EQ(type1, type2);
1516}
1517
1518TEST_F(ObjectExtensionApiTest, PyEnumTypeIsInBuiltins) {
1519 PyObjectPtr builtins(borrow(PyEval_GetBuiltins()));
1520 PyObjectPtr enumerate(PyMapping_GetItemString(builtins, "enumerate"));
1521 EXPECT_EQ(enumerate.asTypeObject(), &PyEnum_Type);
1522}
1523
1524} // namespace testing
1525} // namespace py