aboutsummaryrefslogtreecommitdiff
path: root/Tests/subset/subset_test.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tests/subset/subset_test.py')
-rw-r--r--Tests/subset/subset_test.py422
1 files changed, 250 insertions, 172 deletions
diff --git a/Tests/subset/subset_test.py b/Tests/subset/subset_test.py
index d195af0f..facafb2a 100644
--- a/Tests/subset/subset_test.py
+++ b/Tests/subset/subset_test.py
@@ -1,5 +1,6 @@
import io
-from fontTools.misc.testTools import getXML
+import fontTools.ttLib.tables.otBase
+from fontTools.misc.testTools import getXML, stripVariableItemsFromTTX
from fontTools.misc.textTools import tobytes, tostr
from fontTools import subset
from fontTools.fontBuilder import FontBuilder
@@ -19,44 +20,36 @@ import pathlib
import pytest
-class SubsetTest(unittest.TestCase):
- def __init__(self, methodName):
- unittest.TestCase.__init__(self, methodName)
- # Python 3 renamed assertRaisesRegexp to assertRaisesRegex,
- # and fires deprecation warnings if a program uses the old name.
- if not hasattr(self, "assertRaisesRegex"):
- self.assertRaisesRegex = self.assertRaisesRegexp
+class SubsetTest:
+ @classmethod
+ def setup_class(cls):
+ cls.tempdir = None
+ cls.num_tempfiles = 0
- def setUp(self):
- self.tempdir = None
- self.num_tempfiles = 0
-
- def tearDown(self):
- if self.tempdir:
- shutil.rmtree(self.tempdir)
+ @classmethod
+ def teardown_class(cls):
+ if cls.tempdir:
+ shutil.rmtree(cls.tempdir, ignore_errors=True)
@staticmethod
def getpath(testfile):
path, _ = os.path.split(__file__)
return os.path.join(path, "data", testfile)
- def temp_path(self, suffix):
- if not self.tempdir:
- self.tempdir = tempfile.mkdtemp()
- self.num_tempfiles += 1
- return os.path.join(self.tempdir,
- "tmp%d%s" % (self.num_tempfiles, suffix))
-
- def read_ttx(self, path):
- lines = []
- with open(path, "r", encoding="utf-8") as ttx:
- for line in ttx.readlines():
- # Elide ttFont attributes because ttLibVersion may change.
- if line.startswith("<ttFont "):
- lines.append("<ttFont>\n")
- else:
- lines.append(line.rstrip() + "\n")
- return lines
+ @classmethod
+ def temp_path(cls, suffix):
+ if not cls.tempdir:
+ cls.tempdir = tempfile.mkdtemp()
+ cls.num_tempfiles += 1
+ return os.path.join(cls.tempdir,
+ "tmp%d%s" % (cls.num_tempfiles, suffix))
+
+ @staticmethod
+ def read_ttx(path):
+ with open(path, "r", encoding="utf-8") as f:
+ ttx = f.read()
+ # don't care whether TTF or OTF, thus strip sfntVersion as well
+ return stripVariableItemsFromTTX(ttx, sfntVersion=True).splitlines(True)
def expect_ttx(self, font, expected_ttx, tables=None):
path = self.temp_path(suffix=".ttx")
@@ -67,21 +60,21 @@ class SubsetTest(unittest.TestCase):
for line in difflib.unified_diff(
expected, actual, fromfile=expected_ttx, tofile=path):
sys.stdout.write(line)
- self.fail("TTX output is different from expected")
+ pytest.fail("TTX output is different from expected")
def compile_font(self, path, suffix):
savepath = self.temp_path(suffix=suffix)
font = TTFont(recalcBBoxes=False, recalcTimestamp=False)
font.importXML(path)
font.save(savepath, reorderTables=None)
- return font, savepath
+ return savepath
# -----
# Tests
# -----
def test_layout_scripts(self):
- _, fontpath = self.compile_font(self.getpath("layout_scripts.ttx"), ".otf")
+ fontpath = self.compile_font(self.getpath("layout_scripts.ttx"), ".otf")
subsetpath = self.temp_path(".otf")
subset.main([fontpath, "--glyphs=*", "--layout-features=*",
"--layout-scripts=latn,arab.URD,arab.dflt",
@@ -91,41 +84,41 @@ class SubsetTest(unittest.TestCase):
["GPOS", "GSUB"])
def test_no_notdef_outline_otf(self):
- _, fontpath = self.compile_font(self.getpath("TestOTF-Regular.ttx"), ".otf")
+ fontpath = self.compile_font(self.getpath("TestOTF-Regular.ttx"), ".otf")
subsetpath = self.temp_path(".otf")
subset.main([fontpath, "--no-notdef-outline", "--gids=0", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_no_notdef_outline_otf.ttx"), ["CFF "])
def test_no_notdef_outline_cid(self):
- _, fontpath = self.compile_font(self.getpath("TestCID-Regular.ttx"), ".otf")
+ fontpath = self.compile_font(self.getpath("TestCID-Regular.ttx"), ".otf")
subsetpath = self.temp_path(".otf")
subset.main([fontpath, "--no-notdef-outline", "--gids=0", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_no_notdef_outline_cid.ttx"), ["CFF "])
def test_no_notdef_outline_ttf(self):
- _, fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--no-notdef-outline", "--gids=0", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_no_notdef_outline_ttf.ttx"), ["glyf", "hmtx"])
def test_subset_ankr(self):
- _, fontpath = self.compile_font(self.getpath("TestANKR.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestANKR.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--glyphs=one", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_ankr.ttx"), ["ankr"])
def test_subset_ankr_remove(self):
- _, fontpath = self.compile_font(self.getpath("TestANKR.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestANKR.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--glyphs=two", "--output-file=%s" % subsetpath])
- self.assertNotIn("ankr", TTFont(subsetpath))
+ assert "ankr" not in TTFont(subsetpath)
def test_subset_bsln_format_0(self):
- _, fontpath = self.compile_font(self.getpath("TestBSLN-0.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestBSLN-0.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--glyphs=one", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
@@ -138,7 +131,7 @@ class SubsetTest(unittest.TestCase):
# a subsetted font with {zero, one} and the implicit .notdef, all
# glyphs in the resulting font use the Roman baseline. In this case,
# we expect a format 0 'bsln' table because it is the most compact.
- _, fontpath = self.compile_font(self.getpath("TestBSLN-1.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestBSLN-1.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+0030-0031",
"--output-file=%s" % subsetpath])
@@ -154,7 +147,7 @@ class SubsetTest(unittest.TestCase):
# subsetted font, we expect a format 1 'bsln' table whose default
# is Roman, but with an override that uses the ideographic baseline
# for uni2EA2.
- _, fontpath = self.compile_font(self.getpath("TestBSLN-1.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestBSLN-1.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+0030-0031,U+2EA2",
"--output-file=%s" % subsetpath])
@@ -165,7 +158,7 @@ class SubsetTest(unittest.TestCase):
# The 'bsln' table in TestBSLN-2 refers to control points in glyph 'P'
# for defining its baselines. Therefore, the subsetted font should
# include this glyph even though it is not requested explicitly.
- _, fontpath = self.compile_font(self.getpath("TestBSLN-2.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestBSLN-2.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--glyphs=one", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
@@ -179,7 +172,7 @@ class SubsetTest(unittest.TestCase):
# baseline measurement, all glyphs in the resulting font use the Roman
# baseline. In this case, we expect a format 2 'bsln' table because it
# is the most compact encoding.
- _, fontpath = self.compile_font(self.getpath("TestBSLN-3.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestBSLN-3.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+0030",
"--output-file=%s" % subsetpath])
@@ -195,7 +188,7 @@ class SubsetTest(unittest.TestCase):
# subsetted font, we expect a format 1 'bsln' table whose default
# is Roman, but with an override that uses the ideographic baseline
# for uni2EA2.
- _, fontpath = self.compile_font(self.getpath("TestBSLN-3.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestBSLN-3.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+0030-0031,U+2EA2",
"--output-file=%s" % subsetpath])
@@ -203,35 +196,35 @@ class SubsetTest(unittest.TestCase):
self.expect_ttx(subsetfont, self.getpath("expect_bsln_3.ttx"), ["bsln"])
def test_subset_clr(self):
- _, fontpath = self.compile_font(self.getpath("TestCLR-Regular.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestCLR-Regular.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--glyphs=smileface", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_keep_colr.ttx"), ["GlyphOrder", "hmtx", "glyf", "COLR", "CPAL"])
def test_subset_gvar(self):
- _, fontpath = self.compile_font(self.getpath("TestGVAR.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestGVAR.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+002B,U+2212", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_keep_gvar.ttx"), ["GlyphOrder", "avar", "fvar", "gvar", "name"])
def test_subset_gvar_notdef_outline(self):
- _, fontpath = self.compile_font(self.getpath("TestGVAR.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestGVAR.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+0030", "--notdef_outline", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_keep_gvar_notdef_outline.ttx"), ["GlyphOrder", "avar", "fvar", "gvar", "name"])
def test_subset_lcar_remove(self):
- _, fontpath = self.compile_font(self.getpath("TestLCAR-0.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestLCAR-0.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--glyphs=one", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
- self.assertNotIn("lcar", subsetfont)
+ assert "lcar" not in subsetfont
def test_subset_lcar_format_0(self):
- _, fontpath = self.compile_font(self.getpath("TestLCAR-0.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestLCAR-0.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+FB01",
"--output-file=%s" % subsetpath])
@@ -239,7 +232,7 @@ class SubsetTest(unittest.TestCase):
self.expect_ttx(subsetfont, self.getpath("expect_lcar_0.ttx"), ["lcar"])
def test_subset_lcar_format_1(self):
- _, fontpath = self.compile_font(self.getpath("TestLCAR-1.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestLCAR-1.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+FB01",
"--output-file=%s" % subsetpath])
@@ -247,14 +240,14 @@ class SubsetTest(unittest.TestCase):
self.expect_ttx(subsetfont, self.getpath("expect_lcar_1.ttx"), ["lcar"])
def test_subset_math(self):
- _, fontpath = self.compile_font(self.getpath("TestMATH-Regular.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestMATH-Regular.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+0041,U+0028,U+0302,U+1D400,U+1D435", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_keep_math.ttx"), ["GlyphOrder", "CFF ", "MATH", "hmtx"])
def test_subset_math_partial(self):
- _, fontpath = self.compile_font(self.getpath("test_math_partial.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("test_math_partial.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--text=A", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
@@ -265,21 +258,21 @@ class SubsetTest(unittest.TestCase):
# the Optical Bounds table. When subsetting, we do not request any
# of those glyphs. Therefore, the produced subsetted font should
# not contain an 'opbd' table.
- _, fontpath = self.compile_font(self.getpath("TestOPBD-0.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestOPBD-0.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--glyphs=one", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
- self.assertNotIn("opbd", subsetfont)
+ assert "opbd" not in subsetfont
def test_subset_opbd_format_0(self):
- _, fontpath = self.compile_font(self.getpath("TestOPBD-0.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestOPBD-0.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--glyphs=A", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_opbd_0.ttx"), ["opbd"])
def test_subset_opbd_format_1(self):
- _, fontpath = self.compile_font(self.getpath("TestOPBD-1.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestOPBD-1.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--glyphs=A", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
@@ -288,12 +281,12 @@ class SubsetTest(unittest.TestCase):
def test_subset_prop_remove_default_zero(self):
# If all glyphs have an AAT glyph property with value 0,
# the "prop" table should be removed from the subsetted font.
- _, fontpath = self.compile_font(self.getpath("TestPROP.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestPROP.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+0041",
"--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
- self.assertNotIn("prop", subsetfont)
+ assert "prop" not in subsetfont
def test_subset_prop_0(self):
# If all glyphs share the same AAT glyph properties, the "prop" table
@@ -302,7 +295,7 @@ class SubsetTest(unittest.TestCase):
# Unless the shared value is zero, in which case the subsetted font
# should have no "prop" table at all. But that case has already been
# tested above in test_subset_prop_remove_default_zero().
- _, fontpath = self.compile_font(self.getpath("TestPROP.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestPROP.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+0030-0032", "--no-notdef-glyph",
"--output-file=%s" % subsetpath])
@@ -313,7 +306,7 @@ class SubsetTest(unittest.TestCase):
# If not all glyphs share the same AAT glyph properties, the subsetted
# font should contain a "prop" table in format 1. To save space, the
# DefaultProperties should be set to the most frequent value.
- _, fontpath = self.compile_font(self.getpath("TestPROP.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestPROP.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=U+0030-0032", "--notdef-outline",
"--output-file=%s" % subsetpath])
@@ -323,32 +316,32 @@ class SubsetTest(unittest.TestCase):
def test_options(self):
# https://github.com/fonttools/fonttools/issues/413
opt1 = subset.Options()
- self.assertTrue('Xyz-' not in opt1.layout_features)
+ assert 'Xyz-' not in opt1.layout_features
opt2 = subset.Options()
opt2.layout_features.append('Xyz-')
- self.assertTrue('Xyz-' in opt2.layout_features)
- self.assertTrue('Xyz-' not in opt1.layout_features)
+ assert 'Xyz-' in opt2.layout_features
+ assert 'Xyz-' not in opt1.layout_features
def test_google_color(self):
- _, fontpath = self.compile_font(self.getpath("google_color.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("google_color.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--gids=0,1", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
- self.assertTrue("CBDT" in subsetfont)
- self.assertTrue("CBLC" in subsetfont)
- self.assertTrue("x" in subsetfont['CBDT'].strikeData[0])
- self.assertFalse("y" in subsetfont['CBDT'].strikeData[0])
+ assert "CBDT" in subsetfont
+ assert "CBLC" in subsetfont
+ assert "x" in subsetfont['CBDT'].strikeData[0]
+ assert "y" not in subsetfont['CBDT'].strikeData[0]
def test_google_color_all(self):
- _, fontpath = self.compile_font(self.getpath("google_color.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("google_color.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=*", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
- self.assertTrue("x" in subsetfont['CBDT'].strikeData[0])
- self.assertTrue("y" in subsetfont['CBDT'].strikeData[0])
+ assert "x" in subsetfont['CBDT'].strikeData[0]
+ assert "y" in subsetfont['CBDT'].strikeData[0]
def test_sbix(self):
- _, fontpath = self.compile_font(self.getpath("sbix.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("sbix.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--gids=0,1", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
@@ -356,7 +349,7 @@ class SubsetTest(unittest.TestCase):
"expect_sbix.ttx"), ["sbix"])
def test_timing_publishes_parts(self):
- _, fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
options = subset.Options()
options.timing = True
@@ -367,15 +360,15 @@ class SubsetTest(unittest.TestCase):
subsetter.subset(font)
logs = captor.records
- self.assertTrue(len(logs) > 5)
- self.assertEqual(len(logs), len([l for l in logs if 'msg' in l.args and 'time' in l.args]))
+ assert len(logs) > 5
+ assert len(logs) == len([l for l in logs if 'msg' in l.args and 'time' in l.args])
# Look for a few things we know should happen
- self.assertTrue(filter(lambda l: l.args['msg'] == "load 'cmap'", logs))
- self.assertTrue(filter(lambda l: l.args['msg'] == "subset 'cmap'", logs))
- self.assertTrue(filter(lambda l: l.args['msg'] == "subset 'glyf'", logs))
+ assert filter(lambda l: l.args['msg'] == "load 'cmap'", logs)
+ assert filter(lambda l: l.args['msg'] == "subset 'cmap'", logs)
+ assert filter(lambda l: l.args['msg'] == "subset 'glyf'", logs)
def test_passthrough_tables(self):
- _, fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
font = TTFont(fontpath)
unknown_tag = 'ZZZZ'
unknown_table = newTable(unknown_tag)
@@ -388,17 +381,17 @@ class SubsetTest(unittest.TestCase):
subsetfont = TTFont(subsetpath)
# tables we can't subset are dropped by default
- self.assertFalse(unknown_tag in subsetfont)
+ assert unknown_tag not in subsetfont
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--passthrough-tables", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
# unknown tables are kept if --passthrough-tables option is passed
- self.assertTrue(unknown_tag in subsetfont)
+ assert unknown_tag in subsetfont
def test_non_BMP_text_arg_input(self):
- _, fontpath = self.compile_font(
+ fontpath = self.compile_font(
self.getpath("TestTTF-Regular_non_BMP_char.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
text = tostr(u"A\U0001F6D2", encoding='utf-8')
@@ -406,11 +399,11 @@ class SubsetTest(unittest.TestCase):
subset.main([fontpath, "--text=%s" % text, "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
- self.assertEqual(subsetfont['maxp'].numGlyphs, 3)
- self.assertEqual(subsetfont.getGlyphOrder(), ['.notdef', 'A', 'u1F6D2'])
+ assert subsetfont['maxp'].numGlyphs == 3
+ assert subsetfont.getGlyphOrder() == ['.notdef', 'A', 'u1F6D2']
def test_non_BMP_text_file_input(self):
- _, fontpath = self.compile_font(
+ fontpath = self.compile_font(
self.getpath("TestTTF-Regular_non_BMP_char.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
text = tobytes(u"A\U0001F6D2", encoding='utf-8')
@@ -424,12 +417,12 @@ class SubsetTest(unittest.TestCase):
finally:
os.remove(tmp.name)
- self.assertEqual(subsetfont['maxp'].numGlyphs, 3)
- self.assertEqual(subsetfont.getGlyphOrder(), ['.notdef', 'A', 'u1F6D2'])
+ assert subsetfont['maxp'].numGlyphs == 3
+ assert subsetfont.getGlyphOrder() == ['.notdef', 'A', 'u1F6D2']
def test_no_hinting_CFF(self):
ttxpath = self.getpath("Lobster.subset.ttx")
- _, fontpath = self.compile_font(ttxpath, ".otf")
+ fontpath = self.compile_font(ttxpath, ".otf")
subsetpath = self.temp_path(".otf")
subset.main([fontpath, "--no-hinting", "--notdef-outline",
"--output-file=%s" % subsetpath, "*"])
@@ -439,7 +432,7 @@ class SubsetTest(unittest.TestCase):
def test_desubroutinize_CFF(self):
ttxpath = self.getpath("Lobster.subset.ttx")
- _, fontpath = self.compile_font(ttxpath, ".otf")
+ fontpath = self.compile_font(ttxpath, ".otf")
subsetpath = self.temp_path(".otf")
subset.main([fontpath, "--desubroutinize", "--notdef-outline",
"--output-file=%s" % subsetpath, "*"])
@@ -449,7 +442,7 @@ class SubsetTest(unittest.TestCase):
def test_desubroutinize_hinted_subrs_CFF(self):
ttxpath = self.getpath("test_hinted_subrs_CFF.ttx")
- _, fontpath = self.compile_font(ttxpath, ".otf")
+ fontpath = self.compile_font(ttxpath, ".otf")
subsetpath = self.temp_path(".otf")
subset.main([fontpath, "--desubroutinize", "--notdef-outline",
"--output-file=%s" % subsetpath, "*"])
@@ -459,7 +452,7 @@ class SubsetTest(unittest.TestCase):
def test_desubroutinize_cntrmask_CFF(self):
ttxpath = self.getpath("test_cntrmask_CFF.ttx")
- _, fontpath = self.compile_font(ttxpath, ".otf")
+ fontpath = self.compile_font(ttxpath, ".otf")
subsetpath = self.temp_path(".otf")
subset.main([fontpath, "--desubroutinize", "--notdef-outline",
"--output-file=%s" % subsetpath, "*"])
@@ -469,7 +462,7 @@ class SubsetTest(unittest.TestCase):
def test_no_hinting_desubroutinize_CFF(self):
ttxpath = self.getpath("test_hinted_subrs_CFF.ttx")
- _, fontpath = self.compile_font(ttxpath, ".otf")
+ fontpath = self.compile_font(ttxpath, ".otf")
subsetpath = self.temp_path(".otf")
subset.main([fontpath, "--no-hinting", "--desubroutinize", "--notdef-outline",
"--output-file=%s" % subsetpath, "*"])
@@ -478,7 +471,7 @@ class SubsetTest(unittest.TestCase):
"expect_no_hinting_desubroutinize_CFF.ttx"), ["CFF "])
def test_no_hinting_TTF(self):
- _, fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--no-hinting", "--notdef-outline",
"--output-file=%s" % subsetpath, "*"])
@@ -486,11 +479,11 @@ class SubsetTest(unittest.TestCase):
self.expect_ttx(subsetfont, self.getpath(
"expect_no_hinting_TTF.ttx"), ["glyf", "maxp"])
for tag in subset.Options().hinting_tables:
- self.assertTrue(tag not in subsetfont)
+ assert tag not in subsetfont
def test_notdef_width_cid(self):
# https://github.com/fonttools/fonttools/pull/845
- _, fontpath = self.compile_font(self.getpath("NotdefWidthCID-Regular.ttx"), ".otf")
+ fontpath = self.compile_font(self.getpath("NotdefWidthCID-Regular.ttx"), ".otf")
subsetpath = self.temp_path(".otf")
subset.main([fontpath, "--no-notdef-outline", "--gids=0,1", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
@@ -503,18 +496,18 @@ class SubsetTest(unittest.TestCase):
head = font['head']
bounds = [head.xMin, head.yMin, head.xMax, head.yMax]
- _, fontpath = self.compile_font(ttxpath, ".ttf")
+ fontpath = self.compile_font(ttxpath, ".ttf")
subsetpath = self.temp_path(".ttf")
# by default, the subsetter does not recalculate the bounding box
subset.main([fontpath, "--output-file=%s" % subsetpath, "*"])
head = TTFont(subsetpath)['head']
- self.assertEqual(bounds, [head.xMin, head.yMin, head.xMax, head.yMax])
+ assert bounds == [head.xMin, head.yMin, head.xMax, head.yMax]
subset.main([fontpath, "--recalc-bounds", "--output-file=%s" % subsetpath, "*"])
head = TTFont(subsetpath)['head']
bounds = [132, 304, 365, 567]
- self.assertEqual(bounds, [head.xMin, head.yMin, head.xMax, head.yMax])
+ assert bounds == [head.xMin, head.yMin, head.xMax, head.yMax]
def test_recalc_bounds_otf(self):
ttxpath = self.getpath("TestOTF-Regular.ttx")
@@ -523,76 +516,76 @@ class SubsetTest(unittest.TestCase):
head = font['head']
bounds = [head.xMin, head.yMin, head.xMax, head.yMax]
- _, fontpath = self.compile_font(ttxpath, ".otf")
+ fontpath = self.compile_font(ttxpath, ".otf")
subsetpath = self.temp_path(".otf")
# by default, the subsetter does not recalculate the bounding box
subset.main([fontpath, "--output-file=%s" % subsetpath, "*"])
head = TTFont(subsetpath)['head']
- self.assertEqual(bounds, [head.xMin, head.yMin, head.xMax, head.yMax])
+ assert bounds == [head.xMin, head.yMin, head.xMax, head.yMax]
subset.main([fontpath, "--recalc-bounds", "--output-file=%s" % subsetpath, "*"])
head = TTFont(subsetpath)['head']
bounds = [132, 304, 365, 567]
- self.assertEqual(bounds, [head.xMin, head.yMin, head.xMax, head.yMax])
+ assert bounds == [head.xMin, head.yMin, head.xMax, head.yMax]
def test_recalc_timestamp_ttf(self):
ttxpath = self.getpath("TestTTF-Regular.ttx")
font = TTFont()
font.importXML(ttxpath)
modified = font['head'].modified
- _, fontpath = self.compile_font(ttxpath, ".ttf")
+ fontpath = self.compile_font(ttxpath, ".ttf")
subsetpath = self.temp_path(".ttf")
# by default, the subsetter does not recalculate the modified timestamp
subset.main([fontpath, "--output-file=%s" % subsetpath, "*"])
- self.assertEqual(modified, TTFont(subsetpath)['head'].modified)
+ assert modified == TTFont(subsetpath)['head'].modified
subset.main([fontpath, "--recalc-timestamp", "--output-file=%s" % subsetpath, "*"])
- self.assertLess(modified, TTFont(subsetpath)['head'].modified)
+ assert modified < TTFont(subsetpath)['head'].modified
def test_recalc_timestamp_otf(self):
ttxpath = self.getpath("TestOTF-Regular.ttx")
font = TTFont()
font.importXML(ttxpath)
modified = font['head'].modified
- _, fontpath = self.compile_font(ttxpath, ".otf")
+ fontpath = self.compile_font(ttxpath, ".otf")
subsetpath = self.temp_path(".otf")
# by default, the subsetter does not recalculate the modified timestamp
subset.main([fontpath, "--output-file=%s" % subsetpath, "*"])
- self.assertEqual(modified, TTFont(subsetpath)['head'].modified)
+ assert modified == TTFont(subsetpath)['head'].modified
subset.main([fontpath, "--recalc-timestamp", "--output-file=%s" % subsetpath, "*"])
- self.assertLess(modified, TTFont(subsetpath)['head'].modified)
+ assert modified < TTFont(subsetpath)['head'].modified
def test_recalc_max_context(self):
ttxpath = self.getpath("Lobster.subset.ttx")
font = TTFont()
font.importXML(ttxpath)
max_context = font['OS/2'].usMaxContext
- _, fontpath = self.compile_font(ttxpath, ".otf")
+ fontpath = self.compile_font(ttxpath, ".otf")
subsetpath = self.temp_path(".otf")
# by default, the subsetter does not recalculate the usMaxContext
subset.main([fontpath, "--drop-tables+=GSUB,GPOS",
"--output-file=%s" % subsetpath])
- self.assertEqual(max_context, TTFont(subsetpath)['OS/2'].usMaxContext)
+ assert max_context == TTFont(subsetpath)['OS/2'].usMaxContext
subset.main([fontpath, "--recalc-max-context",
"--drop-tables+=GSUB,GPOS",
"--output-file=%s" % subsetpath])
- self.assertEqual(0, TTFont(subsetpath)['OS/2'].usMaxContext)
+ assert 0 == TTFont(subsetpath)['OS/2'].usMaxContext
def test_retain_gids_ttf(self):
- _, fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
font = TTFont(fontpath)
- self.assertEqual(font["hmtx"]["A"], (500, 132))
- self.assertEqual(font["hmtx"]["B"], (400, 132))
+ assert font["hmtx"]["A"] == (500, 132)
+ assert font["hmtx"]["B"] == (400, 132)
- self.assertGreater(font["glyf"]["A"].numberOfContours, 0)
- self.assertGreater(font["glyf"]["B"].numberOfContours, 0)
+ assert font["glyf"]["A"].numberOfContours > 0
+ assert font["glyf"]["B"].numberOfContours > 0
subsetpath = self.temp_path(".ttf")
subset.main(
@@ -606,29 +599,29 @@ class SubsetTest(unittest.TestCase):
)
subsetfont = TTFont(subsetpath)
- self.assertEqual(subsetfont.getGlyphOrder(), font.getGlyphOrder()[0:3])
+ assert subsetfont.getGlyphOrder() == font.getGlyphOrder()[0:3]
hmtx = subsetfont["hmtx"]
- self.assertEqual(hmtx["A"], ( 0, 0))
- self.assertEqual(hmtx["B"], (400, 132))
+ assert hmtx["A"] == (0, 0)
+ assert hmtx["B"] == (400, 132)
glyf = subsetfont["glyf"]
- self.assertEqual(glyf["A"].numberOfContours, 0)
- self.assertGreater(glyf["B"].numberOfContours, 0)
+ assert glyf["A"].numberOfContours == 0
+ assert glyf["B"].numberOfContours > 0
def test_retain_gids_cff(self):
- _, fontpath = self.compile_font(self.getpath("TestOTF-Regular.ttx"), ".otf")
+ fontpath = self.compile_font(self.getpath("TestOTF-Regular.ttx"), ".otf")
font = TTFont(fontpath)
- self.assertEqual(font["hmtx"]["A"], (500, 132))
- self.assertEqual(font["hmtx"]["B"], (400, 132))
- self.assertEqual(font["hmtx"]["C"], (500, 0))
+ assert font["hmtx"]["A"] == (500, 132)
+ assert font["hmtx"]["B"] == (400, 132)
+ assert font["hmtx"]["C"] == (500, 0)
font["CFF "].cff[0].decompileAllCharStrings()
cs = font["CFF "].cff[0].CharStrings
- self.assertGreater(len(cs["A"].program), 0)
- self.assertGreater(len(cs["B"].program), 0)
- self.assertGreater(len(cs["C"].program), 0)
+ assert len(cs["A"].program) > 0
+ assert len(cs["B"].program) > 0
+ assert len(cs["C"].program) > 0
subsetpath = self.temp_path(".otf")
subset.main(
@@ -642,29 +635,30 @@ class SubsetTest(unittest.TestCase):
)
subsetfont = TTFont(subsetpath)
- self.assertEqual(subsetfont.getGlyphOrder(), font.getGlyphOrder()[0:3])
+ assert subsetfont.getGlyphOrder() == font.getGlyphOrder()[0:3]
hmtx = subsetfont["hmtx"]
- self.assertEqual(hmtx["A"], (0, 0))
- self.assertEqual(hmtx["B"], (400, 132))
+ assert hmtx["A"] == (0, 0)
+ assert hmtx["B"] == (400, 132)
subsetfont["CFF "].cff[0].decompileAllCharStrings()
cs = subsetfont["CFF "].cff[0].CharStrings
- self.assertEqual(cs["A"].program, ["endchar"])
- self.assertGreater(len(cs["B"].program), 0)
+ assert cs["A"].program == ["endchar"]
+ assert len(cs["B"].program) > 0
def test_retain_gids_cff2(self):
ttx_path = self.getpath("../../varLib/data/master_ttx_varfont_otf/TestCFF2VF.ttx")
- font, fontpath = self.compile_font(ttx_path, ".otf")
+ fontpath = self.compile_font(ttx_path, ".otf")
+ font = TTFont(fontpath)
- self.assertEqual(font["hmtx"]["A"], (600, 31))
- self.assertEqual(font["hmtx"]["T"], (600, 41))
+ assert font["hmtx"]["A"] == (600, 31)
+ assert font["hmtx"]["T"] == (600, 41)
font["CFF2"].cff[0].decompileAllCharStrings()
cs = font["CFF2"].cff[0].CharStrings
- self.assertGreater(len(cs["A"].program), 0)
- self.assertGreater(len(cs["T"].program), 0)
+ assert len(cs["A"].program) > 0
+ assert len(cs["T"].program) > 0
subsetpath = self.temp_path(".otf")
subset.main(
@@ -677,33 +671,33 @@ class SubsetTest(unittest.TestCase):
)
subsetfont = TTFont(subsetpath)
- self.assertEqual(len(subsetfont.getGlyphOrder()), len(font.getGlyphOrder()[0:3]))
+ assert len(subsetfont.getGlyphOrder()) == len(font.getGlyphOrder()[0:3])
hmtx = subsetfont["hmtx"]
- self.assertEqual(hmtx["glyph00001"], ( 0, 0))
- self.assertEqual(hmtx["T"], (600, 41))
+ assert hmtx["glyph00001"] == (0, 0)
+ assert hmtx["T"] == (600, 41)
subsetfont["CFF2"].cff[0].decompileAllCharStrings()
cs = subsetfont["CFF2"].cff[0].CharStrings
- self.assertEqual(cs["glyph00001"].program, [])
- self.assertGreater(len(cs["T"].program), 0)
+ assert cs["glyph00001"].program == []
+ assert len(cs["T"].program) > 0
def test_HVAR_VVAR(self):
- _, fontpath = self.compile_font(self.getpath("TestHVVAR.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestHVVAR.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--text=BD", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_HVVAR.ttx"), ["GlyphOrder", "HVAR", "VVAR", "avar", "fvar"])
def test_HVAR_VVAR_retain_gids(self):
- _, fontpath = self.compile_font(self.getpath("TestHVVAR.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestHVVAR.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--text=BD", "--retain-gids", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("expect_HVVAR_retain_gids.ttx"), ["GlyphOrder", "HVAR", "VVAR", "avar", "fvar"])
def test_subset_flavor(self):
- _, fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("TestTTF-Regular.ttx"), ".ttf")
font = TTFont(fontpath)
woff_path = self.temp_path(".woff")
@@ -717,7 +711,7 @@ class SubsetTest(unittest.TestCase):
)
woff = TTFont(woff_path)
- self.assertEqual(woff.flavor, "woff")
+ assert woff.flavor == "woff"
woff2_path = self.temp_path(".woff2")
subset.main(
@@ -730,7 +724,7 @@ class SubsetTest(unittest.TestCase):
)
woff2 = TTFont(woff2_path)
- self.assertEqual(woff2.flavor, "woff2")
+ assert woff2.flavor == "woff2"
ttf_path = self.temp_path(".ttf")
subset.main(
@@ -742,13 +736,13 @@ class SubsetTest(unittest.TestCase):
)
ttf = TTFont(ttf_path)
- self.assertEqual(ttf.flavor, None)
+ assert ttf.flavor is None
def test_subset_context_subst_format_3(self):
# https://github.com/fonttools/fonttools/issues/1879
# Test font contains 'calt' feature with Format 3 ContextSubst lookup subtables
ttx = self.getpath("TestContextSubstFormat3.ttx")
- font, fontpath = self.compile_font(ttx, ".ttf")
+ fontpath = self.compile_font(ttx, ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--unicodes=*", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
@@ -756,13 +750,14 @@ class SubsetTest(unittest.TestCase):
self.expect_ttx(subsetfont, ttx)
def test_cmap_prune_format12(self):
- _, fontpath = self.compile_font(self.getpath("CmapSubsetTest.ttx"), ".ttf")
+ fontpath = self.compile_font(self.getpath("CmapSubsetTest.ttx"), ".ttf")
subsetpath = self.temp_path(".ttf")
subset.main([fontpath, "--glyphs=a", "--output-file=%s" % subsetpath])
subsetfont = TTFont(subsetpath)
self.expect_ttx(subsetfont, self.getpath("CmapSubsetTest.subset.ttx"), ["cmap"])
- def test_GPOS_PairPos_Format2_useClass0(self):
+ @pytest.mark.parametrize("text, n", [("!", 1), ("#", 2)])
+ def test_GPOS_PairPos_Format2_useClass0(self, text, n):
# Check two things related to class 0 ('every other glyph'):
# 1) that it's reused for ClassDef1 when it becomes empty as the subset glyphset
# is intersected with the table's Coverage
@@ -772,29 +767,27 @@ class SubsetTest(unittest.TestCase):
# The test font (from Harfbuzz test suite) is constructed to trigger these two
# situations depending on the input subset --text.
# https://github.com/fonttools/fonttools/pull/2221
- _, fontpath = self.compile_font(
+ fontpath = self.compile_font(
self.getpath("GPOS_PairPos_Format2_PR_2221.ttx"), ".ttf"
)
subsetpath = self.temp_path(".ttf")
- for n, text in enumerate("!#", start=1):
- expected_ttx = self.getpath(
- f"GPOS_PairPos_Format2_ClassDef{n}_useClass0.subset.ttx"
- )
- with self.subTest(text=text, expected_ttx=expected_ttx):
- subset.main(
- [
- fontpath,
- f"--text='{text}'",
- "--layout-features+=test",
- "--output-file=%s" % subsetpath,
- ]
- )
- subsetfont = TTFont(subsetpath)
- self.expect_ttx(subsetfont, expected_ttx, ["GPOS"])
+ expected_ttx = self.getpath(
+ f"GPOS_PairPos_Format2_ClassDef{n}_useClass0.subset.ttx"
+ )
+ subset.main(
+ [
+ fontpath,
+ f"--text='{text}'",
+ "--layout-features+=test",
+ "--output-file=%s" % subsetpath,
+ ]
+ )
+ subsetfont = TTFont(subsetpath)
+ self.expect_ttx(subsetfont, expected_ttx, ["GPOS"])
def test_GPOS_SinglePos_prune_post_subset_no_value(self):
- _, fontpath = self.compile_font(
+ fontpath = self.compile_font(
self.getpath("GPOS_SinglePos_no_value_issue_2312.ttx"), ".ttf"
)
subsetpath = self.temp_path(".ttf")
@@ -806,6 +799,91 @@ class SubsetTest(unittest.TestCase):
["GlyphOrder", "GPOS"],
)
+ @pytest.mark.parametrize(
+ "installed, enabled, ok",
+ [
+ pytest.param(True, None, True, id="installed-auto-ok"),
+ pytest.param(True, None, False, id="installed-auto-fail"),
+ pytest.param(True, True, True, id="installed-enabled-ok"),
+ pytest.param(True, True, False, id="installed-enabled-fail"),
+ pytest.param(True, False, True, id="installed-disabled"),
+ pytest.param(False, True, True, id="not_installed-enabled"),
+ pytest.param(False, False, True, id="not_installed-disabled"),
+ ],
+ )
+ def test_harfbuzz_repacker(self, caplog, monkeypatch, installed, enabled, ok):
+ # Use a mock to test the pure-python serializer is used when uharfbuzz
+ # returns an error or is not installed
+ have_uharfbuzz = fontTools.ttLib.tables.otBase.have_uharfbuzz
+ if installed:
+ if not have_uharfbuzz:
+ pytest.skip("uharfbuzz is not installed")
+ if not ok:
+ # pretend hb.repack returns an error
+ import uharfbuzz as hb
+
+ def mock_repack(data, obj_list):
+ raise hb.RepackerError("mocking")
+
+ monkeypatch.setattr(hb, "repack", mock_repack)
+ else:
+ if have_uharfbuzz:
+ # pretend uharfbuzz is not installed
+ monkeypatch.setattr(
+ fontTools.ttLib.tables.otBase, "have_uharfbuzz", False
+ )
+
+ fontpath = self.compile_font(self.getpath("harfbuzz_repacker.ttx"), ".otf")
+ subsetpath = self.temp_path(".otf")
+ args = [
+ fontpath,
+ "--unicodes=0x53a9",
+ "--layout-features=*",
+ f"--output-file={subsetpath}",
+ ]
+ if enabled is True:
+ args.append("--harfbuzz-repacker")
+ elif enabled is False:
+ args.append("--no-harfbuzz-repacker")
+ # elif enabled is None: ... is the default
+
+ if enabled is True and not installed:
+ # raise if enabled but not installed
+ with pytest.raises(ImportError, match="uharfbuzz"):
+ subset.main(args)
+ return
+
+ with caplog.at_level(logging.DEBUG, "fontTools.ttLib.tables.otBase"):
+ subset.main(args)
+
+ subsetfont = TTFont(subsetpath)
+ # both hb.repack and pure-python serializer compile to the same ttx
+ self.expect_ttx(
+ subsetfont, self.getpath("expect_harfbuzz_repacker.ttx"), ["GSUB"]
+ )
+
+ if enabled or enabled is None:
+ if installed:
+ assert "serializing 'GSUB' with hb.repack" in caplog.text
+
+ if enabled is None and not installed:
+ assert (
+ "uharfbuzz not found, compiling 'GSUB' with pure-python serializer"
+ ) in caplog.text
+
+ if enabled is False:
+ assert (
+ "hb.repack disabled, compiling 'GSUB' with pure-python serializer"
+ ) in caplog.text
+
+ # test we emit a log.error if hb.repack fails (and we don't if successful)
+ assert (
+ (
+ "hb.repack failed to serialize 'GSUB', reverting to "
+ "pure-python serializer; the error message was: RepackerError: mocking"
+ ) in caplog.text
+ ) ^ ok
+
@pytest.fixture
def featureVarsTestFont():