1*e1fe3e4aSElliott Hughesfrom fontTools.ttLib import TTFont 2*e1fe3e4aSElliott Hughesfrom fontTools.varLib import build 3*e1fe3e4aSElliott Hughesfrom fontTools.varLib.mutator import main as mutator 4*e1fe3e4aSElliott Hughesfrom fontTools.varLib.mutator import instantiateVariableFont as make_instance 5*e1fe3e4aSElliott Hughesimport difflib 6*e1fe3e4aSElliott Hughesimport os 7*e1fe3e4aSElliott Hughesimport shutil 8*e1fe3e4aSElliott Hughesimport sys 9*e1fe3e4aSElliott Hughesimport tempfile 10*e1fe3e4aSElliott Hughesimport unittest 11*e1fe3e4aSElliott Hughes 12*e1fe3e4aSElliott Hughes 13*e1fe3e4aSElliott Hughesclass MutatorTest(unittest.TestCase): 14*e1fe3e4aSElliott Hughes def __init__(self, methodName): 15*e1fe3e4aSElliott Hughes unittest.TestCase.__init__(self, methodName) 16*e1fe3e4aSElliott Hughes # Python 3 renamed assertRaisesRegexp to assertRaisesRegex, 17*e1fe3e4aSElliott Hughes # and fires deprecation warnings if a program uses the old name. 18*e1fe3e4aSElliott Hughes if not hasattr(self, "assertRaisesRegex"): 19*e1fe3e4aSElliott Hughes self.assertRaisesRegex = self.assertRaisesRegexp 20*e1fe3e4aSElliott Hughes 21*e1fe3e4aSElliott Hughes def setUp(self): 22*e1fe3e4aSElliott Hughes self.tempdir = None 23*e1fe3e4aSElliott Hughes self.num_tempfiles = 0 24*e1fe3e4aSElliott Hughes 25*e1fe3e4aSElliott Hughes def tearDown(self): 26*e1fe3e4aSElliott Hughes if self.tempdir: 27*e1fe3e4aSElliott Hughes shutil.rmtree(self.tempdir) 28*e1fe3e4aSElliott Hughes 29*e1fe3e4aSElliott Hughes @staticmethod 30*e1fe3e4aSElliott Hughes def get_test_input(test_file_or_folder): 31*e1fe3e4aSElliott Hughes path, _ = os.path.split(__file__) 32*e1fe3e4aSElliott Hughes return os.path.join(path, "data", test_file_or_folder) 33*e1fe3e4aSElliott Hughes 34*e1fe3e4aSElliott Hughes @staticmethod 35*e1fe3e4aSElliott Hughes def get_test_output(test_file_or_folder): 36*e1fe3e4aSElliott Hughes path, _ = os.path.split(__file__) 37*e1fe3e4aSElliott Hughes return os.path.join(path, "data", "test_results", test_file_or_folder) 38*e1fe3e4aSElliott Hughes 39*e1fe3e4aSElliott Hughes @staticmethod 40*e1fe3e4aSElliott Hughes def get_file_list(folder, suffix, prefix=""): 41*e1fe3e4aSElliott Hughes all_files = os.listdir(folder) 42*e1fe3e4aSElliott Hughes file_list = [] 43*e1fe3e4aSElliott Hughes for p in all_files: 44*e1fe3e4aSElliott Hughes if p.startswith(prefix) and p.endswith(suffix): 45*e1fe3e4aSElliott Hughes file_list.append(os.path.abspath(os.path.join(folder, p))) 46*e1fe3e4aSElliott Hughes return file_list 47*e1fe3e4aSElliott Hughes 48*e1fe3e4aSElliott Hughes def temp_path(self, suffix): 49*e1fe3e4aSElliott Hughes self.temp_dir() 50*e1fe3e4aSElliott Hughes self.num_tempfiles += 1 51*e1fe3e4aSElliott Hughes return os.path.join(self.tempdir, "tmp%d%s" % (self.num_tempfiles, suffix)) 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 read_ttx(self, path): 58*e1fe3e4aSElliott Hughes lines = [] 59*e1fe3e4aSElliott Hughes with open(path, "r", encoding="utf-8") as ttx: 60*e1fe3e4aSElliott Hughes for line in ttx.readlines(): 61*e1fe3e4aSElliott Hughes # Elide ttFont attributes because ttLibVersion may change. 62*e1fe3e4aSElliott Hughes if line.startswith("<ttFont "): 63*e1fe3e4aSElliott Hughes lines.append("<ttFont>\n") 64*e1fe3e4aSElliott Hughes else: 65*e1fe3e4aSElliott Hughes lines.append(line.rstrip() + "\n") 66*e1fe3e4aSElliott Hughes return lines 67*e1fe3e4aSElliott Hughes 68*e1fe3e4aSElliott Hughes def expect_ttx(self, font, expected_ttx, tables): 69*e1fe3e4aSElliott Hughes path = self.temp_path(suffix=".ttx") 70*e1fe3e4aSElliott Hughes font.saveXML(path, tables=tables) 71*e1fe3e4aSElliott Hughes actual = self.read_ttx(path) 72*e1fe3e4aSElliott Hughes expected = self.read_ttx(expected_ttx) 73*e1fe3e4aSElliott Hughes if actual != expected: 74*e1fe3e4aSElliott Hughes for line in difflib.unified_diff( 75*e1fe3e4aSElliott Hughes expected, actual, fromfile=expected_ttx, tofile=path 76*e1fe3e4aSElliott Hughes ): 77*e1fe3e4aSElliott Hughes sys.stdout.write(line) 78*e1fe3e4aSElliott Hughes self.fail("TTX output is different from expected") 79*e1fe3e4aSElliott Hughes 80*e1fe3e4aSElliott Hughes def compile_font(self, path, suffix, temp_dir): 81*e1fe3e4aSElliott Hughes ttx_filename = os.path.basename(path) 82*e1fe3e4aSElliott Hughes savepath = os.path.join(temp_dir, ttx_filename.replace(".ttx", suffix)) 83*e1fe3e4aSElliott Hughes font = TTFont(recalcBBoxes=False, recalcTimestamp=False) 84*e1fe3e4aSElliott Hughes font.importXML(path) 85*e1fe3e4aSElliott Hughes font.save(savepath, reorderTables=None) 86*e1fe3e4aSElliott Hughes return font, savepath 87*e1fe3e4aSElliott Hughes 88*e1fe3e4aSElliott Hughes # ----- 89*e1fe3e4aSElliott Hughes # Tests 90*e1fe3e4aSElliott Hughes # ----- 91*e1fe3e4aSElliott Hughes 92*e1fe3e4aSElliott Hughes def test_varlib_mutator_ttf(self): 93*e1fe3e4aSElliott Hughes suffix = ".ttf" 94*e1fe3e4aSElliott Hughes ds_path = self.get_test_input("Build.designspace") 95*e1fe3e4aSElliott Hughes ufo_dir = self.get_test_input("master_ufo") 96*e1fe3e4aSElliott Hughes ttx_dir = self.get_test_input("master_ttx_interpolatable_ttf") 97*e1fe3e4aSElliott Hughes 98*e1fe3e4aSElliott Hughes self.temp_dir() 99*e1fe3e4aSElliott Hughes ttx_paths = self.get_file_list(ttx_dir, ".ttx", "TestFamily-") 100*e1fe3e4aSElliott Hughes for path in ttx_paths: 101*e1fe3e4aSElliott Hughes self.compile_font(path, suffix, self.tempdir) 102*e1fe3e4aSElliott Hughes 103*e1fe3e4aSElliott Hughes finder = lambda s: s.replace(ufo_dir, self.tempdir).replace(".ufo", suffix) 104*e1fe3e4aSElliott Hughes varfont, _, _ = build(ds_path, finder) 105*e1fe3e4aSElliott Hughes varfont_name = "Mutator" 106*e1fe3e4aSElliott Hughes varfont_path = os.path.join(self.tempdir, varfont_name + suffix) 107*e1fe3e4aSElliott Hughes varfont.save(varfont_path) 108*e1fe3e4aSElliott Hughes 109*e1fe3e4aSElliott Hughes args = [varfont_path, "wght=500", "cntr=50"] 110*e1fe3e4aSElliott Hughes mutator(args) 111*e1fe3e4aSElliott Hughes 112*e1fe3e4aSElliott Hughes instfont_path = os.path.splitext(varfont_path)[0] + "-instance" + suffix 113*e1fe3e4aSElliott Hughes instfont = TTFont(instfont_path) 114*e1fe3e4aSElliott Hughes tables = [table_tag for table_tag in instfont.keys() if table_tag != "head"] 115*e1fe3e4aSElliott Hughes expected_ttx_path = self.get_test_output(varfont_name + ".ttx") 116*e1fe3e4aSElliott Hughes self.expect_ttx(instfont, expected_ttx_path, tables) 117*e1fe3e4aSElliott Hughes 118*e1fe3e4aSElliott Hughes def test_varlib_mutator_getvar_ttf(self): 119*e1fe3e4aSElliott Hughes suffix = ".ttf" 120*e1fe3e4aSElliott Hughes ttx_dir = self.get_test_input("master_ttx_getvar_ttf") 121*e1fe3e4aSElliott Hughes 122*e1fe3e4aSElliott Hughes self.temp_dir() 123*e1fe3e4aSElliott Hughes ttx_paths = self.get_file_list(ttx_dir, ".ttx", "Mutator_Getvar") 124*e1fe3e4aSElliott Hughes for path in ttx_paths: 125*e1fe3e4aSElliott Hughes self.compile_font(path, suffix, self.tempdir) 126*e1fe3e4aSElliott Hughes 127*e1fe3e4aSElliott Hughes varfont_name = "Mutator_Getvar" 128*e1fe3e4aSElliott Hughes varfont_path = os.path.join(self.tempdir, varfont_name + suffix) 129*e1fe3e4aSElliott Hughes 130*e1fe3e4aSElliott Hughes args = [varfont_path, "wdth=80", "ASCN=628"] 131*e1fe3e4aSElliott Hughes mutator(args) 132*e1fe3e4aSElliott Hughes 133*e1fe3e4aSElliott Hughes instfont_path = os.path.splitext(varfont_path)[0] + "-instance" + suffix 134*e1fe3e4aSElliott Hughes instfont = TTFont(instfont_path) 135*e1fe3e4aSElliott Hughes tables = [table_tag for table_tag in instfont.keys() if table_tag != "head"] 136*e1fe3e4aSElliott Hughes expected_ttx_path = self.get_test_output(varfont_name + "-instance.ttx") 137*e1fe3e4aSElliott Hughes self.expect_ttx(instfont, expected_ttx_path, tables) 138*e1fe3e4aSElliott Hughes 139*e1fe3e4aSElliott Hughes def test_varlib_mutator_iup_ttf(self): 140*e1fe3e4aSElliott Hughes suffix = ".ttf" 141*e1fe3e4aSElliott Hughes ufo_dir = self.get_test_input("master_ufo") 142*e1fe3e4aSElliott Hughes ttx_dir = self.get_test_input("master_ttx_varfont_ttf") 143*e1fe3e4aSElliott Hughes 144*e1fe3e4aSElliott Hughes self.temp_dir() 145*e1fe3e4aSElliott Hughes ttx_paths = self.get_file_list(ttx_dir, ".ttx", "Mutator_IUP") 146*e1fe3e4aSElliott Hughes for path in ttx_paths: 147*e1fe3e4aSElliott Hughes self.compile_font(path, suffix, self.tempdir) 148*e1fe3e4aSElliott Hughes 149*e1fe3e4aSElliott Hughes varfont_name = "Mutator_IUP" 150*e1fe3e4aSElliott Hughes varfont_path = os.path.join(self.tempdir, varfont_name + suffix) 151*e1fe3e4aSElliott Hughes 152*e1fe3e4aSElliott Hughes args = [varfont_path, "wdth=80", "ASCN=628"] 153*e1fe3e4aSElliott Hughes mutator(args) 154*e1fe3e4aSElliott Hughes 155*e1fe3e4aSElliott Hughes instfont_path = os.path.splitext(varfont_path)[0] + "-instance" + suffix 156*e1fe3e4aSElliott Hughes instfont = TTFont(instfont_path) 157*e1fe3e4aSElliott Hughes tables = [table_tag for table_tag in instfont.keys() if table_tag != "head"] 158*e1fe3e4aSElliott Hughes expected_ttx_path = self.get_test_output(varfont_name + "-instance.ttx") 159*e1fe3e4aSElliott Hughes self.expect_ttx(instfont, expected_ttx_path, tables) 160*e1fe3e4aSElliott Hughes 161*e1fe3e4aSElliott Hughes def test_varlib_mutator_CFF2(self): 162*e1fe3e4aSElliott Hughes suffix = ".otf" 163*e1fe3e4aSElliott Hughes ttx_dir = self.get_test_input("master_ttx_varfont_otf") 164*e1fe3e4aSElliott Hughes 165*e1fe3e4aSElliott Hughes self.temp_dir() 166*e1fe3e4aSElliott Hughes ttx_paths = self.get_file_list(ttx_dir, ".ttx", "TestCFF2VF") 167*e1fe3e4aSElliott Hughes for path in ttx_paths: 168*e1fe3e4aSElliott Hughes self.compile_font(path, suffix, self.tempdir) 169*e1fe3e4aSElliott Hughes 170*e1fe3e4aSElliott Hughes varfont_name = "TestCFF2VF" 171*e1fe3e4aSElliott Hughes varfont_path = os.path.join(self.tempdir, varfont_name + suffix) 172*e1fe3e4aSElliott Hughes 173*e1fe3e4aSElliott Hughes expected_ttx_name = "InterpolateTestCFF2VF" 174*e1fe3e4aSElliott Hughes tables = ["hmtx", "CFF2"] 175*e1fe3e4aSElliott Hughes loc = {"wght": float(200)} 176*e1fe3e4aSElliott Hughes 177*e1fe3e4aSElliott Hughes varfont = TTFont(varfont_path) 178*e1fe3e4aSElliott Hughes new_font = make_instance(varfont, loc) 179*e1fe3e4aSElliott Hughes expected_ttx_path = self.get_test_output(expected_ttx_name + ".ttx") 180*e1fe3e4aSElliott Hughes self.expect_ttx(new_font, expected_ttx_path, tables) 181*e1fe3e4aSElliott Hughes 182*e1fe3e4aSElliott Hughes 183*e1fe3e4aSElliott Hughesif __name__ == "__main__": 184*e1fe3e4aSElliott Hughes sys.exit(unittest.main()) 185