diff options
Diffstat (limited to 'Tests/ttLib/ttFont_test.py')
-rw-r--r-- | Tests/ttLib/ttFont_test.py | 114 |
1 files changed, 110 insertions, 4 deletions
diff --git a/Tests/ttLib/ttFont_test.py b/Tests/ttLib/ttFont_test.py index e0e82b24..2203b4d9 100644 --- a/Tests/ttLib/ttFont_test.py +++ b/Tests/ttLib/ttFont_test.py @@ -2,8 +2,16 @@ import io import os import re import random +import tempfile from fontTools.feaLib.builder import addOpenTypeFeaturesFromString -from fontTools.ttLib import TTFont, newTable, registerCustomTableClass, unregisterCustomTableClass +from fontTools.ttLib import ( + TTFont, + TTLibError, + newTable, + registerCustomTableClass, + unregisterCustomTableClass, +) +from fontTools.ttLib.standardGlyphOrder import standardGlyphOrder from fontTools.ttLib.tables.DefaultTable import DefaultTable from fontTools.ttLib.tables._c_m_a_p import CmapSubtable import pytest @@ -13,7 +21,6 @@ DATA_DIR = os.path.join(os.path.abspath(os.path.dirname(__file__)), "data") class CustomTableClass(DefaultTable): - def decompile(self, data, ttFont): self.numbers = list(data) @@ -143,6 +150,17 @@ def test_setGlyphOrder_also_updates_glyf_glyphOrder(): assert font["glyf"].glyphOrder == new_order +def test_getGlyphOrder_not_true_post_format_1(caplog): + # https://github.com/fonttools/fonttools/issues/2736 + caplog.set_level("WARNING") + font = TTFont(os.path.join(DATA_DIR, "bogus_post_format_1.ttf")) + hmtx = font["hmtx"] + assert len(hmtx.metrics) > len(standardGlyphOrder) + log_rec = caplog.records[-1] + assert log_rec.levelname == "WARNING" + assert "Not enough names found in the 'post' table" in log_rec.message + + @pytest.mark.parametrize("lazy", [None, True, False]) def test_ensureDecompiled(lazy): # test that no matter the lazy value, ensureDecompiled decompiles all tables @@ -159,7 +177,7 @@ def test_ensureDecompiled(lazy): feature dist { pos period period -30; } dist; - """ + """, ) # also add an additional cmap subtable that will be lazily-loaded cm = CmapSubtable.newSubtable(14) @@ -167,7 +185,7 @@ def test_ensureDecompiled(lazy): cm.platEncID = 5 cm.language = 0 cm.cmap = {} - cm.uvsDict = {0xFE00: [(0x002e, None)]} + cm.uvsDict = {0xFE00: [(0x002E, None)]} font["cmap"].tables.append(cm) # save and reload, potentially lazily @@ -212,3 +230,91 @@ def test_ensureDecompiled(lazy): assert "Lookup" in font["GSUB"].table.LookupList.__dict__ assert "reader" not in font["GPOS"].table.LookupList.__dict__ assert "Lookup" in font["GPOS"].table.LookupList.__dict__ + + +@pytest.fixture +def testFont_fvar_avar(): + ttxpath = os.path.join(DATA_DIR, "TestTTF_normalizeLocation.ttx") + ttf = TTFont() + ttf.importXML(ttxpath) + return ttf + + +@pytest.mark.parametrize( + "userLocation, expectedNormalizedLocation", + [ + ({}, {"wght": 0.0}), + ({"wght": 100}, {"wght": -1.0}), + ({"wght": 250}, {"wght": -0.75}), + ({"wght": 400}, {"wght": 0.0}), + ({"wght": 550}, {"wght": 0.75}), + ({"wght": 625}, {"wght": 0.875}), + ({"wght": 700}, {"wght": 1.0}), + ], +) +def test_font_normalizeLocation( + testFont_fvar_avar, userLocation, expectedNormalizedLocation +): + normalizedLocation = testFont_fvar_avar.normalizeLocation(userLocation) + assert expectedNormalizedLocation == normalizedLocation + + +def test_font_normalizeLocation_no_VF(): + ttf = TTFont() + with pytest.raises(TTLibError, match="Not a variable font"): + ttf.normalizeLocation({}) + + +def test_getGlyphID(): + font = TTFont() + font.importXML(os.path.join(DATA_DIR, "TestTTF-Regular.ttx")) + + assert font.getGlyphID("space") == 3 + assert font.getGlyphID("glyph12345") == 12345 # virtual glyph + with pytest.raises(KeyError): + font.getGlyphID("non_existent") + with pytest.raises(KeyError): + font.getGlyphID("glyph_prefix_but_invalid_id") + + +def test_spooled_tempfile_may_not_have_attribute_seekable(): + # SpooledTemporaryFile only got a seekable attribute on Python 3.11 + # https://github.com/fonttools/fonttools/issues/3052 + font = TTFont() + font.importXML(os.path.join(DATA_DIR, "TestTTF-Regular.ttx")) + tmp = tempfile.SpooledTemporaryFile() + font.save(tmp) + # this should not fail + _ = TTFont(tmp) + + +def test_unseekable_file_lazy_loading_fails(): + class NonSeekableFile: + def __init__(self): + self.file = io.BytesIO() + + def read(self, size): + return self.file.read(size) + + def seekable(self): + return False + + f = NonSeekableFile() + with pytest.raises(TTLibError, match="Input file must be seekable when lazy=True"): + TTFont(f, lazy=True) + + +def test_unsupported_seek_operation_lazy_loading_fails(): + class UnsupportedSeekFile: + def __init__(self): + self.file = io.BytesIO() + + def read(self, size): + return self.file.read(size) + + def seek(self, offset): + raise io.UnsupportedOperation("Unsupported seek operation") + + f = UnsupportedSeekFile() + with pytest.raises(TTLibError, match="Input file must be seekable when lazy=True"): + TTFont(f, lazy=True) |