| #!/usr/bin/env python3 | |
| import os | |
| # A single test in a subset test suite. Identifies a font | |
| # a subsetting profile, and a subset to be cut. | |
| class Test: | |
| def __init__( | |
| self, font_path, profile_path, subset, instance, iup_optimize, options | |
| ): | |
| self.font_path = font_path | |
| self.profile_path = profile_path | |
| self.subset = subset | |
| self.instance = instance | |
| self.iup_optimize = iup_optimize | |
| self.options = options | |
| def __str__(self): | |
| # Don't print self.subset as contains non-ASCII and some CI's don't like it | |
| return "Test: %s %s %s %s %s" % ( | |
| self.font_path, | |
| self.profile_path, | |
| self.instance, | |
| self.iup_optimize, | |
| self.options, | |
| ) | |
| def unicodes(self): | |
| import re | |
| if self.subset == "*": | |
| return self.subset[0] | |
| elif self.subset == "no-unicodes": | |
| return "" | |
| elif re.match(r"^U\+", self.subset): | |
| s = re.sub(r"U\+", "", self.subset) | |
| return s | |
| else: | |
| return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset)) | |
| def instance_name(self): | |
| if not self.instance: | |
| return self.instance | |
| else: | |
| # include the first 6 axes to avoid file name too long error | |
| axes = self.instance.replace(":", "-").split(",") | |
| s = "." + ",".join(axes[:6]) | |
| if self.iup_optimize: | |
| s += ".iup_optimize" | |
| return s | |
| def get_profile_flags(self): | |
| with open(self.profile_path, mode="r", encoding="utf-8") as f: | |
| return f.read().splitlines() | |
| def get_instance_flags(self): | |
| if not self.instance: | |
| return [] | |
| else: | |
| return self.instance.split(",") | |
| def get_font_name(self): | |
| font_base_name = os.path.basename(self.font_path) | |
| font_base_name_parts = os.path.splitext(font_base_name) | |
| profile_name = os.path.splitext(os.path.basename(self.profile_path))[0] | |
| if self.unicodes() == "*": | |
| return "%s.%s.all%s%s" % ( | |
| font_base_name_parts[0], | |
| profile_name, | |
| self.instance_name(), | |
| font_base_name_parts[1], | |
| ) | |
| elif self.unicodes() == "": | |
| return "%s.%s.no-unicodes%s%s" % ( | |
| font_base_name_parts[0], | |
| profile_name, | |
| self.instance_name(), | |
| font_base_name_parts[1], | |
| ) | |
| else: | |
| return "%s.%s.%s%s%s" % ( | |
| font_base_name_parts[0], | |
| profile_name, | |
| self.unicodes(), | |
| self.instance_name(), | |
| font_base_name_parts[1], | |
| ) | |
| def get_font_extension(self): | |
| font_base_name = os.path.basename(self.font_path) | |
| font_base_name_parts = os.path.splitext(font_base_name) | |
| return font_base_name_parts[1] | |
| # A group of tests to perform on the subsetter. Each test | |
| # Identifies a font a subsetting profile, and a subset to be cut. | |
| class SubsetTestSuite: | |
| def __init__(self, test_path, definition): | |
| self.test_path = test_path | |
| self.fonts = [] | |
| self.profiles = [] | |
| self.subsets = [] | |
| self.instances = [] | |
| self.options = [] | |
| self.iup_options = [] | |
| self._parse(definition) | |
| def get_output_directory(self): | |
| test_name = os.path.splitext(os.path.basename(self.test_path))[0] | |
| data_dir = os.path.join(os.path.dirname(self.test_path), "..") | |
| output_dir = os.path.normpath(os.path.join(data_dir, "expected", test_name)) | |
| if not os.path.exists(output_dir): | |
| os.mkdir(output_dir) | |
| if not os.path.isdir(output_dir): | |
| raise Exception("%s is not a directory." % output_dir) | |
| return output_dir | |
| def tests(self): | |
| for font in self.fonts: | |
| font = os.path.join(self._base_path(), "fonts", font) | |
| for profile in self.profiles: | |
| profile = os.path.join(self._base_path(), "profiles", profile) | |
| for subset in self.subsets: | |
| if self.instances: | |
| for instance in self.instances: | |
| if self.iup_options: | |
| for iup_option in self.iup_options: | |
| yield Test( | |
| font, | |
| profile, | |
| subset, | |
| instance, | |
| iup_option == "Yes", | |
| options=self.options, | |
| ) | |
| else: | |
| yield Test( | |
| font, | |
| profile, | |
| subset, | |
| instance, | |
| False, | |
| options=self.options, | |
| ) | |
| else: | |
| yield Test( | |
| font, profile, subset, "", False, options=self.options | |
| ) | |
| def _base_path(self): | |
| return os.path.dirname(os.path.dirname(self.test_path)) | |
| def _parse(self, definition): | |
| destinations = { | |
| "FONTS:": self.fonts, | |
| "PROFILES:": self.profiles, | |
| "SUBSETS:": self.subsets, | |
| "INSTANCES:": self.instances, | |
| "OPTIONS:": self.options, | |
| "IUP_OPTIONS:": self.iup_options, | |
| } | |
| current_destination = None | |
| for line in definition.splitlines(): | |
| line = line.strip() | |
| if line.startswith("#"): | |
| continue | |
| if not line: | |
| continue | |
| if line in destinations: | |
| current_destination = destinations[line] | |
| elif current_destination is not None: | |
| current_destination.append(line) | |
| else: | |
| raise Exception("Failed to parse test suite file.") |