added completly new version for haslach 2025

This commit is contained in:
fotobox
2025-03-17 03:47:13 +01:00
parent 152832515c
commit 769ab91da8
2333 changed files with 409208 additions and 341 deletions

View File

@@ -0,0 +1,40 @@
"""Pygame unit test suite package
Exports function run()
A quick way to run the test suite package from the command line
is by importing the go submodule:
python -m "import pygame.tests" [<test options>]
Command line option --help displays a usage message. Available options
correspond to the pygame.tests.run arguments.
The xxxx_test submodules of the tests package are unit test suites for
individual parts of Pygame. Each can also be run as a main program. This is
useful if the test, such as cdrom_test, is interactive.
For Pygame development the test suite can be run from a Pygame distribution
root directory using run_tests.py. Alternately, test/__main__.py can be run
directly.
"""
if __name__ == "pygame.tests":
from pygame.tests.test_utils.run_tests import run
elif __name__ == "__main__":
import os
import sys
pkg_dir = os.path.split(os.path.abspath(__file__))[0]
parent_dir, pkg_name = os.path.split(pkg_dir)
is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame"
if not is_pygame_pkg:
sys.path.insert(0, parent_dir)
if is_pygame_pkg:
import pygame.tests.__main__
else:
import test.__main__
else:
from test.test_utils.run_tests import run

View File

@@ -0,0 +1,143 @@
"""Load and run the Pygame test suite
python -c "import pygame.tests.go" [<test options>]
or
python test/go.py [<test options>]
Command line option --help displays a command line usage message.
run_tests.py in the main distribution directory is an alternative to test.go
"""
import sys
if __name__ == "__main__":
import os
pkg_dir = os.path.split(os.path.abspath(__file__))[0]
parent_dir, pkg_name = os.path.split(pkg_dir)
is_pygame_pkg = pkg_name == "tests" and os.path.split(parent_dir)[1] == "pygame"
if not is_pygame_pkg:
sys.path.insert(0, parent_dir)
else:
is_pygame_pkg = __name__.startswith("pygame.tests.")
if is_pygame_pkg:
from pygame.tests.test_utils.run_tests import run_and_exit
from pygame.tests.test_utils.test_runner import opt_parser
else:
from test.test_utils.run_tests import run_and_exit
from test.test_utils.test_runner import opt_parser
if is_pygame_pkg:
test_pkg_name = "pygame.tests"
else:
test_pkg_name = "test"
program_name = sys.argv[0]
if program_name == "-c":
program_name = f'python -c "import {test_pkg_name}.go"'
###########################################################################
# Set additional command line options
#
# Defined in test_runner.py as it shares options, added to here
opt_parser.set_usage(
f"""
Runs all or some of the {test_pkg_name}.xxxx_test tests.
$ {program_name} sprite threads -sd
Runs the sprite and threads module tests isolated in subprocesses, dumping
all failing tests info in the form of a dict.
"""
)
opt_parser.add_option(
"-d", "--dump", action="store_true", help="dump results as dict ready to eval"
)
opt_parser.add_option("-F", "--file", help="dump results to a file")
opt_parser.add_option(
"-m",
"--multi_thread",
metavar="THREADS",
type="int",
help="run subprocessed tests in x THREADS",
)
opt_parser.add_option(
"-t",
"--time_out",
metavar="SECONDS",
type="int",
help="kill stalled subprocessed tests after SECONDS",
)
opt_parser.add_option(
"-f", "--fake", metavar="DIR", help="run fake tests in run_tests__tests/$DIR"
)
opt_parser.add_option(
"-p",
"--python",
metavar="PYTHON",
help="path to python executable to run subproccesed tests\n"
"default (sys.executable): %s" % sys.executable,
)
opt_parser.add_option(
"-I",
"--interactive",
action="store_true",
help="include tests requiring user input",
)
opt_parser.add_option("-S", "--seed", type="int", help="Randomisation seed")
###########################################################################
# Set run() keyword arguments according to command line arguments.
# args will be the test module list, passed as positional argumemts.
options, args = opt_parser.parse_args()
kwds = {}
if options.incomplete:
kwds["incomplete"] = True
if options.usesubprocess:
kwds["usesubprocess"] = True
else:
kwds["usesubprocess"] = False
if options.dump:
kwds["dump"] = True
if options.file:
kwds["file"] = options.file
if options.exclude:
kwds["exclude"] = options.exclude
if options.unbuffered:
kwds["unbuffered"] = True
if options.randomize:
kwds["randomize"] = True
if options.seed is not None:
kwds["seed"] = options.seed
if options.multi_thread is not None:
kwds["multi_thread"] = options.multi_thread
if options.time_out is not None:
kwds["time_out"] = options.time_out
if options.fake:
kwds["fake"] = options.fake
if options.python:
kwds["python"] = options.python
if options.interactive:
kwds["interactive"] = True
kwds["verbosity"] = options.verbosity if options.verbosity is not None else 1
###########################################################################
# Run the test suite.
run_and_exit(*args, **kwds)

View File

@@ -0,0 +1,623 @@
import sys
import unittest
import platform
IS_PYPY = "PyPy" == platform.python_implementation()
try:
from pygame.tests.test_utils import arrinter
except NameError:
pass
import pygame
quit_count = 0
def quit_hook():
global quit_count
quit_count += 1
class BaseModuleTest(unittest.TestCase):
def tearDown(self):
# Clean up after each test method.
pygame.quit()
def test_get_sdl_byteorder(self):
"""Ensure the SDL byte order is valid"""
byte_order = pygame.get_sdl_byteorder()
expected_options = (pygame.LIL_ENDIAN, pygame.BIG_ENDIAN)
self.assertIn(byte_order, expected_options)
def test_get_sdl_version(self):
"""Ensure the SDL version is valid"""
self.assertEqual(len(pygame.get_sdl_version()), 3)
class ExporterBase:
def __init__(self, shape, typechar, itemsize):
import ctypes
ndim = len(shape)
self.ndim = ndim
self.shape = tuple(shape)
array_len = 1
for d in shape:
array_len *= d
self.size = itemsize * array_len
self.parent = ctypes.create_string_buffer(self.size)
self.itemsize = itemsize
strides = [itemsize] * ndim
for i in range(ndim - 1, 0, -1):
strides[i - 1] = strides[i] * shape[i]
self.strides = tuple(strides)
self.data = ctypes.addressof(self.parent), False
if self.itemsize == 1:
byteorder = "|"
elif sys.byteorder == "big":
byteorder = ">"
else:
byteorder = "<"
self.typestr = byteorder + typechar + str(self.itemsize)
def assertSame(self, proxy, obj):
self.assertEqual(proxy.length, obj.size)
iface = proxy.__array_interface__
self.assertEqual(iface["typestr"], obj.typestr)
self.assertEqual(iface["shape"], obj.shape)
self.assertEqual(iface["strides"], obj.strides)
self.assertEqual(iface["data"], obj.data)
def test_PgObject_GetBuffer_array_interface(self):
from pygame.bufferproxy import BufferProxy
class Exporter(self.ExporterBase):
def get__array_interface__(self):
return {
"version": 3,
"typestr": self.typestr,
"shape": self.shape,
"strides": self.strides,
"data": self.data,
}
__array_interface__ = property(get__array_interface__)
# Should be ignored by PgObject_GetBuffer
__array_struct__ = property(lambda self: None)
_shape = [2, 3, 5, 7, 11] # Some prime numbers
for ndim in range(1, len(_shape)):
o = Exporter(_shape[0:ndim], "i", 2)
v = BufferProxy(o)
self.assertSame(v, o)
ndim = 2
shape = _shape[0:ndim]
for typechar in ("i", "u"):
for itemsize in (1, 2, 4, 8):
o = Exporter(shape, typechar, itemsize)
v = BufferProxy(o)
self.assertSame(v, o)
for itemsize in (4, 8):
o = Exporter(shape, "f", itemsize)
v = BufferProxy(o)
self.assertSame(v, o)
# Is the dict received from an exporting object properly released?
# The dict should be freed before PgObject_GetBuffer returns.
# When the BufferProxy v's length property is referenced, v calls
# PgObject_GetBuffer, which in turn references Exporter2 o's
# __array_interface__ property. The Exporter2 instance o returns a
# dict subclass for which it keeps both a regular reference and a
# weak reference. The regular reference should be the only
# remaining reference when PgObject_GetBuffer returns. This is
# verified by first checking the weak reference both before and
# after the regular reference held by o is removed.
import weakref, gc
class NoDictError(RuntimeError):
pass
class WRDict(dict):
"""Weak referenceable dict"""
pass
class Exporter2(Exporter):
def get__array_interface__2(self):
self.d = WRDict(Exporter.get__array_interface__(self))
self.dict_ref = weakref.ref(self.d)
return self.d
__array_interface__ = property(get__array_interface__2)
def free_dict(self):
self.d = None
def is_dict_alive(self):
try:
return self.dict_ref() is not None
except AttributeError:
raise NoDictError("__array_interface__ is unread")
o = Exporter2((2, 4), "u", 4)
v = BufferProxy(o)
self.assertRaises(NoDictError, o.is_dict_alive)
length = v.length
self.assertTrue(o.is_dict_alive())
o.free_dict()
gc.collect()
self.assertFalse(o.is_dict_alive())
def test_GetView_array_struct(self):
from pygame.bufferproxy import BufferProxy
class Exporter(self.ExporterBase):
def __init__(self, shape, typechar, itemsize):
super().__init__(shape, typechar, itemsize)
self.view = BufferProxy(self.__dict__)
def get__array_struct__(self):
return self.view.__array_struct__
__array_struct__ = property(get__array_struct__)
# Should not cause PgObject_GetBuffer to fail
__array_interface__ = property(lambda self: None)
_shape = [2, 3, 5, 7, 11] # Some prime numbers
for ndim in range(1, len(_shape)):
o = Exporter(_shape[0:ndim], "i", 2)
v = BufferProxy(o)
self.assertSame(v, o)
ndim = 2
shape = _shape[0:ndim]
for typechar in ("i", "u"):
for itemsize in (1, 2, 4, 8):
o = Exporter(shape, typechar, itemsize)
v = BufferProxy(o)
self.assertSame(v, o)
for itemsize in (4, 8):
o = Exporter(shape, "f", itemsize)
v = BufferProxy(o)
self.assertSame(v, o)
# Check returned cobject/capsule reference count
try:
from sys import getrefcount
except ImportError:
# PyPy: no reference counting
pass
else:
o = Exporter(shape, typechar, itemsize)
self.assertEqual(getrefcount(o.__array_struct__), 1)
if pygame.HAVE_NEWBUF:
from pygame.tests.test_utils import buftools
def NEWBUF_assertSame(self, proxy, exp):
buftools = self.buftools
Importer = buftools.Importer
self.assertEqual(proxy.length, exp.len)
imp = Importer(proxy, buftools.PyBUF_RECORDS_RO)
self.assertEqual(imp.readonly, exp.readonly)
self.assertEqual(imp.format, exp.format)
self.assertEqual(imp.itemsize, exp.itemsize)
self.assertEqual(imp.ndim, exp.ndim)
self.assertEqual(imp.shape, exp.shape)
self.assertEqual(imp.strides, exp.strides)
self.assertTrue(imp.suboffsets is None)
@unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented")
@unittest.skipIf(IS_PYPY, "pypy no likey")
def test_newbuf(self):
from pygame.bufferproxy import BufferProxy
Exporter = self.buftools.Exporter
_shape = [2, 3, 5, 7, 11] # Some prime numbers
for ndim in range(1, len(_shape)):
o = Exporter(_shape[0:ndim], "=h")
v = BufferProxy(o)
self.NEWBUF_assertSame(v, o)
ndim = 2
shape = _shape[0:ndim]
for format in [
"b",
"B",
"=h",
"=H",
"=i",
"=I",
"=q",
"=Q",
"f",
"d",
"1h",
"=1h",
"x",
"1x",
"2x",
"3x",
"4x",
"5x",
"6x",
"7x",
"8x",
"9x",
]:
o = Exporter(shape, format)
v = BufferProxy(o)
self.NEWBUF_assertSame(v, o)
@unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented")
def test_bad_format(self):
from pygame.bufferproxy import BufferProxy
from pygame.newbuffer import BufferMixin
from ctypes import create_string_buffer, addressof
buftools = self.buftools
Exporter = buftools.Exporter
Importer = buftools.Importer
PyBUF_FORMAT = buftools.PyBUF_FORMAT
for format in [
"",
"=",
"1",
" ",
"2h",
"=2h",
"0x",
"11x",
"=!",
"h ",
" h",
"hh",
"?",
]:
exp = Exporter((1,), format, itemsize=2)
b = BufferProxy(exp)
self.assertRaises(ValueError, Importer, b, PyBUF_FORMAT)
@unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented")
@unittest.skipIf(IS_PYPY, "fails on pypy")
def test_PgDict_AsBuffer_PyBUF_flags(self):
from pygame.bufferproxy import BufferProxy
is_lil_endian = pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN
fsys, frev = ("<", ">") if is_lil_endian else (">", "<")
buftools = self.buftools
Importer = buftools.Importer
a = BufferProxy(
{"typestr": "|u4", "shape": (10, 2), "data": (9, False)}
) # 9? No data accesses.
b = Importer(a, buftools.PyBUF_SIMPLE)
self.assertEqual(b.ndim, 0)
self.assertTrue(b.format is None)
self.assertEqual(b.len, a.length)
self.assertEqual(b.itemsize, 4)
self.assertTrue(b.shape is None)
self.assertTrue(b.strides is None)
self.assertTrue(b.suboffsets is None)
self.assertFalse(b.readonly)
self.assertEqual(b.buf, 9)
b = Importer(a, buftools.PyBUF_WRITABLE)
self.assertEqual(b.ndim, 0)
self.assertTrue(b.format is None)
self.assertEqual(b.len, a.length)
self.assertEqual(b.itemsize, 4)
self.assertTrue(b.shape is None)
self.assertTrue(b.strides is None)
self.assertTrue(b.suboffsets is None)
self.assertFalse(b.readonly)
self.assertEqual(b.buf, 9)
b = Importer(a, buftools.PyBUF_ND)
self.assertEqual(b.ndim, 2)
self.assertTrue(b.format is None)
self.assertEqual(b.len, a.length)
self.assertEqual(b.itemsize, 4)
self.assertEqual(b.shape, (10, 2))
self.assertTrue(b.strides is None)
self.assertTrue(b.suboffsets is None)
self.assertFalse(b.readonly)
self.assertEqual(b.buf, 9)
a = BufferProxy(
{
"typestr": fsys + "i2",
"shape": (5, 10),
"strides": (24, 2),
"data": (42, False),
}
) # 42? No data accesses.
b = Importer(a, buftools.PyBUF_STRIDES)
self.assertEqual(b.ndim, 2)
self.assertTrue(b.format is None)
self.assertEqual(b.len, 100)
self.assertEqual(b.itemsize, 2)
self.assertEqual(b.shape, (5, 10))
self.assertEqual(b.strides, (24, 2))
self.assertTrue(b.suboffsets is None)
self.assertFalse(b.readonly)
self.assertEqual(b.buf, 42)
b = Importer(a, buftools.PyBUF_FULL_RO)
self.assertEqual(b.ndim, 2)
self.assertEqual(b.format, "=h")
self.assertEqual(b.len, 100)
self.assertEqual(b.itemsize, 2)
self.assertEqual(b.shape, (5, 10))
self.assertEqual(b.strides, (24, 2))
self.assertTrue(b.suboffsets is None)
self.assertFalse(b.readonly)
self.assertEqual(b.buf, 42)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_CONTIG)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_CONTIG)
a = BufferProxy(
{
"typestr": frev + "i2",
"shape": (3, 5, 10),
"strides": (120, 24, 2),
"data": (1000000, True),
}
) # 1000000? No data accesses.
b = Importer(a, buftools.PyBUF_FULL_RO)
self.assertEqual(b.ndim, 3)
self.assertEqual(b.format, frev + "h")
self.assertEqual(b.len, 300)
self.assertEqual(b.itemsize, 2)
self.assertEqual(b.shape, (3, 5, 10))
self.assertEqual(b.strides, (120, 24, 2))
self.assertTrue(b.suboffsets is None)
self.assertTrue(b.readonly)
self.assertEqual(b.buf, 1000000)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_FULL)
@unittest.skipIf(IS_PYPY or (not pygame.HAVE_NEWBUF), "newbuf with ctypes")
def test_PgObject_AsBuffer_PyBUF_flags(self):
from pygame.bufferproxy import BufferProxy
import ctypes
is_lil_endian = pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN
fsys, frev = ("<", ">") if is_lil_endian else (">", "<")
buftools = self.buftools
Importer = buftools.Importer
e = arrinter.Exporter(
(10, 2), typekind="f", itemsize=ctypes.sizeof(ctypes.c_double)
)
a = BufferProxy(e)
b = Importer(a, buftools.PyBUF_SIMPLE)
self.assertEqual(b.ndim, 0)
self.assertTrue(b.format is None)
self.assertEqual(b.len, e.len)
self.assertEqual(b.itemsize, e.itemsize)
self.assertTrue(b.shape is None)
self.assertTrue(b.strides is None)
self.assertTrue(b.suboffsets is None)
self.assertFalse(b.readonly)
self.assertEqual(b.buf, e.data)
b = Importer(a, buftools.PyBUF_WRITABLE)
self.assertEqual(b.ndim, 0)
self.assertTrue(b.format is None)
self.assertEqual(b.len, e.len)
self.assertEqual(b.itemsize, e.itemsize)
self.assertTrue(b.shape is None)
self.assertTrue(b.strides is None)
self.assertTrue(b.suboffsets is None)
self.assertFalse(b.readonly)
self.assertEqual(b.buf, e.data)
b = Importer(a, buftools.PyBUF_ND)
self.assertEqual(b.ndim, e.nd)
self.assertTrue(b.format is None)
self.assertEqual(b.len, a.length)
self.assertEqual(b.itemsize, e.itemsize)
self.assertEqual(b.shape, e.shape)
self.assertTrue(b.strides is None)
self.assertTrue(b.suboffsets is None)
self.assertFalse(b.readonly)
self.assertEqual(b.buf, e.data)
e = arrinter.Exporter((5, 10), typekind="i", itemsize=2, strides=(24, 2))
a = BufferProxy(e)
b = Importer(a, buftools.PyBUF_STRIDES)
self.assertEqual(b.ndim, e.nd)
self.assertTrue(b.format is None)
self.assertEqual(b.len, e.len)
self.assertEqual(b.itemsize, e.itemsize)
self.assertEqual(b.shape, e.shape)
self.assertEqual(b.strides, e.strides)
self.assertTrue(b.suboffsets is None)
self.assertFalse(b.readonly)
self.assertEqual(b.buf, e.data)
b = Importer(a, buftools.PyBUF_FULL_RO)
self.assertEqual(b.ndim, e.nd)
self.assertEqual(b.format, "=h")
self.assertEqual(b.len, e.len)
self.assertEqual(b.itemsize, e.itemsize)
self.assertEqual(b.shape, e.shape)
self.assertEqual(b.strides, e.strides)
self.assertTrue(b.suboffsets is None)
self.assertFalse(b.readonly)
self.assertEqual(b.buf, e.data)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_WRITABLE)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_WRITABLE)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_CONTIG)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_SIMPLE)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ND)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_C_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_F_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_ANY_CONTIGUOUS)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_CONTIG)
e = arrinter.Exporter(
(3, 5, 10),
typekind="i",
itemsize=2,
strides=(120, 24, 2),
flags=arrinter.PAI_ALIGNED,
)
a = BufferProxy(e)
b = Importer(a, buftools.PyBUF_FULL_RO)
self.assertEqual(b.ndim, e.nd)
self.assertEqual(b.format, frev + "h")
self.assertEqual(b.len, e.len)
self.assertEqual(b.itemsize, e.itemsize)
self.assertEqual(b.shape, e.shape)
self.assertEqual(b.strides, e.strides)
self.assertTrue(b.suboffsets is None)
self.assertTrue(b.readonly)
self.assertEqual(b.buf, e.data)
self.assertRaises(BufferError, Importer, a, buftools.PyBUF_FULL)
def test_PgObject_GetBuffer_exception(self):
# For consistency with surfarray
from pygame.bufferproxy import BufferProxy
bp = BufferProxy(1)
self.assertRaises(ValueError, getattr, bp, "length")
def not_init_assertions(self):
self.assertFalse(pygame.get_init(), "pygame shouldn't be initialized")
self.assertFalse(pygame.display.get_init(), "display shouldn't be initialized")
if "pygame.mixer" in sys.modules:
self.assertFalse(pygame.mixer.get_init(), "mixer shouldn't be initialized")
if "pygame.font" in sys.modules:
self.assertFalse(pygame.font.get_init(), "init shouldn't be initialized")
## !!! TODO : Remove when scrap works for OS X
import platform
if platform.system().startswith("Darwin"):
return
try:
self.assertRaises(pygame.error, pygame.scrap.get)
except NotImplementedError:
# Scrap is optional.
pass
# pygame.cdrom
# pygame.joystick
def init_assertions(self):
self.assertTrue(pygame.get_init())
self.assertTrue(pygame.display.get_init())
if "pygame.mixer" in sys.modules:
self.assertTrue(pygame.mixer.get_init())
if "pygame.font" in sys.modules:
self.assertTrue(pygame.font.get_init())
def test_quit__and_init(self):
# __doc__ (as of 2008-06-25) for pygame.base.quit:
# pygame.quit(): return None
# uninitialize all pygame modules
# Make sure everything is not init
self.not_init_assertions()
# Initiate it
pygame.init()
# Check
self.init_assertions()
# Quit
pygame.quit()
# All modules have quit
self.not_init_assertions()
def test_register_quit(self):
"""Ensure that a registered function is called on quit()"""
self.assertEqual(quit_count, 0)
pygame.init()
pygame.register_quit(quit_hook)
pygame.quit()
self.assertEqual(quit_count, 1)
def test_get_error(self):
# __doc__ (as of 2008-08-02) for pygame.base.get_error:
# pygame.get_error(): return errorstr
# get the current error message
#
# SDL maintains an internal error message. This message will usually
# be given to you when pygame.error is raised. You will rarely need to
# call this function.
#
# The first error could be all sorts of nonsense or empty.
e = pygame.get_error()
pygame.set_error("hi")
self.assertEqual(pygame.get_error(), "hi")
pygame.set_error("")
self.assertEqual(pygame.get_error(), "")
def test_set_error(self):
# The first error could be all sorts of nonsense or empty.
e = pygame.get_error()
pygame.set_error("hi")
self.assertEqual(pygame.get_error(), "hi")
pygame.set_error("")
self.assertEqual(pygame.get_error(), "")
def test_unicode_error(self):
pygame.set_error("你好")
self.assertEqual("你好", pygame.get_error())
def test_init(self):
"""Ensures init() works properly."""
# Make sure nothing initialized.
self.not_init_assertions()
# display and joystick must init, at minimum
expected_min_passes = 2
# All modules should pass.
expected_fails = 0
passes, fails = pygame.init()
self.init_assertions()
self.assertGreaterEqual(passes, expected_min_passes)
self.assertEqual(fails, expected_fails)
def test_get_init(self):
# Test if get_init() gets the init state.
self.assertFalse(pygame.get_init())
def test_get_init__after_init(self):
# Test if get_init() gets the init state after pygame.init() called.
pygame.init()
self.assertTrue(pygame.get_init())
def test_get_init__after_quit(self):
# Test if get_init() gets the init state after pygame.quit() called.
pygame.init()
pygame.quit()
self.assertFalse(pygame.get_init())
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,153 @@
import unittest
import pygame
from pygame.locals import *
class BlitTest(unittest.TestCase):
def test_SRCALPHA(self):
"""SRCALPHA tests."""
# blend(s, 0, d) = d
s = pygame.Surface((1, 1), SRCALPHA, 32)
s.fill((255, 255, 255, 0))
d = pygame.Surface((1, 1), SRCALPHA, 32)
d.fill((0, 0, 255, 255))
s.blit(d, (0, 0))
self.assertEqual(s.get_at((0, 0)), d.get_at((0, 0)))
# blend(s, 255, d) = s
s = pygame.Surface((1, 1), SRCALPHA, 32)
s.fill((123, 0, 0, 255))
s1 = pygame.Surface((1, 1), SRCALPHA, 32)
s1.fill((123, 0, 0, 255))
d = pygame.Surface((1, 1), SRCALPHA, 32)
d.fill((10, 0, 0, 0))
s.blit(d, (0, 0))
self.assertEqual(s.get_at((0, 0)), s1.get_at((0, 0)))
# TODO: these should be true too.
# blend(0, sA, 0) = 0
# blend(255, sA, 255) = 255
# blend(s, sA, d) <= 255
def test_BLEND(self):
"""BLEND_ tests."""
# test that it doesn't overflow, and that it is saturated.
s = pygame.Surface((1, 1), SRCALPHA, 32)
s.fill((255, 255, 255, 0))
d = pygame.Surface((1, 1), SRCALPHA, 32)
d.fill((0, 0, 255, 255))
s.blit(d, (0, 0), None, BLEND_ADD)
# print("d %s" % (d.get_at((0,0)),))
# print(s.get_at((0,0)))
# self.assertEqual(s.get_at((0,0))[2], 255 )
# self.assertEqual(s.get_at((0,0))[3], 0 )
s.blit(d, (0, 0), None, BLEND_RGBA_ADD)
# print(s.get_at((0,0)))
self.assertEqual(s.get_at((0, 0))[3], 255)
# test adding works.
s.fill((20, 255, 255, 0))
d.fill((10, 0, 255, 255))
s.blit(d, (0, 0), None, BLEND_ADD)
self.assertEqual(s.get_at((0, 0))[2], 255)
# test subbing works.
s.fill((20, 255, 255, 0))
d.fill((10, 0, 255, 255))
s.blit(d, (0, 0), None, BLEND_SUB)
self.assertEqual(s.get_at((0, 0))[0], 10)
# no overflow in sub blend.
s.fill((20, 255, 255, 0))
d.fill((30, 0, 255, 255))
s.blit(d, (0, 0), None, BLEND_SUB)
self.assertEqual(s.get_at((0, 0))[0], 0)
def make_blit_list(self, num_surfs):
blit_list = []
for i in range(num_surfs):
dest = (i * 10, 0)
surf = pygame.Surface((10, 10), SRCALPHA, 32)
color = (i * 1, i * 1, i * 1)
surf.fill(color)
blit_list.append((surf, dest))
return blit_list
def test_blits(self):
NUM_SURFS = 255
PRINT_TIMING = 0
dst = pygame.Surface((NUM_SURFS * 10, 10), SRCALPHA, 32)
dst.fill((230, 230, 230))
blit_list = self.make_blit_list(NUM_SURFS)
def blits(blit_list):
for surface, dest in blit_list:
dst.blit(surface, dest)
from time import time
t0 = time()
results = blits(blit_list)
t1 = time()
if PRINT_TIMING:
print(f"python blits: {t1 - t0}")
dst.fill((230, 230, 230))
t0 = time()
results = dst.blits(blit_list)
t1 = time()
if PRINT_TIMING:
print(f"Surface.blits :{t1 - t0}")
# check if we blit all the different colors in the correct spots.
for i in range(NUM_SURFS):
color = (i * 1, i * 1, i * 1)
self.assertEqual(dst.get_at((i * 10, 0)), color)
self.assertEqual(dst.get_at(((i * 10) + 5, 5)), color)
self.assertEqual(len(results), NUM_SURFS)
t0 = time()
results = dst.blits(blit_list, doreturn=0)
t1 = time()
if PRINT_TIMING:
print(f"Surface.blits doreturn=0: {t1 - t0}")
self.assertEqual(results, None)
t0 = time()
results = dst.blits(((surf, dest) for surf, dest in blit_list))
t1 = time()
if PRINT_TIMING:
print(f"Surface.blits generator: {t1 - t0}")
def test_blits_not_sequence(self):
dst = pygame.Surface((100, 10), SRCALPHA, 32)
self.assertRaises(ValueError, dst.blits, None)
def test_blits_wrong_length(self):
dst = pygame.Surface((100, 10), SRCALPHA, 32)
self.assertRaises(
ValueError, dst.blits, [pygame.Surface((10, 10), SRCALPHA, 32)]
)
def test_blits_bad_surf_args(self):
dst = pygame.Surface((100, 10), SRCALPHA, 32)
self.assertRaises(TypeError, dst.blits, [(None, None)])
def test_blits_bad_dest(self):
dst = pygame.Surface((100, 10), SRCALPHA, 32)
self.assertRaises(
TypeError, dst.blits, [(pygame.Surface((10, 10), SRCALPHA, 32), None)]
)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,504 @@
import re
import weakref
import gc
import ctypes
import unittest
import pygame
from pygame.bufferproxy import BufferProxy
try:
BufferError
except NameError:
from pygame import BufferError
class BufferProxyTest(unittest.TestCase):
view_keywords = {
"shape": (5, 4, 3),
"typestr": "|u1",
"data": (0, True),
"strides": (4, 20, 1),
}
def test_module_name(self):
self.assertEqual(pygame.bufferproxy.__name__, "pygame.bufferproxy")
def test_class_name(self):
self.assertEqual(BufferProxy.__name__, "BufferProxy")
def test___array_struct___property(self):
kwds = self.view_keywords
v = BufferProxy(kwds)
d = pygame.get_array_interface(v)
self.assertEqual(len(d), 5)
self.assertEqual(d["version"], 3)
self.assertEqual(d["shape"], kwds["shape"])
self.assertEqual(d["typestr"], kwds["typestr"])
self.assertEqual(d["data"], kwds["data"])
self.assertEqual(d["strides"], kwds["strides"])
def test___array_interface___property(self):
kwds = self.view_keywords
v = BufferProxy(kwds)
d = v.__array_interface__
self.assertEqual(len(d), 5)
self.assertEqual(d["version"], 3)
self.assertEqual(d["shape"], kwds["shape"])
self.assertEqual(d["typestr"], kwds["typestr"])
self.assertEqual(d["data"], kwds["data"])
self.assertEqual(d["strides"], kwds["strides"])
def test_parent_property(self):
kwds = dict(self.view_keywords)
p = []
kwds["parent"] = p
v = BufferProxy(kwds)
self.assertIs(v.parent, p)
def test_before(self):
def callback(parent):
success.append(parent is p)
class MyException(Exception):
pass
def raise_exception(parent):
raise MyException("Just a test.")
kwds = dict(self.view_keywords)
p = []
kwds["parent"] = p
# For array interface
success = []
kwds["before"] = callback
v = BufferProxy(kwds)
self.assertEqual(len(success), 0)
d = v.__array_interface__
self.assertEqual(len(success), 1)
self.assertTrue(success[0])
d = v.__array_interface__
self.assertEqual(len(success), 1)
d = v = None
gc.collect()
self.assertEqual(len(success), 1)
# For array struct
success = []
kwds["before"] = callback
v = BufferProxy(kwds)
self.assertEqual(len(success), 0)
c = v.__array_struct__
self.assertEqual(len(success), 1)
self.assertTrue(success[0])
c = v.__array_struct__
self.assertEqual(len(success), 1)
c = v = None
gc.collect()
self.assertEqual(len(success), 1)
# Callback raises an exception
kwds["before"] = raise_exception
v = BufferProxy(kwds)
self.assertRaises(MyException, lambda: v.__array_struct__)
def test_after(self):
def callback(parent):
success.append(parent is p)
kwds = dict(self.view_keywords)
p = []
kwds["parent"] = p
# For array interface
success = []
kwds["after"] = callback
v = BufferProxy(kwds)
self.assertEqual(len(success), 0)
d = v.__array_interface__
self.assertEqual(len(success), 0)
d = v.__array_interface__
self.assertEqual(len(success), 0)
d = v = None
gc.collect()
self.assertEqual(len(success), 1)
self.assertTrue(success[0])
# For array struct
success = []
kwds["after"] = callback
v = BufferProxy(kwds)
self.assertEqual(len(success), 0)
c = v.__array_struct__
self.assertEqual(len(success), 0)
c = v.__array_struct__
self.assertEqual(len(success), 0)
c = v = None
gc.collect()
self.assertEqual(len(success), 1)
self.assertTrue(success[0])
def test_attribute(self):
v = BufferProxy(self.view_keywords)
self.assertRaises(AttributeError, getattr, v, "undefined")
v.undefined = 12
self.assertEqual(v.undefined, 12)
del v.undefined
self.assertRaises(AttributeError, getattr, v, "undefined")
def test_weakref(self):
v = BufferProxy(self.view_keywords)
weak_v = weakref.ref(v)
self.assertIs(weak_v(), v)
v = None
gc.collect()
self.assertIsNone(weak_v())
def test_gc(self):
"""refcount agnostic check that contained objects are freed"""
def before_callback(parent):
return r[0]
def after_callback(parent):
return r[1]
class Obj:
pass
p = Obj()
a = Obj()
r = [Obj(), Obj()]
weak_p = weakref.ref(p)
weak_a = weakref.ref(a)
weak_r0 = weakref.ref(r[0])
weak_r1 = weakref.ref(r[1])
weak_before = weakref.ref(before_callback)
weak_after = weakref.ref(after_callback)
kwds = dict(self.view_keywords)
kwds["parent"] = p
kwds["before"] = before_callback
kwds["after"] = after_callback
v = BufferProxy(kwds)
v.some_attribute = a
weak_v = weakref.ref(v)
kwds = p = a = before_callback = after_callback = None
gc.collect()
self.assertTrue(weak_p() is not None)
self.assertTrue(weak_a() is not None)
self.assertTrue(weak_before() is not None)
self.assertTrue(weak_after() is not None)
v = None
[gc.collect() for x in range(4)]
self.assertTrue(weak_v() is None)
self.assertTrue(weak_p() is None)
self.assertTrue(weak_a() is None)
self.assertTrue(weak_before() is None)
self.assertTrue(weak_after() is None)
self.assertTrue(weak_r0() is not None)
self.assertTrue(weak_r1() is not None)
r = None
gc.collect()
self.assertTrue(weak_r0() is None)
self.assertTrue(weak_r1() is None)
# Cycle removal
kwds = dict(self.view_keywords)
kwds["parent"] = []
v = BufferProxy(kwds)
v.some_attribute = v
tracked = True
for o in gc.get_objects():
if o is v:
break
else:
tracked = False
self.assertTrue(tracked)
kwds["parent"].append(v)
kwds = None
gc.collect()
n1 = len(gc.garbage)
v = None
gc.collect()
n2 = len(gc.garbage)
self.assertEqual(n2, n1)
def test_c_api(self):
api = pygame.bufferproxy._PYGAME_C_API
api_type = type(pygame.base._PYGAME_C_API)
self.assertIsInstance(api, api_type)
def test_repr(self):
v = BufferProxy(self.view_keywords)
cname = BufferProxy.__name__
oname, ovalue = re.findall(r"<([^)]+)\(([^)]+)\)>", repr(v))[0]
self.assertEqual(oname, cname)
self.assertEqual(v.length, int(ovalue))
def test_subclassing(self):
class MyBufferProxy(BufferProxy):
def __repr__(self):
return f"*{BufferProxy.__repr__(self)}*"
kwds = dict(self.view_keywords)
kwds["parent"] = 0
v = MyBufferProxy(kwds)
self.assertEqual(v.parent, 0)
r = repr(v)
self.assertEqual(r[:2], "*<")
self.assertEqual(r[-2:], ">*")
@unittest.skipIf(not pygame.HAVE_NEWBUF, "newbuf not implemented")
def NEWBUF_test_newbuf(self):
from ctypes import string_at
from pygame.tests.test_utils import buftools
Exporter = buftools.Exporter
Importer = buftools.Importer
exp = Exporter((10,), "B", readonly=True)
b = BufferProxy(exp)
self.assertEqual(b.length, exp.len)
self.assertEqual(b.raw, string_at(exp.buf, exp.len))
d = b.__array_interface__
try:
self.assertEqual(d["typestr"], "|u1")
self.assertEqual(d["shape"], exp.shape)
self.assertEqual(d["strides"], exp.strides)
self.assertEqual(d["data"], (exp.buf, True))
finally:
d = None
exp = Exporter((3,), "=h")
b = BufferProxy(exp)
self.assertEqual(b.length, exp.len)
self.assertEqual(b.raw, string_at(exp.buf, exp.len))
d = b.__array_interface__
try:
lil_endian = pygame.get_sdl_byteorder() == pygame.LIL_ENDIAN
f = f"{'<' if lil_endian else '>'}i{exp.itemsize}"
self.assertEqual(d["typestr"], f)
self.assertEqual(d["shape"], exp.shape)
self.assertEqual(d["strides"], exp.strides)
self.assertEqual(d["data"], (exp.buf, False))
finally:
d = None
exp = Exporter((10, 2), "=i")
b = BufferProxy(exp)
imp = Importer(b, buftools.PyBUF_RECORDS)
self.assertTrue(imp.obj is b)
self.assertEqual(imp.buf, exp.buf)
self.assertEqual(imp.ndim, exp.ndim)
self.assertEqual(imp.format, exp.format)
self.assertEqual(imp.readonly, exp.readonly)
self.assertEqual(imp.itemsize, exp.itemsize)
self.assertEqual(imp.len, exp.len)
self.assertEqual(imp.shape, exp.shape)
self.assertEqual(imp.strides, exp.strides)
self.assertTrue(imp.suboffsets is None)
d = {
"typestr": "|u1",
"shape": (10,),
"strides": (1,),
"data": (9, True),
} # 9? Will not reading the data anyway.
b = BufferProxy(d)
imp = Importer(b, buftools.PyBUF_SIMPLE)
self.assertTrue(imp.obj is b)
self.assertEqual(imp.buf, 9)
self.assertEqual(imp.len, 10)
self.assertEqual(imp.format, None)
self.assertEqual(imp.itemsize, 1)
self.assertEqual(imp.ndim, 0)
self.assertTrue(imp.readonly)
self.assertTrue(imp.shape is None)
self.assertTrue(imp.strides is None)
self.assertTrue(imp.suboffsets is None)
try:
pygame.bufferproxy.get_segcount
except AttributeError:
pass
else:
def test_oldbuf_arg(self):
self.OLDBUF_test_oldbuf_arg()
def OLDBUF_test_oldbuf_arg(self):
from pygame.bufferproxy import get_segcount, get_read_buffer, get_write_buffer
content = b"\x01\x00\x00\x02" * 12
memory = ctypes.create_string_buffer(content)
memaddr = ctypes.addressof(memory)
def raise_exception(o):
raise ValueError("An exception")
bf = BufferProxy(
{
"shape": (len(content),),
"typestr": "|u1",
"data": (memaddr, False),
"strides": (1,),
}
)
seglen, segaddr = get_read_buffer(bf, 0)
self.assertEqual(segaddr, 0)
self.assertEqual(seglen, 0)
seglen, segaddr = get_write_buffer(bf, 0)
self.assertEqual(segaddr, 0)
self.assertEqual(seglen, 0)
segcount, buflen = get_segcount(bf)
self.assertEqual(segcount, 1)
self.assertEqual(buflen, len(content))
seglen, segaddr = get_read_buffer(bf, 0)
self.assertEqual(segaddr, memaddr)
self.assertEqual(seglen, len(content))
seglen, segaddr = get_write_buffer(bf, 0)
self.assertEqual(segaddr, memaddr)
self.assertEqual(seglen, len(content))
bf = BufferProxy(
{
"shape": (len(content),),
"typestr": "|u1",
"data": (memaddr, True),
"strides": (1,),
}
)
segcount, buflen = get_segcount(bf)
self.assertEqual(segcount, 1)
self.assertEqual(buflen, len(content))
seglen, segaddr = get_read_buffer(bf, 0)
self.assertEqual(segaddr, memaddr)
self.assertEqual(seglen, len(content))
self.assertRaises(ValueError, get_write_buffer, bf, 0)
bf = BufferProxy(
{
"shape": (len(content),),
"typestr": "|u1",
"data": (memaddr, True),
"strides": (1,),
"before": raise_exception,
}
)
segcount, buflen = get_segcount(bf)
self.assertEqual(segcount, 0)
self.assertEqual(buflen, 0)
bf = BufferProxy(
{
"shape": (3, 4),
"typestr": "|u4",
"data": (memaddr, True),
"strides": (12, 4),
}
)
segcount, buflen = get_segcount(bf)
self.assertEqual(segcount, 3 * 4)
self.assertEqual(buflen, 3 * 4 * 4)
for i in range(0, 4):
seglen, segaddr = get_read_buffer(bf, i)
self.assertEqual(segaddr, memaddr + i * 4)
self.assertEqual(seglen, 4)
class BufferProxyLegacyTest(unittest.TestCase):
content = b"\x01\x00\x00\x02" * 12
buffer = ctypes.create_string_buffer(content)
data = (ctypes.addressof(buffer), True)
def test_length(self):
# __doc__ (as of 2008-08-02) for pygame.bufferproxy.BufferProxy.length:
# The size of the buffer data in bytes.
bf = BufferProxy(
{"shape": (3, 4), "typestr": "|u4", "data": self.data, "strides": (12, 4)}
)
self.assertEqual(bf.length, len(self.content))
bf = BufferProxy(
{"shape": (3, 3), "typestr": "|u4", "data": self.data, "strides": (12, 4)}
)
self.assertEqual(bf.length, 3 * 3 * 4)
def test_raw(self):
# __doc__ (as of 2008-08-02) for pygame.bufferproxy.BufferProxy.raw:
# The raw buffer data as string. The string may contain NUL bytes.
bf = BufferProxy(
{"shape": (len(self.content),), "typestr": "|u1", "data": self.data}
)
self.assertEqual(bf.raw, self.content)
bf = BufferProxy(
{"shape": (3, 4), "typestr": "|u4", "data": self.data, "strides": (4, 12)}
)
self.assertEqual(bf.raw, self.content)
bf = BufferProxy(
{"shape": (3, 4), "typestr": "|u1", "data": self.data, "strides": (16, 4)}
)
self.assertRaises(ValueError, getattr, bf, "raw")
def test_write(self):
# __doc__ (as of 2008-08-02) for pygame.bufferproxy.BufferProxy.write:
# B.write (bufferproxy, buffer, offset) -> None
#
# Writes raw data to the bufferproxy.
#
# Writes the raw data from buffer to the BufferProxy object, starting
# at the specified offset within the BufferProxy.
# If the length of the passed buffer exceeds the length of the
# BufferProxy (reduced by the offset), an IndexError will be raised.
from ctypes import c_byte, sizeof, addressof, string_at, memset
nullbyte = b"\x00"
Buf = c_byte * 10
data_buf = Buf(*range(1, 3 * sizeof(Buf) + 1, 3))
data = string_at(data_buf, sizeof(data_buf))
buf = Buf()
bp = BufferProxy(
{"typestr": "|u1", "shape": (sizeof(buf),), "data": (addressof(buf), False)}
)
try:
self.assertEqual(bp.raw, nullbyte * sizeof(Buf))
bp.write(data)
self.assertEqual(bp.raw, data)
memset(buf, 0, sizeof(buf))
bp.write(data[:3], 2)
raw = bp.raw
self.assertEqual(raw[:2], nullbyte * 2)
self.assertEqual(raw[2:5], data[:3])
self.assertEqual(raw[5:], nullbyte * (sizeof(Buf) - 5))
bp.write(data[:3], bp.length - 3)
raw = bp.raw
self.assertEqual(raw[-3:], data[:3])
self.assertRaises(IndexError, bp.write, data, 1)
self.assertRaises(IndexError, bp.write, data[:5], -1)
self.assertRaises(IndexError, bp.write, data[:5], bp.length)
self.assertRaises(TypeError, bp.write, 12)
bp = BufferProxy(
{
"typestr": "|u1",
"shape": (sizeof(buf),),
"data": (addressof(buf), True),
}
)
self.assertRaises(pygame.BufferError, bp.write, b"123")
finally:
# Make sure bp is garbage collected before buf
bp = None
gc.collect()
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,5 @@
import unittest
class CameraModuleTest(unittest.TestCase):
pass

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,426 @@
import unittest
import pygame.constants
# K_* and KSCAN_* common names.
K_AND_KSCAN_COMMON_NAMES = (
"UNKNOWN",
"BACKSPACE",
"TAB",
"CLEAR",
"RETURN",
"PAUSE",
"ESCAPE",
"SPACE",
"COMMA",
"MINUS",
"PERIOD",
"SLASH",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"SEMICOLON",
"EQUALS",
"LEFTBRACKET",
"BACKSLASH",
"RIGHTBRACKET",
"DELETE",
"KP0",
"KP1",
"KP2",
"KP3",
"KP4",
"KP5",
"KP6",
"KP7",
"KP8",
"KP9",
"KP_PERIOD",
"KP_DIVIDE",
"KP_MULTIPLY",
"KP_MINUS",
"KP_PLUS",
"KP_ENTER",
"KP_EQUALS",
"UP",
"DOWN",
"RIGHT",
"LEFT",
"INSERT",
"HOME",
"END",
"PAGEUP",
"PAGEDOWN",
"F1",
"F2",
"F3",
"F4",
"F5",
"F6",
"F7",
"F8",
"F9",
"F10",
"F11",
"F12",
"F13",
"F14",
"F15",
"NUMLOCK",
"CAPSLOCK",
"SCROLLOCK",
"RSHIFT",
"LSHIFT",
"RCTRL",
"LCTRL",
"RALT",
"LALT",
"RMETA",
"LMETA",
"LSUPER",
"RSUPER",
"MODE",
"HELP",
"PRINT",
"SYSREQ",
"BREAK",
"MENU",
"POWER",
"EURO",
"KP_0",
"KP_1",
"KP_2",
"KP_3",
"KP_4",
"KP_5",
"KP_6",
"KP_7",
"KP_8",
"KP_9",
"NUMLOCKCLEAR",
"SCROLLLOCK",
"RGUI",
"LGUI",
"PRINTSCREEN",
"CURRENCYUNIT",
"CURRENCYSUBUNIT",
)
# Constants that have the same value.
K_AND_KSCAN_COMMON_OVERLAPS = (
("KP0", "KP_0"),
("KP1", "KP_1"),
("KP2", "KP_2"),
("KP3", "KP_3"),
("KP4", "KP_4"),
("KP5", "KP_5"),
("KP6", "KP_6"),
("KP7", "KP_7"),
("KP8", "KP_8"),
("KP9", "KP_9"),
("NUMLOCK", "NUMLOCKCLEAR"),
("SCROLLOCK", "SCROLLLOCK"),
("LSUPER", "LMETA", "LGUI"),
("RSUPER", "RMETA", "RGUI"),
("PRINT", "PRINTSCREEN"),
("BREAK", "PAUSE"),
("EURO", "CURRENCYUNIT"),
)
def create_overlap_set(constant_names):
"""Helper function to find overlapping constant values/names.
Returns a set of fronzensets:
set(frozenset(names of overlapping constants), ...)
"""
# Create an overlap dict.
overlap_dict = {}
for name in constant_names:
value = getattr(pygame.constants, name)
overlap_dict.setdefault(value, set()).add(name)
# Get all entries with more than 1 value.
overlaps = set()
for overlap_names in overlap_dict.values():
if len(overlap_names) > 1:
overlaps.add(frozenset(overlap_names))
return overlaps
class KConstantsTests(unittest.TestCase):
"""Test K_* (key) constants."""
# K_* specific names.
K_SPECIFIC_NAMES = (
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"QUOTE",
"BACKQUOTE",
"EXCLAIM",
"QUOTEDBL",
"HASH",
"DOLLAR",
"AMPERSAND",
"LEFTPAREN",
"RIGHTPAREN",
"ASTERISK",
"PLUS",
"COLON",
"LESS",
"GREATER",
"QUESTION",
"AT",
"CARET",
"UNDERSCORE",
"PERCENT",
)
# Create a sequence of all the K_* constant names.
K_NAMES = tuple("K_" + n for n in K_AND_KSCAN_COMMON_NAMES + K_SPECIFIC_NAMES)
def test_k__existence(self):
"""Ensures K constants exist."""
for name in self.K_NAMES:
self.assertTrue(hasattr(pygame.constants, name), f"missing constant {name}")
def test_k__type(self):
"""Ensures K constants are the correct type."""
for name in self.K_NAMES:
value = getattr(pygame.constants, name)
self.assertIs(type(value), int)
def test_k__value_overlap(self):
"""Ensures no unexpected K constant values overlap."""
EXPECTED_OVERLAPS = {
frozenset("K_" + n for n in item) for item in K_AND_KSCAN_COMMON_OVERLAPS
}
overlaps = create_overlap_set(self.K_NAMES)
self.assertSetEqual(overlaps, EXPECTED_OVERLAPS)
class KscanConstantsTests(unittest.TestCase):
"""Test KSCAN_* (scancode) constants."""
# KSCAN_* specific names.
KSCAN_SPECIFIC_NAMES = (
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"APOSTROPHE",
"GRAVE",
"INTERNATIONAL1",
"INTERNATIONAL2",
"INTERNATIONAL3",
"INTERNATIONAL4",
"INTERNATIONAL5",
"INTERNATIONAL6",
"INTERNATIONAL7",
"INTERNATIONAL8",
"INTERNATIONAL9",
"LANG1",
"LANG2",
"LANG3",
"LANG4",
"LANG5",
"LANG6",
"LANG7",
"LANG8",
"LANG9",
"NONUSBACKSLASH",
"NONUSHASH",
)
# Create a sequence of all the KSCAN_* constant names.
KSCAN_NAMES = tuple(
"KSCAN_" + n for n in K_AND_KSCAN_COMMON_NAMES + KSCAN_SPECIFIC_NAMES
)
def test_kscan__existence(self):
"""Ensures KSCAN constants exist."""
for name in self.KSCAN_NAMES:
self.assertTrue(hasattr(pygame.constants, name), f"missing constant {name}")
def test_kscan__type(self):
"""Ensures KSCAN constants are the correct type."""
for name in self.KSCAN_NAMES:
value = getattr(pygame.constants, name)
self.assertIs(type(value), int)
def test_kscan__value_overlap(self):
"""Ensures no unexpected KSCAN constant values overlap."""
EXPECTED_OVERLAPS = {
frozenset("KSCAN_" + n for n in item)
for item in K_AND_KSCAN_COMMON_OVERLAPS
}
overlaps = create_overlap_set(self.KSCAN_NAMES)
self.assertSetEqual(overlaps, EXPECTED_OVERLAPS)
class KmodConstantsTests(unittest.TestCase):
"""Test KMOD_* (key modifier) constants."""
# KMOD_* constant names.
KMOD_CONSTANTS = (
"KMOD_NONE",
"KMOD_LSHIFT",
"KMOD_RSHIFT",
"KMOD_SHIFT",
"KMOD_LCTRL",
"KMOD_RCTRL",
"KMOD_CTRL",
"KMOD_LALT",
"KMOD_RALT",
"KMOD_ALT",
"KMOD_LMETA",
"KMOD_RMETA",
"KMOD_META",
"KMOD_NUM",
"KMOD_CAPS",
"KMOD_MODE",
"KMOD_LGUI",
"KMOD_RGUI",
"KMOD_GUI",
)
def test_kmod__existence(self):
"""Ensures KMOD constants exist."""
for name in self.KMOD_CONSTANTS:
self.assertTrue(hasattr(pygame.constants, name), f"missing constant {name}")
def test_kmod__type(self):
"""Ensures KMOD constants are the correct type."""
for name in self.KMOD_CONSTANTS:
value = getattr(pygame.constants, name)
self.assertIs(type(value), int)
def test_kmod__value_overlap(self):
"""Ensures no unexpected KMOD constant values overlap."""
# KMODs that have the same values.
EXPECTED_OVERLAPS = {
frozenset(["KMOD_LGUI", "KMOD_LMETA"]),
frozenset(["KMOD_RGUI", "KMOD_RMETA"]),
frozenset(["KMOD_GUI", "KMOD_META"]),
}
overlaps = create_overlap_set(self.KMOD_CONSTANTS)
self.assertSetEqual(overlaps, EXPECTED_OVERLAPS)
def test_kmod__no_bitwise_overlap(self):
"""Ensures certain KMOD constants have no overlapping bits."""
NO_BITWISE_OVERLAP = (
"KMOD_NONE",
"KMOD_LSHIFT",
"KMOD_RSHIFT",
"KMOD_LCTRL",
"KMOD_RCTRL",
"KMOD_LALT",
"KMOD_RALT",
"KMOD_LMETA",
"KMOD_RMETA",
"KMOD_NUM",
"KMOD_CAPS",
"KMOD_MODE",
)
kmods = 0
for name in NO_BITWISE_OVERLAP:
value = getattr(pygame.constants, name)
self.assertFalse(kmods & value)
kmods |= value
def test_kmod__bitwise_overlap(self):
"""Ensures certain KMOD constants have overlapping bits."""
# KMODS that are comprised of other KMODs.
KMOD_COMPRISED_DICT = {
"KMOD_SHIFT": ("KMOD_LSHIFT", "KMOD_RSHIFT"),
"KMOD_CTRL": ("KMOD_LCTRL", "KMOD_RCTRL"),
"KMOD_ALT": ("KMOD_LALT", "KMOD_RALT"),
"KMOD_META": ("KMOD_LMETA", "KMOD_RMETA"),
"KMOD_GUI": ("KMOD_LGUI", "KMOD_RGUI"),
}
for base_name, seq_names in KMOD_COMPRISED_DICT.items():
expected_value = 0 # Reset.
for name in seq_names:
expected_value |= getattr(pygame.constants, name)
value = getattr(pygame.constants, base_name)
self.assertEqual(value, expected_value)
################################################################################
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,357 @@
import unittest
import pygame
import pygame._sdl2.controller as controller
from pygame.tests.test_utils import prompt, question
class ControllerModuleTest(unittest.TestCase):
def setUp(self):
controller.init()
def tearDown(self):
controller.quit()
def test_init(self):
controller.quit()
controller.init()
self.assertTrue(controller.get_init())
def test_init__multiple(self):
controller.init()
controller.init()
self.assertTrue(controller.get_init())
def test_quit(self):
controller.quit()
self.assertFalse(controller.get_init())
def test_quit__multiple(self):
controller.quit()
controller.quit()
self.assertFalse(controller.get_init())
def test_get_init(self):
self.assertTrue(controller.get_init())
def test_get_eventstate(self):
controller.set_eventstate(True)
self.assertTrue(controller.get_eventstate())
controller.set_eventstate(False)
self.assertFalse(controller.get_eventstate())
controller.set_eventstate(True)
def test_get_count(self):
self.assertGreaterEqual(controller.get_count(), 0)
def test_is_controller(self):
for i in range(controller.get_count()):
if controller.is_controller(i):
c = controller.Controller(i)
self.assertIsInstance(c, controller.Controller)
c.quit()
else:
with self.assertRaises(pygame._sdl2.sdl2.error):
c = controller.Controller(i)
with self.assertRaises(TypeError):
controller.is_controller("Test")
def test_name_forindex(self):
self.assertIsNone(controller.name_forindex(-1))
class ControllerTypeTest(unittest.TestCase):
def setUp(self):
controller.init()
def tearDown(self):
controller.quit()
def _get_first_controller(self):
for i in range(controller.get_count()):
if controller.is_controller(i):
return controller.Controller(i)
def test_construction(self):
c = self._get_first_controller()
if c:
self.assertIsInstance(c, controller.Controller)
else:
self.skipTest("No controller connected")
def test__auto_init(self):
c = self._get_first_controller()
if c:
self.assertTrue(c.get_init())
else:
self.skipTest("No controller connected")
def test_get_init(self):
c = self._get_first_controller()
if c:
self.assertTrue(c.get_init())
c.quit()
self.assertFalse(c.get_init())
else:
self.skipTest("No controller connected")
def test_from_joystick(self):
for i in range(controller.get_count()):
if controller.is_controller(i):
joy = pygame.joystick.Joystick(i)
break
else:
self.skipTest("No controller connected")
c = controller.Controller.from_joystick(joy)
self.assertIsInstance(c, controller.Controller)
def test_as_joystick(self):
c = self._get_first_controller()
if c:
joy = c.as_joystick()
self.assertIsInstance(joy, type(pygame.joystick.Joystick(0)))
else:
self.skipTest("No controller connected")
def test_get_mapping(self):
c = self._get_first_controller()
if c:
mapping = c.get_mapping()
self.assertIsInstance(mapping, dict)
self.assertIsNotNone(mapping["a"])
else:
self.skipTest("No controller connected")
def test_set_mapping(self):
c = self._get_first_controller()
if c:
mapping = c.get_mapping()
mapping["a"] = "b3"
mapping["y"] = "b0"
c.set_mapping(mapping)
new_mapping = c.get_mapping()
self.assertEqual(len(mapping), len(new_mapping))
for i in mapping:
if mapping[i] not in ("a", "y"):
self.assertEqual(mapping[i], new_mapping[i])
else:
if i == "a":
self.assertEqual(new_mapping[i], mapping["y"])
else:
self.assertEqual(new_mapping[i], mapping["a"])
else:
self.skipTest("No controller connected")
class ControllerInteractiveTest(unittest.TestCase):
__tags__ = ["interactive"]
def _get_first_controller(self):
for i in range(controller.get_count()):
if controller.is_controller(i):
return controller.Controller(i)
def setUp(self):
controller.init()
def tearDown(self):
controller.quit()
def test__get_count_interactive(self):
prompt(
"Please connect at least one controller "
"before the test for controller.get_count() starts"
)
# Reset the number of joysticks counted
controller.quit()
controller.init()
joystick_num = controller.get_count()
ans = question(
"get_count() thinks there are {} joysticks "
"connected. Is that correct?".format(joystick_num)
)
self.assertTrue(ans)
def test_set_eventstate_on_interactive(self):
c = self._get_first_controller()
if not c:
self.skipTest("No controller connected")
pygame.display.init()
pygame.font.init()
screen = pygame.display.set_mode((400, 400))
font = pygame.font.Font(None, 20)
running = True
screen.fill((255, 255, 255))
screen.blit(
font.render("Press button 'x' (on ps4) or 'a' (on xbox).", True, (0, 0, 0)),
(0, 0),
)
pygame.display.update()
controller.set_eventstate(True)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.CONTROLLERBUTTONDOWN:
running = False
pygame.display.quit()
pygame.font.quit()
def test_set_eventstate_off_interactive(self):
c = self._get_first_controller()
if not c:
self.skipTest("No controller connected")
pygame.display.init()
pygame.font.init()
screen = pygame.display.set_mode((400, 400))
font = pygame.font.Font(None, 20)
running = True
screen.fill((255, 255, 255))
screen.blit(
font.render("Press button 'x' (on ps4) or 'a' (on xbox).", True, (0, 0, 0)),
(0, 0),
)
pygame.display.update()
controller.set_eventstate(False)
while running:
for event in pygame.event.get(pygame.QUIT):
if event:
running = False
if c.get_button(pygame.CONTROLLER_BUTTON_A):
if pygame.event.peek(pygame.CONTROLLERBUTTONDOWN):
pygame.display.quit()
pygame.font.quit()
self.fail()
else:
running = False
pygame.display.quit()
pygame.font.quit()
def test_get_button_interactive(self):
c = self._get_first_controller()
if not c:
self.skipTest("No controller connected")
pygame.display.init()
pygame.font.init()
screen = pygame.display.set_mode((400, 400))
font = pygame.font.Font(None, 20)
running = True
label1 = font.render(
"Press button 'x' (on ps4) or 'a' (on xbox).", True, (0, 0, 0)
)
label2 = font.render(
'The two values should match up. Press "y" or "n" to confirm.',
True,
(0, 0, 0),
)
is_pressed = [False, False] # event, get_button()
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.CONTROLLERBUTTONDOWN and event.button == 0:
is_pressed[0] = True
if event.type == pygame.CONTROLLERBUTTONUP and event.button == 0:
is_pressed[0] = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_y:
running = False
if event.key == pygame.K_n:
running = False
pygame.display.quit()
pygame.font.quit()
self.fail()
is_pressed[1] = c.get_button(pygame.CONTROLLER_BUTTON_A)
screen.fill((255, 255, 255))
screen.blit(label1, (0, 0))
screen.blit(label2, (0, 20))
screen.blit(font.render(str(is_pressed), True, (0, 0, 0)), (0, 40))
pygame.display.update()
pygame.display.quit()
pygame.font.quit()
def test_get_axis_interactive(self):
c = self._get_first_controller()
if not c:
self.skipTest("No controller connected")
pygame.display.init()
pygame.font.init()
screen = pygame.display.set_mode((400, 400))
font = pygame.font.Font(None, 20)
running = True
label1 = font.render(
"Press down the right trigger. The value on-screen should", True, (0, 0, 0)
)
label2 = font.render(
"indicate how far the trigger is pressed down. This value should",
True,
(0, 0, 0),
)
label3 = font.render(
'be in the range of 0-32767. Press "y" or "n" to confirm.', True, (0, 0, 0)
)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_y:
running = False
if event.key == pygame.K_n:
running = False
pygame.display.quit()
pygame.font.quit()
self.fail()
right_trigger = c.get_axis(pygame.CONTROLLER_AXIS_TRIGGERRIGHT)
screen.fill((255, 255, 255))
screen.blit(label1, (0, 0))
screen.blit(label2, (0, 20))
screen.blit(label3, (0, 40))
screen.blit(font.render(str(right_trigger), True, (0, 0, 0)), (0, 60))
pygame.display.update()
pygame.display.quit()
pygame.font.quit()
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,290 @@
import unittest
from pygame.tests.test_utils import fixture_path
import pygame
class CursorsModuleTest(unittest.TestCase):
def test_compile(self):
# __doc__ (as of 2008-06-25) for pygame.cursors.compile:
# pygame.cursors.compile(strings, black, white,xor) -> data, mask
# compile cursor strings into cursor data
#
# This takes a set of strings with equal length and computes
# the binary data for that cursor. The string widths must be
# divisible by 8.
#
# The black and white arguments are single letter strings that
# tells which characters will represent black pixels, and which
# characters represent white pixels. All other characters are
# considered clear.
#
# This returns a tuple containing the cursor data and cursor mask
# data. Both these arguments are used when setting a cursor with
# pygame.mouse.set_cursor().
# Various types of input strings
test_cursor1 = ("X.X.XXXX", "XXXXXX..", " XXXX ")
test_cursor2 = (
"X.X.XXXX",
"XXXXXX..",
"XXXXXX ",
"XXXXXX..",
"XXXXXX..",
"XXXXXX",
"XXXXXX..",
"XXXXXX..",
)
test_cursor3 = (".XX.", " ", ".. ", "X.. X")
# Test such that total number of strings is not divisible by 8
with self.assertRaises(ValueError):
pygame.cursors.compile(test_cursor1)
# Test such that size of individual string is not divisible by 8
with self.assertRaises(ValueError):
pygame.cursors.compile(test_cursor2)
# Test such that neither size of individual string nor total number of strings is divisible by 8
with self.assertRaises(ValueError):
pygame.cursors.compile(test_cursor3)
# Test that checks whether the byte data from compile function is equal to actual byte data
actual_byte_data = (
192,
0,
0,
224,
0,
0,
240,
0,
0,
216,
0,
0,
204,
0,
0,
198,
0,
0,
195,
0,
0,
193,
128,
0,
192,
192,
0,
192,
96,
0,
192,
48,
0,
192,
56,
0,
192,
248,
0,
220,
192,
0,
246,
96,
0,
198,
96,
0,
6,
96,
0,
3,
48,
0,
3,
48,
0,
1,
224,
0,
1,
128,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
), (
192,
0,
0,
224,
0,
0,
240,
0,
0,
248,
0,
0,
252,
0,
0,
254,
0,
0,
255,
0,
0,
255,
128,
0,
255,
192,
0,
255,
224,
0,
255,
240,
0,
255,
248,
0,
255,
248,
0,
255,
192,
0,
247,
224,
0,
199,
224,
0,
7,
224,
0,
3,
240,
0,
3,
240,
0,
1,
224,
0,
1,
128,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
)
cursor = pygame.cursors.compile(pygame.cursors.thickarrow_strings)
self.assertEqual(cursor, actual_byte_data)
# Test such that cursor byte data obtained from compile function is valid in pygame.mouse.set_cursor()
pygame.display.init()
try:
pygame.mouse.set_cursor((24, 24), (0, 0), *cursor)
except pygame.error as e:
if "not currently supported" in str(e):
unittest.skip("skipping test as set_cursor() is not supported")
finally:
pygame.display.quit()
################################################################################
def test_load_xbm(self):
# __doc__ (as of 2008-06-25) for pygame.cursors.load_xbm:
# pygame.cursors.load_xbm(cursorfile, maskfile) -> cursor_args
# reads a pair of XBM files into set_cursor arguments
#
# Arguments can either be filenames or filelike objects
# with the readlines method. Not largely tested, but
# should work with typical XBM files.
# Test that load_xbm will take filenames as arguments
cursorfile = fixture_path(r"xbm_cursors/white_sizing.xbm")
maskfile = fixture_path(r"xbm_cursors/white_sizing_mask.xbm")
cursor = pygame.cursors.load_xbm(cursorfile, maskfile)
# Test that load_xbm will take file objects as arguments
with open(cursorfile) as cursor_f, open(maskfile) as mask_f:
cursor = pygame.cursors.load_xbm(cursor_f, mask_f)
# Can it load using pathlib.Path?
import pathlib
cursor = pygame.cursors.load_xbm(
pathlib.Path(cursorfile), pathlib.Path(maskfile)
)
# Is it in a format that mouse.set_cursor won't blow up on?
pygame.display.init()
try:
pygame.mouse.set_cursor(*cursor)
except pygame.error as e:
if "not currently supported" in str(e):
unittest.skip("skipping test as set_cursor() is not supported")
finally:
pygame.display.quit()
def test_Cursor(self):
"""Ensure that the cursor object parses information properly"""
c1 = pygame.cursors.Cursor(pygame.SYSTEM_CURSOR_CROSSHAIR)
self.assertEqual(c1.data, (pygame.SYSTEM_CURSOR_CROSSHAIR,))
self.assertEqual(c1.type, "system")
c2 = pygame.cursors.Cursor(c1)
self.assertEqual(c1, c2)
with self.assertRaises(TypeError):
pygame.cursors.Cursor(-34002)
with self.assertRaises(TypeError):
pygame.cursors.Cursor("a", "b", "c", "d")
with self.assertRaises(TypeError):
pygame.cursors.Cursor((2,))
c3 = pygame.cursors.Cursor((0, 0), pygame.Surface((20, 20)))
self.assertEqual(c3.data[0], (0, 0))
self.assertEqual(c3.data[1].get_size(), (20, 20))
self.assertEqual(c3.type, "color")
xormask, andmask = pygame.cursors.compile(pygame.cursors.thickarrow_strings)
c4 = pygame.cursors.Cursor((24, 24), (0, 0), xormask, andmask)
self.assertEqual(c4.data, ((24, 24), (0, 0), xormask, andmask))
self.assertEqual(c4.type, "bitmap")
################################################################################
if __name__ == "__main__":
unittest.main()
################################################################################

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,35 @@
import os
import subprocess
import sys
import unittest
class DocsIncludedTest(unittest.TestCase):
def test_doc_import_works(self):
from pygame.docs.__main__ import has_local_docs, open_docs
@unittest.skipIf("CI" not in os.environ, "Docs not required for local builds")
def test_docs_included(self):
from pygame.docs.__main__ import has_local_docs
self.assertTrue(has_local_docs())
@unittest.skipIf("CI" not in os.environ, "Docs not required for local builds")
def test_docs_command(self):
try:
subprocess.run(
[sys.executable, "-m", "pygame.docs"],
timeout=5,
# check ensures an exception is raised when the process fails
check=True,
# pipe stdout/stderr so that they don't clutter main stdout
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
except subprocess.TimeoutExpired:
# timeout errors are not an issue
pass
if __name__ == "__main__":
unittest.main()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,949 @@
import collections
import time
import unittest
import os
import pygame
EVENT_TYPES = (
# pygame.NOEVENT,
# pygame.ACTIVEEVENT,
pygame.KEYDOWN,
pygame.KEYUP,
pygame.MOUSEMOTION,
pygame.MOUSEBUTTONDOWN,
pygame.MOUSEBUTTONUP,
pygame.JOYAXISMOTION,
pygame.JOYBALLMOTION,
pygame.JOYHATMOTION,
pygame.JOYBUTTONDOWN,
pygame.JOYBUTTONUP,
pygame.VIDEORESIZE,
pygame.VIDEOEXPOSE,
pygame.QUIT,
pygame.SYSWMEVENT,
pygame.USEREVENT,
# pygame.NUMEVENTS,
)
EVENT_TEST_PARAMS = collections.defaultdict(dict)
EVENT_TEST_PARAMS.update(
{
pygame.KEYDOWN: {"key": pygame.K_SPACE},
pygame.KEYUP: {"key": pygame.K_SPACE},
pygame.MOUSEMOTION: dict(),
pygame.MOUSEBUTTONDOWN: dict(button=1),
pygame.MOUSEBUTTONUP: dict(button=1),
}
)
NAMES_AND_EVENTS = (
("NoEvent", pygame.NOEVENT),
("ActiveEvent", pygame.ACTIVEEVENT),
("KeyDown", pygame.KEYDOWN),
("KeyUp", pygame.KEYUP),
("MouseMotion", pygame.MOUSEMOTION),
("MouseButtonDown", pygame.MOUSEBUTTONDOWN),
("MouseButtonUp", pygame.MOUSEBUTTONUP),
("JoyAxisMotion", pygame.JOYAXISMOTION),
("JoyBallMotion", pygame.JOYBALLMOTION),
("JoyHatMotion", pygame.JOYHATMOTION),
("JoyButtonDown", pygame.JOYBUTTONDOWN),
("JoyButtonUp", pygame.JOYBUTTONUP),
("VideoResize", pygame.VIDEORESIZE),
("VideoExpose", pygame.VIDEOEXPOSE),
("Quit", pygame.QUIT),
("SysWMEvent", pygame.SYSWMEVENT),
("MidiIn", pygame.MIDIIN),
("MidiOut", pygame.MIDIOUT),
("UserEvent", pygame.USEREVENT),
("Unknown", 0xFFFF),
("FingerMotion", pygame.FINGERMOTION),
("FingerDown", pygame.FINGERDOWN),
("FingerUp", pygame.FINGERUP),
("MultiGesture", pygame.MULTIGESTURE),
("MouseWheel", pygame.MOUSEWHEEL),
("TextInput", pygame.TEXTINPUT),
("TextEditing", pygame.TEXTEDITING),
("ControllerAxisMotion", pygame.CONTROLLERAXISMOTION),
("ControllerButtonDown", pygame.CONTROLLERBUTTONDOWN),
("ControllerButtonUp", pygame.CONTROLLERBUTTONUP),
("ControllerDeviceAdded", pygame.CONTROLLERDEVICEADDED),
("ControllerDeviceRemoved", pygame.CONTROLLERDEVICEREMOVED),
("ControllerDeviceMapped", pygame.CONTROLLERDEVICEREMAPPED),
("DropFile", pygame.DROPFILE),
("AudioDeviceAdded", pygame.AUDIODEVICEADDED),
("AudioDeviceRemoved", pygame.AUDIODEVICEREMOVED),
("DropText", pygame.DROPTEXT),
("DropBegin", pygame.DROPBEGIN),
("DropComplete", pygame.DROPCOMPLETE),
)
class EventTypeTest(unittest.TestCase):
def test_Event(self):
"""Ensure an Event object can be created."""
e = pygame.event.Event(pygame.USEREVENT, some_attr=1, other_attr="1")
self.assertEqual(e.some_attr, 1)
self.assertEqual(e.other_attr, "1")
# Event now uses tp_dictoffset and tp_members:
# https://github.com/pygame/pygame/issues/62
self.assertEqual(e.type, pygame.USEREVENT)
self.assertIs(e.dict, e.__dict__)
e.some_attr = 12
self.assertEqual(e.some_attr, 12)
e.new_attr = 15
self.assertEqual(e.new_attr, 15)
self.assertRaises(AttributeError, setattr, e, "type", 0)
self.assertRaises(AttributeError, setattr, e, "dict", None)
# Ensure attributes are visible to dir(), part of the original
# posted request.
d = dir(e)
attrs = ("type", "dict", "__dict__", "some_attr", "other_attr", "new_attr")
for attr in attrs:
self.assertIn(attr, d)
# redundant type field as kwarg
self.assertRaises(ValueError, pygame.event.Event, 10, type=100)
def test_as_str(self):
# Bug reported on Pygame mailing list July 24, 2011:
# For Python 3.x str(event) to raises an UnicodeEncodeError when
# an event attribute is a string with a non-ascii character.
try:
str(pygame.event.Event(EVENT_TYPES[0], a="\xed"))
except UnicodeEncodeError:
self.fail("Event object raised exception for non-ascii character")
# Passed.
def test_event_bool(self):
self.assertFalse(pygame.event.Event(pygame.NOEVENT))
for event_type in [
pygame.MOUSEBUTTONDOWN,
pygame.ACTIVEEVENT,
pygame.WINDOWLEAVE,
pygame.USEREVENT_DROPFILE,
]:
self.assertTrue(pygame.event.Event(event_type))
def test_event_equality(self):
"""Ensure that events can be compared correctly."""
a = pygame.event.Event(EVENT_TYPES[0], a=1)
b = pygame.event.Event(EVENT_TYPES[0], a=1)
c = pygame.event.Event(EVENT_TYPES[1], a=1)
d = pygame.event.Event(EVENT_TYPES[0], a=2)
self.assertTrue(a == a)
self.assertFalse(a != a)
self.assertTrue(a == b)
self.assertFalse(a != b)
self.assertTrue(a != c)
self.assertFalse(a == c)
self.assertTrue(a != d)
self.assertFalse(a == d)
race_condition_notification = """
This test is dependent on timing. The event queue is cleared in preparation for
tests. There is a small window where outside events from the OS may have effected
results. Try running the test again.
"""
class EventModuleArgsTest(unittest.TestCase):
def setUp(self):
pygame.display.init()
pygame.event.clear()
def tearDown(self):
pygame.display.quit()
def test_get(self):
pygame.event.get()
pygame.event.get(None)
pygame.event.get(None, True)
pygame.event.get(pump=False)
pygame.event.get(pump=True)
pygame.event.get(eventtype=None)
pygame.event.get(eventtype=[pygame.KEYUP, pygame.KEYDOWN])
pygame.event.get(eventtype=pygame.USEREVENT, pump=False)
# event type out of range
self.assertRaises(ValueError, pygame.event.get, 0x00010000)
self.assertRaises(TypeError, pygame.event.get, 1 + 2j)
self.assertRaises(TypeError, pygame.event.get, "foo")
def test_clear(self):
pygame.event.clear()
pygame.event.clear(None)
pygame.event.clear(None, True)
pygame.event.clear(pump=False)
pygame.event.clear(pump=True)
pygame.event.clear(eventtype=None)
pygame.event.clear(eventtype=[pygame.KEYUP, pygame.KEYDOWN])
pygame.event.clear(eventtype=pygame.USEREVENT, pump=False)
# event type out of range
self.assertRaises(ValueError, pygame.event.clear, 0x0010FFFFF)
self.assertRaises(TypeError, pygame.event.get, ["a", "b", "c"])
def test_peek(self):
pygame.event.peek()
pygame.event.peek(None)
pygame.event.peek(None, True)
pygame.event.peek(pump=False)
pygame.event.peek(pump=True)
pygame.event.peek(eventtype=None)
pygame.event.peek(eventtype=[pygame.KEYUP, pygame.KEYDOWN])
pygame.event.peek(eventtype=pygame.USEREVENT, pump=False)
class Foo:
pass
# event type out of range
self.assertRaises(ValueError, pygame.event.peek, -1)
self.assertRaises(ValueError, pygame.event.peek, [-10])
self.assertRaises(TypeError, pygame.event.peek, Foo())
class EventCustomTypeTest(unittest.TestCase):
"""Those tests are special in that they need the _custom_event counter to
be reset before and/or after being run."""
def setUp(self):
pygame.quit()
pygame.init()
pygame.display.init()
def tearDown(self):
pygame.quit()
def test_custom_type(self):
self.assertEqual(pygame.event.custom_type(), pygame.USEREVENT + 1)
atype = pygame.event.custom_type()
atype2 = pygame.event.custom_type()
self.assertEqual(atype, atype2 - 1)
ev = pygame.event.Event(atype)
pygame.event.post(ev)
queue = pygame.event.get(atype)
self.assertEqual(len(queue), 1)
self.assertEqual(queue[0].type, atype)
def test_custom_type__end_boundary(self):
"""Ensure custom_type() raises error when no more custom types.
The last allowed custom type number should be (pygame.NUMEVENTS - 1).
"""
last = -1
start = pygame.event.custom_type() + 1
for _ in range(start, pygame.NUMEVENTS):
last = pygame.event.custom_type()
self.assertEqual(last, pygame.NUMEVENTS - 1)
with self.assertRaises(pygame.error):
pygame.event.custom_type()
def test_custom_type__reset(self):
"""Ensure custom events get 'deregistered' by quit()."""
before = pygame.event.custom_type()
self.assertEqual(before, pygame.event.custom_type() - 1)
pygame.quit()
pygame.init()
pygame.display.init()
self.assertEqual(before, pygame.event.custom_type())
class EventModuleTest(unittest.TestCase):
def _assertCountEqual(self, *args, **kwargs):
# Handle method name differences between Python versions.
# Is this still needed?
self.assertCountEqual(*args, **kwargs)
def _assertExpectedEvents(self, expected, got):
"""Find events like expected events, raise on unexpected or missing,
ignore additional event properties if expected properties are present."""
# This does greedy matching, don't encode an NP-hard problem
# into your input data, *please*
items_left = got[:]
for expected_element in expected:
for item in items_left:
for key in expected_element.__dict__:
if item.__dict__[key] != expected_element.__dict__[key]:
break
else:
# found item!
items_left.remove(item)
break
else:
raise AssertionError(
"Expected "
+ str(expected_element)
+ " among remaining events "
+ str(items_left)
+ " out of "
+ str(got)
)
if len(items_left) > 0:
raise AssertionError("Unexpected Events: " + str(items_left))
def setUp(self):
pygame.display.init()
pygame.event.clear() # flush events
def tearDown(self):
pygame.event.clear() # flush events
pygame.display.quit()
def test_event_numevents(self):
"""Ensures NUMEVENTS does not exceed the maximum SDL number of events."""
# Ref: https://www.libsdl.org/tmp/SDL/include/SDL_events.h
MAX_SDL_EVENTS = 0xFFFF # SDL_LASTEVENT = 0xFFFF
self.assertLessEqual(pygame.NUMEVENTS, MAX_SDL_EVENTS)
def test_event_attribute(self):
e1 = pygame.event.Event(pygame.USEREVENT, attr1="attr1")
self.assertEqual(e1.attr1, "attr1")
def test_set_blocked(self):
"""Ensure events can be blocked from the queue."""
event = EVENT_TYPES[0]
unblocked_event = EVENT_TYPES[1]
pygame.event.set_blocked(event)
self.assertTrue(pygame.event.get_blocked(event))
self.assertFalse(pygame.event.get_blocked(unblocked_event))
posted = pygame.event.post(
pygame.event.Event(event, **EVENT_TEST_PARAMS[event])
)
self.assertFalse(posted)
# post an unblocked event
posted = pygame.event.post(
pygame.event.Event(unblocked_event, **EVENT_TEST_PARAMS[unblocked_event])
)
self.assertTrue(posted)
ret = pygame.event.get()
should_be_blocked = [e for e in ret if e.type == event]
should_be_allowed_types = [e.type for e in ret if e.type != event]
self.assertEqual(should_be_blocked, [])
self.assertTrue(unblocked_event in should_be_allowed_types)
def test_set_blocked__event_sequence(self):
"""Ensure a sequence of event types can be blocked."""
event_types = [
pygame.KEYDOWN,
pygame.KEYUP,
pygame.MOUSEMOTION,
pygame.MOUSEBUTTONDOWN,
pygame.MOUSEBUTTONUP,
pygame.WINDOWFOCUSLOST,
pygame.USEREVENT,
]
pygame.event.set_blocked(event_types)
for etype in event_types:
self.assertTrue(pygame.event.get_blocked(etype))
def test_set_blocked_all(self):
"""Ensure all events can be unblocked at once."""
pygame.event.set_blocked(None)
for e in EVENT_TYPES:
self.assertTrue(pygame.event.get_blocked(e))
def test_post__and_poll(self):
"""Ensure events can be posted to the queue."""
e1 = pygame.event.Event(pygame.USEREVENT, attr1="attr1")
pygame.event.post(e1)
posted_event = pygame.event.poll()
self.assertEqual(e1.attr1, posted_event.attr1, race_condition_notification)
# fuzzing event types
for i in range(1, 13):
pygame.event.post(
pygame.event.Event(EVENT_TYPES[i], **EVENT_TEST_PARAMS[EVENT_TYPES[i]])
)
self.assertEqual(
pygame.event.poll().type, EVENT_TYPES[i], race_condition_notification
)
def test_post_and_get_keydown(self):
"""Ensure keydown events can be posted to the queue."""
activemodkeys = pygame.key.get_mods()
events = [
pygame.event.Event(pygame.KEYDOWN, key=pygame.K_p),
pygame.event.Event(pygame.KEYDOWN, key=pygame.K_y, mod=activemodkeys),
pygame.event.Event(pygame.KEYDOWN, key=pygame.K_g, unicode="g"),
pygame.event.Event(pygame.KEYDOWN, key=pygame.K_a, unicode=None),
pygame.event.Event(pygame.KEYDOWN, key=pygame.K_m, mod=None, window=None),
pygame.event.Event(
pygame.KEYDOWN, key=pygame.K_e, mod=activemodkeys, unicode="e"
),
]
for e in events:
pygame.event.post(e)
posted_event = pygame.event.poll()
self.assertEqual(e, posted_event, race_condition_notification)
def test_post_large_user_event(self):
pygame.event.post(
pygame.event.Event(
pygame.USEREVENT, {"a": "a" * 1024}, test=list(range(100))
)
)
e = pygame.event.poll()
self.assertEqual(e.type, pygame.USEREVENT)
self.assertEqual(e.a, "a" * 1024)
self.assertEqual(e.test, list(range(100)))
def test_post_blocked(self):
"""
Test blocked events are not posted. Also test whether post()
returns a boolean correctly
"""
pygame.event.set_blocked(pygame.USEREVENT)
self.assertFalse(pygame.event.post(pygame.event.Event(pygame.USEREVENT)))
self.assertFalse(pygame.event.poll())
pygame.event.set_allowed(pygame.USEREVENT)
self.assertTrue(pygame.event.post(pygame.event.Event(pygame.USEREVENT)))
self.assertEqual(pygame.event.poll(), pygame.event.Event(pygame.USEREVENT))
def test_get(self):
"""Ensure get() retrieves all the events on the queue."""
event_cnt = 10
for _ in range(event_cnt):
pygame.event.post(pygame.event.Event(pygame.USEREVENT))
queue = pygame.event.get()
self.assertEqual(len(queue), event_cnt)
self.assertTrue(all(e.type == pygame.USEREVENT for e in queue))
def test_get_type(self):
ev = pygame.event.Event(pygame.USEREVENT)
pygame.event.post(ev)
queue = pygame.event.get(pygame.USEREVENT)
self.assertEqual(len(queue), 1)
self.assertEqual(queue[0].type, pygame.USEREVENT)
TESTEVENTS = 10
for _ in range(TESTEVENTS):
pygame.event.post(ev)
q = pygame.event.get([pygame.USEREVENT])
self.assertEqual(len(q), TESTEVENTS)
for event in q:
self.assertEqual(event, ev)
def test_get_exclude_throw(self):
self.assertRaises(
pygame.error, pygame.event.get, pygame.KEYDOWN, False, pygame.KEYUP
)
def test_get_exclude(self):
pygame.event.post(pygame.event.Event(pygame.USEREVENT))
pygame.event.post(pygame.event.Event(pygame.KEYDOWN))
queue = pygame.event.get(exclude=pygame.KEYDOWN)
self.assertEqual(len(queue), 1)
self.assertEqual(queue[0].type, pygame.USEREVENT)
pygame.event.post(pygame.event.Event(pygame.KEYUP))
pygame.event.post(pygame.event.Event(pygame.USEREVENT))
queue = pygame.event.get(exclude=(pygame.KEYDOWN, pygame.KEYUP))
self.assertEqual(len(queue), 1)
self.assertEqual(queue[0].type, pygame.USEREVENT)
queue = pygame.event.get()
self.assertEqual(len(queue), 2)
def test_get__empty_queue(self):
"""Ensure get() works correctly on an empty queue."""
expected_events = []
pygame.event.clear()
# Ensure all events can be checked.
retrieved_events = pygame.event.get()
self.assertListEqual(retrieved_events, expected_events)
# Ensure events can be checked individually.
for event_type in EVENT_TYPES:
retrieved_events = pygame.event.get(event_type)
self.assertListEqual(retrieved_events, expected_events)
# Ensure events can be checked as a sequence.
retrieved_events = pygame.event.get(EVENT_TYPES)
self.assertListEqual(retrieved_events, expected_events)
def test_get__event_sequence(self):
"""Ensure get() can handle a sequence of event types."""
event_types = [pygame.KEYDOWN, pygame.KEYUP, pygame.MOUSEMOTION]
other_event_type = pygame.MOUSEBUTTONUP
# Test when no events in the queue.
expected_events = []
pygame.event.clear()
retrieved_events = pygame.event.get(event_types)
# don't use self._assertCountEqual here. This checks for
# expected properties in events, and ignores unexpected ones, for
# forward compatibility with SDL2.
self._assertExpectedEvents(expected=expected_events, got=retrieved_events)
# Test when an event type not in the list is in the queue.
expected_events = []
pygame.event.clear()
pygame.event.post(
pygame.event.Event(other_event_type, **EVENT_TEST_PARAMS[other_event_type])
)
retrieved_events = pygame.event.get(event_types)
self._assertExpectedEvents(expected=expected_events, got=retrieved_events)
# Test when 1 event type in the list is in the queue.
expected_events = [
pygame.event.Event(event_types[0], **EVENT_TEST_PARAMS[event_types[0]])
]
pygame.event.clear()
pygame.event.post(expected_events[0])
retrieved_events = pygame.event.get(event_types)
self._assertExpectedEvents(expected=expected_events, got=retrieved_events)
# Test all events in the list are in the queue.
pygame.event.clear()
expected_events = []
for etype in event_types:
expected_events.append(
pygame.event.Event(etype, **EVENT_TEST_PARAMS[etype])
)
pygame.event.post(expected_events[-1])
retrieved_events = pygame.event.get(event_types)
self._assertExpectedEvents(expected=expected_events, got=retrieved_events)
def test_get_clears_queue(self):
"""Ensure get() clears the event queue after a call"""
pygame.event.get() # should clear the queue completely by getting all events
self.assertEqual(pygame.event.get(), [])
def test_clear(self):
"""Ensure clear() removes all the events on the queue."""
for e in EVENT_TYPES:
pygame.event.post(pygame.event.Event(e, **EVENT_TEST_PARAMS[e]))
poll_event = pygame.event.poll()
self.assertNotEqual(poll_event.type, pygame.NOEVENT)
pygame.event.clear()
poll_event = pygame.event.poll()
self.assertEqual(poll_event.type, pygame.NOEVENT, race_condition_notification)
def test_clear__empty_queue(self):
"""Ensure clear() works correctly on an empty queue."""
expected_events = []
pygame.event.clear()
# Test calling clear() on an already empty queue.
pygame.event.clear()
retrieved_events = pygame.event.get()
self.assertListEqual(retrieved_events, expected_events)
def test_clear__event_sequence(self):
"""Ensure a sequence of event types can be cleared from the queue."""
cleared_event_types = EVENT_TYPES[:5]
expected_event_types = EVENT_TYPES[5:10]
expected_events = []
# Add the events to the queue.
for etype in cleared_event_types:
pygame.event.post(pygame.event.Event(etype, **EVENT_TEST_PARAMS[etype]))
for etype in expected_events:
expected_events.append(
pygame.event.Event(etype, **EVENT_TEST_PARAMS[etype])
)
pygame.event.post(expected_events[-1])
# Clear the cleared_events from the queue.
pygame.event.clear(cleared_event_types)
# Check the rest of the events in the queue.
remaining_events = pygame.event.get()
self._assertCountEqual(remaining_events, expected_events)
def test_event_name(self):
"""Ensure event_name() returns the correct event name."""
for expected_name, event in NAMES_AND_EVENTS:
self.assertEqual(
pygame.event.event_name(event), expected_name, f"0x{event:X}"
)
def test_event_name__userevent_range(self):
"""Ensures event_name() returns the correct name for user events.
Tests the full range of user events.
"""
expected_name = "UserEvent"
for event in range(pygame.USEREVENT, pygame.NUMEVENTS):
self.assertEqual(
pygame.event.event_name(event), expected_name, f"0x{event:X}"
)
def test_event_name__userevent_boundary(self):
"""Ensures event_name() does not return 'UserEvent' for events
just outside the user event range.
"""
unexpected_name = "UserEvent"
for event in (pygame.USEREVENT - 1, pygame.NUMEVENTS):
self.assertNotEqual(
pygame.event.event_name(event), unexpected_name, f"0x{event:X}"
)
def test_event_name__kwargs(self):
"""Ensure event_name() returns the correct event name when kwargs used."""
for expected_name, event in NAMES_AND_EVENTS:
self.assertEqual(
pygame.event.event_name(type=event), expected_name, f"0x{event:X}"
)
def test_peek(self):
"""Ensure queued events can be peeked at."""
event_types = [pygame.KEYDOWN, pygame.KEYUP, pygame.MOUSEMOTION]
for event_type in event_types:
pygame.event.post(
pygame.event.Event(event_type, **EVENT_TEST_PARAMS[event_type])
)
# Ensure events can be checked individually.
for event_type in event_types:
self.assertTrue(pygame.event.peek(event_type))
# Ensure events can be checked as a sequence.
self.assertTrue(pygame.event.peek(event_types))
def test_peek__event_sequence(self):
"""Ensure peek() can handle a sequence of event types."""
event_types = [pygame.KEYDOWN, pygame.KEYUP, pygame.MOUSEMOTION]
other_event_type = pygame.MOUSEBUTTONUP
# Test when no events in the queue.
pygame.event.clear()
peeked = pygame.event.peek(event_types)
self.assertFalse(peeked)
# Test when an event type not in the list is in the queue.
pygame.event.clear()
pygame.event.post(
pygame.event.Event(other_event_type, **EVENT_TEST_PARAMS[other_event_type])
)
peeked = pygame.event.peek(event_types)
self.assertFalse(peeked)
# Test when 1 event type in the list is in the queue.
pygame.event.clear()
pygame.event.post(
pygame.event.Event(event_types[0], **EVENT_TEST_PARAMS[event_types[0]])
)
peeked = pygame.event.peek(event_types)
self.assertTrue(peeked)
# Test all events in the list are in the queue.
pygame.event.clear()
for etype in event_types:
pygame.event.post(pygame.event.Event(etype, **EVENT_TEST_PARAMS[etype]))
peeked = pygame.event.peek(event_types)
self.assertTrue(peeked)
def test_peek__empty_queue(self):
"""Ensure peek() works correctly on an empty queue."""
pygame.event.clear()
# Ensure all events can be checked.
peeked = pygame.event.peek()
self.assertFalse(peeked)
# Ensure events can be checked individually.
for event_type in EVENT_TYPES:
peeked = pygame.event.peek(event_type)
self.assertFalse(peeked)
# Ensure events can be checked as a sequence.
peeked = pygame.event.peek(EVENT_TYPES)
self.assertFalse(peeked)
def test_set_allowed(self):
"""Ensure a blocked event type can be unblocked/allowed."""
event = EVENT_TYPES[0]
pygame.event.set_blocked(event)
self.assertTrue(pygame.event.get_blocked(event))
pygame.event.set_allowed(event)
self.assertFalse(pygame.event.get_blocked(event))
def test_set_allowed__event_sequence(self):
"""Ensure a sequence of blocked event types can be unblocked/allowed."""
event_types = [
pygame.KEYDOWN,
pygame.KEYUP,
pygame.MOUSEMOTION,
pygame.MOUSEBUTTONDOWN,
pygame.MOUSEBUTTONUP,
]
pygame.event.set_blocked(event_types)
pygame.event.set_allowed(event_types)
for etype in event_types:
self.assertFalse(pygame.event.get_blocked(etype))
def test_set_allowed_all(self):
"""Ensure all events can be unblocked/allowed at once."""
pygame.event.set_blocked(None)
for e in EVENT_TYPES:
self.assertTrue(pygame.event.get_blocked(e))
pygame.event.set_allowed(None)
for e in EVENT_TYPES:
self.assertFalse(pygame.event.get_blocked(e))
def test_pump(self):
"""Ensure pump() functions properly."""
pygame.event.pump()
# @unittest.skipIf(
# os.environ.get("SDL_VIDEODRIVER") == "dummy",
# 'requires the SDL_VIDEODRIVER to be a non "dummy" value',
# )
# Fails on SDL 2.0.18
@unittest.skip("flaky test, and broken on 2.0.18 windows")
def test_set_grab__and_get_symmetric(self):
"""Ensure event grabbing can be enabled and disabled.
WARNING: Moving the mouse off the display during this test can cause it
to fail.
"""
surf = pygame.display.set_mode((10, 10))
pygame.event.set_grab(True)
self.assertTrue(pygame.event.get_grab())
pygame.event.set_grab(False)
self.assertFalse(pygame.event.get_grab())
def test_get_blocked(self):
"""Ensure an event's blocked state can be retrieved."""
# Test each event is not blocked.
pygame.event.set_allowed(None)
for etype in EVENT_TYPES:
blocked = pygame.event.get_blocked(etype)
self.assertFalse(blocked)
# Test each event type is blocked.
pygame.event.set_blocked(None)
for etype in EVENT_TYPES:
blocked = pygame.event.get_blocked(etype)
self.assertTrue(blocked)
def test_get_blocked__event_sequence(self):
"""Ensure get_blocked() can handle a sequence of event types."""
event_types = [
pygame.KEYDOWN,
pygame.KEYUP,
pygame.MOUSEMOTION,
pygame.MOUSEBUTTONDOWN,
pygame.MOUSEBUTTONUP,
pygame.WINDOWMINIMIZED,
pygame.USEREVENT,
]
# Test no event types in the list are blocked.
blocked = pygame.event.get_blocked(event_types)
self.assertFalse(blocked)
# Test when 1 event type in the list is blocked.
pygame.event.set_blocked(event_types[2])
blocked = pygame.event.get_blocked(event_types)
self.assertTrue(blocked)
# Test all event types in the list are blocked.
pygame.event.set_blocked(event_types)
blocked = pygame.event.get_blocked(event_types)
self.assertTrue(blocked)
# @unittest.skipIf(
# os.environ.get("SDL_VIDEODRIVER") == "dummy",
# 'requires the SDL_VIDEODRIVER to be a non "dummy" value',
# )
# Fails on SDL 2.0.18
@unittest.skip("flaky test, and broken on 2.0.18 windows")
def test_get_grab(self):
"""Ensure get_grab() works as expected"""
surf = pygame.display.set_mode((10, 10))
# Test 5 times
for i in range(5):
pygame.event.set_grab(i % 2)
self.assertEqual(pygame.event.get_grab(), i % 2)
@unittest.skipIf(
os.environ.get("SDL_VIDEODRIVER") == "dummy",
"requires the SDL_VIDEODRIVER to be a non dummy value",
)
@unittest.skipIf(pygame.get_sdl_version() < (2, 0, 16), "Needs at least SDL 2.0.16")
def test_set_keyboard_grab_and_get_keyboard_grab(self):
"""Ensure set_keyboard_grab() and get_keyboard_grab() work as expected"""
surf = pygame.display.set_mode((10, 10))
pygame.event.set_keyboard_grab(True)
self.assertTrue(pygame.event.get_keyboard_grab())
pygame.event.set_keyboard_grab(False)
self.assertFalse(pygame.event.get_keyboard_grab())
def test_poll(self):
"""Ensure poll() works as expected"""
pygame.event.clear()
ev = pygame.event.poll()
# poll() on empty queue should return NOEVENT
self.assertEqual(ev.type, pygame.NOEVENT)
# test poll returns stuff in same order
e1 = pygame.event.Event(pygame.USEREVENT)
e2 = pygame.event.Event(pygame.KEYDOWN, key=pygame.K_a)
e3 = pygame.event.Event(pygame.KEYUP, key=pygame.K_a)
pygame.event.post(e1)
pygame.event.post(e2)
pygame.event.post(e3)
self.assertEqual(pygame.event.poll().type, e1.type)
self.assertEqual(pygame.event.poll().type, e2.type)
self.assertEqual(pygame.event.poll().type, e3.type)
self.assertEqual(pygame.event.poll().type, pygame.NOEVENT)
class EventModuleTestsWithTiming(unittest.TestCase):
__tags__ = ["timing"]
def setUp(self):
pygame.display.init()
pygame.event.clear() # flush events
def tearDown(self):
pygame.event.clear() # flush events
pygame.display.quit()
def test_event_wait(self):
"""Ensure wait() waits for an event on the queue."""
# Test case without timeout.
event = pygame.event.Event(EVENT_TYPES[0], **EVENT_TEST_PARAMS[EVENT_TYPES[0]])
pygame.event.post(event)
wait_event = pygame.event.wait()
self.assertEqual(wait_event.type, event.type)
# Test case with timeout and no event in the queue.
wait_event = pygame.event.wait(100)
self.assertEqual(wait_event.type, pygame.NOEVENT)
# Test case with timeout and an event in the queue.
event = pygame.event.Event(EVENT_TYPES[0], **EVENT_TEST_PARAMS[EVENT_TYPES[0]])
pygame.event.post(event)
wait_event = pygame.event.wait(100)
self.assertEqual(wait_event.type, event.type)
# test wait with timeout waits for the correct duration
pygame.time.set_timer(pygame.USEREVENT, 50, 3)
for wait_time, expected_type, expected_time in (
(60, pygame.USEREVENT, 50),
(65, pygame.USEREVENT, 50),
(20, pygame.NOEVENT, 20),
(45, pygame.USEREVENT, 30),
(70, pygame.NOEVENT, 70),
):
start_time = time.perf_counter()
self.assertEqual(pygame.event.wait(wait_time).type, expected_type)
self.assertAlmostEqual(
time.perf_counter() - start_time, expected_time / 1000, delta=0.01
)
# test wait without timeout waits for the full duration
pygame.time.set_timer(pygame.USEREVENT, 100, 1)
start_time = time.perf_counter()
self.assertEqual(pygame.event.wait().type, pygame.USEREVENT)
self.assertAlmostEqual(time.perf_counter() - start_time, 0.1, delta=0.01)
# test wait returns no event if event is arriving later
pygame.time.set_timer(pygame.USEREVENT, 50, 1)
self.assertEqual(pygame.event.wait(40).type, pygame.NOEVENT)
################################################################################
if __name__ == "__main__":
unittest.main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 B

View File

@@ -0,0 +1,165 @@
STARTFONT 2.1
FONT -FontForge-PyGameMono-Medium-R-Normal--25-180-100-100-M-250-ISO10646-1
SIZE 18 100 100
FONTBOUNDINGBOX 21 22 0 0
COMMENT "Generated by fontforge, http://fontforge.sourceforge.net"
COMMENT "Created by Lenard Lindstrom,,, with FontForge 2.0 (http://fontforge.sf.net)"
STARTPROPERTIES 29
FOUNDRY "FontForge"
FAMILY_NAME "PyGameMono"
WEIGHT_NAME "Medium"
SLANT "R"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
PIXEL_SIZE 25
POINT_SIZE 180
RESOLUTION_X 100
RESOLUTION_Y 100
SPACING "M"
AVERAGE_WIDTH 250
CHARSET_REGISTRY "ISO10646"
CHARSET_ENCODING "1"
FONTNAME_REGISTRY ""
CHARSET_COLLECTIONS "ISO10646-1"
FONT_NAME "PyGameMono"
FACE_NAME "PyGame Mono"
FONT_VERSION "001.000"
FONT_ASCENT 20
FONT_DESCENT 5
UNDERLINE_POSITION -2
UNDERLINE_THICKNESS 2
RAW_ASCENT 800
RAW_DESCENT 200
RELATIVE_WEIGHT 50
RELATIVE_SETWIDTH 50
FIGURE_WIDTH -1
AVG_UPPERCASE_WIDTH 250
ENDPROPERTIES
CHARS 5
STARTCHAR .notdef
ENCODING 0
SWIDTH 1000 0
DWIDTH 25 0
BBX 20 20 0 0
BITMAP
FFFFF0
FFFFF0
FE07F0
F801F0
F000F0
E00070
E00070
C00030
C00030
C00030
C00030
C00030
C00030
E00070
E00070
F000F0
F801F0
FE07F0
FFFFF0
FFFFF0
ENDCHAR
STARTCHAR A
ENCODING 65
SWIDTH 1000 0
DWIDTH 25 0
BBX 20 21 0 1
BITMAP
03FC00
1FFF80
3FFFC0
7C03E0
F000F0
E00070
E00070
F000F0
FC03F0
FFFFF0
FFFFF0
FFFFF0
FF0FF0
7C03F0
7801E0
7800E0
7000E0
700060
600060
200040
200040
ENDCHAR
STARTCHAR B
ENCODING 66
SWIDTH 1000 0
DWIDTH 25 0
BBX 18 20 1 0
BITMAP
FFFE00
FFFF80
7E0780
7801C0
7000C0
3000C0
3000C0
3801C0
3E0780
3FFF00
3FFF00
3E0780
380180
3000C0
3000C0
3000C0
7801C0
7E07C0
FFFF80
FFFE00
ENDCHAR
STARTCHAR C
ENCODING 67
SWIDTH 1000 0
DWIDTH 25 0
BBX 20 20 0 0
BITMAP
00FC00
03FF00
0FFF80
1F03E0
3E0070
7C0010
780000
F80000
F00000
F00000
F00000
F00000
F80000
780000
7C0010
3E0070
1F01E0
0FFFC0
03FF80
00FE00
ENDCHAR
STARTCHAR u13079
ENCODING 77945
SWIDTH 1000 0
DWIDTH 25 0
BBX 21 10 0 5
BITMAP
03FC00
0FFF80
1E73C0
78F8F0
F0F878
70F870
3870E0
1E03C0
0FFF80
03FC00
ENDCHAR
ENDFONT

View File

@@ -0,0 +1,143 @@
STARTFONT 2.1
FONT -FontForge-PyGameMono-Medium-R-Normal--19-180-75-75-M-190-ISO10646-1
SIZE 18 75 75
FONTBOUNDINGBOX 15 17 0 0
COMMENT "Generated by fontforge, http://fontforge.sourceforge.net"
COMMENT "Created by Lenard Lindstrom,,, with FontForge 2.0 (http://fontforge.sf.net)"
STARTPROPERTIES 29
FOUNDRY "FontForge"
FAMILY_NAME "PyGameMono"
WEIGHT_NAME "Medium"
SLANT "R"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
PIXEL_SIZE 19
POINT_SIZE 180
RESOLUTION_X 75
RESOLUTION_Y 75
SPACING "M"
AVERAGE_WIDTH 190
CHARSET_REGISTRY "ISO10646"
CHARSET_ENCODING "1"
FONTNAME_REGISTRY ""
CHARSET_COLLECTIONS "ISO10646-1"
FONT_NAME "PyGameMono"
FACE_NAME "PyGame Mono"
FONT_VERSION "001.000"
FONT_ASCENT 15
FONT_DESCENT 4
UNDERLINE_POSITION -2
UNDERLINE_THICKNESS 1
RAW_ASCENT 800
RAW_DESCENT 200
RELATIVE_WEIGHT 50
RELATIVE_SETWIDTH 50
FIGURE_WIDTH -1
AVG_UPPERCASE_WIDTH 190
ENDPROPERTIES
CHARS 5
STARTCHAR .notdef
ENCODING 0
SWIDTH 1000 0
DWIDTH 19 0
BBX 15 15 0 0
BITMAP
FFFE
FFFE
FC7E
F01E
E00E
C006
C006
C006
C006
C006
E00E
F01E
FC7E
FFFE
FFFE
ENDCHAR
STARTCHAR A
ENCODING 65
SWIDTH 1000 0
DWIDTH 19 0
BBX 15 17 0 0
BITMAP
0FE0
3FF8
783C
F01E
E00E
E00E
F01E
F83E
FFFE
FFFE
FC7E
701C
701C
600C
600C
4004
4004
ENDCHAR
STARTCHAR B
ENCODING 66
SWIDTH 1000 0
DWIDTH 19 0
BBX 15 15 0 0
BITMAP
FFF8
7FFC
780E
3006
3006
380E
3FF8
3FF8
3FF8
380E
3006
3006
7C1E
7FFC
FFF8
ENDCHAR
STARTCHAR C
ENCODING 67
SWIDTH 1000 0
DWIDTH 19 0
BBX 15 15 0 0
BITMAP
03E0
0FF8
3C1C
7806
7000
E000
E000
E000
E000
E000
7000
7806
3C1C
0FF8
03E0
ENDCHAR
STARTCHAR u13079
ENCODING 77945
SWIDTH 1000 0
DWIDTH 19 0
BBX 15 7 0 4
BITMAP
0FE0
3838
638C
E38E
638C
3838
0FE0
ENDCHAR
ENDFONT

View File

@@ -0,0 +1,103 @@
STARTFONT 2.1
FONT -FontForge-PyGameMono-Medium-R-Normal--8-80-75-75-C-80-ISO10646-1
SIZE 8 75 75
FONTBOUNDINGBOX 6 7 0 0
COMMENT "Generated by fontforge, http://fontforge.sourceforge.net"
COMMENT "Created by Lenard Lindstrom,,, with FontForge 2.0 (http://fontforge.sf.net)"
STARTPROPERTIES 29
FOUNDRY "FontForge"
FAMILY_NAME "PyGameMono"
WEIGHT_NAME "Medium"
SLANT "R"
SETWIDTH_NAME "Normal"
ADD_STYLE_NAME ""
PIXEL_SIZE 8
POINT_SIZE 80
RESOLUTION_X 75
RESOLUTION_Y 75
SPACING "C"
AVERAGE_WIDTH 80
CHARSET_REGISTRY "ISO10646"
CHARSET_ENCODING "1"
FONTNAME_REGISTRY ""
CHARSET_COLLECTIONS "ISO10646-1"
FONT_NAME "PyGameMono"
FACE_NAME "PyGame Mono"
FONT_VERSION "001.000"
FONT_ASCENT 6
FONT_DESCENT 2
UNDERLINE_POSITION -1
UNDERLINE_THICKNESS 1
RAW_ASCENT 800
RAW_DESCENT 200
RELATIVE_WEIGHT 50
RELATIVE_SETWIDTH 50
FIGURE_WIDTH -1
AVG_UPPERCASE_WIDTH 80
ENDPROPERTIES
CHARS 5
STARTCHAR .notdef
ENCODING 0
SWIDTH 1000 0
DWIDTH 8 0
BBX 6 6 0 0
BITMAP
FC
84
84
84
84
FC
ENDCHAR
STARTCHAR A
ENCODING 65
SWIDTH 1000 0
DWIDTH 8 0
BBX 6 7 0 0
BITMAP
78
84
84
FC
84
84
84
ENDCHAR
STARTCHAR B
ENCODING 66
SWIDTH 1000 0
DWIDTH 8 0
BBX 6 6 0 0
BITMAP
FC
44
78
4C
44
FC
ENDCHAR
STARTCHAR C
ENCODING 67
SWIDTH 1000 0
DWIDTH 8 0
BBX 6 6 0 0
BITMAP
78
C4
C0
C0
C4
78
ENDCHAR
STARTCHAR u13079
ENCODING 77945
SWIDTH 1000 0
DWIDTH 8 0
BBX 6 4 0 1
BITMAP
78
B4
B4
78
ENDCHAR
ENDFONT

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 B

View File

@@ -0,0 +1,8 @@
#define resize_white_width 16
#define resize_white_height 16
#define resize_white_x_hot 7
#define resize_white_y_hot 7
static unsigned char resize_white_bits[] = {
0xff, 0x03, 0x01, 0x02, 0xfd, 0x03, 0x05, 0x00, 0xf5, 0x0f, 0x15, 0x08,
0xd5, 0xeb, 0x55, 0xaa, 0x55, 0xaa, 0xd7, 0xab, 0x10, 0xa8, 0xf0, 0xb7,
0x00, 0xa8, 0xc0, 0x9f, 0x40, 0x80, 0xc0, 0xff};

View File

@@ -0,0 +1,8 @@
#define resize_white_mask_width 16
#define resize_white_mask_height 16
#define resize_white_mask_x_hot 7
#define resize_white_mask_y_hot 7
static unsigned char resize_white_mask_bits[] = {
0xff, 0x03, 0xff, 0x03, 0xff, 0x03, 0x07, 0x00, 0xf7, 0x0f, 0xf7, 0x0f,
0xf7, 0xef, 0x77, 0xee, 0x77, 0xee, 0xf7, 0xef, 0xf0, 0xef, 0xf0, 0xff,
0x00, 0xf8, 0xc0, 0xff, 0xc0, 0xff, 0xc0, 0xff};

View File

@@ -0,0 +1,749 @@
# -*- coding: utf-8 -*-
from re import T
import sys
import os
import unittest
import pathlib
import platform
import pygame
from pygame import font as pygame_font # So font can be replaced with ftfont
FONTDIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "fixtures", "fonts")
def equal_images(s1, s2):
size = s1.get_size()
if s2.get_size() != size:
return False
w, h = size
for x in range(w):
for y in range(h):
if s1.get_at((x, y)) != s2.get_at((x, y)):
return False
return True
IS_PYPY = "PyPy" == platform.python_implementation()
@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO
class FontModuleTest(unittest.TestCase):
def setUp(self):
pygame_font.init()
def tearDown(self):
pygame_font.quit()
def test_get_sdl_ttf_version(self):
def test_ver_tuple(ver):
self.assertIsInstance(ver, tuple)
self.assertEqual(len(ver), 3)
for i in ver:
self.assertIsInstance(i, int)
if pygame_font.__name__ != "pygame.ftfont":
compiled = pygame_font.get_sdl_ttf_version()
linked = pygame_font.get_sdl_ttf_version(linked=True)
test_ver_tuple(compiled)
test_ver_tuple(linked)
self.assertTrue(linked >= compiled)
def test_SysFont(self):
# Can only check that a font object is returned.
fonts = pygame_font.get_fonts()
if "arial" in fonts:
# Try to use arial font if it is there, rather than a random font
# which can be different depending on installed fonts on the system.
font_name = "arial"
else:
font_name = sorted(fonts)[0]
o = pygame_font.SysFont(font_name, 20)
self.assertTrue(isinstance(o, pygame_font.FontType))
o = pygame_font.SysFont(font_name, 20, italic=True)
self.assertTrue(isinstance(o, pygame_font.FontType))
o = pygame_font.SysFont(font_name, 20, bold=True)
self.assertTrue(isinstance(o, pygame_font.FontType))
o = pygame_font.SysFont("thisisnotafont", 20)
self.assertTrue(isinstance(o, pygame_font.FontType))
def test_get_default_font(self):
self.assertEqual(pygame_font.get_default_font(), "freesansbold.ttf")
def test_get_fonts_returns_something(self):
fnts = pygame_font.get_fonts()
self.assertTrue(fnts)
# to test if some files exist...
# def XXtest_has_file_osx_10_5_sdk(self):
# import os
# f = "/Developer/SDKs/MacOSX10.5.sdk/usr/X11/include/ft2build.h"
# self.assertEqual(os.path.exists(f), True)
# def XXtest_has_file_osx_10_4_sdk(self):
# import os
# f = "/Developer/SDKs/MacOSX10.4u.sdk/usr/X11R6/include/ft2build.h"
# self.assertEqual(os.path.exists(f), True)
def test_get_fonts(self):
fnts = pygame_font.get_fonts()
self.assertTrue(fnts, msg=repr(fnts))
for name in fnts:
# note, on ubuntu 2.6 they are all unicode strings.
self.assertTrue(isinstance(name, str), name)
# Font names can be comprised of only numeric characters, so
# just checking name.islower() will not work as expected here.
self.assertFalse(any(c.isupper() for c in name))
self.assertTrue(name.isalnum(), name)
def test_get_init(self):
self.assertTrue(pygame_font.get_init())
pygame_font.quit()
self.assertFalse(pygame_font.get_init())
def test_init(self):
pygame_font.init()
def test_match_font_all_exist(self):
fonts = pygame_font.get_fonts()
# Ensure all listed fonts are in fact available, and the returned file
# name is a full path.
for font in fonts:
path = pygame_font.match_font(font)
self.assertFalse(path is None)
self.assertTrue(os.path.isabs(path) and os.path.isfile(path))
def test_match_font_name(self):
"""That match_font accepts names of various types"""
font = pygame_font.get_fonts()[0]
font_path = pygame_font.match_font(font)
self.assertIsNotNone(font_path)
font_b = font.encode()
not_a_font = "thisisnotafont"
not_a_font_b = b"thisisnotafont"
good_font_names = [
# Check single name bytes.
font_b,
# Check string of comma-separated names.
",".join([not_a_font, font, not_a_font]),
# Check list of names.
[not_a_font, font, not_a_font],
# Check generator:
(name for name in [not_a_font, font, not_a_font]),
# Check comma-separated bytes.
b",".join([not_a_font_b, font_b, not_a_font_b]),
# Check list of bytes.
[not_a_font_b, font_b, not_a_font_b],
# Check mixed list of bytes and string.
[font, not_a_font, font_b, not_a_font_b],
]
for font_name in good_font_names:
self.assertEqual(pygame_font.match_font(font_name), font_path, font_name)
def test_not_match_font_name(self):
"""match_font return None when names of various types do not exist"""
not_a_font = "thisisnotafont"
not_a_font_b = b"thisisnotafont"
bad_font_names = [
not_a_font,
",".join([not_a_font, not_a_font, not_a_font]),
[not_a_font, not_a_font, not_a_font],
(name for name in [not_a_font, not_a_font, not_a_font]),
not_a_font_b,
b",".join([not_a_font_b, not_a_font_b, not_a_font_b]),
[not_a_font_b, not_a_font_b, not_a_font_b],
[not_a_font, not_a_font_b, not_a_font],
]
for font_name in bad_font_names:
self.assertIsNone(pygame_font.match_font(font_name), font_name)
def test_match_font_bold(self):
fonts = pygame_font.get_fonts()
# Look for a bold font.
self.assertTrue(any(pygame_font.match_font(font, bold=True) for font in fonts))
def test_match_font_italic(self):
fonts = pygame_font.get_fonts()
# Look for an italic font.
self.assertTrue(
any(pygame_font.match_font(font, italic=True) for font in fonts)
)
def test_issue_742(self):
"""that the font background does not crash."""
surf = pygame.Surface((320, 240))
font = pygame_font.Font(None, 24)
image = font.render("Test", 0, (255, 255, 255), (0, 0, 0))
self.assertIsNone(image.get_colorkey())
image.set_alpha(255)
surf.blit(image, (0, 0))
# not issue 742, but be sure to test that background color is
# correctly issued on this mode
self.assertEqual(surf.get_at((0, 0)), pygame.Color(0, 0, 0))
def test_issue_font_alphablit(self):
"""Check that blitting anti-aliased text doesn't
change the background blue"""
pygame.display.set_mode((600, 400))
font = pygame_font.Font(None, 24)
(color, text, center, pos) = ((160, 200, 250), "Music", (190, 170), "midright")
img1 = font.render(text, True, color)
img = pygame.Surface(img1.get_size(), depth=32)
pre_blit_corner_pixel = img.get_at((0, 0))
img.blit(img1, (0, 0))
post_blit_corner_pixel = img.get_at((0, 0))
self.assertEqual(pre_blit_corner_pixel, post_blit_corner_pixel)
def test_segfault_after_reinit(self):
"""Reinitialization of font module should not cause
segmentation fault"""
import gc
font = pygame_font.Font(None, 20)
pygame_font.quit()
pygame_font.init()
del font
gc.collect()
def test_quit(self):
pygame_font.quit()
@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO
class FontTest(unittest.TestCase):
def setUp(self):
pygame_font.init()
def tearDown(self):
pygame_font.quit()
def test_render_args(self):
screen = pygame.display.set_mode((600, 400))
rect = screen.get_rect()
f = pygame_font.Font(None, 20)
screen.fill((10, 10, 10))
font_surface = f.render(" bar", True, (0, 0, 0), (255, 255, 255))
font_rect = font_surface.get_rect()
font_rect.topleft = rect.topleft
self.assertTrue(font_surface)
screen.blit(font_surface, font_rect, font_rect)
pygame.display.update()
self.assertEqual(tuple(screen.get_at((0, 0)))[:3], (255, 255, 255))
self.assertEqual(tuple(screen.get_at(font_rect.topleft))[:3], (255, 255, 255))
# If we don't have a real display, don't do this test.
# Transparent background doesn't seem to work without a read video card.
if os.environ.get("SDL_VIDEODRIVER") != "dummy":
screen.fill((10, 10, 10))
font_surface = f.render(" bar", True, (0, 0, 0), None)
font_rect = font_surface.get_rect()
font_rect.topleft = rect.topleft
self.assertTrue(font_surface)
screen.blit(font_surface, font_rect, font_rect)
pygame.display.update()
self.assertEqual(tuple(screen.get_at((0, 0)))[:3], (10, 10, 10))
self.assertEqual(tuple(screen.get_at(font_rect.topleft))[:3], (10, 10, 10))
screen.fill((10, 10, 10))
font_surface = f.render(" bar", True, (0, 0, 0))
font_rect = font_surface.get_rect()
font_rect.topleft = rect.topleft
self.assertTrue(font_surface)
screen.blit(font_surface, font_rect, font_rect)
pygame.display.update(rect)
self.assertEqual(tuple(screen.get_at((0, 0)))[:3], (10, 10, 10))
self.assertEqual(tuple(screen.get_at(font_rect.topleft))[:3], (10, 10, 10))
@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO
class FontTypeTest(unittest.TestCase):
def setUp(self):
pygame_font.init()
def tearDown(self):
pygame_font.quit()
def test_default_parameters(self):
f = pygame_font.Font()
def test_get_ascent(self):
# Ckecking ascent would need a custom test font to do properly.
f = pygame_font.Font(None, 20)
ascent = f.get_ascent()
self.assertTrue(isinstance(ascent, int))
self.assertTrue(ascent > 0)
s = f.render("X", False, (255, 255, 255))
self.assertTrue(s.get_size()[1] > ascent)
def test_get_descent(self):
# Ckecking descent would need a custom test font to do properly.
f = pygame_font.Font(None, 20)
descent = f.get_descent()
self.assertTrue(isinstance(descent, int))
self.assertTrue(descent < 0)
def test_get_height(self):
# Ckecking height would need a custom test font to do properly.
f = pygame_font.Font(None, 20)
height = f.get_height()
self.assertTrue(isinstance(height, int))
self.assertTrue(height > 0)
s = f.render("X", False, (255, 255, 255))
self.assertTrue(s.get_size()[1] == height)
def test_get_linesize(self):
# Ckecking linesize would need a custom test font to do properly.
# Questions: How do linesize, height and descent relate?
f = pygame_font.Font(None, 20)
linesize = f.get_linesize()
self.assertTrue(isinstance(linesize, int))
self.assertTrue(linesize > 0)
def test_metrics(self):
# Ensure bytes decoding works correctly. Can only compare results
# with unicode for now.
f = pygame_font.Font(None, 20)
um = f.metrics(".")
bm = f.metrics(b".")
self.assertEqual(len(um), 1)
self.assertEqual(len(bm), 1)
self.assertIsNotNone(um[0])
self.assertEqual(um, bm)
u = "\u212A"
b = u.encode("UTF-16")[2:] # Keep byte order consistent. [2:] skips BOM
bm = f.metrics(b)
self.assertEqual(len(bm), 2)
try: # FIXME why do we do this try/except ?
um = f.metrics(u)
except pygame.error:
pass
else:
self.assertEqual(len(um), 1)
self.assertNotEqual(bm[0], um[0])
self.assertNotEqual(bm[1], um[0])
u = "\U00013000"
bm = f.metrics(u)
self.assertEqual(len(bm), 1)
self.assertIsNone(bm[0])
return # unfinished
# The documentation is useless here. How large a list?
# How do list positions relate to character codes?
# What about unicode characters?
# __doc__ (as of 2008-08-02) for pygame_font.Font.metrics:
# Font.metrics(text): return list
# Gets the metrics for each character in the passed string.
#
# The list contains tuples for each character, which contain the
# minimum X offset, the maximum X offset, the minimum Y offset, the
# maximum Y offset and the advance offset (bearing plus width) of the
# character. [(minx, maxx, miny, maxy, advance), (minx, maxx, miny,
# maxy, advance), ...]
self.fail()
def test_render(self):
f = pygame_font.Font(None, 20)
s = f.render("foo", True, [0, 0, 0], [255, 255, 255])
s = f.render("xxx", True, [0, 0, 0], [255, 255, 255])
s = f.render("", True, [0, 0, 0], [255, 255, 255])
s = f.render("foo", False, [0, 0, 0], [255, 255, 255])
s = f.render("xxx", False, [0, 0, 0], [255, 255, 255])
s = f.render("xxx", False, [0, 0, 0])
s = f.render(" ", False, [0, 0, 0])
s = f.render(" ", False, [0, 0, 0], [255, 255, 255])
# null text should be 0 pixel wide.
s = f.render("", False, [0, 0, 0], [255, 255, 255])
self.assertEqual(s.get_size()[0], 0)
# None text should be 0 pixel wide.
s = f.render(None, False, [0, 0, 0], [255, 255, 255])
self.assertEqual(s.get_size()[0], 0)
# Non-text should raise a TypeError.
self.assertRaises(TypeError, f.render, [], False, [0, 0, 0], [255, 255, 255])
self.assertRaises(TypeError, f.render, 1, False, [0, 0, 0], [255, 255, 255])
# is background transparent for antialiasing?
s = f.render(".", True, [255, 255, 255])
self.assertEqual(s.get_at((0, 0))[3], 0)
# is Unicode and bytes encoding correct?
# Cannot really test if the correct characters are rendered, but
# at least can assert the encodings differ.
su = f.render(".", False, [0, 0, 0], [255, 255, 255])
sb = f.render(b".", False, [0, 0, 0], [255, 255, 255])
self.assertTrue(equal_images(su, sb))
u = "\u212A"
b = u.encode("UTF-16")[2:] # Keep byte order consistent. [2:] skips BOM
sb = f.render(b, False, [0, 0, 0], [255, 255, 255])
try: # FIXME why do we do this try/except ?
su = f.render(u, False, [0, 0, 0], [255, 255, 255])
except pygame.error:
pass
else:
self.assertFalse(equal_images(su, sb))
# test for internal null bytes
self.assertRaises(ValueError, f.render, b"ab\x00cd", 0, [0, 0, 0])
self.assertRaises(ValueError, f.render, "ab\x00cd", 0, [0, 0, 0])
def test_render_ucs2_ucs4(self):
"""that it renders without raising if there is a new enough SDL_ttf."""
f = pygame_font.Font(None, 20)
# If the font module is SDL_ttf < 2.0.15 based, then it only supports UCS-2
# it will raise an exception for an out-of-range UCS-4 code point.
if hasattr(pygame_font, "UCS4"):
ucs_2 = "\uFFEE"
s = f.render(ucs_2, False, [0, 0, 0], [255, 255, 255])
ucs_4 = "\U00010000"
s = f.render(ucs_4, False, [0, 0, 0], [255, 255, 255])
def test_set_bold(self):
f = pygame_font.Font(None, 20)
self.assertFalse(f.get_bold())
f.set_bold(True)
self.assertTrue(f.get_bold())
f.set_bold(False)
self.assertFalse(f.get_bold())
def test_set_italic(self):
f = pygame_font.Font(None, 20)
self.assertFalse(f.get_italic())
f.set_italic(True)
self.assertTrue(f.get_italic())
f.set_italic(False)
self.assertFalse(f.get_italic())
def test_set_underline(self):
f = pygame_font.Font(None, 20)
self.assertFalse(f.get_underline())
f.set_underline(True)
self.assertTrue(f.get_underline())
f.set_underline(False)
self.assertFalse(f.get_underline())
def test_set_strikethrough(self):
if pygame_font.__name__ != "pygame.ftfont":
f = pygame_font.Font(None, 20)
self.assertFalse(f.get_strikethrough())
f.set_strikethrough(True)
self.assertTrue(f.get_strikethrough())
f.set_strikethrough(False)
self.assertFalse(f.get_strikethrough())
def test_bold_attr(self):
f = pygame_font.Font(None, 20)
self.assertFalse(f.bold)
f.bold = True
self.assertTrue(f.bold)
f.bold = False
self.assertFalse(f.bold)
def test_set_italic_property(self):
f = pygame_font.Font(None, 20)
self.assertFalse(f.italic)
f.italic = True
self.assertTrue(f.italic)
f.italic = False
self.assertFalse(f.italic)
def test_set_underline_property(self):
f = pygame_font.Font(None, 20)
self.assertFalse(f.underline)
f.underline = True
self.assertTrue(f.underline)
f.underline = False
self.assertFalse(f.underline)
def test_set_strikethrough_property(self):
if pygame_font.__name__ != "pygame.ftfont":
f = pygame_font.Font(None, 20)
self.assertFalse(f.strikethrough)
f.strikethrough = True
self.assertTrue(f.strikethrough)
f.strikethrough = False
self.assertFalse(f.strikethrough)
def test_size(self):
f = pygame_font.Font(None, 20)
text = "Xg"
size = f.size(text)
w, h = size
s = f.render(text, False, (255, 255, 255))
btext = text.encode("ascii")
self.assertIsInstance(w, int)
self.assertIsInstance(h, int)
self.assertEqual(s.get_size(), size)
self.assertEqual(f.size(btext), size)
text = "\u212A"
btext = text.encode("UTF-16")[2:] # Keep the byte order consistent.
bsize = f.size(btext)
size = f.size(text)
self.assertNotEqual(size, bsize)
def test_font_file_not_found(self):
# A per BUG reported by Bo Jangeborg on pygame-user mailing list,
# http://www.mail-archive.com/pygame-users@seul.org/msg11675.html
pygame_font.init()
self.assertRaises(
FileNotFoundError, pygame_font.Font, "some-fictional-font.ttf", 20
)
def test_load_from_file(self):
font_name = pygame_font.get_default_font()
font_path = os.path.join(
os.path.split(pygame.__file__)[0], pygame_font.get_default_font()
)
f = pygame_font.Font(font_path, 20)
def test_load_from_file_default(self):
font_name = pygame_font.get_default_font()
font_path = os.path.join(
os.path.split(pygame.__file__)[0], pygame_font.get_default_font()
)
f = pygame_font.Font(font_path)
def test_load_from_pathlib(self):
font_name = pygame_font.get_default_font()
font_path = os.path.join(
os.path.split(pygame.__file__)[0], pygame_font.get_default_font()
)
f = pygame_font.Font(pathlib.Path(font_path), 20)
f = pygame_font.Font(pathlib.Path(font_path))
def test_load_from_pathlib_default(self):
font_name = pygame_font.get_default_font()
font_path = os.path.join(
os.path.split(pygame.__file__)[0], pygame_font.get_default_font()
)
f = pygame_font.Font(pathlib.Path(font_path))
def test_load_from_file_obj(self):
font_name = pygame_font.get_default_font()
font_path = os.path.join(
os.path.split(pygame.__file__)[0], pygame_font.get_default_font()
)
with open(font_path, "rb") as f:
font = pygame_font.Font(f, 20)
def test_load_from_file_obj_default(self):
font_name = pygame_font.get_default_font()
font_path = os.path.join(
os.path.split(pygame.__file__)[0], pygame_font.get_default_font()
)
with open(font_path, "rb") as f:
font = pygame_font.Font(f)
def test_load_default_font_filename(self):
# In font_init, a special case is when the filename argument is
# identical to the default font file name.
f = pygame_font.Font(pygame_font.get_default_font(), 20)
def test_load_default_font_filename_default(self):
# In font_init, a special case is when the filename argument is
# identical to the default font file name.
f = pygame_font.Font(pygame_font.get_default_font())
def _load_unicode(self, path):
import shutil
fdir = str(FONTDIR)
temp = os.path.join(fdir, path)
pgfont = os.path.join(fdir, "test_sans.ttf")
shutil.copy(pgfont, temp)
try:
with open(temp, "rb") as f:
pass
except FileNotFoundError:
raise unittest.SkipTest("the path cannot be opened")
try:
pygame_font.Font(temp, 20)
finally:
os.remove(temp)
def test_load_from_file_unicode_0(self):
"""ASCII string as a unicode object"""
self._load_unicode("temp_file.ttf")
def test_load_from_file_unicode_1(self):
self._load_unicode("你好.ttf")
def test_load_from_file_bytes(self):
font_path = os.path.join(
os.path.split(pygame.__file__)[0], pygame_font.get_default_font()
)
filesystem_encoding = sys.getfilesystemencoding()
filesystem_errors = "replace" if sys.platform == "win32" else "surrogateescape"
try: # FIXME why do we do this try/except ?
font_path = font_path.decode(filesystem_encoding, filesystem_errors)
except AttributeError:
pass
bfont_path = font_path.encode(filesystem_encoding, filesystem_errors)
f = pygame_font.Font(bfont_path, 20)
def test_issue_3144(self):
fpath = os.path.join(FONTDIR, "PlayfairDisplaySemibold.ttf")
# issue in SDL_ttf 2.0.18 DLL on Windows
# tested to make us aware of any regressions
for size in (60, 40, 10, 20, 70, 45, 50, 10):
font = pygame_font.Font(fpath, size)
font.render("WHERE", True, "black")
def test_font_set_script(self):
if pygame_font.__name__ == "pygame.ftfont":
return # this ain't a pygame.ftfont thing!
font = pygame_font.Font(None, 16)
ttf_version = pygame_font.get_sdl_ttf_version()
if ttf_version >= (2, 20, 0):
self.assertRaises(TypeError, pygame.font.Font.set_script)
self.assertRaises(TypeError, pygame.font.Font.set_script, font)
self.assertRaises(TypeError, pygame.font.Font.set_script, "hey", "Deva")
self.assertRaises(TypeError, font.set_script, 1)
self.assertRaises(TypeError, font.set_script, ["D", "e", "v", "a"])
self.assertRaises(ValueError, font.set_script, "too long by far")
self.assertRaises(ValueError, font.set_script, "")
self.assertRaises(ValueError, font.set_script, "a")
font.set_script("Deva")
else:
self.assertRaises(pygame.error, font.set_script, "Deva")
@unittest.skipIf(IS_PYPY, "pypy skip known failure") # TODO
class VisualTests(unittest.TestCase):
__tags__ = ["interactive"]
screen = None
aborted = False
def setUp(self):
if self.screen is None:
pygame.init()
self.screen = pygame.display.set_mode((600, 200))
self.screen.fill((255, 255, 255))
pygame.display.flip()
self.f = pygame_font.Font(None, 32)
def abort(self):
if self.screen is not None:
pygame.quit()
self.aborted = True
def query(
self,
bold=False,
italic=False,
underline=False,
strikethrough=False,
antialiase=False,
):
if self.aborted:
return False
spacing = 10
offset = 20
y = spacing
f = self.f
screen = self.screen
screen.fill((255, 255, 255))
pygame.display.flip()
if not (bold or italic or underline or strikethrough or antialiase):
text = "normal"
else:
modes = []
if bold:
modes.append("bold")
if italic:
modes.append("italic")
if underline:
modes.append("underlined")
if strikethrough:
modes.append("strikethrough")
if antialiase:
modes.append("antialiased")
text = f"{'-'.join(modes)} (y/n):"
f.set_bold(bold)
f.set_italic(italic)
f.set_underline(underline)
if pygame_font.__name__ != "pygame.ftfont":
f.set_strikethrough(strikethrough)
s = f.render(text, antialiase, (0, 0, 0))
screen.blit(s, (offset, y))
y += s.get_size()[1] + spacing
f.set_bold(False)
f.set_italic(False)
f.set_underline(False)
if pygame_font.__name__ != "pygame.ftfont":
f.set_strikethrough(False)
s = f.render("(some comparison text)", False, (0, 0, 0))
screen.blit(s, (offset, y))
pygame.display.flip()
while True:
for evt in pygame.event.get():
if evt.type == pygame.KEYDOWN:
if evt.key == pygame.K_ESCAPE:
self.abort()
return False
if evt.key == pygame.K_y:
return True
if evt.key == pygame.K_n:
return False
if evt.type == pygame.QUIT:
self.abort()
return False
def test_bold(self):
self.assertTrue(self.query(bold=True))
def test_italic(self):
self.assertTrue(self.query(italic=True))
def test_underline(self):
self.assertTrue(self.query(underline=True))
def test_strikethrough(self):
if pygame_font.__name__ != "pygame.ftfont":
self.assertTrue(self.query(strikethrough=True))
def test_antialiase(self):
self.assertTrue(self.query(antialiase=True))
def test_bold_antialiase(self):
self.assertTrue(self.query(bold=True, antialiase=True))
def test_italic_underline(self):
self.assertTrue(self.query(italic=True, underline=True))
def test_bold_strikethrough(self):
if pygame_font.__name__ != "pygame.ftfont":
self.assertTrue(self.query(bold=True, strikethrough=True))
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,11 @@
__tags__ = ["development"]
exclude = False
try:
import pygame.freetype
except ImportError:
exclude = True
if exclude:
__tags__.extend(["ignore", "subprocess_ignore"])

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,11 @@
__tags__ = ["development"]
exclude = False
try:
import pygame.ftfont
except ImportError:
exclude = True
if exclude:
__tags__.extend(["ignore", "subprocess_ignore"])

View File

@@ -0,0 +1,17 @@
import sys
import os
import unittest
from pygame.tests import font_test
import pygame.ftfont
font_test.pygame_font = pygame.ftfont
for name in dir(font_test):
obj = getattr(font_test, name)
if isinstance(obj, type) and issubclass(obj, unittest.TestCase): # conditional and
new_name = f"Ft{name}"
globals()[new_name] = type(new_name, (obj,), {})
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,876 @@
import unittest
import pygame
import pygame.gfxdraw
from pygame.locals import *
from pygame.tests.test_utils import SurfaceSubclass
def intensity(c, i):
"""Return color c changed by intensity i
For 0 <= i <= 127 the color is a shade, with 0 being black, 127 being the
unaltered color.
For 128 <= i <= 255 the color is a tint, with 255 being white, 128 the
unaltered color.
"""
r, g, b = c[0:3]
if 0 <= i <= 127:
# Darken
return ((r * i) // 127, (g * i) // 127, (b * i) // 127)
# Lighten
return (
r + ((255 - r) * (255 - i)) // 127,
g + ((255 - g) * (255 - i)) // 127,
b + ((255 - b) * (255 - i)) // 127,
)
class GfxdrawDefaultTest(unittest.TestCase):
is_started = False
foreground_color = (128, 64, 8)
background_color = (255, 255, 255)
def make_palette(base_color):
"""Return color palette that is various intensities of base_color"""
# Need this function for Python 3.x so the base_color
# is within the scope of the list comprehension.
return [intensity(base_color, i) for i in range(0, 256)]
default_palette = make_palette(foreground_color)
default_size = (100, 100)
def check_at(self, surf, posn, color):
sc = surf.get_at(posn)
fail_msg = "%s != %s at %s, bitsize: %i, flags: %i, masks: %s" % (
sc,
color,
posn,
surf.get_bitsize(),
surf.get_flags(),
surf.get_masks(),
)
self.assertEqual(sc, color, fail_msg)
def check_not_at(self, surf, posn, color):
sc = surf.get_at(posn)
fail_msg = "%s != %s at %s, bitsize: %i, flags: %i, masks: %s" % (
sc,
color,
posn,
surf.get_bitsize(),
surf.get_flags(),
surf.get_masks(),
)
self.assertNotEqual(sc, color, fail_msg)
@classmethod
def setUpClass(cls):
# Necessary for Surface.set_palette.
pygame.init()
pygame.display.set_mode((1, 1))
@classmethod
def tearDownClass(cls):
pygame.quit()
def setUp(self):
# This makes sure pygame is always initialized before each test (in
# case a test calls pygame.quit()).
if not pygame.get_init():
pygame.init()
Surface = pygame.Surface
size = self.default_size
palette = self.default_palette
if not self.is_started:
# Create test surfaces
self.surfaces = [
Surface(size, 0, 8),
Surface(size, SRCALPHA, 16),
Surface(size, SRCALPHA, 32),
]
self.surfaces[0].set_palette(palette)
nonpalette_fmts = (
# (8, (0xe0, 0x1c, 0x3, 0x0)),
(12, (0xF00, 0xF0, 0xF, 0x0)),
(15, (0x7C00, 0x3E0, 0x1F, 0x0)),
(15, (0x1F, 0x3E0, 0x7C00, 0x0)),
(16, (0xF00, 0xF0, 0xF, 0xF000)),
(16, (0xF000, 0xF00, 0xF0, 0xF)),
(16, (0xF, 0xF0, 0xF00, 0xF000)),
(16, (0xF0, 0xF00, 0xF000, 0xF)),
(16, (0x7C00, 0x3E0, 0x1F, 0x8000)),
(16, (0xF800, 0x7C0, 0x3E, 0x1)),
(16, (0x1F, 0x3E0, 0x7C00, 0x8000)),
(16, (0x3E, 0x7C0, 0xF800, 0x1)),
(16, (0xF800, 0x7E0, 0x1F, 0x0)),
(16, (0x1F, 0x7E0, 0xF800, 0x0)),
(24, (0xFF, 0xFF00, 0xFF0000, 0x0)),
(24, (0xFF0000, 0xFF00, 0xFF, 0x0)),
(32, (0xFF0000, 0xFF00, 0xFF, 0x0)),
(32, (0xFF000000, 0xFF0000, 0xFF00, 0x0)),
(32, (0xFF, 0xFF00, 0xFF0000, 0x0)),
(32, (0xFF00, 0xFF0000, 0xFF000000, 0x0)),
(32, (0xFF0000, 0xFF00, 0xFF, 0xFF000000)),
(32, (0xFF000000, 0xFF0000, 0xFF00, 0xFF)),
(32, (0xFF, 0xFF00, 0xFF0000, 0xFF000000)),
(32, (0xFF00, 0xFF0000, 0xFF000000, 0xFF)),
)
for bitsize, masks in nonpalette_fmts:
self.surfaces.append(Surface(size, 0, bitsize, masks))
for surf in self.surfaces:
surf.fill(self.background_color)
def test_gfxdraw__subclassed_surface(self):
"""Ensure pygame.gfxdraw works on subclassed surfaces."""
surface = SurfaceSubclass((11, 13), SRCALPHA, 32)
surface.fill(pygame.Color("blue"))
expected_color = pygame.Color("red")
x, y = 1, 2
pygame.gfxdraw.pixel(surface, x, y, expected_color)
self.assertEqual(surface.get_at((x, y)), expected_color)
def test_pixel(self):
"""pixel(surface, x, y, color): return None"""
fg = self.foreground_color
bg = self.background_color
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.pixel(surf, 2, 2, fg)
for x in range(1, 4):
for y in range(1, 4):
if x == 2 and y == 2:
self.check_at(surf, (x, y), fg_adjusted)
else:
self.check_at(surf, (x, y), bg_adjusted)
def test_hline(self):
"""hline(surface, x1, x2, y, color): return None"""
fg = self.foreground_color
bg = self.background_color
startx = 10
stopx = 80
y = 50
fg_test_points = [(startx, y), (stopx, y), ((stopx - startx) // 2, y)]
bg_test_points = [
(startx - 1, y),
(stopx + 1, y),
(startx, y - 1),
(startx, y + 1),
(stopx, y - 1),
(stopx, y + 1),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.hline(surf, startx, stopx, y, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_vline(self):
"""vline(surface, x, y1, y2, color): return None"""
fg = self.foreground_color
bg = self.background_color
x = 50
starty = 10
stopy = 80
fg_test_points = [(x, starty), (x, stopy), (x, (stopy - starty) // 2)]
bg_test_points = [
(x, starty - 1),
(x, stopy + 1),
(x - 1, starty),
(x + 1, starty),
(x - 1, stopy),
(x + 1, stopy),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.vline(surf, x, starty, stopy, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_rectangle(self):
"""rectangle(surface, rect, color): return None"""
fg = self.foreground_color
bg = self.background_color
rect = pygame.Rect(10, 15, 55, 62)
rect_tuple = tuple(rect)
fg_test_points = [
rect.topleft,
(rect.right - 1, rect.top),
(rect.left, rect.bottom - 1),
(rect.right - 1, rect.bottom - 1),
]
bg_test_points = [
(rect.left - 1, rect.top - 1),
(rect.left + 1, rect.top + 1),
(rect.right, rect.top - 1),
(rect.right - 2, rect.top + 1),
(rect.left - 1, rect.bottom),
(rect.left + 1, rect.bottom - 2),
(rect.right, rect.bottom),
(rect.right - 2, rect.bottom - 2),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.rectangle(surf, rect, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
surf.fill(bg)
pygame.gfxdraw.rectangle(surf, rect_tuple, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_box(self):
"""box(surface, rect, color): return None"""
fg = self.foreground_color
bg = self.background_color
rect = pygame.Rect(10, 15, 55, 62)
rect_tuple = tuple(rect)
fg_test_points = [
rect.topleft,
(rect.left + 1, rect.top + 1),
(rect.right - 1, rect.top),
(rect.right - 2, rect.top + 1),
(rect.left, rect.bottom - 1),
(rect.left + 1, rect.bottom - 2),
(rect.right - 1, rect.bottom - 1),
(rect.right - 2, rect.bottom - 2),
]
bg_test_points = [
(rect.left - 1, rect.top - 1),
(rect.right, rect.top - 1),
(rect.left - 1, rect.bottom),
(rect.right, rect.bottom),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.box(surf, rect, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
surf.fill(bg)
pygame.gfxdraw.box(surf, rect_tuple, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_line(self):
"""line(surface, x1, y1, x2, y2, color): return None"""
fg = self.foreground_color
bg = self.background_color
x1 = 10
y1 = 15
x2 = 92
y2 = 77
fg_test_points = [(x1, y1), (x2, y2)]
bg_test_points = [
(x1 - 1, y1),
(x1, y1 - 1),
(x1 - 1, y1 - 1),
(x2 + 1, y2),
(x2, y2 + 1),
(x2 + 1, y2 + 1),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.line(surf, x1, y1, x2, y2, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_circle(self):
"""circle(surface, x, y, r, color): return None"""
fg = self.foreground_color
bg = self.background_color
x = 45
y = 40
r = 30
fg_test_points = [(x, y - r), (x, y + r), (x - r, y), (x + r, y)]
bg_test_points = [
(x, y),
(x, y - r + 1),
(x, y - r - 1),
(x, y + r + 1),
(x, y + r - 1),
(x - r - 1, y),
(x - r + 1, y),
(x + r + 1, y),
(x + r - 1, y),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.circle(surf, x, y, r, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_arc(self):
"""arc(surface, x, y, r, start, end, color): return None"""
fg = self.foreground_color
bg = self.background_color
x = 45
y = 40
r = 30
start = 0 # +x direction, but not (x + r, y) (?)
end = 90 # -y direction, including (x, y + r)
fg_test_points = [(x, y + r), (x + r, y + 1)]
bg_test_points = [
(x, y),
(x, y - r),
(x - r, y),
(x, y + r + 1),
(x, y + r - 1),
(x - 1, y + r),
(x + r + 1, y),
(x + r - 1, y),
(x + r, y),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.arc(surf, x, y, r, start, end, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_aacircle(self):
"""aacircle(surface, x, y, r, color): return None"""
fg = self.foreground_color
bg = self.background_color
x = 45
y = 40
r = 30
fg_test_points = [(x, y - r), (x, y + r), (x - r, y), (x + r, y)]
bg_test_points = [
(x, y),
(x, y - r + 1),
(x, y - r - 1),
(x, y + r + 1),
(x, y + r - 1),
(x - r - 1, y),
(x - r + 1, y),
(x + r + 1, y),
(x + r - 1, y),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.aacircle(surf, x, y, r, fg)
for posn in fg_test_points:
self.check_not_at(surf, posn, bg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_filled_circle(self):
"""filled_circle(surface, x, y, r, color): return None"""
fg = self.foreground_color
bg = self.background_color
x = 45
y = 40
r = 30
fg_test_points = [
(x, y - r),
(x, y - r + 1),
(x, y + r),
(x, y + r - 1),
(x - r, y),
(x - r + 1, y),
(x + r, y),
(x + r - 1, y),
(x, y),
]
bg_test_points = [
(x, y - r - 1),
(x, y + r + 1),
(x - r - 1, y),
(x + r + 1, y),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.filled_circle(surf, x, y, r, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_ellipse(self):
"""ellipse(surface, x, y, rx, ry, color): return None"""
fg = self.foreground_color
bg = self.background_color
x = 45
y = 40
rx = 30
ry = 35
fg_test_points = [(x, y - ry), (x, y + ry), (x - rx, y), (x + rx, y)]
bg_test_points = [
(x, y),
(x, y - ry + 1),
(x, y - ry - 1),
(x, y + ry + 1),
(x, y + ry - 1),
(x - rx - 1, y),
(x - rx + 1, y),
(x + rx + 1, y),
(x + rx - 1, y),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.ellipse(surf, x, y, rx, ry, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_aaellipse(self):
"""aaellipse(surface, x, y, rx, ry, color): return None"""
fg = self.foreground_color
bg = self.background_color
x = 45
y = 40
rx = 30
ry = 35
fg_test_points = [(x, y - ry), (x, y + ry), (x - rx, y), (x + rx, y)]
bg_test_points = [
(x, y),
(x, y - ry + 1),
(x, y - ry - 1),
(x, y + ry + 1),
(x, y + ry - 1),
(x - rx - 1, y),
(x - rx + 1, y),
(x + rx + 1, y),
(x + rx - 1, y),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.aaellipse(surf, x, y, rx, ry, fg)
for posn in fg_test_points:
self.check_not_at(surf, posn, bg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_filled_ellipse(self):
"""filled_ellipse(surface, x, y, rx, ry, color): return None"""
fg = self.foreground_color
bg = self.background_color
x = 45
y = 40
rx = 30
ry = 35
fg_test_points = [
(x, y - ry),
(x, y - ry + 1),
(x, y + ry),
(x, y + ry - 1),
(x - rx, y),
(x - rx + 1, y),
(x + rx, y),
(x + rx - 1, y),
(x, y),
]
bg_test_points = [
(x, y - ry - 1),
(x, y + ry + 1),
(x - rx - 1, y),
(x + rx + 1, y),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.filled_ellipse(surf, x, y, rx, ry, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_pie(self):
"""pie(surface, x, y, r, start, end, color): return None"""
fg = self.foreground_color
bg = self.background_color
x = 45
y = 40
r = 30
start = 0 # +x direction, including (x + r, y)
end = 90 # -y direction, but not (x, y + r) (?)
fg_test_points = [(x, y), (x + 1, y), (x, y + 1), (x + r, y)]
bg_test_points = [
(x - 1, y),
(x, y - 1),
(x - 1, y - 1),
(x + 1, y + 1),
(x + r + 1, y),
(x + r, y - 1),
(x, y + r + 1),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.pie(surf, x, y, r, start, end, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_trigon(self):
"""trigon(surface, x1, y1, x2, y2, x3, y3, color): return None"""
fg = self.foreground_color
bg = self.background_color
x1 = 10
y1 = 15
x2 = 92
y2 = 77
x3 = 20
y3 = 60
fg_test_points = [(x1, y1), (x2, y2), (x3, y3)]
bg_test_points = [
(x1 - 1, y1 - 1),
(x2 + 1, y2 + 1),
(x3 - 1, y3 + 1),
(x1 + 10, y1 + 30),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.trigon(surf, x1, y1, x2, y2, x3, y3, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_aatrigon(self):
"""aatrigon(surface, x1, y1, x2, y2, x3, y3, color): return None"""
fg = self.foreground_color
bg = self.background_color
x1 = 10
y1 = 15
x2 = 92
y2 = 77
x3 = 20
y3 = 60
fg_test_points = [(x1, y1), (x2, y2), (x3, y3)]
bg_test_points = [
(x1 - 1, y1 - 1),
(x2 + 1, y2 + 1),
(x3 - 1, y3 + 1),
(x1 + 10, y1 + 30),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.aatrigon(surf, x1, y1, x2, y2, x3, y3, fg)
for posn in fg_test_points:
self.check_not_at(surf, posn, bg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_aatrigon__with_horizontal_edge(self):
"""Ensure aatrigon draws horizontal edges correctly.
This test creates 2 surfaces and draws an aatrigon on each. The pixels
on each surface are compared to ensure they are the same. The only
difference between the 2 aatrigons is the order the points are drawn.
The order of the points should have no impact on the final drawing.
Related to issue #622.
"""
bg_color = pygame.Color("white")
line_color = pygame.Color("black")
width, height = 11, 10
expected_surface = pygame.Surface((width, height), 0, 32)
expected_surface.fill(bg_color)
surface = pygame.Surface((width, height), 0, 32)
surface.fill(bg_color)
x1, y1 = width - 1, 0
x2, y2 = (width - 1) // 2, height - 1
x3, y3 = 0, 0
# The points in this order draw as expected.
pygame.gfxdraw.aatrigon(expected_surface, x1, y1, x2, y2, x3, y3, line_color)
# The points in reverse order fail to draw the horizontal edge along
# the top.
pygame.gfxdraw.aatrigon(surface, x3, y3, x2, y2, x1, y1, line_color)
# The surfaces are locked for a possible speed up of pixel access.
expected_surface.lock()
surface.lock()
for x in range(width):
for y in range(height):
self.assertEqual(
expected_surface.get_at((x, y)),
surface.get_at((x, y)),
f"pos=({x}, {y})",
)
surface.unlock()
expected_surface.unlock()
def test_filled_trigon(self):
"""filled_trigon(surface, x1, y1, x2, y2, x3, y3, color): return None"""
fg = self.foreground_color
bg = self.background_color
x1 = 10
y1 = 15
x2 = 92
y2 = 77
x3 = 20
y3 = 60
fg_test_points = [(x1, y1), (x2, y2), (x3, y3), (x1 + 10, y1 + 30)]
bg_test_points = [(x1 - 1, y1 - 1), (x2 + 1, y2 + 1), (x3 - 1, y3 + 1)]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.filled_trigon(surf, x1, y1, x2, y2, x3, y3, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_polygon(self):
"""polygon(surface, points, color): return None"""
fg = self.foreground_color
bg = self.background_color
points = [(10, 80), (10, 15), (92, 25), (92, 80)]
fg_test_points = points + [
(points[0][0], points[0][1] - 1),
(points[0][0] + 1, points[0][1]),
(points[3][0] - 1, points[3][1]),
(points[3][0], points[3][1] - 1),
(points[2][0], points[2][1] + 1),
]
bg_test_points = [
(points[0][0] - 1, points[0][1]),
(points[0][0], points[0][1] + 1),
(points[0][0] - 1, points[0][1] + 1),
(points[0][0] + 1, points[0][1] - 1),
(points[3][0] + 1, points[3][1]),
(points[3][0], points[3][1] + 1),
(points[3][0] + 1, points[3][1] + 1),
(points[3][0] - 1, points[3][1] - 1),
(points[2][0] + 1, points[2][1]),
(points[2][0] - 1, points[2][1] + 1),
(points[1][0] - 1, points[1][1]),
(points[1][0], points[1][1] - 1),
(points[1][0] - 1, points[1][1] - 1),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.polygon(surf, points, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_aapolygon(self):
"""aapolygon(surface, points, color): return None"""
fg = self.foreground_color
bg = self.background_color
points = [(10, 80), (10, 15), (92, 25), (92, 80)]
fg_test_points = points
bg_test_points = [
(points[0][0] - 1, points[0][1]),
(points[0][0], points[0][1] + 1),
(points[0][0] - 1, points[0][1] + 1),
(points[0][0] + 1, points[0][1] - 1),
(points[3][0] + 1, points[3][1]),
(points[3][0], points[3][1] + 1),
(points[3][0] + 1, points[3][1] + 1),
(points[3][0] - 1, points[3][1] - 1),
(points[2][0] + 1, points[2][1]),
(points[2][0] - 1, points[2][1] + 1),
(points[1][0] - 1, points[1][1]),
(points[1][0], points[1][1] - 1),
(points[1][0] - 1, points[1][1] - 1),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.aapolygon(surf, points, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_not_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_aapolygon__with_horizontal_edge(self):
"""Ensure aapolygon draws horizontal edges correctly.
This test creates 2 surfaces and draws a polygon on each. The pixels
on each surface are compared to ensure they are the same. The only
difference between the 2 polygons is that one is drawn using
aapolygon() and the other using multiple line() calls. They should
produce the same final drawing.
Related to issue #622.
"""
bg_color = pygame.Color("white")
line_color = pygame.Color("black")
width, height = 11, 10
expected_surface = pygame.Surface((width, height), 0, 32)
expected_surface.fill(bg_color)
surface = pygame.Surface((width, height), 0, 32)
surface.fill(bg_color)
points = ((0, 0), (0, height - 1), (width - 1, height - 1), (width - 1, 0))
# The points are used to draw the expected aapolygon using the line()
# function.
for (x1, y1), (x2, y2) in zip(points, points[1:] + points[:1]):
pygame.gfxdraw.line(expected_surface, x1, y1, x2, y2, line_color)
# The points in this order fail to draw the horizontal edge along
# the top.
pygame.gfxdraw.aapolygon(surface, points, line_color)
# The surfaces are locked for a possible speed up of pixel access.
expected_surface.lock()
surface.lock()
for x in range(width):
for y in range(height):
self.assertEqual(
expected_surface.get_at((x, y)),
surface.get_at((x, y)),
f"pos=({x}, {y})",
)
surface.unlock()
expected_surface.unlock()
def test_filled_polygon(self):
"""filled_polygon(surface, points, color): return None"""
fg = self.foreground_color
bg = self.background_color
points = [(10, 80), (10, 15), (92, 25), (92, 80)]
fg_test_points = points + [
(points[0][0], points[0][1] - 1),
(points[0][0] + 1, points[0][1]),
(points[0][0] + 1, points[0][1] - 1),
(points[3][0] - 1, points[3][1]),
(points[3][0], points[3][1] - 1),
(points[3][0] - 1, points[3][1] - 1),
(points[2][0], points[2][1] + 1),
(points[2][0] - 1, points[2][1] + 1),
]
bg_test_points = [
(points[0][0] - 1, points[0][1]),
(points[0][0], points[0][1] + 1),
(points[0][0] - 1, points[0][1] + 1),
(points[3][0] + 1, points[3][1]),
(points[3][0], points[3][1] + 1),
(points[3][0] + 1, points[3][1] + 1),
(points[2][0] + 1, points[2][1]),
(points[1][0] - 1, points[1][1]),
(points[1][0], points[1][1] - 1),
(points[1][0] - 1, points[1][1] - 1),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.filled_polygon(surf, points, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
def test_textured_polygon(self):
"""textured_polygon(surface, points, texture, tx, ty): return None"""
w, h = self.default_size
fg = self.foreground_color
bg = self.background_color
tx = 0
ty = 0
texture = pygame.Surface((w + tx, h + ty), 0, 24)
texture.fill(fg, (0, 0, w, h))
points = [(10, 80), (10, 15), (92, 25), (92, 80)]
# Don't know how to really check this as boarder points may
# or may not be included in the textured polygon.
fg_test_points = [(points[1][0] + 30, points[1][1] + 40)]
bg_test_points = [
(points[0][0] - 1, points[0][1]),
(points[0][0], points[0][1] + 1),
(points[0][0] - 1, points[0][1] + 1),
(points[3][0] + 1, points[3][1]),
(points[3][0], points[3][1] + 1),
(points[3][0] + 1, points[3][1] + 1),
(points[2][0] + 1, points[2][1]),
(points[1][0] - 1, points[1][1]),
(points[1][0], points[1][1] - 1),
(points[1][0] - 1, points[1][1] - 1),
]
for surf in self.surfaces[1:]:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.textured_polygon(surf, points, texture, -tx, -ty)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
# Alpha blit to 8 bits-per-pixel surface forbidden.
texture = pygame.Surface(self.default_size, SRCALPHA, 32)
self.assertRaises(
ValueError,
pygame.gfxdraw.textured_polygon,
self.surfaces[0],
points,
texture,
0,
0,
)
def test_bezier(self):
"""bezier(surface, points, steps, color): return None"""
fg = self.foreground_color
bg = self.background_color
points = [(10, 50), (25, 15), (60, 80), (92, 30)]
fg_test_points = [points[0], points[3]]
bg_test_points = [
(points[0][0] - 1, points[0][1]),
(points[3][0] + 1, points[3][1]),
(points[1][0], points[1][1] + 3),
(points[2][0], points[2][1] - 3),
]
for surf in self.surfaces:
fg_adjusted = surf.unmap_rgb(surf.map_rgb(fg))
bg_adjusted = surf.unmap_rgb(surf.map_rgb(bg))
pygame.gfxdraw.bezier(surf, points, 30, fg)
for posn in fg_test_points:
self.check_at(surf, posn, fg_adjusted)
for posn in bg_test_points:
self.check_at(surf, posn, bg_adjusted)
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,46 @@
import os
import unittest
from pygame.tests import test_utils
import pygame
from pygame.locals import *
@unittest.skipIf(
os.environ.get("SDL_VIDEODRIVER") == "dummy",
'OpenGL requires a non-"dummy" SDL_VIDEODRIVER',
)
class GL_ImageSave(unittest.TestCase):
def test_image_save_works_with_opengl_surfaces(self):
"""
|tags:display,slow,opengl|
"""
pygame.display.init()
screen = pygame.display.set_mode((640, 480), OPENGL | DOUBLEBUF)
pygame.display.flip()
tmp_dir = test_utils.get_tmp_dir()
# Try the imageext module.
tmp_file = os.path.join(tmp_dir, "opengl_save_surface_test.png")
pygame.image.save(screen, tmp_file)
self.assertTrue(os.path.exists(tmp_file))
os.remove(tmp_file)
# Only test the image module.
tmp_file = os.path.join(tmp_dir, "opengl_save_surface_test.bmp")
pygame.image.save(screen, tmp_file)
self.assertTrue(os.path.exists(tmp_file))
os.remove(tmp_file)
# stops tonnes of tmp dirs building up in trunk dir
os.rmdir(tmp_dir)
pygame.display.quit()
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,7 @@
__tags__ = []
import pygame
import sys
if "pygame.image" not in sys.modules:
__tags__.extend(("ignore", "subprocess_ignore"))

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
__tags__ = []
import pygame
import sys
if "pygame.imageext" not in sys.modules:
__tags__.extend(("ignore", "subprocess_ignore"))

View File

@@ -0,0 +1,93 @@
import os
import os.path
import sys
import unittest
from pygame.tests.test_utils import example_path
import pygame, pygame.image, pygame.pkgdata
imageext = sys.modules["pygame.imageext"]
class ImageextModuleTest(unittest.TestCase):
# Most of the testing is done indirectly through image_test.py
# This just confirms file path encoding and error handling.
def test_save_non_string_file(self):
im = pygame.Surface((10, 10), 0, 32)
self.assertRaises(TypeError, imageext.save_extended, im, [])
def test_load_non_string_file(self):
self.assertRaises(TypeError, imageext.load_extended, [])
@unittest.skip("SDL silently removes invalid characters")
def test_save_bad_filename(self):
im = pygame.Surface((10, 10), 0, 32)
u = "a\x00b\x00c.png"
self.assertRaises(pygame.error, imageext.save_extended, im, u)
@unittest.skip("SDL silently removes invalid characters")
def test_load_bad_filename(self):
u = "a\x00b\x00c.png"
self.assertRaises(pygame.error, imageext.load_extended, u)
def test_save_unknown_extension(self):
im = pygame.Surface((10, 10), 0, 32)
s = "foo.bar"
self.assertRaises(pygame.error, imageext.save_extended, im, s)
def test_load_unknown_extension(self):
s = "foo.bar"
self.assertRaises(FileNotFoundError, imageext.load_extended, s)
def test_load_unknown_file(self):
s = "nonexistent.png"
self.assertRaises(FileNotFoundError, imageext.load_extended, s)
def test_load_unicode_path_0(self):
u = example_path("data/alien1.png")
im = imageext.load_extended(u)
def test_load_unicode_path_1(self):
"""non-ASCII unicode"""
import shutil
orig = example_path("data/alien1.png")
temp = os.path.join(example_path("data"), "你好.png")
shutil.copy(orig, temp)
try:
im = imageext.load_extended(temp)
finally:
os.remove(temp)
def _unicode_save(self, temp_file):
im = pygame.Surface((10, 10), 0, 32)
try:
with open(temp_file, "w") as f:
pass
os.remove(temp_file)
except OSError:
raise unittest.SkipTest("the path cannot be opened")
self.assertFalse(os.path.exists(temp_file))
try:
imageext.save_extended(im, temp_file)
self.assertGreater(os.path.getsize(temp_file), 10)
finally:
try:
os.remove(temp_file)
except OSError:
pass
def test_save_unicode_path_0(self):
"""unicode object with ASCII chars"""
self._unicode_save("temp_file.png")
def test_save_unicode_path_1(self):
self._unicode_save("你好.png")
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,166 @@
import unittest
from pygame.tests.test_utils import question, prompt
import pygame
import pygame._sdl2.controller
class JoystickTypeTest(unittest.TestCase):
def todo_test_Joystick(self):
# __doc__ (as of 2008-08-02) for pygame.joystick.Joystick:
# pygame.joystick.Joystick(id): return Joystick
# create a new Joystick object
#
# Create a new joystick to access a physical device. The id argument
# must be a value from 0 to pygame.joystick.get_count()-1.
#
# To access most of the Joystick methods, you'll need to init() the
# Joystick. This is separate from making sure the joystick module is
# initialized. When multiple Joysticks objects are created for the
# same physical joystick device (i.e., they have the same ID number),
# the state and values for those Joystick objects will be shared.
#
# The Joystick object allows you to get information about the types of
# controls on a joystick device. Once the device is initialized the
# Pygame event queue will start receiving events about its input.
#
# You can call the Joystick.get_name() and Joystick.get_id() functions
# without initializing the Joystick object.
#
self.fail()
class JoystickModuleTest(unittest.TestCase):
def test_get_init(self):
# Check that get_init() matches what is actually happening
def error_check_get_init():
try:
pygame.joystick.get_count()
except pygame.error:
return False
return True
# Start uninitialised
self.assertEqual(pygame.joystick.get_init(), False)
pygame.joystick.init()
self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # True
pygame.joystick.quit()
self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # False
pygame.joystick.init()
pygame.joystick.init()
self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # True
pygame.joystick.quit()
self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # False
pygame.joystick.quit()
self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # False
for i in range(100):
pygame.joystick.init()
self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # True
pygame.joystick.quit()
self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # False
for i in range(100):
pygame.joystick.quit()
self.assertEqual(pygame.joystick.get_init(), error_check_get_init()) # False
def test_init(self):
"""
This unit test is for joystick.init()
It was written to help reduce maintenance costs
and to help test against changes to the code or
different platforms.
"""
pygame.quit()
# test that pygame.init automatically calls joystick.init
pygame.init()
self.assertEqual(pygame.joystick.get_init(), True)
# Controller module interferes with the joystick module.
pygame._sdl2.controller.quit()
# test that get_count doesn't work w/o joystick init
# this is done before and after an init to test
# that init activates the joystick functions
pygame.joystick.quit()
with self.assertRaises(pygame.error):
pygame.joystick.get_count()
# test explicit call(s) to joystick.init.
# Also test that get_count works once init is called
iterations = 20
for i in range(iterations):
pygame.joystick.init()
self.assertEqual(pygame.joystick.get_init(), True)
self.assertIsNotNone(pygame.joystick.get_count())
def test_quit(self):
"""Test if joystick.quit works."""
pygame.joystick.init()
self.assertIsNotNone(pygame.joystick.get_count()) # Is not None before quit
pygame.joystick.quit()
with self.assertRaises(pygame.error): # Raises error if quit worked
pygame.joystick.get_count()
def test_get_count(self):
# Test that get_count correctly returns a non-negative number of joysticks
pygame.joystick.init()
try:
count = pygame.joystick.get_count()
self.assertGreaterEqual(
count, 0, ("joystick.get_count() must " "return a value >= 0")
)
finally:
pygame.joystick.quit()
class JoystickInteractiveTest(unittest.TestCase):
__tags__ = ["interactive"]
def test_get_count_interactive(self):
# Test get_count correctly identifies number of connected joysticks
prompt(
"Please connect any joysticks/controllers now before starting the "
"joystick.get_count() test."
)
pygame.joystick.init()
# pygame.joystick.get_count(): return count
# number of joysticks on the system, 0 means no joysticks connected
count = pygame.joystick.get_count()
response = question(
"NOTE: Having Steam open may add an extra virtual controller for "
"each joystick/controller physically plugged in.\n"
f"joystick.get_count() thinks there is [{count}] joystick(s)/controller(s)"
"connected to this system. Is this correct?"
)
self.assertTrue(response)
# When you create Joystick objects using Joystick(id), you pass an
# integer that must be lower than this count.
# Test Joystick(id) for each connected joystick
if count != 0:
for x in range(count):
pygame.joystick.Joystick(x)
with self.assertRaises(pygame.error):
pygame.joystick.Joystick(count)
pygame.joystick.quit()
################################################################################
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,306 @@
import os
import time
import unittest
import pygame
import pygame.key
# keys that are not tested for const-name match
SKIPPED_KEYS = {"K_UNKNOWN"}
# This is the expected compat output
KEY_NAME_COMPAT = {
"K_0": "0",
"K_1": "1",
"K_2": "2",
"K_3": "3",
"K_4": "4",
"K_5": "5",
"K_6": "6",
"K_7": "7",
"K_8": "8",
"K_9": "9",
"K_AC_BACK": "AC Back",
"K_AMPERSAND": "&",
"K_ASTERISK": "*",
"K_AT": "@",
"K_BACKQUOTE": "`",
"K_BACKSLASH": "\\",
"K_BACKSPACE": "backspace",
"K_BREAK": "break",
"K_CAPSLOCK": "caps lock",
"K_CARET": "^",
"K_CLEAR": "clear",
"K_COLON": ":",
"K_COMMA": ",",
"K_CURRENCYSUBUNIT": "CurrencySubUnit",
"K_CURRENCYUNIT": "euro",
"K_DELETE": "delete",
"K_DOLLAR": "$",
"K_DOWN": "down",
"K_END": "end",
"K_EQUALS": "=",
"K_ESCAPE": "escape",
"K_EURO": "euro",
"K_EXCLAIM": "!",
"K_F1": "f1",
"K_F10": "f10",
"K_F11": "f11",
"K_F12": "f12",
"K_F13": "f13",
"K_F14": "f14",
"K_F15": "f15",
"K_F2": "f2",
"K_F3": "f3",
"K_F4": "f4",
"K_F5": "f5",
"K_F6": "f6",
"K_F7": "f7",
"K_F8": "f8",
"K_F9": "f9",
"K_GREATER": ">",
"K_HASH": "#",
"K_HELP": "help",
"K_HOME": "home",
"K_INSERT": "insert",
"K_KP0": "[0]",
"K_KP1": "[1]",
"K_KP2": "[2]",
"K_KP3": "[3]",
"K_KP4": "[4]",
"K_KP5": "[5]",
"K_KP6": "[6]",
"K_KP7": "[7]",
"K_KP8": "[8]",
"K_KP9": "[9]",
"K_KP_0": "[0]",
"K_KP_1": "[1]",
"K_KP_2": "[2]",
"K_KP_3": "[3]",
"K_KP_4": "[4]",
"K_KP_5": "[5]",
"K_KP_6": "[6]",
"K_KP_7": "[7]",
"K_KP_8": "[8]",
"K_KP_9": "[9]",
"K_KP_DIVIDE": "[/]",
"K_KP_ENTER": "enter",
"K_KP_EQUALS": "equals",
"K_KP_MINUS": "[-]",
"K_KP_MULTIPLY": "[*]",
"K_KP_PERIOD": "[.]",
"K_KP_PLUS": "[+]",
"K_LALT": "left alt",
"K_LCTRL": "left ctrl",
"K_LEFT": "left",
"K_LEFTBRACKET": "[",
"K_LEFTPAREN": "(",
"K_LESS": "<",
"K_LGUI": "left meta",
"K_LMETA": "left meta",
"K_LSHIFT": "left shift",
"K_LSUPER": "left meta",
"K_MENU": "menu",
"K_MINUS": "-",
"K_MODE": "alt gr",
"K_NUMLOCK": "numlock",
"K_NUMLOCKCLEAR": "numlock",
"K_PAGEDOWN": "page down",
"K_PAGEUP": "page up",
"K_PAUSE": "break",
"K_PERCENT": "%",
"K_PERIOD": ".",
"K_PLUS": "+",
"K_POWER": "power",
"K_PRINT": "print screen",
"K_PRINTSCREEN": "print screen",
"K_QUESTION": "?",
"K_QUOTE": "'",
"K_QUOTEDBL": '"',
"K_RALT": "right alt",
"K_RCTRL": "right ctrl",
"K_RETURN": "return",
"K_RGUI": "right meta",
"K_RIGHT": "right",
"K_RIGHTBRACKET": "]",
"K_RIGHTPAREN": ")",
"K_RMETA": "right meta",
"K_RSHIFT": "right shift",
"K_RSUPER": "right meta",
"K_SCROLLLOCK": "scroll lock",
"K_SCROLLOCK": "scroll lock",
"K_SEMICOLON": ";",
"K_SLASH": "/",
"K_SPACE": "space",
"K_SYSREQ": "sys req",
"K_TAB": "tab",
"K_UNDERSCORE": "_",
"K_UP": "up",
"K_a": "a",
"K_b": "b",
"K_c": "c",
"K_d": "d",
"K_e": "e",
"K_f": "f",
"K_g": "g",
"K_h": "h",
"K_i": "i",
"K_j": "j",
"K_k": "k",
"K_l": "l",
"K_m": "m",
"K_n": "n",
"K_o": "o",
"K_p": "p",
"K_q": "q",
"K_r": "r",
"K_s": "s",
"K_t": "t",
"K_u": "u",
"K_v": "v",
"K_w": "w",
"K_x": "x",
"K_y": "y",
"K_z": "z",
}
class KeyModuleTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
pygame.init()
@classmethod
def tearDownClass(cls):
pygame.quit()
def setUp(self):
# This makes sure pygame is always initialized before each test (in
# case a test calls pygame.quit()).
if not pygame.get_init():
pygame.init()
if not pygame.display.get_init():
pygame.display.init()
def test_import(self):
"""does it import?"""
import pygame.key
# fixme: test_get_focused failing systematically in some linux
# fixme: test_get_focused failing on SDL 2.0.18 on Windows
@unittest.skip("flaky test, and broken on 2.0.18 windows")
def test_get_focused(self):
# This test fails in SDL2 in some linux
# This test was skipped in SDL1.
focused = pygame.key.get_focused()
self.assertFalse(focused) # No window to focus
self.assertIsInstance(focused, int)
# Dummy video driver never gets keyboard focus.
if os.environ.get("SDL_VIDEODRIVER") != "dummy":
# Positive test, fullscreen with events grabbed
display_sizes = pygame.display.list_modes()
if display_sizes == -1:
display_sizes = [(500, 500)]
pygame.display.set_mode(size=display_sizes[-1], flags=pygame.FULLSCREEN)
pygame.event.set_grab(True)
# Pump event queue to get window focus on macos
pygame.event.pump()
focused = pygame.key.get_focused()
self.assertIsInstance(focused, int)
self.assertTrue(focused)
# Now test negative, iconify takes away focus
pygame.event.clear()
# TODO: iconify test fails in windows
if os.name != "nt":
pygame.display.iconify()
# Apparent need to pump event queue in order to make sure iconify
# happens. See display_test.py's test_get_active_iconify
for _ in range(50):
time.sleep(0.01)
pygame.event.pump()
self.assertFalse(pygame.key.get_focused())
# Test if focus is returned when iconify is gone
pygame.display.set_mode(size=display_sizes[-1], flags=pygame.FULLSCREEN)
for i in range(50):
time.sleep(0.01)
pygame.event.pump()
self.assertTrue(pygame.key.get_focused())
# Test if a quit display raises an error:
pygame.display.quit()
with self.assertRaises(pygame.error) as cm:
pygame.key.get_focused()
def test_get_pressed(self):
states = pygame.key.get_pressed()
self.assertEqual(states[pygame.K_RIGHT], 0)
# def test_get_pressed_not_iter(self):
# states = pygame.key.get_pressed()
# with self.assertRaises(TypeError):
# next(states)
# with self.assertRaises(TypeError):
# for k in states:
# pass
def test_name_and_key_code(self):
for const_name in dir(pygame):
if not const_name.startswith("K_") or const_name in SKIPPED_KEYS:
continue
try:
expected_str_name = KEY_NAME_COMPAT[const_name]
except KeyError:
self.fail(
"If you are seeing this error in a test run, you probably added a "
"new pygame key constant, but forgot to update key_test unitests"
)
const_val = getattr(pygame, const_name)
# with these tests below, we also make sure that key.name and key.key_code
# can work together and handle each others outputs
# test positional args
self.assertEqual(pygame.key.name(const_val), expected_str_name)
# test kwarg
self.assertEqual(pygame.key.name(key=const_val), expected_str_name)
# test positional args
self.assertEqual(pygame.key.key_code(expected_str_name), const_val)
# test kwarg
self.assertEqual(pygame.key.key_code(name=expected_str_name), const_val)
alt_name = pygame.key.name(const_val, use_compat=False)
self.assertIsInstance(alt_name, str)
# This is a test for an implementation detail of name with use_compat=False
# If this test breaks in the future for any key, it is safe to put skips on
# failing keys (the implementation detail is documented as being unreliable)
self.assertEqual(pygame.key.key_code(alt_name), const_val)
self.assertRaises(TypeError, pygame.key.name, "fizzbuzz")
self.assertRaises(TypeError, pygame.key.key_code, pygame.K_a)
self.assertRaises(ValueError, pygame.key.key_code, "fizzbuzz")
def test_set_and_get_mods(self):
pygame.key.set_mods(pygame.KMOD_CTRL)
self.assertEqual(pygame.key.get_mods(), pygame.KMOD_CTRL)
pygame.key.set_mods(pygame.KMOD_ALT)
self.assertEqual(pygame.key.get_mods(), pygame.KMOD_ALT)
pygame.key.set_mods(pygame.KMOD_CTRL | pygame.KMOD_ALT)
self.assertEqual(pygame.key.get_mods(), pygame.KMOD_CTRL | pygame.KMOD_ALT)
def test_set_and_get_repeat(self):
self.assertEqual(pygame.key.get_repeat(), (0, 0))
pygame.key.set_repeat(10, 15)
self.assertEqual(pygame.key.get_repeat(), (10, 15))
pygame.key.set_repeat()
self.assertEqual(pygame.key.get_repeat(), (0, 0))
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,17 @@
import unittest
import pygame.constants
import pygame.locals
class LocalsTest(unittest.TestCase):
def test_locals_has_all_constants(self):
constants_set = set(pygame.constants.__all__)
locals_set = set(pygame.locals.__all__)
# locals should have everything that constants has
self.assertEqual(constants_set - locals_set, set())
if __name__ == "__main__":
unittest.main()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,463 @@
import unittest
import pygame
class MidiInputTest(unittest.TestCase):
__tags__ = ["interactive"]
def setUp(self):
import pygame.midi
pygame.midi.init()
in_id = pygame.midi.get_default_input_id()
if in_id != -1:
self.midi_input = pygame.midi.Input(in_id)
else:
self.midi_input = None
def tearDown(self):
if self.midi_input:
self.midi_input.close()
pygame.midi.quit()
def test_Input(self):
i = pygame.midi.get_default_input_id()
if self.midi_input:
self.assertEqual(self.midi_input.device_id, i)
# try feeding it an input id.
i = pygame.midi.get_default_output_id()
# can handle some invalid input too.
self.assertRaises(pygame.midi.MidiException, pygame.midi.Input, i)
self.assertRaises(pygame.midi.MidiException, pygame.midi.Input, 9009)
self.assertRaises(pygame.midi.MidiException, pygame.midi.Input, -1)
self.assertRaises(TypeError, pygame.midi.Input, "1234")
self.assertRaises(OverflowError, pygame.midi.Input, pow(2, 99))
def test_poll(self):
if not self.midi_input:
self.skipTest("No midi Input device")
self.assertFalse(self.midi_input.poll())
# TODO fake some incoming data
pygame.midi.quit()
self.assertRaises(RuntimeError, self.midi_input.poll)
# set midi_input to None to avoid error in tearDown
self.midi_input = None
def test_read(self):
if not self.midi_input:
self.skipTest("No midi Input device")
read = self.midi_input.read(5)
self.assertEqual(read, [])
# TODO fake some incoming data
pygame.midi.quit()
self.assertRaises(RuntimeError, self.midi_input.read, 52)
# set midi_input to None to avoid error in tearDown
self.midi_input = None
def test_close(self):
if not self.midi_input:
self.skipTest("No midi Input device")
self.assertIsNotNone(self.midi_input._input)
self.midi_input.close()
self.assertIsNone(self.midi_input._input)
class MidiOutputTest(unittest.TestCase):
__tags__ = ["interactive"]
def setUp(self):
import pygame.midi
pygame.midi.init()
m_out_id = pygame.midi.get_default_output_id()
if m_out_id != -1:
self.midi_output = pygame.midi.Output(m_out_id)
else:
self.midi_output = None
def tearDown(self):
if self.midi_output:
self.midi_output.close()
pygame.midi.quit()
def test_Output(self):
i = pygame.midi.get_default_output_id()
if self.midi_output:
self.assertEqual(self.midi_output.device_id, i)
# try feeding it an input id.
i = pygame.midi.get_default_input_id()
# can handle some invalid input too.
self.assertRaises(pygame.midi.MidiException, pygame.midi.Output, i)
self.assertRaises(pygame.midi.MidiException, pygame.midi.Output, 9009)
self.assertRaises(pygame.midi.MidiException, pygame.midi.Output, -1)
self.assertRaises(TypeError, pygame.midi.Output, "1234")
self.assertRaises(OverflowError, pygame.midi.Output, pow(2, 99))
def test_note_off(self):
if self.midi_output:
out = self.midi_output
out.note_on(5, 30, 0)
out.note_off(5, 30, 0)
with self.assertRaises(ValueError) as cm:
out.note_off(5, 30, 25)
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
with self.assertRaises(ValueError) as cm:
out.note_off(5, 30, -1)
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
def test_note_on(self):
if self.midi_output:
out = self.midi_output
out.note_on(5, 30, 0)
out.note_on(5, 42, 10)
with self.assertRaises(ValueError) as cm:
out.note_on(5, 30, 25)
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
with self.assertRaises(ValueError) as cm:
out.note_on(5, 30, -1)
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
def test_set_instrument(self):
if not self.midi_output:
self.skipTest("No midi device")
out = self.midi_output
out.set_instrument(5)
out.set_instrument(42, channel=2)
with self.assertRaises(ValueError) as cm:
out.set_instrument(-6)
self.assertEqual(str(cm.exception), "Undefined instrument id: -6")
with self.assertRaises(ValueError) as cm:
out.set_instrument(156)
self.assertEqual(str(cm.exception), "Undefined instrument id: 156")
with self.assertRaises(ValueError) as cm:
out.set_instrument(5, -1)
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
with self.assertRaises(ValueError) as cm:
out.set_instrument(5, 16)
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
def test_write(self):
if not self.midi_output:
self.skipTest("No midi device")
out = self.midi_output
out.write([[[0xC0, 0, 0], 20000]])
# is equivalent to
out.write([[[0xC0], 20000]])
# example from the docstring :
# 1. choose program change 1 at time 20000 and
# 2. send note 65 with velocity 100 500 ms later
out.write([[[0xC0, 0, 0], 20000], [[0x90, 60, 100], 20500]])
out.write([])
verrry_long = [[[0x90, 60, i % 100], 20000 + 100 * i] for i in range(1024)]
out.write(verrry_long)
too_long = [[[0x90, 60, i % 100], 20000 + 100 * i] for i in range(1025)]
self.assertRaises(IndexError, out.write, too_long)
# test wrong data
with self.assertRaises(TypeError) as cm:
out.write("Non sens ?")
error_msg = "unsupported operand type(s) for &: 'str' and 'int'"
self.assertEqual(str(cm.exception), error_msg)
with self.assertRaises(TypeError) as cm:
out.write(["Hey what's that?"])
self.assertEqual(str(cm.exception), error_msg)
def test_write_short(self):
if not self.midi_output:
self.skipTest("No midi device")
out = self.midi_output
# program change
out.write_short(0xC0)
# put a note on, then off.
out.write_short(0x90, 65, 100)
out.write_short(0x80, 65, 100)
out.write_short(0x90)
def test_write_sys_ex(self):
if not self.midi_output:
self.skipTest("No midi device")
out = self.midi_output
out.write_sys_ex(pygame.midi.time(), [0xF0, 0x7D, 0x10, 0x11, 0x12, 0x13, 0xF7])
def test_pitch_bend(self):
# FIXME : pitch_bend in the code, but not in documentation
if not self.midi_output:
self.skipTest("No midi device")
out = self.midi_output
with self.assertRaises(ValueError) as cm:
out.pitch_bend(5, channel=-1)
self.assertEqual(str(cm.exception), "Channel not between 0 and 15.")
with self.assertRaises(ValueError) as cm:
out.pitch_bend(5, channel=16)
with self.assertRaises(ValueError) as cm:
out.pitch_bend(-10001, 1)
self.assertEqual(
str(cm.exception),
"Pitch bend value must be between " "-8192 and +8191, not -10001.",
)
with self.assertRaises(ValueError) as cm:
out.pitch_bend(10665, 2)
def test_close(self):
if not self.midi_output:
self.skipTest("No midi device")
self.assertIsNotNone(self.midi_output._output)
self.midi_output.close()
self.assertIsNone(self.midi_output._output)
def test_abort(self):
if not self.midi_output:
self.skipTest("No midi device")
self.assertEqual(self.midi_output._aborted, 0)
self.midi_output.abort()
self.assertEqual(self.midi_output._aborted, 1)
class MidiModuleTest(unittest.TestCase):
"""Midi module tests that require midi hardware or midi.init().
See MidiModuleNonInteractiveTest for non-interactive module tests.
"""
__tags__ = ["interactive"]
def setUp(self):
import pygame.midi
pygame.midi.init()
def tearDown(self):
pygame.midi.quit()
def test_get_count(self):
c = pygame.midi.get_count()
self.assertIsInstance(c, int)
self.assertTrue(c >= 0)
def test_get_default_input_id(self):
midin_id = pygame.midi.get_default_input_id()
# if there is a not None return make sure it is an int.
self.assertIsInstance(midin_id, int)
self.assertTrue(midin_id >= -1)
pygame.midi.quit()
self.assertRaises(RuntimeError, pygame.midi.get_default_output_id)
def test_get_default_output_id(self):
c = pygame.midi.get_default_output_id()
self.assertIsInstance(c, int)
self.assertTrue(c >= -1)
pygame.midi.quit()
self.assertRaises(RuntimeError, pygame.midi.get_default_output_id)
def test_get_device_info(self):
an_id = pygame.midi.get_default_output_id()
if an_id != -1:
interf, name, input, output, opened = pygame.midi.get_device_info(an_id)
self.assertEqual(output, 1)
self.assertEqual(input, 0)
self.assertEqual(opened, 0)
an_in_id = pygame.midi.get_default_input_id()
if an_in_id != -1:
r = pygame.midi.get_device_info(an_in_id)
# if r is None, it means that the id is out of range.
interf, name, input, output, opened = r
self.assertEqual(output, 0)
self.assertEqual(input, 1)
self.assertEqual(opened, 0)
out_of_range = pygame.midi.get_count()
for num in range(out_of_range):
self.assertIsNotNone(pygame.midi.get_device_info(num))
info = pygame.midi.get_device_info(out_of_range)
self.assertIsNone(info)
def test_init(self):
pygame.midi.quit()
self.assertRaises(RuntimeError, pygame.midi.get_count)
# initialising many times should be fine.
pygame.midi.init()
pygame.midi.init()
pygame.midi.init()
pygame.midi.init()
self.assertTrue(pygame.midi.get_init())
def test_quit(self):
# It is safe to call this more than once.
pygame.midi.quit()
pygame.midi.init()
pygame.midi.quit()
pygame.midi.quit()
pygame.midi.init()
pygame.midi.init()
pygame.midi.quit()
self.assertFalse(pygame.midi.get_init())
def test_get_init(self):
# Already initialized as pygame.midi.init() was called in setUp().
self.assertTrue(pygame.midi.get_init())
def test_time(self):
mtime = pygame.midi.time()
self.assertIsInstance(mtime, int)
# should be close to 2-3... since the timer is just init'd.
self.assertTrue(0 <= mtime < 100)
class MidiModuleNonInteractiveTest(unittest.TestCase):
"""Midi module tests that do not require midi hardware or midi.init().
See MidiModuleTest for interactive module tests.
"""
def setUp(self):
import pygame.midi
def test_midiin(self):
"""Ensures the MIDIIN event id exists in the midi module.
The MIDIIN event id can be accessed via the midi module for backward
compatibility.
"""
self.assertEqual(pygame.midi.MIDIIN, pygame.MIDIIN)
self.assertEqual(pygame.midi.MIDIIN, pygame.locals.MIDIIN)
self.assertNotEqual(pygame.midi.MIDIIN, pygame.MIDIOUT)
self.assertNotEqual(pygame.midi.MIDIIN, pygame.locals.MIDIOUT)
def test_midiout(self):
"""Ensures the MIDIOUT event id exists in the midi module.
The MIDIOUT event id can be accessed via the midi module for backward
compatibility.
"""
self.assertEqual(pygame.midi.MIDIOUT, pygame.MIDIOUT)
self.assertEqual(pygame.midi.MIDIOUT, pygame.locals.MIDIOUT)
self.assertNotEqual(pygame.midi.MIDIOUT, pygame.MIDIIN)
self.assertNotEqual(pygame.midi.MIDIOUT, pygame.locals.MIDIIN)
def test_MidiException(self):
"""Ensures the MidiException is raised as expected."""
def raiseit():
raise pygame.midi.MidiException("Hello Midi param")
with self.assertRaises(pygame.midi.MidiException) as cm:
raiseit()
self.assertEqual(cm.exception.parameter, "Hello Midi param")
def test_midis2events(self):
"""Ensures midi events are properly converted to pygame events."""
# List/tuple indexes.
MIDI_DATA = 0
MD_STATUS = 0
MD_DATA1 = 1
MD_DATA2 = 2
MD_DATA3 = 3
TIMESTAMP = 1
# Midi events take the form of:
# ((status, data1, data2, data3), timestamp)
midi_events = (
((0xC0, 0, 1, 2), 20000),
((0x90, 60, 1000, "string_data"), 20001),
(("0", "1", "2", "3"), "4"),
)
expected_num_events = len(midi_events)
# Test different device ids.
for device_id in range(3):
pg_events = pygame.midi.midis2events(midi_events, device_id)
self.assertEqual(len(pg_events), expected_num_events)
for i, pg_event in enumerate(pg_events):
# Get the original midi data for comparison.
midi_event = midi_events[i]
midi_event_data = midi_event[MIDI_DATA]
# Can't directly check event instance as pygame.event.Event is
# a function.
# self.assertIsInstance(pg_event, pygame.event.Event)
self.assertEqual(pg_event.__class__.__name__, "Event")
self.assertEqual(pg_event.type, pygame.MIDIIN)
self.assertEqual(pg_event.status, midi_event_data[MD_STATUS])
self.assertEqual(pg_event.data1, midi_event_data[MD_DATA1])
self.assertEqual(pg_event.data2, midi_event_data[MD_DATA2])
self.assertEqual(pg_event.data3, midi_event_data[MD_DATA3])
self.assertEqual(pg_event.timestamp, midi_event[TIMESTAMP])
self.assertEqual(pg_event.vice_id, device_id)
def test_midis2events__missing_event_data(self):
"""Ensures midi events with missing values are handled properly."""
midi_event_missing_data = ((0xC0, 0, 1), 20000)
midi_event_missing_timestamp = ((0xC0, 0, 1, 2),)
for midi_event in (midi_event_missing_data, midi_event_missing_timestamp):
with self.assertRaises(ValueError):
events = pygame.midi.midis2events([midi_event], 0)
def test_midis2events__extra_event_data(self):
"""Ensures midi events with extra values are handled properly."""
midi_event_extra_data = ((0xC0, 0, 1, 2, "extra"), 20000)
midi_event_extra_timestamp = ((0xC0, 0, 1, 2), 20000, "extra")
for midi_event in (midi_event_extra_data, midi_event_extra_timestamp):
with self.assertRaises(ValueError):
events = pygame.midi.midis2events([midi_event], 0)
def test_midis2events__extra_event_data_missing_timestamp(self):
"""Ensures midi events with extra data and no timestamps are handled
properly.
"""
midi_event_extra_data_no_timestamp = ((0xC0, 0, 1, 2, "extra"),)
with self.assertRaises(ValueError):
events = pygame.midi.midis2events([midi_event_extra_data_no_timestamp], 0)
def test_conversions(self):
"""of frequencies to midi note numbers and ansi note names."""
from pygame.midi import frequency_to_midi, midi_to_frequency, midi_to_ansi_note
self.assertEqual(frequency_to_midi(27.5), 21)
self.assertEqual(frequency_to_midi(36.7), 26)
self.assertEqual(frequency_to_midi(4186.0), 108)
self.assertEqual(midi_to_frequency(21), 27.5)
self.assertEqual(midi_to_frequency(26), 36.7)
self.assertEqual(midi_to_frequency(108), 4186.0)
self.assertEqual(midi_to_ansi_note(21), "A0")
self.assertEqual(midi_to_ansi_note(71), "B4")
self.assertEqual(midi_to_ansi_note(82), "A#5")
self.assertEqual(midi_to_ansi_note(83), "B5")
self.assertEqual(midi_to_ansi_note(93), "A6")
self.assertEqual(midi_to_ansi_note(94), "A#6")
self.assertEqual(midi_to_ansi_note(95), "B6")
self.assertEqual(midi_to_ansi_note(96), "C7")
self.assertEqual(midi_to_ansi_note(102), "F#7")
self.assertEqual(midi_to_ansi_note(108), "C8")
if __name__ == "__main__":
unittest.main()

View File

@@ -0,0 +1,7 @@
__tags__ = []
import pygame
import sys
if "pygame.mixer_music" not in sys.modules:
__tags__.extend(("ignore", "subprocess_ignore"))

View File

@@ -0,0 +1,437 @@
import os
import sys
import platform
import unittest
import time
from pygame.tests.test_utils import example_path
import pygame
class MixerMusicModuleTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
# Initializing the mixer is slow, so minimize the times it is called.
pygame.mixer.init()
@classmethod
def tearDownClass(cls):
pygame.mixer.quit()
def setUp(cls):
# This makes sure the mixer is always initialized before each test (in
# case a test calls pygame.mixer.quit()).
if pygame.mixer.get_init() is None:
pygame.mixer.init()
def test_load_mp3(self):
"|tags:music|"
self.music_load("mp3")
def test_load_ogg(self):
"|tags:music|"
self.music_load("ogg")
def test_load_wav(self):
"|tags:music|"
self.music_load("wav")
def music_load(self, format):
data_fname = example_path("data")
path = os.path.join(data_fname, f"house_lo.{format}")
if os.sep == "\\":
path = path.replace("\\", "\\\\")
umusfn = str(path)
bmusfn = umusfn.encode()
pygame.mixer.music.load(umusfn)
pygame.mixer.music.load(bmusfn)
def test_load_object(self):
"""test loading music from file-like objects."""
formats = ["ogg", "wav"]
data_fname = example_path("data")
for f in formats:
path = os.path.join(data_fname, f"house_lo.{f}")
if os.sep == "\\":
path = path.replace("\\", "\\\\")
bmusfn = path.encode()
with open(bmusfn, "rb") as musf:
pygame.mixer.music.load(musf)
def test_object_namehint(self):
"""test loading & queuing music from file-like objects with namehint argument."""
formats = ["wav", "ogg"]
data_fname = example_path("data")
for f in formats:
path = os.path.join(data_fname, f"house_lo.{f}")
if os.sep == "\\":
path = path.replace("\\", "\\\\")
bmusfn = path.encode()
# these two "with open" blocks need to be separate, which is kinda weird
with open(bmusfn, "rb") as musf:
pygame.mixer.music.load(musf, f)
with open(bmusfn, "rb") as musf:
pygame.mixer.music.queue(musf, f)
with open(bmusfn, "rb") as musf:
pygame.mixer.music.load(musf, namehint=f)
with open(bmusfn, "rb") as musf:
pygame.mixer.music.queue(musf, namehint=f)
def test_load_unicode(self):
"""test non-ASCII unicode path"""
import shutil
ep = example_path("data")
temp_file = os.path.join(ep, "你好.wav")
org_file = os.path.join(ep, "house_lo.wav")
try:
with open(temp_file, "w") as f:
pass
os.remove(temp_file)
except OSError:
raise unittest.SkipTest("the path cannot be opened")
shutil.copy(org_file, temp_file)
try:
pygame.mixer.music.load(temp_file)
pygame.mixer.music.load(org_file) # unload
finally:
os.remove(temp_file)
def test_unload(self):
import shutil
import tempfile
ep = example_path("data")
org_file = os.path.join(ep, "house_lo.wav")
tmpfd, tmppath = tempfile.mkstemp(".wav")
os.close(tmpfd)
shutil.copy(org_file, tmppath)
try:
pygame.mixer.music.load(tmppath)
pygame.mixer.music.unload()
finally:
os.remove(tmppath)
def test_queue_mp3(self):
"""Ensures queue() accepts mp3 files.
|tags:music|
"""
filename = example_path(os.path.join("data", "house_lo.mp3"))
pygame.mixer.music.queue(filename)
def test_queue_ogg(self):
"""Ensures queue() accepts ogg files.
|tags:music|
"""
filename = example_path(os.path.join("data", "house_lo.ogg"))
pygame.mixer.music.queue(filename)
def test_queue_wav(self):
"""Ensures queue() accepts wav files.
|tags:music|
"""
filename = example_path(os.path.join("data", "house_lo.wav"))
pygame.mixer.music.queue(filename)
def test_queue__multiple_calls(self):
"""Ensures queue() can be called multiple times."""
ogg_file = example_path(os.path.join("data", "house_lo.ogg"))
wav_file = example_path(os.path.join("data", "house_lo.wav"))
pygame.mixer.music.queue(ogg_file)
pygame.mixer.music.queue(wav_file)
def test_queue__arguments(self):
"""Ensures queue() can be called with proper arguments."""
wav_file = example_path(os.path.join("data", "house_lo.wav"))
pygame.mixer.music.queue(wav_file, loops=2)
pygame.mixer.music.queue(wav_file, namehint="")
pygame.mixer.music.queue(wav_file, "")
pygame.mixer.music.queue(wav_file, "", 2)
def test_queue__no_file(self):
"""Ensures queue() correctly handles missing the file argument."""
with self.assertRaises(TypeError):
pygame.mixer.music.queue()
def test_queue__invalid_sound_type(self):
"""Ensures queue() correctly handles invalid file types."""
not_a_sound_file = example_path(os.path.join("data", "city.png"))
with self.assertRaises(pygame.error):
pygame.mixer.music.queue(not_a_sound_file)
def test_queue__invalid_filename(self):
"""Ensures queue() correctly handles invalid filenames."""
with self.assertRaises(pygame.error):
pygame.mixer.music.queue("")
def test_music_pause__unpause(self):
"""Ensure music has the correct position immediately after unpausing
|tags:music|
"""
filename = example_path(os.path.join("data", "house_lo.mp3"))
pygame.mixer.music.load(filename)
pygame.mixer.music.play()
# Wait 0.05s, then pause
time.sleep(0.05)
pygame.mixer.music.pause()
# Wait 0.05s, get position, unpause, then get position again
time.sleep(0.05)
before_unpause = pygame.mixer.music.get_pos()
pygame.mixer.music.unpause()
after_unpause = pygame.mixer.music.get_pos()
self.assertEqual(before_unpause, after_unpause)
def test_stop(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.stop:
# Stops the music playback if it is currently playing.
filename = example_path(os.path.join("data", "house_lo.mp3"))
pygame.mixer.music.load(filename)
pygame.mixer.music.play()
pygame.mixer.music.stop()
self.assertEqual(pygame.mixer.music.get_busy(), False)
def todo_test_rewind(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.rewind:
# Resets playback of the current music to the beginning.
self.fail()
def todo_test_get_pos(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.get_pos:
# This gets the number of milliseconds that the music has been playing
# for. The returned time only represents how long the music has been
# playing; it does not take into account any starting position
# offsets.
#
self.fail()
# def test_fadeout(self):
# filename = example_path(os.path.join("data", "house_lo.mp3"))
# pygame.mixer.music.load(filename)
# pygame.mixer.music.play()
# pygame.mixer.music.fadeout(50)
# time.sleep(0.3)
# self.assertEqual(pygame.mixer.music.get_busy(), False)
@unittest.skipIf(
os.environ.get("SDL_AUDIODRIVER") == "disk",
'disk audio driver "playback" writing to disk is slow',
)
def test_play__start_time(self):
pygame.display.init()
# music file is 7 seconds long
filename = example_path(os.path.join("data", "house_lo.ogg"))
pygame.mixer.music.load(filename)
start_time_in_seconds = 6.0 # 6 seconds
music_finished = False
clock = pygame.time.Clock()
start_time_in_ms = clock.tick()
# should play the last 1 second
pygame.mixer.music.play(0, start=start_time_in_seconds)
running = True
while running:
pygame.event.pump()
if not (pygame.mixer.music.get_busy() or music_finished):
music_finished = True
time_to_finish = (clock.tick() - start_time_in_ms) // 1000
self.assertEqual(time_to_finish, 1)
running = False
def test_play(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.play:
# This will play the loaded music stream. If the music is already
# playing it will be restarted.
#
# The loops argument controls the number of repeats a music will play.
# play(5) will cause the music to played once, then repeated five
# times, for a total of six. If the loops is -1 then the music will
# repeat indefinitely.
#
# The starting position argument controls where in the music the song
# starts playing. The starting position is dependent on the format of
# music playing. MP3 and OGG use the position as time (in seconds).
# MOD music it is the pattern order number. Passing a startpos will
# raise a NotImplementedError if it cannot set the start position
#
filename = example_path(os.path.join("data", "house_lo.mp3"))
pygame.mixer.music.load(filename)
pygame.mixer.music.play()
self.assertTrue(pygame.mixer.music.get_busy())
pygame.mixer.music.stop()
def todo_test_load(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.load:
# This will load a music file and prepare it for playback. If a music
# stream is already playing it will be stopped. This does not start
# the music playing.
#
# Music can only be loaded from filenames, not python file objects
# like the other pygame loading functions.
#
self.fail()
def test_get_volume(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.get_volume:
# Returns the current volume for the mixer. The value will be between
# 0.0 and 1.0.
#
filename = example_path(os.path.join("data", "house_lo.mp3"))
pygame.mixer.music.load(filename)
pygame.mixer.music.play()
vol = pygame.mixer.music.get_volume()
self.assertGreaterEqual(vol, 0)
self.assertLessEqual(vol, 1)
pygame.mixer.music.stop()
def todo_test_set_endevent(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.set_endevent:
# This causes Pygame to signal (by means of the event queue) when the
# music is done playing. The argument determines the type of event
# that will be queued.
#
# The event will be queued every time the music finishes, not just the
# first time. To stop the event from being queued, call this method
# with no argument.
#
self.fail()
def test_pause(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.pause:
# Temporarily stop playback of the music stream. It can be resumed
# with the pygame.mixer.music.unpause() function.
#
self.music_load("ogg")
self.assertFalse(pygame.mixer.music.get_busy())
pygame.mixer.music.play()
self.assertTrue(pygame.mixer.music.get_busy())
pygame.mixer.music.pause()
self.assertFalse(pygame.mixer.music.get_busy())
def test_get_busy(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.get_busy:
# Returns True when the music stream is actively playing. When the
# music is idle this returns False.
#
self.music_load("ogg")
self.assertFalse(pygame.mixer.music.get_busy())
pygame.mixer.music.play()
self.assertTrue(pygame.mixer.music.get_busy())
pygame.mixer.music.pause()
self.assertFalse(pygame.mixer.music.get_busy())
def todo_test_get_endevent(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.get_endevent:
# Returns the event type to be sent every time the music finishes
# playback. If there is no endevent the function returns
# pygame.NOEVENT.
#
self.fail()
def test_unpause(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.unpause:
# This will resume the playback of a music stream after it has been paused.
filename = example_path(os.path.join("data", "house_lo.mp3"))
pygame.mixer.music.load(filename)
pygame.mixer.music.play()
self.assertTrue(pygame.mixer.music.get_busy())
time.sleep(0.1)
pygame.mixer.music.pause()
self.assertFalse(pygame.mixer.music.get_busy())
before = pygame.mixer.music.get_pos()
pygame.mixer.music.unpause()
after = pygame.mixer.music.get_pos()
self.assertTrue(pygame.mixer.music.get_busy())
self.assertEqual(before, after)
pygame.mixer.music.stop()
def test_set_volume(self):
# __doc__ (as of 2008-08-02) for pygame.mixer_music.set_volume:
# Set the volume of the music playback. The value argument is between
# 0.0 and 1.0. When new music is loaded the volume is reset.
#
filename = example_path(os.path.join("data", "house_lo.mp3"))
pygame.mixer.music.load(filename)
pygame.mixer.music.play()
pygame.mixer.music.set_volume(0.5)
vol = pygame.mixer.music.get_volume()
self.assertEqual(vol, 0.5)
pygame.mixer.music.stop()
def todo_test_set_pos(self):
# __doc__ (as of 2010-24-05) for pygame.mixer_music.set_pos:
# This sets the position in the music file where playback will start. The
# meaning of "pos", a float (or a number that can be converted to a float),
# depends on the music format. Newer versions of SDL_mixer have better
# positioning support than earlier. An SDLError is raised if a particular
# format does not support positioning.
#
self.fail()
def test_init(self):
"""issue #955. unload music whenever mixer.quit() is called"""
import tempfile
import shutil
testfile = example_path(os.path.join("data", "house_lo.wav"))
tempcopy = os.path.join(tempfile.gettempdir(), "tempfile.wav")
for i in range(10):
pygame.mixer.init()
try:
shutil.copy2(testfile, tempcopy)
pygame.mixer.music.load(tempcopy)
pygame.mixer.quit()
finally:
os.remove(tempcopy)
if __name__ == "__main__":
unittest.main()

Some files were not shown because too many files have changed in this diff Show More