aboutsummaryrefslogtreecommitdiff
path: root/Tests/t1Lib/t1Lib_test.py
blob: 3e639a5828c7ee544643f1788f96483c94a6d408 (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
189
190
191
192
193
194
195
196
197
198
199
200
201
import unittest
import os
import sys
from fontTools import t1Lib
from fontTools.pens.basePen import NullPen
from fontTools.misc.psCharStrings import T1CharString
import random


CWD = os.path.abspath(os.path.dirname(__file__))
DATADIR = os.path.join(CWD, 'data')
# I used `tx` to convert PFA to LWFN (stored in the data fork)
LWFN = os.path.join(DATADIR, 'TestT1-Regular.lwfn')
PFA = os.path.join(DATADIR, 'TestT1-Regular.pfa')
PFB = os.path.join(DATADIR, 'TestT1-Regular.pfb')
WEIRD_ZEROS = os.path.join(DATADIR, 'TestT1-weird-zeros.pfa')
# ellipsis is hinted with 55 131 296 131 537 131 vstem3 0 122 hstem
ELLIPSIS_HINTED = os.path.join(DATADIR, 'TestT1-ellipsis-hinted.pfa')


class FindEncryptedChunksTest(unittest.TestCase):

	def test_findEncryptedChunks(self):
		with open(PFA, "rb") as f:
			data = f.read()
		chunks = t1Lib.findEncryptedChunks(data)
		self.assertEqual(len(chunks), 3)
		self.assertFalse(chunks[0][0])
		# the second chunk is encrypted
		self.assertTrue(chunks[1][0])
		self.assertFalse(chunks[2][0])

	def test_findEncryptedChunks_weird_zeros(self):
		with open(WEIRD_ZEROS, 'rb') as f:
			data = f.read()

		# Just assert that this doesn't raise any exception for not finding the
		# end of eexec
		t1Lib.findEncryptedChunks(data)


class DecryptType1Test(unittest.TestCase):

	def test_decryptType1(self):
		with open(PFA, "rb") as f:
			data = f.read()
		decrypted = t1Lib.decryptType1(data)
		self.assertNotEqual(decrypted, data)


class ReadWriteTest(unittest.TestCase):

	def test_read_pfa_write_pfb(self):
		font = t1Lib.T1Font(PFA)
		data = self.write(font, 'PFB')
		self.assertEqual(font.getData(), data)

	def test_read_and_parse_pfa_write_pfb(self):
		font = t1Lib.T1Font(PFA)
		font.parse()
		saved_font = self.write(font, 'PFB', dohex=False, doparse=True)
		self.assertTrue(same_dicts(font.font, saved_font))

	def test_read_pfb_write_pfa(self):
		font = t1Lib.T1Font(PFB)
		# 'OTHER' == 'PFA'
		data = self.write(font, 'OTHER', dohex=True)
		self.assertEqual(font.getData(), data)

	def test_read_and_parse_pfb_write_pfa(self):
		font = t1Lib.T1Font(PFB)
		font.parse()
		# 'OTHER' == 'PFA'
		saved_font = self.write(font, 'OTHER', dohex=True, doparse=True)
		self.assertTrue(same_dicts(font.font, saved_font))

	def test_read_with_path(self):
		import pathlib
		font = t1Lib.T1Font(pathlib.Path(PFB))

	@staticmethod
	def write(font, outtype, dohex=False, doparse=False):
		temp = os.path.join(DATADIR, 'temp.' + outtype.lower())
		try:
			font.saveAs(temp, outtype, dohex=dohex)
			newfont = t1Lib.T1Font(temp)
			if doparse:
				newfont.parse()
				data = newfont.font
			else:
				data = newfont.getData()
		finally:
			if os.path.exists(temp):
				os.remove(temp)
		return data


class T1FontTest(unittest.TestCase):

	def test_parse_lwfn(self):
		# the extended attrs are lost on git so we can't auto-detect 'LWFN'
		font = t1Lib.T1Font(LWFN, kind="LWFN")
		font.parse()
		self.assertEqual(font['FontName'], 'TestT1-Regular')
		self.assertTrue('Subrs' in font['Private'])

	def test_parse_pfa(self):
		font = t1Lib.T1Font(PFA)
		font.parse()
		self.assertEqual(font['FontName'], 'TestT1-Regular')
		self.assertTrue('Subrs' in font['Private'])

	def test_parse_pfb(self):
		font = t1Lib.T1Font(PFB)
		font.parse()
		self.assertEqual(font['FontName'], 'TestT1-Regular')
		self.assertTrue('Subrs' in font['Private'])

	def test_getGlyphSet(self):
		font = t1Lib.T1Font(PFA)
		glyphs = font.getGlyphSet()
		i = random.randrange(len(glyphs))
		aglyph = list(glyphs.values())[i]
		self.assertTrue(hasattr(aglyph, 'draw'))
		self.assertFalse(hasattr(aglyph, 'width'))
		aglyph.draw(NullPen())
		self.assertTrue(hasattr(aglyph, 'width'))


class EditTest(unittest.TestCase):

	def test_edit_pfa(self):
		font = t1Lib.T1Font(PFA)
		ellipsis = font.getGlyphSet()["ellipsis"]
		ellipsis.decompile()
		program = []
		for v in ellipsis.program:
			try:
				program.append(int(v))
			except:
				program.append(v)
				if v == 'hsbw':
					hints = [55, 131, 296, 131, 537, 131, 'vstem3', 0, 122, 'hstem']
					program.extend(hints)
		ellipsis.program = program
		# 'OTHER' == 'PFA'
		saved_font = self.write(font, 'OTHER', dohex=True, doparse=True)
		hinted_font = t1Lib.T1Font(ELLIPSIS_HINTED)
		hinted_font.parse()
		self.assertTrue(same_dicts(hinted_font.font, saved_font))

	@staticmethod
	def write(font, outtype, dohex=False, doparse=False):
		temp = os.path.join(DATADIR, 'temp.' + outtype.lower())
		try:
			font.saveAs(temp, outtype, dohex=dohex)
			newfont = t1Lib.T1Font(temp)
			if doparse:
				newfont.parse()
				data = newfont.font
			else:
				data = newfont.getData()
		finally:
			if os.path.exists(temp):
				os.remove(temp)
		return data


def same_dicts(dict1, dict2):
	if dict1.keys() != dict2.keys():
		return False
	for key, value in dict1.items():
		if isinstance(value, dict):
			if not same_dicts(value, dict2[key]):
				return False
		elif isinstance(value, list):
			if len(value) != len(dict2[key]):
				return False
			for elem1, elem2 in zip(value, dict2[key]):
				if isinstance(elem1, T1CharString):
					elem1.compile()
					elem2.compile()
					if elem1.bytecode != elem2.bytecode:
						return False
				else:
					if elem1 != elem2:
						return False
		elif isinstance(value, T1CharString):
			value.compile()
			dict2[key].compile()
			if value.bytecode != dict2[key].bytecode:
				return False
		else:
			if value != dict2[key]:
				return False
	return True


if __name__ == '__main__':
	import sys
	sys.exit(unittest.main())