1407 lines
46 KiB
Python
1407 lines
46 KiB
Python
|
#################################### IMPORTS ###################################
|
||
|
# -*- encoding: utf-8 -*-
|
||
|
|
||
|
|
||
|
import unittest
|
||
|
|
||
|
import pygame
|
||
|
from pygame import sprite
|
||
|
|
||
|
|
||
|
################################# MODULE LEVEL #################################
|
||
|
|
||
|
|
||
|
class SpriteModuleTest(unittest.TestCase):
|
||
|
pass
|
||
|
|
||
|
|
||
|
######################### SPRITECOLLIDE FUNCTIONS TEST #########################
|
||
|
|
||
|
|
||
|
class SpriteCollideTest(unittest.TestCase):
|
||
|
def setUp(self):
|
||
|
self.ag = sprite.AbstractGroup()
|
||
|
self.ag2 = sprite.AbstractGroup()
|
||
|
self.s1 = sprite.Sprite(self.ag)
|
||
|
self.s2 = sprite.Sprite(self.ag2)
|
||
|
self.s3 = sprite.Sprite(self.ag2)
|
||
|
|
||
|
self.s1.image = pygame.Surface((50, 10), pygame.SRCALPHA, 32)
|
||
|
self.s2.image = pygame.Surface((10, 10), pygame.SRCALPHA, 32)
|
||
|
self.s3.image = pygame.Surface((10, 10), pygame.SRCALPHA, 32)
|
||
|
|
||
|
self.s1.rect = self.s1.image.get_rect()
|
||
|
self.s2.rect = self.s2.image.get_rect()
|
||
|
self.s3.rect = self.s3.image.get_rect()
|
||
|
self.s2.rect.move_ip(40, 0)
|
||
|
self.s3.rect.move_ip(100, 100)
|
||
|
|
||
|
def test_spritecollide__works_if_collided_cb_is_None(self):
|
||
|
# Test that sprites collide without collided function.
|
||
|
self.assertEqual(
|
||
|
sprite.spritecollide(self.s1, self.ag2, dokill=False, collided=None),
|
||
|
[self.s2],
|
||
|
)
|
||
|
|
||
|
def test_spritecollide__works_if_collided_cb_not_passed(self):
|
||
|
# Should also work when collided function isn't passed at all.
|
||
|
self.assertEqual(
|
||
|
sprite.spritecollide(self.s1, self.ag2, dokill=False), [self.s2]
|
||
|
)
|
||
|
|
||
|
def test_spritecollide__collided_must_be_a_callable(self):
|
||
|
# Need to pass a callable.
|
||
|
self.assertRaises(
|
||
|
TypeError, sprite.spritecollide, self.s1, self.ag2, dokill=False, collided=1
|
||
|
)
|
||
|
|
||
|
def test_spritecollide__collided_defaults_to_collide_rect(self):
|
||
|
# collide_rect should behave the same as default.
|
||
|
self.assertEqual(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=sprite.collide_rect
|
||
|
),
|
||
|
[self.s2],
|
||
|
)
|
||
|
|
||
|
def test_collide_rect_ratio__ratio_of_one_like_default(self):
|
||
|
# collide_rect_ratio should behave the same as default at a 1.0 ratio.
|
||
|
self.assertEqual(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=sprite.collide_rect_ratio(1.0)
|
||
|
),
|
||
|
[self.s2],
|
||
|
)
|
||
|
|
||
|
def test_collide_rect_ratio__collides_all_at_ratio_of_twenty(self):
|
||
|
# collide_rect_ratio should collide all at a 20.0 ratio.
|
||
|
collided_func = sprite.collide_rect_ratio(20.0)
|
||
|
expected_sprites = sorted(self.ag2.sprites(), key=id)
|
||
|
|
||
|
collided_sprites = sorted(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=collided_func
|
||
|
),
|
||
|
key=id,
|
||
|
)
|
||
|
|
||
|
self.assertListEqual(collided_sprites, expected_sprites)
|
||
|
|
||
|
def test_collide_circle__no_radius_set(self):
|
||
|
# collide_circle with no radius set.
|
||
|
self.assertEqual(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=sprite.collide_circle
|
||
|
),
|
||
|
[self.s2],
|
||
|
)
|
||
|
|
||
|
def test_collide_circle_ratio__no_radius_and_ratio_of_one(self):
|
||
|
# collide_circle_ratio with no radius set, at a 1.0 ratio.
|
||
|
self.assertEqual(
|
||
|
sprite.spritecollide(
|
||
|
self.s1,
|
||
|
self.ag2,
|
||
|
dokill=False,
|
||
|
collided=sprite.collide_circle_ratio(1.0),
|
||
|
),
|
||
|
[self.s2],
|
||
|
)
|
||
|
|
||
|
def test_collide_circle_ratio__no_radius_and_ratio_of_twenty(self):
|
||
|
# collide_circle_ratio with no radius set, at a 20.0 ratio.
|
||
|
collided_func = sprite.collide_circle_ratio(20.0)
|
||
|
expected_sprites = sorted(self.ag2.sprites(), key=id)
|
||
|
|
||
|
collided_sprites = sorted(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=collided_func
|
||
|
),
|
||
|
key=id,
|
||
|
)
|
||
|
|
||
|
self.assertListEqual(expected_sprites, collided_sprites)
|
||
|
|
||
|
def test_collide_circle__radius_set_by_collide_circle_ratio(self):
|
||
|
# Call collide_circle_ratio with no radius set, at a 20.0 ratio.
|
||
|
# That should return group ag2 AND set the radius attribute of the
|
||
|
# sprites in such a way that collide_circle would give same result as
|
||
|
# if it had been called without the radius being set.
|
||
|
collided_func = sprite.collide_circle_ratio(20.0)
|
||
|
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=collided_func
|
||
|
)
|
||
|
|
||
|
self.assertEqual(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=sprite.collide_circle
|
||
|
),
|
||
|
[self.s2],
|
||
|
)
|
||
|
|
||
|
def test_collide_circle_ratio__no_radius_and_ratio_of_two_twice(self):
|
||
|
# collide_circle_ratio with no radius set, at a 2.0 ratio,
|
||
|
# called twice to check if the bug where the calculated radius
|
||
|
# is not stored correctly in the radius attribute of each sprite.
|
||
|
collided_func = sprite.collide_circle_ratio(2.0)
|
||
|
|
||
|
# Calling collide_circle_ratio will set the radius attribute of the
|
||
|
# sprites. If an incorrect value is stored then we will not get the
|
||
|
# same result next time it is called:
|
||
|
expected_sprites = sorted(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=collided_func
|
||
|
),
|
||
|
key=id,
|
||
|
)
|
||
|
collided_sprites = sorted(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=collided_func
|
||
|
),
|
||
|
key=id,
|
||
|
)
|
||
|
|
||
|
self.assertListEqual(expected_sprites, collided_sprites)
|
||
|
|
||
|
def test_collide_circle__with_radii_set(self):
|
||
|
# collide_circle with a radius set.
|
||
|
self.s1.radius = 50
|
||
|
self.s2.radius = 10
|
||
|
self.s3.radius = 400
|
||
|
collided_func = sprite.collide_circle
|
||
|
expected_sprites = sorted(self.ag2.sprites(), key=id)
|
||
|
|
||
|
collided_sprites = sorted(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=collided_func
|
||
|
),
|
||
|
key=id,
|
||
|
)
|
||
|
|
||
|
self.assertListEqual(expected_sprites, collided_sprites)
|
||
|
|
||
|
def test_collide_circle_ratio__with_radii_set(self):
|
||
|
# collide_circle_ratio with a radius set.
|
||
|
self.s1.radius = 50
|
||
|
self.s2.radius = 10
|
||
|
self.s3.radius = 400
|
||
|
collided_func = sprite.collide_circle_ratio(0.5)
|
||
|
expected_sprites = sorted(self.ag2.sprites(), key=id)
|
||
|
|
||
|
collided_sprites = sorted(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=collided_func
|
||
|
),
|
||
|
key=id,
|
||
|
)
|
||
|
|
||
|
self.assertListEqual(expected_sprites, collided_sprites)
|
||
|
|
||
|
def test_collide_mask__opaque(self):
|
||
|
# make some fully opaque sprites that will collide with masks.
|
||
|
self.s1.image.fill((255, 255, 255, 255))
|
||
|
self.s2.image.fill((255, 255, 255, 255))
|
||
|
self.s3.image.fill((255, 255, 255, 255))
|
||
|
|
||
|
# masks should be autogenerated from image if they don't exist.
|
||
|
self.assertEqual(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=sprite.collide_mask
|
||
|
),
|
||
|
[self.s2],
|
||
|
)
|
||
|
|
||
|
self.s1.mask = pygame.mask.from_surface(self.s1.image)
|
||
|
self.s2.mask = pygame.mask.from_surface(self.s2.image)
|
||
|
self.s3.mask = pygame.mask.from_surface(self.s3.image)
|
||
|
|
||
|
# with set masks.
|
||
|
self.assertEqual(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=sprite.collide_mask
|
||
|
),
|
||
|
[self.s2],
|
||
|
)
|
||
|
|
||
|
def test_collide_mask__transparent(self):
|
||
|
# make some sprites that are fully transparent, so they won't collide.
|
||
|
self.s1.image.fill((255, 255, 255, 0))
|
||
|
self.s2.image.fill((255, 255, 255, 0))
|
||
|
self.s3.image.fill((255, 255, 255, 0))
|
||
|
|
||
|
self.s1.mask = pygame.mask.from_surface(self.s1.image, 255)
|
||
|
self.s2.mask = pygame.mask.from_surface(self.s2.image, 255)
|
||
|
self.s3.mask = pygame.mask.from_surface(self.s3.image, 255)
|
||
|
|
||
|
self.assertFalse(
|
||
|
sprite.spritecollide(
|
||
|
self.s1, self.ag2, dokill=False, collided=sprite.collide_mask
|
||
|
)
|
||
|
)
|
||
|
|
||
|
def test_spritecollideany__without_collided_callback(self):
|
||
|
|
||
|
# pygame.sprite.spritecollideany(sprite, group) -> sprite
|
||
|
# finds any sprites that collide
|
||
|
|
||
|
# if collided is not passed, all
|
||
|
# sprites must have a "rect" value, which is a
|
||
|
# rectangle of the sprite area, which will be used
|
||
|
# to calculate the collision.
|
||
|
|
||
|
# s2 in, s3 out
|
||
|
expected_sprite = self.s2
|
||
|
collided_sprite = sprite.spritecollideany(self.s1, self.ag2)
|
||
|
|
||
|
self.assertEqual(collided_sprite, expected_sprite)
|
||
|
|
||
|
# s2 and s3 out
|
||
|
self.s2.rect.move_ip(0, 10)
|
||
|
collided_sprite = sprite.spritecollideany(self.s1, self.ag2)
|
||
|
|
||
|
self.assertIsNone(collided_sprite)
|
||
|
|
||
|
# s2 out, s3 in
|
||
|
self.s3.rect.move_ip(-105, -105)
|
||
|
expected_sprite = self.s3
|
||
|
collided_sprite = sprite.spritecollideany(self.s1, self.ag2)
|
||
|
|
||
|
self.assertEqual(collided_sprite, expected_sprite)
|
||
|
|
||
|
# s2 and s3 in
|
||
|
self.s2.rect.move_ip(0, -10)
|
||
|
expected_sprite_choices = self.ag2.sprites()
|
||
|
collided_sprite = sprite.spritecollideany(self.s1, self.ag2)
|
||
|
|
||
|
self.assertIn(collided_sprite, expected_sprite_choices)
|
||
|
|
||
|
def test_spritecollideany__with_collided_callback(self):
|
||
|
|
||
|
# pygame.sprite.spritecollideany(sprite, group) -> sprite
|
||
|
# finds any sprites that collide
|
||
|
|
||
|
# collided is a callback function used to calculate if
|
||
|
# two sprites are colliding. it should take two sprites
|
||
|
# as values, and return a bool value indicating if
|
||
|
# they are colliding.
|
||
|
|
||
|
# This collision test can be faster than pygame.sprite.spritecollide()
|
||
|
# since it has less work to do.
|
||
|
|
||
|
arg_dict_a = {}
|
||
|
arg_dict_b = {}
|
||
|
return_container = [True]
|
||
|
|
||
|
# This function is configurable using the mutable default arguments!
|
||
|
def collided_callback(
|
||
|
spr_a,
|
||
|
spr_b,
|
||
|
arg_dict_a=arg_dict_a,
|
||
|
arg_dict_b=arg_dict_b,
|
||
|
return_container=return_container,
|
||
|
):
|
||
|
|
||
|
count = arg_dict_a.get(spr_a, 0)
|
||
|
arg_dict_a[spr_a] = 1 + count
|
||
|
|
||
|
count = arg_dict_b.get(spr_b, 0)
|
||
|
arg_dict_b[spr_b] = 1 + count
|
||
|
|
||
|
return return_container[0]
|
||
|
|
||
|
# This should return a sprite from self.ag2 because the callback
|
||
|
# function (collided_callback()) currently returns True.
|
||
|
expected_sprite_choices = self.ag2.sprites()
|
||
|
collided_sprite = sprite.spritecollideany(self.s1, self.ag2, collided_callback)
|
||
|
|
||
|
self.assertIn(collided_sprite, expected_sprite_choices)
|
||
|
|
||
|
# The callback function should have been called only once, so self.s1
|
||
|
# should have only been passed as an argument once
|
||
|
self.assertEqual(len(arg_dict_a), 1)
|
||
|
self.assertEqual(arg_dict_a[self.s1], 1)
|
||
|
|
||
|
# The callback function should have been called only once, so self.s2
|
||
|
# exclusive-or self.s3 should have only been passed as an argument
|
||
|
# once
|
||
|
self.assertEqual(len(arg_dict_b), 1)
|
||
|
self.assertEqual(list(arg_dict_b.values())[0], 1)
|
||
|
self.assertTrue(self.s2 in arg_dict_b or self.s3 in arg_dict_b)
|
||
|
|
||
|
arg_dict_a.clear()
|
||
|
arg_dict_b.clear()
|
||
|
return_container[0] = False
|
||
|
|
||
|
# This should return None because the callback function
|
||
|
# (collided_callback()) currently returns False.
|
||
|
collided_sprite = sprite.spritecollideany(self.s1, self.ag2, collided_callback)
|
||
|
|
||
|
self.assertIsNone(collided_sprite)
|
||
|
|
||
|
# The callback function should have been called as many times as
|
||
|
# there are sprites in self.ag2
|
||
|
self.assertEqual(len(arg_dict_a), 1)
|
||
|
self.assertEqual(arg_dict_a[self.s1], len(self.ag2))
|
||
|
self.assertEqual(len(arg_dict_b), len(self.ag2))
|
||
|
|
||
|
# Each sprite in self.ag2 should be called once.
|
||
|
for s in self.ag2:
|
||
|
self.assertEqual(arg_dict_b[s], 1)
|
||
|
|
||
|
def test_groupcollide__without_collided_callback(self):
|
||
|
|
||
|
# pygame.sprite.groupcollide(groupa, groupb, dokilla, dokillb) -> dict
|
||
|
# collision detection between group and group
|
||
|
|
||
|
# test no kill
|
||
|
expected_dict = {self.s1: [self.s2]}
|
||
|
crashed = pygame.sprite.groupcollide(self.ag, self.ag2, False, False)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
crashed = pygame.sprite.groupcollide(self.ag, self.ag2, False, False)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
# Test dokill2=True (kill colliding sprites in second group).
|
||
|
crashed = pygame.sprite.groupcollide(self.ag, self.ag2, False, True)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
expected_dict = {}
|
||
|
crashed = pygame.sprite.groupcollide(self.ag, self.ag2, False, False)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
# Test dokill1=True (kill colliding sprites in first group).
|
||
|
self.s3.rect.move_ip(-100, -100)
|
||
|
expected_dict = {self.s1: [self.s3]}
|
||
|
crashed = pygame.sprite.groupcollide(self.ag, self.ag2, True, False)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
expected_dict = {}
|
||
|
crashed = pygame.sprite.groupcollide(self.ag, self.ag2, False, False)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
def test_groupcollide__with_collided_callback(self):
|
||
|
|
||
|
collided_callback_true = lambda spr_a, spr_b: True
|
||
|
collided_callback_false = lambda spr_a, spr_b: False
|
||
|
|
||
|
# test no kill
|
||
|
expected_dict = {}
|
||
|
crashed = pygame.sprite.groupcollide(
|
||
|
self.ag, self.ag2, False, False, collided_callback_false
|
||
|
)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
expected_dict = {self.s1: sorted(self.ag2.sprites(), key=id)}
|
||
|
crashed = pygame.sprite.groupcollide(
|
||
|
self.ag, self.ag2, False, False, collided_callback_true
|
||
|
)
|
||
|
for value in crashed.values():
|
||
|
value.sort(key=id)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
# expected_dict is the same again for this collide
|
||
|
crashed = pygame.sprite.groupcollide(
|
||
|
self.ag, self.ag2, False, False, collided_callback_true
|
||
|
)
|
||
|
for value in crashed.values():
|
||
|
value.sort(key=id)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
# Test dokill2=True (kill colliding sprites in second group).
|
||
|
expected_dict = {}
|
||
|
crashed = pygame.sprite.groupcollide(
|
||
|
self.ag, self.ag2, False, True, collided_callback_false
|
||
|
)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
expected_dict = {self.s1: sorted(self.ag2.sprites(), key=id)}
|
||
|
crashed = pygame.sprite.groupcollide(
|
||
|
self.ag, self.ag2, False, True, collided_callback_true
|
||
|
)
|
||
|
for value in crashed.values():
|
||
|
value.sort(key=id)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
expected_dict = {}
|
||
|
crashed = pygame.sprite.groupcollide(
|
||
|
self.ag, self.ag2, False, True, collided_callback_true
|
||
|
)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
# Test dokill1=True (kill colliding sprites in first group).
|
||
|
self.ag.add(self.s2)
|
||
|
self.ag2.add(self.s3)
|
||
|
expected_dict = {}
|
||
|
crashed = pygame.sprite.groupcollide(
|
||
|
self.ag, self.ag2, True, False, collided_callback_false
|
||
|
)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
expected_dict = {self.s1: [self.s3], self.s2: [self.s3]}
|
||
|
crashed = pygame.sprite.groupcollide(
|
||
|
self.ag, self.ag2, True, False, collided_callback_true
|
||
|
)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
expected_dict = {}
|
||
|
crashed = pygame.sprite.groupcollide(
|
||
|
self.ag, self.ag2, True, False, collided_callback_true
|
||
|
)
|
||
|
|
||
|
self.assertDictEqual(expected_dict, crashed)
|
||
|
|
||
|
def test_collide_rect(self):
|
||
|
# Test colliding - some edges touching
|
||
|
self.assertTrue(pygame.sprite.collide_rect(self.s1, self.s2))
|
||
|
self.assertTrue(pygame.sprite.collide_rect(self.s2, self.s1))
|
||
|
|
||
|
# Test colliding - all edges touching
|
||
|
self.s2.rect.center = self.s3.rect.center
|
||
|
|
||
|
self.assertTrue(pygame.sprite.collide_rect(self.s2, self.s3))
|
||
|
self.assertTrue(pygame.sprite.collide_rect(self.s3, self.s2))
|
||
|
|
||
|
# Test colliding - no edges touching
|
||
|
self.s2.rect.inflate_ip(10, 10)
|
||
|
|
||
|
self.assertTrue(pygame.sprite.collide_rect(self.s2, self.s3))
|
||
|
self.assertTrue(pygame.sprite.collide_rect(self.s3, self.s2))
|
||
|
|
||
|
# Test colliding - some edges intersecting
|
||
|
self.s2.rect.center = (self.s1.rect.right, self.s1.rect.bottom)
|
||
|
|
||
|
self.assertTrue(pygame.sprite.collide_rect(self.s1, self.s2))
|
||
|
self.assertTrue(pygame.sprite.collide_rect(self.s2, self.s1))
|
||
|
|
||
|
# Test not colliding
|
||
|
self.assertFalse(pygame.sprite.collide_rect(self.s1, self.s3))
|
||
|
self.assertFalse(pygame.sprite.collide_rect(self.s3, self.s1))
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
|
||
|
|
||
|
class AbstractGroupTypeTest(unittest.TestCase):
|
||
|
def setUp(self):
|
||
|
self.ag = sprite.AbstractGroup()
|
||
|
self.ag2 = sprite.AbstractGroup()
|
||
|
self.s1 = sprite.Sprite(self.ag)
|
||
|
self.s2 = sprite.Sprite(self.ag)
|
||
|
self.s3 = sprite.Sprite(self.ag2)
|
||
|
self.s4 = sprite.Sprite(self.ag2)
|
||
|
|
||
|
self.s1.image = pygame.Surface((10, 10))
|
||
|
self.s1.image.fill(pygame.Color("red"))
|
||
|
self.s1.rect = self.s1.image.get_rect()
|
||
|
|
||
|
self.s2.image = pygame.Surface((10, 10))
|
||
|
self.s2.image.fill(pygame.Color("green"))
|
||
|
self.s2.rect = self.s2.image.get_rect()
|
||
|
self.s2.rect.left = 10
|
||
|
|
||
|
self.s3.image = pygame.Surface((10, 10))
|
||
|
self.s3.image.fill(pygame.Color("blue"))
|
||
|
self.s3.rect = self.s3.image.get_rect()
|
||
|
self.s3.rect.top = 10
|
||
|
|
||
|
self.s4.image = pygame.Surface((10, 10))
|
||
|
self.s4.image.fill(pygame.Color("white"))
|
||
|
self.s4.rect = self.s4.image.get_rect()
|
||
|
self.s4.rect.left = 10
|
||
|
self.s4.rect.top = 10
|
||
|
|
||
|
self.bg = pygame.Surface((20, 20))
|
||
|
self.scr = pygame.Surface((20, 20))
|
||
|
self.scr.fill(pygame.Color("grey"))
|
||
|
|
||
|
def test_has(self):
|
||
|
" See if AbstractGroup.has() works as expected. "
|
||
|
|
||
|
self.assertEqual(True, self.s1 in self.ag)
|
||
|
|
||
|
self.assertEqual(True, self.ag.has(self.s1))
|
||
|
|
||
|
self.assertEqual(True, self.ag.has([self.s1, self.s2]))
|
||
|
|
||
|
# see if one of them not being in there.
|
||
|
self.assertNotEqual(True, self.ag.has([self.s1, self.s2, self.s3]))
|
||
|
self.assertNotEqual(True, self.ag.has(self.s1, self.s2, self.s3))
|
||
|
self.assertNotEqual(True, self.ag.has(self.s1, sprite.Group(self.s2, self.s3)))
|
||
|
self.assertNotEqual(True, self.ag.has(self.s1, [self.s2, self.s3]))
|
||
|
|
||
|
# test empty list processing
|
||
|
self.assertFalse(self.ag.has(*[]))
|
||
|
self.assertFalse(self.ag.has([]))
|
||
|
self.assertFalse(self.ag.has([[]]))
|
||
|
|
||
|
# see if a second AbstractGroup works.
|
||
|
self.assertEqual(True, self.ag2.has(self.s3))
|
||
|
|
||
|
def test_add(self):
|
||
|
ag3 = sprite.AbstractGroup()
|
||
|
sprites = (self.s1, self.s2, self.s3, self.s4)
|
||
|
|
||
|
for s in sprites:
|
||
|
self.assertNotIn(s, ag3)
|
||
|
|
||
|
ag3.add(self.s1, [self.s2], self.ag2)
|
||
|
|
||
|
for s in sprites:
|
||
|
self.assertIn(s, ag3)
|
||
|
|
||
|
def test_add_internal(self):
|
||
|
self.assertNotIn(self.s1, self.ag2)
|
||
|
|
||
|
self.ag2.add_internal(self.s1)
|
||
|
|
||
|
self.assertIn(self.s1, self.ag2)
|
||
|
|
||
|
def test_clear(self):
|
||
|
|
||
|
self.ag.draw(self.scr)
|
||
|
self.ag.clear(self.scr, self.bg)
|
||
|
self.assertEqual((0, 0, 0, 255), self.scr.get_at((5, 5)))
|
||
|
self.assertEqual((0, 0, 0, 255), self.scr.get_at((15, 5)))
|
||
|
|
||
|
def test_draw(self):
|
||
|
|
||
|
self.ag.draw(self.scr)
|
||
|
self.assertEqual((255, 0, 0, 255), self.scr.get_at((5, 5)))
|
||
|
self.assertEqual((0, 255, 0, 255), self.scr.get_at((15, 5)))
|
||
|
|
||
|
self.assertEqual(self.ag.spritedict[self.s1], pygame.Rect(0, 0, 10, 10))
|
||
|
self.assertEqual(self.ag.spritedict[self.s2], pygame.Rect(10, 0, 10, 10))
|
||
|
|
||
|
def test_empty(self):
|
||
|
|
||
|
self.ag.empty()
|
||
|
self.assertFalse(self.s1 in self.ag)
|
||
|
self.assertFalse(self.s2 in self.ag)
|
||
|
|
||
|
def test_has_internal(self):
|
||
|
self.assertTrue(self.ag.has_internal(self.s1))
|
||
|
self.assertFalse(self.ag.has_internal(self.s3))
|
||
|
|
||
|
def test_remove(self):
|
||
|
|
||
|
# Test removal of 1 sprite
|
||
|
self.ag.remove(self.s1)
|
||
|
self.assertFalse(self.ag in self.s1.groups())
|
||
|
self.assertFalse(self.ag.has(self.s1))
|
||
|
|
||
|
# Test removal of 2 sprites as 2 arguments
|
||
|
self.ag2.remove(self.s3, self.s4)
|
||
|
self.assertFalse(self.ag2 in self.s3.groups())
|
||
|
self.assertFalse(self.ag2 in self.s4.groups())
|
||
|
self.assertFalse(self.ag2.has(self.s3, self.s4))
|
||
|
|
||
|
# Test removal of 4 sprites as a list containing a sprite and a group
|
||
|
# containing a sprite and another group containing 2 sprites.
|
||
|
self.ag.add(self.s1, self.s3, self.s4)
|
||
|
self.ag2.add(self.s3, self.s4)
|
||
|
g = sprite.Group(self.s2)
|
||
|
self.ag.remove([self.s1, g], self.ag2)
|
||
|
self.assertFalse(self.ag in self.s1.groups())
|
||
|
self.assertFalse(self.ag in self.s2.groups())
|
||
|
self.assertFalse(self.ag in self.s3.groups())
|
||
|
self.assertFalse(self.ag in self.s4.groups())
|
||
|
self.assertFalse(self.ag.has(self.s1, self.s2, self.s3, self.s4))
|
||
|
|
||
|
def test_remove_internal(self):
|
||
|
|
||
|
self.ag.remove_internal(self.s1)
|
||
|
self.assertFalse(self.ag.has_internal(self.s1))
|
||
|
|
||
|
def test_sprites(self):
|
||
|
expected_sprites = sorted((self.s1, self.s2), key=id)
|
||
|
sprite_list = sorted(self.ag.sprites(), key=id)
|
||
|
|
||
|
self.assertListEqual(sprite_list, expected_sprites)
|
||
|
|
||
|
def test_update(self):
|
||
|
class test_sprite(pygame.sprite.Sprite):
|
||
|
sink = []
|
||
|
|
||
|
def __init__(self, *groups):
|
||
|
pygame.sprite.Sprite.__init__(self, *groups)
|
||
|
|
||
|
def update(self, *args):
|
||
|
self.sink += args
|
||
|
|
||
|
s = test_sprite(self.ag)
|
||
|
self.ag.update(1, 2, 3)
|
||
|
|
||
|
self.assertEqual(test_sprite.sink, [1, 2, 3])
|
||
|
|
||
|
def test_update_with_kwargs(self):
|
||
|
class test_sprite(pygame.sprite.Sprite):
|
||
|
sink = []
|
||
|
sink_kwargs = {}
|
||
|
|
||
|
def __init__(self, *groups):
|
||
|
pygame.sprite.Sprite.__init__(self, *groups)
|
||
|
|
||
|
def update(self, *args, **kwargs):
|
||
|
self.sink += args
|
||
|
self.sink_kwargs.update(kwargs)
|
||
|
|
||
|
s = test_sprite(self.ag)
|
||
|
self.ag.update(1, 2, 3, foo=4, bar=5)
|
||
|
|
||
|
self.assertEqual(test_sprite.sink, [1, 2, 3])
|
||
|
self.assertEqual(test_sprite.sink_kwargs, {"foo": 4, "bar": 5})
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
|
||
|
# A base class to share tests between similar classes
|
||
|
|
||
|
|
||
|
class LayeredGroupBase:
|
||
|
def test_get_layer_of_sprite(self):
|
||
|
expected_layer = 666
|
||
|
spr = self.sprite()
|
||
|
self.LG.add(spr, layer=expected_layer)
|
||
|
layer = self.LG.get_layer_of_sprite(spr)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), 1)
|
||
|
self.assertEqual(layer, self.LG.get_layer_of_sprite(spr))
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
self.assertEqual(layer, self.LG._spritelayers[spr])
|
||
|
|
||
|
def test_add(self):
|
||
|
expected_layer = self.LG._default_layer
|
||
|
spr = self.sprite()
|
||
|
self.LG.add(spr)
|
||
|
layer = self.LG.get_layer_of_sprite(spr)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), 1)
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__sprite_with_layer_attribute(self):
|
||
|
expected_layer = 100
|
||
|
spr = self.sprite()
|
||
|
spr._layer = expected_layer
|
||
|
self.LG.add(spr)
|
||
|
layer = self.LG.get_layer_of_sprite(spr)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), 1)
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__passing_layer_keyword(self):
|
||
|
expected_layer = 100
|
||
|
spr = self.sprite()
|
||
|
self.LG.add(spr, layer=expected_layer)
|
||
|
layer = self.LG.get_layer_of_sprite(spr)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), 1)
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__overriding_sprite_layer_attr(self):
|
||
|
expected_layer = 200
|
||
|
spr = self.sprite()
|
||
|
spr._layer = 100
|
||
|
self.LG.add(spr, layer=expected_layer)
|
||
|
layer = self.LG.get_layer_of_sprite(spr)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), 1)
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__adding_sprite_on_init(self):
|
||
|
spr = self.sprite()
|
||
|
lrg2 = sprite.LayeredUpdates(spr)
|
||
|
expected_layer = lrg2._default_layer
|
||
|
layer = lrg2._spritelayers[spr]
|
||
|
|
||
|
self.assertEqual(len(lrg2._spritelist), 1)
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__sprite_init_layer_attr(self):
|
||
|
expected_layer = 20
|
||
|
spr = self.sprite()
|
||
|
spr._layer = expected_layer
|
||
|
lrg2 = sprite.LayeredUpdates(spr)
|
||
|
layer = lrg2._spritelayers[spr]
|
||
|
|
||
|
self.assertEqual(len(lrg2._spritelist), 1)
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__sprite_init_passing_layer(self):
|
||
|
expected_layer = 33
|
||
|
spr = self.sprite()
|
||
|
lrg2 = sprite.LayeredUpdates(spr, layer=expected_layer)
|
||
|
layer = lrg2._spritelayers[spr]
|
||
|
|
||
|
self.assertEqual(len(lrg2._spritelist), 1)
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__sprite_init_overiding_layer(self):
|
||
|
expected_layer = 33
|
||
|
spr = self.sprite()
|
||
|
spr._layer = 55
|
||
|
lrg2 = sprite.LayeredUpdates(spr, layer=expected_layer)
|
||
|
layer = lrg2._spritelayers[spr]
|
||
|
|
||
|
self.assertEqual(len(lrg2._spritelist), 1)
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__spritelist(self):
|
||
|
expected_layer = self.LG._default_layer
|
||
|
sprite_count = 10
|
||
|
sprites = [self.sprite() for _ in range(sprite_count)]
|
||
|
|
||
|
self.LG.add(sprites)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), sprite_count)
|
||
|
|
||
|
for i in range(sprite_count):
|
||
|
layer = self.LG.get_layer_of_sprite(sprites[i])
|
||
|
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__spritelist_with_layer_attr(self):
|
||
|
sprites = []
|
||
|
sprite_and_layer_count = 10
|
||
|
for i in range(sprite_and_layer_count):
|
||
|
sprites.append(self.sprite())
|
||
|
sprites[-1]._layer = i
|
||
|
|
||
|
self.LG.add(sprites)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), sprite_and_layer_count)
|
||
|
|
||
|
for i in range(sprite_and_layer_count):
|
||
|
layer = self.LG.get_layer_of_sprite(sprites[i])
|
||
|
|
||
|
self.assertEqual(layer, i)
|
||
|
|
||
|
def test_add__spritelist_passing_layer(self):
|
||
|
expected_layer = 33
|
||
|
sprite_count = 10
|
||
|
sprites = [self.sprite() for _ in range(sprite_count)]
|
||
|
|
||
|
self.LG.add(sprites, layer=expected_layer)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), sprite_count)
|
||
|
|
||
|
for i in range(sprite_count):
|
||
|
layer = self.LG.get_layer_of_sprite(sprites[i])
|
||
|
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__spritelist_overriding_layer(self):
|
||
|
expected_layer = 33
|
||
|
sprites = []
|
||
|
sprite_and_layer_count = 10
|
||
|
for i in range(sprite_and_layer_count):
|
||
|
sprites.append(self.sprite())
|
||
|
sprites[-1].layer = i
|
||
|
|
||
|
self.LG.add(sprites, layer=expected_layer)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), sprite_and_layer_count)
|
||
|
|
||
|
for i in range(sprite_and_layer_count):
|
||
|
layer = self.LG.get_layer_of_sprite(sprites[i])
|
||
|
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_add__spritelist_init(self):
|
||
|
sprite_count = 10
|
||
|
sprites = [self.sprite() for _ in range(sprite_count)]
|
||
|
|
||
|
lrg2 = sprite.LayeredUpdates(sprites)
|
||
|
expected_layer = lrg2._default_layer
|
||
|
|
||
|
self.assertEqual(len(lrg2._spritelist), sprite_count)
|
||
|
|
||
|
for i in range(sprite_count):
|
||
|
layer = lrg2.get_layer_of_sprite(sprites[i])
|
||
|
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_remove__sprite(self):
|
||
|
sprites = []
|
||
|
sprite_count = 10
|
||
|
for i in range(sprite_count):
|
||
|
sprites.append(self.sprite())
|
||
|
sprites[-1].rect = pygame.Rect((0, 0, 0, 0))
|
||
|
|
||
|
self.LG.add(sprites)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), sprite_count)
|
||
|
|
||
|
for i in range(sprite_count):
|
||
|
self.LG.remove(sprites[i])
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), 0)
|
||
|
|
||
|
def test_sprites(self):
|
||
|
sprites = []
|
||
|
sprite_and_layer_count = 10
|
||
|
for i in range(sprite_and_layer_count, 0, -1):
|
||
|
sprites.append(self.sprite())
|
||
|
sprites[-1]._layer = i
|
||
|
|
||
|
self.LG.add(sprites)
|
||
|
|
||
|
self.assertEqual(len(self.LG._spritelist), sprite_and_layer_count)
|
||
|
|
||
|
# Sprites should be ordered based on their layer (bottom to top),
|
||
|
# which is the reverse order of the sprites list.
|
||
|
expected_sprites = list(reversed(sprites))
|
||
|
actual_sprites = self.LG.sprites()
|
||
|
|
||
|
self.assertListEqual(actual_sprites, expected_sprites)
|
||
|
|
||
|
def test_layers(self):
|
||
|
sprites = []
|
||
|
expected_layers = []
|
||
|
layer_count = 10
|
||
|
for i in range(layer_count):
|
||
|
expected_layers.append(i)
|
||
|
for j in range(5):
|
||
|
sprites.append(self.sprite())
|
||
|
sprites[-1]._layer = i
|
||
|
self.LG.add(sprites)
|
||
|
|
||
|
layers = self.LG.layers()
|
||
|
|
||
|
self.assertListEqual(layers, expected_layers)
|
||
|
|
||
|
def test_add__layers_are_correct(self):
|
||
|
layers = [1, 4, 6, 8, 3, 6, 2, 6, 4, 5, 6, 1, 0, 9, 7, 6, 54, 8, 2, 43, 6, 1]
|
||
|
for lay in layers:
|
||
|
self.LG.add(self.sprite(), layer=lay)
|
||
|
layers.sort()
|
||
|
|
||
|
for idx, spr in enumerate(self.LG.sprites()):
|
||
|
layer = self.LG.get_layer_of_sprite(spr)
|
||
|
|
||
|
self.assertEqual(layer, layers[idx])
|
||
|
|
||
|
def test_change_layer(self):
|
||
|
expected_layer = 99
|
||
|
spr = self.sprite()
|
||
|
self.LG.add(spr, layer=expected_layer)
|
||
|
|
||
|
self.assertEqual(self.LG._spritelayers[spr], expected_layer)
|
||
|
|
||
|
expected_layer = 44
|
||
|
self.LG.change_layer(spr, expected_layer)
|
||
|
|
||
|
self.assertEqual(self.LG._spritelayers[spr], expected_layer)
|
||
|
|
||
|
expected_layer = 77
|
||
|
spr2 = self.sprite()
|
||
|
spr2.layer = 55
|
||
|
self.LG.add(spr2)
|
||
|
self.LG.change_layer(spr2, expected_layer)
|
||
|
|
||
|
self.assertEqual(spr2.layer, expected_layer)
|
||
|
|
||
|
def test_get_sprites_at(self):
|
||
|
sprites = []
|
||
|
expected_sprites = []
|
||
|
for i in range(3):
|
||
|
spr = self.sprite()
|
||
|
spr.rect = pygame.Rect(i * 50, i * 50, 100, 100)
|
||
|
sprites.append(spr)
|
||
|
if i < 2:
|
||
|
expected_sprites.append(spr)
|
||
|
self.LG.add(sprites)
|
||
|
result = self.LG.get_sprites_at((50, 50))
|
||
|
self.assertEqual(result, expected_sprites)
|
||
|
|
||
|
|
||
|
def test_get_top_layer(self):
|
||
|
layers = [1, 5, 2, 8, 4, 5, 3, 88, 23, 0]
|
||
|
for i in layers:
|
||
|
self.LG.add(self.sprite(), layer=i)
|
||
|
top_layer = self.LG.get_top_layer()
|
||
|
|
||
|
self.assertEqual(top_layer, self.LG.get_top_layer())
|
||
|
self.assertEqual(top_layer, max(layers))
|
||
|
self.assertEqual(top_layer, max(self.LG._spritelayers.values()))
|
||
|
self.assertEqual(top_layer, self.LG._spritelayers[self.LG._spritelist[-1]])
|
||
|
|
||
|
def test_get_bottom_layer(self):
|
||
|
layers = [1, 5, 2, 8, 4, 5, 3, 88, 23, 0]
|
||
|
for i in layers:
|
||
|
self.LG.add(self.sprite(), layer=i)
|
||
|
bottom_layer = self.LG.get_bottom_layer()
|
||
|
|
||
|
self.assertEqual(bottom_layer, self.LG.get_bottom_layer())
|
||
|
self.assertEqual(bottom_layer, min(layers))
|
||
|
self.assertEqual(bottom_layer, min(self.LG._spritelayers.values()))
|
||
|
self.assertEqual(bottom_layer, self.LG._spritelayers[self.LG._spritelist[0]])
|
||
|
|
||
|
def test_move_to_front(self):
|
||
|
layers = [1, 5, 2, 8, 4, 5, 3, 88, 23, 0]
|
||
|
for i in layers:
|
||
|
self.LG.add(self.sprite(), layer=i)
|
||
|
spr = self.sprite()
|
||
|
self.LG.add(spr, layer=3)
|
||
|
|
||
|
self.assertNotEqual(spr, self.LG._spritelist[-1])
|
||
|
|
||
|
self.LG.move_to_front(spr)
|
||
|
|
||
|
self.assertEqual(spr, self.LG._spritelist[-1])
|
||
|
|
||
|
def test_move_to_back(self):
|
||
|
layers = [1, 5, 2, 8, 4, 5, 3, 88, 23, 0]
|
||
|
for i in layers:
|
||
|
self.LG.add(self.sprite(), layer=i)
|
||
|
spr = self.sprite()
|
||
|
self.LG.add(spr, layer=55)
|
||
|
|
||
|
self.assertNotEqual(spr, self.LG._spritelist[0])
|
||
|
|
||
|
self.LG.move_to_back(spr)
|
||
|
|
||
|
self.assertEqual(spr, self.LG._spritelist[0])
|
||
|
|
||
|
def test_get_top_sprite(self):
|
||
|
layers = [1, 5, 2, 8, 4, 5, 3, 88, 23, 0]
|
||
|
for i in layers:
|
||
|
self.LG.add(self.sprite(), layer=i)
|
||
|
expected_layer = self.LG.get_top_layer()
|
||
|
layer = self.LG.get_layer_of_sprite(self.LG.get_top_sprite())
|
||
|
|
||
|
self.assertEqual(layer, expected_layer)
|
||
|
|
||
|
def test_get_sprites_from_layer(self):
|
||
|
sprites = {}
|
||
|
layers = [
|
||
|
1,
|
||
|
4,
|
||
|
5,
|
||
|
6,
|
||
|
3,
|
||
|
7,
|
||
|
8,
|
||
|
2,
|
||
|
1,
|
||
|
3,
|
||
|
4,
|
||
|
5,
|
||
|
6,
|
||
|
7,
|
||
|
8,
|
||
|
9,
|
||
|
1,
|
||
|
2,
|
||
|
3,
|
||
|
4,
|
||
|
5,
|
||
|
6,
|
||
|
7,
|
||
|
8,
|
||
|
9,
|
||
|
0,
|
||
|
1,
|
||
|
6,
|
||
|
5,
|
||
|
4,
|
||
|
3,
|
||
|
2,
|
||
|
]
|
||
|
for lay in layers:
|
||
|
spr = self.sprite()
|
||
|
spr._layer = lay
|
||
|
self.LG.add(spr)
|
||
|
if lay not in sprites:
|
||
|
sprites[lay] = []
|
||
|
sprites[lay].append(spr)
|
||
|
|
||
|
for lay in self.LG.layers():
|
||
|
for spr in self.LG.get_sprites_from_layer(lay):
|
||
|
self.assertIn(spr, sprites[lay])
|
||
|
|
||
|
sprites[lay].remove(spr)
|
||
|
if len(sprites[lay]) == 0:
|
||
|
del sprites[lay]
|
||
|
|
||
|
self.assertEqual(len(sprites.values()), 0)
|
||
|
|
||
|
def test_switch_layer(self):
|
||
|
sprites1 = []
|
||
|
sprites2 = []
|
||
|
layers = [3, 2, 3, 2, 3, 3, 2, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 3, 2, 2, 3, 2, 3]
|
||
|
for lay in layers:
|
||
|
spr = self.sprite()
|
||
|
spr._layer = lay
|
||
|
self.LG.add(spr)
|
||
|
if lay == 2:
|
||
|
sprites1.append(spr)
|
||
|
else:
|
||
|
sprites2.append(spr)
|
||
|
|
||
|
sprites1.sort(key=id)
|
||
|
sprites2.sort(key=id)
|
||
|
layer2_sprites = sorted(self.LG.get_sprites_from_layer(2), key=id)
|
||
|
layer3_sprites = sorted(self.LG.get_sprites_from_layer(3), key=id)
|
||
|
|
||
|
self.assertListEqual(sprites1, layer2_sprites)
|
||
|
self.assertListEqual(sprites2, layer3_sprites)
|
||
|
self.assertEqual(len(self.LG), len(sprites1) + len(sprites2))
|
||
|
|
||
|
self.LG.switch_layer(2, 3)
|
||
|
layer2_sprites = sorted(self.LG.get_sprites_from_layer(2), key=id)
|
||
|
layer3_sprites = sorted(self.LG.get_sprites_from_layer(3), key=id)
|
||
|
|
||
|
self.assertListEqual(sprites1, layer3_sprites)
|
||
|
self.assertListEqual(sprites2, layer2_sprites)
|
||
|
self.assertEqual(len(self.LG), len(sprites1) + len(sprites2))
|
||
|
|
||
|
def test_copy(self):
|
||
|
self.LG.add(self.sprite())
|
||
|
spr = self.LG.sprites()[0]
|
||
|
lg_copy = self.LG.copy()
|
||
|
|
||
|
self.assertIsInstance(lg_copy, type(self.LG))
|
||
|
self.assertIn(spr, lg_copy)
|
||
|
self.assertIn(lg_copy, spr.groups())
|
||
|
|
||
|
|
||
|
########################## LAYERED RENDER GROUP TESTS ##########################
|
||
|
|
||
|
|
||
|
class LayeredUpdatesTypeTest__SpriteTest(LayeredGroupBase, unittest.TestCase):
|
||
|
sprite = sprite.Sprite
|
||
|
|
||
|
def setUp(self):
|
||
|
self.LG = sprite.LayeredUpdates()
|
||
|
|
||
|
|
||
|
class LayeredUpdatesTypeTest__DirtySprite(LayeredGroupBase, unittest.TestCase):
|
||
|
sprite = sprite.DirtySprite
|
||
|
|
||
|
def setUp(self):
|
||
|
self.LG = sprite.LayeredUpdates()
|
||
|
|
||
|
|
||
|
class LayeredDirtyTypeTest__DirtySprite(LayeredGroupBase, unittest.TestCase):
|
||
|
sprite = sprite.DirtySprite
|
||
|
|
||
|
def setUp(self):
|
||
|
self.LG = sprite.LayeredDirty()
|
||
|
|
||
|
def test_repaint_rect(self):
|
||
|
group = self.LG
|
||
|
surface = pygame.Surface((100, 100))
|
||
|
|
||
|
group.repaint_rect(pygame.Rect(0, 0, 100, 100))
|
||
|
group.draw(surface)
|
||
|
|
||
|
def test_repaint_rect_with_clip(self):
|
||
|
group = self.LG
|
||
|
surface = pygame.Surface((100, 100))
|
||
|
|
||
|
group.set_clip(pygame.Rect(0, 0, 100, 100))
|
||
|
group.repaint_rect(pygame.Rect(0, 0, 100, 100))
|
||
|
group.draw(surface)
|
||
|
|
||
|
def _nondirty_intersections_redrawn(self, use_source_rect=False):
|
||
|
# Helper method to ensure non-dirty sprites are redrawn correctly.
|
||
|
#
|
||
|
# Parameters:
|
||
|
# use_source_rect - allows non-dirty sprites to be tested
|
||
|
# with (True) and without (False) a source_rect
|
||
|
#
|
||
|
# This test was written to reproduce the behavior seen in issue #898.
|
||
|
# A non-dirty sprite (using source_rect) was being redrawn incorrectly
|
||
|
# after a dirty sprite intersected with it.
|
||
|
#
|
||
|
# This test does the following.
|
||
|
# 1. Creates a surface filled with white. Also creates an image_source
|
||
|
# with a default fill color of yellow and adds 2 images to it
|
||
|
# (red and blue rectangles).
|
||
|
# 2. Creates 2 DirtySprites (red_sprite and blue_sprite) using the
|
||
|
# image_source and adds them to a LayeredDirty group.
|
||
|
# 3. Moves the red_sprite and calls LayeredDirty.draw(surface) a few
|
||
|
# times.
|
||
|
# 4. Checks to make sure the sprites were redrawn correctly.
|
||
|
RED = pygame.Color("red")
|
||
|
BLUE = pygame.Color("blue")
|
||
|
WHITE = pygame.Color("white")
|
||
|
YELLOW = pygame.Color("yellow")
|
||
|
|
||
|
surface = pygame.Surface((60, 80))
|
||
|
surface.fill(WHITE)
|
||
|
start_pos = (10, 10)
|
||
|
|
||
|
# These rects define each sprite's image area in the image_source.
|
||
|
red_sprite_source = pygame.Rect((45, 0), (5, 4))
|
||
|
blue_sprite_source = pygame.Rect((0, 40), (20, 10))
|
||
|
|
||
|
# Create a source image/surface.
|
||
|
image_source = pygame.Surface((50, 50))
|
||
|
image_source.fill(YELLOW)
|
||
|
image_source.fill(RED, red_sprite_source)
|
||
|
image_source.fill(BLUE, blue_sprite_source)
|
||
|
|
||
|
# The blue_sprite is stationary and will not reset its dirty flag. It
|
||
|
# will be the non-dirty sprite in this test. Its values are dependent
|
||
|
# on the use_source_rect flag.
|
||
|
blue_sprite = pygame.sprite.DirtySprite(self.LG)
|
||
|
|
||
|
if use_source_rect:
|
||
|
blue_sprite.image = image_source
|
||
|
# The rect is a bit smaller than the source_rect to make sure
|
||
|
# LayeredDirty.draw() is using the correct dimensions.
|
||
|
blue_sprite.rect = pygame.Rect(
|
||
|
start_pos, (blue_sprite_source.w - 7, blue_sprite_source.h - 7)
|
||
|
)
|
||
|
blue_sprite.source_rect = blue_sprite_source
|
||
|
start_x, start_y = blue_sprite.rect.topleft
|
||
|
end_x = start_x + blue_sprite.source_rect.w
|
||
|
end_y = start_y + blue_sprite.source_rect.h
|
||
|
else:
|
||
|
blue_sprite.image = image_source.subsurface(blue_sprite_source)
|
||
|
blue_sprite.rect = pygame.Rect(start_pos, blue_sprite_source.size)
|
||
|
start_x, start_y = blue_sprite.rect.topleft
|
||
|
end_x, end_y = blue_sprite.rect.bottomright
|
||
|
|
||
|
# The red_sprite is moving and will always be dirty.
|
||
|
red_sprite = pygame.sprite.DirtySprite(self.LG)
|
||
|
red_sprite.image = image_source
|
||
|
red_sprite.rect = pygame.Rect(start_pos, red_sprite_source.size)
|
||
|
red_sprite.source_rect = red_sprite_source
|
||
|
red_sprite.dirty = 2
|
||
|
|
||
|
# Draw the red_sprite as it moves a few steps.
|
||
|
for _ in range(4):
|
||
|
red_sprite.rect.move_ip(2, 1)
|
||
|
|
||
|
# This is the method being tested.
|
||
|
self.LG.draw(surface)
|
||
|
|
||
|
# Check colors where the blue_sprite is drawn. We expect red where the
|
||
|
# red_sprite is drawn over the blue_sprite, but the rest should be
|
||
|
# blue.
|
||
|
surface.lock() # Lock surface for possible speed up.
|
||
|
try:
|
||
|
for y in range(start_y, end_y):
|
||
|
for x in range(start_x, end_x):
|
||
|
if red_sprite.rect.collidepoint(x, y):
|
||
|
expected_color = RED
|
||
|
else:
|
||
|
expected_color = BLUE
|
||
|
|
||
|
color = surface.get_at((x, y))
|
||
|
|
||
|
self.assertEqual(color, expected_color, "pos=({}, {})".format(x, y))
|
||
|
finally:
|
||
|
surface.unlock()
|
||
|
|
||
|
def test_nondirty_intersections_redrawn(self):
|
||
|
"""Ensure non-dirty sprites are correctly redrawn
|
||
|
when dirty sprites intersect with them.
|
||
|
"""
|
||
|
self._nondirty_intersections_redrawn()
|
||
|
|
||
|
def test_nondirty_intersections_redrawn__with_source_rect(self):
|
||
|
"""Ensure non-dirty sprites using source_rects are correctly redrawn
|
||
|
when dirty sprites intersect with them.
|
||
|
|
||
|
Related to issue #898.
|
||
|
"""
|
||
|
self._nondirty_intersections_redrawn(True)
|
||
|
|
||
|
|
||
|
############################### SPRITE BASE CLASS ##############################
|
||
|
#
|
||
|
# tests common between sprite classes
|
||
|
|
||
|
|
||
|
class SpriteBase:
|
||
|
def setUp(self):
|
||
|
self.groups = []
|
||
|
for Group in self.Groups:
|
||
|
self.groups.append(Group())
|
||
|
|
||
|
self.sprite = self.Sprite()
|
||
|
|
||
|
def test_add_internal(self):
|
||
|
|
||
|
for g in self.groups:
|
||
|
self.sprite.add_internal(g)
|
||
|
|
||
|
for g in self.groups:
|
||
|
self.assertIn(g, self.sprite.groups())
|
||
|
|
||
|
def test_remove_internal(self):
|
||
|
|
||
|
for g in self.groups:
|
||
|
self.sprite.add_internal(g)
|
||
|
|
||
|
for g in self.groups:
|
||
|
self.sprite.remove_internal(g)
|
||
|
|
||
|
for g in self.groups:
|
||
|
self.assertFalse(g in self.sprite.groups())
|
||
|
|
||
|
def test_update(self):
|
||
|
class test_sprite(pygame.sprite.Sprite):
|
||
|
sink = []
|
||
|
|
||
|
def __init__(self, *groups):
|
||
|
pygame.sprite.Sprite.__init__(self, *groups)
|
||
|
|
||
|
def update(self, *args):
|
||
|
self.sink += args
|
||
|
|
||
|
s = test_sprite()
|
||
|
s.update(1, 2, 3)
|
||
|
|
||
|
self.assertEqual(test_sprite.sink, [1, 2, 3])
|
||
|
|
||
|
def test_update_with_kwargs(self):
|
||
|
class test_sprite(pygame.sprite.Sprite):
|
||
|
sink = []
|
||
|
sink_dict = {}
|
||
|
|
||
|
def __init__(self, *groups):
|
||
|
pygame.sprite.Sprite.__init__(self, *groups)
|
||
|
|
||
|
def update(self, *args, **kwargs):
|
||
|
self.sink += args
|
||
|
self.sink_dict.update(kwargs)
|
||
|
|
||
|
s = test_sprite()
|
||
|
s.update(1, 2, 3, foo=4, bar=5)
|
||
|
|
||
|
self.assertEqual(test_sprite.sink, [1, 2, 3])
|
||
|
self.assertEqual(test_sprite.sink_dict, {"foo": 4, "bar": 5})
|
||
|
|
||
|
def test___init____added_to_groups_passed(self):
|
||
|
expected_groups = sorted(self.groups, key=id)
|
||
|
sprite = self.Sprite(self.groups)
|
||
|
groups = sorted(sprite.groups(), key=id)
|
||
|
|
||
|
self.assertListEqual(groups, expected_groups)
|
||
|
|
||
|
def test_add(self):
|
||
|
expected_groups = sorted(self.groups, key=id)
|
||
|
self.sprite.add(self.groups)
|
||
|
groups = sorted(self.sprite.groups(), key=id)
|
||
|
|
||
|
self.assertListEqual(groups, expected_groups)
|
||
|
|
||
|
def test_alive(self):
|
||
|
self.assertFalse(
|
||
|
self.sprite.alive(), "Sprite should not be alive if in no groups"
|
||
|
)
|
||
|
|
||
|
self.sprite.add(self.groups)
|
||
|
|
||
|
self.assertTrue(self.sprite.alive())
|
||
|
|
||
|
def test_groups(self):
|
||
|
for i, g in enumerate(self.groups):
|
||
|
expected_groups = sorted(self.groups[: i + 1], key=id)
|
||
|
self.sprite.add(g)
|
||
|
groups = sorted(self.sprite.groups(), key=id)
|
||
|
|
||
|
self.assertListEqual(groups, expected_groups)
|
||
|
|
||
|
def test_kill(self):
|
||
|
self.sprite.add(self.groups)
|
||
|
|
||
|
self.assertTrue(self.sprite.alive())
|
||
|
|
||
|
self.sprite.kill()
|
||
|
|
||
|
self.assertListEqual(self.sprite.groups(), [])
|
||
|
self.assertFalse(self.sprite.alive())
|
||
|
|
||
|
def test_remove(self):
|
||
|
self.sprite.add(self.groups)
|
||
|
self.sprite.remove(self.groups)
|
||
|
|
||
|
self.assertListEqual(self.sprite.groups(), [])
|
||
|
|
||
|
|
||
|
############################## SPRITE CLASS TESTS ##############################
|
||
|
|
||
|
|
||
|
class SpriteTypeTest(SpriteBase, unittest.TestCase):
|
||
|
Sprite = sprite.Sprite
|
||
|
|
||
|
Groups = [
|
||
|
sprite.Group,
|
||
|
sprite.LayeredUpdates,
|
||
|
sprite.RenderUpdates,
|
||
|
sprite.OrderedUpdates,
|
||
|
]
|
||
|
|
||
|
|
||
|
class DirtySpriteTypeTest(SpriteBase, unittest.TestCase):
|
||
|
Sprite = sprite.DirtySprite
|
||
|
|
||
|
Groups = [
|
||
|
sprite.Group,
|
||
|
sprite.LayeredUpdates,
|
||
|
sprite.RenderUpdates,
|
||
|
sprite.OrderedUpdates,
|
||
|
sprite.LayeredDirty,
|
||
|
]
|
||
|
|
||
|
|
||
|
############################## BUG TESTS #######################################
|
||
|
|
||
|
|
||
|
class SingleGroupBugsTest(unittest.TestCase):
|
||
|
def test_memoryleak_bug(self):
|
||
|
# For memoryleak bug posted to mailing list by Tobias Steinrücken on 16/11/10.
|
||
|
# Fixed in revision 2953.
|
||
|
|
||
|
import weakref
|
||
|
import gc
|
||
|
|
||
|
class MySprite(sprite.Sprite):
|
||
|
def __init__(self, *args, **kwargs):
|
||
|
sprite.Sprite.__init__(self, *args, **kwargs)
|
||
|
self.image = pygame.Surface((2, 4), 0, 24)
|
||
|
self.rect = self.image.get_rect()
|
||
|
|
||
|
g = sprite.GroupSingle()
|
||
|
screen = pygame.Surface((4, 8), 0, 24)
|
||
|
s = MySprite()
|
||
|
r = weakref.ref(s)
|
||
|
g.sprite = s
|
||
|
del s
|
||
|
gc.collect()
|
||
|
|
||
|
self.assertIsNotNone(r())
|
||
|
|
||
|
g.update()
|
||
|
g.draw(screen)
|
||
|
g.sprite = MySprite()
|
||
|
gc.collect()
|
||
|
|
||
|
self.assertIsNone(r())
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
unittest.main()
|