Imported Upstream version 2.3.1
[platform/upstream/harfbuzz.git] / test / subset / run-tests.py
1 #!/usr/bin/env python
2
3 # Runs a subsetting test suite. Compares the results of subsetting via harfbuz
4 # to subsetting via fonttools.
5
6 from __future__ import print_function, division, absolute_import
7
8 import io
9 from difflib import unified_diff
10 import os
11 import re
12 import subprocess
13 import sys
14 import tempfile
15
16 from subset_test_suite import SubsetTestSuite
17
18 # https://stackoverflow.com/a/377028
19 def which(program):
20         def is_exe(fpath):
21                 return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
22
23         fpath, _ = os.path.split(program)
24         if fpath:
25                 if is_exe(program):
26                         return program
27         else:
28                 for path in os.environ["PATH"].split(os.pathsep):
29                         exe_file = os.path.join(path, program)
30                         if is_exe(exe_file):
31                                 return exe_file
32
33         return None
34
35 ttx = which ("ttx")
36 ots_sanitize = which ("ots-sanitize")
37
38 if not ttx:
39         print("TTX is not present, skipping test.")
40         sys.exit (77)
41
42 def cmd(command):
43         p = subprocess.Popen (
44                 command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
45         (stdoutdata, stderrdata) = p.communicate ()
46         print (stderrdata, end="") # file=sys.stderr
47         return stdoutdata, p.returncode
48
49 def read_binary (file_path):
50         with open (file_path, 'rb') as f:
51                 return f.read ()
52
53 def fail_test(test, cli_args, message):
54         print ('ERROR: %s' % message)
55         print ('Test State:')
56         print ('  test.font_path    %s' % os.path.abspath (test.font_path))
57         print ('  test.profile_path %s' % os.path.abspath (test.profile_path))
58         print ('  test.unicodes     %s' % test.unicodes ())
59         expected_file = os.path.join(test_suite.get_output_directory (),
60                                      test.get_font_name ())
61         print ('  expected_file     %s' % os.path.abspath (expected_file))
62         return 1
63
64 def run_test(test, should_check_ots):
65         out_file = os.path.join(tempfile.mkdtemp (), test.get_font_name () + '-subset' + test.get_font_extension ())
66         cli_args = [hb_subset,
67                     "--font-file=" + test.font_path,
68                     "--output-file=" + out_file,
69                     "--unicodes=%s" % test.unicodes ()]
70         cli_args.extend (test.get_profile_flags ())
71         print (' '.join (cli_args))
72         _, return_code = cmd (cli_args)
73
74         if return_code:
75                 return fail_test (test, cli_args, "%s returned %d" % (' '.join (cli_args), return_code))
76
77         expected_ttx, return_code = run_ttx (os.path.join (test_suite.get_output_directory (),
78                                             test.get_font_name ()))
79         if return_code:
80                 return fail_test (test, cli_args, "ttx (expected) returned %d" % (return_code))
81
82         actual_ttx, return_code = run_ttx(out_file)
83         if return_code:
84                 return fail_test (test, cli_args, "ttx (actual) returned %d" % (return_code))
85
86         print ("stripping checksums.")
87         expected_ttx = strip_check_sum (expected_ttx)
88         actual_ttx = strip_check_sum (actual_ttx)
89
90         if not actual_ttx == expected_ttx:
91                 for line in unified_diff (expected_ttx.splitlines (1), actual_ttx.splitlines (1)):
92                         sys.stdout.write (line)
93                 sys.stdout.flush ()
94                 return fail_test(test, cli_args, 'ttx for expected and actual does not match.')
95
96         if should_check_ots:
97                 print ("Checking output with ots-sanitize.")
98                 if not check_ots (out_file):
99                         return fail_test (test, cli_args, 'ots for subsetted file fails.')
100
101         return 0
102
103 def run_ttx (file):
104         print ("ttx %s" % file)
105         return cmd([ttx, "-q", "-o-", file])
106
107 def strip_check_sum (ttx_string):
108         return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]',
109                        'checkSumAdjustment value="0x00000000"',
110                        ttx_string.decode ("utf-8"), count=1)
111
112 def has_ots ():
113         if not ots_sanitize:
114                 print("OTS is not present, skipping all ots checks.")
115                 return False
116         return True
117
118 def check_ots (path):
119         ots_report, returncode = cmd ([ots_sanitize, path])
120         if returncode:
121                 print("OTS Failure: %s" % ots_report);
122                 return False
123         return True
124
125 args = sys.argv[1:]
126 if not args or sys.argv[1].find('hb-subset') == -1 or not os.path.exists (sys.argv[1]):
127         print ("First argument does not seem to point to usable hb-subset.")
128         sys.exit (1)
129 hb_subset, args = args[0], args[1:]
130
131 if not len (args):
132         print ("No tests supplied.")
133         sys.exit (1)
134
135 has_ots = has_ots()
136
137 fails = 0
138 for path in args:
139         with io.open (path, mode="r", encoding="utf-8") as f:
140                 print ("Running tests in " + path)
141                 test_suite = SubsetTestSuite (path, f.read())
142                 for test in test_suite.tests ():
143                         fails += run_test (test, has_ots)
144
145 if fails != 0:
146         print (str (fails) + " test(s) failed.")
147         sys.exit(1)
148 else:
149         print ("All tests passed.")