1import math 2import sys 3import unittest 4import platform 5 6from pygame import Rect, Vector2, get_sdl_version 7from pygame.tests import test_utils 8 9 10PY3 = sys.version_info >= (3, 0, 0) 11SDL1 = get_sdl_version()[0] < 2 12IS_PYPY = "PyPy" == platform.python_implementation() 13 14 15class RectTypeTest(unittest.TestCase): 16 def _assertCountEqual(self, *args, **kwargs): 17 # Handle method name differences between Python versions. 18 if PY3: 19 self.assertCountEqual(*args, **kwargs) 20 else: 21 self.assertItemsEqual(*args, **kwargs) 22 23 def testConstructionXYWidthHeight(self): 24 r = Rect(1, 2, 3, 4) 25 self.assertEqual(1, r.left) 26 self.assertEqual(2, r.top) 27 self.assertEqual(3, r.width) 28 self.assertEqual(4, r.height) 29 30 def testConstructionTopLeftSize(self): 31 r = Rect((1, 2), (3, 4)) 32 self.assertEqual(1, r.left) 33 self.assertEqual(2, r.top) 34 self.assertEqual(3, r.width) 35 self.assertEqual(4, r.height) 36 37 def testCalculatedAttributes(self): 38 r = Rect(1, 2, 3, 4) 39 40 self.assertEqual(r.left + r.width, r.right) 41 self.assertEqual(r.top + r.height, r.bottom) 42 self.assertEqual((r.width, r.height), r.size) 43 self.assertEqual((r.left, r.top), r.topleft) 44 self.assertEqual((r.right, r.top), r.topright) 45 self.assertEqual((r.left, r.bottom), r.bottomleft) 46 self.assertEqual((r.right, r.bottom), r.bottomright) 47 48 midx = r.left + r.width // 2 49 midy = r.top + r.height // 2 50 51 self.assertEqual(midx, r.centerx) 52 self.assertEqual(midy, r.centery) 53 self.assertEqual((r.centerx, r.centery), r.center) 54 self.assertEqual((r.centerx, r.top), r.midtop) 55 self.assertEqual((r.centerx, r.bottom), r.midbottom) 56 self.assertEqual((r.left, r.centery), r.midleft) 57 self.assertEqual((r.right, r.centery), r.midright) 58 59 def test_normalize(self): 60 """Ensures normalize works when width and height are both negative.""" 61 test_rect = Rect((1, 2), (-3, -6)) 62 expected_normalized_rect = ( 63 (test_rect.x + test_rect.w, test_rect.y + test_rect.h), 64 (-test_rect.w, -test_rect.h), 65 ) 66 67 test_rect.normalize() 68 69 self.assertEqual(test_rect, expected_normalized_rect) 70 71 @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") 72 def test_normalize__positive_height(self): 73 """Ensures normalize works with a negative width and a positive height. 74 """ 75 test_rect = Rect((1, 2), (-3, 6)) 76 expected_normalized_rect = ( 77 (test_rect.x + test_rect.w, test_rect.y), 78 (-test_rect.w, test_rect.h), 79 ) 80 81 test_rect.normalize() 82 83 self.assertEqual(test_rect, expected_normalized_rect) 84 85 @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") 86 def test_normalize__positive_width(self): 87 """Ensures normalize works with a positive width and a negative height. 88 """ 89 test_rect = Rect((1, 2), (3, -6)) 90 expected_normalized_rect = ( 91 (test_rect.x, test_rect.y + test_rect.h), 92 (test_rect.w, -test_rect.h), 93 ) 94 95 test_rect.normalize() 96 97 self.assertEqual(test_rect, expected_normalized_rect) 98 99 @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") 100 def test_normalize__zero_height(self): 101 """Ensures normalize works with a negative width and a zero height.""" 102 test_rect = Rect((1, 2), (-3, 0)) 103 expected_normalized_rect = ( 104 (test_rect.x + test_rect.w, test_rect.y), 105 (-test_rect.w, test_rect.h), 106 ) 107 108 test_rect.normalize() 109 110 self.assertEqual(test_rect, expected_normalized_rect) 111 112 @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") 113 def test_normalize__zero_width(self): 114 """Ensures normalize works with a zero width and a negative height.""" 115 test_rect = Rect((1, 2), (0, -6)) 116 expected_normalized_rect = ( 117 (test_rect.x, test_rect.y + test_rect.h), 118 (test_rect.w, -test_rect.h), 119 ) 120 121 test_rect.normalize() 122 123 self.assertEqual(test_rect, expected_normalized_rect) 124 125 @unittest.skipIf(IS_PYPY, "fails on pypy") 126 def test_normalize__non_negative(self): 127 """Ensures normalize works when width and height are both non-negative. 128 129 Tests combinations of positive and zero values for width and height. 130 The normalize method has no impact when both width and height are 131 non-negative. 132 """ 133 for size in ((3, 6), (3, 0), (0, 6), (0, 0)): 134 test_rect = Rect((1, 2), size) 135 expected_normalized_rect = Rect(test_rect) 136 137 test_rect.normalize() 138 139 self.assertEqual(test_rect, expected_normalized_rect) 140 141 def test_x(self): 142 """Ensures changing the x attribute moves the rect and does not change 143 the rect's size. 144 """ 145 expected_x = 10 146 expected_y = 2 147 expected_size = (3, 4) 148 r = Rect((1, expected_y), expected_size) 149 150 r.x = expected_x 151 152 self.assertEqual(r.x, expected_x) 153 self.assertEqual(r.x, r.left) 154 self.assertEqual(r.y, expected_y) 155 self.assertEqual(r.size, expected_size) 156 157 def test_x__invalid_value(self): 158 """Ensures the x attribute handles invalid values correctly.""" 159 r = Rect(0, 0, 1, 1) 160 161 for value in (None, [], "1", (1,), [1, 2, 3]): 162 with self.assertRaises(TypeError): 163 r.x = value 164 165 def test_x__del(self): 166 """Ensures the x attribute can't be deleted.""" 167 r = Rect(0, 0, 1, 1) 168 169 with self.assertRaises(AttributeError): 170 del r.x 171 172 def test_y(self): 173 """Ensures changing the y attribute moves the rect and does not change 174 the rect's size. 175 """ 176 expected_x = 1 177 expected_y = 20 178 expected_size = (3, 4) 179 r = Rect((expected_x, 2), expected_size) 180 181 r.y = expected_y 182 183 self.assertEqual(r.y, expected_y) 184 self.assertEqual(r.y, r.top) 185 self.assertEqual(r.x, expected_x) 186 self.assertEqual(r.size, expected_size) 187 188 def test_y__invalid_value(self): 189 """Ensures the y attribute handles invalid values correctly.""" 190 r = Rect(0, 0, 1, 1) 191 192 for value in (None, [], "1", (1,), [1, 2, 3]): 193 with self.assertRaises(TypeError): 194 r.y = value 195 196 def test_y__del(self): 197 """Ensures the y attribute can't be deleted.""" 198 r = Rect(0, 0, 1, 1) 199 200 with self.assertRaises(AttributeError): 201 del r.y 202 203 def test_left(self): 204 """Changing the left attribute moves the rect and does not change 205 the rect's width 206 """ 207 r = Rect(1, 2, 3, 4) 208 new_left = 10 209 210 r.left = new_left 211 self.assertEqual(new_left, r.left) 212 self.assertEqual(Rect(new_left, 2, 3, 4), r) 213 214 def test_left__invalid_value(self): 215 """Ensures the left attribute handles invalid values correctly.""" 216 r = Rect(0, 0, 1, 1) 217 218 for value in (None, [], "1", (1,), [1, 2, 3]): 219 with self.assertRaises(TypeError): 220 r.left = value 221 222 def test_left__del(self): 223 """Ensures the left attribute can't be deleted.""" 224 r = Rect(0, 0, 1, 1) 225 226 with self.assertRaises(AttributeError): 227 del r.left 228 229 def test_right(self): 230 """Changing the right attribute moves the rect and does not change 231 the rect's width 232 """ 233 r = Rect(1, 2, 3, 4) 234 new_right = r.right + 20 235 expected_left = r.left + 20 236 old_width = r.width 237 238 r.right = new_right 239 self.assertEqual(new_right, r.right) 240 self.assertEqual(expected_left, r.left) 241 self.assertEqual(old_width, r.width) 242 243 def test_right__invalid_value(self): 244 """Ensures the right attribute handles invalid values correctly.""" 245 r = Rect(0, 0, 1, 1) 246 247 for value in (None, [], "1", (1,), [1, 2, 3]): 248 with self.assertRaises(TypeError): 249 r.right = value 250 251 def test_right__del(self): 252 """Ensures the right attribute can't be deleted.""" 253 r = Rect(0, 0, 1, 1) 254 255 with self.assertRaises(AttributeError): 256 del r.right 257 258 def test_top(self): 259 """Changing the top attribute moves the rect and does not change 260 the rect's width 261 """ 262 r = Rect(1, 2, 3, 4) 263 new_top = 10 264 265 r.top = new_top 266 self.assertEqual(Rect(1, new_top, 3, 4), r) 267 self.assertEqual(new_top, r.top) 268 269 def test_top__invalid_value(self): 270 """Ensures the top attribute handles invalid values correctly.""" 271 r = Rect(0, 0, 1, 1) 272 273 for value in (None, [], "1", (1,), [1, 2, 3]): 274 with self.assertRaises(TypeError): 275 r.top = value 276 277 def test_top__del(self): 278 """Ensures the top attribute can't be deleted.""" 279 r = Rect(0, 0, 1, 1) 280 281 with self.assertRaises(AttributeError): 282 del r.top 283 284 def test_bottom(self): 285 """Changing the bottom attribute moves the rect and does not change 286 the rect's height 287 """ 288 r = Rect(1, 2, 3, 4) 289 new_bottom = r.bottom + 20 290 expected_top = r.top + 20 291 old_height = r.height 292 293 r.bottom = new_bottom 294 self.assertEqual(new_bottom, r.bottom) 295 self.assertEqual(expected_top, r.top) 296 self.assertEqual(old_height, r.height) 297 298 def test_bottom__invalid_value(self): 299 """Ensures the bottom attribute handles invalid values correctly.""" 300 r = Rect(0, 0, 1, 1) 301 302 for value in (None, [], "1", (1,), [1, 2, 3]): 303 with self.assertRaises(TypeError): 304 r.bottom = value 305 306 def test_bottom__del(self): 307 """Ensures the bottom attribute can't be deleted.""" 308 r = Rect(0, 0, 1, 1) 309 310 with self.assertRaises(AttributeError): 311 del r.bottom 312 313 def test_centerx(self): 314 """Changing the centerx attribute moves the rect and does not change 315 the rect's width 316 """ 317 r = Rect(1, 2, 3, 4) 318 new_centerx = r.centerx + 20 319 expected_left = r.left + 20 320 old_width = r.width 321 322 r.centerx = new_centerx 323 self.assertEqual(new_centerx, r.centerx) 324 self.assertEqual(expected_left, r.left) 325 self.assertEqual(old_width, r.width) 326 327 def test_centerx__invalid_value(self): 328 """Ensures the centerx attribute handles invalid values correctly.""" 329 r = Rect(0, 0, 1, 1) 330 331 for value in (None, [], "1", (1,), [1, 2, 3]): 332 with self.assertRaises(TypeError): 333 r.centerx = value 334 335 def test_centerx__del(self): 336 """Ensures the centerx attribute can't be deleted.""" 337 r = Rect(0, 0, 1, 1) 338 339 with self.assertRaises(AttributeError): 340 del r.centerx 341 342 def test_centery(self): 343 """Changing the centery attribute moves the rect and does not change 344 the rect's width 345 """ 346 r = Rect(1, 2, 3, 4) 347 new_centery = r.centery + 20 348 expected_top = r.top + 20 349 old_height = r.height 350 351 r.centery = new_centery 352 self.assertEqual(new_centery, r.centery) 353 self.assertEqual(expected_top, r.top) 354 self.assertEqual(old_height, r.height) 355 356 def test_centery__invalid_value(self): 357 """Ensures the centery attribute handles invalid values correctly.""" 358 r = Rect(0, 0, 1, 1) 359 360 for value in (None, [], "1", (1,), [1, 2, 3]): 361 with self.assertRaises(TypeError): 362 r.centery = value 363 364 def test_centery__del(self): 365 """Ensures the centery attribute can't be deleted.""" 366 r = Rect(0, 0, 1, 1) 367 368 with self.assertRaises(AttributeError): 369 del r.centery 370 371 def test_topleft(self): 372 """Changing the topleft attribute moves the rect and does not change 373 the rect's size 374 """ 375 r = Rect(1, 2, 3, 4) 376 new_topleft = (r.left + 20, r.top + 30) 377 old_size = r.size 378 379 r.topleft = new_topleft 380 self.assertEqual(new_topleft, r.topleft) 381 self.assertEqual(old_size, r.size) 382 383 def test_topleft__invalid_value(self): 384 """Ensures the topleft attribute handles invalid values correctly.""" 385 r = Rect(0, 0, 1, 1) 386 387 for value in (None, [], "1", 1, (1,), [1, 2, 3]): 388 with self.assertRaises(TypeError): 389 r.topleft = value 390 391 def test_topleft__del(self): 392 """Ensures the topleft attribute can't be deleted.""" 393 r = Rect(0, 0, 1, 1) 394 395 with self.assertRaises(AttributeError): 396 del r.topleft 397 398 def test_bottomleft(self): 399 """Changing the bottomleft attribute moves the rect and does not change 400 the rect's size 401 """ 402 r = Rect(1, 2, 3, 4) 403 new_bottomleft = (r.left + 20, r.bottom + 30) 404 expected_topleft = (r.left + 20, r.top + 30) 405 old_size = r.size 406 407 r.bottomleft = new_bottomleft 408 self.assertEqual(new_bottomleft, r.bottomleft) 409 self.assertEqual(expected_topleft, r.topleft) 410 self.assertEqual(old_size, r.size) 411 412 def test_bottomleft__invalid_value(self): 413 """Ensures the bottomleft attribute handles invalid values correctly. 414 """ 415 r = Rect(0, 0, 1, 1) 416 417 for value in (None, [], "1", 1, (1,), [1, 2, 3]): 418 with self.assertRaises(TypeError): 419 r.bottomleft = value 420 421 def test_bottomleft__del(self): 422 """Ensures the bottomleft attribute can't be deleted.""" 423 r = Rect(0, 0, 1, 1) 424 425 with self.assertRaises(AttributeError): 426 del r.bottomleft 427 428 def test_topright(self): 429 """Changing the topright attribute moves the rect and does not change 430 the rect's size 431 """ 432 r = Rect(1, 2, 3, 4) 433 new_topright = (r.right + 20, r.top + 30) 434 expected_topleft = (r.left + 20, r.top + 30) 435 old_size = r.size 436 437 r.topright = new_topright 438 self.assertEqual(new_topright, r.topright) 439 self.assertEqual(expected_topleft, r.topleft) 440 self.assertEqual(old_size, r.size) 441 442 def test_topright__invalid_value(self): 443 """Ensures the topright attribute handles invalid values correctly.""" 444 r = Rect(0, 0, 1, 1) 445 446 for value in (None, [], "1", 1, (1,), [1, 2, 3]): 447 with self.assertRaises(TypeError): 448 r.topright = value 449 450 def test_topright__del(self): 451 """Ensures the topright attribute can't be deleted.""" 452 r = Rect(0, 0, 1, 1) 453 454 with self.assertRaises(AttributeError): 455 del r.topright 456 457 def test_bottomright(self): 458 """Changing the bottomright attribute moves the rect and does not change 459 the rect's size 460 """ 461 r = Rect(1, 2, 3, 4) 462 new_bottomright = (r.right + 20, r.bottom + 30) 463 expected_topleft = (r.left + 20, r.top + 30) 464 old_size = r.size 465 466 r.bottomright = new_bottomright 467 self.assertEqual(new_bottomright, r.bottomright) 468 self.assertEqual(expected_topleft, r.topleft) 469 self.assertEqual(old_size, r.size) 470 471 def test_bottomright__invalid_value(self): 472 """Ensures the bottomright attribute handles invalid values correctly. 473 """ 474 r = Rect(0, 0, 1, 1) 475 476 for value in (None, [], "1", 1, (1,), [1, 2, 3]): 477 with self.assertRaises(TypeError): 478 r.bottomright = value 479 480 def test_bottomright__del(self): 481 """Ensures the bottomright attribute can't be deleted.""" 482 r = Rect(0, 0, 1, 1) 483 484 with self.assertRaises(AttributeError): 485 del r.bottomright 486 487 def test_center(self): 488 """Changing the center attribute moves the rect and does not change 489 the rect's size 490 """ 491 r = Rect(1, 2, 3, 4) 492 new_center = (r.centerx + 20, r.centery + 30) 493 expected_topleft = (r.left + 20, r.top + 30) 494 old_size = r.size 495 496 r.center = new_center 497 self.assertEqual(new_center, r.center) 498 self.assertEqual(expected_topleft, r.topleft) 499 self.assertEqual(old_size, r.size) 500 501 def test_center__invalid_value(self): 502 """Ensures the center attribute handles invalid values correctly.""" 503 r = Rect(0, 0, 1, 1) 504 505 for value in (None, [], "1", 1, (1,), [1, 2, 3]): 506 with self.assertRaises(TypeError): 507 r.center = value 508 509 def test_center__del(self): 510 """Ensures the center attribute can't be deleted.""" 511 r = Rect(0, 0, 1, 1) 512 513 with self.assertRaises(AttributeError): 514 del r.center 515 516 def test_midleft(self): 517 """Changing the midleft attribute moves the rect and does not change 518 the rect's size 519 """ 520 r = Rect(1, 2, 3, 4) 521 new_midleft = (r.left + 20, r.centery + 30) 522 expected_topleft = (r.left + 20, r.top + 30) 523 old_size = r.size 524 525 r.midleft = new_midleft 526 self.assertEqual(new_midleft, r.midleft) 527 self.assertEqual(expected_topleft, r.topleft) 528 self.assertEqual(old_size, r.size) 529 530 def test_midleft__invalid_value(self): 531 """Ensures the midleft attribute handles invalid values correctly.""" 532 r = Rect(0, 0, 1, 1) 533 534 for value in (None, [], "1", 1, (1,), [1, 2, 3]): 535 with self.assertRaises(TypeError): 536 r.midleft = value 537 538 def test_midleft__del(self): 539 """Ensures the midleft attribute can't be deleted.""" 540 r = Rect(0, 0, 1, 1) 541 542 with self.assertRaises(AttributeError): 543 del r.midleft 544 545 def test_midright(self): 546 """Changing the midright attribute moves the rect and does not change 547 the rect's size 548 """ 549 r = Rect(1, 2, 3, 4) 550 new_midright = (r.right + 20, r.centery + 30) 551 expected_topleft = (r.left + 20, r.top + 30) 552 old_size = r.size 553 554 r.midright = new_midright 555 self.assertEqual(new_midright, r.midright) 556 self.assertEqual(expected_topleft, r.topleft) 557 self.assertEqual(old_size, r.size) 558 559 def test_midright__invalid_value(self): 560 """Ensures the midright attribute handles invalid values correctly.""" 561 r = Rect(0, 0, 1, 1) 562 563 for value in (None, [], "1", 1, (1,), [1, 2, 3]): 564 with self.assertRaises(TypeError): 565 r.midright = value 566 567 def test_midright__del(self): 568 """Ensures the midright attribute can't be deleted.""" 569 r = Rect(0, 0, 1, 1) 570 571 with self.assertRaises(AttributeError): 572 del r.midright 573 574 def test_midtop(self): 575 """Changing the midtop attribute moves the rect and does not change 576 the rect's size 577 """ 578 r = Rect(1, 2, 3, 4) 579 new_midtop = (r.centerx + 20, r.top + 30) 580 expected_topleft = (r.left + 20, r.top + 30) 581 old_size = r.size 582 583 r.midtop = new_midtop 584 self.assertEqual(new_midtop, r.midtop) 585 self.assertEqual(expected_topleft, r.topleft) 586 self.assertEqual(old_size, r.size) 587 588 def test_midtop__invalid_value(self): 589 """Ensures the midtop attribute handles invalid values correctly.""" 590 r = Rect(0, 0, 1, 1) 591 592 for value in (None, [], "1", 1, (1,), [1, 2, 3]): 593 with self.assertRaises(TypeError): 594 r.midtop = value 595 596 def test_midtop__del(self): 597 """Ensures the midtop attribute can't be deleted.""" 598 r = Rect(0, 0, 1, 1) 599 600 with self.assertRaises(AttributeError): 601 del r.midtop 602 603 def test_midbottom(self): 604 """Changing the midbottom attribute moves the rect and does not change 605 the rect's size 606 """ 607 r = Rect(1, 2, 3, 4) 608 new_midbottom = (r.centerx + 20, r.bottom + 30) 609 expected_topleft = (r.left + 20, r.top + 30) 610 old_size = r.size 611 612 r.midbottom = new_midbottom 613 self.assertEqual(new_midbottom, r.midbottom) 614 self.assertEqual(expected_topleft, r.topleft) 615 self.assertEqual(old_size, r.size) 616 617 def test_midbottom__invalid_value(self): 618 """Ensures the midbottom attribute handles invalid values correctly.""" 619 r = Rect(0, 0, 1, 1) 620 621 for value in (None, [], "1", 1, (1,), [1, 2, 3]): 622 with self.assertRaises(TypeError): 623 r.midbottom = value 624 625 def test_midbottom__del(self): 626 """Ensures the midbottom attribute can't be deleted.""" 627 r = Rect(0, 0, 1, 1) 628 629 with self.assertRaises(AttributeError): 630 del r.midbottom 631 632 def test_width(self): 633 """Changing the width resizes the rect from the top-left corner 634 """ 635 r = Rect(1, 2, 3, 4) 636 new_width = 10 637 old_topleft = r.topleft 638 old_height = r.height 639 640 r.width = new_width 641 self.assertEqual(new_width, r.width) 642 self.assertEqual(old_height, r.height) 643 self.assertEqual(old_topleft, r.topleft) 644 645 def test_width__invalid_value(self): 646 """Ensures the width attribute handles invalid values correctly.""" 647 r = Rect(0, 0, 1, 1) 648 649 for value in (None, [], "1", (1,), [1, 2, 3]): 650 with self.assertRaises(TypeError): 651 r.width = value 652 653 def test_width__del(self): 654 """Ensures the width attribute can't be deleted.""" 655 r = Rect(0, 0, 1, 1) 656 657 with self.assertRaises(AttributeError): 658 del r.width 659 660 def test_height(self): 661 """Changing the height resizes the rect from the top-left corner 662 """ 663 r = Rect(1, 2, 3, 4) 664 new_height = 10 665 old_topleft = r.topleft 666 old_width = r.width 667 668 r.height = new_height 669 self.assertEqual(new_height, r.height) 670 self.assertEqual(old_width, r.width) 671 self.assertEqual(old_topleft, r.topleft) 672 673 def test_height__invalid_value(self): 674 """Ensures the height attribute handles invalid values correctly.""" 675 r = Rect(0, 0, 1, 1) 676 677 for value in (None, [], "1", (1,), [1, 2, 3]): 678 with self.assertRaises(TypeError): 679 r.height = value 680 681 def test_height__del(self): 682 """Ensures the height attribute can't be deleted.""" 683 r = Rect(0, 0, 1, 1) 684 685 with self.assertRaises(AttributeError): 686 del r.height 687 688 def test_size(self): 689 """Changing the size resizes the rect from the top-left corner 690 """ 691 r = Rect(1, 2, 3, 4) 692 new_size = (10, 20) 693 old_topleft = r.topleft 694 695 r.size = new_size 696 self.assertEqual(new_size, r.size) 697 self.assertEqual(old_topleft, r.topleft) 698 699 def test_size__invalid_value(self): 700 """Ensures the size attribute handles invalid values correctly.""" 701 r = Rect(0, 0, 1, 1) 702 703 for value in (None, [], "1", 1, (1,), [1, 2, 3]): 704 with self.assertRaises(TypeError): 705 r.size = value 706 707 def test_size__del(self): 708 """Ensures the size attribute can't be deleted.""" 709 r = Rect(0, 0, 1, 1) 710 711 with self.assertRaises(AttributeError): 712 del r.size 713 714 def test_contains(self): 715 r = Rect(1, 2, 3, 4) 716 717 self.assertTrue( 718 r.contains(Rect(2, 3, 1, 1)), "r does not contain Rect(2, 3, 1, 1)" 719 ) 720 self.assertTrue( 721 r.contains(Rect(r)), "r does not contain the same rect as itself" 722 ) 723 self.assertTrue( 724 r.contains(Rect(2, 3, 0, 0)), 725 "r does not contain an empty rect within its bounds", 726 ) 727 self.assertFalse(r.contains(Rect(0, 0, 1, 2)), "r contains Rect(0, 0, 1, 2)") 728 self.assertFalse(r.contains(Rect(4, 6, 1, 1)), "r contains Rect(4, 6, 1, 1)") 729 self.assertFalse(r.contains(Rect(4, 6, 0, 0)), "r contains Rect(4, 6, 0, 0)") 730 731 def test_collidepoint(self): 732 r = Rect(1, 2, 3, 4) 733 734 self.assertTrue( 735 r.collidepoint(r.left, r.top), "r does not collide with point (left, top)" 736 ) 737 self.assertFalse( 738 r.collidepoint(r.left - 1, r.top), "r collides with point (left - 1, top)" 739 ) 740 self.assertFalse( 741 r.collidepoint(r.left, r.top - 1), "r collides with point (left, top - 1)" 742 ) 743 self.assertFalse( 744 r.collidepoint(r.left - 1, r.top - 1), 745 "r collides with point (left - 1, top - 1)", 746 ) 747 748 self.assertTrue( 749 r.collidepoint(r.right - 1, r.bottom - 1), 750 "r does not collide with point (right - 1, bottom - 1)", 751 ) 752 self.assertFalse( 753 r.collidepoint(r.right, r.bottom), "r collides with point (right, bottom)" 754 ) 755 self.assertFalse( 756 r.collidepoint(r.right - 1, r.bottom), 757 "r collides with point (right - 1, bottom)", 758 ) 759 self.assertFalse( 760 r.collidepoint(r.right, r.bottom - 1), 761 "r collides with point (right, bottom - 1)", 762 ) 763 764 def test_inflate__larger(self): 765 """The inflate method inflates around the center of the rectangle 766 """ 767 r = Rect(2, 4, 6, 8) 768 r2 = r.inflate(4, 6) 769 770 self.assertEqual(r.center, r2.center) 771 self.assertEqual(r.left - 2, r2.left) 772 self.assertEqual(r.top - 3, r2.top) 773 self.assertEqual(r.right + 2, r2.right) 774 self.assertEqual(r.bottom + 3, r2.bottom) 775 self.assertEqual(r.width + 4, r2.width) 776 self.assertEqual(r.height + 6, r2.height) 777 778 def test_inflate__smaller(self): 779 """The inflate method inflates around the center of the rectangle 780 """ 781 r = Rect(2, 4, 6, 8) 782 r2 = r.inflate(-4, -6) 783 784 self.assertEqual(r.center, r2.center) 785 self.assertEqual(r.left + 2, r2.left) 786 self.assertEqual(r.top + 3, r2.top) 787 self.assertEqual(r.right - 2, r2.right) 788 self.assertEqual(r.bottom - 3, r2.bottom) 789 self.assertEqual(r.width - 4, r2.width) 790 self.assertEqual(r.height - 6, r2.height) 791 792 def test_inflate_ip__larger(self): 793 """The inflate_ip method inflates around the center of the rectangle 794 """ 795 r = Rect(2, 4, 6, 8) 796 r2 = Rect(r) 797 r2.inflate_ip(-4, -6) 798 799 self.assertEqual(r.center, r2.center) 800 self.assertEqual(r.left + 2, r2.left) 801 self.assertEqual(r.top + 3, r2.top) 802 self.assertEqual(r.right - 2, r2.right) 803 self.assertEqual(r.bottom - 3, r2.bottom) 804 self.assertEqual(r.width - 4, r2.width) 805 self.assertEqual(r.height - 6, r2.height) 806 807 def test_inflate_ip__smaller(self): 808 """The inflate method inflates around the center of the rectangle 809 """ 810 r = Rect(2, 4, 6, 8) 811 r2 = Rect(r) 812 r2.inflate_ip(-4, -6) 813 814 self.assertEqual(r.center, r2.center) 815 self.assertEqual(r.left + 2, r2.left) 816 self.assertEqual(r.top + 3, r2.top) 817 self.assertEqual(r.right - 2, r2.right) 818 self.assertEqual(r.bottom - 3, r2.bottom) 819 self.assertEqual(r.width - 4, r2.width) 820 self.assertEqual(r.height - 6, r2.height) 821 822 def test_clamp(self): 823 r = Rect(10, 10, 10, 10) 824 c = Rect(19, 12, 5, 5).clamp(r) 825 self.assertEqual(c.right, r.right) 826 self.assertEqual(c.top, 12) 827 c = Rect(1, 2, 3, 4).clamp(r) 828 self.assertEqual(c.topleft, r.topleft) 829 c = Rect(5, 500, 22, 33).clamp(r) 830 self.assertEqual(c.center, r.center) 831 832 def test_clamp_ip(self): 833 r = Rect(10, 10, 10, 10) 834 c = Rect(19, 12, 5, 5) 835 c.clamp_ip(r) 836 self.assertEqual(c.right, r.right) 837 self.assertEqual(c.top, 12) 838 c = Rect(1, 2, 3, 4) 839 c.clamp_ip(r) 840 self.assertEqual(c.topleft, r.topleft) 841 c = Rect(5, 500, 22, 33) 842 c.clamp_ip(r) 843 self.assertEqual(c.center, r.center) 844 845 def test_clip(self): 846 r1 = Rect(1, 2, 3, 4) 847 self.assertEqual(Rect(1, 2, 2, 2), r1.clip(Rect(0, 0, 3, 4))) 848 self.assertEqual(Rect(2, 2, 2, 4), r1.clip(Rect(2, 2, 10, 20))) 849 self.assertEqual(Rect(2, 3, 1, 2), r1.clip(Rect(2, 3, 1, 2))) 850 self.assertEqual((0, 0), r1.clip(20, 30, 5, 6).size) 851 self.assertEqual( 852 r1, r1.clip(Rect(r1)), "r1 does not clip an identical rect to itself" 853 ) 854 855 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 856 def test_clipline(self): 857 """Ensures clipline handles four int parameters. 858 859 Tests the clipline(x1, y1, x2, y2) format. 860 """ 861 rect = Rect((1, 2), (35, 40)) 862 x1 = 5 863 y1 = 6 864 x2 = 11 865 y2 = 19 866 expected_line = ((x1, y1), (x2, y2)) 867 868 clipped_line = rect.clipline(x1, y1, x2, y2) 869 870 self.assertIsInstance(clipped_line, tuple) 871 self.assertTupleEqual(clipped_line, expected_line) 872 873 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 874 def test_clipline__two_sequences(self): 875 """Ensures clipline handles a sequence of two sequences. 876 877 Tests the clipline((x1, y1), (x2, y2)) format. 878 Tests the sequences as different types. 879 """ 880 rect = Rect((1, 2), (35, 40)) 881 pt1 = (5, 6) 882 pt2 = (11, 19) 883 884 INNER_SEQUENCES = (list, tuple, Vector2) 885 expected_line = (pt1, pt2) 886 887 for inner_seq1 in INNER_SEQUENCES: 888 endpt1 = inner_seq1(pt1) 889 890 for inner_seq2 in INNER_SEQUENCES: 891 clipped_line = rect.clipline((endpt1, inner_seq2(pt2))) 892 893 self.assertIsInstance(clipped_line, tuple) 894 self.assertTupleEqual(clipped_line, expected_line) 895 896 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 897 def test_clipline__sequence_of_four_ints(self): 898 """Ensures clipline handles a sequence of four ints. 899 900 Tests the clipline((x1, y1, x2, y2)) format. 901 Tests the sequence as different types. 902 """ 903 rect = Rect((1, 2), (35, 40)) 904 line = (5, 6, 11, 19) 905 expected_line = ((line[0], line[1]), (line[2], line[3])) 906 907 for outer_seq in (list, tuple): 908 clipped_line = rect.clipline(outer_seq(line)) 909 910 self.assertIsInstance(clipped_line, tuple) 911 self.assertTupleEqual(clipped_line, expected_line) 912 913 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 914 def test_clipline__sequence_of_two_sequences(self): 915 """Ensures clipline handles a sequence of two sequences. 916 917 Tests the clipline(((x1, y1), (x2, y2))) format. 918 Tests the sequences as different types. 919 """ 920 rect = Rect((1, 2), (35, 40)) 921 pt1 = (5, 6) 922 pt2 = (11, 19) 923 924 INNER_SEQUENCES = (list, tuple, Vector2) 925 expected_line = (pt1, pt2) 926 927 for inner_seq1 in INNER_SEQUENCES: 928 endpt1 = inner_seq1(pt1) 929 930 for inner_seq2 in INNER_SEQUENCES: 931 endpt2 = inner_seq2(pt2) 932 933 for outer_seq in (list, tuple): 934 clipped_line = rect.clipline(outer_seq((endpt1, endpt2))) 935 936 self.assertIsInstance(clipped_line, tuple) 937 self.assertTupleEqual(clipped_line, expected_line) 938 939 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 940 def test_clipline__floats(self): 941 """Ensures clipline handles float parameters.""" 942 rect = Rect((1, 2), (35, 40)) 943 x1 = 5.9 944 y1 = 6.9 945 x2 = 11.9 946 y2 = 19.9 947 948 # Floats are truncated. 949 expected_line = ( 950 (math.floor(x1), math.floor(y1)), 951 (math.floor(x2), math.floor(y2)), 952 ) 953 954 clipped_line = rect.clipline(x1, y1, x2, y2) 955 956 self.assertIsInstance(clipped_line, tuple) 957 self.assertTupleEqual(clipped_line, expected_line) 958 959 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 960 def test_clipline__no_overlap(self): 961 """Ensures lines that do not overlap the rect are not clipped.""" 962 rect = Rect((10, 25), (15, 20)) 963 # Use a bigger rect to help create test lines. 964 big_rect = rect.inflate(2, 2) 965 lines = ( 966 (big_rect.bottomleft, big_rect.topleft), # Left edge. 967 (big_rect.topleft, big_rect.topright), # Top edge. 968 (big_rect.topright, big_rect.bottomright), # Right edge. 969 (big_rect.bottomright, big_rect.bottomleft), 970 ) # Bottom edge. 971 expected_line = () 972 973 # Test lines outside rect. 974 for line in lines: 975 clipped_line = rect.clipline(line) 976 977 self.assertTupleEqual(clipped_line, expected_line) 978 979 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 980 def test_clipline__both_endpoints_outside(self): 981 """Ensures lines that overlap the rect are clipped. 982 983 Testing lines with both endpoints outside the rect. 984 """ 985 rect = Rect((0, 0), (20, 20)) 986 # Use a bigger rect to help create test lines. 987 big_rect = rect.inflate(2, 2) 988 989 # Create a dict of lines and expected results. 990 line_dict = { 991 (big_rect.midleft, big_rect.midright): ( 992 rect.midleft, 993 (rect.midright[0] - 1, rect.midright[1]), 994 ), 995 (big_rect.midtop, big_rect.midbottom): ( 996 rect.midtop, 997 (rect.midbottom[0], rect.midbottom[1] - 1), 998 ), 999 # Diagonals. 1000 (big_rect.topleft, big_rect.bottomright): ( 1001 rect.topleft, 1002 (rect.bottomright[0] - 1, rect.bottomright[1] - 1), 1003 ), 1004 # This line needs a small adjustment to make sure it intersects 1005 # the rect correctly. 1006 ( 1007 (big_rect.topright[0] - 1, big_rect.topright[1]), 1008 (big_rect.bottomleft[0], big_rect.bottomleft[1] - 1), 1009 ): ( 1010 (rect.topright[0] - 1, rect.topright[1]), 1011 (rect.bottomleft[0], rect.bottomleft[1] - 1), 1012 ), 1013 } 1014 1015 for line, expected_line in line_dict.items(): 1016 clipped_line = rect.clipline(line) 1017 1018 self.assertTupleEqual(clipped_line, expected_line) 1019 1020 # Swap endpoints to test for symmetry. 1021 expected_line = (expected_line[1], expected_line[0]) 1022 1023 clipped_line = rect.clipline((line[1], line[0])) 1024 1025 self.assertTupleEqual(clipped_line, expected_line) 1026 1027 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 1028 def test_clipline__both_endpoints_inside(self): 1029 """Ensures lines that overlap the rect are clipped. 1030 1031 Testing lines with both endpoints inside the rect. 1032 """ 1033 rect = Rect((-10, -5), (20, 20)) 1034 # Use a smaller rect to help create test lines. 1035 small_rect = rect.inflate(-2, -2) 1036 1037 lines = ( 1038 (small_rect.midleft, small_rect.midright), 1039 (small_rect.midtop, small_rect.midbottom), 1040 # Diagonals. 1041 (small_rect.topleft, small_rect.bottomright), 1042 (small_rect.topright, small_rect.bottomleft), 1043 ) 1044 1045 for line in lines: 1046 expected_line = line 1047 1048 clipped_line = rect.clipline(line) 1049 1050 self.assertTupleEqual(clipped_line, expected_line) 1051 1052 # Swap endpoints to test for symmetry. 1053 expected_line = (expected_line[1], expected_line[0]) 1054 1055 clipped_line = rect.clipline((line[1], line[0])) 1056 1057 self.assertTupleEqual(clipped_line, expected_line) 1058 1059 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 1060 def test_clipline__endpoints_inside_and_outside(self): 1061 """Ensures lines that overlap the rect are clipped. 1062 1063 Testing lines with one endpoint outside the rect and the other is 1064 inside the rect. 1065 """ 1066 rect = Rect((0, 0), (21, 21)) 1067 # Use a bigger rect to help create test lines. 1068 big_rect = rect.inflate(2, 2) 1069 1070 # Create a dict of lines and expected results. 1071 line_dict = { 1072 (big_rect.midleft, rect.center): (rect.midleft, rect.center), 1073 (big_rect.midtop, rect.center): (rect.midtop, rect.center), 1074 (big_rect.midright, rect.center): ( 1075 (rect.midright[0] - 1, rect.midright[1]), 1076 rect.center, 1077 ), 1078 (big_rect.midbottom, rect.center): ( 1079 (rect.midbottom[0], rect.midbottom[1] - 1), 1080 rect.center, 1081 ), 1082 # Diagonals. 1083 (big_rect.topleft, rect.center): (rect.topleft, rect.center), 1084 (big_rect.topright, rect.center): ( 1085 (rect.topright[0] - 1, rect.topright[1]), 1086 rect.center, 1087 ), 1088 (big_rect.bottomright, rect.center): ( 1089 (rect.bottomright[0] - 1, rect.bottomright[1] - 1), 1090 rect.center, 1091 ), 1092 # This line needs a small adjustment to make sure it intersects 1093 # the rect correctly. 1094 ((big_rect.bottomleft[0], big_rect.bottomleft[1] - 1), rect.center): ( 1095 (rect.bottomleft[0], rect.bottomleft[1] - 1), 1096 rect.center, 1097 ), 1098 } 1099 1100 for line, expected_line in line_dict.items(): 1101 clipped_line = rect.clipline(line) 1102 1103 self.assertTupleEqual(clipped_line, expected_line) 1104 1105 # Swap endpoints to test for symmetry. 1106 expected_line = (expected_line[1], expected_line[0]) 1107 1108 clipped_line = rect.clipline((line[1], line[0])) 1109 1110 self.assertTupleEqual(clipped_line, expected_line) 1111 1112 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 1113 def test_clipline__edges(self): 1114 """Ensures clipline properly clips line that are along the rect edges. 1115 """ 1116 rect = Rect((10, 25), (15, 20)) 1117 1118 # Create a dict of edges and expected results. 1119 edge_dict = { 1120 # Left edge. 1121 (rect.bottomleft, rect.topleft): ( 1122 (rect.bottomleft[0], rect.bottomleft[1] - 1), 1123 rect.topleft, 1124 ), 1125 # Top edge. 1126 (rect.topleft, rect.topright): ( 1127 rect.topleft, 1128 (rect.topright[0] - 1, rect.topright[1]), 1129 ), 1130 # Right edge. 1131 (rect.topright, rect.bottomright): (), 1132 # Bottom edge. 1133 (rect.bottomright, rect.bottomleft): (), 1134 } 1135 1136 for edge, expected_line in edge_dict.items(): 1137 clipped_line = rect.clipline(edge) 1138 1139 self.assertTupleEqual(clipped_line, expected_line) 1140 1141 # Swap endpoints to test for symmetry. 1142 if expected_line: 1143 expected_line = (expected_line[1], expected_line[0]) 1144 1145 clipped_line = rect.clipline((edge[1], edge[0])) 1146 1147 self.assertTupleEqual(clipped_line, expected_line) 1148 1149 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 1150 def test_clipline__equal_endpoints_with_overlap(self): 1151 """Ensures clipline handles lines with both endpoints the same. 1152 1153 Testing lines that overlap the rect. 1154 """ 1155 rect = Rect((10, 25), (15, 20)) 1156 1157 # Test all the points in and on a rect. 1158 pts = ( 1159 (x, y) 1160 for x in range(rect.left, rect.right) 1161 for y in range(rect.top, rect.bottom) 1162 ) 1163 1164 for pt in pts: 1165 expected_line = (pt, pt) 1166 1167 clipped_line = rect.clipline((pt, pt)) 1168 1169 self.assertTupleEqual(clipped_line, expected_line) 1170 1171 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 1172 def test_clipline__equal_endpoints_no_overlap(self): 1173 """Ensures clipline handles lines with both endpoints the same. 1174 1175 Testing lines that do not overlap the rect. 1176 """ 1177 expected_line = () 1178 rect = Rect((10, 25), (15, 20)) 1179 1180 # Test points outside rect. 1181 for pt in test_utils.rect_perimeter_pts(rect.inflate(2, 2)): 1182 clipped_line = rect.clipline((pt, pt)) 1183 1184 self.assertTupleEqual(clipped_line, expected_line) 1185 1186 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 1187 def test_clipline__zero_size_rect(self): 1188 """Ensures clipline handles zero sized rects correctly.""" 1189 expected_line = () 1190 1191 for size in ((0, 15), (15, 0), (0, 0)): 1192 rect = Rect((10, 25), size) 1193 1194 clipped_line = rect.clipline(rect.topleft, rect.topleft) 1195 1196 self.assertTupleEqual(clipped_line, expected_line) 1197 1198 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 1199 def test_clipline__negative_size_rect(self): 1200 """Ensures clipline handles negative sized rects correctly.""" 1201 expected_line = () 1202 1203 for size in ((-15, 20), (15, -20), (-15, -20)): 1204 rect = Rect((10, 25), size) 1205 norm_rect = rect.copy() 1206 norm_rect.normalize() 1207 # Use a bigger rect to help create test lines. 1208 big_rect = norm_rect.inflate(2, 2) 1209 1210 # Create a dict of lines and expected results. Some line have both 1211 # endpoints outside the rect and some have one inside and one 1212 # outside. 1213 line_dict = { 1214 (big_rect.midleft, big_rect.midright): ( 1215 norm_rect.midleft, 1216 (norm_rect.midright[0] - 1, norm_rect.midright[1]), 1217 ), 1218 (big_rect.midtop, big_rect.midbottom): ( 1219 norm_rect.midtop, 1220 (norm_rect.midbottom[0], norm_rect.midbottom[1] - 1), 1221 ), 1222 (big_rect.midleft, norm_rect.center): ( 1223 norm_rect.midleft, 1224 norm_rect.center, 1225 ), 1226 (big_rect.midtop, norm_rect.center): ( 1227 norm_rect.midtop, 1228 norm_rect.center, 1229 ), 1230 (big_rect.midright, norm_rect.center): ( 1231 (norm_rect.midright[0] - 1, norm_rect.midright[1]), 1232 norm_rect.center, 1233 ), 1234 (big_rect.midbottom, norm_rect.center): ( 1235 (norm_rect.midbottom[0], norm_rect.midbottom[1] - 1), 1236 norm_rect.center, 1237 ), 1238 } 1239 1240 for line, expected_line in line_dict.items(): 1241 clipped_line = rect.clipline(line) 1242 1243 # Make sure rect wasn't normalized. 1244 self.assertNotEqual(rect, norm_rect) 1245 self.assertTupleEqual(clipped_line, expected_line) 1246 1247 # Swap endpoints to test for symmetry. 1248 expected_line = (expected_line[1], expected_line[0]) 1249 1250 clipped_line = rect.clipline((line[1], line[0])) 1251 1252 self.assertTupleEqual(clipped_line, expected_line) 1253 1254 @unittest.skipIf(SDL1, "rect.clipline not available in SDL1") 1255 def test_clipline__invalid_line(self): 1256 """Ensures clipline handles invalid lines correctly.""" 1257 rect = Rect((0, 0), (10, 20)) 1258 invalid_lines = ( 1259 (), 1260 (1,), 1261 (1, 2), 1262 (1, 2, 3), 1263 (1, 2, 3, 4, 5), 1264 ((1, 2),), 1265 ((1, 2), (3,)), 1266 ((1, 2), 3), 1267 ((1, 2, 5), (3, 4)), 1268 ((1, 2), (3, 4, 5)), 1269 ((1, 2), (3, 4), (5, 6)), 1270 ) 1271 1272 for line in invalid_lines: 1273 with self.assertRaises(TypeError): 1274 clipped_line = rect.clipline(line) 1275 1276 with self.assertRaises(TypeError): 1277 clipped_line = rect.clipline(*line) 1278 1279 @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") 1280 def test_move(self): 1281 r = Rect(1, 2, 3, 4) 1282 move_x = 10 1283 move_y = 20 1284 r2 = r.move(move_x, move_y) 1285 expected_r2 = Rect(r.left + move_x, r.top + move_y, r.width, r.height) 1286 self.assertEqual(expected_r2, r2) 1287 1288 @unittest.skipIf(IS_PYPY, "fails on pypy sometimes") 1289 def test_move_ip(self): 1290 r = Rect(1, 2, 3, 4) 1291 r2 = Rect(r) 1292 move_x = 10 1293 move_y = 20 1294 r2.move_ip(move_x, move_y) 1295 expected_r2 = Rect(r.left + move_x, r.top + move_y, r.width, r.height) 1296 self.assertEqual(expected_r2, r2) 1297 1298 def test_update_XYWidthHeight(self): 1299 """Test update with 4 int values(x, y, w, h)""" 1300 rect = Rect(0, 0, 1, 1) 1301 rect.update(1, 2, 3, 4) 1302 1303 self.assertEqual(1, rect.left) 1304 self.assertEqual(2, rect.top) 1305 self.assertEqual(3, rect.width) 1306 self.assertEqual(4, rect.height) 1307 1308 def test_update__TopLeftSize(self): 1309 """Test update with 2 tuples((x, y), (w, h))""" 1310 rect = Rect(0, 0, 1, 1) 1311 rect.update((1, 2), (3, 4)) 1312 1313 self.assertEqual(1, rect.left) 1314 self.assertEqual(2, rect.top) 1315 self.assertEqual(3, rect.width) 1316 self.assertEqual(4, rect.height) 1317 1318 def test_update__List(self): 1319 """Test update with list""" 1320 rect = Rect(0, 0, 1, 1) 1321 rect2 = [1, 2, 3, 4] 1322 rect.update(rect2) 1323 1324 self.assertEqual(1, rect.left) 1325 self.assertEqual(2, rect.top) 1326 self.assertEqual(3, rect.width) 1327 self.assertEqual(4, rect.height) 1328 1329 def test_update__RectObject(self): 1330 """Test update with other rect object""" 1331 rect = Rect(0, 0, 1, 1) 1332 rect2 = Rect(1, 2, 3, 4) 1333 rect.update(rect2) 1334 1335 self.assertEqual(1, rect.left) 1336 self.assertEqual(2, rect.top) 1337 self.assertEqual(3, rect.width) 1338 self.assertEqual(4, rect.height) 1339 1340 def test_union(self): 1341 r1 = Rect(1, 1, 1, 2) 1342 r2 = Rect(-2, -2, 1, 2) 1343 self.assertEqual(Rect(-2, -2, 4, 5), r1.union(r2)) 1344 1345 def test_union__with_identical_Rect(self): 1346 r1 = Rect(1, 2, 3, 4) 1347 self.assertEqual(r1, r1.union(Rect(r1))) 1348 1349 def test_union_ip(self): 1350 r1 = Rect(1, 1, 1, 2) 1351 r2 = Rect(-2, -2, 1, 2) 1352 r1.union_ip(r2) 1353 self.assertEqual(Rect(-2, -2, 4, 5), r1) 1354 1355 def test_unionall(self): 1356 r1 = Rect(0, 0, 1, 1) 1357 r2 = Rect(-2, -2, 1, 1) 1358 r3 = Rect(2, 2, 1, 1) 1359 1360 r4 = r1.unionall([r2, r3]) 1361 self.assertEqual(Rect(-2, -2, 5, 5), r4) 1362 1363 def test_unionall__invalid_rect_format(self): 1364 """Ensures unionall correctly handles invalid rect parameters.""" 1365 numbers = [0, 1.2, 2, 3.3] 1366 strs = ["a", "b", "c"] 1367 nones = [None, None] 1368 1369 for invalid_rects in (numbers, strs, nones): 1370 with self.assertRaises(TypeError): 1371 Rect(0, 0, 1, 1).unionall(invalid_rects) 1372 1373 def test_unionall_ip(self): 1374 r1 = Rect(0, 0, 1, 1) 1375 r2 = Rect(-2, -2, 1, 1) 1376 r3 = Rect(2, 2, 1, 1) 1377 1378 r1.unionall_ip([r2, r3]) 1379 self.assertEqual(Rect(-2, -2, 5, 5), r1) 1380 1381 # Bug for an empty list. Would return a Rect instead of None. 1382 self.assertTrue(r1.unionall_ip([]) is None) 1383 1384 def test_unionall__invalid_rect_format(self): 1385 """Ensures unionall_ip correctly handles invalid rect parameters.""" 1386 numbers = [0, 1.2, 2, 3.3] 1387 strs = ["a", "b", "c"] 1388 nones = [None, None] 1389 1390 for invalid_rects in (numbers, strs, nones): 1391 with self.assertRaises(TypeError): 1392 Rect(0, 0, 1, 1).unionall_ip(invalid_rects) 1393 1394 def test_colliderect(self): 1395 r1 = Rect(1, 2, 3, 4) 1396 self.assertTrue( 1397 r1.colliderect(Rect(0, 0, 2, 3)), 1398 "r1 does not collide with Rect(0, 0, 2, 3)", 1399 ) 1400 self.assertFalse( 1401 r1.colliderect(Rect(0, 0, 1, 2)), "r1 collides with Rect(0, 0, 1, 2)" 1402 ) 1403 self.assertFalse( 1404 r1.colliderect(Rect(r1.right, r1.bottom, 2, 2)), 1405 "r1 collides with Rect(r1.right, r1.bottom, 2, 2)", 1406 ) 1407 self.assertTrue( 1408 r1.colliderect(Rect(r1.left + 1, r1.top + 1, r1.width - 2, r1.height - 2)), 1409 "r1 does not collide with Rect(r1.left + 1, r1.top + 1, " 1410 + "r1.width - 2, r1.height - 2)", 1411 ) 1412 self.assertTrue( 1413 r1.colliderect(Rect(r1.left - 1, r1.top - 1, r1.width + 2, r1.height + 2)), 1414 "r1 does not collide with Rect(r1.left - 1, r1.top - 1, " 1415 + "r1.width + 2, r1.height + 2)", 1416 ) 1417 self.assertTrue( 1418 r1.colliderect(Rect(r1)), "r1 does not collide with an identical rect" 1419 ) 1420 self.assertFalse( 1421 r1.colliderect(Rect(r1.right, r1.bottom, 0, 0)), 1422 "r1 collides with Rect(r1.right, r1.bottom, 0, 0)", 1423 ) 1424 self.assertFalse( 1425 r1.colliderect(Rect(r1.right, r1.bottom, 1, 1)), 1426 "r1 collides with Rect(r1.right, r1.bottom, 1, 1)", 1427 ) 1428 1429 @unittest.skipIf(IS_PYPY, "fails on pypy3 sometimes") 1430 def testEquals(self): 1431 """ check to see how the rect uses __eq__ 1432 """ 1433 r1 = Rect(1, 2, 3, 4) 1434 r2 = Rect(10, 20, 30, 40) 1435 r3 = (10, 20, 30, 40) 1436 r4 = Rect(10, 20, 30, 40) 1437 1438 class foo(Rect): 1439 def __eq__(self, other): 1440 return id(self) == id(other) 1441 1442 def __ne__(self, other): 1443 return id(self) != id(other) 1444 1445 class foo2(Rect): 1446 pass 1447 1448 r5 = foo(10, 20, 30, 40) 1449 r6 = foo2(10, 20, 30, 40) 1450 1451 self.assertNotEqual(r5, r2) 1452 1453 # because we define equality differently for this subclass. 1454 self.assertEqual(r6, r2) 1455 1456 rect_list = [r1, r2, r3, r4, r6] 1457 1458 # see if we can remove 4 of these. 1459 rect_list.remove(r2) 1460 rect_list.remove(r2) 1461 rect_list.remove(r2) 1462 rect_list.remove(r2) 1463 self.assertRaises(ValueError, rect_list.remove, r2) 1464 1465 def test_collidedict(self): 1466 """Ensures collidedict detects collisions.""" 1467 rect = Rect(1, 1, 10, 10) 1468 1469 collide_item1 = ("collide 1", rect.copy()) 1470 collide_item2 = ("collide 2", Rect(5, 5, 10, 10)) 1471 no_collide_item1 = ("no collide 1", Rect(60, 60, 10, 10)) 1472 no_collide_item2 = ("no collide 2", Rect(70, 70, 10, 10)) 1473 1474 # Dict to check collisions with values. 1475 rect_values = dict( 1476 (collide_item1, collide_item2, no_collide_item1, no_collide_item2) 1477 ) 1478 value_collide_items = (collide_item1, collide_item2) 1479 1480 # Dict to check collisions with keys. 1481 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1482 key_collide_items = tuple((tuple(v), k) for k, v in value_collide_items) 1483 1484 for use_values in (True, False): 1485 if use_values: 1486 expected_items = value_collide_items 1487 d = rect_values 1488 else: 1489 expected_items = key_collide_items 1490 d = rect_keys 1491 1492 collide_item = rect.collidedict(d, use_values) 1493 1494 # The detected collision could be any of the possible items. 1495 self.assertIn(collide_item, expected_items) 1496 1497 def test_collidedict__no_collision(self): 1498 """Ensures collidedict returns None when no collisions.""" 1499 rect = Rect(1, 1, 10, 10) 1500 1501 no_collide_item1 = ("no collide 1", Rect(50, 50, 10, 10)) 1502 no_collide_item2 = ("no collide 2", Rect(60, 60, 10, 10)) 1503 no_collide_item3 = ("no collide 3", Rect(70, 70, 10, 10)) 1504 1505 # Dict to check collisions with values. 1506 rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3)) 1507 1508 # Dict to check collisions with keys. 1509 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1510 1511 for use_values in (True, False): 1512 d = rect_values if use_values else rect_keys 1513 1514 collide_item = rect.collidedict(d, use_values) 1515 1516 self.assertIsNone(collide_item) 1517 1518 def test_collidedict__barely_touching(self): 1519 """Ensures collidedict works correctly for rects that barely touch.""" 1520 rect = Rect(1, 1, 10, 10) 1521 # Small rect to test barely touching collisions. 1522 collide_rect = Rect(0, 0, 1, 1) 1523 1524 collide_item1 = ("collide 1", collide_rect) 1525 no_collide_item1 = ("no collide 1", Rect(50, 50, 10, 10)) 1526 no_collide_item2 = ("no collide 2", Rect(60, 60, 10, 10)) 1527 no_collide_item3 = ("no collide 3", Rect(70, 70, 10, 10)) 1528 1529 # Dict to check collisions with values. 1530 no_collide_rect_values = dict( 1531 (no_collide_item1, no_collide_item2, no_collide_item3) 1532 ) 1533 1534 # Dict to check collisions with keys. 1535 no_collide_rect_keys = {tuple(v): k for k, v in no_collide_rect_values.items()} 1536 1537 # Tests the collide_rect on each of the rect's corners. 1538 for attr in ("topleft", "topright", "bottomright", "bottomleft"): 1539 setattr(collide_rect, attr, getattr(rect, attr)) 1540 1541 for use_values in (True, False): 1542 if use_values: 1543 expected_item = collide_item1 1544 d = dict(no_collide_rect_values) 1545 else: 1546 expected_item = (tuple(collide_item1[1]), collide_item1[0]) 1547 d = dict(no_collide_rect_keys) 1548 1549 d.update((expected_item,)) # Add in the expected item. 1550 1551 collide_item = rect.collidedict(d, use_values) 1552 1553 self.assertTupleEqual(collide_item, expected_item) 1554 1555 def test_collidedict__zero_sized_rects(self): 1556 """Ensures collidedict works correctly with zero sized rects. 1557 1558 There should be no collisions with zero sized rects. 1559 """ 1560 zero_rect1 = Rect(1, 1, 0, 0) 1561 zero_rect2 = Rect(1, 1, 1, 0) 1562 zero_rect3 = Rect(1, 1, 0, 1) 1563 zero_rect4 = Rect(1, 1, -1, 0) 1564 zero_rect5 = Rect(1, 1, 0, -1) 1565 1566 no_collide_item1 = ("no collide 1", zero_rect1.copy()) 1567 no_collide_item2 = ("no collide 2", zero_rect2.copy()) 1568 no_collide_item3 = ("no collide 3", zero_rect3.copy()) 1569 no_collide_item4 = ("no collide 4", zero_rect4.copy()) 1570 no_collide_item5 = ("no collide 5", zero_rect5.copy()) 1571 no_collide_item6 = ("no collide 6", Rect(0, 0, 10, 10)) 1572 no_collide_item7 = ("no collide 7", Rect(0, 0, 2, 2)) 1573 1574 # Dict to check collisions with values. 1575 rect_values = dict( 1576 ( 1577 no_collide_item1, 1578 no_collide_item2, 1579 no_collide_item3, 1580 no_collide_item4, 1581 no_collide_item5, 1582 no_collide_item6, 1583 no_collide_item7, 1584 ) 1585 ) 1586 1587 # Dict to check collisions with keys. 1588 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1589 1590 for use_values in (True, False): 1591 d = rect_values if use_values else rect_keys 1592 1593 for zero_rect in ( 1594 zero_rect1, 1595 zero_rect2, 1596 zero_rect3, 1597 zero_rect4, 1598 zero_rect5, 1599 ): 1600 collide_item = zero_rect.collidedict(d, use_values) 1601 1602 self.assertIsNone(collide_item) 1603 1604 def test_collidedict__zero_sized_rects_as_args(self): 1605 """Ensures collidedict works correctly with zero sized rects as args. 1606 1607 There should be no collisions with zero sized rects. 1608 """ 1609 rect = Rect(0, 0, 10, 10) 1610 1611 no_collide_item1 = ("no collide 1", Rect(1, 1, 0, 0)) 1612 no_collide_item2 = ("no collide 2", Rect(1, 1, 1, 0)) 1613 no_collide_item3 = ("no collide 3", Rect(1, 1, 0, 1)) 1614 1615 # Dict to check collisions with values. 1616 rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3)) 1617 1618 # Dict to check collisions with keys. 1619 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1620 1621 for use_values in (True, False): 1622 d = rect_values if use_values else rect_keys 1623 1624 collide_item = rect.collidedict(d, use_values) 1625 1626 self.assertIsNone(collide_item) 1627 1628 def test_collidedict__negative_sized_rects(self): 1629 """Ensures collidedict works correctly with negative sized rects.""" 1630 neg_rect = Rect(1, 1, -1, -1) 1631 1632 collide_item1 = ("collide 1", neg_rect.copy()) 1633 collide_item2 = ("collide 2", Rect(0, 0, 10, 10)) 1634 no_collide_item1 = ("no collide 1", Rect(1, 1, 10, 10)) 1635 1636 # Dict to check collisions with values. 1637 rect_values = dict((collide_item1, collide_item2, no_collide_item1)) 1638 value_collide_items = (collide_item1, collide_item2) 1639 1640 # Dict to check collisions with keys. 1641 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1642 key_collide_items = tuple((tuple(v), k) for k, v in value_collide_items) 1643 1644 for use_values in (True, False): 1645 if use_values: 1646 collide_items = value_collide_items 1647 d = rect_values 1648 else: 1649 collide_items = key_collide_items 1650 d = rect_keys 1651 1652 collide_item = neg_rect.collidedict(d, use_values) 1653 1654 # The detected collision could be any of the possible items. 1655 self.assertIn(collide_item, collide_items) 1656 1657 def test_collidedict__negative_sized_rects_as_args(self): 1658 """Ensures collidedict works correctly with negative sized rect args. 1659 """ 1660 rect = Rect(0, 0, 10, 10) 1661 1662 collide_item1 = ("collide 1", Rect(1, 1, -1, -1)) 1663 no_collide_item1 = ("no collide 1", Rect(1, 1, -1, 0)) 1664 no_collide_item2 = ("no collide 2", Rect(1, 1, 0, -1)) 1665 1666 # Dict to check collisions with values. 1667 rect_values = dict((collide_item1, no_collide_item1, no_collide_item2)) 1668 1669 # Dict to check collisions with keys. 1670 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1671 1672 for use_values in (True, False): 1673 if use_values: 1674 expected_item = collide_item1 1675 d = rect_values 1676 else: 1677 expected_item = (tuple(collide_item1[1]), collide_item1[0]) 1678 d = rect_keys 1679 1680 collide_item = rect.collidedict(d, use_values) 1681 1682 self.assertTupleEqual(collide_item, expected_item) 1683 1684 def test_collidedict__invalid_dict_format(self): 1685 """Ensures collidedict correctly handles invalid dict parameters.""" 1686 rect = Rect(0, 0, 10, 10) 1687 1688 invalid_value_dict = ("collide", rect.copy()) 1689 invalid_key_dict = tuple(invalid_value_dict[1]), invalid_value_dict[0] 1690 1691 for use_values in (True, False): 1692 d = invalid_value_dict if use_values else invalid_key_dict 1693 1694 with self.assertRaises(TypeError): 1695 collide_item = rect.collidedict(d, use_values) 1696 1697 def test_collidedict__invalid_dict_value_format(self): 1698 """Ensures collidedict correctly handles dicts with invalid values.""" 1699 rect = Rect(0, 0, 10, 10) 1700 rect_keys = {tuple(rect): "collide"} 1701 1702 with self.assertRaises(TypeError): 1703 collide_item = rect.collidedict(rect_keys, 1) 1704 1705 def test_collidedict__invalid_dict_key_format(self): 1706 """Ensures collidedict correctly handles dicts with invalid keys.""" 1707 rect = Rect(0, 0, 10, 10) 1708 rect_values = {"collide": rect.copy()} 1709 1710 with self.assertRaises(TypeError): 1711 collide_item = rect.collidedict(rect_values) 1712 1713 def test_collidedict__invalid_use_values_format(self): 1714 """Ensures collidedict correctly handles invalid use_values parameters. 1715 """ 1716 rect = Rect(0, 0, 1, 1) 1717 d = {} 1718 1719 for invalid_param in (None, d, 1.1): 1720 with self.assertRaises(TypeError): 1721 collide_item = rect.collidedict(d, invalid_param) 1722 1723 def test_collidedictall(self): 1724 """Ensures collidedictall detects collisions.""" 1725 rect = Rect(1, 1, 10, 10) 1726 1727 collide_item1 = ("collide 1", rect.copy()) 1728 collide_item2 = ("collide 2", Rect(5, 5, 10, 10)) 1729 no_collide_item1 = ("no collide 1", Rect(60, 60, 20, 20)) 1730 no_collide_item2 = ("no collide 2", Rect(70, 70, 20, 20)) 1731 1732 # Dict to check collisions with values. 1733 rect_values = dict( 1734 (collide_item1, collide_item2, no_collide_item1, no_collide_item2) 1735 ) 1736 value_collide_items = [collide_item1, collide_item2] 1737 1738 # Dict to check collisions with keys. 1739 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1740 key_collide_items = [(tuple(v), k) for k, v in value_collide_items] 1741 1742 for use_values in (True, False): 1743 if use_values: 1744 expected_items = value_collide_items 1745 d = rect_values 1746 else: 1747 expected_items = key_collide_items 1748 d = rect_keys 1749 1750 collide_items = rect.collidedictall(d, use_values) 1751 1752 self._assertCountEqual(collide_items, expected_items) 1753 1754 def test_collidedictall__no_collision(self): 1755 """Ensures collidedictall returns an empty list when no collisions.""" 1756 rect = Rect(1, 1, 10, 10) 1757 1758 no_collide_item1 = ("no collide 1", Rect(50, 50, 20, 20)) 1759 no_collide_item2 = ("no collide 2", Rect(60, 60, 20, 20)) 1760 no_collide_item3 = ("no collide 3", Rect(70, 70, 20, 20)) 1761 1762 # Dict to check collisions with values. 1763 rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3)) 1764 1765 # Dict to check collisions with keys. 1766 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1767 1768 expected_items = [] 1769 1770 for use_values in (True, False): 1771 d = rect_values if use_values else rect_keys 1772 1773 collide_items = rect.collidedictall(d, use_values) 1774 1775 self._assertCountEqual(collide_items, expected_items) 1776 1777 def test_collidedictall__barely_touching(self): 1778 """Ensures collidedictall works correctly for rects that barely touch. 1779 """ 1780 rect = Rect(1, 1, 10, 10) 1781 # Small rect to test barely touching collisions. 1782 collide_rect = Rect(0, 0, 1, 1) 1783 1784 collide_item1 = ("collide 1", collide_rect) 1785 no_collide_item1 = ("no collide 1", Rect(50, 50, 20, 20)) 1786 no_collide_item2 = ("no collide 2", Rect(60, 60, 20, 20)) 1787 no_collide_item3 = ("no collide 3", Rect(70, 70, 20, 20)) 1788 1789 # Dict to check collisions with values. 1790 no_collide_rect_values = dict( 1791 (no_collide_item1, no_collide_item2, no_collide_item3) 1792 ) 1793 1794 # Dict to check collisions with keys. 1795 no_collide_rect_keys = {tuple(v): k for k, v in no_collide_rect_values.items()} 1796 1797 # Tests the collide_rect on each of the rect's corners. 1798 for attr in ("topleft", "topright", "bottomright", "bottomleft"): 1799 setattr(collide_rect, attr, getattr(rect, attr)) 1800 1801 for use_values in (True, False): 1802 if use_values: 1803 expected_items = [collide_item1] 1804 d = dict(no_collide_rect_values) 1805 else: 1806 expected_items = [(tuple(collide_item1[1]), collide_item1[0])] 1807 d = dict(no_collide_rect_keys) 1808 1809 d.update(expected_items) # Add in the expected items. 1810 1811 collide_items = rect.collidedictall(d, use_values) 1812 1813 self._assertCountEqual(collide_items, expected_items) 1814 1815 def test_collidedictall__zero_sized_rects(self): 1816 """Ensures collidedictall works correctly with zero sized rects. 1817 1818 There should be no collisions with zero sized rects. 1819 """ 1820 zero_rect1 = Rect(2, 2, 0, 0) 1821 zero_rect2 = Rect(2, 2, 2, 0) 1822 zero_rect3 = Rect(2, 2, 0, 2) 1823 zero_rect4 = Rect(2, 2, -2, 0) 1824 zero_rect5 = Rect(2, 2, 0, -2) 1825 1826 no_collide_item1 = ("no collide 1", zero_rect1.copy()) 1827 no_collide_item2 = ("no collide 2", zero_rect2.copy()) 1828 no_collide_item3 = ("no collide 3", zero_rect3.copy()) 1829 no_collide_item4 = ("no collide 4", zero_rect4.copy()) 1830 no_collide_item5 = ("no collide 5", zero_rect5.copy()) 1831 no_collide_item6 = ("no collide 6", Rect(0, 0, 10, 10)) 1832 no_collide_item7 = ("no collide 7", Rect(0, 0, 2, 2)) 1833 1834 # Dict to check collisions with values. 1835 rect_values = dict( 1836 ( 1837 no_collide_item1, 1838 no_collide_item2, 1839 no_collide_item3, 1840 no_collide_item4, 1841 no_collide_item5, 1842 no_collide_item6, 1843 no_collide_item7, 1844 ) 1845 ) 1846 1847 # Dict to check collisions with keys. 1848 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1849 1850 expected_items = [] 1851 1852 for use_values in (True, False): 1853 d = rect_values if use_values else rect_keys 1854 1855 for zero_rect in ( 1856 zero_rect1, 1857 zero_rect2, 1858 zero_rect3, 1859 zero_rect4, 1860 zero_rect5, 1861 ): 1862 collide_items = zero_rect.collidedictall(d, use_values) 1863 1864 self._assertCountEqual(collide_items, expected_items) 1865 1866 def test_collidedictall__zero_sized_rects_as_args(self): 1867 """Ensures collidedictall works correctly with zero sized rects 1868 as args. 1869 1870 There should be no collisions with zero sized rects. 1871 """ 1872 rect = Rect(0, 0, 20, 20) 1873 1874 no_collide_item1 = ("no collide 1", Rect(2, 2, 0, 0)) 1875 no_collide_item2 = ("no collide 2", Rect(2, 2, 2, 0)) 1876 no_collide_item3 = ("no collide 3", Rect(2, 2, 0, 2)) 1877 1878 # Dict to check collisions with values. 1879 rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3)) 1880 1881 # Dict to check collisions with keys. 1882 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1883 1884 expected_items = [] 1885 1886 for use_values in (True, False): 1887 d = rect_values if use_values else rect_keys 1888 1889 collide_items = rect.collidedictall(d, use_values) 1890 1891 self._assertCountEqual(collide_items, expected_items) 1892 1893 def test_collidedictall__negative_sized_rects(self): 1894 """Ensures collidedictall works correctly with negative sized rects.""" 1895 neg_rect = Rect(2, 2, -2, -2) 1896 1897 collide_item1 = ("collide 1", neg_rect.copy()) 1898 collide_item2 = ("collide 2", Rect(0, 0, 20, 20)) 1899 no_collide_item1 = ("no collide 1", Rect(2, 2, 20, 20)) 1900 1901 # Dict to check collisions with values. 1902 rect_values = dict((collide_item1, collide_item2, no_collide_item1)) 1903 value_collide_items = [collide_item1, collide_item2] 1904 1905 # Dict to check collisions with keys. 1906 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1907 key_collide_items = [(tuple(v), k) for k, v in value_collide_items] 1908 1909 for use_values in (True, False): 1910 if use_values: 1911 expected_items = value_collide_items 1912 d = rect_values 1913 else: 1914 expected_items = key_collide_items 1915 d = rect_keys 1916 1917 collide_items = neg_rect.collidedictall(d, use_values) 1918 1919 self._assertCountEqual(collide_items, expected_items) 1920 1921 def test_collidedictall__negative_sized_rects_as_args(self): 1922 """Ensures collidedictall works correctly with negative sized rect 1923 args. 1924 """ 1925 rect = Rect(0, 0, 10, 10) 1926 1927 collide_item1 = ("collide 1", Rect(1, 1, -1, -1)) 1928 no_collide_item1 = ("no collide 1", Rect(1, 1, -1, 0)) 1929 no_collide_item2 = ("no collide 2", Rect(1, 1, 0, -1)) 1930 1931 # Dict to check collisions with values. 1932 rect_values = dict((collide_item1, no_collide_item1, no_collide_item2)) 1933 value_collide_items = [collide_item1] 1934 1935 # Dict to check collisions with keys. 1936 rect_keys = {tuple(v): k for k, v in rect_values.items()} 1937 key_collide_items = [(tuple(v), k) for k, v in value_collide_items] 1938 1939 for use_values in (True, False): 1940 if use_values: 1941 expected_items = value_collide_items 1942 d = rect_values 1943 else: 1944 expected_items = key_collide_items 1945 d = rect_keys 1946 1947 collide_items = rect.collidedictall(d, use_values) 1948 1949 self._assertCountEqual(collide_items, expected_items) 1950 1951 def test_collidedictall__invalid_dict_format(self): 1952 """Ensures collidedictall correctly handles invalid dict parameters.""" 1953 rect = Rect(0, 0, 10, 10) 1954 1955 invalid_value_dict = ("collide", rect.copy()) 1956 invalid_key_dict = tuple(invalid_value_dict[1]), invalid_value_dict[0] 1957 1958 for use_values in (True, False): 1959 d = invalid_value_dict if use_values else invalid_key_dict 1960 1961 with self.assertRaises(TypeError): 1962 collide_item = rect.collidedictall(d, use_values) 1963 1964 def test_collidedictall__invalid_dict_value_format(self): 1965 """Ensures collidedictall correctly handles dicts with invalid values. 1966 """ 1967 rect = Rect(0, 0, 10, 10) 1968 rect_keys = {tuple(rect): "collide"} 1969 1970 with self.assertRaises(TypeError): 1971 collide_items = rect.collidedictall(rect_keys, 1) 1972 1973 def test_collidedictall__invalid_dict_key_format(self): 1974 """Ensures collidedictall correctly handles dicts with invalid keys.""" 1975 rect = Rect(0, 0, 10, 10) 1976 rect_values = {"collide": rect.copy()} 1977 1978 with self.assertRaises(TypeError): 1979 collide_items = rect.collidedictall(rect_values) 1980 1981 def test_collidedictall__invalid_use_values_format(self): 1982 """Ensures collidedictall correctly handles invalid use_values 1983 parameters. 1984 """ 1985 rect = Rect(0, 0, 1, 1) 1986 d = {} 1987 1988 for invalid_param in (None, d, 1.1): 1989 with self.assertRaises(TypeError): 1990 collide_items = rect.collidedictall(d, invalid_param) 1991 1992 def test_collidelist(self): 1993 1994 # __doc__ (as of 2008-08-02) for pygame.rect.Rect.collidelist: 1995 1996 # Rect.collidelist(list): return index 1997 # test if one rectangle in a list intersects 1998 # 1999 # Test whether the rectangle collides with any in a sequence of 2000 # rectangles. The index of the first collision found is returned. If 2001 # no collisions are found an index of -1 is returned. 2002 2003 r = Rect(1, 1, 10, 10) 2004 l = [Rect(50, 50, 1, 1), Rect(5, 5, 10, 10), Rect(15, 15, 1, 1)] 2005 2006 self.assertEqual(r.collidelist(l), 1) 2007 2008 f = [Rect(50, 50, 1, 1), (100, 100, 4, 4)] 2009 self.assertEqual(r.collidelist(f), -1) 2010 2011 def test_collidelistall(self): 2012 2013 # __doc__ (as of 2008-08-02) for pygame.rect.Rect.collidelistall: 2014 2015 # Rect.collidelistall(list): return indices 2016 # test if all rectangles in a list intersect 2017 # 2018 # Returns a list of all the indices that contain rectangles that 2019 # collide with the Rect. If no intersecting rectangles are found, an 2020 # empty list is returned. 2021 2022 r = Rect(1, 1, 10, 10) 2023 2024 l = [ 2025 Rect(1, 1, 10, 10), 2026 Rect(5, 5, 10, 10), 2027 Rect(15, 15, 1, 1), 2028 Rect(2, 2, 1, 1), 2029 ] 2030 self.assertEqual(r.collidelistall(l), [0, 1, 3]) 2031 2032 f = [Rect(50, 50, 1, 1), Rect(20, 20, 5, 5)] 2033 self.assertFalse(r.collidelistall(f)) 2034 2035 def test_fit(self): 2036 2037 # __doc__ (as of 2008-08-02) for pygame.rect.Rect.fit: 2038 2039 # Rect.fit(Rect): return Rect 2040 # resize and move a rectangle with aspect ratio 2041 # 2042 # Returns a new rectangle that is moved and resized to fit another. 2043 # The aspect ratio of the original Rect is preserved, so the new 2044 # rectangle may be smaller than the target in either width or height. 2045 2046 r = Rect(10, 10, 30, 30) 2047 2048 r2 = Rect(30, 30, 15, 10) 2049 2050 f = r.fit(r2) 2051 self.assertTrue(r2.contains(f)) 2052 2053 f2 = r2.fit(r) 2054 self.assertTrue(r.contains(f2)) 2055 2056 def test_copy(self): 2057 r = Rect(1, 2, 10, 20) 2058 c = r.copy() 2059 self.assertEqual(c, r) 2060 2061 def test_subscript(self): 2062 r = Rect(1, 2, 3, 4) 2063 self.assertEqual(r[0], 1) 2064 self.assertEqual(r[1], 2) 2065 self.assertEqual(r[2], 3) 2066 self.assertEqual(r[3], 4) 2067 self.assertEqual(r[-1], 4) 2068 self.assertEqual(r[-2], 3) 2069 self.assertEqual(r[-4], 1) 2070 self.assertRaises(IndexError, r.__getitem__, 5) 2071 self.assertRaises(IndexError, r.__getitem__, -5) 2072 self.assertEqual(r[0:2], [1, 2]) 2073 self.assertEqual(r[0:4], [1, 2, 3, 4]) 2074 self.assertEqual(r[0:-1], [1, 2, 3]) 2075 self.assertEqual(r[:], [1, 2, 3, 4]) 2076 self.assertEqual(r[...], [1, 2, 3, 4]) 2077 self.assertEqual(r[0:4:2], [1, 3]) 2078 self.assertEqual(r[0:4:3], [1, 4]) 2079 self.assertEqual(r[3::-1], [4, 3, 2, 1]) 2080 self.assertRaises(TypeError, r.__getitem__, None) 2081 2082 def test_ass_subscript(self): 2083 r = Rect(0, 0, 0, 0) 2084 r[...] = 1, 2, 3, 4 2085 self.assertEqual(r, [1, 2, 3, 4]) 2086 self.assertRaises(TypeError, r.__setitem__, None, 0) 2087 self.assertEqual(r, [1, 2, 3, 4]) 2088 self.assertRaises(TypeError, r.__setitem__, 0, "") 2089 self.assertEqual(r, [1, 2, 3, 4]) 2090 self.assertRaises(IndexError, r.__setitem__, 4, 0) 2091 self.assertEqual(r, [1, 2, 3, 4]) 2092 self.assertRaises(IndexError, r.__setitem__, -5, 0) 2093 self.assertEqual(r, [1, 2, 3, 4]) 2094 r[0] = 10 2095 self.assertEqual(r, [10, 2, 3, 4]) 2096 r[3] = 40 2097 self.assertEqual(r, [10, 2, 3, 40]) 2098 r[-1] = 400 2099 self.assertEqual(r, [10, 2, 3, 400]) 2100 r[-4] = 100 2101 self.assertEqual(r, [100, 2, 3, 400]) 2102 r[1:3] = 0 2103 self.assertEqual(r, [100, 0, 0, 400]) 2104 r[...] = 0 2105 self.assertEqual(r, [0, 0, 0, 0]) 2106 r[:] = 9 2107 self.assertEqual(r, [9, 9, 9, 9]) 2108 r[:] = 11, 12, 13, 14 2109 self.assertEqual(r, [11, 12, 13, 14]) 2110 r[::-1] = r 2111 self.assertEqual(r, [14, 13, 12, 11]) 2112 2113 2114@unittest.skipIf(IS_PYPY, "fails on pypy") 2115class SubclassTest(unittest.TestCase): 2116 class MyRect(Rect): 2117 def __init__(self, *args, **kwds): 2118 super(SubclassTest.MyRect, self).__init__(*args, **kwds) 2119 self.an_attribute = True 2120 2121 def test_copy(self): 2122 mr1 = self.MyRect(1, 2, 10, 20) 2123 self.assertTrue(mr1.an_attribute) 2124 mr2 = mr1.copy() 2125 self.assertTrue(isinstance(mr2, self.MyRect)) 2126 self.assertRaises(AttributeError, getattr, mr2, "an_attribute") 2127 2128 def test_move(self): 2129 mr1 = self.MyRect(1, 2, 10, 20) 2130 self.assertTrue(mr1.an_attribute) 2131 mr2 = mr1.move(1, 2) 2132 self.assertTrue(isinstance(mr2, self.MyRect)) 2133 self.assertRaises(AttributeError, getattr, mr2, "an_attribute") 2134 2135 def test_inflate(self): 2136 mr1 = self.MyRect(1, 2, 10, 20) 2137 self.assertTrue(mr1.an_attribute) 2138 mr2 = mr1.inflate(2, 4) 2139 self.assertTrue(isinstance(mr2, self.MyRect)) 2140 self.assertRaises(AttributeError, getattr, mr2, "an_attribute") 2141 2142 def test_clamp(self): 2143 mr1 = self.MyRect(19, 12, 5, 5) 2144 self.assertTrue(mr1.an_attribute) 2145 mr2 = mr1.clamp(Rect(10, 10, 10, 10)) 2146 self.assertTrue(isinstance(mr2, self.MyRect)) 2147 self.assertRaises(AttributeError, getattr, mr2, "an_attribute") 2148 2149 def test_clip(self): 2150 mr1 = self.MyRect(1, 2, 3, 4) 2151 self.assertTrue(mr1.an_attribute) 2152 mr2 = mr1.clip(Rect(0, 0, 3, 4)) 2153 self.assertTrue(isinstance(mr2, self.MyRect)) 2154 self.assertRaises(AttributeError, getattr, mr2, "an_attribute") 2155 2156 def test_union(self): 2157 mr1 = self.MyRect(1, 1, 1, 2) 2158 self.assertTrue(mr1.an_attribute) 2159 mr2 = mr1.union(Rect(-2, -2, 1, 2)) 2160 self.assertTrue(isinstance(mr2, self.MyRect)) 2161 self.assertRaises(AttributeError, getattr, mr2, "an_attribute") 2162 2163 def test_unionall(self): 2164 mr1 = self.MyRect(0, 0, 1, 1) 2165 self.assertTrue(mr1.an_attribute) 2166 mr2 = mr1.unionall([Rect(-2, -2, 1, 1), Rect(2, 2, 1, 1)]) 2167 self.assertTrue(isinstance(mr2, self.MyRect)) 2168 self.assertRaises(AttributeError, getattr, mr2, "an_attribute") 2169 2170 def test_fit(self): 2171 mr1 = self.MyRect(10, 10, 30, 30) 2172 self.assertTrue(mr1.an_attribute) 2173 mr2 = mr1.fit(Rect(30, 30, 15, 10)) 2174 self.assertTrue(isinstance(mr2, self.MyRect)) 2175 self.assertRaises(AttributeError, getattr, mr2, "an_attribute") 2176 2177 2178if __name__ == "__main__": 2179 unittest.main() 2180