this repo has no description
at trunk 1554 lines 45 kB view raw
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 DictExtensionApiTest = ExtensionApi; 12 13TEST_F(DictExtensionApiTest, GetItemFromNonDictReturnsNull) { 14 // Pass a non dictionary 15 PyObject* result = PyDict_GetItem(Py_None, Py_None); 16 EXPECT_EQ(result, nullptr); 17 EXPECT_EQ(PyErr_Occurred(), nullptr); 18} 19 20TEST_F(DictExtensionApiTest, GetItemNonExistingKeyReturnsNull) { 21 PyObjectPtr dict(PyDict_New()); 22 PyObjectPtr nonkey(PyLong_FromLong(10)); 23 24 // Pass a non existing key 25 PyObject* result = PyDict_GetItem(dict, nonkey); 26 EXPECT_EQ(result, nullptr); 27 EXPECT_EQ(PyErr_Occurred(), nullptr); 28} 29 30TEST_F(DictExtensionApiTest, GetItemReturnsBorrowedValue) { 31 PyObject* dict = PyDict_New(); 32 PyObject* key = PyLong_FromLong(10); 33 PyObject* value = PyLong_FromLong(0); 34 35 // Insert the value into the dictionary 36 ASSERT_EQ(PyDict_SetItem(dict, key, value), 0); 37 38 // Record the reference count of the value 39 long refcnt = Py_REFCNT(value); 40 41 // Get a new reference to the value from the dictionary 42 PyObject* value2 = PyDict_GetItem(dict, key); 43 44 // The new reference should be equal to the original reference 45 EXPECT_EQ(value2, value); 46 47 // The reference count should not be affected 48 EXPECT_EQ(Py_REFCNT(value), refcnt); 49 50 Py_DECREF(value); 51 Py_DECREF(key); 52 Py_DECREF(dict); 53} 54 55TEST_F(DictExtensionApiTest, GetItemWithDictSubclassReturnsValue) { 56 PyRun_SimpleString(R"( 57class Foo(dict): pass 58obj = Foo() 59 )"); 60 61 PyObjectPtr obj(mainModuleGet("obj")); 62 PyObjectPtr key(PyLong_FromLong(1)); 63 PyObjectPtr val(PyLong_FromLong(2)); 64 ASSERT_EQ(PyDict_SetItem(obj, key, val), 0); 65 ASSERT_EQ(PyErr_Occurred(), nullptr); 66 67 PyObject* result = PyDict_GetItem(obj, key); 68 EXPECT_EQ(result, val); 69 EXPECT_EQ(PyErr_Occurred(), nullptr); 70} 71 72TEST_F(DictExtensionApiTest, GetItemWithBigHashTruncatesHash) { 73 PyRun_SimpleString(R"( 74class C: 75 def __init__(self, v): 76 self.v = v 77 def __hash__(self): 78 return 1180591620717411303424 79 def __eq__(self, other): 80 return self.v == other.v 81c1 = C(4) 82c2 = C(5) 83 )"); 84 85 PyObjectPtr c1(mainModuleGet("c1")); 86 PyObjectPtr c2(mainModuleGet("c2")); 87 PyObjectPtr v1(PyLong_FromLong(1)); 88 PyObjectPtr v2(PyLong_FromLong(2)); 89 PyObjectPtr dict(PyDict_New()); 90 ASSERT_EQ(PyDict_SetItem(dict, c1, v1), 0); 91 ASSERT_EQ(PyErr_Occurred(), nullptr); 92 93 ASSERT_EQ(PyDict_SetItem(dict, c2, v2), 0); 94 ASSERT_EQ(PyErr_Occurred(), nullptr); 95 96 PyObject* result = PyDict_GetItem(dict, c1); 97 EXPECT_EQ(PyErr_Occurred(), nullptr); 98 EXPECT_EQ(result, v1); 99} 100 101TEST_F(DictExtensionApiTest, GetItemWithIntSubclassHashUsesInt) { 102 PyRun_SimpleString(R"( 103class H(int): 104 pass 105class C: 106 def __init__(self, v): 107 self.v = v 108 def __hash__(self): 109 return H(42) 110 def __eq__(self, other): 111 return self.v == other.v 112c = C(4) 113)"); 114 115 PyObjectPtr c(mainModuleGet("c")); 116 PyObjectPtr v(PyLong_FromLong(1)); 117 PyObjectPtr dict(PyDict_New()); 118 ASSERT_EQ(PyDict_SetItem(dict, c, v), 0); 119 ASSERT_EQ(PyErr_Occurred(), nullptr); 120 121 PyObject* result = PyDict_GetItem(dict, c); 122 EXPECT_EQ(PyErr_Occurred(), nullptr); 123 EXPECT_EQ(result, v); 124} 125 126TEST_F(DictExtensionApiTest, GetItemWithSameIdentityReturnsObject) { 127 ASSERT_EQ(PyRun_SimpleString(R"( 128called_dunder_eq = False 129class C: 130 def __eq__(self, other): 131 global called_dunder_eq 132 called_dunder_eq = True 133 def __hash__(self): 134 return 5 135c = C() 136d = {} 137d[c] = 4 138)"), 139 0); 140 PyObjectPtr c(mainModuleGet("c")); 141 PyObjectPtr dict(mainModuleGet("d")); 142 PyObject* result = PyDict_GetItem(dict, c); 143 ASSERT_EQ(PyErr_Occurred(), nullptr); 144 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 145 ASSERT_EQ(called_dunder_eq, Py_False); 146 EXPECT_EQ(PyLong_AsLong(result), 4); 147} 148 149TEST_F(DictExtensionApiTest, GetItemWithDifferentHashReturnsNull) { 150 ASSERT_EQ(PyRun_SimpleString(R"( 151called_dunder_eq = False 152class C: 153 def __init__(self, h): 154 self.h = h 155 def __eq__(self, other): 156 global called_dunder_eq 157 called_dunder_eq = True 158 return True 159 def __hash__(self): 160 return self.h 161 162c = C(1) 163d = {} 164d[C(2)] = 2 165)"), 166 0); 167 PyObjectPtr c(mainModuleGet("c")); 168 PyObjectPtr dict(mainModuleGet("d")); 169 PyObject* result = PyDict_GetItem(dict, c); 170 ASSERT_EQ(PyErr_Occurred(), nullptr); 171 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 172 ASSERT_EQ(called_dunder_eq, Py_False); 173 EXPECT_EQ(result, nullptr); 174} 175 176TEST_F(DictExtensionApiTest, GetItemWithDunderEqReturnsObject) { 177 ASSERT_EQ(PyRun_SimpleString(R"( 178called_dunder_eq = False 179class C: 180 def __eq__(self, other): 181 global called_dunder_eq 182 called_dunder_eq = True 183 return True 184 def __hash__(self): 185 return 5 186 187d = {} 188c = C() 189d[C()] = 4 190)"), 191 0); 192 PyObjectPtr c(mainModuleGet("c")); 193 PyObjectPtr dict(mainModuleGet("d")); 194 PyObject* result = PyDict_GetItem(dict, c); 195 ASSERT_EQ(PyErr_Occurred(), nullptr); 196 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 197 ASSERT_EQ(called_dunder_eq, Py_True); 198 EXPECT_EQ(PyLong_AsLong(result), 4); 199} 200 201TEST_F(DictExtensionApiTest, GetItemWithFalseDunderEqReturnsNull) { 202 ASSERT_EQ(PyRun_SimpleString(R"( 203called_dunder_eq = False 204class C: 205 def __eq__(self, other): 206 global called_dunder_eq 207 called_dunder_eq = True 208 return False 209 def __hash__(self): 210 return 5 211 212c = C() 213d = {} 214d[C()] = 4 215)"), 216 0); 217 PyObjectPtr c(mainModuleGet("c")); 218 PyObjectPtr dict(mainModuleGet("d")); 219 PyObject* result = PyDict_GetItem(dict, c); 220 ASSERT_EQ(PyErr_Occurred(), nullptr); 221 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 222 ASSERT_EQ(called_dunder_eq, Py_True); 223 EXPECT_EQ(result, nullptr); 224} 225 226TEST_F(DictExtensionApiTest, 227 GetItemWithExceptionDunderEqSwallowsAndReturnsNull) { 228 ASSERT_EQ(PyRun_SimpleString(R"( 229called_dunder_eq = False 230class C: 231 def __eq__(self, other): 232 global called_dunder_eq 233 called_dunder_eq = True 234 raise ValueError('foo') 235 def __hash__(self): 236 return 5 237 238c = C() 239d = {} 240d[C()] = 4 241)"), 242 0); 243 PyObjectPtr c(mainModuleGet("c")); 244 PyObjectPtr dict(mainModuleGet("d")); 245 PyObject* result = PyDict_GetItem(dict, c); 246 ASSERT_EQ(PyErr_Occurred(), nullptr); 247 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 248 ASSERT_EQ(called_dunder_eq, Py_True); 249 EXPECT_EQ(result, nullptr); 250} 251 252TEST_F(DictExtensionApiTest, GetItemWithNotImplementedDunderEqReturnsNull) { 253 ASSERT_EQ(PyRun_SimpleString(R"( 254called_dunder_eq = False 255class C: 256 def __eq__(self, other): 257 global called_dunder_eq 258 called_dunder_eq = True 259 return NotImplemented 260 def __hash__(self): 261 return 5 262 263c = C() 264d = {} 265d[C()] = 4 266)"), 267 0); 268 PyObjectPtr c(mainModuleGet("c")); 269 PyObjectPtr dict(mainModuleGet("d")); 270 PyObject* result = PyDict_GetItem(dict, c); 271 ASSERT_EQ(PyErr_Occurred(), nullptr); 272 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 273 ASSERT_EQ(called_dunder_eq, Py_True); 274 EXPECT_EQ(result, nullptr); 275} 276 277TEST_F(DictExtensionApiTest, 278 GetItemCallsExistingKeyDunderEqAndThenLookedKeyDunderEq) { 279 ASSERT_EQ(PyRun_SimpleString(R"( 280seq_num = 0 281 282def new_seq_num(): 283 global seq_num 284 seq_num += 1 285 return seq_num 286 287c_eq = 0 288c_hash = 0 289 290class C: 291 def __eq__(self, other): 292 global c_eq 293 c_eq = new_seq_num() 294 return NotImplemented 295 296 def __hash__(self): 297 global c_hash 298 c_hash = new_seq_num() 299 return 5 300 301c = C() 302 303d_eq = 0 304d_hash = 0 305 306class D: 307 def __eq__(self, other): 308 global d_eq 309 d_eq = new_seq_num() 310 return True 311 312 def __hash__(self): 313 global d_hash 314 d_hash = new_seq_num() 315 return 5 316 317d = D() 318)"), 319 0); 320 PyObjectPtr dict(PyDict_New()); 321 PyObjectPtr c(mainModuleGet("c")); 322 PyObjectPtr value(PyLong_FromLong(500)); 323 324 ASSERT_EQ(PyDict_SetItem(dict, c, value), 0); 325 ASSERT_EQ(PyErr_Occurred(), nullptr); 326 ASSERT_EQ(PyDict_Size(dict), 1); 327 PyObjectPtr c_eq(mainModuleGet("c_eq")); 328 ASSERT_EQ(PyLong_AsLong(c_eq), 0); 329 PyObjectPtr c_hash(mainModuleGet("c_hash")); 330 ASSERT_EQ(PyLong_AsLong(c_hash), 1); 331 332 PyObjectPtr d(mainModuleGet("d")); 333 PyObject* result = PyDict_GetItem(dict, d); 334 ASSERT_EQ(PyErr_Occurred(), nullptr); 335 ASSERT_EQ(PyLong_AsLong(result), 500); 336 c_hash = mainModuleGet("c_hash"); 337 EXPECT_EQ(PyLong_AsLong(c_hash), 1); 338 PyObjectPtr d_hash(mainModuleGet("d_hash")); 339 EXPECT_EQ(PyLong_AsLong(d_hash), 2); 340 c_eq = mainModuleGet("c_eq"); 341 EXPECT_EQ(PyLong_AsLong(c_eq), 3); 342 PyObjectPtr d_eq(mainModuleGet("d_eq")); 343 EXPECT_EQ(PyLong_AsLong(d_eq), 4); 344} 345 346TEST_F(DictExtensionApiTest, GetItemComparesHashValueFirst) { 347 ASSERT_EQ(PyRun_SimpleString(R"( 348class C: 349 def __init__(self, hash_code): 350 self.hash_code = hash_code 351 352 def __eq__(self, other): 353 raise UserWarning("unexpected") 354 355 def __hash__(self): 356 return self.hash_code 357 358c = C(4) 359d = C(5) 360)"), 361 0); 362 PyObjectPtr dict(PyDict_New()); 363 PyObjectPtr c(mainModuleGet("c")); 364 PyObjectPtr value(PyLong_FromLong(500)); 365 366 ASSERT_EQ(PyDict_SetItem(dict, c, value), 0); 367 ASSERT_EQ(PyErr_Occurred(), nullptr); 368 ASSERT_EQ(PyDict_Size(dict), 1); 369 370 PyObjectPtr d(mainModuleGet("d")); 371 ASSERT_EQ(PyDict_GetItem(dict, d), nullptr); 372 ASSERT_EQ(PyErr_Occurred(), nullptr); 373} 374 375TEST_F(DictExtensionApiTest, GetItemKnownHashFromNonDictRaisesSystemError) { 376 // Pass a non dictionary 377 PyObject* result = _PyDict_GetItem_KnownHash(Py_None, Py_None, 0); 378 EXPECT_EQ(result, nullptr); 379 ASSERT_NE(PyErr_Occurred(), nullptr); 380 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 381} 382 383TEST_F(DictExtensionApiTest, GetItemKnownHashNonExistingKeyReturnsNull) { 384 PyObjectPtr dict(PyDict_New()); 385 PyObjectPtr nonkey(PyLong_FromLong(11)); 386 387 // Pass a non existing key 388 PyObject* result = _PyDict_GetItem_KnownHash(dict, nonkey, 0); 389 EXPECT_EQ(result, nullptr); 390 EXPECT_EQ(PyErr_Occurred(), nullptr); 391} 392 393TEST_F(DictExtensionApiTest, GetItemKnownHashReturnsBorrowedValue) { 394 PyObject* dict = PyDict_New(); 395 PyObject* key = PyLong_FromLong(10); 396 PyObject* value = PyLong_FromLong(0); 397 398 // Insert the value into the dictionary 399 Py_hash_t hash = Py_hash_t{1} << ((sizeof(Py_hash_t) * CHAR_BIT) - 1); 400 ASSERT_EQ(_PyDict_SetItem_KnownHash(dict, key, value, hash), 0); 401 402 // Record the reference count of the value 403 long refcnt = Py_REFCNT(value); 404 405 // Get a new reference to the value from the dictionary 406 PyObject* value2 = _PyDict_GetItem_KnownHash(dict, key, hash); 407 408 // The new reference should be equal to the original reference 409 EXPECT_EQ(value2, value); 410 411 // The reference count should not be affected 412 EXPECT_EQ(Py_REFCNT(value), refcnt); 413 414 Py_DECREF(value); 415 Py_DECREF(key); 416 Py_DECREF(dict); 417} 418 419TEST_F(DictExtensionApiTest, GetItemStringReturnsValue) { 420 PyObjectPtr dict(PyDict_New()); 421 const char* key_cstr = "key"; 422 PyObjectPtr key(PyUnicode_FromString(key_cstr)); 423 PyObjectPtr value(PyLong_FromLong(0)); 424 ASSERT_EQ(PyDict_SetItem(dict, key, value), 0); 425 426 PyObject* item = PyDict_GetItemString(dict, key_cstr); 427 EXPECT_EQ(item, value); 428} 429 430TEST_F(DictExtensionApiTest, SetItemWithNonDictRaisesSystemError) { 431 PyObjectPtr set(PySet_New(nullptr)); 432 PyObjectPtr key(PyLong_FromLong(0)); 433 PyObjectPtr val(PyLong_FromLong(0)); 434 435 ASSERT_EQ(PyDict_SetItem(set, key, val), -1); 436 ASSERT_NE(PyErr_Occurred(), nullptr); 437 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 438} 439 440TEST_F(DictExtensionApiTest, SetItemWithNewDictReturnsZero) { 441 PyObjectPtr dict(PyDict_New()); 442 PyObjectPtr key(PyLong_FromLong(0)); 443 PyObjectPtr val(PyLong_FromLong(0)); 444 445 EXPECT_EQ(PyDict_SetItem(dict, key, val), 0); 446 EXPECT_EQ(PyErr_Occurred(), nullptr); 447} 448 449TEST_F(DictExtensionApiTest, SetItemWithNewDictSubclassReturnsZero) { 450 PyRun_SimpleString(R"( 451class Foo(dict): pass 452obj = Foo() 453 )"); 454 455 PyObjectPtr obj(mainModuleGet("obj")); 456 PyObjectPtr key(PyLong_FromLong(0)); 457 PyObjectPtr val(PyLong_FromLong(0)); 458 459 EXPECT_EQ(PyDict_SetItem(obj, key, val), 0); 460 EXPECT_EQ(PyErr_Occurred(), nullptr); 461} 462 463TEST_F(DictExtensionApiTest, 464 SetItemWithDunderHashReturningNonIntRaisesTypeError) { 465 PyRun_SimpleString(R"( 466class C: 467 def __hash__(self): 468 return "foo" 469 def __eq__(self, other): 470 return self == other 471c = C() 472)"); 473 PyObjectPtr dict(PyDict_New()); 474 PyObjectPtr key(mainModuleGet("c")); 475 PyObjectPtr val(PyLong_FromLong(0)); 476 477 ASSERT_EQ(PyDict_SetItem(dict, key, val), -1); 478 ASSERT_NE(PyErr_Occurred(), nullptr); 479 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 480} 481 482TEST_F(DictExtensionApiTest, SetItemWithIntSubclassHashReturnsZero) { 483 PyRun_SimpleString(R"( 484class H(int): 485 pass 486class C: 487 def __init__(self, v): 488 self.v = v 489 def __hash__(self): 490 return H(42) 491 def __eq__(self, other): 492 return self.v == other.v 493c = C(4) 494)"); 495 496 PyObjectPtr c(mainModuleGet("c")); 497 PyObjectPtr v(PyLong_FromLong(1)); 498 PyObjectPtr dict(PyDict_New()); 499 EXPECT_EQ(PyDict_SetItem(dict, c, v), 0); 500 EXPECT_EQ(PyErr_Occurred(), nullptr); 501} 502 503TEST_F(DictExtensionApiTest, SetItemWithSameIdentitySupersedesValue) { 504 ASSERT_EQ(PyRun_SimpleString(R"( 505called_dunder_eq = False 506class C: 507 def __eq__(self, other): 508 global called_dunder_eq 509 called_dunder_eq = True 510 def __hash__(self): 511 return 5 512 513c = C() 514d = {} 515d[c] = 0 516)"), 517 0); 518 PyObjectPtr c(mainModuleGet("c")); 519 PyObjectPtr dict(mainModuleGet("d")); 520 PyObjectPtr value(PyLong_FromLong(1)); 521 ASSERT_EQ(PyDict_SetItem(dict, c, value), 0); 522 ASSERT_EQ(PyDict_Size(dict), 1); 523 PyObject* result = PyDict_GetItem(dict, c); 524 ASSERT_EQ(PyErr_Occurred(), nullptr); 525 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 526 ASSERT_EQ(called_dunder_eq, Py_False); 527 EXPECT_EQ(value, result); 528} 529 530TEST_F(DictExtensionApiTest, SetItemWithDifferentHashInsertsValue) { 531 ASSERT_EQ(PyRun_SimpleString(R"( 532called_dunder_eq = False 533class C: 534 def __init__(self, h): 535 self.h = h 536 def __eq__(self, other): 537 global called_dunder_eq 538 called_dunder_eq = True 539 return True 540 def __hash__(self): 541 return self.h 542 543c = C(1) 544d = {} 545d[C(2)] = 2 546)"), 547 0); 548 PyObjectPtr c(mainModuleGet("c")); 549 PyObjectPtr dict(mainModuleGet("d")); 550 PyObjectPtr value(PyLong_FromLong(1)); 551 ASSERT_EQ(PyDict_SetItem(dict, c, value), 0); 552 ASSERT_EQ(PyErr_Occurred(), nullptr); 553 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 554 ASSERT_EQ(called_dunder_eq, Py_False); 555 EXPECT_EQ(PyDict_Size(dict), 2); 556} 557 558TEST_F(DictExtensionApiTest, SetItemWithDunderEqSupersedesValue) { 559 ASSERT_EQ(PyRun_SimpleString(R"( 560called_dunder_eq = False 561class C: 562 def __eq__(self, other): 563 global called_dunder_eq 564 called_dunder_eq = True 565 return True 566 def __hash__(self): 567 return 5 568 569c = C() 570d = {} 571d[C()] = 0 572)"), 573 0); 574 PyObjectPtr c(mainModuleGet("c")); 575 PyObjectPtr dict(mainModuleGet("d")); 576 PyObjectPtr value(PyLong_FromLong(1)); 577 ASSERT_EQ(PyDict_SetItem(dict, c, value), 0); 578 ASSERT_EQ(PyDict_Size(dict), 1); 579 PyObject* result = PyDict_GetItem(dict, c); 580 ASSERT_EQ(PyErr_Occurred(), nullptr); 581 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 582 ASSERT_EQ(called_dunder_eq, Py_True); 583 EXPECT_EQ(value, result); 584} 585 586TEST_F(DictExtensionApiTest, SetItemWithFalseDunderEqInsertsValue) { 587 ASSERT_EQ(PyRun_SimpleString(R"( 588called_dunder_eq = False 589class C: 590 def __eq__(self, other): 591 global called_dunder_eq 592 called_dunder_eq = True 593 return False 594 def __hash__(self): 595 return 5 596 597c = C() 598d = {} 599d[C()] = 0 600)"), 601 0); 602 PyObjectPtr c(mainModuleGet("c")); 603 PyObjectPtr dict(mainModuleGet("d")); 604 PyObjectPtr value(PyLong_FromLong(1)); 605 ASSERT_EQ(PyDict_SetItem(dict, c, value), 0); 606 ASSERT_EQ(PyErr_Occurred(), nullptr); 607 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 608 ASSERT_EQ(called_dunder_eq, Py_True); 609 EXPECT_EQ(PyDict_Size(dict), 2); 610} 611 612TEST_F(DictExtensionApiTest, SetItemWithExceptionDunderEqRaisesException) { 613 ASSERT_EQ(PyRun_SimpleString(R"( 614called_dunder_eq = False 615class C: 616 def __eq__(self, other): 617 global called_dunder_eq 618 called_dunder_eq = True 619 raise ValueError('foo') 620 def __hash__(self): 621 return 5 622 623c = C() 624d = {} 625d[C()] = 0 626)"), 627 0); 628 PyObjectPtr c(mainModuleGet("c")); 629 PyObjectPtr dict(mainModuleGet("d")); 630 PyObjectPtr value(PyLong_FromLong(1)); 631 EXPECT_EQ(PyDict_SetItem(dict, c, value), -1); 632 EXPECT_NE(PyErr_Occurred(), nullptr); 633 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_ValueError)); 634 PyErr_Clear(); 635 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 636 ASSERT_EQ(called_dunder_eq, Py_True); 637 EXPECT_EQ(PyDict_Size(dict), 1); 638} 639 640TEST_F(DictExtensionApiTest, SetItemWithNotImplementedDunderEqInsertsValue) { 641 ASSERT_EQ(PyRun_SimpleString(R"( 642called_dunder_eq = False 643class C: 644 def __eq__(self, other): 645 global called_dunder_eq 646 called_dunder_eq = True 647 return NotImplemented 648 def __hash__(self): 649 return 5 650 651c = C() 652d = {} 653d[C()] = 0 654)"), 655 0); 656 PyObjectPtr c(mainModuleGet("c")); 657 PyObjectPtr dict(mainModuleGet("d")); 658 PyObjectPtr value(PyLong_FromLong(1)); 659 ASSERT_EQ(PyDict_SetItem(dict, c, value), 0); 660 ASSERT_EQ(PyErr_Occurred(), nullptr); 661 PyObjectPtr called_dunder_eq(mainModuleGet("called_dunder_eq")); 662 ASSERT_EQ(called_dunder_eq, Py_True); 663 EXPECT_EQ(PyDict_Size(dict), 2); 664} 665 666TEST_F(DictExtensionApiTest, 667 SetItemCallsExistingKeyDunderEqAndThenLookedKeyDunderEq) { 668 ASSERT_EQ(PyRun_SimpleString(R"( 669seq_num = 0 670 671def new_seq_num(): 672 global seq_num 673 seq_num += 1 674 return seq_num 675 676c_eq = 0 677c_hash = 0 678 679class C: 680 def __eq__(self, other): 681 global c_eq 682 c_eq = new_seq_num() 683 return NotImplemented 684 685 def __hash__(self): 686 global c_hash 687 c_hash = new_seq_num() 688 return 5 689 690c = C() 691 692d_eq = 0 693d_hash = 0 694 695class D: 696 def __eq__(self, other): 697 global d_eq 698 d_eq = new_seq_num() 699 return True 700 701 def __hash__(self): 702 global d_hash 703 d_hash = new_seq_num() 704 return 5 705 706d = D() 707)"), 708 0); 709 PyObjectPtr dict(PyDict_New()); 710 PyObjectPtr c(mainModuleGet("c")); 711 PyObjectPtr value(PyLong_FromLong(1)); 712 713 ASSERT_EQ(PyDict_SetItem(dict, c, value), 0); 714 ASSERT_EQ(PyErr_Occurred(), nullptr); 715 ASSERT_EQ(PyDict_Size(dict), 1); 716 PyObjectPtr c_eq(mainModuleGet("c_eq")); 717 ASSERT_EQ(PyLong_AsLong(c_eq), 0); 718 PyObjectPtr c_hash(mainModuleGet("c_hash")); 719 ASSERT_EQ(PyLong_AsLong(c_hash), 1); 720 721 PyObjectPtr d(mainModuleGet("d")); 722 ASSERT_EQ(PyDict_SetItem(dict, d, value), 0); 723 ASSERT_EQ(PyErr_Occurred(), nullptr); 724 ASSERT_EQ(PyDict_Size(dict), 1); 725 c_hash = mainModuleGet("c_hash"); 726 EXPECT_EQ(PyLong_AsLong(c_hash), 1); 727 PyObjectPtr d_hash(mainModuleGet("d_hash")); 728 EXPECT_EQ(PyLong_AsLong(d_hash), 2); 729 c_eq = mainModuleGet("c_eq"); 730 EXPECT_EQ(PyLong_AsLong(c_eq), 3); 731 PyObjectPtr d_eq(mainModuleGet("d_eq")); 732 EXPECT_EQ(PyLong_AsLong(d_eq), 4); 733} 734 735TEST_F(DictExtensionApiTest, SetItemRetainsExistingKeyObject) { 736 ASSERT_EQ(PyRun_SimpleString(R"( 737class C: 738 def __eq__(self, other): 739 return True 740 741 def __hash__(self): 742 return 5 743 744c = C() 745d = C() 746)"), 747 0); 748 PyObjectPtr dict(PyDict_New()); 749 PyObjectPtr c(mainModuleGet("c")); 750 PyObjectPtr d(mainModuleGet("d")); 751 PyObjectPtr c_value(PyLong_FromLong(1)); 752 PyObjectPtr d_value(PyLong_FromLong(2)); 753 754 ASSERT_EQ(PyDict_SetItem(dict, c, c_value), 0); 755 ASSERT_EQ(PyErr_Occurred(), nullptr); 756 ASSERT_EQ(PyDict_Size(dict), 1); 757 758 ASSERT_EQ(PyDict_SetItem(dict, d, d_value), 0); 759 ASSERT_EQ(PyErr_Occurred(), nullptr); 760 ASSERT_EQ(PyDict_Size(dict), 1); 761 762 PyObjectPtr result(PyDict_Items(dict)); 763 ASSERT_NE(result, nullptr); 764 ASSERT_EQ(PyErr_Occurred(), nullptr); 765 ASSERT_TRUE(PyList_CheckExact(result)); 766 EXPECT_EQ(PyList_Size(result), 1); 767 768 PyObjectPtr kv(borrow(PyList_GetItem(result, 0))); 769 ASSERT_TRUE(PyTuple_CheckExact(kv)); 770 ASSERT_EQ(PyTuple_Size(kv), 2); 771 EXPECT_EQ(PyTuple_GetItem(kv, 0), c); 772 EXPECT_EQ(PyTuple_GetItem(kv, 1), d_value); 773} 774 775TEST_F(DictExtensionApiTest, SetItemComparesHashValueFirst) { 776 ASSERT_EQ(PyRun_SimpleString(R"( 777class C: 778 def __init__(self, hash_code): 779 self.hash_code = hash_code 780 781 def __eq__(self, other): 782 raise UserWarning("unexpected") 783 784 def __hash__(self): 785 return self.hash_code 786 787c = C(4) 788d = C(5) 789)"), 790 0); 791 PyObjectPtr dict(PyDict_New()); 792 PyObjectPtr c(mainModuleGet("c")); 793 PyObjectPtr value(PyLong_FromLong(500)); 794 795 ASSERT_EQ(PyDict_SetItem(dict, c, value), 0); 796 ASSERT_EQ(PyErr_Occurred(), nullptr); 797 ASSERT_EQ(PyDict_Size(dict), 1); 798 799 PyObjectPtr d(mainModuleGet("d")); 800 ASSERT_EQ(PyDict_SetItem(dict, d, value), 0); 801 ASSERT_EQ(PyErr_Occurred(), nullptr); 802 ASSERT_EQ(PyDict_Size(dict), 2); 803} 804 805TEST_F(DictExtensionApiTest, SetItemStringInternsKeys) { 806 PyObjectPtr one(PyLong_FromLong(1)); 807 const char* key = "unique-never-before-seen-test-key"; 808 PyObjectPtr pydict(PyDict_New()); 809 810 // Calling PyDict_SetItemString should create an interned string for the key 811 PyDict_SetItemString(pydict, key, one); 812 PyObjectPtr result(PyDict_Keys(pydict)); 813 ASSERT_NE(result, nullptr); 814 ASSERT_EQ(PyErr_Occurred(), nullptr); 815 ASSERT_TRUE(PyList_Check(result)); 816 EXPECT_EQ(PyList_Size(result), 1); 817 PyObjectPtr interned_str(borrow(PyList_GetItem(result, 0))); 818 ASSERT_EQ(PyErr_Occurred(), nullptr); 819 820 // Use a PyObject* directly because InternInPlace requires a reference to a 821 // PyObject* 822 PyObject* str = PyUnicode_FromString(key); 823 // Prior to interning str it should be a different object than 824 // the dictionary key 825 ASSERT_NE(str, interned_str); 826 // InternInPlace will update the object str points to to be the same as 827 // the dictionary key. 828 PyUnicode_InternInPlace(&str); 829 ASSERT_EQ(PyErr_Occurred(), nullptr); 830 ASSERT_EQ(str, interned_str); 831 Py_DECREF(str); 832} 833 834TEST_F(DictExtensionApiTest, SizeWithNonDictReturnsNegative) { 835 PyObject* list = PyList_New(0); 836 EXPECT_EQ(PyDict_Size(list), -1); 837 ASSERT_NE(PyErr_Occurred(), nullptr); 838 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 839 840 Py_DECREF(list); 841} 842 843TEST_F(DictExtensionApiTest, SizeWithEmptyDictReturnsZero) { 844 PyObjectPtr dict(PyDict_New()); 845 EXPECT_EQ(PyDict_Size(dict), 0); 846} 847 848TEST_F(DictExtensionApiTest, SizeWithNonEmptyDict) { 849 PyObjectPtr dict(PyDict_New()); 850 PyObjectPtr key1(PyLong_FromLong(1)); 851 PyObjectPtr key2(PyLong_FromLong(2)); 852 PyObjectPtr value1(PyLong_FromLong(0)); 853 PyObjectPtr value2(PyLong_FromLong(0)); 854 PyObjectPtr value3(PyLong_FromLong(0)); 855 856 // Dict starts out empty 857 EXPECT_EQ(PyDict_Size(dict), 0); 858 859 // Inserting items for two different keys 860 ASSERT_EQ(PyDict_SetItem(dict, key1, value1), 0); 861 ASSERT_EQ(PyDict_SetItem(dict, key2, value2), 0); 862 EXPECT_EQ(PyDict_Size(dict), 2); 863 864 // Replace value for existing key 865 ASSERT_EQ(PyDict_SetItem(dict, key1, value3), 0); 866 EXPECT_EQ(PyDict_Size(dict), 2); 867} 868 869TEST_F(DictExtensionApiTest, ContainsWithKeyInDictReturnsOne) { 870 PyObjectPtr dict(PyDict_New()); 871 PyObjectPtr key(PyLong_FromLong(10)); 872 PyObjectPtr value(PyLong_FromLong(11)); 873 ASSERT_EQ(PyDict_SetItem(dict, key, value), 0); 874 EXPECT_EQ(PyDict_Contains(dict, key), 1); 875 EXPECT_EQ(PyErr_Occurred(), nullptr); 876} 877 878TEST_F(DictExtensionApiTest, ContainsWithKeyNotInDictReturnsZero) { 879 PyObjectPtr dict(PyDict_New()); 880 PyObjectPtr key(PyLong_FromLong(10)); 881 PyObjectPtr value(PyLong_FromLong(11)); 882 ASSERT_EQ(PyDict_SetItem(dict, key, value), 0); 883 ASSERT_EQ(PyErr_Occurred(), nullptr); 884 PyObjectPtr key2(PyLong_FromLong(666)); 885 EXPECT_EQ(PyDict_Contains(dict, key2), 0); 886 EXPECT_EQ(PyErr_Occurred(), nullptr); 887} 888 889TEST_F(DictExtensionApiTest, ItemsWithNonDictRaisesSystemError) { 890 ASSERT_EQ(PyDict_Items(Py_None), nullptr); 891 ASSERT_NE(PyErr_Occurred(), nullptr); 892 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 893} 894 895TEST_F(DictExtensionApiTest, ItemsWithDictReturnsList) { 896 PyObjectPtr dict(PyDict_New()); 897 PyObjectPtr key(PyLong_FromLong(10)); 898 PyObjectPtr value(PyLong_FromLong(11)); 899 ASSERT_EQ(PyDict_SetItem(dict, key, value), 0); 900 901 PyObjectPtr result(PyDict_Items(dict)); 902 ASSERT_NE(result, nullptr); 903 ASSERT_EQ(PyErr_Occurred(), nullptr); 904 ASSERT_TRUE(PyList_CheckExact(result)); 905 EXPECT_EQ(PyList_Size(result), 1); 906 907 PyObject* kv = PyList_GetItem(result, 0); 908 ASSERT_TRUE(PyTuple_CheckExact(kv)); 909 ASSERT_EQ(PyTuple_Size(kv), 2); 910 EXPECT_EQ(PyTuple_GetItem(kv, 0), key); 911 EXPECT_EQ(PyTuple_GetItem(kv, 1), value); 912} 913 914TEST_F(DictExtensionApiTest, KeysWithNonDictRaisesSystemError) { 915 EXPECT_EQ(PyDict_Keys(Py_None), nullptr); 916 ASSERT_NE(PyErr_Occurred(), nullptr); 917 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 918} 919 920TEST_F(DictExtensionApiTest, KeysWithDictReturnsList) { 921 PyObjectPtr dict(PyDict_New()); 922 923 PyObjectPtr key(PyLong_FromLong(10)); 924 PyObjectPtr value(PyLong_FromLong(11)); 925 ASSERT_EQ(PyDict_SetItem(dict, key, value), 0); 926 927 PyObjectPtr result(PyDict_Keys(dict)); 928 ASSERT_NE(result, nullptr); 929 ASSERT_EQ(PyErr_Occurred(), nullptr); 930 ASSERT_TRUE(PyList_CheckExact(result)); 931 EXPECT_EQ(PyList_Size(result), 1); 932 EXPECT_EQ(PyList_GetItem(result, 0), key); 933} 934 935TEST_F(DictExtensionApiTest, ValuesWithNonDictReturnsNull) { 936 EXPECT_EQ(PyDict_Values(Py_None), nullptr); 937 ASSERT_NE(PyErr_Occurred(), nullptr); 938 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 939} 940 941TEST_F(DictExtensionApiTest, ValuesWithEmptyDictReturnsEmptyList) { 942 PyObjectPtr dict(PyDict_New()); 943 PyObjectPtr result(PyDict_Values(dict)); 944 ASSERT_NE(result, nullptr); 945 ASSERT_EQ(PyErr_Occurred(), nullptr); 946 EXPECT_TRUE(PyList_CheckExact(result)); 947 EXPECT_EQ(PyList_Size(result), 0); 948} 949 950TEST_F(DictExtensionApiTest, ValuesWithNonEmptyDictReturnsNonEmptyList) { 951 PyObjectPtr dict(PyDict_New()); 952 953 PyObjectPtr key(PyLong_FromLong(10)); 954 PyObjectPtr value(PyLong_FromLong(11)); 955 ASSERT_EQ(PyDict_SetItem(dict, key, value), 0); 956 957 PyObjectPtr result(PyDict_Values(dict)); 958 ASSERT_NE(result, nullptr); 959 ASSERT_EQ(PyErr_Occurred(), nullptr); 960 ASSERT_TRUE(PyList_CheckExact(result)); 961 EXPECT_EQ(PyList_Size(result), 1); 962 EXPECT_EQ(PyList_GetItem(result, 0), value); 963} 964 965TEST_F(DictExtensionApiTest, ClearWithNonDictDoesNotRaise) { 966 PyDict_Clear(Py_None); 967 ASSERT_EQ(PyErr_Occurred(), nullptr); 968} 969 970TEST_F(DictExtensionApiTest, ClearRemovesAllItems) { 971 PyObjectPtr dict(PyDict_New()); 972 PyObjectPtr one(PyLong_FromLong(1)); 973 PyObjectPtr two(PyLong_FromLong(1)); 974 PyDict_SetItem(dict, one, two); 975 ASSERT_EQ(PyErr_Occurred(), nullptr); 976 PyObjectPtr three(PyLong_FromLong(1)); 977 PyObjectPtr four(PyLong_FromLong(1)); 978 PyDict_SetItem(dict, three, four); 979 ASSERT_EQ(PyErr_Occurred(), nullptr); 980 981 PyDict_Clear(dict); 982 EXPECT_EQ(PyErr_Occurred(), nullptr); 983 EXPECT_EQ(PyDict_Size(dict), 0); 984} 985 986TEST_F(DictExtensionApiTest, GETSIZEWithEmptyDictReturnsZero) { 987 PyObjectPtr dict(PyDict_New()); 988 EXPECT_EQ(PyDict_GET_SIZE(dict.get()), 0); 989} 990 991TEST_F(DictExtensionApiTest, GETSIZEWithNonEmptyDict) { 992 PyObjectPtr dict(PyDict_New()); 993 PyObjectPtr key1(PyLong_FromLong(1)); 994 PyObjectPtr key2(PyLong_FromLong(2)); 995 PyObjectPtr value1(PyLong_FromLong(0)); 996 PyObjectPtr value2(PyLong_FromLong(0)); 997 PyObjectPtr value3(PyLong_FromLong(0)); 998 999 // Dict starts out empty 1000 EXPECT_EQ(PyDict_GET_SIZE(dict.get()), 0); 1001 1002 // Inserting items for two different keys 1003 ASSERT_EQ(PyDict_SetItem(dict, key1, value1), 0); 1004 ASSERT_EQ(PyDict_SetItem(dict, key2, value2), 0); 1005 EXPECT_EQ(PyDict_GET_SIZE(dict.get()), 2); 1006 1007 // Replace value for existing key 1008 ASSERT_EQ(PyDict_SetItem(dict, key1, value3), 0); 1009 EXPECT_EQ(PyDict_GET_SIZE(dict.get()), 2); 1010} 1011 1012TEST_F(DictExtensionApiTest, GetItemWithErrorNonExistingKeyReturnsNull) { 1013 PyObjectPtr dict(PyDict_New()); 1014 PyObjectPtr key(PyLong_FromLong(666)); 1015 PyObjectPtr result(PyDict_GetItemWithError(dict, key)); 1016 EXPECT_EQ(result, nullptr); 1017 ASSERT_EQ(PyErr_Occurred(), nullptr); 1018} 1019 1020TEST_F(DictExtensionApiTest, GetItemWithErrorReturnsBorrowedValue) { 1021 PyObjectPtr dict(PyDict_New()); 1022 PyObjectPtr key(PyLong_FromLong(10)); 1023 PyObjectPtr value(PyLong_FromLong(666)); 1024 1025 // Insert the value into the dictionary 1026 ASSERT_EQ(PyDict_SetItem(dict, key, value), 0); 1027 1028 // Record the reference count of the value 1029 long refcnt = Py_REFCNT(value); 1030 1031 // Get a new reference to the value from the dictionary 1032 PyObject* value2 = PyDict_GetItemWithError(dict, key); 1033 ASSERT_EQ(PyErr_Occurred(), nullptr); 1034 1035 // The new reference should be equal to the original reference 1036 EXPECT_EQ(value2, value); 1037 1038 // The reference count should not be affected 1039 EXPECT_EQ(Py_REFCNT(value), refcnt); 1040} 1041 1042TEST_F(DictExtensionApiTest, GetItemWithErrorWithDictSubclassReturnsValue) { 1043 PyRun_SimpleString(R"( 1044class Foo(dict): pass 1045obj = Foo() 1046 )"); 1047 1048 PyObjectPtr obj(mainModuleGet("obj")); 1049 PyObjectPtr key(PyLong_FromLong(1)); 1050 PyObjectPtr val(PyLong_FromLong(2)); 1051 ASSERT_EQ(PyDict_SetItem(obj, key, val), 0); 1052 ASSERT_EQ(PyErr_Occurred(), nullptr); 1053 1054 PyObject* result = PyDict_GetItemWithError(obj, key); 1055 ASSERT_EQ(PyErr_Occurred(), nullptr); 1056 EXPECT_EQ(result, val); 1057 EXPECT_EQ(PyErr_Occurred(), nullptr); 1058} 1059 1060TEST_F(DictExtensionApiTest, 1061 GetItemWithErrorWithUnhashableObjectRaisesTypeError) { 1062 PyRun_SimpleString(R"( 1063class C: 1064 __hash__ = None 1065obj = C() 1066)"); 1067 PyObjectPtr dict(PyDict_New()); 1068 PyObjectPtr key(mainModuleGet("obj")); 1069 EXPECT_EQ(PyDict_GetItemWithError(dict, key), nullptr); 1070 ASSERT_NE(PyErr_Occurred(), nullptr); 1071 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 1072} 1073 1074TEST_F(DictExtensionApiTest, DelItemWithNonDictReturnsNegativeOne) { 1075 EXPECT_EQ(PyDict_DelItem(Py_None, Py_None), -1); 1076 ASSERT_NE(PyErr_Occurred(), nullptr); 1077 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 1078} 1079 1080TEST_F(DictExtensionApiTest, DelItemWithKeyInDictReturnsZero) { 1081 PyObjectPtr dict(PyDict_New()); 1082 PyObjectPtr key(PyLong_FromLong(10)); 1083 PyObjectPtr value(PyLong_FromLong(11)); 1084 ASSERT_EQ(PyDict_SetItem(dict, key, value), 0); 1085 EXPECT_EQ(PyDict_DelItem(dict, key), 0); 1086 ASSERT_EQ(PyErr_Occurred(), nullptr); 1087} 1088 1089TEST_F(DictExtensionApiTest, DelItemWithKeyNotInDictRaisesKeyError) { 1090 PyObjectPtr dict(PyDict_New()); 1091 PyObjectPtr key(PyLong_FromLong(10)); 1092 EXPECT_EQ(PyDict_DelItem(dict, key), -1); 1093 ASSERT_NE(PyErr_Occurred(), nullptr); 1094 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_KeyError)); 1095} 1096 1097TEST_F(DictExtensionApiTest, DelItemWithUnhashableObjectRaisesTypeError) { 1098 PyRun_SimpleString(R"( 1099class C: 1100 __hash__ = None 1101c = C() 1102)"); 1103 PyObjectPtr dict(PyDict_New()); 1104 PyObject* main = PyImport_AddModule("__main__"); 1105 PyObjectPtr key(PyObject_GetAttrString(main, "c")); 1106 EXPECT_EQ(PyDict_DelItem(dict, key), -1); 1107 ASSERT_NE(PyErr_Occurred(), nullptr); 1108 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_TypeError)); 1109} 1110 1111TEST_F(DictExtensionApiTest, DelItemStringWithNonDictReturnsNegativeOne) { 1112 EXPECT_EQ(PyDict_DelItemString(Py_None, "hello, there"), -1); 1113 ASSERT_NE(PyErr_Occurred(), nullptr); 1114 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 1115} 1116 1117TEST_F(DictExtensionApiTest, DelItemStringWithKeyInDictReturnsZero) { 1118 PyObjectPtr dict(PyDict_New()); 1119 const char* strkey = "hello, there"; 1120 PyObjectPtr key(PyUnicode_FromString(strkey)); 1121 PyObjectPtr value(PyLong_FromLong(666)); 1122 ASSERT_EQ(PyDict_SetItem(dict, key, value), 0); 1123 EXPECT_EQ(PyDict_DelItemString(dict, strkey), 0); 1124 ASSERT_EQ(PyErr_Occurred(), nullptr); 1125} 1126 1127TEST_F(DictExtensionApiTest, DelItemStringWithKeyNotInDictReturnsNegativeOne) { 1128 PyObjectPtr dict(PyDict_New()); 1129 EXPECT_EQ(PyDict_DelItemString(dict, "hello, there"), -1); 1130 ASSERT_NE(PyErr_Occurred(), nullptr); 1131 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_KeyError)); 1132} 1133 1134TEST_F(DictExtensionApiTest, NextWithEmptyDictReturnsFalse) { 1135 PyObject* key = nullptr; 1136 PyObject* value = nullptr; 1137 Py_ssize_t pos = 0; 1138 PyObjectPtr dict(PyDict_New()); 1139 EXPECT_EQ(PyDict_Next(dict, &pos, &key, &value), 0); 1140 ASSERT_EQ(PyErr_Occurred(), nullptr); 1141} 1142 1143TEST_F(DictExtensionApiTest, NextWithNonEmptyDictReturnsKeysAndValues) { 1144 PyObjectPtr dict(PyDict_New()); 1145 PyObjectPtr one(PyLong_FromLong(1)); 1146 PyObjectPtr two(PyLong_FromLong(2)); 1147 PyDict_SetItem(dict, one, two); 1148 PyObjectPtr three(PyLong_FromLong(3)); 1149 PyObjectPtr four(PyLong_FromLong(4)); 1150 PyDict_SetItem(dict, three, four); 1151 1152 Py_ssize_t pos = 0; 1153 PyObject* key = nullptr; 1154 PyObject* value = nullptr; 1155 ASSERT_EQ(PyDict_Next(dict, &pos, &key, &value), 1); 1156 ASSERT_EQ(PyErr_Occurred(), nullptr); 1157 EXPECT_EQ(key, one); 1158 EXPECT_EQ(value, two); 1159 1160 ASSERT_EQ(PyDict_Next(dict, &pos, &key, &value), 1); 1161 ASSERT_EQ(PyErr_Occurred(), nullptr); 1162 EXPECT_EQ(key, three); 1163 EXPECT_EQ(value, four); 1164 1165 ASSERT_EQ(PyDict_Next(dict, &pos, &key, &value), 0); 1166 ASSERT_EQ(PyErr_Occurred(), nullptr); 1167} 1168 1169TEST_F(DictExtensionApiTest, NextAcceptsNullKeyPointer) { 1170 PyObjectPtr dict(PyDict_New()); 1171 PyObjectPtr one(PyLong_FromLong(1)); 1172 PyObjectPtr two(PyLong_FromLong(2)); 1173 PyDict_SetItem(dict, one, two); 1174 PyObjectPtr three(PyLong_FromLong(3)); 1175 PyObjectPtr four(PyLong_FromLong(4)); 1176 PyDict_SetItem(dict, three, four); 1177 1178 Py_ssize_t pos = 0; 1179 PyObject* value = nullptr; 1180 ASSERT_EQ(PyDict_Next(dict, &pos, nullptr, &value), 1); 1181 ASSERT_EQ(PyErr_Occurred(), nullptr); 1182} 1183 1184TEST_F(DictExtensionApiTest, NextAcceptsNullValuePointer) { 1185 PyObjectPtr dict(PyDict_New()); 1186 PyObjectPtr one(PyLong_FromLong(1)); 1187 PyObjectPtr two(PyLong_FromLong(2)); 1188 PyDict_SetItem(dict, one, two); 1189 PyObjectPtr three(PyLong_FromLong(3)); 1190 PyObjectPtr four(PyLong_FromLong(4)); 1191 PyDict_SetItem(dict, three, four); 1192 1193 Py_ssize_t pos = 0; 1194 PyObject* key = nullptr; 1195 ASSERT_EQ(PyDict_Next(dict, &pos, &key, nullptr), 1); 1196 ASSERT_EQ(PyErr_Occurred(), nullptr); 1197} 1198 1199TEST_F(DictExtensionApiTest, UnderNextWithEmptyDictReturnsFalse) { 1200 PyObject* key = nullptr; 1201 PyObject* value = nullptr; 1202 Py_hash_t hash = 0; 1203 Py_ssize_t pos = 0; 1204 PyObjectPtr dict(PyDict_New()); 1205 EXPECT_EQ(_PyDict_Next(dict, &pos, &key, &value, &hash), 0); 1206 ASSERT_EQ(PyErr_Occurred(), nullptr); 1207} 1208 1209TEST_F(DictExtensionApiTest, UnderNextWithNonEmptyDictReturnsKeysAndValues) { 1210 PyObjectPtr dict(PyDict_New()); 1211 PyObjectPtr one(PyLong_FromLong(1)); 1212 PyObjectPtr two(PyLong_FromLong(2)); 1213 PyDict_SetItem(dict, one, two); 1214 PyObjectPtr three(PyLong_FromLong(3)); 1215 PyObjectPtr four(PyLong_FromLong(4)); 1216 PyDict_SetItem(dict, three, four); 1217 1218 Py_ssize_t pos = 0; 1219 PyObject* key = nullptr; 1220 PyObject* value = nullptr; 1221 Py_hash_t hash = 0; 1222 ASSERT_EQ(_PyDict_Next(dict, &pos, &key, &value, &hash), 1); 1223 ASSERT_EQ(PyErr_Occurred(), nullptr); 1224 EXPECT_EQ(key, one); 1225 EXPECT_EQ(value, two); 1226 EXPECT_EQ(hash, 1); 1227 1228 ASSERT_EQ(_PyDict_Next(dict, &pos, &key, &value, &hash), 1); 1229 ASSERT_EQ(PyErr_Occurred(), nullptr); 1230 EXPECT_EQ(key, three); 1231 EXPECT_EQ(value, four); 1232 EXPECT_EQ(hash, 3); 1233 1234 ASSERT_EQ(_PyDict_Next(dict, &pos, &key, &value, &hash), 0); 1235 ASSERT_EQ(PyErr_Occurred(), nullptr); 1236} 1237 1238TEST_F(DictExtensionApiTest, UnderNextAcceptsNullKeyPointer) { 1239 PyObjectPtr dict(PyDict_New()); 1240 PyObjectPtr one(PyLong_FromLong(1)); 1241 PyObjectPtr two(PyLong_FromLong(2)); 1242 PyDict_SetItem(dict, one, two); 1243 PyObjectPtr three(PyLong_FromLong(3)); 1244 PyObjectPtr four(PyLong_FromLong(4)); 1245 PyDict_SetItem(dict, three, four); 1246 1247 Py_ssize_t pos = 0; 1248 PyObject* value = nullptr; 1249 Py_hash_t hash = 0; 1250 ASSERT_EQ(_PyDict_Next(dict, &pos, nullptr, &value, &hash), 1); 1251 ASSERT_EQ(PyErr_Occurred(), nullptr); 1252} 1253 1254TEST_F(DictExtensionApiTest, UnderNextAcceptsNullValuePointer) { 1255 PyObjectPtr dict(PyDict_New()); 1256 PyObjectPtr one(PyLong_FromLong(1)); 1257 PyObjectPtr two(PyLong_FromLong(2)); 1258 PyDict_SetItem(dict, one, two); 1259 PyObjectPtr three(PyLong_FromLong(3)); 1260 PyObjectPtr four(PyLong_FromLong(4)); 1261 PyDict_SetItem(dict, three, four); 1262 1263 Py_ssize_t pos = 0; 1264 PyObject* key = nullptr; 1265 Py_hash_t hash = 0; 1266 ASSERT_EQ(_PyDict_Next(dict, &pos, &key, nullptr, &hash), 1); 1267 ASSERT_EQ(PyErr_Occurred(), nullptr); 1268} 1269 1270TEST_F(DictExtensionApiTest, UnderNextAcceptsNullHashPointer) { 1271 PyObjectPtr dict(PyDict_New()); 1272 PyObjectPtr one(PyLong_FromLong(1)); 1273 PyObjectPtr two(PyLong_FromLong(2)); 1274 PyDict_SetItem(dict, one, two); 1275 PyObjectPtr three(PyLong_FromLong(3)); 1276 PyObjectPtr four(PyLong_FromLong(4)); 1277 PyDict_SetItem(dict, three, four); 1278 1279 Py_ssize_t pos = 0; 1280 PyObject* key = nullptr; 1281 PyObject* value = nullptr; 1282 ASSERT_EQ(_PyDict_Next(dict, &pos, &key, &value, nullptr), 1); 1283 ASSERT_EQ(PyErr_Occurred(), nullptr); 1284} 1285 1286TEST_F(DictExtensionApiTest, CopyWithNullRaisesSystemError) { 1287 EXPECT_EQ(PyDict_Copy(nullptr), nullptr); 1288 ASSERT_NE(PyErr_Occurred(), nullptr); 1289 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 1290} 1291 1292TEST_F(DictExtensionApiTest, CopyWithNonDictInstanceRaisesSystemError) { 1293 EXPECT_EQ(PyDict_Copy(Py_None), nullptr); 1294 ASSERT_NE(PyErr_Occurred(), nullptr); 1295 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 1296} 1297 1298TEST_F(DictExtensionApiTest, CopyMakesShallowCopyOfDictElements) { 1299 PyObjectPtr dict(PyDict_New()); 1300 PyObjectPtr one(PyLong_FromLong(1)); 1301 PyObjectPtr val1(PyTuple_New(0)); 1302 PyDict_SetItem(dict, one, val1); 1303 PyObjectPtr three(PyLong_FromLong(3)); 1304 PyObjectPtr val2(PyTuple_New(0)); 1305 PyDict_SetItem(dict, three, val2); 1306 1307 PyObjectPtr copy(PyDict_Copy(dict)); 1308 ASSERT_NE(copy, nullptr); 1309 ASSERT_EQ(PyErr_Occurred(), nullptr); 1310 ASSERT_TRUE(PyDict_CheckExact(copy)); 1311 EXPECT_EQ(PyDict_Size(copy), 2); 1312 EXPECT_EQ(PyDict_GetItem(copy, one), val1); 1313 EXPECT_EQ(PyDict_GetItem(copy, three), val2); 1314} 1315 1316TEST_F(DictExtensionApiTest, MergeWithNullLhsRaisesSystemError) { 1317 PyObjectPtr rhs(PyDict_New()); 1318 ASSERT_EQ(PyDict_Merge(nullptr, rhs, 0), -1); 1319 ASSERT_NE(PyErr_Occurred(), nullptr); 1320 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 1321} 1322 1323TEST_F(DictExtensionApiTest, MergeWithNonDictLhsRaisesSystemError) { 1324 PyObjectPtr rhs(PyDict_New()); 1325 ASSERT_EQ(PyDict_Merge(Py_None, rhs, 0), -1); 1326 ASSERT_NE(PyErr_Occurred(), nullptr); 1327 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 1328} 1329 1330TEST_F(DictExtensionApiTest, MergeWithNullRhsRaisesSystemError) { 1331 PyObjectPtr lhs(PyDict_New()); 1332 ASSERT_EQ(PyDict_Merge(lhs, nullptr, 0), -1); 1333 ASSERT_NE(PyErr_Occurred(), nullptr); 1334 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 1335} 1336 1337TEST_F(DictExtensionApiTest, MergeAddsKeysToLhs) { 1338 PyObjectPtr rhs(PyDict_New()); 1339 PyObjectPtr one(PyLong_FromLong(1)); 1340 PyObjectPtr two(PyLong_FromLong(2)); 1341 PyDict_SetItem(rhs, one, two); 1342 PyObjectPtr three(PyLong_FromLong(3)); 1343 PyObjectPtr four(PyLong_FromLong(4)); 1344 PyDict_SetItem(rhs, three, four); 1345 1346 PyObjectPtr lhs(PyDict_New()); 1347 ASSERT_EQ(PyDict_Merge(lhs, rhs, 0), 0); 1348 ASSERT_EQ(PyErr_Occurred(), nullptr); 1349 EXPECT_EQ(PyDict_Size(lhs), 2); 1350 1351 EXPECT_TRUE(PyDict_Contains(lhs, one)); 1352 EXPECT_EQ(PyDict_GetItem(lhs, one), two); 1353 1354 EXPECT_TRUE(PyDict_Contains(lhs, three)); 1355 EXPECT_EQ(PyDict_GetItem(lhs, three), four); 1356} 1357 1358TEST_F(DictExtensionApiTest, MergeWithoutOverrideIgnoresKeys) { 1359 PyObjectPtr lhs(PyDict_New()); 1360 PyObjectPtr rhs(PyDict_New()); 1361 PyObjectPtr one(PyLong_FromLong(1)); 1362 PyObjectPtr two(PyLong_FromLong(2)); 1363 PyDict_SetItem(lhs, one, two); 1364 PyDict_SetItem(rhs, one, two); 1365 PyObjectPtr three(PyLong_FromLong(3)); 1366 PyObjectPtr four(PyLong_FromLong(4)); 1367 PyDict_SetItem(rhs, three, four); 1368 PyObjectPtr not_in_rhs(PyLong_FromLong(666)); 1369 PyDict_SetItem(lhs, three, not_in_rhs); 1370 1371 ASSERT_EQ(PyDict_Merge(lhs, rhs, 0), 0); 1372 ASSERT_EQ(PyErr_Occurred(), nullptr); 1373 EXPECT_EQ(PyDict_Size(lhs), 2); 1374 EXPECT_EQ(PyDict_GetItem(lhs, one), two); 1375 EXPECT_EQ(PyDict_GetItem(lhs, three), not_in_rhs); 1376} 1377 1378TEST_F(DictExtensionApiTest, MergeWithOverrideReplacesKeys) { 1379 PyObjectPtr lhs(PyDict_New()); 1380 PyObjectPtr rhs(PyDict_New()); 1381 PyObjectPtr one(PyLong_FromLong(1)); 1382 PyObjectPtr two(PyLong_FromLong(2)); 1383 PyDict_SetItem(lhs, one, two); 1384 PyDict_SetItem(rhs, one, two); 1385 PyObjectPtr three(PyLong_FromLong(3)); 1386 PyObjectPtr four(PyLong_FromLong(4)); 1387 PyDict_SetItem(rhs, three, four); 1388 PyObjectPtr not_in_rhs(PyLong_FromLong(666)); 1389 PyDict_SetItem(lhs, three, not_in_rhs); 1390 1391 ASSERT_EQ(PyDict_Merge(lhs, rhs, 1), 0); 1392 ASSERT_EQ(PyErr_Occurred(), nullptr); 1393 EXPECT_EQ(PyDict_Size(lhs), 2); 1394 1395 EXPECT_TRUE(PyDict_Contains(lhs, one)); 1396 EXPECT_EQ(PyDict_GetItem(lhs, one), two); 1397 1398 EXPECT_TRUE(PyDict_Contains(lhs, three)); 1399 EXPECT_EQ(PyDict_GetItem(lhs, three), four); 1400} 1401 1402TEST_F(DictExtensionApiTest, MergeWithNonMappingRaisesAttributeError) { 1403 PyRun_SimpleString(R"( 1404class Mapping: 1405 pass 1406m = Mapping() 1407)"); 1408 PyObjectPtr rhs(mainModuleGet("m")); 1409 PyObjectPtr lhs(PyDict_New()); 1410 ASSERT_EQ(PyDict_Merge(lhs, rhs, 0), -1); 1411 ASSERT_NE(PyErr_Occurred(), nullptr); 1412 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError)); 1413} 1414 1415TEST_F(DictExtensionApiTest, MergeWithMappingRhsAddsKeysToLhs) { 1416 PyRun_SimpleString(R"( 1417class Mapping: 1418 def __init__(self): 1419 self.d = {1:2, 3:4} 1420 def keys(self): 1421 return self.d.keys() 1422 def __getitem__(self, i): 1423 return self.d[i] 1424m = Mapping() 1425)"); 1426 PyObjectPtr rhs(mainModuleGet("m")); 1427 PyObjectPtr lhs(PyDict_New()); 1428 ASSERT_EQ(PyDict_Merge(lhs, rhs, 0), 0); 1429 ASSERT_EQ(PyErr_Occurred(), nullptr); 1430 EXPECT_EQ(PyDict_Size(lhs), 2); 1431 1432 PyObjectPtr one(PyLong_FromLong(1)); 1433 EXPECT_TRUE(PyDict_Contains(lhs, one)); 1434 PyObject* two = PyDict_GetItem(lhs, one); 1435 EXPECT_EQ(PyLong_AsLong(two), 2); 1436 1437 PyObjectPtr three(PyLong_FromLong(3)); 1438 EXPECT_TRUE(PyDict_Contains(lhs, three)); 1439 PyObject* four = PyDict_GetItem(lhs, three); 1440 EXPECT_EQ(PyLong_AsLong(four), 4); 1441} 1442 1443TEST_F(DictExtensionApiTest, UpdateWithNullLhsRaisesSystemError) { 1444 PyObjectPtr rhs(PyDict_New()); 1445 ASSERT_EQ(PyDict_Update(nullptr, rhs), -1); 1446 ASSERT_NE(PyErr_Occurred(), nullptr); 1447 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 1448} 1449 1450TEST_F(DictExtensionApiTest, UpdateWithNonListLhsRaisesSystemError) { 1451 PyObjectPtr rhs(PyDict_New()); 1452 ASSERT_EQ(PyDict_Update(Py_None, rhs), -1); 1453 ASSERT_NE(PyErr_Occurred(), nullptr); 1454 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 1455} 1456 1457TEST_F(DictExtensionApiTest, UpdateWithNullRhsRaisesSystemError) { 1458 PyObjectPtr lhs(PyDict_New()); 1459 ASSERT_EQ(PyDict_Update(lhs, nullptr), -1); 1460 ASSERT_NE(PyErr_Occurred(), nullptr); 1461 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_SystemError)); 1462} 1463 1464TEST_F(DictExtensionApiTest, UpdateWithLhsEqualRhsDoesNothing) { 1465 PyObjectPtr lhs(PyDict_New()); 1466 PyObject* rhs = lhs; 1467 ASSERT_EQ(PyDict_Update(lhs, rhs), 0); 1468 ASSERT_EQ(PyErr_Occurred(), nullptr); 1469 EXPECT_EQ(lhs, rhs); 1470} 1471 1472TEST_F(DictExtensionApiTest, UpdateWithEmptyRhsDoesNothing) { 1473 PyObjectPtr lhs(PyDict_New()); 1474 1475 PyObjectPtr one(PyLong_FromLong(1)); 1476 PyObjectPtr two(PyLong_FromLong(2)); 1477 PyDict_SetItem(lhs, one, two); 1478 PyObjectPtr three(PyLong_FromLong(3)); 1479 PyObjectPtr four(PyLong_FromLong(4)); 1480 PyDict_SetItem(lhs, three, four); 1481 ASSERT_EQ(PyDict_Size(lhs), 2); 1482 1483 PyObjectPtr rhs(PyDict_New()); 1484 ASSERT_EQ(PyDict_Update(lhs, rhs), 0); 1485 ASSERT_EQ(PyErr_Occurred(), nullptr); 1486 EXPECT_EQ(PyDict_Size(lhs), 2); 1487 EXPECT_EQ(PyDict_GetItem(lhs, one), two); 1488 EXPECT_EQ(PyDict_GetItem(lhs, three), four); 1489} 1490 1491TEST_F(DictExtensionApiTest, UpdateWithEmptyLhsAddsKeysToLhs) { 1492 PyObjectPtr rhs(PyDict_New()); 1493 PyObjectPtr one(PyLong_FromLong(1)); 1494 PyObjectPtr two(PyLong_FromLong(2)); 1495 PyDict_SetItem(rhs, one, two); 1496 PyObjectPtr three(PyLong_FromLong(3)); 1497 PyObjectPtr four(PyLong_FromLong(4)); 1498 PyDict_SetItem(rhs, three, four); 1499 ASSERT_EQ(PyDict_Size(rhs), 2); 1500 1501 PyObjectPtr lhs(PyDict_New()); 1502 ASSERT_EQ(PyDict_Update(lhs, rhs), 0); 1503 ASSERT_EQ(PyErr_Occurred(), nullptr); 1504 EXPECT_EQ(PyDict_Size(lhs), 2); 1505 1506 EXPECT_TRUE(PyDict_Contains(lhs, one)); 1507 EXPECT_EQ(PyDict_GetItem(lhs, one), two); 1508 EXPECT_TRUE(PyDict_Contains(lhs, three)); 1509 EXPECT_EQ(PyDict_GetItem(lhs, three), four); 1510} 1511 1512TEST_F(DictExtensionApiTest, UpdateOverwritesKeys) { 1513 PyObjectPtr rhs(PyDict_New()); 1514 PyObjectPtr one(PyLong_FromLong(1)); 1515 PyObjectPtr two(PyLong_FromLong(2)); 1516 PyDict_SetItem(rhs, one, two); 1517 PyObjectPtr three(PyLong_FromLong(3)); 1518 PyObjectPtr four(PyLong_FromLong(4)); 1519 PyDict_SetItem(rhs, three, four); 1520 ASSERT_EQ(PyDict_Size(rhs), 2); 1521 1522 PyObjectPtr lhs(PyDict_New()); 1523 PyObjectPtr not_in_rhs(PyLong_FromLong(666)); 1524 ASSERT_EQ(PyDict_SetItem(lhs, one, not_in_rhs), 0); 1525 ASSERT_EQ(PyDict_GetItem(lhs, one), not_in_rhs); 1526 1527 ASSERT_EQ(PyDict_Update(lhs, rhs), 0); 1528 ASSERT_EQ(PyErr_Occurred(), nullptr); 1529 EXPECT_EQ(PyDict_Size(lhs), 2); 1530 1531 EXPECT_TRUE(PyDict_Contains(lhs, one)); 1532 EXPECT_EQ(PyDict_GetItem(lhs, one), two); 1533 1534 EXPECT_TRUE(PyDict_Contains(lhs, three)); 1535 EXPECT_EQ(PyDict_GetItem(lhs, three), four); 1536} 1537 1538TEST_F(DictExtensionApiTest, 1539 ObjectGenericGetDictWithInstanceRaisesAttributeError) { 1540 PyObjectPtr obj(PyLong_FromLong(0)); 1541 ASSERT_EQ(PyObject_GenericGetDict(obj, nullptr), nullptr); 1542 ASSERT_NE(PyErr_Occurred(), nullptr); 1543 EXPECT_TRUE(PyErr_ExceptionMatches(PyExc_AttributeError)); 1544} 1545 1546TEST_F(DictExtensionApiTest, ObjectGenericGetDictWithTypeReturnsTypeDict) { 1547 PyObject* obj = reinterpret_cast<PyObject*>(&PyLong_Type); 1548 PyObjectPtr dict(PyObject_GenericGetDict(obj, nullptr)); 1549 ASSERT_TRUE(PyMapping_Check(dict)); 1550 EXPECT_GT(PyMapping_Length(dict), 0); 1551} 1552 1553} // namespace testing 1554} // namespace py