• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python3
2
3# Runs a subsetting test suite. Compares the results of subsetting via harfbuzz
4# to subsetting via fonttools.
5
6from difflib import unified_diff
7import os
8import re
9import subprocess
10import sys
11import tempfile
12import shutil
13import io
14
15from subset_test_suite import SubsetTestSuite
16
17try:
18	from fontTools.ttLib import TTFont
19except ImportError:
20	print ("fonttools is not present, skipping test.")
21	sys.exit (77)
22
23ots_sanitize = shutil.which ("ots-sanitize")
24
25def cmd (command):
26	p = subprocess.Popen (
27		command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
28		universal_newlines=True)
29	(stdoutdata, stderrdata) = p.communicate ()
30	print (stderrdata, end="", file=sys.stderr)
31	return stdoutdata, p.returncode
32
33def fail_test (test, cli_args, message):
34	print ('ERROR: %s' % message)
35	print ('Test State:')
36	print ('  test.font_path    %s' % os.path.abspath (test.font_path))
37	print ('  test.profile_path %s' % os.path.abspath (test.profile_path))
38	print ('  test.unicodes	    %s' % test.unicodes ())
39	expected_file = os.path.join (test_suite.get_output_directory (),
40				      test.get_font_name ())
41	print ('  expected_file	    %s' % os.path.abspath (expected_file))
42	return 1
43
44def run_test (test, should_check_ots):
45	out_file = os.path.join (tempfile.mkdtemp (), test.get_font_name () + '-subset' + test.get_font_extension ())
46	cli_args = [hb_subset,
47		    "--font-file=" + test.font_path,
48		    "--output-file=" + out_file,
49		    "--unicodes=%s" % test.unicodes (),
50		    "--drop-tables+=DSIG",
51		    "--drop-tables-=sbix"]
52	cli_args.extend (test.get_profile_flags ())
53	print (' '.join (cli_args))
54	_, return_code = cmd (cli_args)
55
56	if return_code:
57		return fail_test (test, cli_args, "%s returned %d" % (' '.join (cli_args), return_code))
58
59	expected_ttx = io.StringIO ()
60	try:
61		with TTFont (os.path.join (test_suite.get_output_directory (), test.get_font_name ())) as font:
62			font.saveXML (expected_ttx)
63	except Exception as e:
64		print (e)
65		return fail_test (test, cli_args, "ttx failed to parse the expected result")
66
67	actual_ttx = io.StringIO ()
68	try:
69		with TTFont (out_file) as font:
70			font.saveXML (actual_ttx)
71	except Exception as e:
72		print (e)
73		return fail_test (test, cli_args, "ttx failed to parse the actual result")
74
75	expected_ttx_text = strip_check_sum (expected_ttx.getvalue ())
76	expected_ttx.close ()
77	actual_ttx_text = strip_check_sum (actual_ttx.getvalue ())
78	actual_ttx.close ()
79
80	if not actual_ttx_text == expected_ttx_text:
81		for line in unified_diff (expected_ttx_text.splitlines (1), actual_ttx_text.splitlines (1)):
82			sys.stdout.write (line)
83		sys.stdout.flush ()
84		return fail_test (test, cli_args, 'ttx for expected and actual does not match.')
85
86	if should_check_ots:
87		print ("Checking output with ots-sanitize.")
88		if not check_ots (out_file):
89			return fail_test (test, cli_args, 'ots for subsetted file fails.')
90
91	return 0
92
93def strip_check_sum (ttx_string):
94	return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]',
95		       'checkSumAdjustment value="0x00000000"',
96		       ttx_string, count=1)
97
98def has_ots ():
99	if not ots_sanitize:
100		print ("OTS is not present, skipping all ots checks.")
101		return False
102	return True
103
104def check_ots (path):
105	ots_report, returncode = cmd ([ots_sanitize, path])
106	if returncode:
107		print ("OTS Failure: %s" % ots_report)
108		return False
109	return True
110
111args = sys.argv[1:]
112if not args or sys.argv[1].find ('hb-subset') == -1 or not os.path.exists (sys.argv[1]):
113	sys.exit ("First argument does not seem to point to usable hb-subset.")
114hb_subset, args = args[0], args[1:]
115
116if not len (args):
117	sys.exit ("No tests supplied.")
118
119has_ots = has_ots()
120
121fails = 0
122for path in args:
123	with open (path, mode="r", encoding="utf-8") as f:
124		print ("Running tests in " + path)
125		test_suite = SubsetTestSuite (path, f.read ())
126		for test in test_suite.tests ():
127			fails += run_test (test, has_ots)
128
129if fails != 0:
130	sys.exit ("%d test(s) failed." % fails)
131else:
132	print ("All tests passed.")
133