xref: /aosp_15_r20/external/fonttools/Tests/varLib/mutator_test.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
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