1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
|
from io import BytesIO
import os
import unittest
from fontTools.ttLib import TTFont
from fontTools.misc.textTools import strjoin
from fontTools.misc.xmlReader import XMLReader, ProgressPrinter, BUFSIZE
import tempfile
class TestXMLReader(unittest.TestCase):
def test_decode_utf8(self):
class DebugXMLReader(XMLReader):
def __init__(self, fileOrPath, ttFont, progress=None):
super(DebugXMLReader, self).__init__(fileOrPath, ttFont, progress)
self.contents = []
def _endElementHandler(self, name):
if self.stackSize == 3:
name, attrs, content = self.root
self.contents.append(content)
super(DebugXMLReader, self)._endElementHandler(name)
expected = "fôôbär"
data = (
"""\
<?xml version="1.0" encoding="UTF-8"?>
<ttFont>
<name>
<namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
%s
</namerecord>
</name>
</ttFont>
"""
% expected
)
with BytesIO(data.encode("utf-8")) as tmp:
reader = DebugXMLReader(tmp, TTFont())
reader.read()
content = strjoin(reader.contents[0]).strip()
self.assertEqual(expected, content)
def test_normalise_newlines(self):
class DebugXMLReader(XMLReader):
def __init__(self, fileOrPath, ttFont, progress=None):
super(DebugXMLReader, self).__init__(fileOrPath, ttFont, progress)
self.newlines = []
def _characterDataHandler(self, data):
self.newlines.extend([c for c in data if c in ("\r", "\n")])
# notice how when CR is escaped, it is not normalised by the XML parser
data = (
"<ttFont>\r" # \r -> \n
" <test>\r\n" # \r\n -> \n
" a line of text\n" # \n
" escaped CR and unix newline \n" # \n -> \r\n
" escaped CR and macintosh newline \r" # \r -> \r\n
" escaped CR and windows newline \r\n" # \r\n -> \r\n
" </test>\n" # \n
"</ttFont>"
)
with BytesIO(data.encode("utf-8")) as tmp:
reader = DebugXMLReader(tmp, TTFont())
reader.read()
expected = ["\n"] * 3 + ["\r", "\n"] * 3 + ["\n"]
self.assertEqual(expected, reader.newlines)
def test_progress(self):
class DummyProgressPrinter(ProgressPrinter):
def __init__(self, title, maxval=100):
self.label = title
self.maxval = maxval
self.pos = 0
def set(self, val, maxval=None):
if maxval is not None:
self.maxval = maxval
self.pos = val
def increment(self, val=1):
self.pos += val
def setLabel(self, text):
self.label = text
data = (
"<ttFont>\n"
" <test>\n"
" %s\n"
" </test>\n"
"</ttFont>\n" % ("z" * 2 * BUFSIZE)
).encode("utf-8")
dataSize = len(data)
progressBar = DummyProgressPrinter("test")
with BytesIO(data) as tmp:
reader = XMLReader(tmp, TTFont(), progress=progressBar)
self.assertEqual(progressBar.pos, 0)
reader.read()
self.assertEqual(progressBar.pos, dataSize // 100)
self.assertEqual(progressBar.maxval, dataSize // 100)
self.assertTrue("test" in progressBar.label)
with BytesIO(b"<ttFont></ttFont>") as tmp:
reader = XMLReader(tmp, TTFont(), progress=progressBar)
reader.read()
# when data size is less than 100 bytes, 'maxval' is 1
self.assertEqual(progressBar.maxval, 1)
def test_close_file_path(self):
with tempfile.NamedTemporaryFile(delete=False) as tmp:
tmp.write(b"<ttFont></ttFont>")
reader = XMLReader(tmp.name, TTFont())
reader.read()
# when reading from path, the file is closed automatically at the end
self.assertTrue(reader.file.closed)
# this does nothing
reader.close()
self.assertTrue(reader.file.closed)
os.remove(tmp.name)
def test_close_file_obj(self):
with tempfile.NamedTemporaryFile(delete=False) as tmp:
tmp.write(b'<ttFont>"hello"</ttFont>')
with open(tmp.name, "rb") as f:
reader = XMLReader(f, TTFont())
reader.read()
# when reading from a file or file-like object, the latter is kept open
self.assertFalse(reader.file.closed)
# ... until the user explicitly closes it
reader.close()
self.assertTrue(reader.file.closed)
os.remove(tmp.name)
def test_read_sub_file(self):
# Verifies that sub-file content is able to be read to a table.
expectedContent = "testContent"
expectedNameID = "1"
expectedPlatform = "3"
expectedLangId = "0x409"
with tempfile.NamedTemporaryFile(delete=False) as tmp:
subFileData = (
'<ttFont ttLibVersion="3.15">'
"<name>"
'<namerecord nameID="%s" platformID="%s" platEncID="1" langID="%s">'
"%s"
"</namerecord>"
"</name>"
"</ttFont>"
) % (expectedNameID, expectedPlatform, expectedLangId, expectedContent)
tmp.write(subFileData.encode("utf-8"))
with tempfile.NamedTemporaryFile(delete=False) as tmp2:
fileData = (
'<ttFont ttLibVersion="3.15">'
"<name>"
'<namerecord src="%s"/>'
"</name>"
"</ttFont>"
) % tmp.name
tmp2.write(fileData.encode("utf-8"))
ttf = TTFont()
with open(tmp2.name, "rb") as f:
reader = XMLReader(f, ttf)
reader.read()
reader.close()
nameTable = ttf["name"]
self.assertTrue(int(expectedNameID) == nameTable.names[0].nameID)
self.assertTrue(int(expectedLangId, 16) == nameTable.names[0].langID)
self.assertTrue(int(expectedPlatform) == nameTable.names[0].platformID)
self.assertEqual(
expectedContent,
nameTable.names[0].string.decode(nameTable.names[0].getEncoding()),
)
os.remove(tmp.name)
os.remove(tmp2.name)
if __name__ == "__main__":
import sys
sys.exit(unittest.main())
|