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