[test] Compile python modules
Minor speedup.
Need to distribute them from meson.build I suppose.
diff --git a/test/shape/run-tests.py b/test/shape/run-tests.py
index 21b8327..2184a5f 100755
--- a/test/shape/run-tests.py
+++ b/test/shape/run-tests.py
@@ -1,332 +1,3 @@
#!/usr/bin/env python3
-import sys, os, subprocess, hashlib
-
-args = sys.argv[1:]
-
-verbose = False
-if args and args[0] == "-v":
- verbose = True
- args = args[1:]
-
-if not args or args[0].find("hb-shape") == -1 or not os.path.exists(args[0]):
- sys.exit("""First argument does not seem to point to usable hb-shape.""")
-hb_shape, args = args[0], args[1:]
-
-env = os.environ.copy()
-env["LC_ALL"] = "C"
-
-EXE_WRAPPER = os.environ.get("MESON_EXE_WRAPPER")
-
-
-def open_shape_batch_process():
- cmd = [hb_shape, "--batch"]
- if EXE_WRAPPER:
- cmd = [EXE_WRAPPER] + cmd
-
- process = subprocess.Popen(
- cmd,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=sys.stdout,
- env=env,
- )
- return process
-
-
-shape_process = open_shape_batch_process()
-no_glyph_names_process = None
-
-
-def shape_cmd(command, shape_process, verbose=False):
- global hb_shape
-
- # (Re)start shaper if it is dead
- if shape_process.poll() is not None:
- shape_process = open_shape_batch_process()
-
- if verbose:
- print(hb_shape + " " + " ".join(command))
- shape_process.stdin.write((";".join(command) + "\n").encode("utf-8"))
- shape_process.stdin.flush()
- return shape_process.stdout.readline().decode("utf-8").strip()
-
-
-def plural(what):
- if not what.endswith("s"):
- what += "s"
- return what
-
-
-def whats_var_name(what):
- return plural(what).replace("-", "_")
-
-
-def supported_whats_var_name(what):
- whats = whats_var_name(what)
- return "supported_" + whats
-
-
-def supported_whats(what):
- return globals()[supported_whats_var_name(what)]
-
-
-def all_whats_var_name(what):
- whats = whats_var_name(what)
- return "all_" + whats
-
-
-def all_whats(what):
- return globals()[all_whats_var_name(what)]
-
-
-# Collect supported backends
-for what in ["shaper", "face-loader", "font-funcs"]:
- subcommand = "--list-" + plural(what)
-
- cmd = [hb_shape, subcommand]
- if EXE_WRAPPER:
- cmd = [EXE_WRAPPER] + cmd
-
- what_process = subprocess.Popen(
- cmd,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=sys.stdout,
- env=env,
- )
- # Capture the output
- what_list = what_process.communicate()[0].decode("utf-8").strip().split()
- if what_process.returncode:
- sys.exit(f"Failed to run: {hb_shape} {subcommand}")
- whats = plural(what)
- var_name = supported_whats_var_name(what)
- globals()[var_name] = what_list
- print(f"Supported {whats}: {what_list}")
-
-# If running under Wine and not native dlls, make the respective shapers unavailable.
-if os.environ.get("WINEPATH"):
- overrides = os.environ.get("WINEDLLOVERRIDES", "").lower()
- if "directwrite" in supported_shapers and overrides.find("dwrite") == -1:
- supported_shapers.remove("directwrite")
- print("Skipping DirectWrite shaper under Wine.")
- if "uniscribe" in supported_shapers and overrides.find("usp10") == -1:
- supported_shapers.remove("uniscribe")
- print("Skipping Uniscribe shaper under Wine.")
-
-
-passes = 0
-fails = 0
-skips = 0
-
-if not len(args):
- args = ["-"]
-
-for filename in args:
- if filename == "-":
- print("Running tests from standard input")
- else:
- print("Running tests in " + filename)
-
- if filename == "-":
- f = sys.stdin
- else:
- f = open(filename, encoding="utf8")
-
- # By default test all backends
- for what in ["shaper", "face-loader", "font-funcs"]:
- all_var_name = all_whats_var_name(what)
- globals()[all_var_name] = supported_whats(what)
- all_shapers = ["ot"] # But only 'ot' shaper
-
- # Right now we only test the 'ot' shaper if nothing specified,
- # but try all font-funcs unless overriden.
- # Only 'ot' face-loader is tested.
-
- for line in f:
- comment = False
- if line.startswith("#"):
- comment = True
- line = line[1:]
-
- if line.startswith(" "):
- if verbose:
- print("#%s" % line)
- continue
-
- line = line.strip()
- if not line:
- continue
-
- if line.startswith("@"):
- # Directive
- line = line.strip()
- line = line.split("#")[0].strip()[1:]
- consumed = False
- for what in ["shaper", "face-loader", "font-funcs"]:
- whats = plural(what)
- if line.startswith(what) or line.startswith(whats):
- command, values = line.split("=")
- values = values.strip().split(",")
-
- supported = supported_whats(what)
- if command[-1] == "-":
- # Exclude
- values = [v for v in supported if v not in values]
- else:
- # Specify
- values = [v for v in values if v in supported]
-
- var_name = all_whats_var_name(what)
- print(f"Setting {whats} to test to {values}")
- globals()[var_name] = values
- consumed = True
- if consumed:
- print(line)
- continue
- else:
- print("Unrecognized directive: %s" % line, file=sys.stderr)
- sys.exit(1)
-
- fontfile, options, unicodes, glyphs_expected = line.split(";")
- options = options.split()
- if fontfile.startswith("/") or fontfile.startswith('"/'):
- if os.name == "nt": # Skip on Windows
- continue
-
- fontfile, expected_hash = (fontfile.split("@") + [""])[:2]
-
- try:
- with open(fontfile, "rb") as ff:
- if expected_hash:
- actual_hash = hashlib.sha1(ff.read()).hexdigest().strip()
- if actual_hash != expected_hash:
- print(
- "different version of %s found; Expected hash %s, got %s; skipping."
- % (fontfile, expected_hash, actual_hash)
- )
- skips += 1
- continue
- except IOError:
- print("%s not found, skip." % fontfile)
- skips += 1
- continue
- else:
- cwd = os.path.dirname(filename)
- fontfile = os.path.normpath(os.path.join(cwd, fontfile))
-
- if comment:
- if verbose:
- print('# %s "%s" --unicodes %s' % (hb_shape, fontfile, unicodes))
- continue
-
- skip_test = False
- shaper = None
- face_loader = None
- font_funcs = None
- new_options = []
- it = iter(options)
- for option in it:
- consumed = False
- for what in ["shaper", "face-loader", "font-funcs"]:
- if option.startswith("--" + what):
- try:
- backend = option.split("=")[1]
- except IndexError:
- backend = next(it)
- if backend not in supported_whats(what):
- skips += 1
- print(f"Skipping test with {what}={backend}.")
- skip_test = True
- break
- what = what.replace("-", "_")
- globals()[what] = backend
- consumed = True
- if not consumed:
- new_options.append(option)
-
- if skip_test:
- break
- if skip_test:
- continue
- options = new_options
-
- for shaper in [shaper] if shaper else all_whats("shaper"):
- for font_funcs in [font_funcs] if font_funcs else all_whats("font-funcs"):
- extra_options = []
-
- if shaper:
- extra_options.append("--shaper=" + shaper)
- if face_loader:
- extra_options.append("--face-loader=" + face_loader)
- if font_funcs:
- extra_options.append("--font-funcs=" + font_funcs)
-
- if glyphs_expected != "*":
- extra_options.append("--verify")
- extra_options.append("--unsafe-to-concat")
-
- if verbose:
- print(
- "# shaper=%s face-loader=%s font-funcs=%s"
- % (shaper, face_loader, font_funcs)
- )
- cmd = [fontfile] + ["--unicodes", unicodes] + options + extra_options
- glyphs = shape_cmd(cmd, shape_process, verbose).strip()
-
- if glyphs_expected == "*":
- passes += 1
- continue
-
- final_glyphs = glyphs
- final_glyphs_expected = glyphs_expected
-
- if glyphs != glyphs_expected and glyphs.find("gid") != -1:
- if not no_glyph_names_process:
- no_glyph_names_process = open_shape_batch_process()
-
- cmd2 = [fontfile] + ["--glyphs", "--no-glyph-names", glyphs]
- final_glyphs = shape_cmd(cmd2, no_glyph_names_process).strip()
-
- cmd2 = [fontfile] + [
- "--glyphs",
- "--no-glyph-names",
- glyphs_expected,
- ]
- final_glyphs_expected = shape_cmd(
- cmd2, no_glyph_names_process
- ).strip()
-
- # If the removal of glyph_ids failed, fail the test.
- # https://github.com/harfbuzz/harfbuzz/issues/5169
- if not final_glyphs_expected or final_glyphs != final_glyphs_expected:
- print(hb_shape + " " + " ".join(cmd), file=sys.stderr)
- print("Actual: " + glyphs, file=sys.stderr)
- print("Expected: " + glyphs_expected, file=sys.stderr)
- if final_glyphs != glyphs:
- print(
- "Actual (no glyph names): " + final_glyphs,
- file=sys.stderr,
- )
- print(
- "Expected (no glyph names): " + final_glyphs_expected,
- file=sys.stderr,
- )
- fails += 1
- else:
- passes += 1
-
-print(
- "%d tests passed; %d failed; %d skipped." % (passes, fails, skips), file=sys.stderr
-)
-if not (fails + passes):
- print("No tests ran.")
-elif not (fails + skips):
- print("All tests passed.")
-
-if fails:
- sys.exit(1)
-elif passes:
- sys.exit(0)
-else:
- sys.exit(77)
+import run_tests_module
diff --git a/test/shape/run_tests_module.py b/test/shape/run_tests_module.py
new file mode 100644
index 0000000..7871bd5
--- /dev/null
+++ b/test/shape/run_tests_module.py
@@ -0,0 +1,330 @@
+import sys, os, subprocess, hashlib
+
+args = sys.argv[1:]
+
+verbose = False
+if args and args[0] == "-v":
+ verbose = True
+ args = args[1:]
+
+if not args or args[0].find("hb-shape") == -1 or not os.path.exists(args[0]):
+ sys.exit("""First argument does not seem to point to usable hb-shape.""")
+hb_shape, args = args[0], args[1:]
+
+env = os.environ.copy()
+env["LC_ALL"] = "C"
+
+EXE_WRAPPER = os.environ.get("MESON_EXE_WRAPPER")
+
+
+def open_shape_batch_process():
+ cmd = [hb_shape, "--batch"]
+ if EXE_WRAPPER:
+ cmd = [EXE_WRAPPER] + cmd
+
+ process = subprocess.Popen(
+ cmd,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=sys.stdout,
+ env=env,
+ )
+ return process
+
+
+shape_process = open_shape_batch_process()
+no_glyph_names_process = None
+
+
+def shape_cmd(command, shape_process, verbose=False):
+ global hb_shape
+
+ # (Re)start shaper if it is dead
+ if shape_process.poll() is not None:
+ shape_process = open_shape_batch_process()
+
+ if verbose:
+ print(hb_shape + " " + " ".join(command))
+ shape_process.stdin.write((";".join(command) + "\n").encode("utf-8"))
+ shape_process.stdin.flush()
+ return shape_process.stdout.readline().decode("utf-8").strip()
+
+
+def plural(what):
+ if not what.endswith("s"):
+ what += "s"
+ return what
+
+
+def whats_var_name(what):
+ return plural(what).replace("-", "_")
+
+
+def supported_whats_var_name(what):
+ whats = whats_var_name(what)
+ return "supported_" + whats
+
+
+def supported_whats(what):
+ return globals()[supported_whats_var_name(what)]
+
+
+def all_whats_var_name(what):
+ whats = whats_var_name(what)
+ return "all_" + whats
+
+
+def all_whats(what):
+ return globals()[all_whats_var_name(what)]
+
+
+# Collect supported backends
+for what in ["shaper", "face-loader", "font-funcs"]:
+ subcommand = "--list-" + plural(what)
+
+ cmd = [hb_shape, subcommand]
+ if EXE_WRAPPER:
+ cmd = [EXE_WRAPPER] + cmd
+
+ what_process = subprocess.Popen(
+ cmd,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=sys.stdout,
+ env=env,
+ )
+ # Capture the output
+ what_list = what_process.communicate()[0].decode("utf-8").strip().split()
+ if what_process.returncode:
+ sys.exit(f"Failed to run: {hb_shape} {subcommand}")
+ whats = plural(what)
+ var_name = supported_whats_var_name(what)
+ globals()[var_name] = what_list
+ print(f"Supported {whats}: {what_list}")
+
+# If running under Wine and not native dlls, make the respective shapers unavailable.
+if os.environ.get("WINEPATH"):
+ overrides = os.environ.get("WINEDLLOVERRIDES", "").lower()
+ if "directwrite" in supported_shapers and overrides.find("dwrite") == -1:
+ supported_shapers.remove("directwrite")
+ print("Skipping DirectWrite shaper under Wine.")
+ if "uniscribe" in supported_shapers and overrides.find("usp10") == -1:
+ supported_shapers.remove("uniscribe")
+ print("Skipping Uniscribe shaper under Wine.")
+
+
+passes = 0
+fails = 0
+skips = 0
+
+if not len(args):
+ args = ["-"]
+
+for filename in args:
+ if filename == "-":
+ print("Running tests from standard input")
+ else:
+ print("Running tests in " + filename)
+
+ if filename == "-":
+ f = sys.stdin
+ else:
+ f = open(filename, encoding="utf8")
+
+ # By default test all backends
+ for what in ["shaper", "face-loader", "font-funcs"]:
+ all_var_name = all_whats_var_name(what)
+ globals()[all_var_name] = supported_whats(what)
+ all_shapers = ["ot"] # But only 'ot' shaper
+
+ # Right now we only test the 'ot' shaper if nothing specified,
+ # but try all font-funcs unless overriden.
+ # Only 'ot' face-loader is tested.
+
+ for line in f:
+ comment = False
+ if line.startswith("#"):
+ comment = True
+ line = line[1:]
+
+ if line.startswith(" "):
+ if verbose:
+ print("#%s" % line)
+ continue
+
+ line = line.strip()
+ if not line:
+ continue
+
+ if line.startswith("@"):
+ # Directive
+ line = line.strip()
+ line = line.split("#")[0].strip()[1:]
+ consumed = False
+ for what in ["shaper", "face-loader", "font-funcs"]:
+ whats = plural(what)
+ if line.startswith(what) or line.startswith(whats):
+ command, values = line.split("=")
+ values = values.strip().split(",")
+
+ supported = supported_whats(what)
+ if command[-1] == "-":
+ # Exclude
+ values = [v for v in supported if v not in values]
+ else:
+ # Specify
+ values = [v for v in values if v in supported]
+
+ var_name = all_whats_var_name(what)
+ print(f"Setting {whats} to test to {values}")
+ globals()[var_name] = values
+ consumed = True
+ if consumed:
+ print(line)
+ continue
+ else:
+ print("Unrecognized directive: %s" % line, file=sys.stderr)
+ sys.exit(1)
+
+ fontfile, options, unicodes, glyphs_expected = line.split(";")
+ options = options.split()
+ if fontfile.startswith("/") or fontfile.startswith('"/'):
+ if os.name == "nt": # Skip on Windows
+ continue
+
+ fontfile, expected_hash = (fontfile.split("@") + [""])[:2]
+
+ try:
+ with open(fontfile, "rb") as ff:
+ if expected_hash:
+ actual_hash = hashlib.sha1(ff.read()).hexdigest().strip()
+ if actual_hash != expected_hash:
+ print(
+ "different version of %s found; Expected hash %s, got %s; skipping."
+ % (fontfile, expected_hash, actual_hash)
+ )
+ skips += 1
+ continue
+ except IOError:
+ print("%s not found, skip." % fontfile)
+ skips += 1
+ continue
+ else:
+ cwd = os.path.dirname(filename)
+ fontfile = os.path.normpath(os.path.join(cwd, fontfile))
+
+ if comment:
+ if verbose:
+ print('# %s "%s" --unicodes %s' % (hb_shape, fontfile, unicodes))
+ continue
+
+ skip_test = False
+ shaper = None
+ face_loader = None
+ font_funcs = None
+ new_options = []
+ it = iter(options)
+ for option in it:
+ consumed = False
+ for what in ["shaper", "face-loader", "font-funcs"]:
+ if option.startswith("--" + what):
+ try:
+ backend = option.split("=")[1]
+ except IndexError:
+ backend = next(it)
+ if backend not in supported_whats(what):
+ skips += 1
+ print(f"Skipping test with {what}={backend}.")
+ skip_test = True
+ break
+ what = what.replace("-", "_")
+ globals()[what] = backend
+ consumed = True
+ if not consumed:
+ new_options.append(option)
+
+ if skip_test:
+ break
+ if skip_test:
+ continue
+ options = new_options
+
+ for shaper in [shaper] if shaper else all_whats("shaper"):
+ for font_funcs in [font_funcs] if font_funcs else all_whats("font-funcs"):
+ extra_options = []
+
+ if shaper:
+ extra_options.append("--shaper=" + shaper)
+ if face_loader:
+ extra_options.append("--face-loader=" + face_loader)
+ if font_funcs:
+ extra_options.append("--font-funcs=" + font_funcs)
+
+ if glyphs_expected != "*":
+ extra_options.append("--verify")
+ extra_options.append("--unsafe-to-concat")
+
+ if verbose:
+ print(
+ "# shaper=%s face-loader=%s font-funcs=%s"
+ % (shaper, face_loader, font_funcs)
+ )
+ cmd = [fontfile] + ["--unicodes", unicodes] + options + extra_options
+ glyphs = shape_cmd(cmd, shape_process, verbose).strip()
+
+ if glyphs_expected == "*":
+ passes += 1
+ continue
+
+ final_glyphs = glyphs
+ final_glyphs_expected = glyphs_expected
+
+ if glyphs != glyphs_expected and glyphs.find("gid") != -1:
+ if not no_glyph_names_process:
+ no_glyph_names_process = open_shape_batch_process()
+
+ cmd2 = [fontfile] + ["--glyphs", "--no-glyph-names", glyphs]
+ final_glyphs = shape_cmd(cmd2, no_glyph_names_process).strip()
+
+ cmd2 = [fontfile] + [
+ "--glyphs",
+ "--no-glyph-names",
+ glyphs_expected,
+ ]
+ final_glyphs_expected = shape_cmd(
+ cmd2, no_glyph_names_process
+ ).strip()
+
+ # If the removal of glyph_ids failed, fail the test.
+ # https://github.com/harfbuzz/harfbuzz/issues/5169
+ if not final_glyphs_expected or final_glyphs != final_glyphs_expected:
+ print(hb_shape + " " + " ".join(cmd), file=sys.stderr)
+ print("Actual: " + glyphs, file=sys.stderr)
+ print("Expected: " + glyphs_expected, file=sys.stderr)
+ if final_glyphs != glyphs:
+ print(
+ "Actual (no glyph names): " + final_glyphs,
+ file=sys.stderr,
+ )
+ print(
+ "Expected (no glyph names): " + final_glyphs_expected,
+ file=sys.stderr,
+ )
+ fails += 1
+ else:
+ passes += 1
+
+print(
+ "%d tests passed; %d failed; %d skipped." % (passes, fails, skips), file=sys.stderr
+)
+if not (fails + passes):
+ print("No tests ran.")
+elif not (fails + skips):
+ print("All tests passed.")
+
+if fails:
+ sys.exit(1)
+elif passes:
+ sys.exit(0)
+else:
+ sys.exit(77)
diff --git a/test/subset/run-repack-tests.py b/test/subset/run-repack-tests.py
index a0389e5..406374b 100755
--- a/test/subset/run-repack-tests.py
+++ b/test/subset/run-repack-tests.py
@@ -1,131 +1,3 @@
#!/usr/bin/env python3
-# Runs a subsetting test suite. Compares the results of subsetting via harfbuzz
-# to subsetting via fonttools.
-
-from difflib import unified_diff
-import os
-import re
-import subprocess
-import sys
-import tempfile
-import shutil
-import io
-
-from repack_test import RepackTest
-
-try:
- from fontTools.ttLib import TTFont
-except ImportError:
- print("fonttools is not present, skipping test.")
- sys.exit(77)
-
-ots_sanitize = shutil.which("ots-sanitize")
-
-EXE_WRAPPER = os.environ.get("MESON_EXE_WRAPPER")
-
-
-def subset_cmd(command):
- global hb_subset, process
- print(hb_subset + " " + " ".join(command))
- process.stdin.write((";".join(command) + "\n").encode("utf-8"))
- process.stdin.flush()
- return process.stdout.readline().decode("utf-8").strip()
-
-
-def cmd(command):
- p = subprocess.Popen(
- command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
- )
- (stdoutdata, stderrdata) = p.communicate()
- print(stderrdata, end="", file=sys.stderr)
- return stdoutdata, p.returncode
-
-
-def fail_test(test, cli_args, message):
- print("ERROR: %s" % message)
- print("Test State:")
- print(" test.font_name %s" % test.font_name)
- print(" test.test_path %s" % os.path.abspath(test.test_path))
- return 1
-
-
-def run_test(test, should_check_ots):
- out_file = os.path.join(out_dir, test.font_name + "-subset.ttf")
- cli_args = [
- "--font-file=" + test.font_path(),
- "--output-file=" + out_file,
- "--unicodes=%s" % test.codepoints_string(),
- "--drop-tables-=GPOS,GSUB,GDEF",
- ]
- print(" ".join(cli_args))
- ret = subset_cmd(cli_args)
-
- if ret != "success":
- return fail_test(test, cli_args, "%s failed" % " ".join(cli_args))
-
- try:
- with TTFont(out_file) as font:
- pass
- except Exception as e:
- print(e)
- return fail_test(test, cli_args, "ttx failed to parse the result")
-
- if should_check_ots:
- print("Checking output with ots-sanitize.")
- if not check_ots(out_file):
- return fail_test(test, cli_args, "ots for subsetted file fails.")
-
- return 0
-
-
-def has_ots():
- if not ots_sanitize:
- print("OTS is not present, skipping all ots checks.")
- return False
- return True
-
-
-def check_ots(path):
- ots_report, returncode = cmd([ots_sanitize, path])
- if returncode:
- print("OTS Failure: %s" % ots_report)
- return False
- return True
-
-
-args = sys.argv[1:]
-if not args or sys.argv[1].find("hb-subset") == -1 or not os.path.exists(sys.argv[1]):
- sys.exit("First argument does not seem to point to usable hb-subset.")
-hb_subset, args = args[0], args[1:]
-
-if len(args) != 1:
- sys.exit("No tests supplied.")
-
-has_ots = has_ots()
-
-batch_cmd = [hb_subset, "--batch"]
-if EXE_WRAPPER:
- batch_cmd = [EXE_WRAPPER] + batch_cmd
-process = subprocess.Popen(
- batch_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=sys.stdout
-)
-
-fails = 0
-
-path = args[0]
-if not path.endswith(".tests"):
- sys.exit("Not a valid test case path.")
-
-out_dir = tempfile.mkdtemp()
-
-with open(path, mode="r", encoding="utf-8") as f:
- # TODO(garretrieger): re-enable OTS checking.
- fails += run_test(RepackTest(path, f.read()), False)
-
-
-if fails != 0:
- sys.exit("%d test(s) failed; output left in %s" % (fails, out_dir))
-else:
- print("All tests passed.")
- shutil.rmtree(out_dir)
+import run_repack_tests_module
diff --git a/test/subset/run-tests.py b/test/subset/run-tests.py
index b403bfa..2184a5f 100755
--- a/test/subset/run-tests.py
+++ b/test/subset/run-tests.py
@@ -1,207 +1,3 @@
#!/usr/bin/env python3
-# Runs a subsetting test suite. Compares the results of subsetting via harfbuzz
-# to subsetting via fonttools.
-
-from difflib import unified_diff
-import os
-import re
-import subprocess
-import sys
-import tempfile
-import shutil
-import io
-
-from subset_test_suite import SubsetTestSuite
-
-try:
- from fontTools.ttLib import TTFont
-except ImportError:
- TTFont = None
-
-ots_sanitize = shutil.which("ots-sanitize")
-
-
-def subset_cmd(command):
- global hb_subset, subset_process
-
- # (Re)start shaper if it is dead
- if subset_process.poll() is not None:
- subset_process = open_subset_batch_process()
-
- print(hb_subset + " " + " ".join(command))
- subset_process.stdin.write((";".join(command) + "\n").encode("utf-8"))
- subset_process.stdin.flush()
- return subset_process.stdout.readline().decode("utf-8").strip()
-
-
-def cmd(command):
- p = subprocess.Popen(
- command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
- )
- (stdoutdata, stderrdata) = p.communicate()
- print(stderrdata, end="", file=sys.stderr)
- return stdoutdata, p.returncode
-
-
-def fail_test(test, cli_args, message):
- print("ERROR: %s" % message)
- print("Test State:")
- print(" test.font_path %s" % os.path.abspath(test.font_path))
- print(" test.profile_path %s" % os.path.abspath(test.profile_path))
- print(" test.unicodes %s" % test.unicodes())
- expected_file = os.path.join(
- test_suite.get_output_directory(), test.get_font_name()
- )
- print(" expected_file %s" % os.path.abspath(expected_file))
- return 1
-
-
-def run_test(test, should_check_ots, preprocess):
- out_file = os.path.join(
- out_dir, test.get_font_name() + "-subset" + test.get_font_extension()
- )
- cli_args = [
- "--font-file=" + test.font_path,
- "--output-file=" + out_file,
- "--unicodes=%s" % test.unicodes(),
- "--drop-tables+=DSIG,BASE",
- "--drop-tables-=sbix",
- ]
- if preprocess:
- cli_args.extend(
- [
- "--preprocess",
- ]
- )
-
- cli_args.extend(test.get_profile_flags())
- if test.get_instance_flags():
- cli_args.extend(["--instance=%s" % ",".join(test.get_instance_flags())])
- if test.iup_optimize:
- cli_args.extend(
- [
- "--optimize",
- ]
- )
- ret = subset_cmd(cli_args)
-
- if ret != "success":
- return fail_test(test, cli_args, "%s failed" % " ".join(cli_args))
-
- expected_file = os.path.join(
- test_suite.get_output_directory(), test.get_font_name()
- )
- with open(expected_file, "rb") as fp:
- expected_contents = fp.read()
- with open(out_file, "rb") as fp:
- actual_contents = fp.read()
-
- if expected_contents == actual_contents:
- if should_check_ots:
- print("Checking output with ots-sanitize.")
- if not check_ots(out_file):
- return fail_test(test, cli_args, "ots for subsetted file fails.")
- return 0
-
- if TTFont is None:
- print("fonttools is not present, skipping TTX diff.")
- return fail_test(test, cli_args, "hash for expected and actual does not match.")
-
- with io.StringIO() as fp:
- try:
- with TTFont(expected_file) as font:
- font.saveXML(fp)
- except Exception as e:
- print(e)
- return fail_test(test, cli_args, "ttx failed to parse the expected result")
- expected_ttx = fp.getvalue()
-
- with io.StringIO() as fp:
- try:
- with TTFont(out_file) as font:
- font.saveXML(fp)
- except Exception as e:
- print(e)
- return fail_test(test, cli_args, "ttx failed to parse the actual result")
- actual_ttx = fp.getvalue()
-
- if actual_ttx != expected_ttx:
- for line in unified_diff(expected_ttx.splitlines(1), actual_ttx.splitlines(1)):
- sys.stdout.write(line)
- sys.stdout.flush()
- return fail_test(test, cli_args, "ttx for expected and actual does not match.")
-
- return fail_test(
- test,
- cli_args,
- "hash for expected and actual does not match, "
- "but the ttx matches. Expected file needs to be updated?",
- )
-
-
-def has_ots():
- if not ots_sanitize:
- print("OTS is not present, skipping all ots checks.")
- return False
- return True
-
-
-def check_ots(path):
- ots_report, returncode = cmd([ots_sanitize, path])
- if returncode:
- print("OTS Failure: %s" % ots_report)
- return False
- return True
-
-
-args = sys.argv[1:]
-if not args or sys.argv[1].find("hb-subset") == -1 or not os.path.exists(sys.argv[1]):
- sys.exit("First argument does not seem to point to usable hb-subset.")
-hb_subset, args = args[0], args[1:]
-
-if not len(args):
- sys.exit("No tests supplied.")
-
-has_ots = has_ots()
-
-env = os.environ.copy()
-env["LC_ALL"] = "C"
-
-EXE_WRAPPER = os.environ.get("MESON_EXE_WRAPPER")
-
-
-def open_subset_batch_process():
- cmd = [hb_subset, "--batch"]
- if EXE_WRAPPER:
- cmd = [EXE_WRAPPER] + cmd
-
- process = subprocess.Popen(
- cmd,
- stdin=subprocess.PIPE,
- stdout=subprocess.PIPE,
- stderr=sys.stdout,
- env=env,
- )
- return process
-
-
-subset_process = open_subset_batch_process()
-out_dir = tempfile.mkdtemp()
-
-fails = 0
-for path in args:
- with open(path, mode="r", encoding="utf-8") as f:
- print("Running tests in " + path)
- test_suite = SubsetTestSuite(path, f.read())
- for test in test_suite.tests():
- # Tests are run with and without preprocessing, results should be the
- # same between them.
- fails += run_test(test, has_ots, False)
- fails += run_test(test, has_ots, True)
-
-if fails != 0:
- sys.exit("%d test(s) failed; output left in %s" % (fails, out_dir))
-else:
- print("All tests passed.")
- shutil.rmtree(out_dir)
+import run_tests_module
diff --git a/test/subset/run_repack_tests_module.py b/test/subset/run_repack_tests_module.py
new file mode 100755
index 0000000..a0389e5
--- /dev/null
+++ b/test/subset/run_repack_tests_module.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python3
+
+# Runs a subsetting test suite. Compares the results of subsetting via harfbuzz
+# to subsetting via fonttools.
+
+from difflib import unified_diff
+import os
+import re
+import subprocess
+import sys
+import tempfile
+import shutil
+import io
+
+from repack_test import RepackTest
+
+try:
+ from fontTools.ttLib import TTFont
+except ImportError:
+ print("fonttools is not present, skipping test.")
+ sys.exit(77)
+
+ots_sanitize = shutil.which("ots-sanitize")
+
+EXE_WRAPPER = os.environ.get("MESON_EXE_WRAPPER")
+
+
+def subset_cmd(command):
+ global hb_subset, process
+ print(hb_subset + " " + " ".join(command))
+ process.stdin.write((";".join(command) + "\n").encode("utf-8"))
+ process.stdin.flush()
+ return process.stdout.readline().decode("utf-8").strip()
+
+
+def cmd(command):
+ p = subprocess.Popen(
+ command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
+ )
+ (stdoutdata, stderrdata) = p.communicate()
+ print(stderrdata, end="", file=sys.stderr)
+ return stdoutdata, p.returncode
+
+
+def fail_test(test, cli_args, message):
+ print("ERROR: %s" % message)
+ print("Test State:")
+ print(" test.font_name %s" % test.font_name)
+ print(" test.test_path %s" % os.path.abspath(test.test_path))
+ return 1
+
+
+def run_test(test, should_check_ots):
+ out_file = os.path.join(out_dir, test.font_name + "-subset.ttf")
+ cli_args = [
+ "--font-file=" + test.font_path(),
+ "--output-file=" + out_file,
+ "--unicodes=%s" % test.codepoints_string(),
+ "--drop-tables-=GPOS,GSUB,GDEF",
+ ]
+ print(" ".join(cli_args))
+ ret = subset_cmd(cli_args)
+
+ if ret != "success":
+ return fail_test(test, cli_args, "%s failed" % " ".join(cli_args))
+
+ try:
+ with TTFont(out_file) as font:
+ pass
+ except Exception as e:
+ print(e)
+ return fail_test(test, cli_args, "ttx failed to parse the result")
+
+ if should_check_ots:
+ print("Checking output with ots-sanitize.")
+ if not check_ots(out_file):
+ return fail_test(test, cli_args, "ots for subsetted file fails.")
+
+ return 0
+
+
+def has_ots():
+ if not ots_sanitize:
+ print("OTS is not present, skipping all ots checks.")
+ return False
+ return True
+
+
+def check_ots(path):
+ ots_report, returncode = cmd([ots_sanitize, path])
+ if returncode:
+ print("OTS Failure: %s" % ots_report)
+ return False
+ return True
+
+
+args = sys.argv[1:]
+if not args or sys.argv[1].find("hb-subset") == -1 or not os.path.exists(sys.argv[1]):
+ sys.exit("First argument does not seem to point to usable hb-subset.")
+hb_subset, args = args[0], args[1:]
+
+if len(args) != 1:
+ sys.exit("No tests supplied.")
+
+has_ots = has_ots()
+
+batch_cmd = [hb_subset, "--batch"]
+if EXE_WRAPPER:
+ batch_cmd = [EXE_WRAPPER] + batch_cmd
+process = subprocess.Popen(
+ batch_cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=sys.stdout
+)
+
+fails = 0
+
+path = args[0]
+if not path.endswith(".tests"):
+ sys.exit("Not a valid test case path.")
+
+out_dir = tempfile.mkdtemp()
+
+with open(path, mode="r", encoding="utf-8") as f:
+ # TODO(garretrieger): re-enable OTS checking.
+ fails += run_test(RepackTest(path, f.read()), False)
+
+
+if fails != 0:
+ sys.exit("%d test(s) failed; output left in %s" % (fails, out_dir))
+else:
+ print("All tests passed.")
+ shutil.rmtree(out_dir)
diff --git a/test/subset/run_tests_module.py b/test/subset/run_tests_module.py
new file mode 100755
index 0000000..b403bfa
--- /dev/null
+++ b/test/subset/run_tests_module.py
@@ -0,0 +1,207 @@
+#!/usr/bin/env python3
+
+# Runs a subsetting test suite. Compares the results of subsetting via harfbuzz
+# to subsetting via fonttools.
+
+from difflib import unified_diff
+import os
+import re
+import subprocess
+import sys
+import tempfile
+import shutil
+import io
+
+from subset_test_suite import SubsetTestSuite
+
+try:
+ from fontTools.ttLib import TTFont
+except ImportError:
+ TTFont = None
+
+ots_sanitize = shutil.which("ots-sanitize")
+
+
+def subset_cmd(command):
+ global hb_subset, subset_process
+
+ # (Re)start shaper if it is dead
+ if subset_process.poll() is not None:
+ subset_process = open_subset_batch_process()
+
+ print(hb_subset + " " + " ".join(command))
+ subset_process.stdin.write((";".join(command) + "\n").encode("utf-8"))
+ subset_process.stdin.flush()
+ return subset_process.stdout.readline().decode("utf-8").strip()
+
+
+def cmd(command):
+ p = subprocess.Popen(
+ command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True
+ )
+ (stdoutdata, stderrdata) = p.communicate()
+ print(stderrdata, end="", file=sys.stderr)
+ return stdoutdata, p.returncode
+
+
+def fail_test(test, cli_args, message):
+ print("ERROR: %s" % message)
+ print("Test State:")
+ print(" test.font_path %s" % os.path.abspath(test.font_path))
+ print(" test.profile_path %s" % os.path.abspath(test.profile_path))
+ print(" test.unicodes %s" % test.unicodes())
+ expected_file = os.path.join(
+ test_suite.get_output_directory(), test.get_font_name()
+ )
+ print(" expected_file %s" % os.path.abspath(expected_file))
+ return 1
+
+
+def run_test(test, should_check_ots, preprocess):
+ out_file = os.path.join(
+ out_dir, test.get_font_name() + "-subset" + test.get_font_extension()
+ )
+ cli_args = [
+ "--font-file=" + test.font_path,
+ "--output-file=" + out_file,
+ "--unicodes=%s" % test.unicodes(),
+ "--drop-tables+=DSIG,BASE",
+ "--drop-tables-=sbix",
+ ]
+ if preprocess:
+ cli_args.extend(
+ [
+ "--preprocess",
+ ]
+ )
+
+ cli_args.extend(test.get_profile_flags())
+ if test.get_instance_flags():
+ cli_args.extend(["--instance=%s" % ",".join(test.get_instance_flags())])
+ if test.iup_optimize:
+ cli_args.extend(
+ [
+ "--optimize",
+ ]
+ )
+ ret = subset_cmd(cli_args)
+
+ if ret != "success":
+ return fail_test(test, cli_args, "%s failed" % " ".join(cli_args))
+
+ expected_file = os.path.join(
+ test_suite.get_output_directory(), test.get_font_name()
+ )
+ with open(expected_file, "rb") as fp:
+ expected_contents = fp.read()
+ with open(out_file, "rb") as fp:
+ actual_contents = fp.read()
+
+ if expected_contents == actual_contents:
+ if should_check_ots:
+ print("Checking output with ots-sanitize.")
+ if not check_ots(out_file):
+ return fail_test(test, cli_args, "ots for subsetted file fails.")
+ return 0
+
+ if TTFont is None:
+ print("fonttools is not present, skipping TTX diff.")
+ return fail_test(test, cli_args, "hash for expected and actual does not match.")
+
+ with io.StringIO() as fp:
+ try:
+ with TTFont(expected_file) as font:
+ font.saveXML(fp)
+ except Exception as e:
+ print(e)
+ return fail_test(test, cli_args, "ttx failed to parse the expected result")
+ expected_ttx = fp.getvalue()
+
+ with io.StringIO() as fp:
+ try:
+ with TTFont(out_file) as font:
+ font.saveXML(fp)
+ except Exception as e:
+ print(e)
+ return fail_test(test, cli_args, "ttx failed to parse the actual result")
+ actual_ttx = fp.getvalue()
+
+ if actual_ttx != expected_ttx:
+ for line in unified_diff(expected_ttx.splitlines(1), actual_ttx.splitlines(1)):
+ sys.stdout.write(line)
+ sys.stdout.flush()
+ return fail_test(test, cli_args, "ttx for expected and actual does not match.")
+
+ return fail_test(
+ test,
+ cli_args,
+ "hash for expected and actual does not match, "
+ "but the ttx matches. Expected file needs to be updated?",
+ )
+
+
+def has_ots():
+ if not ots_sanitize:
+ print("OTS is not present, skipping all ots checks.")
+ return False
+ return True
+
+
+def check_ots(path):
+ ots_report, returncode = cmd([ots_sanitize, path])
+ if returncode:
+ print("OTS Failure: %s" % ots_report)
+ return False
+ return True
+
+
+args = sys.argv[1:]
+if not args or sys.argv[1].find("hb-subset") == -1 or not os.path.exists(sys.argv[1]):
+ sys.exit("First argument does not seem to point to usable hb-subset.")
+hb_subset, args = args[0], args[1:]
+
+if not len(args):
+ sys.exit("No tests supplied.")
+
+has_ots = has_ots()
+
+env = os.environ.copy()
+env["LC_ALL"] = "C"
+
+EXE_WRAPPER = os.environ.get("MESON_EXE_WRAPPER")
+
+
+def open_subset_batch_process():
+ cmd = [hb_subset, "--batch"]
+ if EXE_WRAPPER:
+ cmd = [EXE_WRAPPER] + cmd
+
+ process = subprocess.Popen(
+ cmd,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=sys.stdout,
+ env=env,
+ )
+ return process
+
+
+subset_process = open_subset_batch_process()
+out_dir = tempfile.mkdtemp()
+
+fails = 0
+for path in args:
+ with open(path, mode="r", encoding="utf-8") as f:
+ print("Running tests in " + path)
+ test_suite = SubsetTestSuite(path, f.read())
+ for test in test_suite.tests():
+ # Tests are run with and without preprocessing, results should be the
+ # same between them.
+ fails += run_test(test, has_ots, False)
+ fails += run_test(test, has_ots, True)
+
+if fails != 0:
+ sys.exit("%d test(s) failed; output left in %s" % (fails, out_dir))
+else:
+ print("All tests passed.")
+ shutil.rmtree(out_dir)