1*e1fe3e4aSElliott Hughesfrom fontTools.misc.testTools import parseXML 2*e1fe3e4aSElliott Hughesfrom fontTools.misc.timeTools import timestampSinceEpoch 3*e1fe3e4aSElliott Hughesfrom fontTools.ttLib import TTFont, TTLibError 4*e1fe3e4aSElliott Hughesfrom fontTools.ttLib.tables.DefaultTable import DefaultTable 5*e1fe3e4aSElliott Hughesfrom fontTools import ttx 6*e1fe3e4aSElliott Hughesimport base64 7*e1fe3e4aSElliott Hughesimport getopt 8*e1fe3e4aSElliott Hughesimport logging 9*e1fe3e4aSElliott Hughesimport os 10*e1fe3e4aSElliott Hughesimport shutil 11*e1fe3e4aSElliott Hughesimport subprocess 12*e1fe3e4aSElliott Hughesimport sys 13*e1fe3e4aSElliott Hughesimport tempfile 14*e1fe3e4aSElliott Hughesimport unittest 15*e1fe3e4aSElliott Hughesfrom pathlib import Path 16*e1fe3e4aSElliott Hughes 17*e1fe3e4aSElliott Hughesimport pytest 18*e1fe3e4aSElliott Hughes 19*e1fe3e4aSElliott Hughestry: 20*e1fe3e4aSElliott Hughes import zopfli 21*e1fe3e4aSElliott Hughesexcept ImportError: 22*e1fe3e4aSElliott Hughes zopfli = None 23*e1fe3e4aSElliott Hughestry: 24*e1fe3e4aSElliott Hughes try: 25*e1fe3e4aSElliott Hughes import brotlicffi as brotli 26*e1fe3e4aSElliott Hughes except ImportError: 27*e1fe3e4aSElliott Hughes import brotli 28*e1fe3e4aSElliott Hughesexcept ImportError: 29*e1fe3e4aSElliott Hughes brotli = None 30*e1fe3e4aSElliott Hughes 31*e1fe3e4aSElliott Hughes 32*e1fe3e4aSElliott Hughesclass TTXTest(unittest.TestCase): 33*e1fe3e4aSElliott Hughes def __init__(self, methodName): 34*e1fe3e4aSElliott Hughes unittest.TestCase.__init__(self, methodName) 35*e1fe3e4aSElliott Hughes # Python 3 renamed assertRaisesRegexp to assertRaisesRegex, 36*e1fe3e4aSElliott Hughes # and fires deprecation warnings if a program uses the old name. 37*e1fe3e4aSElliott Hughes if not hasattr(self, "assertRaisesRegex"): 38*e1fe3e4aSElliott Hughes self.assertRaisesRegex = self.assertRaisesRegexp 39*e1fe3e4aSElliott Hughes 40*e1fe3e4aSElliott Hughes def setUp(self): 41*e1fe3e4aSElliott Hughes self.tempdir = None 42*e1fe3e4aSElliott Hughes self.num_tempfiles = 0 43*e1fe3e4aSElliott Hughes 44*e1fe3e4aSElliott Hughes def tearDown(self): 45*e1fe3e4aSElliott Hughes if self.tempdir: 46*e1fe3e4aSElliott Hughes shutil.rmtree(self.tempdir) 47*e1fe3e4aSElliott Hughes 48*e1fe3e4aSElliott Hughes @staticmethod 49*e1fe3e4aSElliott Hughes def getpath(testfile): 50*e1fe3e4aSElliott Hughes path, _ = os.path.split(__file__) 51*e1fe3e4aSElliott Hughes return os.path.join(path, "data", testfile) 52*e1fe3e4aSElliott Hughes 53*e1fe3e4aSElliott Hughes def temp_dir(self): 54*e1fe3e4aSElliott Hughes if not self.tempdir: 55*e1fe3e4aSElliott Hughes self.tempdir = tempfile.mkdtemp() 56*e1fe3e4aSElliott Hughes 57*e1fe3e4aSElliott Hughes def temp_font(self, font_path, file_name): 58*e1fe3e4aSElliott Hughes self.temp_dir() 59*e1fe3e4aSElliott Hughes temppath = os.path.join(self.tempdir, file_name) 60*e1fe3e4aSElliott Hughes shutil.copy2(font_path, temppath) 61*e1fe3e4aSElliott Hughes return temppath 62*e1fe3e4aSElliott Hughes 63*e1fe3e4aSElliott Hughes @staticmethod 64*e1fe3e4aSElliott Hughes def read_file(file_path): 65*e1fe3e4aSElliott Hughes with open(file_path, "r", encoding="utf-8") as f: 66*e1fe3e4aSElliott Hughes return f.readlines() 67*e1fe3e4aSElliott Hughes 68*e1fe3e4aSElliott Hughes # ----- 69*e1fe3e4aSElliott Hughes # Tests 70*e1fe3e4aSElliott Hughes # ----- 71*e1fe3e4aSElliott Hughes 72*e1fe3e4aSElliott Hughes def test_parseOptions_no_args(self): 73*e1fe3e4aSElliott Hughes with self.assertRaises(getopt.GetoptError) as cm: 74*e1fe3e4aSElliott Hughes ttx.parseOptions([]) 75*e1fe3e4aSElliott Hughes self.assertTrue("Must specify at least one input file" in str(cm.exception)) 76*e1fe3e4aSElliott Hughes 77*e1fe3e4aSElliott Hughes def test_parseOptions_invalid_path(self): 78*e1fe3e4aSElliott Hughes file_path = "invalid_font_path" 79*e1fe3e4aSElliott Hughes with self.assertRaises(getopt.GetoptError) as cm: 80*e1fe3e4aSElliott Hughes ttx.parseOptions([file_path]) 81*e1fe3e4aSElliott Hughes self.assertTrue('File not found: "%s"' % file_path in str(cm.exception)) 82*e1fe3e4aSElliott Hughes 83*e1fe3e4aSElliott Hughes def test_parseOptions_font2ttx_1st_time(self): 84*e1fe3e4aSElliott Hughes file_name = "TestOTF.otf" 85*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 86*e1fe3e4aSElliott Hughes temp_path = self.temp_font(font_path, file_name) 87*e1fe3e4aSElliott Hughes jobs, _ = ttx.parseOptions([temp_path]) 88*e1fe3e4aSElliott Hughes self.assertEqual(jobs[0][0].__name__, "ttDump") 89*e1fe3e4aSElliott Hughes self.assertEqual( 90*e1fe3e4aSElliott Hughes jobs[0][1:], 91*e1fe3e4aSElliott Hughes ( 92*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_name), 93*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_name.split(".")[0] + ".ttx"), 94*e1fe3e4aSElliott Hughes ), 95*e1fe3e4aSElliott Hughes ) 96*e1fe3e4aSElliott Hughes 97*e1fe3e4aSElliott Hughes def test_parseOptions_font2ttx_2nd_time(self): 98*e1fe3e4aSElliott Hughes file_name = "TestTTF.ttf" 99*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 100*e1fe3e4aSElliott Hughes temp_path = self.temp_font(font_path, file_name) 101*e1fe3e4aSElliott Hughes _, _ = ttx.parseOptions([temp_path]) # this is NOT a mistake 102*e1fe3e4aSElliott Hughes jobs, _ = ttx.parseOptions([temp_path]) 103*e1fe3e4aSElliott Hughes self.assertEqual(jobs[0][0].__name__, "ttDump") 104*e1fe3e4aSElliott Hughes self.assertEqual( 105*e1fe3e4aSElliott Hughes jobs[0][1:], 106*e1fe3e4aSElliott Hughes ( 107*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_name), 108*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_name.split(".")[0] + "#1.ttx"), 109*e1fe3e4aSElliott Hughes ), 110*e1fe3e4aSElliott Hughes ) 111*e1fe3e4aSElliott Hughes 112*e1fe3e4aSElliott Hughes def test_parseOptions_ttx2font_1st_time(self): 113*e1fe3e4aSElliott Hughes file_name = "TestTTF.ttx" 114*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 115*e1fe3e4aSElliott Hughes temp_path = self.temp_font(font_path, file_name) 116*e1fe3e4aSElliott Hughes jobs, _ = ttx.parseOptions([temp_path]) 117*e1fe3e4aSElliott Hughes self.assertEqual(jobs[0][0].__name__, "ttCompile") 118*e1fe3e4aSElliott Hughes self.assertEqual( 119*e1fe3e4aSElliott Hughes jobs[0][1:], 120*e1fe3e4aSElliott Hughes ( 121*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_name), 122*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_name.split(".")[0] + ".ttf"), 123*e1fe3e4aSElliott Hughes ), 124*e1fe3e4aSElliott Hughes ) 125*e1fe3e4aSElliott Hughes 126*e1fe3e4aSElliott Hughes def test_parseOptions_ttx2font_2nd_time(self): 127*e1fe3e4aSElliott Hughes file_name = "TestOTF.ttx" 128*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 129*e1fe3e4aSElliott Hughes temp_path = self.temp_font(font_path, file_name) 130*e1fe3e4aSElliott Hughes _, _ = ttx.parseOptions([temp_path]) # this is NOT a mistake 131*e1fe3e4aSElliott Hughes jobs, _ = ttx.parseOptions([temp_path]) 132*e1fe3e4aSElliott Hughes self.assertEqual(jobs[0][0].__name__, "ttCompile") 133*e1fe3e4aSElliott Hughes self.assertEqual( 134*e1fe3e4aSElliott Hughes jobs[0][1:], 135*e1fe3e4aSElliott Hughes ( 136*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_name), 137*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_name.split(".")[0] + "#1.otf"), 138*e1fe3e4aSElliott Hughes ), 139*e1fe3e4aSElliott Hughes ) 140*e1fe3e4aSElliott Hughes 141*e1fe3e4aSElliott Hughes def test_parseOptions_multiple_fonts(self): 142*e1fe3e4aSElliott Hughes file_names = ["TestOTF.otf", "TestTTF.ttf"] 143*e1fe3e4aSElliott Hughes font_paths = [self.getpath(file_name) for file_name in file_names] 144*e1fe3e4aSElliott Hughes temp_paths = [ 145*e1fe3e4aSElliott Hughes self.temp_font(font_path, file_name) 146*e1fe3e4aSElliott Hughes for font_path, file_name in zip(font_paths, file_names) 147*e1fe3e4aSElliott Hughes ] 148*e1fe3e4aSElliott Hughes jobs, _ = ttx.parseOptions(temp_paths) 149*e1fe3e4aSElliott Hughes for i in range(len(jobs)): 150*e1fe3e4aSElliott Hughes self.assertEqual(jobs[i][0].__name__, "ttDump") 151*e1fe3e4aSElliott Hughes self.assertEqual( 152*e1fe3e4aSElliott Hughes jobs[i][1:], 153*e1fe3e4aSElliott Hughes ( 154*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_names[i]), 155*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_names[i].split(".")[0] + ".ttx"), 156*e1fe3e4aSElliott Hughes ), 157*e1fe3e4aSElliott Hughes ) 158*e1fe3e4aSElliott Hughes 159*e1fe3e4aSElliott Hughes def test_parseOptions_mixed_files(self): 160*e1fe3e4aSElliott Hughes operations = ["ttDump", "ttCompile"] 161*e1fe3e4aSElliott Hughes extensions = [".ttx", ".ttf"] 162*e1fe3e4aSElliott Hughes file_names = ["TestOTF.otf", "TestTTF.ttx"] 163*e1fe3e4aSElliott Hughes font_paths = [self.getpath(file_name) for file_name in file_names] 164*e1fe3e4aSElliott Hughes temp_paths = [ 165*e1fe3e4aSElliott Hughes self.temp_font(font_path, file_name) 166*e1fe3e4aSElliott Hughes for font_path, file_name in zip(font_paths, file_names) 167*e1fe3e4aSElliott Hughes ] 168*e1fe3e4aSElliott Hughes jobs, _ = ttx.parseOptions(temp_paths) 169*e1fe3e4aSElliott Hughes for i in range(len(jobs)): 170*e1fe3e4aSElliott Hughes self.assertEqual(jobs[i][0].__name__, operations[i]) 171*e1fe3e4aSElliott Hughes self.assertEqual( 172*e1fe3e4aSElliott Hughes jobs[i][1:], 173*e1fe3e4aSElliott Hughes ( 174*e1fe3e4aSElliott Hughes os.path.join(self.tempdir, file_names[i]), 175*e1fe3e4aSElliott Hughes os.path.join( 176*e1fe3e4aSElliott Hughes self.tempdir, 177*e1fe3e4aSElliott Hughes file_names[i].split(".")[0] + extensions[i], 178*e1fe3e4aSElliott Hughes ), 179*e1fe3e4aSElliott Hughes ), 180*e1fe3e4aSElliott Hughes ) 181*e1fe3e4aSElliott Hughes 182*e1fe3e4aSElliott Hughes def test_parseOptions_splitTables(self): 183*e1fe3e4aSElliott Hughes file_name = "TestTTF.ttf" 184*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 185*e1fe3e4aSElliott Hughes temp_path = self.temp_font(font_path, file_name) 186*e1fe3e4aSElliott Hughes args = ["-s", temp_path] 187*e1fe3e4aSElliott Hughes 188*e1fe3e4aSElliott Hughes jobs, options = ttx.parseOptions(args) 189*e1fe3e4aSElliott Hughes 190*e1fe3e4aSElliott Hughes ttx_file_path = jobs[0][2] 191*e1fe3e4aSElliott Hughes temp_folder = os.path.dirname(ttx_file_path) 192*e1fe3e4aSElliott Hughes self.assertTrue(options.splitTables) 193*e1fe3e4aSElliott Hughes self.assertTrue(os.path.exists(ttx_file_path)) 194*e1fe3e4aSElliott Hughes 195*e1fe3e4aSElliott Hughes ttx.process(jobs, options) 196*e1fe3e4aSElliott Hughes 197*e1fe3e4aSElliott Hughes # Read the TTX file but strip the first two and the last lines: 198*e1fe3e4aSElliott Hughes # <?xml version="1.0" encoding="UTF-8"?> 199*e1fe3e4aSElliott Hughes # <ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.22"> 200*e1fe3e4aSElliott Hughes # ... 201*e1fe3e4aSElliott Hughes # </ttFont> 202*e1fe3e4aSElliott Hughes parsed_xml = parseXML(self.read_file(ttx_file_path)[2:-1]) 203*e1fe3e4aSElliott Hughes for item in parsed_xml: 204*e1fe3e4aSElliott Hughes if not isinstance(item, tuple): 205*e1fe3e4aSElliott Hughes continue 206*e1fe3e4aSElliott Hughes # the tuple looks like this: 207*e1fe3e4aSElliott Hughes # (u'head', {u'src': u'TestTTF._h_e_a_d.ttx'}, []) 208*e1fe3e4aSElliott Hughes table_file_name = item[1].get("src") 209*e1fe3e4aSElliott Hughes table_file_path = os.path.join(temp_folder, table_file_name) 210*e1fe3e4aSElliott Hughes self.assertTrue(os.path.exists(table_file_path)) 211*e1fe3e4aSElliott Hughes 212*e1fe3e4aSElliott Hughes def test_parseOptions_splitGlyphs(self): 213*e1fe3e4aSElliott Hughes file_name = "TestTTF.ttf" 214*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 215*e1fe3e4aSElliott Hughes temp_path = self.temp_font(font_path, file_name) 216*e1fe3e4aSElliott Hughes args = ["-g", temp_path] 217*e1fe3e4aSElliott Hughes 218*e1fe3e4aSElliott Hughes jobs, options = ttx.parseOptions(args) 219*e1fe3e4aSElliott Hughes 220*e1fe3e4aSElliott Hughes ttx_file_path = jobs[0][2] 221*e1fe3e4aSElliott Hughes temp_folder = os.path.dirname(ttx_file_path) 222*e1fe3e4aSElliott Hughes self.assertTrue(options.splitGlyphs) 223*e1fe3e4aSElliott Hughes # splitGlyphs also forces splitTables 224*e1fe3e4aSElliott Hughes self.assertTrue(options.splitTables) 225*e1fe3e4aSElliott Hughes self.assertTrue(os.path.exists(ttx_file_path)) 226*e1fe3e4aSElliott Hughes 227*e1fe3e4aSElliott Hughes ttx.process(jobs, options) 228*e1fe3e4aSElliott Hughes 229*e1fe3e4aSElliott Hughes # Read the TTX file but strip the first two and the last lines: 230*e1fe3e4aSElliott Hughes # <?xml version="1.0" encoding="UTF-8"?> 231*e1fe3e4aSElliott Hughes # <ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.22"> 232*e1fe3e4aSElliott Hughes # ... 233*e1fe3e4aSElliott Hughes # </ttFont> 234*e1fe3e4aSElliott Hughes for item in parseXML(self.read_file(ttx_file_path)[2:-1]): 235*e1fe3e4aSElliott Hughes if not isinstance(item, tuple): 236*e1fe3e4aSElliott Hughes continue 237*e1fe3e4aSElliott Hughes # the tuple looks like this: 238*e1fe3e4aSElliott Hughes # (u'head', {u'src': u'TestTTF._h_e_a_d.ttx'}, []) 239*e1fe3e4aSElliott Hughes table_tag = item[0] 240*e1fe3e4aSElliott Hughes table_file_name = item[1].get("src") 241*e1fe3e4aSElliott Hughes table_file_path = os.path.join(temp_folder, table_file_name) 242*e1fe3e4aSElliott Hughes self.assertTrue(os.path.exists(table_file_path)) 243*e1fe3e4aSElliott Hughes if table_tag != "glyf": 244*e1fe3e4aSElliott Hughes continue 245*e1fe3e4aSElliott Hughes # also strip the enclosing 'glyf' element 246*e1fe3e4aSElliott Hughes for item in parseXML(self.read_file(table_file_path)[4:-3]): 247*e1fe3e4aSElliott Hughes if not isinstance(item, tuple): 248*e1fe3e4aSElliott Hughes continue 249*e1fe3e4aSElliott Hughes # glyphs without outline data only have 'name' attribute 250*e1fe3e4aSElliott Hughes glyph_file_name = item[1].get("src") 251*e1fe3e4aSElliott Hughes if glyph_file_name is not None: 252*e1fe3e4aSElliott Hughes glyph_file_path = os.path.join(temp_folder, glyph_file_name) 253*e1fe3e4aSElliott Hughes self.assertTrue(os.path.exists(glyph_file_path)) 254*e1fe3e4aSElliott Hughes 255*e1fe3e4aSElliott Hughes def test_guessFileType_ttf(self): 256*e1fe3e4aSElliott Hughes file_name = "TestTTF.ttf" 257*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 258*e1fe3e4aSElliott Hughes self.assertEqual(ttx.guessFileType(font_path), "TTF") 259*e1fe3e4aSElliott Hughes 260*e1fe3e4aSElliott Hughes def test_guessFileType_otf(self): 261*e1fe3e4aSElliott Hughes file_name = "TestOTF.otf" 262*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 263*e1fe3e4aSElliott Hughes self.assertEqual(ttx.guessFileType(font_path), "OTF") 264*e1fe3e4aSElliott Hughes 265*e1fe3e4aSElliott Hughes def test_guessFileType_woff(self): 266*e1fe3e4aSElliott Hughes file_name = "TestWOFF.woff" 267*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 268*e1fe3e4aSElliott Hughes self.assertEqual(ttx.guessFileType(font_path), "WOFF") 269*e1fe3e4aSElliott Hughes 270*e1fe3e4aSElliott Hughes def test_guessFileType_woff2(self): 271*e1fe3e4aSElliott Hughes file_name = "TestWOFF2.woff2" 272*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 273*e1fe3e4aSElliott Hughes self.assertEqual(ttx.guessFileType(font_path), "WOFF2") 274*e1fe3e4aSElliott Hughes 275*e1fe3e4aSElliott Hughes def test_guessFileType_ttc(self): 276*e1fe3e4aSElliott Hughes file_name = "TestTTC.ttc" 277*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 278*e1fe3e4aSElliott Hughes self.assertEqual(ttx.guessFileType(font_path), "TTC") 279*e1fe3e4aSElliott Hughes 280*e1fe3e4aSElliott Hughes def test_guessFileType_dfont(self): 281*e1fe3e4aSElliott Hughes file_name = "TestDFONT.dfont" 282*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 283*e1fe3e4aSElliott Hughes self.assertEqual(ttx.guessFileType(font_path), "TTF") 284*e1fe3e4aSElliott Hughes 285*e1fe3e4aSElliott Hughes def test_guessFileType_ttx_ttf(self): 286*e1fe3e4aSElliott Hughes file_name = "TestTTF.ttx" 287*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 288*e1fe3e4aSElliott Hughes self.assertEqual(ttx.guessFileType(font_path), "TTX") 289*e1fe3e4aSElliott Hughes 290*e1fe3e4aSElliott Hughes def test_guessFileType_ttx_otf(self): 291*e1fe3e4aSElliott Hughes file_name = "TestOTF.ttx" 292*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 293*e1fe3e4aSElliott Hughes self.assertEqual(ttx.guessFileType(font_path), "OTX") 294*e1fe3e4aSElliott Hughes 295*e1fe3e4aSElliott Hughes def test_guessFileType_ttx_bom(self): 296*e1fe3e4aSElliott Hughes file_name = "TestBOM.ttx" 297*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 298*e1fe3e4aSElliott Hughes self.assertEqual(ttx.guessFileType(font_path), "TTX") 299*e1fe3e4aSElliott Hughes 300*e1fe3e4aSElliott Hughes def test_guessFileType_ttx_no_sfntVersion(self): 301*e1fe3e4aSElliott Hughes file_name = "TestNoSFNT.ttx" 302*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 303*e1fe3e4aSElliott Hughes self.assertEqual(ttx.guessFileType(font_path), "TTX") 304*e1fe3e4aSElliott Hughes 305*e1fe3e4aSElliott Hughes def test_guessFileType_ttx_no_xml(self): 306*e1fe3e4aSElliott Hughes file_name = "TestNoXML.ttx" 307*e1fe3e4aSElliott Hughes font_path = self.getpath(file_name) 308*e1fe3e4aSElliott Hughes self.assertIsNone(ttx.guessFileType(font_path)) 309*e1fe3e4aSElliott Hughes 310*e1fe3e4aSElliott Hughes def test_guessFileType_invalid_path(self): 311*e1fe3e4aSElliott Hughes font_path = "invalid_font_path" 312*e1fe3e4aSElliott Hughes self.assertIsNone(ttx.guessFileType(font_path)) 313*e1fe3e4aSElliott Hughes 314*e1fe3e4aSElliott Hughes 315*e1fe3e4aSElliott Hughes# ----------------------- 316*e1fe3e4aSElliott Hughes# ttx.Options class tests 317*e1fe3e4aSElliott Hughes# ----------------------- 318*e1fe3e4aSElliott Hughes 319*e1fe3e4aSElliott Hughes 320*e1fe3e4aSElliott Hughesdef test_options_flag_h(capsys): 321*e1fe3e4aSElliott Hughes with pytest.raises(SystemExit): 322*e1fe3e4aSElliott Hughes ttx.Options([("-h", None)], 1) 323*e1fe3e4aSElliott Hughes 324*e1fe3e4aSElliott Hughes out, err = capsys.readouterr() 325*e1fe3e4aSElliott Hughes assert "TTX -- From OpenType To XML And Back" in out 326*e1fe3e4aSElliott Hughes 327*e1fe3e4aSElliott Hughes 328*e1fe3e4aSElliott Hughesdef test_options_flag_version(capsys): 329*e1fe3e4aSElliott Hughes with pytest.raises(SystemExit): 330*e1fe3e4aSElliott Hughes ttx.Options([("--version", None)], 1) 331*e1fe3e4aSElliott Hughes 332*e1fe3e4aSElliott Hughes out, err = capsys.readouterr() 333*e1fe3e4aSElliott Hughes version_list = out.split(".") 334*e1fe3e4aSElliott Hughes assert len(version_list) >= 3 335*e1fe3e4aSElliott Hughes assert version_list[0].isdigit() 336*e1fe3e4aSElliott Hughes assert version_list[1].isdigit() 337*e1fe3e4aSElliott Hughes assert version_list[2].strip().isdigit() 338*e1fe3e4aSElliott Hughes 339*e1fe3e4aSElliott Hughes 340*e1fe3e4aSElliott Hughesdef test_options_d_goodpath(tmpdir): 341*e1fe3e4aSElliott Hughes temp_dir_path = str(tmpdir) 342*e1fe3e4aSElliott Hughes tto = ttx.Options([("-d", temp_dir_path)], 1) 343*e1fe3e4aSElliott Hughes assert tto.outputDir == temp_dir_path 344*e1fe3e4aSElliott Hughes 345*e1fe3e4aSElliott Hughes 346*e1fe3e4aSElliott Hughesdef test_options_d_badpath(): 347*e1fe3e4aSElliott Hughes with pytest.raises(getopt.GetoptError): 348*e1fe3e4aSElliott Hughes ttx.Options([("-d", "bogusdir")], 1) 349*e1fe3e4aSElliott Hughes 350*e1fe3e4aSElliott Hughes 351*e1fe3e4aSElliott Hughesdef test_options_o(): 352*e1fe3e4aSElliott Hughes tto = ttx.Options([("-o", "testfile.ttx")], 1) 353*e1fe3e4aSElliott Hughes assert tto.outputFile == "testfile.ttx" 354*e1fe3e4aSElliott Hughes 355*e1fe3e4aSElliott Hughes 356*e1fe3e4aSElliott Hughesdef test_options_f(): 357*e1fe3e4aSElliott Hughes tto = ttx.Options([("-f", "")], 1) 358*e1fe3e4aSElliott Hughes assert tto.overWrite is True 359*e1fe3e4aSElliott Hughes 360*e1fe3e4aSElliott Hughes 361*e1fe3e4aSElliott Hughesdef test_options_v(): 362*e1fe3e4aSElliott Hughes tto = ttx.Options([("-v", "")], 1) 363*e1fe3e4aSElliott Hughes assert tto.verbose is True 364*e1fe3e4aSElliott Hughes assert tto.logLevel == logging.DEBUG 365*e1fe3e4aSElliott Hughes 366*e1fe3e4aSElliott Hughes 367*e1fe3e4aSElliott Hughesdef test_options_q(): 368*e1fe3e4aSElliott Hughes tto = ttx.Options([("-q", "")], 1) 369*e1fe3e4aSElliott Hughes assert tto.quiet is True 370*e1fe3e4aSElliott Hughes assert tto.logLevel == logging.WARNING 371*e1fe3e4aSElliott Hughes 372*e1fe3e4aSElliott Hughes 373*e1fe3e4aSElliott Hughesdef test_options_l(): 374*e1fe3e4aSElliott Hughes tto = ttx.Options([("-l", "")], 1) 375*e1fe3e4aSElliott Hughes assert tto.listTables is True 376*e1fe3e4aSElliott Hughes 377*e1fe3e4aSElliott Hughes 378*e1fe3e4aSElliott Hughesdef test_options_t_nopadding(): 379*e1fe3e4aSElliott Hughes tto = ttx.Options([("-t", "CFF2")], 1) 380*e1fe3e4aSElliott Hughes assert len(tto.onlyTables) == 1 381*e1fe3e4aSElliott Hughes assert tto.onlyTables[0] == "CFF2" 382*e1fe3e4aSElliott Hughes 383*e1fe3e4aSElliott Hughes 384*e1fe3e4aSElliott Hughesdef test_options_t_withpadding(): 385*e1fe3e4aSElliott Hughes tto = ttx.Options([("-t", "CFF")], 1) 386*e1fe3e4aSElliott Hughes assert len(tto.onlyTables) == 1 387*e1fe3e4aSElliott Hughes assert tto.onlyTables[0] == "CFF " 388*e1fe3e4aSElliott Hughes 389*e1fe3e4aSElliott Hughes 390*e1fe3e4aSElliott Hughesdef test_options_s(): 391*e1fe3e4aSElliott Hughes tto = ttx.Options([("-s", "")], 1) 392*e1fe3e4aSElliott Hughes assert tto.splitTables is True 393*e1fe3e4aSElliott Hughes assert tto.splitGlyphs is False 394*e1fe3e4aSElliott Hughes 395*e1fe3e4aSElliott Hughes 396*e1fe3e4aSElliott Hughesdef test_options_g(): 397*e1fe3e4aSElliott Hughes tto = ttx.Options([("-g", "")], 1) 398*e1fe3e4aSElliott Hughes assert tto.splitGlyphs is True 399*e1fe3e4aSElliott Hughes assert tto.splitTables is True 400*e1fe3e4aSElliott Hughes 401*e1fe3e4aSElliott Hughes 402*e1fe3e4aSElliott Hughesdef test_options_i(): 403*e1fe3e4aSElliott Hughes tto = ttx.Options([("-i", "")], 1) 404*e1fe3e4aSElliott Hughes assert tto.disassembleInstructions is False 405*e1fe3e4aSElliott Hughes 406*e1fe3e4aSElliott Hughes 407*e1fe3e4aSElliott Hughesdef test_options_z_validoptions(): 408*e1fe3e4aSElliott Hughes valid_options = ("raw", "row", "bitwise", "extfile") 409*e1fe3e4aSElliott Hughes for option in valid_options: 410*e1fe3e4aSElliott Hughes tto = ttx.Options([("-z", option)], 1) 411*e1fe3e4aSElliott Hughes assert tto.bitmapGlyphDataFormat == option 412*e1fe3e4aSElliott Hughes 413*e1fe3e4aSElliott Hughes 414*e1fe3e4aSElliott Hughesdef test_options_z_invalidoption(): 415*e1fe3e4aSElliott Hughes with pytest.raises(getopt.GetoptError): 416*e1fe3e4aSElliott Hughes ttx.Options([("-z", "bogus")], 1) 417*e1fe3e4aSElliott Hughes 418*e1fe3e4aSElliott Hughes 419*e1fe3e4aSElliott Hughesdef test_options_y_validvalue(): 420*e1fe3e4aSElliott Hughes tto = ttx.Options([("-y", "1")], 1) 421*e1fe3e4aSElliott Hughes assert tto.fontNumber == 1 422*e1fe3e4aSElliott Hughes 423*e1fe3e4aSElliott Hughes 424*e1fe3e4aSElliott Hughesdef test_options_y_invalidvalue(): 425*e1fe3e4aSElliott Hughes with pytest.raises(ValueError): 426*e1fe3e4aSElliott Hughes ttx.Options([("-y", "A")], 1) 427*e1fe3e4aSElliott Hughes 428*e1fe3e4aSElliott Hughes 429*e1fe3e4aSElliott Hughesdef test_options_m(): 430*e1fe3e4aSElliott Hughes tto = ttx.Options([("-m", "testfont.ttf")], 1) 431*e1fe3e4aSElliott Hughes assert tto.mergeFile == "testfont.ttf" 432*e1fe3e4aSElliott Hughes 433*e1fe3e4aSElliott Hughes 434*e1fe3e4aSElliott Hughesdef test_options_b(): 435*e1fe3e4aSElliott Hughes tto = ttx.Options([("-b", "")], 1) 436*e1fe3e4aSElliott Hughes assert tto.recalcBBoxes is False 437*e1fe3e4aSElliott Hughes 438*e1fe3e4aSElliott Hughes 439*e1fe3e4aSElliott Hughesdef test_options_e(): 440*e1fe3e4aSElliott Hughes tto = ttx.Options([("-e", "")], 1) 441*e1fe3e4aSElliott Hughes assert tto.ignoreDecompileErrors is False 442*e1fe3e4aSElliott Hughes 443*e1fe3e4aSElliott Hughes 444*e1fe3e4aSElliott Hughesdef test_options_unicodedata(): 445*e1fe3e4aSElliott Hughes tto = ttx.Options([("--unicodedata", "UnicodeData.txt")], 1) 446*e1fe3e4aSElliott Hughes assert tto.unicodedata == "UnicodeData.txt" 447*e1fe3e4aSElliott Hughes 448*e1fe3e4aSElliott Hughes 449*e1fe3e4aSElliott Hughesdef test_options_newline_lf(): 450*e1fe3e4aSElliott Hughes tto = ttx.Options([("--newline", "LF")], 1) 451*e1fe3e4aSElliott Hughes assert tto.newlinestr == "\n" 452*e1fe3e4aSElliott Hughes 453*e1fe3e4aSElliott Hughes 454*e1fe3e4aSElliott Hughesdef test_options_newline_cr(): 455*e1fe3e4aSElliott Hughes tto = ttx.Options([("--newline", "CR")], 1) 456*e1fe3e4aSElliott Hughes assert tto.newlinestr == "\r" 457*e1fe3e4aSElliott Hughes 458*e1fe3e4aSElliott Hughes 459*e1fe3e4aSElliott Hughesdef test_options_newline_crlf(): 460*e1fe3e4aSElliott Hughes tto = ttx.Options([("--newline", "CRLF")], 1) 461*e1fe3e4aSElliott Hughes assert tto.newlinestr == "\r\n" 462*e1fe3e4aSElliott Hughes 463*e1fe3e4aSElliott Hughes 464*e1fe3e4aSElliott Hughesdef test_options_newline_invalid(): 465*e1fe3e4aSElliott Hughes with pytest.raises(getopt.GetoptError): 466*e1fe3e4aSElliott Hughes ttx.Options([("--newline", "BOGUS")], 1) 467*e1fe3e4aSElliott Hughes 468*e1fe3e4aSElliott Hughes 469*e1fe3e4aSElliott Hughesdef test_options_recalc_timestamp(): 470*e1fe3e4aSElliott Hughes tto = ttx.Options([("--recalc-timestamp", "")], 1) 471*e1fe3e4aSElliott Hughes assert tto.recalcTimestamp is True 472*e1fe3e4aSElliott Hughes 473*e1fe3e4aSElliott Hughes 474*e1fe3e4aSElliott Hughesdef test_options_recalc_timestamp(): 475*e1fe3e4aSElliott Hughes tto = ttx.Options([("--no-recalc-timestamp", "")], 1) 476*e1fe3e4aSElliott Hughes assert tto.recalcTimestamp is False 477*e1fe3e4aSElliott Hughes 478*e1fe3e4aSElliott Hughes 479*e1fe3e4aSElliott Hughesdef test_options_flavor(): 480*e1fe3e4aSElliott Hughes tto = ttx.Options([("--flavor", "woff")], 1) 481*e1fe3e4aSElliott Hughes assert tto.flavor == "woff" 482*e1fe3e4aSElliott Hughes 483*e1fe3e4aSElliott Hughes 484*e1fe3e4aSElliott Hughesdef test_options_with_zopfli(): 485*e1fe3e4aSElliott Hughes tto = ttx.Options([("--with-zopfli", ""), ("--flavor", "woff")], 1) 486*e1fe3e4aSElliott Hughes assert tto.useZopfli is True 487*e1fe3e4aSElliott Hughes 488*e1fe3e4aSElliott Hughes 489*e1fe3e4aSElliott Hughesdef test_options_with_zopfli_fails_without_woff_flavor(): 490*e1fe3e4aSElliott Hughes with pytest.raises(getopt.GetoptError): 491*e1fe3e4aSElliott Hughes ttx.Options([("--with-zopfli", "")], 1) 492*e1fe3e4aSElliott Hughes 493*e1fe3e4aSElliott Hughes 494*e1fe3e4aSElliott Hughesdef test_options_quiet_and_verbose_shouldfail(): 495*e1fe3e4aSElliott Hughes with pytest.raises(getopt.GetoptError): 496*e1fe3e4aSElliott Hughes ttx.Options([("-q", ""), ("-v", "")], 1) 497*e1fe3e4aSElliott Hughes 498*e1fe3e4aSElliott Hughes 499*e1fe3e4aSElliott Hughesdef test_options_mergefile_and_flavor_shouldfail(): 500*e1fe3e4aSElliott Hughes with pytest.raises(getopt.GetoptError): 501*e1fe3e4aSElliott Hughes ttx.Options([("-m", "testfont.ttf"), ("--flavor", "woff")], 1) 502*e1fe3e4aSElliott Hughes 503*e1fe3e4aSElliott Hughes 504*e1fe3e4aSElliott Hughesdef test_options_onlytables_and_skiptables_shouldfail(): 505*e1fe3e4aSElliott Hughes with pytest.raises(getopt.GetoptError): 506*e1fe3e4aSElliott Hughes ttx.Options([("-t", "CFF"), ("-x", "CFF2")], 1) 507*e1fe3e4aSElliott Hughes 508*e1fe3e4aSElliott Hughes 509*e1fe3e4aSElliott Hughesdef test_options_mergefile_and_multiplefiles_shouldfail(): 510*e1fe3e4aSElliott Hughes with pytest.raises(getopt.GetoptError): 511*e1fe3e4aSElliott Hughes ttx.Options([("-m", "testfont.ttf")], 2) 512*e1fe3e4aSElliott Hughes 513*e1fe3e4aSElliott Hughes 514*e1fe3e4aSElliott Hughesdef test_options_woff2_and_zopfli_shouldfail(): 515*e1fe3e4aSElliott Hughes with pytest.raises(getopt.GetoptError): 516*e1fe3e4aSElliott Hughes ttx.Options([("--with-zopfli", ""), ("--flavor", "woff2")], 1) 517*e1fe3e4aSElliott Hughes 518*e1fe3e4aSElliott Hughes 519*e1fe3e4aSElliott Hughes# ---------------------------- 520*e1fe3e4aSElliott Hughes# ttx.ttCompile function tests 521*e1fe3e4aSElliott Hughes# ---------------------------- 522*e1fe3e4aSElliott Hughes 523*e1fe3e4aSElliott Hughes 524*e1fe3e4aSElliott Hughesdef test_ttcompile_otf_compile_default(tmpdir): 525*e1fe3e4aSElliott Hughes inttx = os.path.join("Tests", "ttx", "data", "TestOTF.ttx") 526*e1fe3e4aSElliott Hughes # outotf = os.path.join(str(tmpdir), "TestOTF.otf") 527*e1fe3e4aSElliott Hughes outotf = tmpdir.join("TestOTF.ttx") 528*e1fe3e4aSElliott Hughes default_options = ttx.Options([], 1) 529*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outotf), default_options) 530*e1fe3e4aSElliott Hughes # confirm that font was built 531*e1fe3e4aSElliott Hughes assert outotf.check(file=True) 532*e1fe3e4aSElliott Hughes # confirm that it is valid OTF file, can instantiate a TTFont, has expected OpenType tables 533*e1fe3e4aSElliott Hughes ttf = TTFont(str(outotf)) 534*e1fe3e4aSElliott Hughes expected_tables = ( 535*e1fe3e4aSElliott Hughes "head", 536*e1fe3e4aSElliott Hughes "hhea", 537*e1fe3e4aSElliott Hughes "maxp", 538*e1fe3e4aSElliott Hughes "OS/2", 539*e1fe3e4aSElliott Hughes "name", 540*e1fe3e4aSElliott Hughes "cmap", 541*e1fe3e4aSElliott Hughes "post", 542*e1fe3e4aSElliott Hughes "CFF ", 543*e1fe3e4aSElliott Hughes "hmtx", 544*e1fe3e4aSElliott Hughes "DSIG", 545*e1fe3e4aSElliott Hughes ) 546*e1fe3e4aSElliott Hughes for table in expected_tables: 547*e1fe3e4aSElliott Hughes assert table in ttf 548*e1fe3e4aSElliott Hughes 549*e1fe3e4aSElliott Hughes 550*e1fe3e4aSElliott Hughesdef test_ttcompile_otf_to_woff_without_zopfli(tmpdir): 551*e1fe3e4aSElliott Hughes inttx = os.path.join("Tests", "ttx", "data", "TestOTF.ttx") 552*e1fe3e4aSElliott Hughes outwoff = tmpdir.join("TestOTF.woff") 553*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 554*e1fe3e4aSElliott Hughes options.flavor = "woff" 555*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outwoff), options) 556*e1fe3e4aSElliott Hughes # confirm that font was built 557*e1fe3e4aSElliott Hughes assert outwoff.check(file=True) 558*e1fe3e4aSElliott Hughes # confirm that it is valid TTF file, can instantiate a TTFont, has expected OpenType tables 559*e1fe3e4aSElliott Hughes ttf = TTFont(str(outwoff)) 560*e1fe3e4aSElliott Hughes expected_tables = ( 561*e1fe3e4aSElliott Hughes "head", 562*e1fe3e4aSElliott Hughes "hhea", 563*e1fe3e4aSElliott Hughes "maxp", 564*e1fe3e4aSElliott Hughes "OS/2", 565*e1fe3e4aSElliott Hughes "name", 566*e1fe3e4aSElliott Hughes "cmap", 567*e1fe3e4aSElliott Hughes "post", 568*e1fe3e4aSElliott Hughes "CFF ", 569*e1fe3e4aSElliott Hughes "hmtx", 570*e1fe3e4aSElliott Hughes "DSIG", 571*e1fe3e4aSElliott Hughes ) 572*e1fe3e4aSElliott Hughes for table in expected_tables: 573*e1fe3e4aSElliott Hughes assert table in ttf 574*e1fe3e4aSElliott Hughes 575*e1fe3e4aSElliott Hughes 576*e1fe3e4aSElliott Hughes@pytest.mark.skipif(zopfli is None, reason="zopfli not installed") 577*e1fe3e4aSElliott Hughesdef test_ttcompile_otf_to_woff_with_zopfli(tmpdir): 578*e1fe3e4aSElliott Hughes inttx = os.path.join("Tests", "ttx", "data", "TestOTF.ttx") 579*e1fe3e4aSElliott Hughes outwoff = tmpdir.join("TestOTF.woff") 580*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 581*e1fe3e4aSElliott Hughes options.flavor = "woff" 582*e1fe3e4aSElliott Hughes options.useZopfli = True 583*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outwoff), options) 584*e1fe3e4aSElliott Hughes # confirm that font was built 585*e1fe3e4aSElliott Hughes assert outwoff.check(file=True) 586*e1fe3e4aSElliott Hughes # confirm that it is valid TTF file, can instantiate a TTFont, has expected OpenType tables 587*e1fe3e4aSElliott Hughes ttf = TTFont(str(outwoff)) 588*e1fe3e4aSElliott Hughes expected_tables = ( 589*e1fe3e4aSElliott Hughes "head", 590*e1fe3e4aSElliott Hughes "hhea", 591*e1fe3e4aSElliott Hughes "maxp", 592*e1fe3e4aSElliott Hughes "OS/2", 593*e1fe3e4aSElliott Hughes "name", 594*e1fe3e4aSElliott Hughes "cmap", 595*e1fe3e4aSElliott Hughes "post", 596*e1fe3e4aSElliott Hughes "CFF ", 597*e1fe3e4aSElliott Hughes "hmtx", 598*e1fe3e4aSElliott Hughes "DSIG", 599*e1fe3e4aSElliott Hughes ) 600*e1fe3e4aSElliott Hughes for table in expected_tables: 601*e1fe3e4aSElliott Hughes assert table in ttf 602*e1fe3e4aSElliott Hughes 603*e1fe3e4aSElliott Hughes 604*e1fe3e4aSElliott Hughes@pytest.mark.skipif(brotli is None, reason="brotli not installed") 605*e1fe3e4aSElliott Hughesdef test_ttcompile_otf_to_woff2(tmpdir): 606*e1fe3e4aSElliott Hughes inttx = os.path.join("Tests", "ttx", "data", "TestOTF.ttx") 607*e1fe3e4aSElliott Hughes outwoff2 = tmpdir.join("TestTTF.woff2") 608*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 609*e1fe3e4aSElliott Hughes options.flavor = "woff2" 610*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outwoff2), options) 611*e1fe3e4aSElliott Hughes # confirm that font was built 612*e1fe3e4aSElliott Hughes assert outwoff2.check(file=True) 613*e1fe3e4aSElliott Hughes # confirm that it is valid TTF file, can instantiate a TTFont, has expected OpenType tables 614*e1fe3e4aSElliott Hughes ttf = TTFont(str(outwoff2)) 615*e1fe3e4aSElliott Hughes # DSIG should not be included from original ttx as per woff2 spec (https://dev.w3.org/webfonts/WOFF2/spec/) 616*e1fe3e4aSElliott Hughes assert "DSIG" not in ttf 617*e1fe3e4aSElliott Hughes expected_tables = ( 618*e1fe3e4aSElliott Hughes "head", 619*e1fe3e4aSElliott Hughes "hhea", 620*e1fe3e4aSElliott Hughes "maxp", 621*e1fe3e4aSElliott Hughes "OS/2", 622*e1fe3e4aSElliott Hughes "name", 623*e1fe3e4aSElliott Hughes "cmap", 624*e1fe3e4aSElliott Hughes "post", 625*e1fe3e4aSElliott Hughes "CFF ", 626*e1fe3e4aSElliott Hughes "hmtx", 627*e1fe3e4aSElliott Hughes ) 628*e1fe3e4aSElliott Hughes for table in expected_tables: 629*e1fe3e4aSElliott Hughes assert table in ttf 630*e1fe3e4aSElliott Hughes 631*e1fe3e4aSElliott Hughes 632*e1fe3e4aSElliott Hughesdef test_ttcompile_ttf_compile_default(tmpdir): 633*e1fe3e4aSElliott Hughes inttx = os.path.join("Tests", "ttx", "data", "TestTTF.ttx") 634*e1fe3e4aSElliott Hughes outttf = tmpdir.join("TestTTF.ttf") 635*e1fe3e4aSElliott Hughes default_options = ttx.Options([], 1) 636*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outttf), default_options) 637*e1fe3e4aSElliott Hughes # confirm that font was built 638*e1fe3e4aSElliott Hughes assert outttf.check(file=True) 639*e1fe3e4aSElliott Hughes # confirm that it is valid TTF file, can instantiate a TTFont, has expected OpenType tables 640*e1fe3e4aSElliott Hughes ttf = TTFont(str(outttf)) 641*e1fe3e4aSElliott Hughes expected_tables = ( 642*e1fe3e4aSElliott Hughes "head", 643*e1fe3e4aSElliott Hughes "hhea", 644*e1fe3e4aSElliott Hughes "maxp", 645*e1fe3e4aSElliott Hughes "OS/2", 646*e1fe3e4aSElliott Hughes "name", 647*e1fe3e4aSElliott Hughes "cmap", 648*e1fe3e4aSElliott Hughes "hmtx", 649*e1fe3e4aSElliott Hughes "fpgm", 650*e1fe3e4aSElliott Hughes "prep", 651*e1fe3e4aSElliott Hughes "cvt ", 652*e1fe3e4aSElliott Hughes "loca", 653*e1fe3e4aSElliott Hughes "glyf", 654*e1fe3e4aSElliott Hughes "post", 655*e1fe3e4aSElliott Hughes "gasp", 656*e1fe3e4aSElliott Hughes "DSIG", 657*e1fe3e4aSElliott Hughes ) 658*e1fe3e4aSElliott Hughes for table in expected_tables: 659*e1fe3e4aSElliott Hughes assert table in ttf 660*e1fe3e4aSElliott Hughes 661*e1fe3e4aSElliott Hughes 662*e1fe3e4aSElliott Hughesdef test_ttcompile_ttf_to_woff_without_zopfli(tmpdir): 663*e1fe3e4aSElliott Hughes inttx = os.path.join("Tests", "ttx", "data", "TestTTF.ttx") 664*e1fe3e4aSElliott Hughes outwoff = tmpdir.join("TestTTF.woff") 665*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 666*e1fe3e4aSElliott Hughes options.flavor = "woff" 667*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outwoff), options) 668*e1fe3e4aSElliott Hughes # confirm that font was built 669*e1fe3e4aSElliott Hughes assert outwoff.check(file=True) 670*e1fe3e4aSElliott Hughes # confirm that it is valid TTF file, can instantiate a TTFont, has expected OpenType tables 671*e1fe3e4aSElliott Hughes ttf = TTFont(str(outwoff)) 672*e1fe3e4aSElliott Hughes expected_tables = ( 673*e1fe3e4aSElliott Hughes "head", 674*e1fe3e4aSElliott Hughes "hhea", 675*e1fe3e4aSElliott Hughes "maxp", 676*e1fe3e4aSElliott Hughes "OS/2", 677*e1fe3e4aSElliott Hughes "name", 678*e1fe3e4aSElliott Hughes "cmap", 679*e1fe3e4aSElliott Hughes "hmtx", 680*e1fe3e4aSElliott Hughes "fpgm", 681*e1fe3e4aSElliott Hughes "prep", 682*e1fe3e4aSElliott Hughes "cvt ", 683*e1fe3e4aSElliott Hughes "loca", 684*e1fe3e4aSElliott Hughes "glyf", 685*e1fe3e4aSElliott Hughes "post", 686*e1fe3e4aSElliott Hughes "gasp", 687*e1fe3e4aSElliott Hughes "DSIG", 688*e1fe3e4aSElliott Hughes ) 689*e1fe3e4aSElliott Hughes for table in expected_tables: 690*e1fe3e4aSElliott Hughes assert table in ttf 691*e1fe3e4aSElliott Hughes 692*e1fe3e4aSElliott Hughes 693*e1fe3e4aSElliott Hughes@pytest.mark.skipif(zopfli is None, reason="zopfli not installed") 694*e1fe3e4aSElliott Hughesdef test_ttcompile_ttf_to_woff_with_zopfli(tmpdir): 695*e1fe3e4aSElliott Hughes inttx = os.path.join("Tests", "ttx", "data", "TestTTF.ttx") 696*e1fe3e4aSElliott Hughes outwoff = tmpdir.join("TestTTF.woff") 697*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 698*e1fe3e4aSElliott Hughes options.flavor = "woff" 699*e1fe3e4aSElliott Hughes options.useZopfli = True 700*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outwoff), options) 701*e1fe3e4aSElliott Hughes # confirm that font was built 702*e1fe3e4aSElliott Hughes assert outwoff.check(file=True) 703*e1fe3e4aSElliott Hughes # confirm that it is valid TTF file, can instantiate a TTFont, has expected OpenType tables 704*e1fe3e4aSElliott Hughes ttf = TTFont(str(outwoff)) 705*e1fe3e4aSElliott Hughes expected_tables = ( 706*e1fe3e4aSElliott Hughes "head", 707*e1fe3e4aSElliott Hughes "hhea", 708*e1fe3e4aSElliott Hughes "maxp", 709*e1fe3e4aSElliott Hughes "OS/2", 710*e1fe3e4aSElliott Hughes "name", 711*e1fe3e4aSElliott Hughes "cmap", 712*e1fe3e4aSElliott Hughes "hmtx", 713*e1fe3e4aSElliott Hughes "fpgm", 714*e1fe3e4aSElliott Hughes "prep", 715*e1fe3e4aSElliott Hughes "cvt ", 716*e1fe3e4aSElliott Hughes "loca", 717*e1fe3e4aSElliott Hughes "glyf", 718*e1fe3e4aSElliott Hughes "post", 719*e1fe3e4aSElliott Hughes "gasp", 720*e1fe3e4aSElliott Hughes "DSIG", 721*e1fe3e4aSElliott Hughes ) 722*e1fe3e4aSElliott Hughes for table in expected_tables: 723*e1fe3e4aSElliott Hughes assert table in ttf 724*e1fe3e4aSElliott Hughes 725*e1fe3e4aSElliott Hughes 726*e1fe3e4aSElliott Hughes@pytest.mark.skipif(brotli is None, reason="brotli not installed") 727*e1fe3e4aSElliott Hughesdef test_ttcompile_ttf_to_woff2(tmpdir): 728*e1fe3e4aSElliott Hughes inttx = os.path.join("Tests", "ttx", "data", "TestTTF.ttx") 729*e1fe3e4aSElliott Hughes outwoff2 = tmpdir.join("TestTTF.woff2") 730*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 731*e1fe3e4aSElliott Hughes options.flavor = "woff2" 732*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outwoff2), options) 733*e1fe3e4aSElliott Hughes # confirm that font was built 734*e1fe3e4aSElliott Hughes assert outwoff2.check(file=True) 735*e1fe3e4aSElliott Hughes # confirm that it is valid TTF file, can instantiate a TTFont, has expected OpenType tables 736*e1fe3e4aSElliott Hughes ttf = TTFont(str(outwoff2)) 737*e1fe3e4aSElliott Hughes # DSIG should not be included from original ttx as per woff2 spec (https://dev.w3.org/webfonts/WOFF2/spec/) 738*e1fe3e4aSElliott Hughes assert "DSIG" not in ttf 739*e1fe3e4aSElliott Hughes expected_tables = ( 740*e1fe3e4aSElliott Hughes "head", 741*e1fe3e4aSElliott Hughes "hhea", 742*e1fe3e4aSElliott Hughes "maxp", 743*e1fe3e4aSElliott Hughes "OS/2", 744*e1fe3e4aSElliott Hughes "name", 745*e1fe3e4aSElliott Hughes "cmap", 746*e1fe3e4aSElliott Hughes "hmtx", 747*e1fe3e4aSElliott Hughes "fpgm", 748*e1fe3e4aSElliott Hughes "prep", 749*e1fe3e4aSElliott Hughes "cvt ", 750*e1fe3e4aSElliott Hughes "loca", 751*e1fe3e4aSElliott Hughes "glyf", 752*e1fe3e4aSElliott Hughes "post", 753*e1fe3e4aSElliott Hughes "gasp", 754*e1fe3e4aSElliott Hughes ) 755*e1fe3e4aSElliott Hughes for table in expected_tables: 756*e1fe3e4aSElliott Hughes assert table in ttf 757*e1fe3e4aSElliott Hughes 758*e1fe3e4aSElliott Hughes 759*e1fe3e4aSElliott Hughes@pytest.mark.parametrize( 760*e1fe3e4aSElliott Hughes "inpath, outpath1, outpath2", 761*e1fe3e4aSElliott Hughes [ 762*e1fe3e4aSElliott Hughes ("TestTTF.ttx", "TestTTF1.ttf", "TestTTF2.ttf"), 763*e1fe3e4aSElliott Hughes ("TestOTF.ttx", "TestOTF1.otf", "TestOTF2.otf"), 764*e1fe3e4aSElliott Hughes ], 765*e1fe3e4aSElliott Hughes) 766*e1fe3e4aSElliott Hughesdef test_ttcompile_timestamp_calcs(inpath, outpath1, outpath2, tmpdir): 767*e1fe3e4aSElliott Hughes inttx = os.path.join("Tests", "ttx", "data", inpath) 768*e1fe3e4aSElliott Hughes outttf1 = tmpdir.join(outpath1) 769*e1fe3e4aSElliott Hughes outttf2 = tmpdir.join(outpath2) 770*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 771*e1fe3e4aSElliott Hughes # build with default options = do not recalculate timestamp 772*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outttf1), options) 773*e1fe3e4aSElliott Hughes # confirm that font was built 774*e1fe3e4aSElliott Hughes assert outttf1.check(file=True) 775*e1fe3e4aSElliott Hughes # confirm that timestamp is same as modified time on ttx file 776*e1fe3e4aSElliott Hughes mtime = os.path.getmtime(inttx) 777*e1fe3e4aSElliott Hughes epochtime = timestampSinceEpoch(mtime) 778*e1fe3e4aSElliott Hughes ttf = TTFont(str(outttf1)) 779*e1fe3e4aSElliott Hughes assert ttf["head"].modified == epochtime 780*e1fe3e4aSElliott Hughes 781*e1fe3e4aSElliott Hughes # reset options to recalculate the timestamp and compile new font 782*e1fe3e4aSElliott Hughes options.recalcTimestamp = True 783*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outttf2), options) 784*e1fe3e4aSElliott Hughes # confirm that font was built 785*e1fe3e4aSElliott Hughes assert outttf2.check(file=True) 786*e1fe3e4aSElliott Hughes # confirm that timestamp is more recent than modified time on ttx file 787*e1fe3e4aSElliott Hughes mtime = os.path.getmtime(inttx) 788*e1fe3e4aSElliott Hughes epochtime = timestampSinceEpoch(mtime) 789*e1fe3e4aSElliott Hughes ttf = TTFont(str(outttf2)) 790*e1fe3e4aSElliott Hughes assert ttf["head"].modified > epochtime 791*e1fe3e4aSElliott Hughes 792*e1fe3e4aSElliott Hughes # --no-recalc-timestamp will keep original timestamp 793*e1fe3e4aSElliott Hughes options.recalcTimestamp = False 794*e1fe3e4aSElliott Hughes ttx.ttCompile(inttx, str(outttf2), options) 795*e1fe3e4aSElliott Hughes assert outttf2.check(file=True) 796*e1fe3e4aSElliott Hughes inttf = TTFont() 797*e1fe3e4aSElliott Hughes inttf.importXML(inttx) 798*e1fe3e4aSElliott Hughes assert inttf["head"].modified == TTFont(str(outttf2))["head"].modified 799*e1fe3e4aSElliott Hughes 800*e1fe3e4aSElliott Hughes 801*e1fe3e4aSElliott Hughes# ------------------------- 802*e1fe3e4aSElliott Hughes# ttx.ttList function tests 803*e1fe3e4aSElliott Hughes# ------------------------- 804*e1fe3e4aSElliott Hughes 805*e1fe3e4aSElliott Hughes 806*e1fe3e4aSElliott Hughesdef test_ttlist_ttf(capsys, tmpdir): 807*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestTTF.ttf") 808*e1fe3e4aSElliott Hughes fakeoutpath = tmpdir.join("TestTTF.ttx") 809*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 810*e1fe3e4aSElliott Hughes options.listTables = True 811*e1fe3e4aSElliott Hughes ttx.ttList(inpath, str(fakeoutpath), options) 812*e1fe3e4aSElliott Hughes out, err = capsys.readouterr() 813*e1fe3e4aSElliott Hughes expected_tables = ( 814*e1fe3e4aSElliott Hughes "head", 815*e1fe3e4aSElliott Hughes "hhea", 816*e1fe3e4aSElliott Hughes "maxp", 817*e1fe3e4aSElliott Hughes "OS/2", 818*e1fe3e4aSElliott Hughes "name", 819*e1fe3e4aSElliott Hughes "cmap", 820*e1fe3e4aSElliott Hughes "hmtx", 821*e1fe3e4aSElliott Hughes "fpgm", 822*e1fe3e4aSElliott Hughes "prep", 823*e1fe3e4aSElliott Hughes "cvt ", 824*e1fe3e4aSElliott Hughes "loca", 825*e1fe3e4aSElliott Hughes "glyf", 826*e1fe3e4aSElliott Hughes "post", 827*e1fe3e4aSElliott Hughes "gasp", 828*e1fe3e4aSElliott Hughes "DSIG", 829*e1fe3e4aSElliott Hughes ) 830*e1fe3e4aSElliott Hughes # confirm that expected tables are printed to stdout 831*e1fe3e4aSElliott Hughes for table in expected_tables: 832*e1fe3e4aSElliott Hughes assert table in out 833*e1fe3e4aSElliott Hughes # test for one of the expected tag/checksum/length/offset strings 834*e1fe3e4aSElliott Hughes assert "OS/2 0x67230FF8 96 376" in out 835*e1fe3e4aSElliott Hughes 836*e1fe3e4aSElliott Hughes 837*e1fe3e4aSElliott Hughesdef test_ttlist_otf(capsys, tmpdir): 838*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestOTF.otf") 839*e1fe3e4aSElliott Hughes fakeoutpath = tmpdir.join("TestOTF.ttx") 840*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 841*e1fe3e4aSElliott Hughes options.listTables = True 842*e1fe3e4aSElliott Hughes ttx.ttList(inpath, str(fakeoutpath), options) 843*e1fe3e4aSElliott Hughes out, err = capsys.readouterr() 844*e1fe3e4aSElliott Hughes expected_tables = ( 845*e1fe3e4aSElliott Hughes "head", 846*e1fe3e4aSElliott Hughes "hhea", 847*e1fe3e4aSElliott Hughes "maxp", 848*e1fe3e4aSElliott Hughes "OS/2", 849*e1fe3e4aSElliott Hughes "name", 850*e1fe3e4aSElliott Hughes "cmap", 851*e1fe3e4aSElliott Hughes "post", 852*e1fe3e4aSElliott Hughes "CFF ", 853*e1fe3e4aSElliott Hughes "hmtx", 854*e1fe3e4aSElliott Hughes "DSIG", 855*e1fe3e4aSElliott Hughes ) 856*e1fe3e4aSElliott Hughes # confirm that expected tables are printed to stdout 857*e1fe3e4aSElliott Hughes for table in expected_tables: 858*e1fe3e4aSElliott Hughes assert table in out 859*e1fe3e4aSElliott Hughes # test for one of the expected tag/checksum/length/offset strings 860*e1fe3e4aSElliott Hughes assert "OS/2 0x67230FF8 96 272" in out 861*e1fe3e4aSElliott Hughes 862*e1fe3e4aSElliott Hughes 863*e1fe3e4aSElliott Hughesdef test_ttlist_woff(capsys, tmpdir): 864*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestWOFF.woff") 865*e1fe3e4aSElliott Hughes fakeoutpath = tmpdir.join("TestWOFF.ttx") 866*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 867*e1fe3e4aSElliott Hughes options.listTables = True 868*e1fe3e4aSElliott Hughes options.flavor = "woff" 869*e1fe3e4aSElliott Hughes ttx.ttList(inpath, str(fakeoutpath), options) 870*e1fe3e4aSElliott Hughes out, err = capsys.readouterr() 871*e1fe3e4aSElliott Hughes expected_tables = ( 872*e1fe3e4aSElliott Hughes "head", 873*e1fe3e4aSElliott Hughes "hhea", 874*e1fe3e4aSElliott Hughes "maxp", 875*e1fe3e4aSElliott Hughes "OS/2", 876*e1fe3e4aSElliott Hughes "name", 877*e1fe3e4aSElliott Hughes "cmap", 878*e1fe3e4aSElliott Hughes "post", 879*e1fe3e4aSElliott Hughes "CFF ", 880*e1fe3e4aSElliott Hughes "hmtx", 881*e1fe3e4aSElliott Hughes "DSIG", 882*e1fe3e4aSElliott Hughes ) 883*e1fe3e4aSElliott Hughes # confirm that expected tables are printed to stdout 884*e1fe3e4aSElliott Hughes for table in expected_tables: 885*e1fe3e4aSElliott Hughes assert table in out 886*e1fe3e4aSElliott Hughes # test for one of the expected tag/checksum/length/offset strings 887*e1fe3e4aSElliott Hughes assert "OS/2 0x67230FF8 84 340" in out 888*e1fe3e4aSElliott Hughes 889*e1fe3e4aSElliott Hughes 890*e1fe3e4aSElliott Hughes@pytest.mark.skipif(brotli is None, reason="brotli not installed") 891*e1fe3e4aSElliott Hughesdef test_ttlist_woff2(capsys, tmpdir): 892*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestWOFF2.woff2") 893*e1fe3e4aSElliott Hughes fakeoutpath = tmpdir.join("TestWOFF2.ttx") 894*e1fe3e4aSElliott Hughes options = ttx.Options([], 1) 895*e1fe3e4aSElliott Hughes options.listTables = True 896*e1fe3e4aSElliott Hughes options.flavor = "woff2" 897*e1fe3e4aSElliott Hughes ttx.ttList(inpath, str(fakeoutpath), options) 898*e1fe3e4aSElliott Hughes out, err = capsys.readouterr() 899*e1fe3e4aSElliott Hughes expected_tables = ( 900*e1fe3e4aSElliott Hughes "head", 901*e1fe3e4aSElliott Hughes "hhea", 902*e1fe3e4aSElliott Hughes "maxp", 903*e1fe3e4aSElliott Hughes "OS/2", 904*e1fe3e4aSElliott Hughes "name", 905*e1fe3e4aSElliott Hughes "cmap", 906*e1fe3e4aSElliott Hughes "hmtx", 907*e1fe3e4aSElliott Hughes "fpgm", 908*e1fe3e4aSElliott Hughes "prep", 909*e1fe3e4aSElliott Hughes "cvt ", 910*e1fe3e4aSElliott Hughes "loca", 911*e1fe3e4aSElliott Hughes "glyf", 912*e1fe3e4aSElliott Hughes "post", 913*e1fe3e4aSElliott Hughes "gasp", 914*e1fe3e4aSElliott Hughes ) 915*e1fe3e4aSElliott Hughes # confirm that expected tables are printed to stdout 916*e1fe3e4aSElliott Hughes for table in expected_tables: 917*e1fe3e4aSElliott Hughes assert table in out 918*e1fe3e4aSElliott Hughes # test for one of the expected tag/checksum/length/offset strings 919*e1fe3e4aSElliott Hughes assert "OS/2 0x67230FF8 96 0" in out 920*e1fe3e4aSElliott Hughes 921*e1fe3e4aSElliott Hughes 922*e1fe3e4aSElliott Hughes# ------------------- 923*e1fe3e4aSElliott Hughes# main function tests 924*e1fe3e4aSElliott Hughes# ------------------- 925*e1fe3e4aSElliott Hughes 926*e1fe3e4aSElliott Hughes 927*e1fe3e4aSElliott Hughesdef test_main_default_ttf_dump_to_ttx(tmpdir): 928*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestTTF.ttf") 929*e1fe3e4aSElliott Hughes outpath = tmpdir.join("TestTTF.ttx") 930*e1fe3e4aSElliott Hughes args = ["-o", str(outpath), inpath] 931*e1fe3e4aSElliott Hughes ttx.main(args) 932*e1fe3e4aSElliott Hughes assert outpath.check(file=True) 933*e1fe3e4aSElliott Hughes 934*e1fe3e4aSElliott Hughes 935*e1fe3e4aSElliott Hughesdef test_main_default_ttx_compile_to_ttf(tmpdir): 936*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestTTF.ttx") 937*e1fe3e4aSElliott Hughes outpath = tmpdir.join("TestTTF.ttf") 938*e1fe3e4aSElliott Hughes args = ["-o", str(outpath), inpath] 939*e1fe3e4aSElliott Hughes ttx.main(args) 940*e1fe3e4aSElliott Hughes assert outpath.check(file=True) 941*e1fe3e4aSElliott Hughes 942*e1fe3e4aSElliott Hughes 943*e1fe3e4aSElliott Hughesdef test_main_getopterror_missing_directory(): 944*e1fe3e4aSElliott Hughes with pytest.raises(SystemExit): 945*e1fe3e4aSElliott Hughes with pytest.raises(getopt.GetoptError): 946*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestTTF.ttf") 947*e1fe3e4aSElliott Hughes args = ["-d", "bogusdir", inpath] 948*e1fe3e4aSElliott Hughes ttx.main(args) 949*e1fe3e4aSElliott Hughes 950*e1fe3e4aSElliott Hughes 951*e1fe3e4aSElliott Hughesdef test_main_keyboard_interrupt(tmpdir, monkeypatch, caplog): 952*e1fe3e4aSElliott Hughes with pytest.raises(SystemExit): 953*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestTTF.ttx") 954*e1fe3e4aSElliott Hughes outpath = tmpdir.join("TestTTF.ttf") 955*e1fe3e4aSElliott Hughes args = ["-o", str(outpath), inpath] 956*e1fe3e4aSElliott Hughes monkeypatch.setattr( 957*e1fe3e4aSElliott Hughes ttx, "process", (lambda x, y: raise_exception(KeyboardInterrupt)) 958*e1fe3e4aSElliott Hughes ) 959*e1fe3e4aSElliott Hughes ttx.main(args) 960*e1fe3e4aSElliott Hughes 961*e1fe3e4aSElliott Hughes assert "(Cancelled.)" in caplog.text 962*e1fe3e4aSElliott Hughes 963*e1fe3e4aSElliott Hughes 964*e1fe3e4aSElliott Hughesdef test_main_system_exit(tmpdir, monkeypatch): 965*e1fe3e4aSElliott Hughes with pytest.raises(SystemExit): 966*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestTTF.ttx") 967*e1fe3e4aSElliott Hughes outpath = tmpdir.join("TestTTF.ttf") 968*e1fe3e4aSElliott Hughes args = ["-o", str(outpath), inpath] 969*e1fe3e4aSElliott Hughes monkeypatch.setattr(ttx, "process", (lambda x, y: raise_exception(SystemExit))) 970*e1fe3e4aSElliott Hughes ttx.main(args) 971*e1fe3e4aSElliott Hughes 972*e1fe3e4aSElliott Hughes 973*e1fe3e4aSElliott Hughesdef test_main_ttlib_error(tmpdir, monkeypatch, caplog): 974*e1fe3e4aSElliott Hughes with pytest.raises(SystemExit): 975*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestTTF.ttx") 976*e1fe3e4aSElliott Hughes outpath = tmpdir.join("TestTTF.ttf") 977*e1fe3e4aSElliott Hughes args = ["-o", str(outpath), inpath] 978*e1fe3e4aSElliott Hughes monkeypatch.setattr( 979*e1fe3e4aSElliott Hughes ttx, 980*e1fe3e4aSElliott Hughes "process", 981*e1fe3e4aSElliott Hughes (lambda x, y: raise_exception(TTLibError("Test error"))), 982*e1fe3e4aSElliott Hughes ) 983*e1fe3e4aSElliott Hughes ttx.main(args) 984*e1fe3e4aSElliott Hughes 985*e1fe3e4aSElliott Hughes assert "Test error" in caplog.text 986*e1fe3e4aSElliott Hughes 987*e1fe3e4aSElliott Hughes 988*e1fe3e4aSElliott Hughesdef test_main_base_exception(tmpdir, monkeypatch, caplog): 989*e1fe3e4aSElliott Hughes with pytest.raises(SystemExit): 990*e1fe3e4aSElliott Hughes inpath = os.path.join("Tests", "ttx", "data", "TestTTF.ttx") 991*e1fe3e4aSElliott Hughes outpath = tmpdir.join("TestTTF.ttf") 992*e1fe3e4aSElliott Hughes args = ["-o", str(outpath), inpath] 993*e1fe3e4aSElliott Hughes monkeypatch.setattr( 994*e1fe3e4aSElliott Hughes ttx, 995*e1fe3e4aSElliott Hughes "process", 996*e1fe3e4aSElliott Hughes (lambda x, y: raise_exception(Exception("Test error"))), 997*e1fe3e4aSElliott Hughes ) 998*e1fe3e4aSElliott Hughes ttx.main(args) 999*e1fe3e4aSElliott Hughes 1000*e1fe3e4aSElliott Hughes assert "Unhandled exception has occurred" in caplog.text 1001*e1fe3e4aSElliott Hughes 1002*e1fe3e4aSElliott Hughes 1003*e1fe3e4aSElliott Hughesdef test_main_ttf_dump_stdin_to_stdout(tmp_path): 1004*e1fe3e4aSElliott Hughes inpath = Path("Tests").joinpath("ttx", "data", "TestTTF.ttf") 1005*e1fe3e4aSElliott Hughes outpath = tmp_path / "TestTTF.ttx" 1006*e1fe3e4aSElliott Hughes args = [sys.executable, "-m", "fontTools.ttx", "-q", "-o", "-", "-"] 1007*e1fe3e4aSElliott Hughes with inpath.open("rb") as infile, outpath.open("w", encoding="utf-8") as outfile: 1008*e1fe3e4aSElliott Hughes subprocess.run(args, check=True, stdin=infile, stdout=outfile) 1009*e1fe3e4aSElliott Hughes assert outpath.is_file() 1010*e1fe3e4aSElliott Hughes 1011*e1fe3e4aSElliott Hughes 1012*e1fe3e4aSElliott Hughesdef test_main_ttx_compile_stdin_to_stdout(tmp_path): 1013*e1fe3e4aSElliott Hughes inpath = Path("Tests").joinpath("ttx", "data", "TestTTF.ttx") 1014*e1fe3e4aSElliott Hughes outpath = tmp_path / "TestTTF.ttf" 1015*e1fe3e4aSElliott Hughes args = [sys.executable, "-m", "fontTools.ttx", "-q", "-o", "-", "-"] 1016*e1fe3e4aSElliott Hughes with inpath.open("r", encoding="utf-8") as infile, outpath.open("wb") as outfile: 1017*e1fe3e4aSElliott Hughes subprocess.run(args, check=True, stdin=infile, stdout=outfile) 1018*e1fe3e4aSElliott Hughes assert outpath.is_file() 1019*e1fe3e4aSElliott Hughes 1020*e1fe3e4aSElliott Hughes 1021*e1fe3e4aSElliott Hughesdef test_roundtrip_DSIG_split_at_XML_parse_buffer_size(tmp_path): 1022*e1fe3e4aSElliott Hughes inpath = Path("Tests").joinpath( 1023*e1fe3e4aSElliott Hughes "ttx", "data", "roundtrip_DSIG_split_at_XML_parse_buffer_size.ttx" 1024*e1fe3e4aSElliott Hughes ) 1025*e1fe3e4aSElliott Hughes font = TTFont() 1026*e1fe3e4aSElliott Hughes font.importXML(inpath) 1027*e1fe3e4aSElliott Hughes font["DMMY"] = DefaultTable(tag="DMMY") 1028*e1fe3e4aSElliott Hughes # just enough dummy bytes to hit the cut off point whereby DSIG data gets 1029*e1fe3e4aSElliott Hughes # split into two chunks and triggers the bug from 1030*e1fe3e4aSElliott Hughes # https://github.com/fonttools/fonttools/issues/2614 1031*e1fe3e4aSElliott Hughes font["DMMY"].data = b"\x01\x02\x03\x04" * 2438 1032*e1fe3e4aSElliott Hughes font.saveXML(tmp_path / "roundtrip_DSIG_split_at_XML_parse_buffer_size.ttx") 1033*e1fe3e4aSElliott Hughes 1034*e1fe3e4aSElliott Hughes outpath = tmp_path / "font.ttf" 1035*e1fe3e4aSElliott Hughes args = [ 1036*e1fe3e4aSElliott Hughes sys.executable, 1037*e1fe3e4aSElliott Hughes "-m", 1038*e1fe3e4aSElliott Hughes "fontTools.ttx", 1039*e1fe3e4aSElliott Hughes "-q", 1040*e1fe3e4aSElliott Hughes "-o", 1041*e1fe3e4aSElliott Hughes str(outpath), 1042*e1fe3e4aSElliott Hughes str(tmp_path / "roundtrip_DSIG_split_at_XML_parse_buffer_size.ttx"), 1043*e1fe3e4aSElliott Hughes ] 1044*e1fe3e4aSElliott Hughes subprocess.run(args, check=True) 1045*e1fe3e4aSElliott Hughes 1046*e1fe3e4aSElliott Hughes assert outpath.is_file() 1047*e1fe3e4aSElliott Hughes assert TTFont(outpath)["DSIG"].signatureRecords[0].pkcs7 == base64.b64decode( 1048*e1fe3e4aSElliott Hughes b"0000000100000000" 1049*e1fe3e4aSElliott Hughes ) 1050*e1fe3e4aSElliott Hughes 1051*e1fe3e4aSElliott Hughes 1052*e1fe3e4aSElliott Hughes# --------------------------- 1053*e1fe3e4aSElliott Hughes# support functions for tests 1054*e1fe3e4aSElliott Hughes# --------------------------- 1055*e1fe3e4aSElliott Hughes 1056*e1fe3e4aSElliott Hughes 1057*e1fe3e4aSElliott Hughesdef raise_exception(exception): 1058*e1fe3e4aSElliott Hughes raise exception 1059