aboutsummaryrefslogtreecommitdiff
path: root/Tests/misc/xmlReader_test.py
blob: ec4aff57820b572cb1e5115161645e54b5b33745 (plain)
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
188
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 &#13;\n'       #   &#13;\n -> \r\n
			'    escaped CR and macintosh newline &#13;\r'  #   &#13;\r -> \r\n
			'    escaped CR and windows newline &#13;\r\n'  # &#13;\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())