3
if __name__ == '__main__':
4
pkg_dir = os.path.split(os.path.abspath(__file__))[0]
5
parent_dir, pkg_name = os.path.split(pkg_dir)
6
is_pygame_pkg = (pkg_name == 'tests' and
7
os.path.split(parent_dir)[1] == 'pygame')
9
sys.path.insert(0, parent_dir)
11
is_pygame_pkg = __name__.startswith('pygame.tests.')
15
from pygame import font as pygame_font # So font can be replaced with ftfont
16
from pygame.compat import as_unicode, as_bytes, xrange_, filesystem_errors
17
from pygame.compat import PY_MAJOR_VERSION
19
UCS_4 = sys.maxunicode > 0xFFFF
21
def equal_images(s1, s2):
23
if s2.get_size() != size:
28
if s1.get_at((x, y)) != s2.get_at((x, y)):
33
class FontModuleTest( unittest.TestCase ):
40
def test_SysFont(self):
41
# Can only check that a font object is returned.
42
fonts = pygame_font.get_fonts()
43
o = pygame_font.SysFont(fonts[0], 20)
44
self.failUnless(isinstance(o, pygame_font.FontType))
45
o = pygame_font.SysFont(fonts[0], 20, italic=True)
46
self.failUnless(isinstance(o, pygame_font.FontType))
47
o = pygame_font.SysFont(fonts[0], 20, bold=True)
48
self.failUnless(isinstance(o, pygame_font.FontType))
49
o = pygame_font.SysFont('thisisnotafont', 20)
50
self.failUnless(isinstance(o, pygame_font.FontType))
52
def test_get_default_font(self):
53
self.failUnlessEqual(pygame_font.get_default_font(), 'freesansbold.ttf')
55
def test_get_fonts_returns_something(self):
56
fnts = pygame_font.get_fonts()
60
# to test if some files exist...
61
#def XXtest_has_file_osx_10_5_sdk(self):
63
# f = "/Developer/SDKs/MacOSX10.5.sdk/usr/X11/include/ft2build.h"
64
# self.assertEqual(os.path.exists(f), True)
66
#def XXtest_has_file_osx_10_4_sdk(self):
68
# f = "/Developer/SDKs/MacOSX10.4u.sdk/usr/X11R6/include/ft2build.h"
69
# self.assertEqual(os.path.exists(f), True)
75
def test_get_fonts(self):
76
fnts = pygame_font.get_fonts()
79
raise Exception(repr(fnts))
83
if (PY_MAJOR_VERSION >= 3):
84
# For Python 3.x, names will always be unicode strings.
87
# For Python 2.x, names may be either unicode or ascii strings.
88
name_types = (str, unicode)
91
# note, on ubuntu 2.6 they are all unicode strings.
93
self.failUnless(isinstance(name, name_types), name)
94
self.failUnless(name.islower(), name)
95
self.failUnless(name.isalnum(), name)
97
def test_get_init(self):
98
self.failUnless(pygame_font.get_init())
100
self.failIf(pygame_font.get_init())
105
def test_match_font_all_exist(self):
106
fonts = pygame_font.get_fonts()
108
# Ensure all listed fonts are in fact available, and the returned file
109
# name is a full path.
111
path = pygame_font.match_font(font)
112
self.failIf(path is None)
113
self.failUnless(os.path.isabs(path))
115
def test_match_font_bold(self):
117
fonts = pygame_font.get_fonts()
119
# Look for a bold font.
121
if pygame_font.match_font(font, bold=True) is not None:
126
def test_match_font_italic(self):
128
fonts = pygame_font.get_fonts()
130
# Look for an italic font.
132
if pygame_font.match_font(font, italic=True) is not None:
138
def test_match_font_comma_separated(self):
140
fonts = pygame_font.get_fonts()
142
# Check for not found.
143
self.failUnless(pygame_font.match_font('thisisnotafont') is None)
145
# Check comma separated list.
146
names = ','.join(['thisisnotafont', fonts[-1], 'anothernonfont'])
147
self.failIf(pygame_font.match_font(names) is None)
148
names = ','.join(['thisisnotafont1', 'thisisnotafont2', 'thisisnotafont3'])
149
self.failUnless(pygame_font.match_font(names) is None)
160
class FontTest(unittest.TestCase):
168
def test_render_args(self):
169
screen = pygame.display.set_mode((600, 400))
170
rect = screen.get_rect()
171
f = pygame_font.Font(None, 20)
172
screen.fill((10, 10, 10))
173
font_surface = f.render(" bar", True, (0, 0, 0), (255, 255, 255))
174
font_rect = font_surface.get_rect()
175
font_rect.topleft = rect.topleft
176
self.assertTrue(font_surface)
177
screen.blit(font_surface, font_rect, font_rect)
178
pygame.display.update()
179
self.assertEqual(tuple(screen.get_at((0,0)))[:3], (255, 255, 255))
180
self.assertEqual(tuple(screen.get_at(font_rect.topleft))[:3], (255, 255, 255))
182
# If we don't have a real display, don't do this test.
183
# Transparent background doesn't seem to work without a read video card.
184
if os.environ.get('SDL_VIDEODRIVER') != 'dummy':
185
screen.fill((10, 10, 10))
186
font_surface = f.render(" bar", True, (0, 0, 0), None)
187
font_rect = font_surface.get_rect()
188
font_rect.topleft = rect.topleft
189
self.assertTrue(font_surface)
190
screen.blit(font_surface, font_rect, font_rect)
191
pygame.display.update()
192
self.assertEqual(tuple(screen.get_at((0,0)))[:3], (10, 10, 10))
193
self.assertEqual(tuple(screen.get_at(font_rect.topleft))[:3], (10, 10, 10))
195
screen.fill((10, 10, 10))
196
font_surface = f.render(" bar", True, (0, 0, 0))
197
font_rect = font_surface.get_rect()
198
font_rect.topleft = rect.topleft
199
self.assertTrue(font_surface)
200
screen.blit(font_surface, font_rect, font_rect)
201
pygame.display.update(rect)
202
self.assertEqual(tuple(screen.get_at((0,0)))[:3], (10, 10, 10))
203
self.assertEqual(tuple(screen.get_at(font_rect.topleft))[:3], (10, 10, 10))
211
class FontTypeTest( unittest.TestCase ):
218
def test_get_ascent(self):
219
# Ckecking ascent would need a custom test font to do properly.
220
f = pygame_font.Font(None, 20)
221
ascent = f.get_ascent()
222
self.failUnless(isinstance(ascent, int))
223
self.failUnless(ascent > 0)
224
s = f.render("X", False, (255, 255, 255))
225
self.failUnless(s.get_size()[1] > ascent)
227
def test_get_descent(self):
228
# Ckecking descent would need a custom test font to do properly.
229
f = pygame_font.Font(None, 20)
230
descent = f.get_descent()
231
self.failUnless(isinstance(descent, int))
232
self.failUnless(descent < 0)
234
def test_get_height(self):
235
# Ckecking height would need a custom test font to do properly.
236
f = pygame_font.Font(None, 20)
237
height = f.get_height()
238
self.failUnless(isinstance(height, int))
239
self.failUnless(height > 0)
240
s = f.render("X", False, (255, 255, 255))
241
self.failUnless(s.get_size()[1] == height)
243
def test_get_linesize(self):
244
# Ckecking linesize would need a custom test font to do properly.
245
# Questions: How do linesize, height and descent relate?
246
f = pygame_font.Font(None, 20)
247
linesize = f.get_linesize()
248
self.failUnless(isinstance(linesize, int))
249
self.failUnless(linesize > 0)
251
def test_metrics(self):
252
# Ensure bytes decoding works correctly. Can only compare results
253
# with unicode for now.
254
f = pygame_font.Font(None, 20)
255
um = f.metrics(as_unicode("."))
256
bm = f.metrics(as_bytes("."))
257
self.assert_(len(um) == 1)
258
self.assert_(len(bm) == 1)
259
self.assert_(um[0] is not None)
260
self.assert_(um == bm)
261
u = as_unicode(r"\u212A")
262
b = u.encode("UTF-16")[2:] # Keep byte order consistent. [2:] skips BOM
264
self.assert_(len(bm) == 2)
270
self.assert_(len(um) == 1)
271
self.assert_(bm[0] != um[0])
272
self.assert_(bm[1] != um[0])
275
u = as_unicode(r"\U00013000")
277
self.assert_(len(bm) == 1 and bm[0] is None)
280
# The documentation is useless here. How large a list?
281
# How do list positions relate to character codes?
282
# What about unicode characters?
284
# __doc__ (as of 2008-08-02) for pygame_font.Font.metrics:
286
# Font.metrics(text): return list
287
# Gets the metrics for each character in the pased string.
289
# The list contains tuples for each character, which contain the
290
# minimum X offset, the maximum X offset, the minimum Y offset, the
291
# maximum Y offset and the advance offset (bearing plus width) of the
292
# character. [(minx, maxx, miny, maxy, advance), (minx, maxx, miny,
293
# maxy, advance), ...]
297
def test_render(self):
301
f = pygame_font.Font(None, 20)
302
s = f.render("foo", True, [0, 0, 0], [255, 255, 255])
303
s = f.render("xxx", True, [0, 0, 0], [255, 255, 255])
304
s = f.render("", True, [0, 0, 0], [255, 255, 255])
305
s = f.render("foo", False, [0, 0, 0], [255, 255, 255])
306
s = f.render("xxx", False, [0, 0, 0], [255, 255, 255])
307
s = f.render("xxx", False, [0, 0, 0])
308
s = f.render(" ", False, [0, 0, 0])
309
s = f.render(" ", False, [0, 0, 0], [255, 255, 255])
310
# null text should be 1 pixel wide.
311
s = f.render("", False, [0, 0, 0], [255, 255, 255])
312
self.assertEqual(s.get_size()[0], 1)
313
# None text should be 1 pixel wide.
314
s = f.render(None, False, [0, 0, 0], [255, 255, 255])
315
self.assertEqual(s.get_size()[0], 1)
316
# Non-text should raise a TypeError.
317
self.assertRaises(TypeError, f.render,
318
[], False, [0, 0, 0], [255, 255, 255])
319
self.assertRaises(TypeError, f.render,
320
1, False, [0, 0, 0], [255, 255, 255])
321
# is background transparent for antialiasing?
322
s = f.render(".", True, [255, 255, 255])
323
self.failUnlessEqual(s.get_at((0, 0))[3], 0)
324
# is Unicode and bytes encoding correct?
325
# Cannot really test if the correct characters are rendered, but
326
# at least can assert the encodings differ.
327
su = f.render(as_unicode("."), False, [0, 0, 0], [255, 255, 255])
328
sb = f.render(as_bytes("."), False, [0, 0, 0], [255, 255, 255])
329
self.assert_(equal_images(su, sb))
330
u = as_unicode(r"\u212A")
331
b = u.encode("UTF-16")[2:] # Keep byte order consistent. [2:] skips BOM
332
sb = f.render(b, False, [0, 0, 0], [255, 255, 255])
334
su = f.render(u, False, [0, 0, 0], [255, 255, 255])
338
self.assert_(not equal_images(su, sb))
340
# If the font module is SDL_ttf based, then it can only supports UCS-2;
341
# it will raise an exception for an out-of-range UCS-4 code point.
342
if UCS_4 and not hasattr(f, 'ucs4'):
343
ucs_2 = as_unicode(r"\uFFEE")
344
s = f.render(ucs_2, False, [0, 0, 0], [255, 255, 255])
345
ucs_4 = as_unicode(r"\U00010000")
346
self.assertRaises(UnicodeError, f.render,
347
ucs_4, False, [0, 0, 0], [255, 255, 255])
349
b = as_bytes("ab\x00cd")
350
self.assertRaises(ValueError, f.render, b, 0, [0, 0, 0])
351
u = as_unicode("ab\x00cd")
352
self.assertRaises(ValueError, f.render, b, 0, [0, 0, 0])
354
# __doc__ (as of 2008-08-02) for pygame_font.Font.render:
356
# Font.render(text, antialias, color, background=None): return Surface
357
# draw text on a new Surface
359
# This creates a new Surface with the specified text rendered on it.
360
# Pygame provides no way to directly draw text on an existing Surface:
361
# instead you must use Font.render() to create an image (Surface) of
362
# the text, then blit this image onto another Surface.
364
# The text can only be a single line: newline characters are not
365
# rendered. The antialias argument is a boolean: if true the
366
# characters will have smooth edges. The color argument is the color
367
# of the text [e.g.: (0,0,255) for blue]. The optional background
368
# argument is a color to use for the text background. If no background
369
# is passed the area outside the text will be transparent.
371
# The Surface returned will be of the dimensions required to hold the
372
# text. (the same as those returned by Font.size()). If an empty
373
# string is passed for the text, a blank surface will be returned that
374
# is one pixel wide and the height of the font.
376
# Depending on the type of background and antialiasing used, this
377
# returns different types of Surfaces. For performance reasons, it is
378
# good to know what type of image will be used. If antialiasing is not
379
# used, the return image will always be an 8bit image with a two color
380
# palette. If the background is transparent a colorkey will be set.
381
# Antialiased images are rendered to 24-bit RGB images. If the
382
# background is transparent a pixel alpha will be included.
384
# Optimization: if you know that the final destination for the text
385
# (on the screen) will always have a solid background, and the text is
386
# antialiased, you can improve performance by specifying the
387
# background color. This will cause the resulting image to maintain
388
# transparency information by colorkey rather than (much less
389
# efficient) alpha values.
391
# If you render '\n' a unknown char will be rendered. Usually a
392
# rectangle. Instead you need to handle new lines yourself.
394
# Font rendering is not thread safe: only a single thread can render
398
def test_set_bold(self):
399
f = pygame_font.Font(None, 20)
400
self.failIf(f.get_bold())
402
self.failUnless(f.get_bold())
404
self.failIf(f.get_bold())
406
def test_set_italic(self):
407
f = pygame_font.Font(None, 20)
408
self.failIf(f.get_italic())
410
self.failUnless(f.get_italic())
412
self.failIf(f.get_italic())
414
def test_set_underline(self):
415
f = pygame_font.Font(None, 20)
416
self.failIf(f.get_underline())
417
f.set_underline(True)
418
self.failUnless(f.get_underline())
419
f.set_underline(False)
420
self.failIf(f.get_underline())
423
f = pygame_font.Font(None, 20)
424
text = as_unicode("Xg")
427
self.assert_(isinstance(w, int) and isinstance(h, int))
428
s = f.render(text, False, (255, 255, 255))
429
self.assert_(size == s.get_size())
430
btext = text.encode("ascii")
431
self.assert_(f.size(btext) == size)
432
text = as_unicode(r"\u212A")
433
btext = text.encode("UTF-16")[2:] # Keep the byte order consistent.
434
bsize = f.size(btext)
440
self.assert_(size != bsize)
442
def test_font_file_not_found(self):
443
# A per BUG reported by Bo Jangeborg on pygame-user mailing list,
444
# http://www.mail-archive.com/pygame-users@seul.org/msg11675.html
447
self.failUnlessRaises(IOError,
449
'some-fictional-font.ttf', 20)
451
def test_load_from_file(self):
452
font_name = pygame_font.get_default_font()
453
font_path = os.path.join(os.path.split(pygame.__file__)[0],
454
pygame_font.get_default_font())
455
f = pygame_font.Font(font_path, 20)
457
def test_load_from_file_obj(self):
458
font_name = pygame_font.get_default_font()
459
font_path = os.path.join(os.path.split(pygame.__file__)[0],
460
pygame_font.get_default_font())
461
f = open(font_path, "rb")
462
font = pygame_font.Font(f, 20)
464
def test_load_default_font_filename(self):
465
# In font_init, a special case is when the filename argument is
466
# identical to the default font file name.
467
f = pygame_font.Font(pygame_font.get_default_font(), 20)
469
def test_load_from_file_unicode(self):
470
base_dir = os.path.dirname(pygame.__file__)
471
font_path = os.path.join(base_dir, pygame_font.get_default_font())
472
if os.path.sep == '\\':
473
font_path = font_path.replace('\\', '\\\\')
474
ufont_path = as_unicode(font_path)
475
f = pygame_font.Font(ufont_path, 20)
477
def test_load_from_file_bytes(self):
478
font_path = os.path.join(os.path.split(pygame.__file__)[0],
479
pygame_font.get_default_font())
480
filesystem_encoding = sys.getfilesystemencoding()
482
font_path = font_path.decode(filesystem_encoding,
484
except AttributeError:
486
bfont_path = font_path.encode(filesystem_encoding,
488
f = pygame_font.Font(bfont_path, 20)
490
class VisualTests( unittest.TestCase ):
491
__tags__ = ['interactive']
497
if self.screen is None:
499
self.screen = pygame.display.set_mode((600, 200))
500
self.screen.fill((255, 255, 255))
501
pygame.display.flip()
502
self.f = pygame_font.Font(None, 32)
505
if self.screen is not None:
510
bold=False, italic=False, underline=False, antialiase=False):
518
screen.fill((255, 255, 255))
519
pygame.display.flip()
520
if not (bold or italic or underline or antialiase):
527
modes.append("italic")
529
modes.append("underlined")
531
modes.append("antialiased")
532
text = "%s (y/n):" % ('-'.join(modes),)
535
f.set_underline(underline)
536
s = f.render(text, antialiase, (0, 0, 0))
537
screen.blit(s, (offset, y))
538
y += s.get_size()[1] + spacing
541
f.set_underline(False)
542
s = f.render("(some comparison text)", False, (0, 0, 0))
543
screen.blit(s, (offset, y))
544
pygame.display.flip()
546
for evt in pygame.event.get():
547
if evt.type == pygame.KEYDOWN:
548
if evt.key == pygame.K_ESCAPE:
551
if evt.key == pygame.K_y:
553
if evt.key == pygame.K_n:
555
if evt.type == pygame.QUIT:
560
self.failUnless(self.query(bold=True))
562
def test_italic(self):
563
self.failUnless(self.query(italic=True))
565
def test_underline(self):
566
self.failUnless(self.query(underline=True))
568
def test_antialiase(self):
569
self.failUnless(self.query(antialiase=True))
571
def test_bold_antialiase(self):
572
self.failUnless(self.query(bold=True, antialiase=True))
574
def test_italic_underline(self):
575
self.failUnless(self.query(italic=True, underline=True))
578
if __name__ == '__main__':