2180 lines
74 KiB
Python
2180 lines
74 KiB
Python
import math
|
|
import sys
|
|
import unittest
|
|
import platform
|
|
|
|
from pygame import Rect, Vector2, get_sdl_version
|
|
from pygame.tests import test_utils
|
|
|
|
|
|
PY3 = sys.version_info >= (3, 0, 0)
|
|
SDL1 = get_sdl_version()[0] < 2
|
|
IS_PYPY = "PyPy" == platform.python_implementation()
|
|
|
|
|
|
class RectTypeTest(unittest.TestCase):
|
|
def _assertCountEqual(self, *args, **kwargs):
|
|
# Handle method name differences between Python versions.
|
|
if PY3:
|
|
self.assertCountEqual(*args, **kwargs)
|
|
else:
|
|
self.assertItemsEqual(*args, **kwargs)
|
|
|
|
def testConstructionXYWidthHeight(self):
|
|
r = Rect(1, 2, 3, 4)
|
|
self.assertEqual(1, r.left)
|
|
self.assertEqual(2, r.top)
|
|
self.assertEqual(3, r.width)
|
|
self.assertEqual(4, r.height)
|
|
|
|
def testConstructionTopLeftSize(self):
|
|
r = Rect((1, 2), (3, 4))
|
|
self.assertEqual(1, r.left)
|
|
self.assertEqual(2, r.top)
|
|
self.assertEqual(3, r.width)
|
|
self.assertEqual(4, r.height)
|
|
|
|
def testCalculatedAttributes(self):
|
|
r = Rect(1, 2, 3, 4)
|
|
|
|
self.assertEqual(r.left + r.width, r.right)
|
|
self.assertEqual(r.top + r.height, r.bottom)
|
|
self.assertEqual((r.width, r.height), r.size)
|
|
self.assertEqual((r.left, r.top), r.topleft)
|
|
self.assertEqual((r.right, r.top), r.topright)
|
|
self.assertEqual((r.left, r.bottom), r.bottomleft)
|
|
self.assertEqual((r.right, r.bottom), r.bottomright)
|
|
|
|
midx = r.left + r.width // 2
|
|
midy = r.top + r.height // 2
|
|
|
|
self.assertEqual(midx, r.centerx)
|
|
self.assertEqual(midy, r.centery)
|
|
self.assertEqual((r.centerx, r.centery), r.center)
|
|
self.assertEqual((r.centerx, r.top), r.midtop)
|
|
self.assertEqual((r.centerx, r.bottom), r.midbottom)
|
|
self.assertEqual((r.left, r.centery), r.midleft)
|
|
self.assertEqual((r.right, r.centery), r.midright)
|
|
|
|
def test_normalize(self):
|
|
"""Ensures normalize works when width and height are both negative."""
|
|
test_rect = Rect((1, 2), (-3, -6))
|
|
expected_normalized_rect = (
|
|
(test_rect.x + test_rect.w, test_rect.y + test_rect.h),
|
|
(-test_rect.w, -test_rect.h),
|
|
)
|
|
|
|
test_rect.normalize()
|
|
|
|
self.assertEqual(test_rect, expected_normalized_rect)
|
|
|
|
@unittest.skipIf(IS_PYPY, "fails on pypy sometimes")
|
|
def test_normalize__positive_height(self):
|
|
"""Ensures normalize works with a negative width and a positive height.
|
|
"""
|
|
test_rect = Rect((1, 2), (-3, 6))
|
|
expected_normalized_rect = (
|
|
(test_rect.x + test_rect.w, test_rect.y),
|
|
(-test_rect.w, test_rect.h),
|
|
)
|
|
|
|
test_rect.normalize()
|
|
|
|
self.assertEqual(test_rect, expected_normalized_rect)
|
|
|
|
@unittest.skipIf(IS_PYPY, "fails on pypy sometimes")
|
|
def test_normalize__positive_width(self):
|
|
"""Ensures normalize works with a positive width and a negative height.
|
|
"""
|
|
test_rect = Rect((1, 2), (3, -6))
|
|
expected_normalized_rect = (
|
|
(test_rect.x, test_rect.y + test_rect.h),
|
|
(test_rect.w, -test_rect.h),
|
|
)
|
|
|
|
test_rect.normalize()
|
|
|
|
self.assertEqual(test_rect, expected_normalized_rect)
|
|
|
|
@unittest.skipIf(IS_PYPY, "fails on pypy sometimes")
|
|
def test_normalize__zero_height(self):
|
|
"""Ensures normalize works with a negative width and a zero height."""
|
|
test_rect = Rect((1, 2), (-3, 0))
|
|
expected_normalized_rect = (
|
|
(test_rect.x + test_rect.w, test_rect.y),
|
|
(-test_rect.w, test_rect.h),
|
|
)
|
|
|
|
test_rect.normalize()
|
|
|
|
self.assertEqual(test_rect, expected_normalized_rect)
|
|
|
|
@unittest.skipIf(IS_PYPY, "fails on pypy sometimes")
|
|
def test_normalize__zero_width(self):
|
|
"""Ensures normalize works with a zero width and a negative height."""
|
|
test_rect = Rect((1, 2), (0, -6))
|
|
expected_normalized_rect = (
|
|
(test_rect.x, test_rect.y + test_rect.h),
|
|
(test_rect.w, -test_rect.h),
|
|
)
|
|
|
|
test_rect.normalize()
|
|
|
|
self.assertEqual(test_rect, expected_normalized_rect)
|
|
|
|
@unittest.skipIf(IS_PYPY, "fails on pypy")
|
|
def test_normalize__non_negative(self):
|
|
"""Ensures normalize works when width and height are both non-negative.
|
|
|
|
Tests combinations of positive and zero values for width and height.
|
|
The normalize method has no impact when both width and height are
|
|
non-negative.
|
|
"""
|
|
for size in ((3, 6), (3, 0), (0, 6), (0, 0)):
|
|
test_rect = Rect((1, 2), size)
|
|
expected_normalized_rect = Rect(test_rect)
|
|
|
|
test_rect.normalize()
|
|
|
|
self.assertEqual(test_rect, expected_normalized_rect)
|
|
|
|
def test_x(self):
|
|
"""Ensures changing the x attribute moves the rect and does not change
|
|
the rect's size.
|
|
"""
|
|
expected_x = 10
|
|
expected_y = 2
|
|
expected_size = (3, 4)
|
|
r = Rect((1, expected_y), expected_size)
|
|
|
|
r.x = expected_x
|
|
|
|
self.assertEqual(r.x, expected_x)
|
|
self.assertEqual(r.x, r.left)
|
|
self.assertEqual(r.y, expected_y)
|
|
self.assertEqual(r.size, expected_size)
|
|
|
|
def test_x__invalid_value(self):
|
|
"""Ensures the x attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.x = value
|
|
|
|
def test_x__del(self):
|
|
"""Ensures the x attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.x
|
|
|
|
def test_y(self):
|
|
"""Ensures changing the y attribute moves the rect and does not change
|
|
the rect's size.
|
|
"""
|
|
expected_x = 1
|
|
expected_y = 20
|
|
expected_size = (3, 4)
|
|
r = Rect((expected_x, 2), expected_size)
|
|
|
|
r.y = expected_y
|
|
|
|
self.assertEqual(r.y, expected_y)
|
|
self.assertEqual(r.y, r.top)
|
|
self.assertEqual(r.x, expected_x)
|
|
self.assertEqual(r.size, expected_size)
|
|
|
|
def test_y__invalid_value(self):
|
|
"""Ensures the y attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.y = value
|
|
|
|
def test_y__del(self):
|
|
"""Ensures the y attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.y
|
|
|
|
def test_left(self):
|
|
"""Changing the left attribute moves the rect and does not change
|
|
the rect's width
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_left = 10
|
|
|
|
r.left = new_left
|
|
self.assertEqual(new_left, r.left)
|
|
self.assertEqual(Rect(new_left, 2, 3, 4), r)
|
|
|
|
def test_left__invalid_value(self):
|
|
"""Ensures the left attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.left = value
|
|
|
|
def test_left__del(self):
|
|
"""Ensures the left attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.left
|
|
|
|
def test_right(self):
|
|
"""Changing the right attribute moves the rect and does not change
|
|
the rect's width
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_right = r.right + 20
|
|
expected_left = r.left + 20
|
|
old_width = r.width
|
|
|
|
r.right = new_right
|
|
self.assertEqual(new_right, r.right)
|
|
self.assertEqual(expected_left, r.left)
|
|
self.assertEqual(old_width, r.width)
|
|
|
|
def test_right__invalid_value(self):
|
|
"""Ensures the right attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.right = value
|
|
|
|
def test_right__del(self):
|
|
"""Ensures the right attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.right
|
|
|
|
def test_top(self):
|
|
"""Changing the top attribute moves the rect and does not change
|
|
the rect's width
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_top = 10
|
|
|
|
r.top = new_top
|
|
self.assertEqual(Rect(1, new_top, 3, 4), r)
|
|
self.assertEqual(new_top, r.top)
|
|
|
|
def test_top__invalid_value(self):
|
|
"""Ensures the top attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.top = value
|
|
|
|
def test_top__del(self):
|
|
"""Ensures the top attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.top
|
|
|
|
def test_bottom(self):
|
|
"""Changing the bottom attribute moves the rect and does not change
|
|
the rect's height
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_bottom = r.bottom + 20
|
|
expected_top = r.top + 20
|
|
old_height = r.height
|
|
|
|
r.bottom = new_bottom
|
|
self.assertEqual(new_bottom, r.bottom)
|
|
self.assertEqual(expected_top, r.top)
|
|
self.assertEqual(old_height, r.height)
|
|
|
|
def test_bottom__invalid_value(self):
|
|
"""Ensures the bottom attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.bottom = value
|
|
|
|
def test_bottom__del(self):
|
|
"""Ensures the bottom attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.bottom
|
|
|
|
def test_centerx(self):
|
|
"""Changing the centerx attribute moves the rect and does not change
|
|
the rect's width
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_centerx = r.centerx + 20
|
|
expected_left = r.left + 20
|
|
old_width = r.width
|
|
|
|
r.centerx = new_centerx
|
|
self.assertEqual(new_centerx, r.centerx)
|
|
self.assertEqual(expected_left, r.left)
|
|
self.assertEqual(old_width, r.width)
|
|
|
|
def test_centerx__invalid_value(self):
|
|
"""Ensures the centerx attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.centerx = value
|
|
|
|
def test_centerx__del(self):
|
|
"""Ensures the centerx attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.centerx
|
|
|
|
def test_centery(self):
|
|
"""Changing the centery attribute moves the rect and does not change
|
|
the rect's width
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_centery = r.centery + 20
|
|
expected_top = r.top + 20
|
|
old_height = r.height
|
|
|
|
r.centery = new_centery
|
|
self.assertEqual(new_centery, r.centery)
|
|
self.assertEqual(expected_top, r.top)
|
|
self.assertEqual(old_height, r.height)
|
|
|
|
def test_centery__invalid_value(self):
|
|
"""Ensures the centery attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.centery = value
|
|
|
|
def test_centery__del(self):
|
|
"""Ensures the centery attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.centery
|
|
|
|
def test_topleft(self):
|
|
"""Changing the topleft attribute moves the rect and does not change
|
|
the rect's size
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_topleft = (r.left + 20, r.top + 30)
|
|
old_size = r.size
|
|
|
|
r.topleft = new_topleft
|
|
self.assertEqual(new_topleft, r.topleft)
|
|
self.assertEqual(old_size, r.size)
|
|
|
|
def test_topleft__invalid_value(self):
|
|
"""Ensures the topleft attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", 1, (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.topleft = value
|
|
|
|
def test_topleft__del(self):
|
|
"""Ensures the topleft attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.topleft
|
|
|
|
def test_bottomleft(self):
|
|
"""Changing the bottomleft attribute moves the rect and does not change
|
|
the rect's size
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_bottomleft = (r.left + 20, r.bottom + 30)
|
|
expected_topleft = (r.left + 20, r.top + 30)
|
|
old_size = r.size
|
|
|
|
r.bottomleft = new_bottomleft
|
|
self.assertEqual(new_bottomleft, r.bottomleft)
|
|
self.assertEqual(expected_topleft, r.topleft)
|
|
self.assertEqual(old_size, r.size)
|
|
|
|
def test_bottomleft__invalid_value(self):
|
|
"""Ensures the bottomleft attribute handles invalid values correctly.
|
|
"""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", 1, (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.bottomleft = value
|
|
|
|
def test_bottomleft__del(self):
|
|
"""Ensures the bottomleft attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.bottomleft
|
|
|
|
def test_topright(self):
|
|
"""Changing the topright attribute moves the rect and does not change
|
|
the rect's size
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_topright = (r.right + 20, r.top + 30)
|
|
expected_topleft = (r.left + 20, r.top + 30)
|
|
old_size = r.size
|
|
|
|
r.topright = new_topright
|
|
self.assertEqual(new_topright, r.topright)
|
|
self.assertEqual(expected_topleft, r.topleft)
|
|
self.assertEqual(old_size, r.size)
|
|
|
|
def test_topright__invalid_value(self):
|
|
"""Ensures the topright attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", 1, (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.topright = value
|
|
|
|
def test_topright__del(self):
|
|
"""Ensures the topright attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.topright
|
|
|
|
def test_bottomright(self):
|
|
"""Changing the bottomright attribute moves the rect and does not change
|
|
the rect's size
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_bottomright = (r.right + 20, r.bottom + 30)
|
|
expected_topleft = (r.left + 20, r.top + 30)
|
|
old_size = r.size
|
|
|
|
r.bottomright = new_bottomright
|
|
self.assertEqual(new_bottomright, r.bottomright)
|
|
self.assertEqual(expected_topleft, r.topleft)
|
|
self.assertEqual(old_size, r.size)
|
|
|
|
def test_bottomright__invalid_value(self):
|
|
"""Ensures the bottomright attribute handles invalid values correctly.
|
|
"""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", 1, (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.bottomright = value
|
|
|
|
def test_bottomright__del(self):
|
|
"""Ensures the bottomright attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.bottomright
|
|
|
|
def test_center(self):
|
|
"""Changing the center attribute moves the rect and does not change
|
|
the rect's size
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_center = (r.centerx + 20, r.centery + 30)
|
|
expected_topleft = (r.left + 20, r.top + 30)
|
|
old_size = r.size
|
|
|
|
r.center = new_center
|
|
self.assertEqual(new_center, r.center)
|
|
self.assertEqual(expected_topleft, r.topleft)
|
|
self.assertEqual(old_size, r.size)
|
|
|
|
def test_center__invalid_value(self):
|
|
"""Ensures the center attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", 1, (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.center = value
|
|
|
|
def test_center__del(self):
|
|
"""Ensures the center attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.center
|
|
|
|
def test_midleft(self):
|
|
"""Changing the midleft attribute moves the rect and does not change
|
|
the rect's size
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_midleft = (r.left + 20, r.centery + 30)
|
|
expected_topleft = (r.left + 20, r.top + 30)
|
|
old_size = r.size
|
|
|
|
r.midleft = new_midleft
|
|
self.assertEqual(new_midleft, r.midleft)
|
|
self.assertEqual(expected_topleft, r.topleft)
|
|
self.assertEqual(old_size, r.size)
|
|
|
|
def test_midleft__invalid_value(self):
|
|
"""Ensures the midleft attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", 1, (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.midleft = value
|
|
|
|
def test_midleft__del(self):
|
|
"""Ensures the midleft attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.midleft
|
|
|
|
def test_midright(self):
|
|
"""Changing the midright attribute moves the rect and does not change
|
|
the rect's size
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_midright = (r.right + 20, r.centery + 30)
|
|
expected_topleft = (r.left + 20, r.top + 30)
|
|
old_size = r.size
|
|
|
|
r.midright = new_midright
|
|
self.assertEqual(new_midright, r.midright)
|
|
self.assertEqual(expected_topleft, r.topleft)
|
|
self.assertEqual(old_size, r.size)
|
|
|
|
def test_midright__invalid_value(self):
|
|
"""Ensures the midright attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", 1, (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.midright = value
|
|
|
|
def test_midright__del(self):
|
|
"""Ensures the midright attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.midright
|
|
|
|
def test_midtop(self):
|
|
"""Changing the midtop attribute moves the rect and does not change
|
|
the rect's size
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_midtop = (r.centerx + 20, r.top + 30)
|
|
expected_topleft = (r.left + 20, r.top + 30)
|
|
old_size = r.size
|
|
|
|
r.midtop = new_midtop
|
|
self.assertEqual(new_midtop, r.midtop)
|
|
self.assertEqual(expected_topleft, r.topleft)
|
|
self.assertEqual(old_size, r.size)
|
|
|
|
def test_midtop__invalid_value(self):
|
|
"""Ensures the midtop attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", 1, (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.midtop = value
|
|
|
|
def test_midtop__del(self):
|
|
"""Ensures the midtop attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.midtop
|
|
|
|
def test_midbottom(self):
|
|
"""Changing the midbottom attribute moves the rect and does not change
|
|
the rect's size
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_midbottom = (r.centerx + 20, r.bottom + 30)
|
|
expected_topleft = (r.left + 20, r.top + 30)
|
|
old_size = r.size
|
|
|
|
r.midbottom = new_midbottom
|
|
self.assertEqual(new_midbottom, r.midbottom)
|
|
self.assertEqual(expected_topleft, r.topleft)
|
|
self.assertEqual(old_size, r.size)
|
|
|
|
def test_midbottom__invalid_value(self):
|
|
"""Ensures the midbottom attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", 1, (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.midbottom = value
|
|
|
|
def test_midbottom__del(self):
|
|
"""Ensures the midbottom attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.midbottom
|
|
|
|
def test_width(self):
|
|
"""Changing the width resizes the rect from the top-left corner
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_width = 10
|
|
old_topleft = r.topleft
|
|
old_height = r.height
|
|
|
|
r.width = new_width
|
|
self.assertEqual(new_width, r.width)
|
|
self.assertEqual(old_height, r.height)
|
|
self.assertEqual(old_topleft, r.topleft)
|
|
|
|
def test_width__invalid_value(self):
|
|
"""Ensures the width attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.width = value
|
|
|
|
def test_width__del(self):
|
|
"""Ensures the width attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.width
|
|
|
|
def test_height(self):
|
|
"""Changing the height resizes the rect from the top-left corner
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_height = 10
|
|
old_topleft = r.topleft
|
|
old_width = r.width
|
|
|
|
r.height = new_height
|
|
self.assertEqual(new_height, r.height)
|
|
self.assertEqual(old_width, r.width)
|
|
self.assertEqual(old_topleft, r.topleft)
|
|
|
|
def test_height__invalid_value(self):
|
|
"""Ensures the height attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.height = value
|
|
|
|
def test_height__del(self):
|
|
"""Ensures the height attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.height
|
|
|
|
def test_size(self):
|
|
"""Changing the size resizes the rect from the top-left corner
|
|
"""
|
|
r = Rect(1, 2, 3, 4)
|
|
new_size = (10, 20)
|
|
old_topleft = r.topleft
|
|
|
|
r.size = new_size
|
|
self.assertEqual(new_size, r.size)
|
|
self.assertEqual(old_topleft, r.topleft)
|
|
|
|
def test_size__invalid_value(self):
|
|
"""Ensures the size attribute handles invalid values correctly."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
for value in (None, [], "1", 1, (1,), [1, 2, 3]):
|
|
with self.assertRaises(TypeError):
|
|
r.size = value
|
|
|
|
def test_size__del(self):
|
|
"""Ensures the size attribute can't be deleted."""
|
|
r = Rect(0, 0, 1, 1)
|
|
|
|
with self.assertRaises(AttributeError):
|
|
del r.size
|
|
|
|
def test_contains(self):
|
|
r = Rect(1, 2, 3, 4)
|
|
|
|
self.assertTrue(
|
|
r.contains(Rect(2, 3, 1, 1)), "r does not contain Rect(2, 3, 1, 1)"
|
|
)
|
|
self.assertTrue(
|
|
r.contains(Rect(r)), "r does not contain the same rect as itself"
|
|
)
|
|
self.assertTrue(
|
|
r.contains(Rect(2, 3, 0, 0)),
|
|
"r does not contain an empty rect within its bounds",
|
|
)
|
|
self.assertFalse(r.contains(Rect(0, 0, 1, 2)), "r contains Rect(0, 0, 1, 2)")
|
|
self.assertFalse(r.contains(Rect(4, 6, 1, 1)), "r contains Rect(4, 6, 1, 1)")
|
|
self.assertFalse(r.contains(Rect(4, 6, 0, 0)), "r contains Rect(4, 6, 0, 0)")
|
|
|
|
def test_collidepoint(self):
|
|
r = Rect(1, 2, 3, 4)
|
|
|
|
self.assertTrue(
|
|
r.collidepoint(r.left, r.top), "r does not collide with point (left, top)"
|
|
)
|
|
self.assertFalse(
|
|
r.collidepoint(r.left - 1, r.top), "r collides with point (left - 1, top)"
|
|
)
|
|
self.assertFalse(
|
|
r.collidepoint(r.left, r.top - 1), "r collides with point (left, top - 1)"
|
|
)
|
|
self.assertFalse(
|
|
r.collidepoint(r.left - 1, r.top - 1),
|
|
"r collides with point (left - 1, top - 1)",
|
|
)
|
|
|
|
self.assertTrue(
|
|
r.collidepoint(r.right - 1, r.bottom - 1),
|
|
"r does not collide with point (right - 1, bottom - 1)",
|
|
)
|
|
self.assertFalse(
|
|
r.collidepoint(r.right, r.bottom), "r collides with point (right, bottom)"
|
|
)
|
|
self.assertFalse(
|
|
r.collidepoint(r.right - 1, r.bottom),
|
|
"r collides with point (right - 1, bottom)",
|
|
)
|
|
self.assertFalse(
|
|
r.collidepoint(r.right, r.bottom - 1),
|
|
"r collides with point (right, bottom - 1)",
|
|
)
|
|
|
|
def test_inflate__larger(self):
|
|
"""The inflate method inflates around the center of the rectangle
|
|
"""
|
|
r = Rect(2, 4, 6, 8)
|
|
r2 = r.inflate(4, 6)
|
|
|
|
self.assertEqual(r.center, r2.center)
|
|
self.assertEqual(r.left - 2, r2.left)
|
|
self.assertEqual(r.top - 3, r2.top)
|
|
self.assertEqual(r.right + 2, r2.right)
|
|
self.assertEqual(r.bottom + 3, r2.bottom)
|
|
self.assertEqual(r.width + 4, r2.width)
|
|
self.assertEqual(r.height + 6, r2.height)
|
|
|
|
def test_inflate__smaller(self):
|
|
"""The inflate method inflates around the center of the rectangle
|
|
"""
|
|
r = Rect(2, 4, 6, 8)
|
|
r2 = r.inflate(-4, -6)
|
|
|
|
self.assertEqual(r.center, r2.center)
|
|
self.assertEqual(r.left + 2, r2.left)
|
|
self.assertEqual(r.top + 3, r2.top)
|
|
self.assertEqual(r.right - 2, r2.right)
|
|
self.assertEqual(r.bottom - 3, r2.bottom)
|
|
self.assertEqual(r.width - 4, r2.width)
|
|
self.assertEqual(r.height - 6, r2.height)
|
|
|
|
def test_inflate_ip__larger(self):
|
|
"""The inflate_ip method inflates around the center of the rectangle
|
|
"""
|
|
r = Rect(2, 4, 6, 8)
|
|
r2 = Rect(r)
|
|
r2.inflate_ip(-4, -6)
|
|
|
|
self.assertEqual(r.center, r2.center)
|
|
self.assertEqual(r.left + 2, r2.left)
|
|
self.assertEqual(r.top + 3, r2.top)
|
|
self.assertEqual(r.right - 2, r2.right)
|
|
self.assertEqual(r.bottom - 3, r2.bottom)
|
|
self.assertEqual(r.width - 4, r2.width)
|
|
self.assertEqual(r.height - 6, r2.height)
|
|
|
|
def test_inflate_ip__smaller(self):
|
|
"""The inflate method inflates around the center of the rectangle
|
|
"""
|
|
r = Rect(2, 4, 6, 8)
|
|
r2 = Rect(r)
|
|
r2.inflate_ip(-4, -6)
|
|
|
|
self.assertEqual(r.center, r2.center)
|
|
self.assertEqual(r.left + 2, r2.left)
|
|
self.assertEqual(r.top + 3, r2.top)
|
|
self.assertEqual(r.right - 2, r2.right)
|
|
self.assertEqual(r.bottom - 3, r2.bottom)
|
|
self.assertEqual(r.width - 4, r2.width)
|
|
self.assertEqual(r.height - 6, r2.height)
|
|
|
|
def test_clamp(self):
|
|
r = Rect(10, 10, 10, 10)
|
|
c = Rect(19, 12, 5, 5).clamp(r)
|
|
self.assertEqual(c.right, r.right)
|
|
self.assertEqual(c.top, 12)
|
|
c = Rect(1, 2, 3, 4).clamp(r)
|
|
self.assertEqual(c.topleft, r.topleft)
|
|
c = Rect(5, 500, 22, 33).clamp(r)
|
|
self.assertEqual(c.center, r.center)
|
|
|
|
def test_clamp_ip(self):
|
|
r = Rect(10, 10, 10, 10)
|
|
c = Rect(19, 12, 5, 5)
|
|
c.clamp_ip(r)
|
|
self.assertEqual(c.right, r.right)
|
|
self.assertEqual(c.top, 12)
|
|
c = Rect(1, 2, 3, 4)
|
|
c.clamp_ip(r)
|
|
self.assertEqual(c.topleft, r.topleft)
|
|
c = Rect(5, 500, 22, 33)
|
|
c.clamp_ip(r)
|
|
self.assertEqual(c.center, r.center)
|
|
|
|
def test_clip(self):
|
|
r1 = Rect(1, 2, 3, 4)
|
|
self.assertEqual(Rect(1, 2, 2, 2), r1.clip(Rect(0, 0, 3, 4)))
|
|
self.assertEqual(Rect(2, 2, 2, 4), r1.clip(Rect(2, 2, 10, 20)))
|
|
self.assertEqual(Rect(2, 3, 1, 2), r1.clip(Rect(2, 3, 1, 2)))
|
|
self.assertEqual((0, 0), r1.clip(20, 30, 5, 6).size)
|
|
self.assertEqual(
|
|
r1, r1.clip(Rect(r1)), "r1 does not clip an identical rect to itself"
|
|
)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline(self):
|
|
"""Ensures clipline handles four int parameters.
|
|
|
|
Tests the clipline(x1, y1, x2, y2) format.
|
|
"""
|
|
rect = Rect((1, 2), (35, 40))
|
|
x1 = 5
|
|
y1 = 6
|
|
x2 = 11
|
|
y2 = 19
|
|
expected_line = ((x1, y1), (x2, y2))
|
|
|
|
clipped_line = rect.clipline(x1, y1, x2, y2)
|
|
|
|
self.assertIsInstance(clipped_line, tuple)
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__two_sequences(self):
|
|
"""Ensures clipline handles a sequence of two sequences.
|
|
|
|
Tests the clipline((x1, y1), (x2, y2)) format.
|
|
Tests the sequences as different types.
|
|
"""
|
|
rect = Rect((1, 2), (35, 40))
|
|
pt1 = (5, 6)
|
|
pt2 = (11, 19)
|
|
|
|
INNER_SEQUENCES = (list, tuple, Vector2)
|
|
expected_line = (pt1, pt2)
|
|
|
|
for inner_seq1 in INNER_SEQUENCES:
|
|
endpt1 = inner_seq1(pt1)
|
|
|
|
for inner_seq2 in INNER_SEQUENCES:
|
|
clipped_line = rect.clipline((endpt1, inner_seq2(pt2)))
|
|
|
|
self.assertIsInstance(clipped_line, tuple)
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__sequence_of_four_ints(self):
|
|
"""Ensures clipline handles a sequence of four ints.
|
|
|
|
Tests the clipline((x1, y1, x2, y2)) format.
|
|
Tests the sequence as different types.
|
|
"""
|
|
rect = Rect((1, 2), (35, 40))
|
|
line = (5, 6, 11, 19)
|
|
expected_line = ((line[0], line[1]), (line[2], line[3]))
|
|
|
|
for outer_seq in (list, tuple):
|
|
clipped_line = rect.clipline(outer_seq(line))
|
|
|
|
self.assertIsInstance(clipped_line, tuple)
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__sequence_of_two_sequences(self):
|
|
"""Ensures clipline handles a sequence of two sequences.
|
|
|
|
Tests the clipline(((x1, y1), (x2, y2))) format.
|
|
Tests the sequences as different types.
|
|
"""
|
|
rect = Rect((1, 2), (35, 40))
|
|
pt1 = (5, 6)
|
|
pt2 = (11, 19)
|
|
|
|
INNER_SEQUENCES = (list, tuple, Vector2)
|
|
expected_line = (pt1, pt2)
|
|
|
|
for inner_seq1 in INNER_SEQUENCES:
|
|
endpt1 = inner_seq1(pt1)
|
|
|
|
for inner_seq2 in INNER_SEQUENCES:
|
|
endpt2 = inner_seq2(pt2)
|
|
|
|
for outer_seq in (list, tuple):
|
|
clipped_line = rect.clipline(outer_seq((endpt1, endpt2)))
|
|
|
|
self.assertIsInstance(clipped_line, tuple)
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__floats(self):
|
|
"""Ensures clipline handles float parameters."""
|
|
rect = Rect((1, 2), (35, 40))
|
|
x1 = 5.9
|
|
y1 = 6.9
|
|
x2 = 11.9
|
|
y2 = 19.9
|
|
|
|
# Floats are truncated.
|
|
expected_line = (
|
|
(math.floor(x1), math.floor(y1)),
|
|
(math.floor(x2), math.floor(y2)),
|
|
)
|
|
|
|
clipped_line = rect.clipline(x1, y1, x2, y2)
|
|
|
|
self.assertIsInstance(clipped_line, tuple)
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__no_overlap(self):
|
|
"""Ensures lines that do not overlap the rect are not clipped."""
|
|
rect = Rect((10, 25), (15, 20))
|
|
# Use a bigger rect to help create test lines.
|
|
big_rect = rect.inflate(2, 2)
|
|
lines = (
|
|
(big_rect.bottomleft, big_rect.topleft), # Left edge.
|
|
(big_rect.topleft, big_rect.topright), # Top edge.
|
|
(big_rect.topright, big_rect.bottomright), # Right edge.
|
|
(big_rect.bottomright, big_rect.bottomleft),
|
|
) # Bottom edge.
|
|
expected_line = ()
|
|
|
|
# Test lines outside rect.
|
|
for line in lines:
|
|
clipped_line = rect.clipline(line)
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__both_endpoints_outside(self):
|
|
"""Ensures lines that overlap the rect are clipped.
|
|
|
|
Testing lines with both endpoints outside the rect.
|
|
"""
|
|
rect = Rect((0, 0), (20, 20))
|
|
# Use a bigger rect to help create test lines.
|
|
big_rect = rect.inflate(2, 2)
|
|
|
|
# Create a dict of lines and expected results.
|
|
line_dict = {
|
|
(big_rect.midleft, big_rect.midright): (
|
|
rect.midleft,
|
|
(rect.midright[0] - 1, rect.midright[1]),
|
|
),
|
|
(big_rect.midtop, big_rect.midbottom): (
|
|
rect.midtop,
|
|
(rect.midbottom[0], rect.midbottom[1] - 1),
|
|
),
|
|
# Diagonals.
|
|
(big_rect.topleft, big_rect.bottomright): (
|
|
rect.topleft,
|
|
(rect.bottomright[0] - 1, rect.bottomright[1] - 1),
|
|
),
|
|
# This line needs a small adjustment to make sure it intersects
|
|
# the rect correctly.
|
|
(
|
|
(big_rect.topright[0] - 1, big_rect.topright[1]),
|
|
(big_rect.bottomleft[0], big_rect.bottomleft[1] - 1),
|
|
): (
|
|
(rect.topright[0] - 1, rect.topright[1]),
|
|
(rect.bottomleft[0], rect.bottomleft[1] - 1),
|
|
),
|
|
}
|
|
|
|
for line, expected_line in line_dict.items():
|
|
clipped_line = rect.clipline(line)
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
# Swap endpoints to test for symmetry.
|
|
expected_line = (expected_line[1], expected_line[0])
|
|
|
|
clipped_line = rect.clipline((line[1], line[0]))
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__both_endpoints_inside(self):
|
|
"""Ensures lines that overlap the rect are clipped.
|
|
|
|
Testing lines with both endpoints inside the rect.
|
|
"""
|
|
rect = Rect((-10, -5), (20, 20))
|
|
# Use a smaller rect to help create test lines.
|
|
small_rect = rect.inflate(-2, -2)
|
|
|
|
lines = (
|
|
(small_rect.midleft, small_rect.midright),
|
|
(small_rect.midtop, small_rect.midbottom),
|
|
# Diagonals.
|
|
(small_rect.topleft, small_rect.bottomright),
|
|
(small_rect.topright, small_rect.bottomleft),
|
|
)
|
|
|
|
for line in lines:
|
|
expected_line = line
|
|
|
|
clipped_line = rect.clipline(line)
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
# Swap endpoints to test for symmetry.
|
|
expected_line = (expected_line[1], expected_line[0])
|
|
|
|
clipped_line = rect.clipline((line[1], line[0]))
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__endpoints_inside_and_outside(self):
|
|
"""Ensures lines that overlap the rect are clipped.
|
|
|
|
Testing lines with one endpoint outside the rect and the other is
|
|
inside the rect.
|
|
"""
|
|
rect = Rect((0, 0), (21, 21))
|
|
# Use a bigger rect to help create test lines.
|
|
big_rect = rect.inflate(2, 2)
|
|
|
|
# Create a dict of lines and expected results.
|
|
line_dict = {
|
|
(big_rect.midleft, rect.center): (rect.midleft, rect.center),
|
|
(big_rect.midtop, rect.center): (rect.midtop, rect.center),
|
|
(big_rect.midright, rect.center): (
|
|
(rect.midright[0] - 1, rect.midright[1]),
|
|
rect.center,
|
|
),
|
|
(big_rect.midbottom, rect.center): (
|
|
(rect.midbottom[0], rect.midbottom[1] - 1),
|
|
rect.center,
|
|
),
|
|
# Diagonals.
|
|
(big_rect.topleft, rect.center): (rect.topleft, rect.center),
|
|
(big_rect.topright, rect.center): (
|
|
(rect.topright[0] - 1, rect.topright[1]),
|
|
rect.center,
|
|
),
|
|
(big_rect.bottomright, rect.center): (
|
|
(rect.bottomright[0] - 1, rect.bottomright[1] - 1),
|
|
rect.center,
|
|
),
|
|
# This line needs a small adjustment to make sure it intersects
|
|
# the rect correctly.
|
|
((big_rect.bottomleft[0], big_rect.bottomleft[1] - 1), rect.center): (
|
|
(rect.bottomleft[0], rect.bottomleft[1] - 1),
|
|
rect.center,
|
|
),
|
|
}
|
|
|
|
for line, expected_line in line_dict.items():
|
|
clipped_line = rect.clipline(line)
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
# Swap endpoints to test for symmetry.
|
|
expected_line = (expected_line[1], expected_line[0])
|
|
|
|
clipped_line = rect.clipline((line[1], line[0]))
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__edges(self):
|
|
"""Ensures clipline properly clips line that are along the rect edges.
|
|
"""
|
|
rect = Rect((10, 25), (15, 20))
|
|
|
|
# Create a dict of edges and expected results.
|
|
edge_dict = {
|
|
# Left edge.
|
|
(rect.bottomleft, rect.topleft): (
|
|
(rect.bottomleft[0], rect.bottomleft[1] - 1),
|
|
rect.topleft,
|
|
),
|
|
# Top edge.
|
|
(rect.topleft, rect.topright): (
|
|
rect.topleft,
|
|
(rect.topright[0] - 1, rect.topright[1]),
|
|
),
|
|
# Right edge.
|
|
(rect.topright, rect.bottomright): (),
|
|
# Bottom edge.
|
|
(rect.bottomright, rect.bottomleft): (),
|
|
}
|
|
|
|
for edge, expected_line in edge_dict.items():
|
|
clipped_line = rect.clipline(edge)
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
# Swap endpoints to test for symmetry.
|
|
if expected_line:
|
|
expected_line = (expected_line[1], expected_line[0])
|
|
|
|
clipped_line = rect.clipline((edge[1], edge[0]))
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__equal_endpoints_with_overlap(self):
|
|
"""Ensures clipline handles lines with both endpoints the same.
|
|
|
|
Testing lines that overlap the rect.
|
|
"""
|
|
rect = Rect((10, 25), (15, 20))
|
|
|
|
# Test all the points in and on a rect.
|
|
pts = (
|
|
(x, y)
|
|
for x in range(rect.left, rect.right)
|
|
for y in range(rect.top, rect.bottom)
|
|
)
|
|
|
|
for pt in pts:
|
|
expected_line = (pt, pt)
|
|
|
|
clipped_line = rect.clipline((pt, pt))
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__equal_endpoints_no_overlap(self):
|
|
"""Ensures clipline handles lines with both endpoints the same.
|
|
|
|
Testing lines that do not overlap the rect.
|
|
"""
|
|
expected_line = ()
|
|
rect = Rect((10, 25), (15, 20))
|
|
|
|
# Test points outside rect.
|
|
for pt in test_utils.rect_perimeter_pts(rect.inflate(2, 2)):
|
|
clipped_line = rect.clipline((pt, pt))
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__zero_size_rect(self):
|
|
"""Ensures clipline handles zero sized rects correctly."""
|
|
expected_line = ()
|
|
|
|
for size in ((0, 15), (15, 0), (0, 0)):
|
|
rect = Rect((10, 25), size)
|
|
|
|
clipped_line = rect.clipline(rect.topleft, rect.topleft)
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__negative_size_rect(self):
|
|
"""Ensures clipline handles negative sized rects correctly."""
|
|
expected_line = ()
|
|
|
|
for size in ((-15, 20), (15, -20), (-15, -20)):
|
|
rect = Rect((10, 25), size)
|
|
norm_rect = rect.copy()
|
|
norm_rect.normalize()
|
|
# Use a bigger rect to help create test lines.
|
|
big_rect = norm_rect.inflate(2, 2)
|
|
|
|
# Create a dict of lines and expected results. Some line have both
|
|
# endpoints outside the rect and some have one inside and one
|
|
# outside.
|
|
line_dict = {
|
|
(big_rect.midleft, big_rect.midright): (
|
|
norm_rect.midleft,
|
|
(norm_rect.midright[0] - 1, norm_rect.midright[1]),
|
|
),
|
|
(big_rect.midtop, big_rect.midbottom): (
|
|
norm_rect.midtop,
|
|
(norm_rect.midbottom[0], norm_rect.midbottom[1] - 1),
|
|
),
|
|
(big_rect.midleft, norm_rect.center): (
|
|
norm_rect.midleft,
|
|
norm_rect.center,
|
|
),
|
|
(big_rect.midtop, norm_rect.center): (
|
|
norm_rect.midtop,
|
|
norm_rect.center,
|
|
),
|
|
(big_rect.midright, norm_rect.center): (
|
|
(norm_rect.midright[0] - 1, norm_rect.midright[1]),
|
|
norm_rect.center,
|
|
),
|
|
(big_rect.midbottom, norm_rect.center): (
|
|
(norm_rect.midbottom[0], norm_rect.midbottom[1] - 1),
|
|
norm_rect.center,
|
|
),
|
|
}
|
|
|
|
for line, expected_line in line_dict.items():
|
|
clipped_line = rect.clipline(line)
|
|
|
|
# Make sure rect wasn't normalized.
|
|
self.assertNotEqual(rect, norm_rect)
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
# Swap endpoints to test for symmetry.
|
|
expected_line = (expected_line[1], expected_line[0])
|
|
|
|
clipped_line = rect.clipline((line[1], line[0]))
|
|
|
|
self.assertTupleEqual(clipped_line, expected_line)
|
|
|
|
@unittest.skipIf(SDL1, "rect.clipline not available in SDL1")
|
|
def test_clipline__invalid_line(self):
|
|
"""Ensures clipline handles invalid lines correctly."""
|
|
rect = Rect((0, 0), (10, 20))
|
|
invalid_lines = (
|
|
(),
|
|
(1,),
|
|
(1, 2),
|
|
(1, 2, 3),
|
|
(1, 2, 3, 4, 5),
|
|
((1, 2),),
|
|
((1, 2), (3,)),
|
|
((1, 2), 3),
|
|
((1, 2, 5), (3, 4)),
|
|
((1, 2), (3, 4, 5)),
|
|
((1, 2), (3, 4), (5, 6)),
|
|
)
|
|
|
|
for line in invalid_lines:
|
|
with self.assertRaises(TypeError):
|
|
clipped_line = rect.clipline(line)
|
|
|
|
with self.assertRaises(TypeError):
|
|
clipped_line = rect.clipline(*line)
|
|
|
|
@unittest.skipIf(IS_PYPY, "fails on pypy sometimes")
|
|
def test_move(self):
|
|
r = Rect(1, 2, 3, 4)
|
|
move_x = 10
|
|
move_y = 20
|
|
r2 = r.move(move_x, move_y)
|
|
expected_r2 = Rect(r.left + move_x, r.top + move_y, r.width, r.height)
|
|
self.assertEqual(expected_r2, r2)
|
|
|
|
@unittest.skipIf(IS_PYPY, "fails on pypy sometimes")
|
|
def test_move_ip(self):
|
|
r = Rect(1, 2, 3, 4)
|
|
r2 = Rect(r)
|
|
move_x = 10
|
|
move_y = 20
|
|
r2.move_ip(move_x, move_y)
|
|
expected_r2 = Rect(r.left + move_x, r.top + move_y, r.width, r.height)
|
|
self.assertEqual(expected_r2, r2)
|
|
|
|
def test_update_XYWidthHeight(self):
|
|
"""Test update with 4 int values(x, y, w, h)"""
|
|
rect = Rect(0, 0, 1, 1)
|
|
rect.update(1, 2, 3, 4)
|
|
|
|
self.assertEqual(1, rect.left)
|
|
self.assertEqual(2, rect.top)
|
|
self.assertEqual(3, rect.width)
|
|
self.assertEqual(4, rect.height)
|
|
|
|
def test_update__TopLeftSize(self):
|
|
"""Test update with 2 tuples((x, y), (w, h))"""
|
|
rect = Rect(0, 0, 1, 1)
|
|
rect.update((1, 2), (3, 4))
|
|
|
|
self.assertEqual(1, rect.left)
|
|
self.assertEqual(2, rect.top)
|
|
self.assertEqual(3, rect.width)
|
|
self.assertEqual(4, rect.height)
|
|
|
|
def test_update__List(self):
|
|
"""Test update with list"""
|
|
rect = Rect(0, 0, 1, 1)
|
|
rect2 = [1, 2, 3, 4]
|
|
rect.update(rect2)
|
|
|
|
self.assertEqual(1, rect.left)
|
|
self.assertEqual(2, rect.top)
|
|
self.assertEqual(3, rect.width)
|
|
self.assertEqual(4, rect.height)
|
|
|
|
def test_update__RectObject(self):
|
|
"""Test update with other rect object"""
|
|
rect = Rect(0, 0, 1, 1)
|
|
rect2 = Rect(1, 2, 3, 4)
|
|
rect.update(rect2)
|
|
|
|
self.assertEqual(1, rect.left)
|
|
self.assertEqual(2, rect.top)
|
|
self.assertEqual(3, rect.width)
|
|
self.assertEqual(4, rect.height)
|
|
|
|
def test_union(self):
|
|
r1 = Rect(1, 1, 1, 2)
|
|
r2 = Rect(-2, -2, 1, 2)
|
|
self.assertEqual(Rect(-2, -2, 4, 5), r1.union(r2))
|
|
|
|
def test_union__with_identical_Rect(self):
|
|
r1 = Rect(1, 2, 3, 4)
|
|
self.assertEqual(r1, r1.union(Rect(r1)))
|
|
|
|
def test_union_ip(self):
|
|
r1 = Rect(1, 1, 1, 2)
|
|
r2 = Rect(-2, -2, 1, 2)
|
|
r1.union_ip(r2)
|
|
self.assertEqual(Rect(-2, -2, 4, 5), r1)
|
|
|
|
def test_unionall(self):
|
|
r1 = Rect(0, 0, 1, 1)
|
|
r2 = Rect(-2, -2, 1, 1)
|
|
r3 = Rect(2, 2, 1, 1)
|
|
|
|
r4 = r1.unionall([r2, r3])
|
|
self.assertEqual(Rect(-2, -2, 5, 5), r4)
|
|
|
|
def test_unionall__invalid_rect_format(self):
|
|
"""Ensures unionall correctly handles invalid rect parameters."""
|
|
numbers = [0, 1.2, 2, 3.3]
|
|
strs = ["a", "b", "c"]
|
|
nones = [None, None]
|
|
|
|
for invalid_rects in (numbers, strs, nones):
|
|
with self.assertRaises(TypeError):
|
|
Rect(0, 0, 1, 1).unionall(invalid_rects)
|
|
|
|
def test_unionall_ip(self):
|
|
r1 = Rect(0, 0, 1, 1)
|
|
r2 = Rect(-2, -2, 1, 1)
|
|
r3 = Rect(2, 2, 1, 1)
|
|
|
|
r1.unionall_ip([r2, r3])
|
|
self.assertEqual(Rect(-2, -2, 5, 5), r1)
|
|
|
|
# Bug for an empty list. Would return a Rect instead of None.
|
|
self.assertTrue(r1.unionall_ip([]) is None)
|
|
|
|
def test_unionall__invalid_rect_format(self):
|
|
"""Ensures unionall_ip correctly handles invalid rect parameters."""
|
|
numbers = [0, 1.2, 2, 3.3]
|
|
strs = ["a", "b", "c"]
|
|
nones = [None, None]
|
|
|
|
for invalid_rects in (numbers, strs, nones):
|
|
with self.assertRaises(TypeError):
|
|
Rect(0, 0, 1, 1).unionall_ip(invalid_rects)
|
|
|
|
def test_colliderect(self):
|
|
r1 = Rect(1, 2, 3, 4)
|
|
self.assertTrue(
|
|
r1.colliderect(Rect(0, 0, 2, 3)),
|
|
"r1 does not collide with Rect(0, 0, 2, 3)",
|
|
)
|
|
self.assertFalse(
|
|
r1.colliderect(Rect(0, 0, 1, 2)), "r1 collides with Rect(0, 0, 1, 2)"
|
|
)
|
|
self.assertFalse(
|
|
r1.colliderect(Rect(r1.right, r1.bottom, 2, 2)),
|
|
"r1 collides with Rect(r1.right, r1.bottom, 2, 2)",
|
|
)
|
|
self.assertTrue(
|
|
r1.colliderect(Rect(r1.left + 1, r1.top + 1, r1.width - 2, r1.height - 2)),
|
|
"r1 does not collide with Rect(r1.left + 1, r1.top + 1, "
|
|
+ "r1.width - 2, r1.height - 2)",
|
|
)
|
|
self.assertTrue(
|
|
r1.colliderect(Rect(r1.left - 1, r1.top - 1, r1.width + 2, r1.height + 2)),
|
|
"r1 does not collide with Rect(r1.left - 1, r1.top - 1, "
|
|
+ "r1.width + 2, r1.height + 2)",
|
|
)
|
|
self.assertTrue(
|
|
r1.colliderect(Rect(r1)), "r1 does not collide with an identical rect"
|
|
)
|
|
self.assertFalse(
|
|
r1.colliderect(Rect(r1.right, r1.bottom, 0, 0)),
|
|
"r1 collides with Rect(r1.right, r1.bottom, 0, 0)",
|
|
)
|
|
self.assertFalse(
|
|
r1.colliderect(Rect(r1.right, r1.bottom, 1, 1)),
|
|
"r1 collides with Rect(r1.right, r1.bottom, 1, 1)",
|
|
)
|
|
|
|
@unittest.skipIf(IS_PYPY, "fails on pypy3 sometimes")
|
|
def testEquals(self):
|
|
""" check to see how the rect uses __eq__
|
|
"""
|
|
r1 = Rect(1, 2, 3, 4)
|
|
r2 = Rect(10, 20, 30, 40)
|
|
r3 = (10, 20, 30, 40)
|
|
r4 = Rect(10, 20, 30, 40)
|
|
|
|
class foo(Rect):
|
|
def __eq__(self, other):
|
|
return id(self) == id(other)
|
|
|
|
def __ne__(self, other):
|
|
return id(self) != id(other)
|
|
|
|
class foo2(Rect):
|
|
pass
|
|
|
|
r5 = foo(10, 20, 30, 40)
|
|
r6 = foo2(10, 20, 30, 40)
|
|
|
|
self.assertNotEqual(r5, r2)
|
|
|
|
# because we define equality differently for this subclass.
|
|
self.assertEqual(r6, r2)
|
|
|
|
rect_list = [r1, r2, r3, r4, r6]
|
|
|
|
# see if we can remove 4 of these.
|
|
rect_list.remove(r2)
|
|
rect_list.remove(r2)
|
|
rect_list.remove(r2)
|
|
rect_list.remove(r2)
|
|
self.assertRaises(ValueError, rect_list.remove, r2)
|
|
|
|
def test_collidedict(self):
|
|
"""Ensures collidedict detects collisions."""
|
|
rect = Rect(1, 1, 10, 10)
|
|
|
|
collide_item1 = ("collide 1", rect.copy())
|
|
collide_item2 = ("collide 2", Rect(5, 5, 10, 10))
|
|
no_collide_item1 = ("no collide 1", Rect(60, 60, 10, 10))
|
|
no_collide_item2 = ("no collide 2", Rect(70, 70, 10, 10))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict(
|
|
(collide_item1, collide_item2, no_collide_item1, no_collide_item2)
|
|
)
|
|
value_collide_items = (collide_item1, collide_item2)
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
key_collide_items = tuple((tuple(v), k) for k, v in value_collide_items)
|
|
|
|
for use_values in (True, False):
|
|
if use_values:
|
|
expected_items = value_collide_items
|
|
d = rect_values
|
|
else:
|
|
expected_items = key_collide_items
|
|
d = rect_keys
|
|
|
|
collide_item = rect.collidedict(d, use_values)
|
|
|
|
# The detected collision could be any of the possible items.
|
|
self.assertIn(collide_item, expected_items)
|
|
|
|
def test_collidedict__no_collision(self):
|
|
"""Ensures collidedict returns None when no collisions."""
|
|
rect = Rect(1, 1, 10, 10)
|
|
|
|
no_collide_item1 = ("no collide 1", Rect(50, 50, 10, 10))
|
|
no_collide_item2 = ("no collide 2", Rect(60, 60, 10, 10))
|
|
no_collide_item3 = ("no collide 3", Rect(70, 70, 10, 10))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3))
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
|
|
for use_values in (True, False):
|
|
d = rect_values if use_values else rect_keys
|
|
|
|
collide_item = rect.collidedict(d, use_values)
|
|
|
|
self.assertIsNone(collide_item)
|
|
|
|
def test_collidedict__barely_touching(self):
|
|
"""Ensures collidedict works correctly for rects that barely touch."""
|
|
rect = Rect(1, 1, 10, 10)
|
|
# Small rect to test barely touching collisions.
|
|
collide_rect = Rect(0, 0, 1, 1)
|
|
|
|
collide_item1 = ("collide 1", collide_rect)
|
|
no_collide_item1 = ("no collide 1", Rect(50, 50, 10, 10))
|
|
no_collide_item2 = ("no collide 2", Rect(60, 60, 10, 10))
|
|
no_collide_item3 = ("no collide 3", Rect(70, 70, 10, 10))
|
|
|
|
# Dict to check collisions with values.
|
|
no_collide_rect_values = dict(
|
|
(no_collide_item1, no_collide_item2, no_collide_item3)
|
|
)
|
|
|
|
# Dict to check collisions with keys.
|
|
no_collide_rect_keys = {tuple(v): k for k, v in no_collide_rect_values.items()}
|
|
|
|
# Tests the collide_rect on each of the rect's corners.
|
|
for attr in ("topleft", "topright", "bottomright", "bottomleft"):
|
|
setattr(collide_rect, attr, getattr(rect, attr))
|
|
|
|
for use_values in (True, False):
|
|
if use_values:
|
|
expected_item = collide_item1
|
|
d = dict(no_collide_rect_values)
|
|
else:
|
|
expected_item = (tuple(collide_item1[1]), collide_item1[0])
|
|
d = dict(no_collide_rect_keys)
|
|
|
|
d.update((expected_item,)) # Add in the expected item.
|
|
|
|
collide_item = rect.collidedict(d, use_values)
|
|
|
|
self.assertTupleEqual(collide_item, expected_item)
|
|
|
|
def test_collidedict__zero_sized_rects(self):
|
|
"""Ensures collidedict works correctly with zero sized rects.
|
|
|
|
There should be no collisions with zero sized rects.
|
|
"""
|
|
zero_rect1 = Rect(1, 1, 0, 0)
|
|
zero_rect2 = Rect(1, 1, 1, 0)
|
|
zero_rect3 = Rect(1, 1, 0, 1)
|
|
zero_rect4 = Rect(1, 1, -1, 0)
|
|
zero_rect5 = Rect(1, 1, 0, -1)
|
|
|
|
no_collide_item1 = ("no collide 1", zero_rect1.copy())
|
|
no_collide_item2 = ("no collide 2", zero_rect2.copy())
|
|
no_collide_item3 = ("no collide 3", zero_rect3.copy())
|
|
no_collide_item4 = ("no collide 4", zero_rect4.copy())
|
|
no_collide_item5 = ("no collide 5", zero_rect5.copy())
|
|
no_collide_item6 = ("no collide 6", Rect(0, 0, 10, 10))
|
|
no_collide_item7 = ("no collide 7", Rect(0, 0, 2, 2))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict(
|
|
(
|
|
no_collide_item1,
|
|
no_collide_item2,
|
|
no_collide_item3,
|
|
no_collide_item4,
|
|
no_collide_item5,
|
|
no_collide_item6,
|
|
no_collide_item7,
|
|
)
|
|
)
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
|
|
for use_values in (True, False):
|
|
d = rect_values if use_values else rect_keys
|
|
|
|
for zero_rect in (
|
|
zero_rect1,
|
|
zero_rect2,
|
|
zero_rect3,
|
|
zero_rect4,
|
|
zero_rect5,
|
|
):
|
|
collide_item = zero_rect.collidedict(d, use_values)
|
|
|
|
self.assertIsNone(collide_item)
|
|
|
|
def test_collidedict__zero_sized_rects_as_args(self):
|
|
"""Ensures collidedict works correctly with zero sized rects as args.
|
|
|
|
There should be no collisions with zero sized rects.
|
|
"""
|
|
rect = Rect(0, 0, 10, 10)
|
|
|
|
no_collide_item1 = ("no collide 1", Rect(1, 1, 0, 0))
|
|
no_collide_item2 = ("no collide 2", Rect(1, 1, 1, 0))
|
|
no_collide_item3 = ("no collide 3", Rect(1, 1, 0, 1))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3))
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
|
|
for use_values in (True, False):
|
|
d = rect_values if use_values else rect_keys
|
|
|
|
collide_item = rect.collidedict(d, use_values)
|
|
|
|
self.assertIsNone(collide_item)
|
|
|
|
def test_collidedict__negative_sized_rects(self):
|
|
"""Ensures collidedict works correctly with negative sized rects."""
|
|
neg_rect = Rect(1, 1, -1, -1)
|
|
|
|
collide_item1 = ("collide 1", neg_rect.copy())
|
|
collide_item2 = ("collide 2", Rect(0, 0, 10, 10))
|
|
no_collide_item1 = ("no collide 1", Rect(1, 1, 10, 10))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict((collide_item1, collide_item2, no_collide_item1))
|
|
value_collide_items = (collide_item1, collide_item2)
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
key_collide_items = tuple((tuple(v), k) for k, v in value_collide_items)
|
|
|
|
for use_values in (True, False):
|
|
if use_values:
|
|
collide_items = value_collide_items
|
|
d = rect_values
|
|
else:
|
|
collide_items = key_collide_items
|
|
d = rect_keys
|
|
|
|
collide_item = neg_rect.collidedict(d, use_values)
|
|
|
|
# The detected collision could be any of the possible items.
|
|
self.assertIn(collide_item, collide_items)
|
|
|
|
def test_collidedict__negative_sized_rects_as_args(self):
|
|
"""Ensures collidedict works correctly with negative sized rect args.
|
|
"""
|
|
rect = Rect(0, 0, 10, 10)
|
|
|
|
collide_item1 = ("collide 1", Rect(1, 1, -1, -1))
|
|
no_collide_item1 = ("no collide 1", Rect(1, 1, -1, 0))
|
|
no_collide_item2 = ("no collide 2", Rect(1, 1, 0, -1))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict((collide_item1, no_collide_item1, no_collide_item2))
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
|
|
for use_values in (True, False):
|
|
if use_values:
|
|
expected_item = collide_item1
|
|
d = rect_values
|
|
else:
|
|
expected_item = (tuple(collide_item1[1]), collide_item1[0])
|
|
d = rect_keys
|
|
|
|
collide_item = rect.collidedict(d, use_values)
|
|
|
|
self.assertTupleEqual(collide_item, expected_item)
|
|
|
|
def test_collidedict__invalid_dict_format(self):
|
|
"""Ensures collidedict correctly handles invalid dict parameters."""
|
|
rect = Rect(0, 0, 10, 10)
|
|
|
|
invalid_value_dict = ("collide", rect.copy())
|
|
invalid_key_dict = tuple(invalid_value_dict[1]), invalid_value_dict[0]
|
|
|
|
for use_values in (True, False):
|
|
d = invalid_value_dict if use_values else invalid_key_dict
|
|
|
|
with self.assertRaises(TypeError):
|
|
collide_item = rect.collidedict(d, use_values)
|
|
|
|
def test_collidedict__invalid_dict_value_format(self):
|
|
"""Ensures collidedict correctly handles dicts with invalid values."""
|
|
rect = Rect(0, 0, 10, 10)
|
|
rect_keys = {tuple(rect): "collide"}
|
|
|
|
with self.assertRaises(TypeError):
|
|
collide_item = rect.collidedict(rect_keys, 1)
|
|
|
|
def test_collidedict__invalid_dict_key_format(self):
|
|
"""Ensures collidedict correctly handles dicts with invalid keys."""
|
|
rect = Rect(0, 0, 10, 10)
|
|
rect_values = {"collide": rect.copy()}
|
|
|
|
with self.assertRaises(TypeError):
|
|
collide_item = rect.collidedict(rect_values)
|
|
|
|
def test_collidedict__invalid_use_values_format(self):
|
|
"""Ensures collidedict correctly handles invalid use_values parameters.
|
|
"""
|
|
rect = Rect(0, 0, 1, 1)
|
|
d = {}
|
|
|
|
for invalid_param in (None, d, 1.1):
|
|
with self.assertRaises(TypeError):
|
|
collide_item = rect.collidedict(d, invalid_param)
|
|
|
|
def test_collidedictall(self):
|
|
"""Ensures collidedictall detects collisions."""
|
|
rect = Rect(1, 1, 10, 10)
|
|
|
|
collide_item1 = ("collide 1", rect.copy())
|
|
collide_item2 = ("collide 2", Rect(5, 5, 10, 10))
|
|
no_collide_item1 = ("no collide 1", Rect(60, 60, 20, 20))
|
|
no_collide_item2 = ("no collide 2", Rect(70, 70, 20, 20))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict(
|
|
(collide_item1, collide_item2, no_collide_item1, no_collide_item2)
|
|
)
|
|
value_collide_items = [collide_item1, collide_item2]
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
key_collide_items = [(tuple(v), k) for k, v in value_collide_items]
|
|
|
|
for use_values in (True, False):
|
|
if use_values:
|
|
expected_items = value_collide_items
|
|
d = rect_values
|
|
else:
|
|
expected_items = key_collide_items
|
|
d = rect_keys
|
|
|
|
collide_items = rect.collidedictall(d, use_values)
|
|
|
|
self._assertCountEqual(collide_items, expected_items)
|
|
|
|
def test_collidedictall__no_collision(self):
|
|
"""Ensures collidedictall returns an empty list when no collisions."""
|
|
rect = Rect(1, 1, 10, 10)
|
|
|
|
no_collide_item1 = ("no collide 1", Rect(50, 50, 20, 20))
|
|
no_collide_item2 = ("no collide 2", Rect(60, 60, 20, 20))
|
|
no_collide_item3 = ("no collide 3", Rect(70, 70, 20, 20))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3))
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
|
|
expected_items = []
|
|
|
|
for use_values in (True, False):
|
|
d = rect_values if use_values else rect_keys
|
|
|
|
collide_items = rect.collidedictall(d, use_values)
|
|
|
|
self._assertCountEqual(collide_items, expected_items)
|
|
|
|
def test_collidedictall__barely_touching(self):
|
|
"""Ensures collidedictall works correctly for rects that barely touch.
|
|
"""
|
|
rect = Rect(1, 1, 10, 10)
|
|
# Small rect to test barely touching collisions.
|
|
collide_rect = Rect(0, 0, 1, 1)
|
|
|
|
collide_item1 = ("collide 1", collide_rect)
|
|
no_collide_item1 = ("no collide 1", Rect(50, 50, 20, 20))
|
|
no_collide_item2 = ("no collide 2", Rect(60, 60, 20, 20))
|
|
no_collide_item3 = ("no collide 3", Rect(70, 70, 20, 20))
|
|
|
|
# Dict to check collisions with values.
|
|
no_collide_rect_values = dict(
|
|
(no_collide_item1, no_collide_item2, no_collide_item3)
|
|
)
|
|
|
|
# Dict to check collisions with keys.
|
|
no_collide_rect_keys = {tuple(v): k for k, v in no_collide_rect_values.items()}
|
|
|
|
# Tests the collide_rect on each of the rect's corners.
|
|
for attr in ("topleft", "topright", "bottomright", "bottomleft"):
|
|
setattr(collide_rect, attr, getattr(rect, attr))
|
|
|
|
for use_values in (True, False):
|
|
if use_values:
|
|
expected_items = [collide_item1]
|
|
d = dict(no_collide_rect_values)
|
|
else:
|
|
expected_items = [(tuple(collide_item1[1]), collide_item1[0])]
|
|
d = dict(no_collide_rect_keys)
|
|
|
|
d.update(expected_items) # Add in the expected items.
|
|
|
|
collide_items = rect.collidedictall(d, use_values)
|
|
|
|
self._assertCountEqual(collide_items, expected_items)
|
|
|
|
def test_collidedictall__zero_sized_rects(self):
|
|
"""Ensures collidedictall works correctly with zero sized rects.
|
|
|
|
There should be no collisions with zero sized rects.
|
|
"""
|
|
zero_rect1 = Rect(2, 2, 0, 0)
|
|
zero_rect2 = Rect(2, 2, 2, 0)
|
|
zero_rect3 = Rect(2, 2, 0, 2)
|
|
zero_rect4 = Rect(2, 2, -2, 0)
|
|
zero_rect5 = Rect(2, 2, 0, -2)
|
|
|
|
no_collide_item1 = ("no collide 1", zero_rect1.copy())
|
|
no_collide_item2 = ("no collide 2", zero_rect2.copy())
|
|
no_collide_item3 = ("no collide 3", zero_rect3.copy())
|
|
no_collide_item4 = ("no collide 4", zero_rect4.copy())
|
|
no_collide_item5 = ("no collide 5", zero_rect5.copy())
|
|
no_collide_item6 = ("no collide 6", Rect(0, 0, 10, 10))
|
|
no_collide_item7 = ("no collide 7", Rect(0, 0, 2, 2))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict(
|
|
(
|
|
no_collide_item1,
|
|
no_collide_item2,
|
|
no_collide_item3,
|
|
no_collide_item4,
|
|
no_collide_item5,
|
|
no_collide_item6,
|
|
no_collide_item7,
|
|
)
|
|
)
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
|
|
expected_items = []
|
|
|
|
for use_values in (True, False):
|
|
d = rect_values if use_values else rect_keys
|
|
|
|
for zero_rect in (
|
|
zero_rect1,
|
|
zero_rect2,
|
|
zero_rect3,
|
|
zero_rect4,
|
|
zero_rect5,
|
|
):
|
|
collide_items = zero_rect.collidedictall(d, use_values)
|
|
|
|
self._assertCountEqual(collide_items, expected_items)
|
|
|
|
def test_collidedictall__zero_sized_rects_as_args(self):
|
|
"""Ensures collidedictall works correctly with zero sized rects
|
|
as args.
|
|
|
|
There should be no collisions with zero sized rects.
|
|
"""
|
|
rect = Rect(0, 0, 20, 20)
|
|
|
|
no_collide_item1 = ("no collide 1", Rect(2, 2, 0, 0))
|
|
no_collide_item2 = ("no collide 2", Rect(2, 2, 2, 0))
|
|
no_collide_item3 = ("no collide 3", Rect(2, 2, 0, 2))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict((no_collide_item1, no_collide_item2, no_collide_item3))
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
|
|
expected_items = []
|
|
|
|
for use_values in (True, False):
|
|
d = rect_values if use_values else rect_keys
|
|
|
|
collide_items = rect.collidedictall(d, use_values)
|
|
|
|
self._assertCountEqual(collide_items, expected_items)
|
|
|
|
def test_collidedictall__negative_sized_rects(self):
|
|
"""Ensures collidedictall works correctly with negative sized rects."""
|
|
neg_rect = Rect(2, 2, -2, -2)
|
|
|
|
collide_item1 = ("collide 1", neg_rect.copy())
|
|
collide_item2 = ("collide 2", Rect(0, 0, 20, 20))
|
|
no_collide_item1 = ("no collide 1", Rect(2, 2, 20, 20))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict((collide_item1, collide_item2, no_collide_item1))
|
|
value_collide_items = [collide_item1, collide_item2]
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
key_collide_items = [(tuple(v), k) for k, v in value_collide_items]
|
|
|
|
for use_values in (True, False):
|
|
if use_values:
|
|
expected_items = value_collide_items
|
|
d = rect_values
|
|
else:
|
|
expected_items = key_collide_items
|
|
d = rect_keys
|
|
|
|
collide_items = neg_rect.collidedictall(d, use_values)
|
|
|
|
self._assertCountEqual(collide_items, expected_items)
|
|
|
|
def test_collidedictall__negative_sized_rects_as_args(self):
|
|
"""Ensures collidedictall works correctly with negative sized rect
|
|
args.
|
|
"""
|
|
rect = Rect(0, 0, 10, 10)
|
|
|
|
collide_item1 = ("collide 1", Rect(1, 1, -1, -1))
|
|
no_collide_item1 = ("no collide 1", Rect(1, 1, -1, 0))
|
|
no_collide_item2 = ("no collide 2", Rect(1, 1, 0, -1))
|
|
|
|
# Dict to check collisions with values.
|
|
rect_values = dict((collide_item1, no_collide_item1, no_collide_item2))
|
|
value_collide_items = [collide_item1]
|
|
|
|
# Dict to check collisions with keys.
|
|
rect_keys = {tuple(v): k for k, v in rect_values.items()}
|
|
key_collide_items = [(tuple(v), k) for k, v in value_collide_items]
|
|
|
|
for use_values in (True, False):
|
|
if use_values:
|
|
expected_items = value_collide_items
|
|
d = rect_values
|
|
else:
|
|
expected_items = key_collide_items
|
|
d = rect_keys
|
|
|
|
collide_items = rect.collidedictall(d, use_values)
|
|
|
|
self._assertCountEqual(collide_items, expected_items)
|
|
|
|
def test_collidedictall__invalid_dict_format(self):
|
|
"""Ensures collidedictall correctly handles invalid dict parameters."""
|
|
rect = Rect(0, 0, 10, 10)
|
|
|
|
invalid_value_dict = ("collide", rect.copy())
|
|
invalid_key_dict = tuple(invalid_value_dict[1]), invalid_value_dict[0]
|
|
|
|
for use_values in (True, False):
|
|
d = invalid_value_dict if use_values else invalid_key_dict
|
|
|
|
with self.assertRaises(TypeError):
|
|
collide_item = rect.collidedictall(d, use_values)
|
|
|
|
def test_collidedictall__invalid_dict_value_format(self):
|
|
"""Ensures collidedictall correctly handles dicts with invalid values.
|
|
"""
|
|
rect = Rect(0, 0, 10, 10)
|
|
rect_keys = {tuple(rect): "collide"}
|
|
|
|
with self.assertRaises(TypeError):
|
|
collide_items = rect.collidedictall(rect_keys, 1)
|
|
|
|
def test_collidedictall__invalid_dict_key_format(self):
|
|
"""Ensures collidedictall correctly handles dicts with invalid keys."""
|
|
rect = Rect(0, 0, 10, 10)
|
|
rect_values = {"collide": rect.copy()}
|
|
|
|
with self.assertRaises(TypeError):
|
|
collide_items = rect.collidedictall(rect_values)
|
|
|
|
def test_collidedictall__invalid_use_values_format(self):
|
|
"""Ensures collidedictall correctly handles invalid use_values
|
|
parameters.
|
|
"""
|
|
rect = Rect(0, 0, 1, 1)
|
|
d = {}
|
|
|
|
for invalid_param in (None, d, 1.1):
|
|
with self.assertRaises(TypeError):
|
|
collide_items = rect.collidedictall(d, invalid_param)
|
|
|
|
def test_collidelist(self):
|
|
|
|
# __doc__ (as of 2008-08-02) for pygame.rect.Rect.collidelist:
|
|
|
|
# Rect.collidelist(list): return index
|
|
# test if one rectangle in a list intersects
|
|
#
|
|
# Test whether the rectangle collides with any in a sequence of
|
|
# rectangles. The index of the first collision found is returned. If
|
|
# no collisions are found an index of -1 is returned.
|
|
|
|
r = Rect(1, 1, 10, 10)
|
|
l = [Rect(50, 50, 1, 1), Rect(5, 5, 10, 10), Rect(15, 15, 1, 1)]
|
|
|
|
self.assertEqual(r.collidelist(l), 1)
|
|
|
|
f = [Rect(50, 50, 1, 1), (100, 100, 4, 4)]
|
|
self.assertEqual(r.collidelist(f), -1)
|
|
|
|
def test_collidelistall(self):
|
|
|
|
# __doc__ (as of 2008-08-02) for pygame.rect.Rect.collidelistall:
|
|
|
|
# Rect.collidelistall(list): return indices
|
|
# test if all rectangles in a list intersect
|
|
#
|
|
# Returns a list of all the indices that contain rectangles that
|
|
# collide with the Rect. If no intersecting rectangles are found, an
|
|
# empty list is returned.
|
|
|
|
r = Rect(1, 1, 10, 10)
|
|
|
|
l = [
|
|
Rect(1, 1, 10, 10),
|
|
Rect(5, 5, 10, 10),
|
|
Rect(15, 15, 1, 1),
|
|
Rect(2, 2, 1, 1),
|
|
]
|
|
self.assertEqual(r.collidelistall(l), [0, 1, 3])
|
|
|
|
f = [Rect(50, 50, 1, 1), Rect(20, 20, 5, 5)]
|
|
self.assertFalse(r.collidelistall(f))
|
|
|
|
def test_fit(self):
|
|
|
|
# __doc__ (as of 2008-08-02) for pygame.rect.Rect.fit:
|
|
|
|
# Rect.fit(Rect): return Rect
|
|
# resize and move a rectangle with aspect ratio
|
|
#
|
|
# Returns a new rectangle that is moved and resized to fit another.
|
|
# The aspect ratio of the original Rect is preserved, so the new
|
|
# rectangle may be smaller than the target in either width or height.
|
|
|
|
r = Rect(10, 10, 30, 30)
|
|
|
|
r2 = Rect(30, 30, 15, 10)
|
|
|
|
f = r.fit(r2)
|
|
self.assertTrue(r2.contains(f))
|
|
|
|
f2 = r2.fit(r)
|
|
self.assertTrue(r.contains(f2))
|
|
|
|
def test_copy(self):
|
|
r = Rect(1, 2, 10, 20)
|
|
c = r.copy()
|
|
self.assertEqual(c, r)
|
|
|
|
def test_subscript(self):
|
|
r = Rect(1, 2, 3, 4)
|
|
self.assertEqual(r[0], 1)
|
|
self.assertEqual(r[1], 2)
|
|
self.assertEqual(r[2], 3)
|
|
self.assertEqual(r[3], 4)
|
|
self.assertEqual(r[-1], 4)
|
|
self.assertEqual(r[-2], 3)
|
|
self.assertEqual(r[-4], 1)
|
|
self.assertRaises(IndexError, r.__getitem__, 5)
|
|
self.assertRaises(IndexError, r.__getitem__, -5)
|
|
self.assertEqual(r[0:2], [1, 2])
|
|
self.assertEqual(r[0:4], [1, 2, 3, 4])
|
|
self.assertEqual(r[0:-1], [1, 2, 3])
|
|
self.assertEqual(r[:], [1, 2, 3, 4])
|
|
self.assertEqual(r[...], [1, 2, 3, 4])
|
|
self.assertEqual(r[0:4:2], [1, 3])
|
|
self.assertEqual(r[0:4:3], [1, 4])
|
|
self.assertEqual(r[3::-1], [4, 3, 2, 1])
|
|
self.assertRaises(TypeError, r.__getitem__, None)
|
|
|
|
def test_ass_subscript(self):
|
|
r = Rect(0, 0, 0, 0)
|
|
r[...] = 1, 2, 3, 4
|
|
self.assertEqual(r, [1, 2, 3, 4])
|
|
self.assertRaises(TypeError, r.__setitem__, None, 0)
|
|
self.assertEqual(r, [1, 2, 3, 4])
|
|
self.assertRaises(TypeError, r.__setitem__, 0, "")
|
|
self.assertEqual(r, [1, 2, 3, 4])
|
|
self.assertRaises(IndexError, r.__setitem__, 4, 0)
|
|
self.assertEqual(r, [1, 2, 3, 4])
|
|
self.assertRaises(IndexError, r.__setitem__, -5, 0)
|
|
self.assertEqual(r, [1, 2, 3, 4])
|
|
r[0] = 10
|
|
self.assertEqual(r, [10, 2, 3, 4])
|
|
r[3] = 40
|
|
self.assertEqual(r, [10, 2, 3, 40])
|
|
r[-1] = 400
|
|
self.assertEqual(r, [10, 2, 3, 400])
|
|
r[-4] = 100
|
|
self.assertEqual(r, [100, 2, 3, 400])
|
|
r[1:3] = 0
|
|
self.assertEqual(r, [100, 0, 0, 400])
|
|
r[...] = 0
|
|
self.assertEqual(r, [0, 0, 0, 0])
|
|
r[:] = 9
|
|
self.assertEqual(r, [9, 9, 9, 9])
|
|
r[:] = 11, 12, 13, 14
|
|
self.assertEqual(r, [11, 12, 13, 14])
|
|
r[::-1] = r
|
|
self.assertEqual(r, [14, 13, 12, 11])
|
|
|
|
|
|
@unittest.skipIf(IS_PYPY, "fails on pypy")
|
|
class SubclassTest(unittest.TestCase):
|
|
class MyRect(Rect):
|
|
def __init__(self, *args, **kwds):
|
|
super(SubclassTest.MyRect, self).__init__(*args, **kwds)
|
|
self.an_attribute = True
|
|
|
|
def test_copy(self):
|
|
mr1 = self.MyRect(1, 2, 10, 20)
|
|
self.assertTrue(mr1.an_attribute)
|
|
mr2 = mr1.copy()
|
|
self.assertTrue(isinstance(mr2, self.MyRect))
|
|
self.assertRaises(AttributeError, getattr, mr2, "an_attribute")
|
|
|
|
def test_move(self):
|
|
mr1 = self.MyRect(1, 2, 10, 20)
|
|
self.assertTrue(mr1.an_attribute)
|
|
mr2 = mr1.move(1, 2)
|
|
self.assertTrue(isinstance(mr2, self.MyRect))
|
|
self.assertRaises(AttributeError, getattr, mr2, "an_attribute")
|
|
|
|
def test_inflate(self):
|
|
mr1 = self.MyRect(1, 2, 10, 20)
|
|
self.assertTrue(mr1.an_attribute)
|
|
mr2 = mr1.inflate(2, 4)
|
|
self.assertTrue(isinstance(mr2, self.MyRect))
|
|
self.assertRaises(AttributeError, getattr, mr2, "an_attribute")
|
|
|
|
def test_clamp(self):
|
|
mr1 = self.MyRect(19, 12, 5, 5)
|
|
self.assertTrue(mr1.an_attribute)
|
|
mr2 = mr1.clamp(Rect(10, 10, 10, 10))
|
|
self.assertTrue(isinstance(mr2, self.MyRect))
|
|
self.assertRaises(AttributeError, getattr, mr2, "an_attribute")
|
|
|
|
def test_clip(self):
|
|
mr1 = self.MyRect(1, 2, 3, 4)
|
|
self.assertTrue(mr1.an_attribute)
|
|
mr2 = mr1.clip(Rect(0, 0, 3, 4))
|
|
self.assertTrue(isinstance(mr2, self.MyRect))
|
|
self.assertRaises(AttributeError, getattr, mr2, "an_attribute")
|
|
|
|
def test_union(self):
|
|
mr1 = self.MyRect(1, 1, 1, 2)
|
|
self.assertTrue(mr1.an_attribute)
|
|
mr2 = mr1.union(Rect(-2, -2, 1, 2))
|
|
self.assertTrue(isinstance(mr2, self.MyRect))
|
|
self.assertRaises(AttributeError, getattr, mr2, "an_attribute")
|
|
|
|
def test_unionall(self):
|
|
mr1 = self.MyRect(0, 0, 1, 1)
|
|
self.assertTrue(mr1.an_attribute)
|
|
mr2 = mr1.unionall([Rect(-2, -2, 1, 1), Rect(2, 2, 1, 1)])
|
|
self.assertTrue(isinstance(mr2, self.MyRect))
|
|
self.assertRaises(AttributeError, getattr, mr2, "an_attribute")
|
|
|
|
def test_fit(self):
|
|
mr1 = self.MyRect(10, 10, 30, 30)
|
|
self.assertTrue(mr1.an_attribute)
|
|
mr2 = mr1.fit(Rect(30, 30, 15, 10))
|
|
self.assertTrue(isinstance(mr2, self.MyRect))
|
|
self.assertRaises(AttributeError, getattr, mr2, "an_attribute")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|