1*e1fe3e4aSElliott Hughesfrom fontTools.ttLib import TTFont 2*e1fe3e4aSElliott Hughesfrom fontTools.varLib.interpolatable import main as interpolatable_main 3*e1fe3e4aSElliott Hughesimport os 4*e1fe3e4aSElliott Hughesimport shutil 5*e1fe3e4aSElliott Hughesimport sys 6*e1fe3e4aSElliott Hughesimport tempfile 7*e1fe3e4aSElliott Hughesimport unittest 8*e1fe3e4aSElliott Hughesimport pytest 9*e1fe3e4aSElliott Hughes 10*e1fe3e4aSElliott Hughestry: 11*e1fe3e4aSElliott Hughes import scipy 12*e1fe3e4aSElliott Hughesexcept: 13*e1fe3e4aSElliott Hughes scipy = None 14*e1fe3e4aSElliott Hughes 15*e1fe3e4aSElliott Hughestry: 16*e1fe3e4aSElliott Hughes import munkres 17*e1fe3e4aSElliott Hughesexcept ImportError: 18*e1fe3e4aSElliott Hughes munkres = None 19*e1fe3e4aSElliott Hughes 20*e1fe3e4aSElliott Hughes 21*e1fe3e4aSElliott Hughes@unittest.skipUnless(scipy or munkres, "scipy or munkres not installed") 22*e1fe3e4aSElliott Hughesclass InterpolatableTest(unittest.TestCase): 23*e1fe3e4aSElliott Hughes def __init__(self, methodName): 24*e1fe3e4aSElliott Hughes unittest.TestCase.__init__(self, methodName) 25*e1fe3e4aSElliott Hughes # Python 3 renamed assertRaisesRegexp to assertRaisesRegex, 26*e1fe3e4aSElliott Hughes # and fires deprecation warnings if a program uses the old name. 27*e1fe3e4aSElliott Hughes if not hasattr(self, "assertRaisesRegex"): 28*e1fe3e4aSElliott Hughes self.assertRaisesRegex = self.assertRaisesRegexp 29*e1fe3e4aSElliott Hughes 30*e1fe3e4aSElliott Hughes def setUp(self): 31*e1fe3e4aSElliott Hughes self.tempdir = None 32*e1fe3e4aSElliott Hughes self.num_tempfiles = 0 33*e1fe3e4aSElliott Hughes 34*e1fe3e4aSElliott Hughes def tearDown(self): 35*e1fe3e4aSElliott Hughes if self.tempdir: 36*e1fe3e4aSElliott Hughes shutil.rmtree(self.tempdir) 37*e1fe3e4aSElliott Hughes 38*e1fe3e4aSElliott Hughes @staticmethod 39*e1fe3e4aSElliott Hughes def get_test_input(*test_file_or_folder): 40*e1fe3e4aSElliott Hughes path, _ = os.path.split(__file__) 41*e1fe3e4aSElliott Hughes return os.path.join(path, "data", *test_file_or_folder) 42*e1fe3e4aSElliott Hughes 43*e1fe3e4aSElliott Hughes @staticmethod 44*e1fe3e4aSElliott Hughes def get_file_list(folder, suffix, prefix=""): 45*e1fe3e4aSElliott Hughes all_files = os.listdir(folder) 46*e1fe3e4aSElliott Hughes file_list = [] 47*e1fe3e4aSElliott Hughes for p in all_files: 48*e1fe3e4aSElliott Hughes if p.startswith(prefix) and p.endswith(suffix): 49*e1fe3e4aSElliott Hughes file_list.append(os.path.abspath(os.path.join(folder, p))) 50*e1fe3e4aSElliott Hughes return sorted(file_list) 51*e1fe3e4aSElliott Hughes 52*e1fe3e4aSElliott Hughes def temp_path(self, suffix): 53*e1fe3e4aSElliott Hughes self.temp_dir() 54*e1fe3e4aSElliott Hughes self.num_tempfiles += 1 55*e1fe3e4aSElliott Hughes return os.path.join(self.tempdir, "tmp%d%s" % (self.num_tempfiles, suffix)) 56*e1fe3e4aSElliott Hughes 57*e1fe3e4aSElliott Hughes def temp_dir(self): 58*e1fe3e4aSElliott Hughes if not self.tempdir: 59*e1fe3e4aSElliott Hughes self.tempdir = tempfile.mkdtemp() 60*e1fe3e4aSElliott Hughes 61*e1fe3e4aSElliott Hughes def compile_font(self, path, suffix, temp_dir): 62*e1fe3e4aSElliott Hughes ttx_filename = os.path.basename(path) 63*e1fe3e4aSElliott Hughes savepath = os.path.join(temp_dir, ttx_filename.replace(".ttx", suffix)) 64*e1fe3e4aSElliott Hughes font = TTFont(recalcBBoxes=False, recalcTimestamp=False) 65*e1fe3e4aSElliott Hughes font.importXML(path) 66*e1fe3e4aSElliott Hughes font.save(savepath, reorderTables=None) 67*e1fe3e4aSElliott Hughes return font, savepath 68*e1fe3e4aSElliott Hughes 69*e1fe3e4aSElliott Hughes # ----- 70*e1fe3e4aSElliott Hughes # Tests 71*e1fe3e4aSElliott Hughes # ----- 72*e1fe3e4aSElliott Hughes 73*e1fe3e4aSElliott Hughes def test_interpolatable_ttf(self): 74*e1fe3e4aSElliott Hughes suffix = ".ttf" 75*e1fe3e4aSElliott Hughes ttx_dir = self.get_test_input("master_ttx_interpolatable_ttf") 76*e1fe3e4aSElliott Hughes 77*e1fe3e4aSElliott Hughes self.temp_dir() 78*e1fe3e4aSElliott Hughes ttx_paths = self.get_file_list(ttx_dir, ".ttx", "TestFamily2-") 79*e1fe3e4aSElliott Hughes for path in ttx_paths: 80*e1fe3e4aSElliott Hughes self.compile_font(path, suffix, self.tempdir) 81*e1fe3e4aSElliott Hughes 82*e1fe3e4aSElliott Hughes ttf_paths = self.get_file_list(self.tempdir, suffix) 83*e1fe3e4aSElliott Hughes self.assertIsNone(interpolatable_main(ttf_paths)) 84*e1fe3e4aSElliott Hughes 85*e1fe3e4aSElliott Hughes def test_interpolatable_otf(self): 86*e1fe3e4aSElliott Hughes suffix = ".otf" 87*e1fe3e4aSElliott Hughes ttx_dir = self.get_test_input("master_ttx_interpolatable_otf") 88*e1fe3e4aSElliott Hughes 89*e1fe3e4aSElliott Hughes self.temp_dir() 90*e1fe3e4aSElliott Hughes ttx_paths = self.get_file_list(ttx_dir, ".ttx", "TestFamily2-") 91*e1fe3e4aSElliott Hughes for path in ttx_paths: 92*e1fe3e4aSElliott Hughes self.compile_font(path, suffix, self.tempdir) 93*e1fe3e4aSElliott Hughes 94*e1fe3e4aSElliott Hughes otf_paths = self.get_file_list(self.tempdir, suffix) 95*e1fe3e4aSElliott Hughes self.assertIsNone(interpolatable_main(otf_paths)) 96*e1fe3e4aSElliott Hughes 97*e1fe3e4aSElliott Hughes def test_interpolatable_ufo(self): 98*e1fe3e4aSElliott Hughes ttx_dir = self.get_test_input("master_ufo") 99*e1fe3e4aSElliott Hughes ufo_paths = self.get_file_list(ttx_dir, ".ufo", "TestFamily2-") 100*e1fe3e4aSElliott Hughes self.assertIsNone(interpolatable_main(ufo_paths)) 101*e1fe3e4aSElliott Hughes 102*e1fe3e4aSElliott Hughes def test_designspace(self): 103*e1fe3e4aSElliott Hughes designspace_path = self.get_test_input("InterpolateLayout.designspace") 104*e1fe3e4aSElliott Hughes self.assertIsNone(interpolatable_main([designspace_path])) 105*e1fe3e4aSElliott Hughes 106*e1fe3e4aSElliott Hughes def test_glyphsapp(self): 107*e1fe3e4aSElliott Hughes pytest.importorskip("glyphsLib") 108*e1fe3e4aSElliott Hughes glyphsapp_path = self.get_test_input("InterpolateLayout.glyphs") 109*e1fe3e4aSElliott Hughes self.assertIsNone(interpolatable_main([glyphsapp_path])) 110*e1fe3e4aSElliott Hughes 111*e1fe3e4aSElliott Hughes def test_VF(self): 112*e1fe3e4aSElliott Hughes suffix = ".ttf" 113*e1fe3e4aSElliott Hughes ttx_dir = self.get_test_input("master_ttx_varfont_ttf") 114*e1fe3e4aSElliott Hughes 115*e1fe3e4aSElliott Hughes self.temp_dir() 116*e1fe3e4aSElliott Hughes ttx_paths = self.get_file_list(ttx_dir, ".ttx", "SparseMasters-") 117*e1fe3e4aSElliott Hughes for path in ttx_paths: 118*e1fe3e4aSElliott Hughes self.compile_font(path, suffix, self.tempdir) 119*e1fe3e4aSElliott Hughes 120*e1fe3e4aSElliott Hughes ttf_paths = self.get_file_list(self.tempdir, suffix) 121*e1fe3e4aSElliott Hughes 122*e1fe3e4aSElliott Hughes problems = interpolatable_main(["--quiet"] + ttf_paths) 123*e1fe3e4aSElliott Hughes self.assertIsNone(problems) 124*e1fe3e4aSElliott Hughes 125*e1fe3e4aSElliott Hughes def test_sparse_interpolatable_ttfs(self): 126*e1fe3e4aSElliott Hughes suffix = ".ttf" 127*e1fe3e4aSElliott Hughes ttx_dir = self.get_test_input("master_ttx_interpolatable_ttf") 128*e1fe3e4aSElliott Hughes 129*e1fe3e4aSElliott Hughes self.temp_dir() 130*e1fe3e4aSElliott Hughes ttx_paths = self.get_file_list(ttx_dir, ".ttx", "SparseMasters-") 131*e1fe3e4aSElliott Hughes for path in ttx_paths: 132*e1fe3e4aSElliott Hughes self.compile_font(path, suffix, self.tempdir) 133*e1fe3e4aSElliott Hughes 134*e1fe3e4aSElliott Hughes ttf_paths = self.get_file_list(self.tempdir, suffix) 135*e1fe3e4aSElliott Hughes 136*e1fe3e4aSElliott Hughes # without --ignore-missing 137*e1fe3e4aSElliott Hughes problems = interpolatable_main(["--quiet"] + ttf_paths) 138*e1fe3e4aSElliott Hughes self.assertEqual( 139*e1fe3e4aSElliott Hughes problems["a"], 140*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 141*e1fe3e4aSElliott Hughes ) 142*e1fe3e4aSElliott Hughes self.assertEqual( 143*e1fe3e4aSElliott Hughes problems["s"], 144*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 145*e1fe3e4aSElliott Hughes ) 146*e1fe3e4aSElliott Hughes self.assertEqual( 147*e1fe3e4aSElliott Hughes problems["edotabove"], 148*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 149*e1fe3e4aSElliott Hughes ) 150*e1fe3e4aSElliott Hughes self.assertEqual( 151*e1fe3e4aSElliott Hughes problems["dotabovecomb"], 152*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 153*e1fe3e4aSElliott Hughes ) 154*e1fe3e4aSElliott Hughes 155*e1fe3e4aSElliott Hughes # normal order, with --ignore-missing 156*e1fe3e4aSElliott Hughes self.assertIsNone(interpolatable_main(["--ignore-missing"] + ttf_paths)) 157*e1fe3e4aSElliott Hughes # purposely putting the sparse master (medium) first 158*e1fe3e4aSElliott Hughes self.assertIsNone( 159*e1fe3e4aSElliott Hughes interpolatable_main( 160*e1fe3e4aSElliott Hughes ["--ignore-missing"] + [ttf_paths[1]] + [ttf_paths[0]] + [ttf_paths[2]] 161*e1fe3e4aSElliott Hughes ) 162*e1fe3e4aSElliott Hughes ) 163*e1fe3e4aSElliott Hughes # purposely putting the sparse master (medium) last 164*e1fe3e4aSElliott Hughes self.assertIsNone( 165*e1fe3e4aSElliott Hughes interpolatable_main( 166*e1fe3e4aSElliott Hughes ["--ignore-missing"] + [ttf_paths[0]] + [ttf_paths[2]] + [ttf_paths[1]] 167*e1fe3e4aSElliott Hughes ) 168*e1fe3e4aSElliott Hughes ) 169*e1fe3e4aSElliott Hughes 170*e1fe3e4aSElliott Hughes def test_sparse_interpolatable_ufos(self): 171*e1fe3e4aSElliott Hughes ttx_dir = self.get_test_input("master_ufo") 172*e1fe3e4aSElliott Hughes ufo_paths = self.get_file_list(ttx_dir, ".ufo", "SparseMasters-") 173*e1fe3e4aSElliott Hughes 174*e1fe3e4aSElliott Hughes # without --ignore-missing 175*e1fe3e4aSElliott Hughes problems = interpolatable_main(["--quiet"] + ufo_paths) 176*e1fe3e4aSElliott Hughes self.assertEqual( 177*e1fe3e4aSElliott Hughes problems["a"], 178*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 179*e1fe3e4aSElliott Hughes ) 180*e1fe3e4aSElliott Hughes self.assertEqual( 181*e1fe3e4aSElliott Hughes problems["s"], 182*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 183*e1fe3e4aSElliott Hughes ) 184*e1fe3e4aSElliott Hughes self.assertEqual( 185*e1fe3e4aSElliott Hughes problems["edotabove"], 186*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 187*e1fe3e4aSElliott Hughes ) 188*e1fe3e4aSElliott Hughes self.assertEqual( 189*e1fe3e4aSElliott Hughes problems["dotabovecomb"], 190*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 191*e1fe3e4aSElliott Hughes ) 192*e1fe3e4aSElliott Hughes 193*e1fe3e4aSElliott Hughes # normal order, with --ignore-missing 194*e1fe3e4aSElliott Hughes self.assertIsNone(interpolatable_main(["--ignore-missing"] + ufo_paths)) 195*e1fe3e4aSElliott Hughes # purposely putting the sparse master (medium) first 196*e1fe3e4aSElliott Hughes self.assertIsNone( 197*e1fe3e4aSElliott Hughes interpolatable_main( 198*e1fe3e4aSElliott Hughes ["--ignore-missing"] + [ufo_paths[1]] + [ufo_paths[0]] + [ufo_paths[2]] 199*e1fe3e4aSElliott Hughes ) 200*e1fe3e4aSElliott Hughes ) 201*e1fe3e4aSElliott Hughes # purposely putting the sparse master (medium) last 202*e1fe3e4aSElliott Hughes self.assertIsNone( 203*e1fe3e4aSElliott Hughes interpolatable_main( 204*e1fe3e4aSElliott Hughes ["--ignore-missing"] + [ufo_paths[0]] + [ufo_paths[2]] + [ufo_paths[1]] 205*e1fe3e4aSElliott Hughes ) 206*e1fe3e4aSElliott Hughes ) 207*e1fe3e4aSElliott Hughes 208*e1fe3e4aSElliott Hughes def test_sparse_designspace(self): 209*e1fe3e4aSElliott Hughes designspace_path = self.get_test_input("SparseMasters_ufo.designspace") 210*e1fe3e4aSElliott Hughes 211*e1fe3e4aSElliott Hughes problems = interpolatable_main(["--quiet", designspace_path]) 212*e1fe3e4aSElliott Hughes self.assertEqual( 213*e1fe3e4aSElliott Hughes problems["a"], 214*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 215*e1fe3e4aSElliott Hughes ) 216*e1fe3e4aSElliott Hughes self.assertEqual( 217*e1fe3e4aSElliott Hughes problems["s"], 218*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 219*e1fe3e4aSElliott Hughes ) 220*e1fe3e4aSElliott Hughes self.assertEqual( 221*e1fe3e4aSElliott Hughes problems["edotabove"], 222*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 223*e1fe3e4aSElliott Hughes ) 224*e1fe3e4aSElliott Hughes self.assertEqual( 225*e1fe3e4aSElliott Hughes problems["dotabovecomb"], 226*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "SparseMasters-Medium", "master_idx": 1}], 227*e1fe3e4aSElliott Hughes ) 228*e1fe3e4aSElliott Hughes 229*e1fe3e4aSElliott Hughes # normal order, with --ignore-missing 230*e1fe3e4aSElliott Hughes self.assertIsNone(interpolatable_main(["--ignore-missing", designspace_path])) 231*e1fe3e4aSElliott Hughes 232*e1fe3e4aSElliott Hughes def test_sparse_glyphsapp(self): 233*e1fe3e4aSElliott Hughes pytest.importorskip("glyphsLib") 234*e1fe3e4aSElliott Hughes glyphsapp_path = self.get_test_input("SparseMasters.glyphs") 235*e1fe3e4aSElliott Hughes 236*e1fe3e4aSElliott Hughes problems = interpolatable_main(["--quiet", glyphsapp_path]) 237*e1fe3e4aSElliott Hughes self.assertEqual( 238*e1fe3e4aSElliott Hughes problems["a"], 239*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "Sparse Masters-Medium", "master_idx": 1}], 240*e1fe3e4aSElliott Hughes ) 241*e1fe3e4aSElliott Hughes self.assertEqual( 242*e1fe3e4aSElliott Hughes problems["s"], 243*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "Sparse Masters-Medium", "master_idx": 1}], 244*e1fe3e4aSElliott Hughes ) 245*e1fe3e4aSElliott Hughes self.assertEqual( 246*e1fe3e4aSElliott Hughes problems["edotabove"], 247*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "Sparse Masters-Medium", "master_idx": 1}], 248*e1fe3e4aSElliott Hughes ) 249*e1fe3e4aSElliott Hughes self.assertEqual( 250*e1fe3e4aSElliott Hughes problems["dotabovecomb"], 251*e1fe3e4aSElliott Hughes [{"type": "missing", "master": "Sparse Masters-Medium", "master_idx": 1}], 252*e1fe3e4aSElliott Hughes ) 253*e1fe3e4aSElliott Hughes 254*e1fe3e4aSElliott Hughes # normal order, with --ignore-missing 255*e1fe3e4aSElliott Hughes self.assertIsNone(interpolatable_main(["--ignore-missing", glyphsapp_path])) 256*e1fe3e4aSElliott Hughes 257*e1fe3e4aSElliott Hughes def test_interpolatable_varComposite(self): 258*e1fe3e4aSElliott Hughes input_path = self.get_test_input( 259*e1fe3e4aSElliott Hughes "..", "..", "ttLib", "data", "varc-ac00-ac01.ttf" 260*e1fe3e4aSElliott Hughes ) 261*e1fe3e4aSElliott Hughes # This particular test font which was generated by machine-learning 262*e1fe3e4aSElliott Hughes # exhibits an "error" in one of the masters; it's a false-positive. 263*e1fe3e4aSElliott Hughes # Just make sure the code runs. 264*e1fe3e4aSElliott Hughes interpolatable_main((input_path,)) 265*e1fe3e4aSElliott Hughes 266*e1fe3e4aSElliott Hughes 267*e1fe3e4aSElliott Hughesif __name__ == "__main__": 268*e1fe3e4aSElliott Hughes sys.exit(unittest.main()) 269