xref: /aosp_15_r20/external/fonttools/Tests/ttLib/tables/otConverters_test.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1*e1fe3e4aSElliott Hughesfrom fontTools.misc.loggingTools import CapturingLogHandler
2*e1fe3e4aSElliott Hughesfrom fontTools.misc.testTools import FakeFont, makeXMLWriter
3*e1fe3e4aSElliott Hughesfrom fontTools.misc.textTools import deHexStr
4*e1fe3e4aSElliott Hughesimport fontTools.ttLib.tables.otConverters as otConverters
5*e1fe3e4aSElliott Hughesfrom fontTools.ttLib import newTable
6*e1fe3e4aSElliott Hughesfrom fontTools.ttLib.tables.otBase import OTTableReader, OTTableWriter
7*e1fe3e4aSElliott Hughesimport unittest
8*e1fe3e4aSElliott Hughes
9*e1fe3e4aSElliott Hughes
10*e1fe3e4aSElliott Hughesclass Char64Test(unittest.TestCase):
11*e1fe3e4aSElliott Hughes    font = FakeFont([])
12*e1fe3e4aSElliott Hughes    converter = otConverters.Char64("char64", 0, None, None)
13*e1fe3e4aSElliott Hughes
14*e1fe3e4aSElliott Hughes    def test_read(self):
15*e1fe3e4aSElliott Hughes        reader = OTTableReader(b"Hello\0junk after zero byte" + 100 * b"\0")
16*e1fe3e4aSElliott Hughes        self.assertEqual(self.converter.read(reader, self.font, {}), "Hello")
17*e1fe3e4aSElliott Hughes        self.assertEqual(reader.pos, 64)
18*e1fe3e4aSElliott Hughes
19*e1fe3e4aSElliott Hughes    def test_read_replace_not_ascii(self):
20*e1fe3e4aSElliott Hughes        reader = OTTableReader(b"Hello \xE4 world" + 100 * b"\0")
21*e1fe3e4aSElliott Hughes        with CapturingLogHandler(otConverters.log, "WARNING") as captor:
22*e1fe3e4aSElliott Hughes            data = self.converter.read(reader, self.font, {})
23*e1fe3e4aSElliott Hughes        self.assertEqual(data, "Hello � world")
24*e1fe3e4aSElliott Hughes        self.assertEqual(reader.pos, 64)
25*e1fe3e4aSElliott Hughes        self.assertIn(
26*e1fe3e4aSElliott Hughes            'replaced non-ASCII characters in "Hello � world"',
27*e1fe3e4aSElliott Hughes            [r.msg for r in captor.records],
28*e1fe3e4aSElliott Hughes        )
29*e1fe3e4aSElliott Hughes
30*e1fe3e4aSElliott Hughes    def test_write(self):
31*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
32*e1fe3e4aSElliott Hughes        self.converter.write(writer, self.font, {}, "Hello world")
33*e1fe3e4aSElliott Hughes        self.assertEqual(writer.getData(), b"Hello world" + 53 * b"\0")
34*e1fe3e4aSElliott Hughes
35*e1fe3e4aSElliott Hughes    def test_write_replace_not_ascii(self):
36*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
37*e1fe3e4aSElliott Hughes        with CapturingLogHandler(otConverters.log, "WARNING") as captor:
38*e1fe3e4aSElliott Hughes            self.converter.write(writer, self.font, {}, "Hello ☃")
39*e1fe3e4aSElliott Hughes        self.assertEqual(writer.getData(), b"Hello ?" + 57 * b"\0")
40*e1fe3e4aSElliott Hughes        self.assertIn(
41*e1fe3e4aSElliott Hughes            'replacing non-ASCII characters in "Hello ☃"',
42*e1fe3e4aSElliott Hughes            [r.msg for r in captor.records],
43*e1fe3e4aSElliott Hughes        )
44*e1fe3e4aSElliott Hughes
45*e1fe3e4aSElliott Hughes    def test_write_truncated(self):
46*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
47*e1fe3e4aSElliott Hughes        with CapturingLogHandler(otConverters.log, "WARNING") as captor:
48*e1fe3e4aSElliott Hughes            self.converter.write(writer, self.font, {}, "A" * 80)
49*e1fe3e4aSElliott Hughes        self.assertEqual(writer.getData(), b"A" * 64)
50*e1fe3e4aSElliott Hughes        self.assertIn(
51*e1fe3e4aSElliott Hughes            'truncating overlong "' + "A" * 80 + '" to 64 bytes',
52*e1fe3e4aSElliott Hughes            [r.msg for r in captor.records],
53*e1fe3e4aSElliott Hughes        )
54*e1fe3e4aSElliott Hughes
55*e1fe3e4aSElliott Hughes    def test_xmlRead(self):
56*e1fe3e4aSElliott Hughes        value = self.converter.xmlRead({"value": "Foo"}, [], self.font)
57*e1fe3e4aSElliott Hughes        self.assertEqual(value, "Foo")
58*e1fe3e4aSElliott Hughes
59*e1fe3e4aSElliott Hughes    def test_xmlWrite(self):
60*e1fe3e4aSElliott Hughes        writer = makeXMLWriter()
61*e1fe3e4aSElliott Hughes        self.converter.xmlWrite(
62*e1fe3e4aSElliott Hughes            writer, self.font, "Hello world", "Element", [("attr", "v")]
63*e1fe3e4aSElliott Hughes        )
64*e1fe3e4aSElliott Hughes        xml = writer.file.getvalue().decode("utf-8").rstrip()
65*e1fe3e4aSElliott Hughes        self.assertEqual(xml, '<Element attr="v" value="Hello world"/>')
66*e1fe3e4aSElliott Hughes
67*e1fe3e4aSElliott Hughes
68*e1fe3e4aSElliott Hughesclass GlyphIDTest(unittest.TestCase):
69*e1fe3e4aSElliott Hughes    font = FakeFont(".notdef A B C".split())
70*e1fe3e4aSElliott Hughes    converter = otConverters.GlyphID("GlyphID", 0, None, None)
71*e1fe3e4aSElliott Hughes
72*e1fe3e4aSElliott Hughes    def test_readArray(self):
73*e1fe3e4aSElliott Hughes        reader = OTTableReader(deHexStr("0002 0001 DEAD 0002"))
74*e1fe3e4aSElliott Hughes        self.assertEqual(
75*e1fe3e4aSElliott Hughes            self.converter.readArray(reader, self.font, {}, 4),
76*e1fe3e4aSElliott Hughes            ["B", "A", "glyph57005", "B"],
77*e1fe3e4aSElliott Hughes        )
78*e1fe3e4aSElliott Hughes        self.assertEqual(reader.pos, 8)
79*e1fe3e4aSElliott Hughes
80*e1fe3e4aSElliott Hughes    def test_read(self):
81*e1fe3e4aSElliott Hughes        reader = OTTableReader(deHexStr("0003"))
82*e1fe3e4aSElliott Hughes        self.assertEqual(self.converter.read(reader, self.font, {}), "C")
83*e1fe3e4aSElliott Hughes        self.assertEqual(reader.pos, 2)
84*e1fe3e4aSElliott Hughes
85*e1fe3e4aSElliott Hughes    def test_write(self):
86*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
87*e1fe3e4aSElliott Hughes        self.converter.write(writer, self.font, {}, "B")
88*e1fe3e4aSElliott Hughes        self.assertEqual(writer.getData(), deHexStr("0002"))
89*e1fe3e4aSElliott Hughes
90*e1fe3e4aSElliott Hughes
91*e1fe3e4aSElliott Hughesclass LongTest(unittest.TestCase):
92*e1fe3e4aSElliott Hughes    font = FakeFont([])
93*e1fe3e4aSElliott Hughes    converter = otConverters.Long("Long", 0, None, None)
94*e1fe3e4aSElliott Hughes
95*e1fe3e4aSElliott Hughes    def test_read(self):
96*e1fe3e4aSElliott Hughes        reader = OTTableReader(deHexStr("FF0000EE"))
97*e1fe3e4aSElliott Hughes        self.assertEqual(self.converter.read(reader, self.font, {}), -16776978)
98*e1fe3e4aSElliott Hughes        self.assertEqual(reader.pos, 4)
99*e1fe3e4aSElliott Hughes
100*e1fe3e4aSElliott Hughes    def test_write(self):
101*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
102*e1fe3e4aSElliott Hughes        self.converter.write(writer, self.font, {}, -16777213)
103*e1fe3e4aSElliott Hughes        self.assertEqual(writer.getData(), deHexStr("FF000003"))
104*e1fe3e4aSElliott Hughes
105*e1fe3e4aSElliott Hughes    def test_xmlRead(self):
106*e1fe3e4aSElliott Hughes        value = self.converter.xmlRead({"value": "314159"}, [], self.font)
107*e1fe3e4aSElliott Hughes        self.assertEqual(value, 314159)
108*e1fe3e4aSElliott Hughes
109*e1fe3e4aSElliott Hughes    def test_xmlWrite(self):
110*e1fe3e4aSElliott Hughes        writer = makeXMLWriter()
111*e1fe3e4aSElliott Hughes        self.converter.xmlWrite(writer, self.font, 291, "Foo", [("attr", "v")])
112*e1fe3e4aSElliott Hughes        xml = writer.file.getvalue().decode("utf-8").rstrip()
113*e1fe3e4aSElliott Hughes        self.assertEqual(xml, '<Foo attr="v" value="291"/>')
114*e1fe3e4aSElliott Hughes
115*e1fe3e4aSElliott Hughes
116*e1fe3e4aSElliott Hughesclass NameIDTest(unittest.TestCase):
117*e1fe3e4aSElliott Hughes    converter = otConverters.NameID("NameID", 0, None, None)
118*e1fe3e4aSElliott Hughes
119*e1fe3e4aSElliott Hughes    def makeFont(self):
120*e1fe3e4aSElliott Hughes        nameTable = newTable("name")
121*e1fe3e4aSElliott Hughes        nameTable.setName("Demibold Condensed", 0x123, 3, 0, 0x409)
122*e1fe3e4aSElliott Hughes        nameTable.setName("Copyright 2018", 0, 3, 0, 0x409)
123*e1fe3e4aSElliott Hughes        return {"name": nameTable}
124*e1fe3e4aSElliott Hughes
125*e1fe3e4aSElliott Hughes    def test_read(self):
126*e1fe3e4aSElliott Hughes        font = self.makeFont()
127*e1fe3e4aSElliott Hughes        reader = OTTableReader(deHexStr("0123"))
128*e1fe3e4aSElliott Hughes        self.assertEqual(self.converter.read(reader, font, {}), 0x123)
129*e1fe3e4aSElliott Hughes
130*e1fe3e4aSElliott Hughes    def test_write(self):
131*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
132*e1fe3e4aSElliott Hughes        self.converter.write(writer, self.makeFont(), {}, 0x123)
133*e1fe3e4aSElliott Hughes        self.assertEqual(writer.getData(), deHexStr("0123"))
134*e1fe3e4aSElliott Hughes
135*e1fe3e4aSElliott Hughes    def test_xmlWrite(self):
136*e1fe3e4aSElliott Hughes        writer = makeXMLWriter()
137*e1fe3e4aSElliott Hughes        self.converter.xmlWrite(
138*e1fe3e4aSElliott Hughes            writer, self.makeFont(), 291, "FooNameID", [("attr", "val")]
139*e1fe3e4aSElliott Hughes        )
140*e1fe3e4aSElliott Hughes        xml = writer.file.getvalue().decode("utf-8").rstrip()
141*e1fe3e4aSElliott Hughes        self.assertEqual(
142*e1fe3e4aSElliott Hughes            xml, '<FooNameID attr="val" value="291"/>  <!-- Demibold Condensed -->'
143*e1fe3e4aSElliott Hughes        )
144*e1fe3e4aSElliott Hughes
145*e1fe3e4aSElliott Hughes    def test_xmlWrite_missingID(self):
146*e1fe3e4aSElliott Hughes        writer = makeXMLWriter()
147*e1fe3e4aSElliott Hughes        with CapturingLogHandler(otConverters.log, "WARNING") as captor:
148*e1fe3e4aSElliott Hughes            self.converter.xmlWrite(
149*e1fe3e4aSElliott Hughes                writer, self.makeFont(), 666, "Entity", [("attrib", "val")]
150*e1fe3e4aSElliott Hughes            )
151*e1fe3e4aSElliott Hughes        self.assertIn(
152*e1fe3e4aSElliott Hughes            "name id 666 missing from name table", [r.msg for r in captor.records]
153*e1fe3e4aSElliott Hughes        )
154*e1fe3e4aSElliott Hughes        xml = writer.file.getvalue().decode("utf-8").rstrip()
155*e1fe3e4aSElliott Hughes        self.assertEqual(
156*e1fe3e4aSElliott Hughes            xml,
157*e1fe3e4aSElliott Hughes            '<Entity attrib="val"' ' value="666"/>  <!-- missing from name table -->',
158*e1fe3e4aSElliott Hughes        )
159*e1fe3e4aSElliott Hughes
160*e1fe3e4aSElliott Hughes    def test_xmlWrite_NULL(self):
161*e1fe3e4aSElliott Hughes        writer = makeXMLWriter()
162*e1fe3e4aSElliott Hughes        self.converter.xmlWrite(
163*e1fe3e4aSElliott Hughes            writer, self.makeFont(), 0, "FooNameID", [("attr", "val")]
164*e1fe3e4aSElliott Hughes        )
165*e1fe3e4aSElliott Hughes        xml = writer.file.getvalue().decode("utf-8").rstrip()
166*e1fe3e4aSElliott Hughes        self.assertEqual(xml, '<FooNameID attr="val" value="0"/>')
167*e1fe3e4aSElliott Hughes
168*e1fe3e4aSElliott Hughes
169*e1fe3e4aSElliott Hughesclass UInt8Test(unittest.TestCase):
170*e1fe3e4aSElliott Hughes    font = FakeFont([])
171*e1fe3e4aSElliott Hughes    converter = otConverters.UInt8("UInt8", 0, None, None)
172*e1fe3e4aSElliott Hughes
173*e1fe3e4aSElliott Hughes    def test_read(self):
174*e1fe3e4aSElliott Hughes        reader = OTTableReader(deHexStr("FE"))
175*e1fe3e4aSElliott Hughes        self.assertEqual(self.converter.read(reader, self.font, {}), 254)
176*e1fe3e4aSElliott Hughes        self.assertEqual(reader.pos, 1)
177*e1fe3e4aSElliott Hughes
178*e1fe3e4aSElliott Hughes    def test_write(self):
179*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
180*e1fe3e4aSElliott Hughes        self.converter.write(writer, self.font, {}, 253)
181*e1fe3e4aSElliott Hughes        self.assertEqual(writer.getData(), deHexStr("FD"))
182*e1fe3e4aSElliott Hughes
183*e1fe3e4aSElliott Hughes    def test_xmlRead(self):
184*e1fe3e4aSElliott Hughes        value = self.converter.xmlRead({"value": "254"}, [], self.font)
185*e1fe3e4aSElliott Hughes        self.assertEqual(value, 254)
186*e1fe3e4aSElliott Hughes
187*e1fe3e4aSElliott Hughes    def test_xmlWrite(self):
188*e1fe3e4aSElliott Hughes        writer = makeXMLWriter()
189*e1fe3e4aSElliott Hughes        self.converter.xmlWrite(writer, self.font, 251, "Foo", [("attr", "v")])
190*e1fe3e4aSElliott Hughes        xml = writer.file.getvalue().decode("utf-8").rstrip()
191*e1fe3e4aSElliott Hughes        self.assertEqual(xml, '<Foo attr="v" value="251"/>')
192*e1fe3e4aSElliott Hughes
193*e1fe3e4aSElliott Hughes
194*e1fe3e4aSElliott Hughesclass AATLookupTest(unittest.TestCase):
195*e1fe3e4aSElliott Hughes    font = FakeFont(".notdef A B C D E F G H A.alt B.alt".split())
196*e1fe3e4aSElliott Hughes    converter = otConverters.AATLookup(
197*e1fe3e4aSElliott Hughes        "AATLookup", 0, None, tableClass=otConverters.GlyphID
198*e1fe3e4aSElliott Hughes    )
199*e1fe3e4aSElliott Hughes
200*e1fe3e4aSElliott Hughes    def __init__(self, methodName):
201*e1fe3e4aSElliott Hughes        unittest.TestCase.__init__(self, methodName)
202*e1fe3e4aSElliott Hughes        # Python 3 renamed assertRaisesRegexp to assertRaisesRegex,
203*e1fe3e4aSElliott Hughes        # and fires deprecation warnings if a program uses the old name.
204*e1fe3e4aSElliott Hughes        if not hasattr(self, "assertRaisesRegex"):
205*e1fe3e4aSElliott Hughes            self.assertRaisesRegex = self.assertRaisesRegexp
206*e1fe3e4aSElliott Hughes
207*e1fe3e4aSElliott Hughes    def test_readFormat0(self):
208*e1fe3e4aSElliott Hughes        reader = OTTableReader(deHexStr("0000 0000 0001 0002 0000 7D00 0001"))
209*e1fe3e4aSElliott Hughes        self.assertEqual(
210*e1fe3e4aSElliott Hughes            self.converter.read(reader, self.font, None),
211*e1fe3e4aSElliott Hughes            {
212*e1fe3e4aSElliott Hughes                ".notdef": ".notdef",
213*e1fe3e4aSElliott Hughes                "A": "A",
214*e1fe3e4aSElliott Hughes                "B": "B",
215*e1fe3e4aSElliott Hughes                "C": ".notdef",
216*e1fe3e4aSElliott Hughes                "D": "glyph32000",
217*e1fe3e4aSElliott Hughes                "E": "A",
218*e1fe3e4aSElliott Hughes            },
219*e1fe3e4aSElliott Hughes        )
220*e1fe3e4aSElliott Hughes
221*e1fe3e4aSElliott Hughes    def test_readFormat2(self):
222*e1fe3e4aSElliott Hughes        reader = OTTableReader(
223*e1fe3e4aSElliott Hughes            deHexStr(
224*e1fe3e4aSElliott Hughes                "0002 0006 0002 000C 0001 0006 "
225*e1fe3e4aSElliott Hughes                "0002 0001 0003 "  # glyph A..B: map to C
226*e1fe3e4aSElliott Hughes                "0007 0005 0008 "  # glyph E..G: map to H
227*e1fe3e4aSElliott Hughes                "FFFF FFFF FFFF"
228*e1fe3e4aSElliott Hughes            )
229*e1fe3e4aSElliott Hughes        )  # end of search table
230*e1fe3e4aSElliott Hughes        self.assertEqual(
231*e1fe3e4aSElliott Hughes            self.converter.read(reader, self.font, None),
232*e1fe3e4aSElliott Hughes            {
233*e1fe3e4aSElliott Hughes                "A": "C",
234*e1fe3e4aSElliott Hughes                "B": "C",
235*e1fe3e4aSElliott Hughes                "E": "H",
236*e1fe3e4aSElliott Hughes                "F": "H",
237*e1fe3e4aSElliott Hughes                "G": "H",
238*e1fe3e4aSElliott Hughes            },
239*e1fe3e4aSElliott Hughes        )
240*e1fe3e4aSElliott Hughes
241*e1fe3e4aSElliott Hughes    def test_readFormat4(self):
242*e1fe3e4aSElliott Hughes        reader = OTTableReader(
243*e1fe3e4aSElliott Hughes            deHexStr(
244*e1fe3e4aSElliott Hughes                "0004 0006 0003 000C 0001 0006 "
245*e1fe3e4aSElliott Hughes                "0002 0001 001E "  # glyph 1..2: mapping at offset 0x1E
246*e1fe3e4aSElliott Hughes                "0005 0004 001E "  # glyph 4..5: mapping at offset 0x1E
247*e1fe3e4aSElliott Hughes                "FFFF FFFF FFFF "  # end of search table
248*e1fe3e4aSElliott Hughes                "0007 0008"
249*e1fe3e4aSElliott Hughes            )
250*e1fe3e4aSElliott Hughes        )  # offset 0x18: glyphs [7, 8] = [G, H]
251*e1fe3e4aSElliott Hughes        self.assertEqual(
252*e1fe3e4aSElliott Hughes            self.converter.read(reader, self.font, None),
253*e1fe3e4aSElliott Hughes            {
254*e1fe3e4aSElliott Hughes                "A": "G",
255*e1fe3e4aSElliott Hughes                "B": "H",
256*e1fe3e4aSElliott Hughes                "D": "G",
257*e1fe3e4aSElliott Hughes                "E": "H",
258*e1fe3e4aSElliott Hughes            },
259*e1fe3e4aSElliott Hughes        )
260*e1fe3e4aSElliott Hughes
261*e1fe3e4aSElliott Hughes    def test_readFormat6(self):
262*e1fe3e4aSElliott Hughes        reader = OTTableReader(
263*e1fe3e4aSElliott Hughes            deHexStr(
264*e1fe3e4aSElliott Hughes                "0006 0004 0002 0008 0001 0004 "
265*e1fe3e4aSElliott Hughes                "0003 0001 "  # C --> A
266*e1fe3e4aSElliott Hughes                "0005 0002 "  # E --> B
267*e1fe3e4aSElliott Hughes                "FFFF FFFF"
268*e1fe3e4aSElliott Hughes            )
269*e1fe3e4aSElliott Hughes        )  # end of search table
270*e1fe3e4aSElliott Hughes        self.assertEqual(
271*e1fe3e4aSElliott Hughes            self.converter.read(reader, self.font, None),
272*e1fe3e4aSElliott Hughes            {
273*e1fe3e4aSElliott Hughes                "C": "A",
274*e1fe3e4aSElliott Hughes                "E": "B",
275*e1fe3e4aSElliott Hughes            },
276*e1fe3e4aSElliott Hughes        )
277*e1fe3e4aSElliott Hughes
278*e1fe3e4aSElliott Hughes    def test_readFormat8(self):
279*e1fe3e4aSElliott Hughes        reader = OTTableReader(
280*e1fe3e4aSElliott Hughes            deHexStr("0008 " "0003 0003 " "0007 0001 0002")  # first: C, count: 3
281*e1fe3e4aSElliott Hughes        )  # [G, A, B]
282*e1fe3e4aSElliott Hughes        self.assertEqual(
283*e1fe3e4aSElliott Hughes            self.converter.read(reader, self.font, None),
284*e1fe3e4aSElliott Hughes            {
285*e1fe3e4aSElliott Hughes                "C": "G",
286*e1fe3e4aSElliott Hughes                "D": "A",
287*e1fe3e4aSElliott Hughes                "E": "B",
288*e1fe3e4aSElliott Hughes            },
289*e1fe3e4aSElliott Hughes        )
290*e1fe3e4aSElliott Hughes
291*e1fe3e4aSElliott Hughes    def test_readUnknownFormat(self):
292*e1fe3e4aSElliott Hughes        reader = OTTableReader(deHexStr("0009"))
293*e1fe3e4aSElliott Hughes        self.assertRaisesRegex(
294*e1fe3e4aSElliott Hughes            AssertionError,
295*e1fe3e4aSElliott Hughes            "unsupported lookup format: 9",
296*e1fe3e4aSElliott Hughes            self.converter.read,
297*e1fe3e4aSElliott Hughes            reader,
298*e1fe3e4aSElliott Hughes            self.font,
299*e1fe3e4aSElliott Hughes            None,
300*e1fe3e4aSElliott Hughes        )
301*e1fe3e4aSElliott Hughes
302*e1fe3e4aSElliott Hughes    def test_writeFormat0(self):
303*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
304*e1fe3e4aSElliott Hughes        font = FakeFont(".notdef A B C".split())
305*e1fe3e4aSElliott Hughes        self.converter.write(
306*e1fe3e4aSElliott Hughes            writer, font, {}, {".notdef": ".notdef", "A": "C", "B": "C", "C": "A"}
307*e1fe3e4aSElliott Hughes        )
308*e1fe3e4aSElliott Hughes        self.assertEqual(writer.getData(), deHexStr("0000 0000 0003 0003 0001"))
309*e1fe3e4aSElliott Hughes
310*e1fe3e4aSElliott Hughes    def test_writeFormat2(self):
311*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
312*e1fe3e4aSElliott Hughes        font = FakeFont(".notdef A B C D E F G H".split())
313*e1fe3e4aSElliott Hughes        self.converter.write(
314*e1fe3e4aSElliott Hughes            writer,
315*e1fe3e4aSElliott Hughes            font,
316*e1fe3e4aSElliott Hughes            {},
317*e1fe3e4aSElliott Hughes            {
318*e1fe3e4aSElliott Hughes                "B": "C",
319*e1fe3e4aSElliott Hughes                "C": "C",
320*e1fe3e4aSElliott Hughes                "D": "C",
321*e1fe3e4aSElliott Hughes                "E": "C",
322*e1fe3e4aSElliott Hughes                "G": "A",
323*e1fe3e4aSElliott Hughes                "H": "A",
324*e1fe3e4aSElliott Hughes            },
325*e1fe3e4aSElliott Hughes        )
326*e1fe3e4aSElliott Hughes        self.assertEqual(
327*e1fe3e4aSElliott Hughes            writer.getData(),
328*e1fe3e4aSElliott Hughes            deHexStr(
329*e1fe3e4aSElliott Hughes                "0002 "  # format=2
330*e1fe3e4aSElliott Hughes                "0006 "  # binSrchHeader.unitSize=6
331*e1fe3e4aSElliott Hughes                "0002 "  # binSrchHeader.nUnits=2
332*e1fe3e4aSElliott Hughes                "000C "  # binSrchHeader.searchRange=12
333*e1fe3e4aSElliott Hughes                "0001 "  # binSrchHeader.entrySelector=1
334*e1fe3e4aSElliott Hughes                "0000 "  # binSrchHeader.rangeShift=0
335*e1fe3e4aSElliott Hughes                "0005 0002 0003 "  # segments[0].lastGlyph=E, firstGlyph=B, value=C
336*e1fe3e4aSElliott Hughes                "0008 0007 0001 "  # segments[1].lastGlyph=H, firstGlyph=G, value=A
337*e1fe3e4aSElliott Hughes                "FFFF FFFF 0000 "  # segments[2]=<END>
338*e1fe3e4aSElliott Hughes            ),
339*e1fe3e4aSElliott Hughes        )
340*e1fe3e4aSElliott Hughes
341*e1fe3e4aSElliott Hughes    def test_writeFormat6(self):
342*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
343*e1fe3e4aSElliott Hughes        font = FakeFont(".notdef A B C D E".split())
344*e1fe3e4aSElliott Hughes        self.converter.write(
345*e1fe3e4aSElliott Hughes            writer,
346*e1fe3e4aSElliott Hughes            font,
347*e1fe3e4aSElliott Hughes            {},
348*e1fe3e4aSElliott Hughes            {
349*e1fe3e4aSElliott Hughes                "A": "C",
350*e1fe3e4aSElliott Hughes                "C": "B",
351*e1fe3e4aSElliott Hughes                "D": "D",
352*e1fe3e4aSElliott Hughes                "E": "E",
353*e1fe3e4aSElliott Hughes            },
354*e1fe3e4aSElliott Hughes        )
355*e1fe3e4aSElliott Hughes        self.assertEqual(
356*e1fe3e4aSElliott Hughes            writer.getData(),
357*e1fe3e4aSElliott Hughes            deHexStr(
358*e1fe3e4aSElliott Hughes                "0006 "  # format=6
359*e1fe3e4aSElliott Hughes                "0004 "  # binSrchHeader.unitSize=4
360*e1fe3e4aSElliott Hughes                "0004 "  # binSrchHeader.nUnits=4
361*e1fe3e4aSElliott Hughes                "0010 "  # binSrchHeader.searchRange=16
362*e1fe3e4aSElliott Hughes                "0002 "  # binSrchHeader.entrySelector=2
363*e1fe3e4aSElliott Hughes                "0000 "  # binSrchHeader.rangeShift=0
364*e1fe3e4aSElliott Hughes                "0001 0003 "  # entries[0].glyph=A, .value=C
365*e1fe3e4aSElliott Hughes                "0003 0002 "  # entries[1].glyph=C, .value=B
366*e1fe3e4aSElliott Hughes                "0004 0004 "  # entries[2].glyph=D, .value=D
367*e1fe3e4aSElliott Hughes                "0005 0005 "  # entries[3].glyph=E, .value=E
368*e1fe3e4aSElliott Hughes                "FFFF 0000 "  # entries[4]=<END>
369*e1fe3e4aSElliott Hughes            ),
370*e1fe3e4aSElliott Hughes        )
371*e1fe3e4aSElliott Hughes
372*e1fe3e4aSElliott Hughes    def test_writeFormat8(self):
373*e1fe3e4aSElliott Hughes        writer = OTTableWriter()
374*e1fe3e4aSElliott Hughes        font = FakeFont(".notdef A B C D E F G H".split())
375*e1fe3e4aSElliott Hughes        self.converter.write(
376*e1fe3e4aSElliott Hughes            writer,
377*e1fe3e4aSElliott Hughes            font,
378*e1fe3e4aSElliott Hughes            {},
379*e1fe3e4aSElliott Hughes            {
380*e1fe3e4aSElliott Hughes                "B": "B",
381*e1fe3e4aSElliott Hughes                "C": "A",
382*e1fe3e4aSElliott Hughes                "D": "B",
383*e1fe3e4aSElliott Hughes                "E": "C",
384*e1fe3e4aSElliott Hughes                "F": "B",
385*e1fe3e4aSElliott Hughes                "G": "A",
386*e1fe3e4aSElliott Hughes            },
387*e1fe3e4aSElliott Hughes        )
388*e1fe3e4aSElliott Hughes        self.assertEqual(
389*e1fe3e4aSElliott Hughes            writer.getData(),
390*e1fe3e4aSElliott Hughes            deHexStr(
391*e1fe3e4aSElliott Hughes                "0008 "  # format=8
392*e1fe3e4aSElliott Hughes                "0002 "  # firstGlyph=B
393*e1fe3e4aSElliott Hughes                "0006 "  # glyphCount=6
394*e1fe3e4aSElliott Hughes                "0002 0001 0002 0003 0002 0001"  # valueArray=[B, A, B, C, B, A]
395*e1fe3e4aSElliott Hughes            ),
396*e1fe3e4aSElliott Hughes        )
397*e1fe3e4aSElliott Hughes
398*e1fe3e4aSElliott Hughes    def test_xmlRead(self):
399*e1fe3e4aSElliott Hughes        value = self.converter.xmlRead(
400*e1fe3e4aSElliott Hughes            {},
401*e1fe3e4aSElliott Hughes            [
402*e1fe3e4aSElliott Hughes                ("Lookup", {"glyph": "A", "value": "A.alt"}, []),
403*e1fe3e4aSElliott Hughes                ("Lookup", {"glyph": "B", "value": "B.alt"}, []),
404*e1fe3e4aSElliott Hughes            ],
405*e1fe3e4aSElliott Hughes            self.font,
406*e1fe3e4aSElliott Hughes        )
407*e1fe3e4aSElliott Hughes        self.assertEqual(value, {"A": "A.alt", "B": "B.alt"})
408*e1fe3e4aSElliott Hughes
409*e1fe3e4aSElliott Hughes    def test_xmlWrite(self):
410*e1fe3e4aSElliott Hughes        writer = makeXMLWriter()
411*e1fe3e4aSElliott Hughes        self.converter.xmlWrite(
412*e1fe3e4aSElliott Hughes            writer,
413*e1fe3e4aSElliott Hughes            self.font,
414*e1fe3e4aSElliott Hughes            value={"A": "A.alt", "B": "B.alt"},
415*e1fe3e4aSElliott Hughes            name="Foo",
416*e1fe3e4aSElliott Hughes            attrs=[("attr", "val")],
417*e1fe3e4aSElliott Hughes        )
418*e1fe3e4aSElliott Hughes        xml = writer.file.getvalue().decode("utf-8").splitlines()
419*e1fe3e4aSElliott Hughes        self.assertEqual(
420*e1fe3e4aSElliott Hughes            xml,
421*e1fe3e4aSElliott Hughes            [
422*e1fe3e4aSElliott Hughes                '<Foo attr="val">',
423*e1fe3e4aSElliott Hughes                '  <Lookup glyph="A" value="A.alt"/>',
424*e1fe3e4aSElliott Hughes                '  <Lookup glyph="B" value="B.alt"/>',
425*e1fe3e4aSElliott Hughes                "</Foo>",
426*e1fe3e4aSElliott Hughes            ],
427*e1fe3e4aSElliott Hughes        )
428*e1fe3e4aSElliott Hughes
429*e1fe3e4aSElliott Hughes
430*e1fe3e4aSElliott Hughesclass LazyListTest(unittest.TestCase):
431*e1fe3e4aSElliott Hughes    def test_slice(self):
432*e1fe3e4aSElliott Hughes        ll = otConverters._LazyList([10, 11, 12, 13])
433*e1fe3e4aSElliott Hughes        sl = ll[:]
434*e1fe3e4aSElliott Hughes
435*e1fe3e4aSElliott Hughes        self.assertIsNot(sl, ll)
436*e1fe3e4aSElliott Hughes        self.assertIsInstance(sl, list)
437*e1fe3e4aSElliott Hughes        self.assertEqual([10, 11, 12, 13], sl)
438*e1fe3e4aSElliott Hughes
439*e1fe3e4aSElliott Hughes        self.assertEqual([11, 12], ll[1:3])
440*e1fe3e4aSElliott Hughes
441*e1fe3e4aSElliott Hughes    def test_getitem(self):
442*e1fe3e4aSElliott Hughes        count = 2
443*e1fe3e4aSElliott Hughes        reader = OTTableReader(b"\x00\xFE\xFF\x00\x00\x00", offset=1)
444*e1fe3e4aSElliott Hughes        converter = otConverters.UInt8("UInt8", 0, None, None)
445*e1fe3e4aSElliott Hughes        recordSize = converter.staticSize
446*e1fe3e4aSElliott Hughes        l = otConverters._LazyList()
447*e1fe3e4aSElliott Hughes        l.reader = reader
448*e1fe3e4aSElliott Hughes        l.pos = l.reader.pos
449*e1fe3e4aSElliott Hughes        l.font = None
450*e1fe3e4aSElliott Hughes        l.conv = converter
451*e1fe3e4aSElliott Hughes        l.recordSize = recordSize
452*e1fe3e4aSElliott Hughes        l.extend(otConverters._MissingItem([i]) for i in range(count))
453*e1fe3e4aSElliott Hughes        reader.advance(count * recordSize)
454*e1fe3e4aSElliott Hughes
455*e1fe3e4aSElliott Hughes        self.assertEqual(l[0], 254)
456*e1fe3e4aSElliott Hughes        self.assertEqual(l[1], 255)
457*e1fe3e4aSElliott Hughes
458*e1fe3e4aSElliott Hughes    def test_add_both_LazyList(self):
459*e1fe3e4aSElliott Hughes        ll1 = otConverters._LazyList([1])
460*e1fe3e4aSElliott Hughes        ll2 = otConverters._LazyList([2])
461*e1fe3e4aSElliott Hughes
462*e1fe3e4aSElliott Hughes        l3 = ll1 + ll2
463*e1fe3e4aSElliott Hughes
464*e1fe3e4aSElliott Hughes        self.assertIsInstance(l3, list)
465*e1fe3e4aSElliott Hughes        self.assertEqual([1, 2], l3)
466*e1fe3e4aSElliott Hughes
467*e1fe3e4aSElliott Hughes    def test_add_LazyList_and_list(self):
468*e1fe3e4aSElliott Hughes        ll1 = otConverters._LazyList([1])
469*e1fe3e4aSElliott Hughes        l2 = [2]
470*e1fe3e4aSElliott Hughes
471*e1fe3e4aSElliott Hughes        l3 = ll1 + l2
472*e1fe3e4aSElliott Hughes
473*e1fe3e4aSElliott Hughes        self.assertIsInstance(l3, list)
474*e1fe3e4aSElliott Hughes        self.assertEqual([1, 2], l3)
475*e1fe3e4aSElliott Hughes
476*e1fe3e4aSElliott Hughes    def test_add_not_implemented(self):
477*e1fe3e4aSElliott Hughes        with self.assertRaises(TypeError):
478*e1fe3e4aSElliott Hughes            otConverters._LazyList() + 0
479*e1fe3e4aSElliott Hughes        with self.assertRaises(TypeError):
480*e1fe3e4aSElliott Hughes            otConverters._LazyList() + tuple()
481*e1fe3e4aSElliott Hughes
482*e1fe3e4aSElliott Hughes    def test_radd_list_and_LazyList(self):
483*e1fe3e4aSElliott Hughes        l1 = [1]
484*e1fe3e4aSElliott Hughes        ll2 = otConverters._LazyList([2])
485*e1fe3e4aSElliott Hughes
486*e1fe3e4aSElliott Hughes        l3 = l1 + ll2
487*e1fe3e4aSElliott Hughes
488*e1fe3e4aSElliott Hughes        self.assertIsInstance(l3, list)
489*e1fe3e4aSElliott Hughes        self.assertEqual([1, 2], l3)
490*e1fe3e4aSElliott Hughes
491*e1fe3e4aSElliott Hughes    def test_radd_not_implemented(self):
492*e1fe3e4aSElliott Hughes        with self.assertRaises(TypeError):
493*e1fe3e4aSElliott Hughes            0 + otConverters._LazyList()
494*e1fe3e4aSElliott Hughes        with self.assertRaises(TypeError):
495*e1fe3e4aSElliott Hughes            tuple() + otConverters._LazyList()
496*e1fe3e4aSElliott Hughes
497*e1fe3e4aSElliott Hughes
498*e1fe3e4aSElliott Hughesif __name__ == "__main__":
499*e1fe3e4aSElliott Hughes    import sys
500*e1fe3e4aSElliott Hughes
501*e1fe3e4aSElliott Hughes    sys.exit(unittest.main())
502