From 4cdae914e2e2fff1ff91e2f42648a8acb82a5494 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Fri, 26 Jan 2018 13:57:48 -0800 Subject: [PATCH] Add basic directory structure for subsetter integration tests. Plus a utility for generating expected output files. --- .../basics/Roboto-Regular.abc.default.62.ttf | Bin 0 -> 1996 bytes test/subset/data/fonts/Roboto-Regular.abc.ttf | Bin 0 -> 2460 bytes test/subset/data/profiles/default.txt | 0 test/subset/data/tests/basics.txt | 8 ++ test/subset/generate-expected-outputs.py | 40 +++++++++ test/subset/subset_test_suite.py | 82 ++++++++++++++++++ 6 files changed, 130 insertions(+) create mode 100644 test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf create mode 100644 test/subset/data/fonts/Roboto-Regular.abc.ttf create mode 100644 test/subset/data/profiles/default.txt create mode 100644 test/subset/data/tests/basics.txt create mode 100755 test/subset/generate-expected-outputs.py create mode 100644 test/subset/subset_test_suite.py diff --git a/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf b/test/subset/data/expected/basics/Roboto-Regular.abc.default.62.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8e44886f1f31dba3004b2ef0bff3d3afda4c22b4 GIT binary patch literal 1996 zcmZuyZERCj7=F*ax1TGlt!1)a7`N*_7;EVq%L223qU{C_SzU{{mnd7ebsw;?x(^s8 z=z=1%B8c+CU3$hX9re#GD!UXcp?x9o$WcEAqTgcV!17k|0`xmD3 z$dkw``iI6QtTsR`VFz;S;Ba>eI?w{afnXj=O=N_6(T4hWkSqIBLup~g{wIcTkFYT_ zJUUhwf*$18D4rQfXU_LNz<#9rShF1jI9|9TDR_gHLn-v;++Nw`-o)KbE?xs}4RMI6 z+!2ze9p25FPDCW4dy$xtn33d6RuSuRb_Y$|;hc6eZm(5+H{^R77oF2j{zL1YVjjU? zUTyKaHna~YQXW$yjAXX3j)KYChl-OvAc>aZCW zzJ4eFbAG|}<<$%Mz=f;0BYM^XoP-icf=Oqz6Lbj`_|z#1`u)=L{O+z_zxlYMIQ$os zTJ_N7yRP+QTxad~9>@#VZFSaBq&5`Lhj<)%q{DEWlq`dJyyv#<59IuFwz@@aBaKi1 zQF@ELhh2c_jA;Y5w#Jyn@1d9E7A1`eqcg*XmbSJQh(H%~nIR9*YdIr;0_+@xr6vZyj>VH-?^rW*7b#hd?X0 z#noxXPH3~NaFoBfdfFy->ADL-QYYK9SWUvCWvlp0&bMQk{df;_Zwkb3Zn#OwBs+zAgG_ zm&*b?GBvBfZgsi_qVgQnh_|EYchqvIg&cDVwJhgih%>IHx=Psz)>@ch+n!$U^Po8+ zsM|KK)h)68*@nsz@=1H157(BGWoitRmll&{e&yxndYLTCse>;y`N^`r))(L8CCiqK zHCE{=_5+=*jjPF5^hVE4BhPU&m+cOdZ<)vGu$jqP99R#lvguHAl*G4c*aFXC6L4jb6myJ`!I8}^O#dxl`jA{w~AXrm| zc^w2N3BDsJ5Ns*K1Sq4^D%tQP(kV1-0l!!d zXoq1ugTpX}zjjDNAB@8wq+kTI^ikML-|_z$3_mSa5b&HAqb{i#qXgN~MIRqp(SaTs zgm$Qd%^*dacO=2veQ0D5ynQ3-ec&BTjqL|7zK=Lim2%m>^vHf(#i(Q$BSl8*f=AEv iLOI$?>Pzd=Y-G}U_0aIxdKLP575aJ=kJdxsrSUiVPqUE# literal 0 HcmV?d00001 diff --git a/test/subset/data/fonts/Roboto-Regular.abc.ttf b/test/subset/data/fonts/Roboto-Regular.abc.ttf new file mode 100644 index 0000000000000000000000000000000000000000..9d791f7fc5ba42bb66504843d5841f2b180beef7 GIT binary patch literal 2460 zcmZuyeQaA-6+idA=jUg~OP-Arw|;B#+?UVBUa}-LTZp;c*H zj{OkFuK=*ild<^}DDWxF|2&SnCTAX=2yc7$MH~wP2%}Sp=byFC*5E z#FFE}it}GMe+2OzsoD8-AqiNU@+gg`=EhUsow)WZ02$|C`#^wX;i~v|X+Km$BRrb( zHSKbH?&Lm|>u&;w9+Uf8w5-p+Ct3s&0?AVXfB+EW1fPUKxw2x%%UUozTfw-q*$n(i z`yiV0l=&#Bq-JZjth`Lk8e6dS_CS4uZ0xMx-BH`#zPqE|*eO>U9pP|$Tb0l4^;Ooj zg+IO9&?~)FVx#K(+D~43ow2`NOg|Vu{>uDoM=!l4)#uCZdEPjk|4~{WI{wqAesJkP zY(CL<_qWYUFXzj@WvVAf_rCMXd+x_=fD?tQk}d<3!*-a+dHfpD^Qc_Jnw6Gfr7kSa zwOO`^K-?@_Mj%t!Hbtbeoi6IQOU-(=%Hg7#^=-k{+nHA|b~e}zce^{Rd)y6Fpxs^7 z-WHbhch_G}InJ-8Smv*5-~7hP;DL)zoDtj~=KpZ|m<-o{@l^hg`Rlfyzi~bvJpTqT zIEXuT6?be0^yk#-8l2qPDHVySo0Js<3bM??77MOWiCk5=m*mX^X?@$vktDcxmzLeA zFYW>^xv(dGM!8@+`r47df`5HS)*&9cFT`0;*L$WToQ;LJ5aeuEAjHL>-pj?h-XYV7 z>KQ$=FOkuE^{H5bOLfH_2gWne7M;VeIgN6}4Djx#c0(PHMms}XqBIzR-kB&SI9y7A zebLl%J;ZInew~Z;gXY~PUy5kFI}+6b0lkN>51M>Eq6MPS5SMRoM6SoCw^?lMK`!qK zamC6oZ1Qf6Lo}12e8Z*@;7gf|mca@(@%qhpmBA+s-5)pL3iPb9r9n)Eoe|K;U<8Z+ zGK@w-+!5>_HhYj_04X|yys;<5%YwWKJ6ABa6`EPj%}}nmJ6r2C6_jRJ zVS7JwTfmFzieT=&qp_%oL!a-ct0J3p-I@TZFLAJ8T6Z;1!+&T?{~()CpecB&c|1z4A7wWZwg~ybk5^2Hs3o6Y!6S zr&V&`Nu*O~=>pzhE*OGYxF6p%zC$n$ldu3YcrxeEtJn&M>7V<58pG>F0Rhi>1?Ht} zR@;U;!-wt%vRfzLg}QZ{IH48xfE4Nd;t2TT56{hje{yd80r1bn(nr9L-y=56TJ(Ql zeC`O&Vns3>qkN3!#eY0`wo$H4u82R`EFMCM4RPAitz0yZ6Z3T3#HqH(skX?e_6Dbq GW&a ..." + + +def generate_expected_output(input_file, unicodes, output_path): + check_call(["fonttools", "subset", + input_file, + "--unicodes=%s" % unicodes, + "--output-file=%s" % output_path]) + + +args = sys.argv[1:] +if not args: + usage() + +for path in args: + with open(path, 'r') as f: + test_suite = SubsetTestSuite(path, f.read()) + output_directory = test_suite.get_output_directory() + + print "Generating output files for %s" % output_directory + for test in test_suite.tests(): + unicodes = test.unicodes() + font_name = test.get_font_name() + print "Creating subset %s/%s" % (output_directory, font_name) + generate_expected_output(test.font_path, unicodes, + os.path.join(output_directory, + font_name)) diff --git a/test/subset/subset_test_suite.py b/test/subset/subset_test_suite.py new file mode 100644 index 000000000..256e20713 --- /dev/null +++ b/test/subset/subset_test_suite.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python + +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): + self.font_path = font_path + self.profile_path = profile_path + self.subset = subset + + def unicodes(self): + return ",".join("%X" % ord(c) for (i, c) in enumerate(self.subset)) + + 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] + + return "%s.%s.%s%s" % (font_base_name_parts[0], + profile_name, + self.unicodes(), + 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 = set() + self.profiles = set() + self.subsets = set() + 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 Error("%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: + yield Test(font, profile, subset) + + 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 + } + + 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.add(line) + else: + raise Exception("Failed to parse test suite file.")