1#!/usr/bin/env python3 2 3import os 4 5# A single test in a subset test suite. Identifies a font 6# a subsetting profile, and a subset to be cut. 7class Test: 8 def __init__(self, font_path, profile_path, subset, instance, options): 9 self.font_path = font_path 10 self.profile_path = profile_path 11 self.subset = subset 12 self.instance = instance 13 self.options = options 14 15 def unicodes(self): 16 import re 17 if self.subset == '*': 18 return self.subset[0] 19 elif self.subset == "no-unicodes": 20 return "" 21 elif re.match("^U\+", self.subset): 22 s = re.sub (r"U\+", "", self.subset) 23 return s 24 else: 25 return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset)) 26 27 def instance_name(self): 28 if not self.instance: 29 return self.instance 30 else: 31 s = "." + self.instance.replace(':', '-') 32 return s 33 34 def get_profile_flags(self): 35 with open (self.profile_path, mode="r", encoding="utf-8") as f: 36 return f.read().splitlines() 37 38 def get_instance_flags(self): 39 if not self.instance: 40 return [] 41 else: 42 return self.instance.split(',') 43 44 def get_font_name(self): 45 font_base_name = os.path.basename(self.font_path) 46 font_base_name_parts = os.path.splitext(font_base_name) 47 profile_name = os.path.splitext(os.path.basename(self.profile_path))[0] 48 49 if self.unicodes() == "*": 50 return "%s.%s.retain-all-codepoint%s%s" % (font_base_name_parts[0], 51 profile_name, 52 self.instance_name(), 53 font_base_name_parts[1]) 54 elif self.unicodes() == "": 55 return "%s.%s.no-unicodes%s%s" % (font_base_name_parts[0], 56 profile_name, 57 self.instance_name(), 58 font_base_name_parts[1]) 59 else: 60 return "%s.%s.%s%s%s" % (font_base_name_parts[0], 61 profile_name, 62 self.unicodes(), 63 self.instance_name(), 64 font_base_name_parts[1]) 65 66 def get_font_extension(self): 67 font_base_name = os.path.basename(self.font_path) 68 font_base_name_parts = os.path.splitext(font_base_name) 69 return font_base_name_parts[1] 70 71# A group of tests to perform on the subsetter. Each test 72# Identifies a font a subsetting profile, and a subset to be cut. 73class SubsetTestSuite: 74 75 def __init__(self, test_path, definition): 76 self.test_path = test_path 77 self.fonts = [] 78 self.profiles = [] 79 self.subsets = [] 80 self.instances = [] 81 self.options = [] 82 self._parse(definition) 83 84 def get_output_directory(self): 85 test_name = os.path.splitext(os.path.basename(self.test_path))[0] 86 data_dir = os.path.join(os.path.dirname(self.test_path), "..") 87 88 output_dir = os.path.normpath(os.path.join(data_dir, "expected", test_name)) 89 if not os.path.exists(output_dir): 90 os.mkdir(output_dir) 91 if not os.path.isdir(output_dir): 92 raise Exception("%s is not a directory." % output_dir) 93 94 return output_dir 95 96 def tests(self): 97 for font in self.fonts: 98 font = os.path.join(self._base_path(), "fonts", font) 99 for profile in self.profiles: 100 profile = os.path.join(self._base_path(), "profiles", profile) 101 for subset in self.subsets: 102 if self.instances: 103 for instance in self.instances: 104 yield Test(font, profile, subset, instance, options=self.options) 105 else: 106 yield Test(font, profile, subset, "", options=self.options) 107 108 def _base_path(self): 109 return os.path.dirname(os.path.dirname(self.test_path)) 110 111 def _parse(self, definition): 112 destinations = { 113 "FONTS:": self.fonts, 114 "PROFILES:": self.profiles, 115 "SUBSETS:": self.subsets, 116 "INSTANCES:": self.instances, 117 "OPTIONS:": self.options, 118 } 119 120 current_destination = None 121 for line in definition.splitlines(): 122 line = line.strip() 123 124 if line.startswith("#"): 125 continue 126 127 if not line: 128 continue 129 130 if line in destinations: 131 current_destination = destinations[line] 132 elif current_destination is not None: 133 current_destination.append(line) 134 else: 135 raise Exception("Failed to parse test suite file.") 136