• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from fontTools.misc.testTools import FakeFont, getXML, parseXML
2from fontTools.misc.textTools import deHexStr
3from fontTools.ttLib import newTable
4import unittest
5
6
7STAT_DATA = deHexStr(
8    "0001 0000 "  #   0: Version=1.0
9    "0008 0002 "  #   4: DesignAxisSize=8, DesignAxisCount=2
10    "0000 0012 "  #   8: OffsetToDesignAxes=18
11    "0003 0000 0022 "  #  12: AxisValueCount=3, OffsetToAxisValueOffsets=34
12    "7767 6874 "  #  18: DesignAxis[0].AxisTag='wght'
13    "012D 0002 "  #  22: DesignAxis[0].NameID=301, .AxisOrdering=2
14    "5445 5354 "  #  26: DesignAxis[1].AxisTag='TEST'
15    "012E 0001 "  #  30: DesignAxis[1].NameID=302, .AxisOrdering=1
16    "0006 0012 0026 "  #  34: AxisValueOffsets = [6, 18, 38] (+34)
17    "0001 0000 0000  "  #  40: AxisValue[0].Format=1, .AxisIndex=0, .Flags=0
18    "0191 0190 0000 "  #  46: AxisValue[0].ValueNameID=401, .Value=400.0
19    "0002 0001 0000 "  #  52: AxisValue[1].Format=2, .AxisIndex=1, .Flags=0
20    "0192 "  #  58: AxisValue[1].ValueNameID=402
21    "0002 0000 "  #  60: AxisValue[1].NominalValue=2.0
22    "0001 0000 "  #  64: AxisValue[1].RangeMinValue=1.0
23    "0003 0000 "  #  68: AxisValue[1].RangeMaxValue=3.0
24    "0003 0000 0000 "  #  72: AxisValue[2].Format=3, .AxisIndex=0, .Flags=0
25    "0002 "  #  78: AxisValue[2].ValueNameID=2 'Regular'
26    "0190 0000 02BC 0000 "  #  80: AxisValue[2].Value=400.0, .LinkedValue=700.0
27)  #  88: <end>
28assert len(STAT_DATA) == 88
29
30
31STAT_XML = [
32    '<Version value="0x00010000"/>',
33    '<DesignAxisRecordSize value="8"/>',
34    "<!-- DesignAxisCount=2 -->",
35    "<DesignAxisRecord>",
36    '  <Axis index="0">',
37    '    <AxisTag value="wght"/>',
38    '    <AxisNameID value="301"/>',
39    '    <AxisOrdering value="2"/>',
40    "  </Axis>",
41    '  <Axis index="1">',
42    '    <AxisTag value="TEST"/>',
43    '    <AxisNameID value="302"/>',
44    '    <AxisOrdering value="1"/>',
45    "  </Axis>",
46    "</DesignAxisRecord>",
47    "<!-- AxisValueCount=3 -->",
48    "<AxisValueArray>",
49    '  <AxisValue index="0" Format="1">',
50    '    <AxisIndex value="0"/>',
51    '    <Flags value="0"/>',
52    '    <ValueNameID value="401"/>',
53    '    <Value value="400.0"/>',
54    "  </AxisValue>",
55    '  <AxisValue index="1" Format="2">',
56    '    <AxisIndex value="1"/>',
57    '    <Flags value="0"/>',
58    '    <ValueNameID value="402"/>',
59    '    <NominalValue value="2.0"/>',
60    '    <RangeMinValue value="1.0"/>',
61    '    <RangeMaxValue value="3.0"/>',
62    "  </AxisValue>",
63    '  <AxisValue index="2" Format="3">',
64    '    <AxisIndex value="0"/>',
65    '    <Flags value="0"/>',
66    '    <ValueNameID value="2"/>',
67    '    <Value value="400.0"/>',
68    '    <LinkedValue value="700.0"/>',
69    "  </AxisValue>",
70    "</AxisValueArray>",
71]
72
73
74# Contains junk data for making sure we get our offset decoding right.
75STAT_DATA_WITH_AXIS_JUNK = deHexStr(
76    "0001 0000 "  #   0: Version=1.0
77    "000A 0002 "  #   4: DesignAxisSize=10, DesignAxisCount=2
78    "0000 0012 "  #   8: OffsetToDesignAxes=18
79    "0000 0000 0000 "  #  12: AxisValueCount=3, OffsetToAxisValueOffsets=34
80    "7767 6874 "  #  18: DesignAxis[0].AxisTag='wght'
81    "012D 0002 "  #  22: DesignAxis[0].NameID=301, .AxisOrdering=2
82    "DEAD "  #  26: <junk>
83    "5445 5354 "  #  28: DesignAxis[1].AxisTag='TEST'
84    "012E 0001 "  #  32: DesignAxis[1].NameID=302, .AxisOrdering=1
85    "BEEF "  #  36: <junk>
86)  #  38: <end>
87
88assert len(STAT_DATA_WITH_AXIS_JUNK) == 38
89
90
91STAT_XML_WITH_AXIS_JUNK = [
92    '<Version value="0x00010000"/>',
93    '<DesignAxisRecordSize value="10"/>',
94    "<!-- DesignAxisCount=2 -->",
95    "<DesignAxisRecord>",
96    '  <Axis index="0">',
97    '    <AxisTag value="wght"/>',
98    '    <AxisNameID value="301"/>',
99    '    <AxisOrdering value="2"/>',
100    '    <MoreBytes index="0" value="222"/>',  # 0xDE
101    '    <MoreBytes index="1" value="173"/>',  # 0xAD
102    "  </Axis>",
103    '  <Axis index="1">',
104    '    <AxisTag value="TEST"/>',
105    '    <AxisNameID value="302"/>',
106    '    <AxisOrdering value="1"/>',
107    '    <MoreBytes index="0" value="190"/>',  # 0xBE
108    '    <MoreBytes index="1" value="239"/>',  # 0xEF
109    "  </Axis>",
110    "</DesignAxisRecord>",
111    "<!-- AxisValueCount=0 -->",
112]
113
114
115STAT_DATA_AXIS_VALUE_FORMAT3 = deHexStr(
116    "0001 0000 "  #  0: Version=1.0
117    "0008 0001 "  #  4: DesignAxisSize=8, DesignAxisCount=1
118    "0000 0012 "  #  8: OffsetToDesignAxes=18
119    "0001 "  # 12: AxisValueCount=1
120    "0000 001A "  # 14: OffsetToAxisValueOffsets=26
121    "7767 6874 "  # 18: DesignAxis[0].AxisTag='wght'
122    "0102  "  # 22: DesignAxis[0].AxisNameID=258 'Weight'
123    "0000 "  # 24: DesignAxis[0].AxisOrdering=0
124    "0002 "  # 26: AxisValueOffsets=[2] (+26)
125    "0003 "  # 28: AxisValue[0].Format=3
126    "0000 0002 "  # 30: AxisValue[0].AxisIndex=0, .Flags=0x2
127    "0002 "  # 34: AxisValue[0].ValueNameID=2 'Regular'
128    "0190 0000 "  # 36: AxisValue[0].Value=400.0
129    "02BC 0000 "  # 40: AxisValue[0].LinkedValue=700.0
130)  # 44: <end>
131assert len(STAT_DATA_AXIS_VALUE_FORMAT3) == 44
132
133
134STAT_XML_AXIS_VALUE_FORMAT3 = [
135    '<Version value="0x00010000"/>',
136    '<DesignAxisRecordSize value="8"/>',
137    "<!-- DesignAxisCount=1 -->",
138    "<DesignAxisRecord>",
139    '  <Axis index="0">',
140    '    <AxisTag value="wght"/>',
141    '    <AxisNameID value="258"/>',
142    '    <AxisOrdering value="0"/>',
143    "  </Axis>",
144    "</DesignAxisRecord>",
145    "<!-- AxisValueCount=1 -->",
146    "<AxisValueArray>",
147    '  <AxisValue index="0" Format="3">',
148    '    <AxisIndex value="0"/>',
149    '    <Flags value="2"/>  <!-- ElidableAxisValueName -->',
150    '    <ValueNameID value="2"/>',
151    '    <Value value="400.0"/>',
152    '    <LinkedValue value="700.0"/>',
153    "  </AxisValue>",
154    "</AxisValueArray>",
155]
156
157
158STAT_DATA_VERSION_1_1 = deHexStr(
159    "0001 0001 "  #  0: Version=1.1
160    "0008 0001 "  #  4: DesignAxisSize=8, DesignAxisCount=1
161    "0000 0014 "  #  8: OffsetToDesignAxes=20
162    "0001 "  # 12: AxisValueCount=1
163    "0000 001C "  # 14: OffsetToAxisValueOffsets=28
164    "0101 "  # 18: ElidedFallbackNameID: 257
165    "7767 6874 "  # 20: DesignAxis[0].AxisTag='wght'
166    "0102  "  # 24: DesignAxis[0].AxisNameID=258 'Weight'
167    "0000 "  # 26: DesignAxis[0].AxisOrdering=0
168    "0002 "  # 28: AxisValueOffsets=[2] (+28)
169    "0003 "  # 30: AxisValue[0].Format=3
170    "0000 0002 "  # 32: AxisValue[0].AxisIndex=0, .Flags=0x2
171    "0002 "  # 36: AxisValue[0].ValueNameID=2 'Regular'
172    "0190 0000 "  # 38: AxisValue[0].Value=400.0
173    "02BC 0000 "  # 42: AxisValue[0].LinkedValue=700.0
174)  # 46: <end>
175assert len(STAT_DATA_VERSION_1_1) == 46
176
177
178STAT_XML_VERSION_1_1 = [
179    '<Version value="0x00010001"/>',
180    '<DesignAxisRecordSize value="8"/>',
181    "<!-- DesignAxisCount=1 -->",
182    "<DesignAxisRecord>",
183    '  <Axis index="0">',
184    '    <AxisTag value="wght"/>',
185    '    <AxisNameID value="258"/>',
186    '    <AxisOrdering value="0"/>',
187    "  </Axis>",
188    "</DesignAxisRecord>",
189    "<!-- AxisValueCount=1 -->",
190    "<AxisValueArray>",
191    '  <AxisValue index="0" Format="3">',
192    '    <AxisIndex value="0"/>',
193    '    <Flags value="2"/>  <!-- ElidableAxisValueName -->',
194    '    <ValueNameID value="2"/>',
195    '    <Value value="400.0"/>',
196    '    <LinkedValue value="700.0"/>',
197    "  </AxisValue>",
198    "</AxisValueArray>",
199    '<ElidedFallbackNameID value="257"/>',
200]
201
202
203class STATTest(unittest.TestCase):
204    @classmethod
205    def setUpClass(cls):
206        cls.maxDiff = None
207
208    def test_decompile_toXML(self):
209        table = newTable("STAT")
210        table.decompile(STAT_DATA, font=FakeFont([".notdef"]))
211        self.assertEqual(getXML(table.toXML), STAT_XML)
212
213    def test_decompile_toXML_withAxisJunk(self):
214        table = newTable("STAT")
215        table.decompile(STAT_DATA_WITH_AXIS_JUNK, font=FakeFont([".notdef"]))
216        self.assertEqual(getXML(table.toXML), STAT_XML_WITH_AXIS_JUNK)
217
218    def test_decompile_toXML_format3(self):
219        table = newTable("STAT")
220        table.decompile(STAT_DATA_AXIS_VALUE_FORMAT3, font=FakeFont([".notdef"]))
221        self.assertEqual(getXML(table.toXML), STAT_XML_AXIS_VALUE_FORMAT3)
222
223    def test_decompile_toXML_version_1_1(self):
224        table = newTable("STAT")
225        table.decompile(STAT_DATA_VERSION_1_1, font=FakeFont([".notdef"]))
226        self.assertEqual(getXML(table.toXML), STAT_XML_VERSION_1_1)
227
228    def test_compile_fromXML(self):
229        table = newTable("STAT")
230        font = FakeFont([".notdef"])
231        for name, attrs, content in parseXML(STAT_XML):
232            table.fromXML(name, attrs, content, font=font)
233        self.assertEqual(table.compile(font), STAT_DATA)
234
235    def test_compile_fromXML_withAxisJunk(self):
236        table = newTable("STAT")
237        font = FakeFont([".notdef"])
238        for name, attrs, content in parseXML(STAT_XML_WITH_AXIS_JUNK):
239            table.fromXML(name, attrs, content, font=font)
240        self.assertEqual(table.compile(font), STAT_DATA_WITH_AXIS_JUNK)
241
242    def test_compile_fromXML_format3(self):
243        table = newTable("STAT")
244        font = FakeFont([".notdef"])
245        for name, attrs, content in parseXML(STAT_XML_AXIS_VALUE_FORMAT3):
246            table.fromXML(name, attrs, content, font=font)
247        self.assertEqual(table.compile(font), STAT_DATA_AXIS_VALUE_FORMAT3)
248
249    def test_compile_fromXML_version_1_1(self):
250        table = newTable("STAT")
251        font = FakeFont([".notdef"])
252        for name, attrs, content in parseXML(STAT_XML_VERSION_1_1):
253            table.fromXML(name, attrs, content, font=font)
254        self.assertEqual(table.compile(font), STAT_DATA_VERSION_1_1)
255
256
257if __name__ == "__main__":
258    import sys
259
260    sys.exit(unittest.main())
261