• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# -*- coding: utf-8 -*-
2from __future__ import absolute_import, unicode_literals
3import os
4import shutil
5import unittest
6import tempfile
7from io import open
8from fontTools.ufoLib import UFOReader, UFOWriter
9from fontTools.ufoLib import plistlib
10from .testSupport import expectedFontInfo1To2Conversion, expectedFontInfo2To1Conversion
11
12
13# the format version 1 lib.plist contains some data
14# that these tests shouldn't be concerned about.
15removeFromFormatVersion1Lib = [
16	"org.robofab.opentype.classes",
17	"org.robofab.opentype.features",
18	"org.robofab.opentype.featureorder",
19	"org.robofab.postScriptHintData"
20]
21
22
23class ConversionFunctionsTestCase(unittest.TestCase):
24
25	def tearDown(self):
26		path = self.getFontPath("TestFont1 (UFO1) converted.ufo")
27		if os.path.exists(path):
28			shutil.rmtree(path)
29		path = self.getFontPath("TestFont1 (UFO2) converted.ufo")
30		if os.path.exists(path):
31			shutil.rmtree(path)
32
33	def getFontPath(self, fileName):
34		testdata = os.path.join(os.path.dirname(__file__), "testdata")
35		return os.path.join(testdata, fileName)
36
37	def compareFileStructures(self, path1, path2, expectedInfoData, testFeatures):
38		# result
39		metainfoPath1 = os.path.join(path1, "metainfo.plist")
40		fontinfoPath1 = os.path.join(path1, "fontinfo.plist")
41		kerningPath1 = os.path.join(path1, "kerning.plist")
42		groupsPath1 = os.path.join(path1, "groups.plist")
43		libPath1 = os.path.join(path1, "lib.plist")
44		featuresPath1 = os.path.join(path1, "features.plist")
45		glyphsPath1 = os.path.join(path1, "glyphs")
46		glyphsPath1_contents = os.path.join(glyphsPath1, "contents.plist")
47		glyphsPath1_A = os.path.join(glyphsPath1, "A_.glif")
48		glyphsPath1_B = os.path.join(glyphsPath1, "B_.glif")
49		# expected result
50		metainfoPath2 = os.path.join(path2, "metainfo.plist")
51		fontinfoPath2 = os.path.join(path2, "fontinfo.plist")
52		kerningPath2 = os.path.join(path2, "kerning.plist")
53		groupsPath2 = os.path.join(path2, "groups.plist")
54		libPath2 = os.path.join(path2, "lib.plist")
55		featuresPath2 = os.path.join(path2, "features.plist")
56		glyphsPath2 = os.path.join(path2, "glyphs")
57		glyphsPath2_contents = os.path.join(glyphsPath2, "contents.plist")
58		glyphsPath2_A = os.path.join(glyphsPath2, "A_.glif")
59		glyphsPath2_B = os.path.join(glyphsPath2, "B_.glif")
60		# look for existence
61		self.assertEqual(os.path.exists(metainfoPath1), True)
62		self.assertEqual(os.path.exists(fontinfoPath1), True)
63		self.assertEqual(os.path.exists(kerningPath1), True)
64		self.assertEqual(os.path.exists(groupsPath1), True)
65		self.assertEqual(os.path.exists(libPath1), True)
66		self.assertEqual(os.path.exists(glyphsPath1), True)
67		self.assertEqual(os.path.exists(glyphsPath1_contents), True)
68		self.assertEqual(os.path.exists(glyphsPath1_A), True)
69		self.assertEqual(os.path.exists(glyphsPath1_B), True)
70		if testFeatures:
71			self.assertEqual(os.path.exists(featuresPath1), True)
72		# look for aggrement
73		with open(metainfoPath1, "rb") as f:
74			data1 = plistlib.load(f)
75		with open(metainfoPath2, "rb") as f:
76			data2 = plistlib.load(f)
77		self.assertEqual(data1, data2)
78		with open(fontinfoPath1, "rb") as f:
79			data1 = plistlib.load(f)
80		self.assertEqual(sorted(data1.items()), sorted(expectedInfoData.items()))
81		with open(kerningPath1, "rb") as f:
82			data1 = plistlib.load(f)
83		with open(kerningPath2, "rb") as f:
84			data2 = plistlib.load(f)
85		self.assertEqual(data1, data2)
86		with open(groupsPath1, "rb") as f:
87			data1 = plistlib.load(f)
88		with open(groupsPath2, "rb") as f:
89			data2 = plistlib.load(f)
90		self.assertEqual(data1, data2)
91		with open(libPath1, "rb") as f:
92			data1 = plistlib.load(f)
93		with open(libPath2, "rb") as f:
94			data2 = plistlib.load(f)
95		if "UFO1" in libPath1:
96			for key in removeFromFormatVersion1Lib:
97				if key in data1:
98					del data1[key]
99		if "UFO1" in libPath2:
100			for key in removeFromFormatVersion1Lib:
101				if key in data2:
102					del data2[key]
103		self.assertEqual(data1, data2)
104		with open(glyphsPath1_contents, "rb") as f:
105			data1 = plistlib.load(f)
106		with open(glyphsPath2_contents, "rb") as f:
107			data2 = plistlib.load(f)
108		self.assertEqual(data1, data2)
109		with open(glyphsPath1_A, "rb") as f:
110			data1 = plistlib.load(f)
111		with open(glyphsPath2_A, "rb") as f:
112			data2 = plistlib.load(f)
113		self.assertEqual(data1, data2)
114		with open(glyphsPath1_B, "rb") as f:
115			data1 = plistlib.load(f)
116		with open(glyphsPath2_B, "rb") as f:
117			data2 = plistlib.load(f)
118		self.assertEqual(data1, data2)
119
120
121# ---------------------
122# kerning up conversion
123# ---------------------
124
125class TestInfoObject(object): pass
126
127
128class KerningUpConversionTestCase(unittest.TestCase):
129
130	expectedKerning = {
131		("public.kern1.BGroup", "public.kern2.CGroup"): 7,
132		("public.kern1.BGroup", "public.kern2.DGroup"): 8,
133		("public.kern1.BGroup", "A"): 5,
134		("public.kern1.BGroup", "B"): 6,
135		("public.kern1.CGroup", "public.kern2.CGroup"): 11,
136		("public.kern1.CGroup", "public.kern2.DGroup"): 12,
137		("public.kern1.CGroup", "A"): 9,
138		("public.kern1.CGroup", "B"): 10,
139		("A", "public.kern2.CGroup"): 3,
140		("A", "public.kern2.DGroup"): 4,
141		("A", "A"): 1,
142		("A", "B"): 2
143	}
144
145	expectedGroups = {
146		"BGroup": ["B"],
147		"CGroup": ["C", "Ccedilla"],
148		"DGroup": ["D"],
149		"public.kern1.BGroup": ["B"],
150		"public.kern1.CGroup": ["C", "Ccedilla"],
151		"public.kern2.CGroup": ["C", "Ccedilla"],
152		"public.kern2.DGroup": ["D"],
153		"Not A Kerning Group" : ["A"]
154	}
155
156	def setUp(self):
157		self.tempDir = tempfile.mktemp()
158		os.mkdir(self.tempDir)
159		self.ufoPath = os.path.join(self.tempDir, "test.ufo")
160
161	def tearDown(self):
162		shutil.rmtree(self.tempDir)
163
164	def makeUFO(self, formatVersion):
165		self.clearUFO()
166		if not os.path.exists(self.ufoPath):
167			os.mkdir(self.ufoPath)
168		# metainfo.plist
169		metaInfo = dict(creator="test", formatVersion=formatVersion)
170		path = os.path.join(self.ufoPath, "metainfo.plist")
171		with open(path, "wb") as f:
172			plistlib.dump(metaInfo, f)
173		# kerning
174		kerning = {
175			"A" : {
176				"A" : 1,
177				"B" : 2,
178				"CGroup" : 3,
179				"DGroup" : 4
180			},
181			"BGroup" : {
182				"A" : 5,
183				"B" : 6,
184				"CGroup" : 7,
185				"DGroup" : 8
186			},
187			"CGroup" : {
188				"A" : 9,
189				"B" : 10,
190				"CGroup" : 11,
191				"DGroup" : 12
192			}
193		}
194		path = os.path.join(self.ufoPath, "kerning.plist")
195		with open(path, "wb") as f:
196			plistlib.dump(kerning, f)
197		# groups
198		groups = {
199			"BGroup" : ["B"],
200			"CGroup" : ["C", "Ccedilla"],
201			"DGroup" : ["D"],
202			"Not A Kerning Group" : ["A"]
203		}
204		path = os.path.join(self.ufoPath, "groups.plist")
205		with open(path, "wb") as f:
206			plistlib.dump(groups, f)
207		# font info
208		fontInfo = {
209			"familyName" : "Test"
210		}
211		path = os.path.join(self.ufoPath, "fontinfo.plist")
212		with open(path, "wb") as f:
213			plistlib.dump(fontInfo, f)
214
215	def clearUFO(self):
216		if os.path.exists(self.ufoPath):
217			shutil.rmtree(self.ufoPath)
218
219	def testUFO1(self):
220		self.makeUFO(formatVersion=2)
221		reader = UFOReader(self.ufoPath, validate=True)
222		kerning = reader.readKerning()
223		self.assertEqual(self.expectedKerning, kerning)
224		groups = reader.readGroups()
225		self.assertEqual(self.expectedGroups, groups)
226		info = TestInfoObject()
227		reader.readInfo(info)
228
229	def testUFO2(self):
230		self.makeUFO(formatVersion=2)
231		reader = UFOReader(self.ufoPath, validate=True)
232		kerning = reader.readKerning()
233		self.assertEqual(self.expectedKerning, kerning)
234		groups = reader.readGroups()
235		self.assertEqual(self.expectedGroups, groups)
236		info = TestInfoObject()
237		reader.readInfo(info)
238
239
240class KerningDownConversionTestCase(unittest.TestCase):
241
242	expectedKerning = {
243		("public.kern1.BGroup", "public.kern2.CGroup"): 7,
244		("public.kern1.BGroup", "public.kern2.DGroup"): 8,
245		("public.kern1.BGroup", "A"): 5,
246		("public.kern1.BGroup", "B"): 6,
247		("public.kern1.CGroup", "public.kern2.CGroup"): 11,
248		("public.kern1.CGroup", "public.kern2.DGroup"): 12,
249		("public.kern1.CGroup", "A"): 9,
250		("public.kern1.CGroup", "B"): 10,
251		("A", "public.kern2.CGroup"): 3,
252		("A", "public.kern2.DGroup"): 4,
253		("A", "A"): 1,
254		("A", "B"): 2
255	}
256
257	groups = {
258		"BGroup": ["B"],
259		"CGroup": ["C"],
260		"DGroup": ["D"],
261		"public.kern1.BGroup": ["B"],
262		"public.kern1.CGroup": ["C", "Ccedilla"],
263		"public.kern2.CGroup": ["C", "Ccedilla"],
264		"public.kern2.DGroup": ["D"],
265		"Not A Kerning Group" : ["A"]
266	}
267	expectedWrittenGroups = {
268		"BGroup": ["B"],
269		"CGroup": ["C", "Ccedilla"],
270		"DGroup": ["D"],
271		"Not A Kerning Group" : ["A"]
272	}
273
274	kerning = {
275		("public.kern1.BGroup", "public.kern2.CGroup"): 7,
276		("public.kern1.BGroup", "public.kern2.DGroup"): 8,
277		("public.kern1.BGroup", "A"): 5,
278		("public.kern1.BGroup", "B"): 6,
279		("public.kern1.CGroup", "public.kern2.CGroup"): 11,
280		("public.kern1.CGroup", "public.kern2.DGroup"): 12,
281		("public.kern1.CGroup", "A"): 9,
282		("public.kern1.CGroup", "B"): 10,
283		("A", "public.kern2.CGroup"): 3,
284		("A", "public.kern2.DGroup"): 4,
285		("A", "A"): 1,
286		("A", "B"): 2
287	}
288	expectedWrittenKerning = {
289		"BGroup" : {
290			"CGroup" : 7,
291			"DGroup" : 8,
292			"A" : 5,
293			"B" : 6
294		},
295		"CGroup" : {
296			"CGroup" : 11,
297			"DGroup" : 12,
298			"A" : 9,
299			"B" : 10
300		},
301		"A" : {
302			"CGroup" : 3,
303			"DGroup" : 4,
304			"A" : 1,
305			"B" : 2
306		}
307	}
308
309
310	downConversionMapping = {
311		"side1" : {
312			"BGroup" : "public.kern1.BGroup",
313			"CGroup" : "public.kern1.CGroup"
314		},
315		"side2" : {
316			"CGroup" : "public.kern2.CGroup",
317			"DGroup" : "public.kern2.DGroup"
318		}
319	}
320
321	def setUp(self):
322		self.tempDir = tempfile.mktemp()
323		os.mkdir(self.tempDir)
324		self.dstDir = os.path.join(self.tempDir, "test.ufo")
325
326	def tearDown(self):
327		shutil.rmtree(self.tempDir)
328
329	def tearDownUFO(self):
330		shutil.rmtree(self.dstDir)
331
332	def testWrite(self):
333		writer = UFOWriter(self.dstDir, formatVersion=2)
334		writer.setKerningGroupConversionRenameMaps(self.downConversionMapping)
335		writer.writeKerning(self.kerning)
336		writer.writeGroups(self.groups)
337		# test groups
338		path = os.path.join(self.dstDir, "groups.plist")
339		with open(path, "rb") as f:
340			writtenGroups = plistlib.load(f)
341		self.assertEqual(writtenGroups, self.expectedWrittenGroups)
342		# test kerning
343		path = os.path.join(self.dstDir, "kerning.plist")
344		with open(path, "rb") as f:
345			writtenKerning = plistlib.load(f)
346		self.assertEqual(writtenKerning, self.expectedWrittenKerning)
347		self.tearDownUFO()
348