xref: /aosp_15_r20/external/fonttools/Tests/ufoLib/UFO3_test.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1import os
2import shutil
3import unittest
4import tempfile
5from io import open
6from fontTools.ufoLib import UFOReader, UFOWriter, UFOLibError
7from fontTools.ufoLib.glifLib import GlifLibError
8from fontTools.misc import plistlib
9from .testSupport import fontInfoVersion3
10
11
12class TestInfoObject:
13    pass
14
15
16# --------------
17# fontinfo.plist
18# --------------
19
20
21class ReadFontInfoVersion3TestCase(unittest.TestCase):
22    def setUp(self):
23        self.dstDir = tempfile.mktemp()
24        os.mkdir(self.dstDir)
25        metaInfo = {"creator": "test", "formatVersion": 3}
26        path = os.path.join(self.dstDir, "metainfo.plist")
27        with open(path, "wb") as f:
28            plistlib.dump(metaInfo, f)
29
30    def tearDown(self):
31        shutil.rmtree(self.dstDir)
32
33    def _writeInfoToPlist(self, info):
34        path = os.path.join(self.dstDir, "fontinfo.plist")
35        with open(path, "wb") as f:
36            plistlib.dump(info, f)
37
38    def testRead(self):
39        originalData = dict(fontInfoVersion3)
40        self._writeInfoToPlist(originalData)
41        infoObject = TestInfoObject()
42        reader = UFOReader(self.dstDir, validate=True)
43        reader.readInfo(infoObject)
44        readData = {}
45        for attr in list(fontInfoVersion3.keys()):
46            readData[attr] = getattr(infoObject, attr)
47        self.assertEqual(originalData, readData)
48
49    def testGenericRead(self):
50        # familyName
51        info = dict(fontInfoVersion3)
52        info["familyName"] = 123
53        self._writeInfoToPlist(info)
54        reader = UFOReader(self.dstDir, validate=True)
55        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
56        # styleName
57        info = dict(fontInfoVersion3)
58        info["styleName"] = 123
59        self._writeInfoToPlist(info)
60        reader = UFOReader(self.dstDir, validate=True)
61        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
62        # styleMapFamilyName
63        info = dict(fontInfoVersion3)
64        info["styleMapFamilyName"] = 123
65        self._writeInfoToPlist(info)
66        reader = UFOReader(self.dstDir, validate=True)
67        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
68        # styleMapStyleName
69        ## not a string
70        info = dict(fontInfoVersion3)
71        info["styleMapStyleName"] = 123
72        self._writeInfoToPlist(info)
73        reader = UFOReader(self.dstDir, validate=True)
74        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
75        ## out of range
76        info = dict(fontInfoVersion3)
77        info["styleMapStyleName"] = "REGULAR"
78        self._writeInfoToPlist(info)
79        reader = UFOReader(self.dstDir, validate=True)
80        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
81        # versionMajor
82        info = dict(fontInfoVersion3)
83        info["versionMajor"] = "1"
84        self._writeInfoToPlist(info)
85        reader = UFOReader(self.dstDir, validate=True)
86        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
87        # versionMinor
88        info = dict(fontInfoVersion3)
89        info["versionMinor"] = "0"
90        self._writeInfoToPlist(info)
91        reader = UFOReader(self.dstDir, validate=True)
92        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
93        info = dict(fontInfoVersion3)
94        info["versionMinor"] = -1
95        self._writeInfoToPlist(info)
96        reader = UFOReader(self.dstDir, validate=True)
97        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
98        # copyright
99        info = dict(fontInfoVersion3)
100        info["copyright"] = 123
101        self._writeInfoToPlist(info)
102        reader = UFOReader(self.dstDir, validate=True)
103        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
104        # trademark
105        info = dict(fontInfoVersion3)
106        info["trademark"] = 123
107        self._writeInfoToPlist(info)
108        reader = UFOReader(self.dstDir, validate=True)
109        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
110        # unitsPerEm
111        info = dict(fontInfoVersion3)
112        info["unitsPerEm"] = "abc"
113        self._writeInfoToPlist(info)
114        reader = UFOReader(self.dstDir, validate=True)
115        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
116        info = dict(fontInfoVersion3)
117        info["unitsPerEm"] = -1
118        self._writeInfoToPlist(info)
119        reader = UFOReader(self.dstDir, validate=True)
120        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
121        info = dict(fontInfoVersion3)
122        info["unitsPerEm"] = -1.0
123        self._writeInfoToPlist(info)
124        reader = UFOReader(self.dstDir, validate=True)
125        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
126        # descender
127        info = dict(fontInfoVersion3)
128        info["descender"] = "abc"
129        self._writeInfoToPlist(info)
130        reader = UFOReader(self.dstDir, validate=True)
131        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
132        # xHeight
133        info = dict(fontInfoVersion3)
134        info["xHeight"] = "abc"
135        self._writeInfoToPlist(info)
136        reader = UFOReader(self.dstDir, validate=True)
137        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
138        # capHeight
139        info = dict(fontInfoVersion3)
140        info["capHeight"] = "abc"
141        self._writeInfoToPlist(info)
142        reader = UFOReader(self.dstDir, validate=True)
143        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
144        # ascender
145        info = dict(fontInfoVersion3)
146        info["ascender"] = "abc"
147        self._writeInfoToPlist(info)
148        reader = UFOReader(self.dstDir, validate=True)
149        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
150        # italicAngle
151        info = dict(fontInfoVersion3)
152        info["italicAngle"] = "abc"
153        self._writeInfoToPlist(info)
154        reader = UFOReader(self.dstDir, validate=True)
155        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
156
157    def testGaspRead(self):
158        # not a list
159        info = dict(fontInfoVersion3)
160        info["openTypeGaspRangeRecords"] = "abc"
161        self._writeInfoToPlist(info)
162        reader = UFOReader(self.dstDir, validate=True)
163        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
164        # empty list
165        info = dict(fontInfoVersion3)
166        info["openTypeGaspRangeRecords"] = []
167        self._writeInfoToPlist(info)
168        reader = UFOReader(self.dstDir, validate=True)
169        reader.readInfo(TestInfoObject())
170        # not a dict
171        info = dict(fontInfoVersion3)
172        info["openTypeGaspRangeRecords"] = ["abc"]
173        self._writeInfoToPlist(info)
174        reader = UFOReader(self.dstDir, validate=True)
175        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
176        # dict not properly formatted
177        info = dict(fontInfoVersion3)
178        info["openTypeGaspRangeRecords"] = [dict(rangeMaxPPEM=0xFFFF, notTheRightKey=1)]
179        self._writeInfoToPlist(info)
180        reader = UFOReader(self.dstDir, validate=True)
181        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
182        info = dict(fontInfoVersion3)
183        info["openTypeGaspRangeRecords"] = [
184            dict(notTheRightKey=1, rangeGaspBehavior=[0])
185        ]
186        self._writeInfoToPlist(info)
187        reader = UFOReader(self.dstDir, validate=True)
188        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
189        # not an int for ppem
190        info = dict(fontInfoVersion3)
191        info["openTypeGaspRangeRecords"] = [
192            dict(rangeMaxPPEM="abc", rangeGaspBehavior=[0]),
193            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
194        ]
195        self._writeInfoToPlist(info)
196        reader = UFOReader(self.dstDir, validate=True)
197        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
198        # not a list for behavior
199        info = dict(fontInfoVersion3)
200        info["openTypeGaspRangeRecords"] = [
201            dict(rangeMaxPPEM=10, rangeGaspBehavior="abc"),
202            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
203        ]
204        self._writeInfoToPlist(info)
205        reader = UFOReader(self.dstDir, validate=True)
206        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
207        # invalid behavior value
208        info = dict(fontInfoVersion3)
209        info["openTypeGaspRangeRecords"] = [
210            dict(rangeMaxPPEM=10, rangeGaspBehavior=[-1]),
211            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
212        ]
213        self._writeInfoToPlist(info)
214        reader = UFOReader(self.dstDir, validate=True)
215        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
216        # not sorted
217        info = dict(fontInfoVersion3)
218        info["openTypeGaspRangeRecords"] = [
219            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
220            dict(rangeMaxPPEM=10, rangeGaspBehavior=[0]),
221        ]
222        self._writeInfoToPlist(info)
223        reader = UFOReader(self.dstDir, validate=True)
224        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
225        # no 0xFFFF
226        info = dict(fontInfoVersion3)
227        info["openTypeGaspRangeRecords"] = [
228            dict(rangeMaxPPEM=10, rangeGaspBehavior=[0]),
229            dict(rangeMaxPPEM=20, rangeGaspBehavior=[0]),
230        ]
231        self._writeInfoToPlist(info)
232        reader = UFOReader(self.dstDir, validate=True)
233        reader.readInfo(TestInfoObject())
234
235    def testHeadRead(self):
236        # openTypeHeadCreated
237        ## not a string
238        info = dict(fontInfoVersion3)
239        info["openTypeHeadCreated"] = 123
240        self._writeInfoToPlist(info)
241        reader = UFOReader(self.dstDir, validate=True)
242        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
243        ## invalid format
244        info = dict(fontInfoVersion3)
245        info["openTypeHeadCreated"] = "2000-Jan-01 00:00:00"
246        self._writeInfoToPlist(info)
247        reader = UFOReader(self.dstDir, validate=True)
248        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
249        # openTypeHeadLowestRecPPEM
250        info = dict(fontInfoVersion3)
251        info["openTypeHeadLowestRecPPEM"] = "abc"
252        self._writeInfoToPlist(info)
253        reader = UFOReader(self.dstDir, validate=True)
254        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
255        info = dict(fontInfoVersion3)
256        info["openTypeHeadLowestRecPPEM"] = -1
257        self._writeInfoToPlist(info)
258        reader = UFOReader(self.dstDir, validate=True)
259        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
260        # openTypeHeadFlags
261        info = dict(fontInfoVersion3)
262        info["openTypeHeadFlags"] = [-1]
263        self._writeInfoToPlist(info)
264        reader = UFOReader(self.dstDir, validate=True)
265        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
266
267    def testHheaRead(self):
268        # openTypeHheaAscender
269        info = dict(fontInfoVersion3)
270        info["openTypeHheaAscender"] = "abc"
271        self._writeInfoToPlist(info)
272        reader = UFOReader(self.dstDir, validate=True)
273        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
274        # openTypeHheaDescender
275        info = dict(fontInfoVersion3)
276        info["openTypeHheaDescender"] = "abc"
277        self._writeInfoToPlist(info)
278        reader = UFOReader(self.dstDir, validate=True)
279        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
280        # openTypeHheaLineGap
281        info = dict(fontInfoVersion3)
282        info["openTypeHheaLineGap"] = "abc"
283        self._writeInfoToPlist(info)
284        reader = UFOReader(self.dstDir, validate=True)
285        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
286        # openTypeHheaCaretSlopeRise
287        info = dict(fontInfoVersion3)
288        info["openTypeHheaCaretSlopeRise"] = "abc"
289        self._writeInfoToPlist(info)
290        reader = UFOReader(self.dstDir, validate=True)
291        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
292        # openTypeHheaCaretSlopeRun
293        info = dict(fontInfoVersion3)
294        info["openTypeHheaCaretSlopeRun"] = "abc"
295        self._writeInfoToPlist(info)
296        reader = UFOReader(self.dstDir, validate=True)
297        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
298        # openTypeHheaCaretOffset
299        info = dict(fontInfoVersion3)
300        info["openTypeHheaCaretOffset"] = "abc"
301        self._writeInfoToPlist(info)
302        reader = UFOReader(self.dstDir, validate=True)
303        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
304
305    def testNameRead(self):
306        # openTypeNameDesigner
307        info = dict(fontInfoVersion3)
308        info["openTypeNameDesigner"] = 123
309        self._writeInfoToPlist(info)
310        reader = UFOReader(self.dstDir, validate=True)
311        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
312        # openTypeNameDesignerURL
313        info = dict(fontInfoVersion3)
314        info["openTypeNameDesignerURL"] = 123
315        self._writeInfoToPlist(info)
316        reader = UFOReader(self.dstDir, validate=True)
317        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
318        # openTypeNameManufacturer
319        info = dict(fontInfoVersion3)
320        info["openTypeNameManufacturer"] = 123
321        self._writeInfoToPlist(info)
322        reader = UFOReader(self.dstDir, validate=True)
323        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
324        # openTypeNameManufacturerURL
325        info = dict(fontInfoVersion3)
326        info["openTypeNameManufacturerURL"] = 123
327        self._writeInfoToPlist(info)
328        reader = UFOReader(self.dstDir, validate=True)
329        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
330        # openTypeNameLicense
331        info = dict(fontInfoVersion3)
332        info["openTypeNameLicense"] = 123
333        self._writeInfoToPlist(info)
334        reader = UFOReader(self.dstDir, validate=True)
335        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
336        # openTypeNameLicenseURL
337        info = dict(fontInfoVersion3)
338        info["openTypeNameLicenseURL"] = 123
339        self._writeInfoToPlist(info)
340        reader = UFOReader(self.dstDir, validate=True)
341        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
342        # openTypeNameVersion
343        info = dict(fontInfoVersion3)
344        info["openTypeNameVersion"] = 123
345        self._writeInfoToPlist(info)
346        reader = UFOReader(self.dstDir, validate=True)
347        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
348        # openTypeNameUniqueID
349        info = dict(fontInfoVersion3)
350        info["openTypeNameUniqueID"] = 123
351        self._writeInfoToPlist(info)
352        reader = UFOReader(self.dstDir, validate=True)
353        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
354        # openTypeNameDescription
355        info = dict(fontInfoVersion3)
356        info["openTypeNameDescription"] = 123
357        self._writeInfoToPlist(info)
358        reader = UFOReader(self.dstDir, validate=True)
359        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
360        # openTypeNamePreferredFamilyName
361        info = dict(fontInfoVersion3)
362        info["openTypeNamePreferredFamilyName"] = 123
363        self._writeInfoToPlist(info)
364        reader = UFOReader(self.dstDir, validate=True)
365        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
366        # openTypeNamePreferredSubfamilyName
367        info = dict(fontInfoVersion3)
368        info["openTypeNamePreferredSubfamilyName"] = 123
369        self._writeInfoToPlist(info)
370        reader = UFOReader(self.dstDir, validate=True)
371        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
372        # openTypeNameCompatibleFullName
373        info = dict(fontInfoVersion3)
374        info["openTypeNameCompatibleFullName"] = 123
375        self._writeInfoToPlist(info)
376        reader = UFOReader(self.dstDir, validate=True)
377        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
378        # openTypeNameSampleText
379        info = dict(fontInfoVersion3)
380        info["openTypeNameSampleText"] = 123
381        self._writeInfoToPlist(info)
382        reader = UFOReader(self.dstDir, validate=True)
383        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
384        # openTypeNameWWSFamilyName
385        info = dict(fontInfoVersion3)
386        info["openTypeNameWWSFamilyName"] = 123
387        self._writeInfoToPlist(info)
388        reader = UFOReader(self.dstDir, validate=True)
389        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
390        # openTypeNameWWSSubfamilyName
391        info = dict(fontInfoVersion3)
392        info["openTypeNameWWSSubfamilyName"] = 123
393        self._writeInfoToPlist(info)
394        reader = UFOReader(self.dstDir, validate=True)
395        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
396        # openTypeNameRecords
397        ## not a list
398        info = dict(fontInfoVersion3)
399        info["openTypeNameRecords"] = "abc"
400        self._writeInfoToPlist(info)
401        reader = UFOReader(self.dstDir, validate=True)
402        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
403        ## not a dict
404        info = dict(fontInfoVersion3)
405        info["openTypeNameRecords"] = ["abc"]
406        self._writeInfoToPlist(info)
407        reader = UFOReader(self.dstDir, validate=True)
408        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
409        ## invalid dict structure
410        info = dict(fontInfoVersion3)
411        info["openTypeNameRecords"] = [dict(foo="bar")]
412        self._writeInfoToPlist(info)
413        reader = UFOReader(self.dstDir, validate=True)
414        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
415        ## incorrect keys
416        info = dict(fontInfoVersion3)
417        info["openTypeNameRecords"] = [
418            dict(
419                nameID=1,
420                platformID=1,
421                encodingID=1,
422                languageID=1,
423                string="Name Record.",
424                foo="bar",
425            )
426        ]
427        self._writeInfoToPlist(info)
428        reader = UFOReader(self.dstDir, validate=True)
429        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
430        info = dict(fontInfoVersion3)
431        info["openTypeNameRecords"] = [
432            dict(platformID=1, encodingID=1, languageID=1, string="Name Record.")
433        ]
434        self._writeInfoToPlist(info)
435        reader = UFOReader(self.dstDir, validate=True)
436        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
437        info = dict(fontInfoVersion3)
438        info["openTypeNameRecords"] = [
439            dict(nameID=1, encodingID=1, languageID=1, string="Name Record.")
440        ]
441        self._writeInfoToPlist(info)
442        reader = UFOReader(self.dstDir, validate=True)
443        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
444        info = dict(fontInfoVersion3)
445        info["openTypeNameRecords"] = [
446            dict(nameID=1, platformID=1, languageID=1, string="Name Record.")
447        ]
448        self._writeInfoToPlist(info)
449        reader = UFOReader(self.dstDir, validate=True)
450        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
451        info = dict(fontInfoVersion3)
452        info["openTypeNameRecords"] = [
453            dict(nameID=1, platformID=1, encodingID=1, string="Name Record.")
454        ]
455        self._writeInfoToPlist(info)
456        reader = UFOReader(self.dstDir, validate=True)
457        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
458        info = dict(fontInfoVersion3)
459        info["openTypeNameRecords"] = [
460            dict(nameID=1, platformID=1, encodingID=1, languageID=1)
461        ]
462        self._writeInfoToPlist(info)
463        reader = UFOReader(self.dstDir, validate=True)
464        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
465        ## invalid values
466        info = dict(fontInfoVersion3)
467        info["openTypeNameRecords"] = [
468            dict(
469                nameID="1",
470                platformID=1,
471                encodingID=1,
472                languageID=1,
473                string="Name Record.",
474            )
475        ]
476        self._writeInfoToPlist(info)
477        reader = UFOReader(self.dstDir, validate=True)
478        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
479        info = dict(fontInfoVersion3)
480        info["openTypeNameRecords"] = [
481            dict(
482                nameID=1,
483                platformID="1",
484                encodingID=1,
485                languageID=1,
486                string="Name Record.",
487            )
488        ]
489        self._writeInfoToPlist(info)
490        reader = UFOReader(self.dstDir, validate=True)
491        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
492        info = dict(fontInfoVersion3)
493        info["openTypeNameRecords"] = [
494            dict(
495                nameID=1,
496                platformID=1,
497                encodingID="1",
498                languageID=1,
499                string="Name Record.",
500            )
501        ]
502        self._writeInfoToPlist(info)
503        reader = UFOReader(self.dstDir, validate=True)
504        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
505        info = dict(fontInfoVersion3)
506        info["openTypeNameRecords"] = [
507            dict(
508                nameID=1,
509                platformID=1,
510                encodingID=1,
511                languageID="1",
512                string="Name Record.",
513            )
514        ]
515        self._writeInfoToPlist(info)
516        reader = UFOReader(self.dstDir, validate=True)
517        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
518        info = dict(fontInfoVersion3)
519        info["openTypeNameRecords"] = [
520            dict(nameID=1, platformID=1, encodingID=1, languageID=1, string=1)
521        ]
522        self._writeInfoToPlist(info)
523        reader = UFOReader(self.dstDir, validate=True)
524        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
525        ## duplicate
526        info = dict(fontInfoVersion3)
527        info["openTypeNameRecords"] = [
528            dict(
529                nameID=1,
530                platformID=1,
531                encodingID=1,
532                languageID=1,
533                string="Name Record.",
534            ),
535            dict(
536                nameID=1,
537                platformID=1,
538                encodingID=1,
539                languageID=1,
540                string="Name Record.",
541            ),
542        ]
543        self._writeInfoToPlist(info)
544        reader = UFOReader(self.dstDir, validate=True)
545        reader.readInfo(TestInfoObject())
546
547    def testOS2Read(self):
548        # openTypeOS2WidthClass
549        ## not an int
550        info = dict(fontInfoVersion3)
551        info["openTypeOS2WidthClass"] = "abc"
552        self._writeInfoToPlist(info)
553        reader = UFOReader(self.dstDir, validate=True)
554        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
555        ## out or range
556        info = dict(fontInfoVersion3)
557        info["openTypeOS2WidthClass"] = 15
558        self._writeInfoToPlist(info)
559        reader = UFOReader(self.dstDir, validate=True)
560        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
561        # openTypeOS2WeightClass
562        info = dict(fontInfoVersion3)
563        ## not an int
564        info["openTypeOS2WeightClass"] = "abc"
565        self._writeInfoToPlist(info)
566        reader = UFOReader(self.dstDir, validate=True)
567        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
568        ## out of range
569        info["openTypeOS2WeightClass"] = -50
570        self._writeInfoToPlist(info)
571        reader = UFOReader(self.dstDir, validate=True)
572        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
573        # openTypeOS2Selection
574        info = dict(fontInfoVersion3)
575        info["openTypeOS2Selection"] = [-1]
576        self._writeInfoToPlist(info)
577        reader = UFOReader(self.dstDir, validate=True)
578        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
579        # openTypeOS2VendorID
580        info = dict(fontInfoVersion3)
581        info["openTypeOS2VendorID"] = 1234
582        self._writeInfoToPlist(info)
583        reader = UFOReader(self.dstDir, validate=True)
584        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
585        # openTypeOS2Panose
586        ## not an int
587        info = dict(fontInfoVersion3)
588        info["openTypeOS2Panose"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, str(9)]
589        self._writeInfoToPlist(info)
590        reader = UFOReader(self.dstDir, validate=True)
591        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
592        ## negative
593        info = dict(fontInfoVersion3)
594        info["openTypeOS2Panose"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, -9]
595        self._writeInfoToPlist(info)
596        reader = UFOReader(self.dstDir, validate=True)
597        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
598        ## too few values
599        info = dict(fontInfoVersion3)
600        info["openTypeOS2Panose"] = [0, 1, 2, 3]
601        self._writeInfoToPlist(info)
602        reader = UFOReader(self.dstDir, validate=True)
603        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
604        ## too many values
605        info = dict(fontInfoVersion3)
606        info["openTypeOS2Panose"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
607        self._writeInfoToPlist(info)
608        reader = UFOReader(self.dstDir, validate=True)
609        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
610        # openTypeOS2FamilyClass
611        ## not an int
612        info = dict(fontInfoVersion3)
613        info["openTypeOS2FamilyClass"] = [1, str(1)]
614        self._writeInfoToPlist(info)
615        reader = UFOReader(self.dstDir, validate=True)
616        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
617        ## too few values
618        info = dict(fontInfoVersion3)
619        info["openTypeOS2FamilyClass"] = [1]
620        self._writeInfoToPlist(info)
621        reader = UFOReader(self.dstDir, validate=True)
622        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
623        ## too many values
624        info = dict(fontInfoVersion3)
625        info["openTypeOS2FamilyClass"] = [1, 1, 1]
626        self._writeInfoToPlist(info)
627        reader = UFOReader(self.dstDir, validate=True)
628        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
629        ## out of range
630        info = dict(fontInfoVersion3)
631        info["openTypeOS2FamilyClass"] = [1, 201]
632        self._writeInfoToPlist(info)
633        reader = UFOReader(self.dstDir, validate=True)
634        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
635        # openTypeOS2UnicodeRanges
636        ## not an int
637        info = dict(fontInfoVersion3)
638        info["openTypeOS2UnicodeRanges"] = ["0"]
639        self._writeInfoToPlist(info)
640        reader = UFOReader(self.dstDir, validate=True)
641        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
642        ## out of range
643        info = dict(fontInfoVersion3)
644        info["openTypeOS2UnicodeRanges"] = [-1]
645        self._writeInfoToPlist(info)
646        reader = UFOReader(self.dstDir, validate=True)
647        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
648        # openTypeOS2CodePageRanges
649        ## not an int
650        info = dict(fontInfoVersion3)
651        info["openTypeOS2CodePageRanges"] = ["0"]
652        self._writeInfoToPlist(info)
653        reader = UFOReader(self.dstDir, validate=True)
654        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
655        ## out of range
656        info = dict(fontInfoVersion3)
657        info["openTypeOS2CodePageRanges"] = [-1]
658        self._writeInfoToPlist(info)
659        reader = UFOReader(self.dstDir, validate=True)
660        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
661        # openTypeOS2TypoAscender
662        info = dict(fontInfoVersion3)
663        info["openTypeOS2TypoAscender"] = "abc"
664        self._writeInfoToPlist(info)
665        reader = UFOReader(self.dstDir, validate=True)
666        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
667        # openTypeOS2TypoDescender
668        info = dict(fontInfoVersion3)
669        info["openTypeOS2TypoDescender"] = "abc"
670        self._writeInfoToPlist(info)
671        reader = UFOReader(self.dstDir, validate=True)
672        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
673        # openTypeOS2TypoLineGap
674        info = dict(fontInfoVersion3)
675        info["openTypeOS2TypoLineGap"] = "abc"
676        self._writeInfoToPlist(info)
677        reader = UFOReader(self.dstDir, validate=True)
678        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
679        # openTypeOS2WinAscent
680        info = dict(fontInfoVersion3)
681        info["openTypeOS2WinAscent"] = "abc"
682        self._writeInfoToPlist(info)
683        reader = UFOReader(self.dstDir, validate=True)
684        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
685        info = dict(fontInfoVersion3)
686        info["openTypeOS2WinAscent"] = -1
687        self._writeInfoToPlist(info)
688        reader = UFOReader(self.dstDir, validate=True)
689        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
690        # openTypeOS2WinDescent
691        info = dict(fontInfoVersion3)
692        info["openTypeOS2WinDescent"] = "abc"
693        self._writeInfoToPlist(info)
694        reader = UFOReader(self.dstDir, validate=True)
695        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
696        info = dict(fontInfoVersion3)
697        info["openTypeOS2WinDescent"] = -1
698        self._writeInfoToPlist(info)
699        reader = UFOReader(self.dstDir, validate=True)
700        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
701        # openTypeOS2Type
702        ## not an int
703        info = dict(fontInfoVersion3)
704        info["openTypeOS2Type"] = ["1"]
705        self._writeInfoToPlist(info)
706        reader = UFOReader(self.dstDir, validate=True)
707        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
708        ## out of range
709        info = dict(fontInfoVersion3)
710        info["openTypeOS2Type"] = [-1]
711        self._writeInfoToPlist(info)
712        reader = UFOReader(self.dstDir, validate=True)
713        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
714        # openTypeOS2SubscriptXSize
715        info = dict(fontInfoVersion3)
716        info["openTypeOS2SubscriptXSize"] = "abc"
717        self._writeInfoToPlist(info)
718        reader = UFOReader(self.dstDir, validate=True)
719        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
720        # openTypeOS2SubscriptYSize
721        info = dict(fontInfoVersion3)
722        info["openTypeOS2SubscriptYSize"] = "abc"
723        self._writeInfoToPlist(info)
724        reader = UFOReader(self.dstDir, validate=True)
725        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
726        # openTypeOS2SubscriptXOffset
727        info = dict(fontInfoVersion3)
728        info["openTypeOS2SubscriptXOffset"] = "abc"
729        self._writeInfoToPlist(info)
730        reader = UFOReader(self.dstDir, validate=True)
731        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
732        # openTypeOS2SubscriptYOffset
733        info = dict(fontInfoVersion3)
734        info["openTypeOS2SubscriptYOffset"] = "abc"
735        self._writeInfoToPlist(info)
736        reader = UFOReader(self.dstDir, validate=True)
737        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
738        # openTypeOS2SuperscriptXSize
739        info = dict(fontInfoVersion3)
740        info["openTypeOS2SuperscriptXSize"] = "abc"
741        self._writeInfoToPlist(info)
742        reader = UFOReader(self.dstDir, validate=True)
743        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
744        # openTypeOS2SuperscriptYSize
745        info = dict(fontInfoVersion3)
746        info["openTypeOS2SuperscriptYSize"] = "abc"
747        self._writeInfoToPlist(info)
748        reader = UFOReader(self.dstDir, validate=True)
749        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
750        # openTypeOS2SuperscriptXOffset
751        info = dict(fontInfoVersion3)
752        info["openTypeOS2SuperscriptXOffset"] = "abc"
753        self._writeInfoToPlist(info)
754        reader = UFOReader(self.dstDir, validate=True)
755        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
756        # openTypeOS2SuperscriptYOffset
757        info = dict(fontInfoVersion3)
758        info["openTypeOS2SuperscriptYOffset"] = "abc"
759        self._writeInfoToPlist(info)
760        reader = UFOReader(self.dstDir, validate=True)
761        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
762        # openTypeOS2StrikeoutSize
763        info = dict(fontInfoVersion3)
764        info["openTypeOS2StrikeoutSize"] = "abc"
765        self._writeInfoToPlist(info)
766        reader = UFOReader(self.dstDir, validate=True)
767        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
768        # openTypeOS2StrikeoutPosition
769        info = dict(fontInfoVersion3)
770        info["openTypeOS2StrikeoutPosition"] = "abc"
771        self._writeInfoToPlist(info)
772        reader = UFOReader(self.dstDir, validate=True)
773        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
774
775    def testVheaRead(self):
776        # openTypeVheaVertTypoAscender
777        info = dict(fontInfoVersion3)
778        info["openTypeVheaVertTypoAscender"] = "abc"
779        self._writeInfoToPlist(info)
780        reader = UFOReader(self.dstDir, validate=True)
781        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
782        # openTypeVheaVertTypoDescender
783        info = dict(fontInfoVersion3)
784        info["openTypeVheaVertTypoDescender"] = "abc"
785        self._writeInfoToPlist(info)
786        reader = UFOReader(self.dstDir, validate=True)
787        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
788        # openTypeVheaVertTypoLineGap
789        info = dict(fontInfoVersion3)
790        info["openTypeVheaVertTypoLineGap"] = "abc"
791        self._writeInfoToPlist(info)
792        reader = UFOReader(self.dstDir, validate=True)
793        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
794        # openTypeVheaCaretSlopeRise
795        info = dict(fontInfoVersion3)
796        info["openTypeVheaCaretSlopeRise"] = "abc"
797        self._writeInfoToPlist(info)
798        reader = UFOReader(self.dstDir, validate=True)
799        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
800        # openTypeVheaCaretSlopeRun
801        info = dict(fontInfoVersion3)
802        info["openTypeVheaCaretSlopeRun"] = "abc"
803        self._writeInfoToPlist(info)
804        reader = UFOReader(self.dstDir, validate=True)
805        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
806        # openTypeVheaCaretOffset
807        info = dict(fontInfoVersion3)
808        info["openTypeVheaCaretOffset"] = "abc"
809        self._writeInfoToPlist(info)
810        reader = UFOReader(self.dstDir, validate=True)
811        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
812
813    def testFONDRead(self):
814        # macintoshFONDFamilyID
815        info = dict(fontInfoVersion3)
816        info["macintoshFONDFamilyID"] = "abc"
817        self._writeInfoToPlist(info)
818        reader = UFOReader(self.dstDir, validate=True)
819        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
820        # macintoshFONDName
821        info = dict(fontInfoVersion3)
822        info["macintoshFONDName"] = 123
823        self._writeInfoToPlist(info)
824        reader = UFOReader(self.dstDir, validate=True)
825        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
826
827    def testPostscriptRead(self):
828        # postscriptFontName
829        info = dict(fontInfoVersion3)
830        info["postscriptFontName"] = 123
831        self._writeInfoToPlist(info)
832        reader = UFOReader(self.dstDir, validate=True)
833        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
834        # postscriptFullName
835        info = dict(fontInfoVersion3)
836        info["postscriptFullName"] = 123
837        self._writeInfoToPlist(info)
838        reader = UFOReader(self.dstDir, validate=True)
839        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
840        # postscriptSlantAngle
841        info = dict(fontInfoVersion3)
842        info["postscriptSlantAngle"] = "abc"
843        self._writeInfoToPlist(info)
844        reader = UFOReader(self.dstDir, validate=True)
845        self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject())
846        # postscriptUniqueID
847        info = dict(fontInfoVersion3)
848        info["postscriptUniqueID"] = "abc"
849        self._writeInfoToPlist(info)
850        reader = UFOReader(self.dstDir, validate=True)
851        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
852        # postscriptUnderlineThickness
853        info = dict(fontInfoVersion3)
854        info["postscriptUnderlineThickness"] = "abc"
855        self._writeInfoToPlist(info)
856        reader = UFOReader(self.dstDir, validate=True)
857        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
858        # postscriptUnderlinePosition
859        info = dict(fontInfoVersion3)
860        info["postscriptUnderlinePosition"] = "abc"
861        self._writeInfoToPlist(info)
862        reader = UFOReader(self.dstDir, validate=True)
863        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
864        # postscriptIsFixedPitch
865        info = dict(fontInfoVersion3)
866        info["postscriptIsFixedPitch"] = 2
867        self._writeInfoToPlist(info)
868        reader = UFOReader(self.dstDir, validate=True)
869        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
870        # postscriptBlueValues
871        ## not a list
872        info = dict(fontInfoVersion3)
873        info["postscriptBlueValues"] = "abc"
874        self._writeInfoToPlist(info)
875        reader = UFOReader(self.dstDir, validate=True)
876        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
877        ## uneven value count
878        info = dict(fontInfoVersion3)
879        info["postscriptBlueValues"] = [500]
880        self._writeInfoToPlist(info)
881        reader = UFOReader(self.dstDir, validate=True)
882        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
883        ## too many values
884        info = dict(fontInfoVersion3)
885        info["postscriptBlueValues"] = [
886            10,
887            20,
888            30,
889            40,
890            50,
891            60,
892            70,
893            80,
894            90,
895            100,
896            110,
897            120,
898            130,
899            140,
900            150,
901            160,
902        ]
903        self._writeInfoToPlist(info)
904        reader = UFOReader(self.dstDir, validate=True)
905        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
906        # postscriptOtherBlues
907        ## not a list
908        info = dict(fontInfoVersion3)
909        info["postscriptOtherBlues"] = "abc"
910        self._writeInfoToPlist(info)
911        reader = UFOReader(self.dstDir, validate=True)
912        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
913        ## uneven value count
914        info = dict(fontInfoVersion3)
915        info["postscriptOtherBlues"] = [500]
916        self._writeInfoToPlist(info)
917        reader = UFOReader(self.dstDir, validate=True)
918        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
919        ## too many values
920        info = dict(fontInfoVersion3)
921        info["postscriptOtherBlues"] = [
922            10,
923            20,
924            30,
925            40,
926            50,
927            60,
928            70,
929            80,
930            90,
931            100,
932            110,
933            120,
934            130,
935            140,
936            150,
937            160,
938        ]
939        self._writeInfoToPlist(info)
940        reader = UFOReader(self.dstDir, validate=True)
941        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
942        # postscriptFamilyBlues
943        ## not a list
944        info = dict(fontInfoVersion3)
945        info["postscriptFamilyBlues"] = "abc"
946        self._writeInfoToPlist(info)
947        reader = UFOReader(self.dstDir, validate=True)
948        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
949        ## uneven value count
950        info = dict(fontInfoVersion3)
951        info["postscriptFamilyBlues"] = [500]
952        self._writeInfoToPlist(info)
953        reader = UFOReader(self.dstDir, validate=True)
954        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
955        ## too many values
956        info = dict(fontInfoVersion3)
957        info["postscriptFamilyBlues"] = [
958            10,
959            20,
960            30,
961            40,
962            50,
963            60,
964            70,
965            80,
966            90,
967            100,
968            110,
969            120,
970            130,
971            140,
972            150,
973            160,
974        ]
975        self._writeInfoToPlist(info)
976        reader = UFOReader(self.dstDir, validate=True)
977        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
978        # postscriptFamilyOtherBlues
979        ## not a list
980        info = dict(fontInfoVersion3)
981        info["postscriptFamilyOtherBlues"] = "abc"
982        self._writeInfoToPlist(info)
983        reader = UFOReader(self.dstDir, validate=True)
984        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
985        ## uneven value count
986        info = dict(fontInfoVersion3)
987        info["postscriptFamilyOtherBlues"] = [500]
988        self._writeInfoToPlist(info)
989        reader = UFOReader(self.dstDir, validate=True)
990        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
991        ## too many values
992        info = dict(fontInfoVersion3)
993        info["postscriptFamilyOtherBlues"] = [
994            10,
995            20,
996            30,
997            40,
998            50,
999            60,
1000            70,
1001            80,
1002            90,
1003            100,
1004            110,
1005            120,
1006            130,
1007            140,
1008            150,
1009            160,
1010        ]
1011        self._writeInfoToPlist(info)
1012        reader = UFOReader(self.dstDir, validate=True)
1013        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1014        # postscriptStemSnapH
1015        ## not list
1016        info = dict(fontInfoVersion3)
1017        info["postscriptStemSnapH"] = "abc"
1018        self._writeInfoToPlist(info)
1019        reader = UFOReader(self.dstDir, validate=True)
1020        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1021        ## too many values
1022        info = dict(fontInfoVersion3)
1023        info["postscriptStemSnapH"] = [
1024            10,
1025            20,
1026            30,
1027            40,
1028            50,
1029            60,
1030            70,
1031            80,
1032            90,
1033            100,
1034            110,
1035            120,
1036            130,
1037            140,
1038            150,
1039            160,
1040        ]
1041        self._writeInfoToPlist(info)
1042        reader = UFOReader(self.dstDir, validate=True)
1043        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1044        # postscriptStemSnapV
1045        ## not list
1046        info = dict(fontInfoVersion3)
1047        info["postscriptStemSnapV"] = "abc"
1048        self._writeInfoToPlist(info)
1049        reader = UFOReader(self.dstDir, validate=True)
1050        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1051        ## too many values
1052        info = dict(fontInfoVersion3)
1053        info["postscriptStemSnapV"] = [
1054            10,
1055            20,
1056            30,
1057            40,
1058            50,
1059            60,
1060            70,
1061            80,
1062            90,
1063            100,
1064            110,
1065            120,
1066            130,
1067            140,
1068            150,
1069            160,
1070        ]
1071        self._writeInfoToPlist(info)
1072        reader = UFOReader(self.dstDir, validate=True)
1073        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1074        # postscriptBlueFuzz
1075        info = dict(fontInfoVersion3)
1076        info["postscriptBlueFuzz"] = "abc"
1077        self._writeInfoToPlist(info)
1078        reader = UFOReader(self.dstDir, validate=True)
1079        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1080        # postscriptBlueShift
1081        info = dict(fontInfoVersion3)
1082        info["postscriptBlueShift"] = "abc"
1083        self._writeInfoToPlist(info)
1084        reader = UFOReader(self.dstDir, validate=True)
1085        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1086        # postscriptBlueScale
1087        info = dict(fontInfoVersion3)
1088        info["postscriptBlueScale"] = "abc"
1089        self._writeInfoToPlist(info)
1090        reader = UFOReader(self.dstDir, validate=True)
1091        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1092        # postscriptForceBold
1093        info = dict(fontInfoVersion3)
1094        info["postscriptForceBold"] = "abc"
1095        self._writeInfoToPlist(info)
1096        reader = UFOReader(self.dstDir, validate=True)
1097        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1098        # postscriptDefaultWidthX
1099        info = dict(fontInfoVersion3)
1100        info["postscriptDefaultWidthX"] = "abc"
1101        self._writeInfoToPlist(info)
1102        reader = UFOReader(self.dstDir, validate=True)
1103        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1104        # postscriptNominalWidthX
1105        info = dict(fontInfoVersion3)
1106        info["postscriptNominalWidthX"] = "abc"
1107        self._writeInfoToPlist(info)
1108        reader = UFOReader(self.dstDir, validate=True)
1109        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1110        # postscriptWeightName
1111        info = dict(fontInfoVersion3)
1112        info["postscriptWeightName"] = 123
1113        self._writeInfoToPlist(info)
1114        reader = UFOReader(self.dstDir, validate=True)
1115        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1116        # postscriptDefaultCharacter
1117        info = dict(fontInfoVersion3)
1118        info["postscriptDefaultCharacter"] = 123
1119        self._writeInfoToPlist(info)
1120        reader = UFOReader(self.dstDir, validate=True)
1121        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1122        # postscriptWindowsCharacterSet
1123        info = dict(fontInfoVersion3)
1124        info["postscriptWindowsCharacterSet"] = -1
1125        self._writeInfoToPlist(info)
1126        reader = UFOReader(self.dstDir, validate=True)
1127        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1128        # macintoshFONDFamilyID
1129        info = dict(fontInfoVersion3)
1130        info["macintoshFONDFamilyID"] = "abc"
1131        self._writeInfoToPlist(info)
1132        reader = UFOReader(self.dstDir, validate=True)
1133        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1134        # macintoshFONDName
1135        info = dict(fontInfoVersion3)
1136        info["macintoshFONDName"] = 123
1137        self._writeInfoToPlist(info)
1138        reader = UFOReader(self.dstDir, validate=True)
1139        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1140
1141    def testWOFFRead(self):
1142        # woffMajorVersion
1143        info = dict(fontInfoVersion3)
1144        info["woffMajorVersion"] = 1.0
1145        self._writeInfoToPlist(info)
1146        reader = UFOReader(self.dstDir, validate=True)
1147        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1148        info = dict(fontInfoVersion3)
1149        info["woffMajorVersion"] = "abc"
1150        self._writeInfoToPlist(info)
1151        reader = UFOReader(self.dstDir, validate=True)
1152        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1153        # woffMinorVersion
1154        info = dict(fontInfoVersion3)
1155        info["woffMinorVersion"] = 1.0
1156        self._writeInfoToPlist(info)
1157        reader = UFOReader(self.dstDir, validate=True)
1158        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1159        info = dict(fontInfoVersion3)
1160        info["woffMinorVersion"] = "abc"
1161        self._writeInfoToPlist(info)
1162        reader = UFOReader(self.dstDir, validate=True)
1163        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1164        # woffMetadataUniqueID
1165        ## none
1166        info = dict(fontInfoVersion3)
1167        del info["woffMetadataUniqueID"]
1168        self._writeInfoToPlist(info)
1169        reader = UFOReader(self.dstDir, validate=True)
1170        reader.readInfo(TestInfoObject())
1171        ## not a dict
1172        info = dict(fontInfoVersion3)
1173        info["woffMetadataUniqueID"] = 1
1174        self._writeInfoToPlist(info)
1175        reader = UFOReader(self.dstDir, validate=True)
1176        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1177        ## unknown key
1178        info = dict(fontInfoVersion3)
1179        info["woffMetadataUniqueID"] = dict(id="foo", notTheRightKey=1)
1180        self._writeInfoToPlist(info)
1181        reader = UFOReader(self.dstDir, validate=True)
1182        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1183        ## no id
1184        info = dict(fontInfoVersion3)
1185        info["woffMetadataUniqueID"] = dict()
1186        self._writeInfoToPlist(info)
1187        reader = UFOReader(self.dstDir, validate=True)
1188        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1189        ## not a string for id
1190        info = dict(fontInfoVersion3)
1191        info["woffMetadataUniqueID"] = dict(id=1)
1192        self._writeInfoToPlist(info)
1193        reader = UFOReader(self.dstDir, validate=True)
1194        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1195        ## empty string
1196        info = dict(fontInfoVersion3)
1197        info["woffMetadataUniqueID"] = dict(id="")
1198        self._writeInfoToPlist(info)
1199        reader = UFOReader(self.dstDir, validate=True)
1200        reader.readInfo(TestInfoObject())
1201        # woffMetadataVendor
1202        ## no name
1203        info = dict(fontInfoVersion3)
1204        info["woffMetadataVendor"] = dict(url="foo")
1205        self._writeInfoToPlist(info)
1206        reader = UFOReader(self.dstDir, validate=True)
1207        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1208        ## name not a string
1209        info = dict(fontInfoVersion3)
1210        info["woffMetadataVendor"] = dict(name=1, url="foo")
1211        self._writeInfoToPlist(info)
1212        reader = UFOReader(self.dstDir, validate=True)
1213        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1214        ## name an empty string
1215        info = dict(fontInfoVersion3)
1216        info["woffMetadataVendor"] = dict(name="", url="foo")
1217        self._writeInfoToPlist(info)
1218        reader = UFOReader(self.dstDir, validate=True)
1219        reader.readInfo(TestInfoObject())
1220        ## no URL
1221        info = dict(fontInfoVersion3)
1222        info["woffMetadataVendor"] = dict(name="foo")
1223        self._writeInfoToPlist(info)
1224        reader = UFOReader(self.dstDir, validate=True)
1225        reader.readInfo(TestInfoObject())
1226        ## url not a string
1227        info = dict(fontInfoVersion3)
1228        info["woffMetadataVendor"] = dict(name="foo", url=1)
1229        self._writeInfoToPlist(info)
1230        reader = UFOReader(self.dstDir, validate=True)
1231        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1232        ## url empty string
1233        info = dict(fontInfoVersion3)
1234        info["woffMetadataVendor"] = dict(name="foo", url="")
1235        self._writeInfoToPlist(info)
1236        reader = UFOReader(self.dstDir, validate=True)
1237        reader.readInfo(TestInfoObject())
1238        ## have dir
1239        info = dict(fontInfoVersion3)
1240        info["woffMetadataVendor"] = dict(name="foo", url="bar", dir="ltr")
1241        self._writeInfoToPlist(info)
1242        reader = UFOReader(self.dstDir, validate=True)
1243        reader.readInfo(TestInfoObject())
1244        info = dict(fontInfoVersion3)
1245        info["woffMetadataVendor"] = dict(name="foo", url="bar", dir="rtl")
1246        self._writeInfoToPlist(info)
1247        reader = UFOReader(self.dstDir, validate=True)
1248        reader.readInfo(TestInfoObject())
1249        ## dir not a string
1250        info = dict(fontInfoVersion3)
1251        info["woffMetadataVendor"] = dict(name="foo", url="bar", dir=1)
1252        self._writeInfoToPlist(info)
1253        reader = UFOReader(self.dstDir, validate=True)
1254        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1255        ## dir not ltr or rtl
1256        info = dict(fontInfoVersion3)
1257        info["woffMetadataVendor"] = dict(name="foo", url="bar", dir="utd")
1258        self._writeInfoToPlist(info)
1259        reader = UFOReader(self.dstDir, validate=True)
1260        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1261        ## have class
1262        info = dict(fontInfoVersion3)
1263        info["woffMetadataVendor"] = {"name": "foo", "url": "bar", "class": "hello"}
1264        self._writeInfoToPlist(info)
1265        reader = UFOReader(self.dstDir, validate=True)
1266        reader.readInfo(TestInfoObject())
1267        ## class not a string
1268        info = dict(fontInfoVersion3)
1269        info["woffMetadataVendor"] = {"name": "foo", "url": "bar", "class": 1}
1270        self._writeInfoToPlist(info)
1271        reader = UFOReader(self.dstDir, validate=True)
1272        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1273        ## class empty string
1274        info = dict(fontInfoVersion3)
1275        info["woffMetadataVendor"] = {"name": "foo", "url": "bar", "class": ""}
1276        self._writeInfoToPlist(info)
1277        reader = UFOReader(self.dstDir, validate=True)
1278        reader.readInfo(TestInfoObject())
1279        # woffMetadataCredits
1280        ## no credits attribute
1281        info = dict(fontInfoVersion3)
1282        info["woffMetadataCredits"] = {}
1283        self._writeInfoToPlist(info)
1284        reader = UFOReader(self.dstDir, validate=True)
1285        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1286        ## unknown attribute
1287        info = dict(fontInfoVersion3)
1288        info["woffMetadataCredits"] = dict(credits=[dict(name="foo")], notTheRightKey=1)
1289        self._writeInfoToPlist(info)
1290        reader = UFOReader(self.dstDir, validate=True)
1291        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1292        ## not a list
1293        info = dict(fontInfoVersion3)
1294        info["woffMetadataCredits"] = dict(credits="abc")
1295        self._writeInfoToPlist(info)
1296        reader = UFOReader(self.dstDir, validate=True)
1297        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1298        ## no elements in credits
1299        info = dict(fontInfoVersion3)
1300        info["woffMetadataCredits"] = dict(credits=[])
1301        self._writeInfoToPlist(info)
1302        reader = UFOReader(self.dstDir, validate=True)
1303        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1304        ## credit not a dict
1305        info = dict(fontInfoVersion3)
1306        info["woffMetadataCredits"] = dict(credits=["abc"])
1307        self._writeInfoToPlist(info)
1308        reader = UFOReader(self.dstDir, validate=True)
1309        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1310        ## unknown key
1311        info = dict(fontInfoVersion3)
1312        info["woffMetadataCredits"] = dict(credits=[dict(name="foo", notTheRightKey=1)])
1313        self._writeInfoToPlist(info)
1314        reader = UFOReader(self.dstDir, validate=True)
1315        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1316        ## no name
1317        info = dict(fontInfoVersion3)
1318        info["woffMetadataCredits"] = dict(credits=[dict(url="foo")])
1319        self._writeInfoToPlist(info)
1320        reader = UFOReader(self.dstDir, validate=True)
1321        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1322        ## name not a string
1323        info = dict(fontInfoVersion3)
1324        info["woffMetadataCredits"] = dict(credits=[dict(name=1)])
1325        self._writeInfoToPlist(info)
1326        reader = UFOReader(self.dstDir, validate=True)
1327        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1328        ## url not a string
1329        info = dict(fontInfoVersion3)
1330        info["woffMetadataCredits"] = dict(credits=[dict(name="foo", url=1)])
1331        self._writeInfoToPlist(info)
1332        reader = UFOReader(self.dstDir, validate=True)
1333        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1334        ## role not a string
1335        info = dict(fontInfoVersion3)
1336        info["woffMetadataCredits"] = dict(credits=[dict(name="foo", role=1)])
1337        self._writeInfoToPlist(info)
1338        reader = UFOReader(self.dstDir, validate=True)
1339        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1340        ## dir not a string
1341        info = dict(fontInfoVersion3)
1342        info["woffMetadataCredits"] = dict(credits=[dict(name="foo", dir=1)])
1343        self._writeInfoToPlist(info)
1344        reader = UFOReader(self.dstDir, validate=True)
1345        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1346        ## dir not ltr or rtl
1347        info = dict(fontInfoVersion3)
1348        info["woffMetadataCredits"] = dict(credits=[dict(name="foo", dir="utd")])
1349        self._writeInfoToPlist(info)
1350        reader = UFOReader(self.dstDir, validate=True)
1351        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1352        ## class not a string
1353        info = dict(fontInfoVersion3)
1354        info["woffMetadataCredits"] = dict(credits=[{"name": "foo", "class": 1}])
1355        self._writeInfoToPlist(info)
1356        reader = UFOReader(self.dstDir, validate=True)
1357        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1358        # woffMetadataDescription
1359        ## no url
1360        info = dict(fontInfoVersion3)
1361        info["woffMetadataDescription"] = dict(text=[dict(text="foo")])
1362        self._writeInfoToPlist(info)
1363        reader = UFOReader(self.dstDir, validate=True)
1364        reader.readInfo(TestInfoObject())
1365        ## url not a string
1366        info = dict(fontInfoVersion3)
1367        info["woffMetadataDescription"] = dict(text=[dict(text="foo")], url=1)
1368        self._writeInfoToPlist(info)
1369        reader = UFOReader(self.dstDir, validate=True)
1370        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1371        ## no text
1372        info = dict(fontInfoVersion3)
1373        info["woffMetadataDescription"] = dict(url="foo")
1374        self._writeInfoToPlist(info)
1375        reader = UFOReader(self.dstDir, validate=True)
1376        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1377        ## text not a list
1378        info = dict(fontInfoVersion3)
1379        info["woffMetadataDescription"] = dict(text="abc")
1380        self._writeInfoToPlist(info)
1381        reader = UFOReader(self.dstDir, validate=True)
1382        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1383        ## text item not a dict
1384        info = dict(fontInfoVersion3)
1385        info["woffMetadataDescription"] = dict(text=["abc"])
1386        self._writeInfoToPlist(info)
1387        reader = UFOReader(self.dstDir, validate=True)
1388        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1389        ## text item unknown key
1390        info = dict(fontInfoVersion3)
1391        info["woffMetadataDescription"] = dict(
1392            text=[dict(text="foo", notTheRightKey=1)]
1393        )
1394        self._writeInfoToPlist(info)
1395        reader = UFOReader(self.dstDir, validate=True)
1396        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1397        ## text item missing text
1398        info = dict(fontInfoVersion3)
1399        info["woffMetadataDescription"] = dict(text=[dict(language="foo")])
1400        self._writeInfoToPlist(info)
1401        reader = UFOReader(self.dstDir, validate=True)
1402        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1403        ## text not a string
1404        info = dict(fontInfoVersion3)
1405        info["woffMetadataDescription"] = dict(text=[dict(text=1)])
1406        self._writeInfoToPlist(info)
1407        reader = UFOReader(self.dstDir, validate=True)
1408        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1409        ## url not a string
1410        info = dict(fontInfoVersion3)
1411        info["woffMetadataDescription"] = dict(text=[dict(text="foo", url=1)])
1412        self._writeInfoToPlist(info)
1413        reader = UFOReader(self.dstDir, validate=True)
1414        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1415        ## language not a string
1416        info = dict(fontInfoVersion3)
1417        info["woffMetadataDescription"] = dict(text=[dict(text="foo", language=1)])
1418        self._writeInfoToPlist(info)
1419        reader = UFOReader(self.dstDir, validate=True)
1420        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1421        ## dir not ltr or rtl
1422        info = dict(fontInfoVersion3)
1423        info["woffMetadataDescription"] = dict(text=[dict(text="foo", dir="utd")])
1424        self._writeInfoToPlist(info)
1425        reader = UFOReader(self.dstDir, validate=True)
1426        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1427        ## class not a string
1428        info = dict(fontInfoVersion3)
1429        info["woffMetadataDescription"] = dict(text=[{"text": "foo", "class": 1}])
1430        self._writeInfoToPlist(info)
1431        reader = UFOReader(self.dstDir, validate=True)
1432        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1433        # woffMetadataLicense
1434        ## no url
1435        info = dict(fontInfoVersion3)
1436        info["woffMetadataLicense"] = dict(text=[dict(text="foo")])
1437        self._writeInfoToPlist(info)
1438        reader = UFOReader(self.dstDir, validate=True)
1439        reader.readInfo(TestInfoObject())
1440        ## url not a string
1441        info = dict(fontInfoVersion3)
1442        info["woffMetadataLicense"] = dict(text=[dict(text="foo")], url=1)
1443        self._writeInfoToPlist(info)
1444        reader = UFOReader(self.dstDir, validate=True)
1445        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1446        ## id not a string
1447        info = dict(fontInfoVersion3)
1448        info["woffMetadataLicense"] = dict(text=[dict(text="foo")], id=1)
1449        self._writeInfoToPlist(info)
1450        reader = UFOReader(self.dstDir, validate=True)
1451        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1452        ## no text
1453        info = dict(fontInfoVersion3)
1454        info["woffMetadataLicense"] = dict(url="foo")
1455        self._writeInfoToPlist(info)
1456        reader = UFOReader(self.dstDir, validate=True)
1457        reader.readInfo(TestInfoObject())
1458        ## text not a list
1459        info = dict(fontInfoVersion3)
1460        info["woffMetadataLicense"] = dict(text="abc")
1461        self._writeInfoToPlist(info)
1462        reader = UFOReader(self.dstDir, validate=True)
1463        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1464        ## text item not a dict
1465        info = dict(fontInfoVersion3)
1466        info["woffMetadataLicense"] = dict(text=["abc"])
1467        self._writeInfoToPlist(info)
1468        reader = UFOReader(self.dstDir, validate=True)
1469        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1470        ## text item unknown key
1471        info = dict(fontInfoVersion3)
1472        info["woffMetadataLicense"] = dict(text=[dict(text="foo", notTheRightKey=1)])
1473        self._writeInfoToPlist(info)
1474        reader = UFOReader(self.dstDir, validate=True)
1475        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1476        ## text item missing text
1477        info = dict(fontInfoVersion3)
1478        info["woffMetadataLicense"] = dict(text=[dict(language="foo")])
1479        self._writeInfoToPlist(info)
1480        reader = UFOReader(self.dstDir, validate=True)
1481        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1482        ## text not a string
1483        info = dict(fontInfoVersion3)
1484        info["woffMetadataLicense"] = dict(text=[dict(text=1)])
1485        self._writeInfoToPlist(info)
1486        reader = UFOReader(self.dstDir, validate=True)
1487        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1488        ## url not a string
1489        info = dict(fontInfoVersion3)
1490        info["woffMetadataLicense"] = dict(text=[dict(text="foo", url=1)])
1491        self._writeInfoToPlist(info)
1492        reader = UFOReader(self.dstDir, validate=True)
1493        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1494        ## language not a string
1495        info = dict(fontInfoVersion3)
1496        info["woffMetadataLicense"] = dict(text=[dict(text="foo", language=1)])
1497        self._writeInfoToPlist(info)
1498        reader = UFOReader(self.dstDir, validate=True)
1499        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1500        ## dir not ltr or rtl
1501        info = dict(fontInfoVersion3)
1502        info["woffMetadataLicense"] = dict(text=[dict(text="foo", dir="utd")])
1503        self._writeInfoToPlist(info)
1504        reader = UFOReader(self.dstDir, validate=True)
1505        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1506        ## class not a string
1507        info = dict(fontInfoVersion3)
1508        info["woffMetadataLicense"] = dict(text=[{"text": "foo", "class": 1}])
1509        self._writeInfoToPlist(info)
1510        reader = UFOReader(self.dstDir, validate=True)
1511        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1512        # woffMetadataCopyright
1513        ## unknown attribute
1514        info = dict(fontInfoVersion3)
1515        info["woffMetadataCopyright"] = dict(text=[dict(text="foo")], notTheRightKey=1)
1516        self._writeInfoToPlist(info)
1517        reader = UFOReader(self.dstDir, validate=True)
1518        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1519        ## no text
1520        info = dict(fontInfoVersion3)
1521        info["woffMetadataCopyright"] = dict()
1522        self._writeInfoToPlist(info)
1523        reader = UFOReader(self.dstDir, validate=True)
1524        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1525        ## text not a list
1526        info = dict(fontInfoVersion3)
1527        info["woffMetadataCopyright"] = dict(text="abc")
1528        self._writeInfoToPlist(info)
1529        reader = UFOReader(self.dstDir, validate=True)
1530        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1531        ## text item not a dict
1532        info = dict(fontInfoVersion3)
1533        info["woffMetadataCopyright"] = dict(text=["abc"])
1534        self._writeInfoToPlist(info)
1535        reader = UFOReader(self.dstDir, validate=True)
1536        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1537        ## text item unknown key
1538        info = dict(fontInfoVersion3)
1539        info["woffMetadataCopyright"] = dict(text=[dict(text="foo", notTheRightKey=1)])
1540        self._writeInfoToPlist(info)
1541        reader = UFOReader(self.dstDir, validate=True)
1542        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1543        ## text item missing text
1544        info = dict(fontInfoVersion3)
1545        info["woffMetadataCopyright"] = dict(text=[dict(language="foo")])
1546        self._writeInfoToPlist(info)
1547        reader = UFOReader(self.dstDir, validate=True)
1548        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1549        ## text not a string
1550        info = dict(fontInfoVersion3)
1551        info["woffMetadataCopyright"] = dict(text=[dict(text=1)])
1552        self._writeInfoToPlist(info)
1553        reader = UFOReader(self.dstDir, validate=True)
1554        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1555        ## url not a string
1556        info = dict(fontInfoVersion3)
1557        info["woffMetadataCopyright"] = dict(text=[dict(text="foo", url=1)])
1558        self._writeInfoToPlist(info)
1559        reader = UFOReader(self.dstDir, validate=True)
1560        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1561        ## language not a string
1562        info = dict(fontInfoVersion3)
1563        info["woffMetadataCopyright"] = dict(text=[dict(text="foo", language=1)])
1564        self._writeInfoToPlist(info)
1565        reader = UFOReader(self.dstDir, validate=True)
1566        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1567        ## dir not ltr or rtl
1568        info = dict(fontInfoVersion3)
1569        info["woffMetadataCopyright"] = dict(text=[dict(text="foo", dir="utd")])
1570        self._writeInfoToPlist(info)
1571        reader = UFOReader(self.dstDir, validate=True)
1572        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1573        ## class not a string
1574        info = dict(fontInfoVersion3)
1575        info["woffMetadataCopyright"] = dict(text=[{"text": "foo", "class": 1}])
1576        self._writeInfoToPlist(info)
1577        reader = UFOReader(self.dstDir, validate=True)
1578        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1579        # woffMetadataTrademark
1580        ## unknown attribute
1581        info = dict(fontInfoVersion3)
1582        info["woffMetadataTrademark"] = dict(text=[dict(text="foo")], notTheRightKey=1)
1583        self._writeInfoToPlist(info)
1584        reader = UFOReader(self.dstDir, validate=True)
1585        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1586        ## no text
1587        info = dict(fontInfoVersion3)
1588        info["woffMetadataTrademark"] = dict()
1589        self._writeInfoToPlist(info)
1590        reader = UFOReader(self.dstDir, validate=True)
1591        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1592        ## text not a list
1593        info = dict(fontInfoVersion3)
1594        info["woffMetadataTrademark"] = dict(text="abc")
1595        self._writeInfoToPlist(info)
1596        reader = UFOReader(self.dstDir, validate=True)
1597        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1598        ## text item not a dict
1599        info = dict(fontInfoVersion3)
1600        info["woffMetadataTrademark"] = dict(text=["abc"])
1601        self._writeInfoToPlist(info)
1602        reader = UFOReader(self.dstDir, validate=True)
1603        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1604        ## text item unknown key
1605        info = dict(fontInfoVersion3)
1606        info["woffMetadataTrademark"] = dict(text=[dict(text="foo", notTheRightKey=1)])
1607        self._writeInfoToPlist(info)
1608        reader = UFOReader(self.dstDir, validate=True)
1609        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1610        ## text item missing text
1611        info = dict(fontInfoVersion3)
1612        info["woffMetadataTrademark"] = dict(text=[dict(language="foo")])
1613        self._writeInfoToPlist(info)
1614        reader = UFOReader(self.dstDir, validate=True)
1615        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1616        ## text not a string
1617        info = dict(fontInfoVersion3)
1618        info["woffMetadataTrademark"] = dict(text=[dict(text=1)])
1619        self._writeInfoToPlist(info)
1620        reader = UFOReader(self.dstDir, validate=True)
1621        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1622        ## url not a string
1623        info = dict(fontInfoVersion3)
1624        info["woffMetadataTrademark"] = dict(text=[dict(text="foo", url=1)])
1625        self._writeInfoToPlist(info)
1626        reader = UFOReader(self.dstDir, validate=True)
1627        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1628        ## language not a string
1629        info = dict(fontInfoVersion3)
1630        info["woffMetadataTrademark"] = dict(text=[dict(text="foo", language=1)])
1631        self._writeInfoToPlist(info)
1632        reader = UFOReader(self.dstDir, validate=True)
1633        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1634        ## dir not ltr or rtl
1635        info = dict(fontInfoVersion3)
1636        info["woffMetadataTrademark"] = dict(text=[dict(text="foo", dir="utd")])
1637        self._writeInfoToPlist(info)
1638        reader = UFOReader(self.dstDir, validate=True)
1639        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1640        ## class not a string
1641        info = dict(fontInfoVersion3)
1642        info["woffMetadataTrademark"] = dict(text=[{"text": "foo", "class": 1}])
1643        self._writeInfoToPlist(info)
1644        reader = UFOReader(self.dstDir, validate=True)
1645        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1646        # woffMetadataLicensee
1647        ## no name
1648        info = dict(fontInfoVersion3)
1649        info["woffMetadataLicensee"] = dict()
1650        self._writeInfoToPlist(info)
1651        reader = UFOReader(self.dstDir, validate=True)
1652        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1653        ## unknown attribute
1654        info = dict(fontInfoVersion3)
1655        info["woffMetadataLicensee"] = dict(name="foo", notTheRightKey=1)
1656        self._writeInfoToPlist(info)
1657        reader = UFOReader(self.dstDir, validate=True)
1658        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1659        ## name not a string
1660        info = dict(fontInfoVersion3)
1661        info["woffMetadataLicensee"] = dict(name=1)
1662        self._writeInfoToPlist(info)
1663        reader = UFOReader(self.dstDir, validate=True)
1664        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1665        ## dir options
1666        info = dict(fontInfoVersion3)
1667        info["woffMetadataLicensee"] = dict(name="foo", dir="ltr")
1668        self._writeInfoToPlist(info)
1669        reader = UFOReader(self.dstDir, validate=True)
1670        reader.readInfo(TestInfoObject())
1671        info = dict(fontInfoVersion3)
1672        info["woffMetadataLicensee"] = dict(name="foo", dir="rtl")
1673        self._writeInfoToPlist(info)
1674        reader = UFOReader(self.dstDir, validate=True)
1675        reader.readInfo(TestInfoObject())
1676        ## dir not ltr or rtl
1677        info = dict(fontInfoVersion3)
1678        info["woffMetadataLicensee"] = dict(name="foo", dir="utd")
1679        self._writeInfoToPlist(info)
1680        reader = UFOReader(self.dstDir, validate=True)
1681        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1682        ## have class
1683        info = dict(fontInfoVersion3)
1684        info["woffMetadataLicensee"] = {"name": "foo", "class": "hello"}
1685        self._writeInfoToPlist(info)
1686        reader = UFOReader(self.dstDir, validate=True)
1687        reader.readInfo(TestInfoObject())
1688        ## class not a string
1689        info = dict(fontInfoVersion3)
1690        info["woffMetadataLicensee"] = {"name": "foo", "class": 1}
1691        self._writeInfoToPlist(info)
1692        reader = UFOReader(self.dstDir, validate=True)
1693        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1694
1695    def testGuidelinesRead(self):
1696        # x
1697        ## not an int or float
1698        info = dict(fontInfoVersion3)
1699        info["guidelines"] = [dict(x="1")]
1700        self._writeInfoToPlist(info)
1701        reader = UFOReader(self.dstDir, validate=True)
1702        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1703        # y
1704        ## not an int or float
1705        info = dict(fontInfoVersion3)
1706        info["guidelines"] = [dict(y="1")]
1707        self._writeInfoToPlist(info)
1708        reader = UFOReader(self.dstDir, validate=True)
1709        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1710        # angle
1711        ## < 0
1712        info = dict(fontInfoVersion3)
1713        info["guidelines"] = [dict(x=0, y=0, angle=-1)]
1714        self._writeInfoToPlist(info)
1715        reader = UFOReader(self.dstDir, validate=True)
1716        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1717        ## > 360
1718        info = dict(fontInfoVersion3)
1719        info["guidelines"] = [dict(x=0, y=0, angle=361)]
1720        self._writeInfoToPlist(info)
1721        reader = UFOReader(self.dstDir, validate=True)
1722        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1723        # name
1724        ## not a string
1725        info = dict(fontInfoVersion3)
1726        info["guidelines"] = [dict(x=0, name=1)]
1727        self._writeInfoToPlist(info)
1728        reader = UFOReader(self.dstDir, validate=True)
1729        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1730        # color
1731        ## not a string
1732        info = dict(fontInfoVersion3)
1733        info["guidelines"] = [dict(x=0, color=1)]
1734        self._writeInfoToPlist(info)
1735        reader = UFOReader(self.dstDir, validate=True)
1736        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1737        ## not enough commas
1738        info = dict(fontInfoVersion3)
1739        info["guidelines"] = [dict(x=0, color="1 0, 0, 0")]
1740        self._writeInfoToPlist(info)
1741        reader = UFOReader(self.dstDir, validate=True)
1742        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1743        info = dict(fontInfoVersion3)
1744        info["guidelines"] = [dict(x=0, color="1 0 0, 0")]
1745        self._writeInfoToPlist(info)
1746        reader = UFOReader(self.dstDir, validate=True)
1747        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1748        info = dict(fontInfoVersion3)
1749        info["guidelines"] = [dict(x=0, color="1 0 0 0")]
1750        self._writeInfoToPlist(info)
1751        reader = UFOReader(self.dstDir, validate=True)
1752        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1753        ## not enough parts
1754        info = dict(fontInfoVersion3)
1755        info["guidelines"] = [dict(x=0, color=", 0, 0, 0")]
1756        self._writeInfoToPlist(info)
1757        reader = UFOReader(self.dstDir, validate=True)
1758        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1759        info = dict(fontInfoVersion3)
1760        info["guidelines"] = [dict(x=0, color="1, , 0, 0")]
1761        self._writeInfoToPlist(info)
1762        reader = UFOReader(self.dstDir, validate=True)
1763        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1764        info = dict(fontInfoVersion3)
1765        info["guidelines"] = [dict(x=0, color="1, 0, , 0")]
1766        self._writeInfoToPlist(info)
1767        reader = UFOReader(self.dstDir, validate=True)
1768        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1769        info = dict(fontInfoVersion3)
1770        info["guidelines"] = [dict(x=0, color="1, 0, 0, ")]
1771        self._writeInfoToPlist(info)
1772        reader = UFOReader(self.dstDir, validate=True)
1773        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1774        info = dict(fontInfoVersion3)
1775        info["guidelines"] = [dict(x=0, color=", , , ")]
1776        self._writeInfoToPlist(info)
1777        reader = UFOReader(self.dstDir, validate=True)
1778        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1779        ## not a number in all positions
1780        info = dict(fontInfoVersion3)
1781        info["guidelines"] = [dict(x=0, color="r, 1, 1, 1")]
1782        self._writeInfoToPlist(info)
1783        reader = UFOReader(self.dstDir, validate=True)
1784        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1785        info = dict(fontInfoVersion3)
1786        info["guidelines"] = [dict(x=0, color="1, g, 1, 1")]
1787        self._writeInfoToPlist(info)
1788        reader = UFOReader(self.dstDir, validate=True)
1789        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1790        info = dict(fontInfoVersion3)
1791        info["guidelines"] = [dict(x=0, color="1, 1, b, 1")]
1792        self._writeInfoToPlist(info)
1793        reader = UFOReader(self.dstDir, validate=True)
1794        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1795        info = dict(fontInfoVersion3)
1796        info["guidelines"] = [dict(x=0, color="1, 1, 1, a")]
1797        self._writeInfoToPlist(info)
1798        reader = UFOReader(self.dstDir, validate=True)
1799        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1800        ## too many parts
1801        info = dict(fontInfoVersion3)
1802        info["guidelines"] = [dict(x=0, color="1, 0, 0, 0, 0")]
1803        self._writeInfoToPlist(info)
1804        reader = UFOReader(self.dstDir, validate=True)
1805        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1806        ## < 0 in each position
1807        info = dict(fontInfoVersion3)
1808        info["guidelines"] = [dict(x=0, color="-1, 0, 0, 0")]
1809        self._writeInfoToPlist(info)
1810        reader = UFOReader(self.dstDir, validate=True)
1811        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1812        info = dict(fontInfoVersion3)
1813        info["guidelines"] = [dict(x=0, color="0, -1, 0, 0")]
1814        self._writeInfoToPlist(info)
1815        reader = UFOReader(self.dstDir, validate=True)
1816        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1817        info = dict(fontInfoVersion3)
1818        info["guidelines"] = [dict(x=0, color="0, 0, -1, 0")]
1819        self._writeInfoToPlist(info)
1820        reader = UFOReader(self.dstDir, validate=True)
1821        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1822        info = dict(fontInfoVersion3)
1823        info["guidelines"] = [dict(x=0, color="0, 0, 0, -1")]
1824        self._writeInfoToPlist(info)
1825        reader = UFOReader(self.dstDir, validate=True)
1826        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1827        ## > 1 in each position
1828        info = dict(fontInfoVersion3)
1829        info["guidelines"] = [dict(x=0, color="2, 0, 0, 0")]
1830        self._writeInfoToPlist(info)
1831        reader = UFOReader(self.dstDir, validate=True)
1832        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1833        info = dict(fontInfoVersion3)
1834        info["guidelines"] = [dict(x=0, color="0, 2, 0, 0")]
1835        self._writeInfoToPlist(info)
1836        reader = UFOReader(self.dstDir, validate=True)
1837        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1838        info = dict(fontInfoVersion3)
1839        info["guidelines"] = [dict(x=0, color="0, 0, 2, 0")]
1840        self._writeInfoToPlist(info)
1841        reader = UFOReader(self.dstDir, validate=True)
1842        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1843        info = dict(fontInfoVersion3)
1844        info["guidelines"] = [dict(x=0, color="0, 0, 0, 2")]
1845        self._writeInfoToPlist(info)
1846        reader = UFOReader(self.dstDir, validate=True)
1847        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1848        # identifier
1849        ## duplicate
1850        info = dict(fontInfoVersion3)
1851        info["guidelines"] = [
1852            dict(x=0, identifier="guide1"),
1853            dict(y=0, identifier="guide1"),
1854        ]
1855        self._writeInfoToPlist(info)
1856        reader = UFOReader(self.dstDir, validate=True)
1857        self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject())
1858
1859
1860class WriteFontInfoVersion3TestCase(unittest.TestCase):
1861    def setUp(self):
1862        self.tempDir = tempfile.mktemp()
1863        os.mkdir(self.tempDir)
1864        self.dstDir = os.path.join(self.tempDir, "test.ufo")
1865
1866    def tearDown(self):
1867        shutil.rmtree(self.tempDir)
1868
1869    def tearDownUFO(self):
1870        if os.path.exists(self.dstDir):
1871            shutil.rmtree(self.dstDir)
1872
1873    def makeInfoObject(self):
1874        infoObject = TestInfoObject()
1875        for attr, value in list(fontInfoVersion3.items()):
1876            setattr(infoObject, attr, value)
1877        return infoObject
1878
1879    def readPlist(self):
1880        path = os.path.join(self.dstDir, "fontinfo.plist")
1881        with open(path, "rb") as f:
1882            plist = plistlib.load(f)
1883        return plist
1884
1885    def testWrite(self):
1886        infoObject = self.makeInfoObject()
1887        writer = UFOWriter(self.dstDir, formatVersion=3)
1888        writer.writeInfo(infoObject)
1889        writtenData = self.readPlist()
1890        for attr, originalValue in list(fontInfoVersion3.items()):
1891            newValue = writtenData[attr]
1892            self.assertEqual(newValue, originalValue)
1893        self.tearDownUFO()
1894
1895    def testGenericWrite(self):
1896        # familyName
1897        infoObject = self.makeInfoObject()
1898        infoObject.familyName = 123
1899        writer = UFOWriter(self.dstDir, formatVersion=3)
1900        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1901        self.tearDownUFO()
1902        # styleName
1903        infoObject = self.makeInfoObject()
1904        infoObject.styleName = 123
1905        writer = UFOWriter(self.dstDir, formatVersion=3)
1906        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1907        self.tearDownUFO()
1908        # styleMapFamilyName
1909        infoObject = self.makeInfoObject()
1910        infoObject.styleMapFamilyName = 123
1911        writer = UFOWriter(self.dstDir, formatVersion=3)
1912        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1913        self.tearDownUFO()
1914        # styleMapStyleName
1915        ## not a string
1916        infoObject = self.makeInfoObject()
1917        infoObject.styleMapStyleName = 123
1918        writer = UFOWriter(self.dstDir, formatVersion=3)
1919        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1920        self.tearDownUFO()
1921        ## out of range
1922        infoObject = self.makeInfoObject()
1923        infoObject.styleMapStyleName = "REGULAR"
1924        writer = UFOWriter(self.dstDir, formatVersion=3)
1925        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1926        self.tearDownUFO()
1927        # versionMajor
1928        infoObject = self.makeInfoObject()
1929        infoObject.versionMajor = "1"
1930        writer = UFOWriter(self.dstDir, formatVersion=3)
1931        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1932        self.tearDownUFO()
1933        # versionMinor
1934        infoObject = self.makeInfoObject()
1935        infoObject.versionMinor = "0"
1936        writer = UFOWriter(self.dstDir, formatVersion=3)
1937        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1938        self.tearDownUFO()
1939        # copyright
1940        infoObject = self.makeInfoObject()
1941        infoObject.copyright = 123
1942        writer = UFOWriter(self.dstDir, formatVersion=3)
1943        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1944        self.tearDownUFO()
1945        # trademark
1946        infoObject = self.makeInfoObject()
1947        infoObject.trademark = 123
1948        writer = UFOWriter(self.dstDir, formatVersion=3)
1949        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1950        self.tearDownUFO()
1951        # unitsPerEm
1952        infoObject = self.makeInfoObject()
1953        infoObject.unitsPerEm = "abc"
1954        writer = UFOWriter(self.dstDir, formatVersion=3)
1955        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1956        self.tearDownUFO()
1957        # descender
1958        infoObject = self.makeInfoObject()
1959        infoObject.descender = "abc"
1960        writer = UFOWriter(self.dstDir, formatVersion=3)
1961        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1962        self.tearDownUFO()
1963        # xHeight
1964        infoObject = self.makeInfoObject()
1965        infoObject.xHeight = "abc"
1966        writer = UFOWriter(self.dstDir, formatVersion=3)
1967        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1968        self.tearDownUFO()
1969        # capHeight
1970        infoObject = self.makeInfoObject()
1971        infoObject.capHeight = "abc"
1972        writer = UFOWriter(self.dstDir, formatVersion=3)
1973        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1974        self.tearDownUFO()
1975        # ascender
1976        infoObject = self.makeInfoObject()
1977        infoObject.ascender = "abc"
1978        writer = UFOWriter(self.dstDir, formatVersion=3)
1979        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1980        self.tearDownUFO()
1981        # italicAngle
1982        infoObject = self.makeInfoObject()
1983        infoObject.italicAngle = "abc"
1984        writer = UFOWriter(self.dstDir, formatVersion=3)
1985        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1986        self.tearDownUFO()
1987
1988    def testGaspWrite(self):
1989        # not a list
1990        infoObject = self.makeInfoObject()
1991        infoObject.openTypeGaspRangeRecords = "abc"
1992        writer = UFOWriter(self.dstDir, formatVersion=3)
1993        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
1994        self.tearDownUFO()
1995        # empty list
1996        infoObject = self.makeInfoObject()
1997        infoObject.openTypeGaspRangeRecords = []
1998        writer = UFOWriter(self.dstDir, formatVersion=3)
1999        writer.writeInfo(infoObject)
2000        self.tearDownUFO()
2001        # not a dict
2002        infoObject = self.makeInfoObject()
2003        infoObject.openTypeGaspRangeRecords = ["abc"]
2004        writer = UFOWriter(self.dstDir, formatVersion=3)
2005        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2006        self.tearDownUFO()
2007        # dict not properly formatted
2008        infoObject = self.makeInfoObject()
2009        infoObject.openTypeGaspRangeRecords = [
2010            dict(rangeMaxPPEM=0xFFFF, notTheRightKey=1)
2011        ]
2012        writer = UFOWriter(self.dstDir, formatVersion=3)
2013        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2014        self.tearDownUFO()
2015        infoObject = self.makeInfoObject()
2016        infoObject.openTypeGaspRangeRecords = [
2017            dict(notTheRightKey=1, rangeGaspBehavior=[0])
2018        ]
2019        writer = UFOWriter(self.dstDir, formatVersion=3)
2020        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2021        self.tearDownUFO()
2022        # not an int for ppem
2023        infoObject = self.makeInfoObject()
2024        infoObject.openTypeGaspRangeRecords = [
2025            dict(rangeMaxPPEM="abc", rangeGaspBehavior=[0]),
2026            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
2027        ]
2028        writer = UFOWriter(self.dstDir, formatVersion=3)
2029        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2030        self.tearDownUFO()
2031        # not a list for behavior
2032        infoObject = self.makeInfoObject()
2033        infoObject.openTypeGaspRangeRecords = [
2034            dict(rangeMaxPPEM=10, rangeGaspBehavior="abc"),
2035            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
2036        ]
2037        writer = UFOWriter(self.dstDir, formatVersion=3)
2038        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2039        self.tearDownUFO()
2040        # invalid behavior value
2041        infoObject = self.makeInfoObject()
2042        infoObject.openTypeGaspRangeRecords = [
2043            dict(rangeMaxPPEM=10, rangeGaspBehavior=[-1]),
2044            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
2045        ]
2046        writer = UFOWriter(self.dstDir, formatVersion=3)
2047        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2048        self.tearDownUFO()
2049        # not sorted
2050        infoObject = self.makeInfoObject()
2051        infoObject.openTypeGaspRangeRecords = [
2052            dict(rangeMaxPPEM=0xFFFF, rangeGaspBehavior=[0]),
2053            dict(rangeMaxPPEM=10, rangeGaspBehavior=[0]),
2054        ]
2055        writer = UFOWriter(self.dstDir, formatVersion=3)
2056        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2057        self.tearDownUFO()
2058        # no 0xFFFF
2059        infoObject = self.makeInfoObject()
2060        infoObject.openTypeGaspRangeRecords = [
2061            dict(rangeMaxPPEM=10, rangeGaspBehavior=[0]),
2062            dict(rangeMaxPPEM=20, rangeGaspBehavior=[0]),
2063        ]
2064        writer = UFOWriter(self.dstDir, formatVersion=3)
2065        writer.writeInfo(infoObject)
2066        self.tearDownUFO()
2067
2068    def testHeadWrite(self):
2069        # openTypeHeadCreated
2070        ## not a string
2071        infoObject = self.makeInfoObject()
2072        infoObject.openTypeHeadCreated = 123
2073        writer = UFOWriter(self.dstDir, formatVersion=3)
2074        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2075        self.tearDownUFO()
2076        ## invalid format
2077        infoObject = self.makeInfoObject()
2078        infoObject.openTypeHeadCreated = "2000-Jan-01 00:00:00"
2079        writer = UFOWriter(self.dstDir, formatVersion=3)
2080        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2081        self.tearDownUFO()
2082        # openTypeHeadLowestRecPPEM
2083        infoObject = self.makeInfoObject()
2084        infoObject.openTypeHeadLowestRecPPEM = "abc"
2085        writer = UFOWriter(self.dstDir, formatVersion=3)
2086        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2087        self.tearDownUFO()
2088        # openTypeHeadFlags
2089        infoObject = self.makeInfoObject()
2090        infoObject.openTypeHeadFlags = [-1]
2091        writer = UFOWriter(self.dstDir, formatVersion=3)
2092        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2093        self.tearDownUFO()
2094
2095    def testHheaWrite(self):
2096        # openTypeHheaAscender
2097        infoObject = self.makeInfoObject()
2098        infoObject.openTypeHheaAscender = "abc"
2099        writer = UFOWriter(self.dstDir, formatVersion=3)
2100        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2101        self.tearDownUFO()
2102        # openTypeHheaDescender
2103        infoObject = self.makeInfoObject()
2104        infoObject.openTypeHheaDescender = "abc"
2105        writer = UFOWriter(self.dstDir, formatVersion=3)
2106        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2107        self.tearDownUFO()
2108        # openTypeHheaLineGap
2109        infoObject = self.makeInfoObject()
2110        infoObject.openTypeHheaLineGap = "abc"
2111        writer = UFOWriter(self.dstDir, formatVersion=3)
2112        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2113        self.tearDownUFO()
2114        # openTypeHheaCaretSlopeRise
2115        infoObject = self.makeInfoObject()
2116        infoObject.openTypeHheaCaretSlopeRise = "abc"
2117        writer = UFOWriter(self.dstDir, formatVersion=3)
2118        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2119        self.tearDownUFO()
2120        # openTypeHheaCaretSlopeRun
2121        infoObject = self.makeInfoObject()
2122        infoObject.openTypeHheaCaretSlopeRun = "abc"
2123        writer = UFOWriter(self.dstDir, formatVersion=3)
2124        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2125        self.tearDownUFO()
2126        # openTypeHheaCaretOffset
2127        infoObject = self.makeInfoObject()
2128        infoObject.openTypeHheaCaretOffset = "abc"
2129        writer = UFOWriter(self.dstDir, formatVersion=3)
2130        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2131        self.tearDownUFO()
2132
2133    def testNameWrite(self):
2134        # openTypeNameDesigner
2135        infoObject = self.makeInfoObject()
2136        infoObject.openTypeNameDesigner = 123
2137        writer = UFOWriter(self.dstDir, formatVersion=3)
2138        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2139        self.tearDownUFO()
2140        # openTypeNameDesignerURL
2141        infoObject = self.makeInfoObject()
2142        infoObject.openTypeNameDesignerURL = 123
2143        writer = UFOWriter(self.dstDir, formatVersion=3)
2144        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2145        self.tearDownUFO()
2146        # openTypeNameManufacturer
2147        infoObject = self.makeInfoObject()
2148        infoObject.openTypeNameManufacturer = 123
2149        writer = UFOWriter(self.dstDir, formatVersion=3)
2150        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2151        self.tearDownUFO()
2152        # openTypeNameManufacturerURL
2153        infoObject = self.makeInfoObject()
2154        infoObject.openTypeNameManufacturerURL = 123
2155        writer = UFOWriter(self.dstDir, formatVersion=3)
2156        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2157        self.tearDownUFO()
2158        # openTypeNameLicense
2159        infoObject = self.makeInfoObject()
2160        infoObject.openTypeNameLicense = 123
2161        writer = UFOWriter(self.dstDir, formatVersion=3)
2162        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2163        self.tearDownUFO()
2164        # openTypeNameLicenseURL
2165        infoObject = self.makeInfoObject()
2166        infoObject.openTypeNameLicenseURL = 123
2167        writer = UFOWriter(self.dstDir, formatVersion=3)
2168        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2169        self.tearDownUFO()
2170        # openTypeNameVersion
2171        infoObject = self.makeInfoObject()
2172        infoObject.openTypeNameVersion = 123
2173        writer = UFOWriter(self.dstDir, formatVersion=3)
2174        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2175        self.tearDownUFO()
2176        # openTypeNameUniqueID
2177        infoObject = self.makeInfoObject()
2178        infoObject.openTypeNameUniqueID = 123
2179        writer = UFOWriter(self.dstDir, formatVersion=3)
2180        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2181        self.tearDownUFO()
2182        # openTypeNameDescription
2183        infoObject = self.makeInfoObject()
2184        infoObject.openTypeNameDescription = 123
2185        writer = UFOWriter(self.dstDir, formatVersion=3)
2186        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2187        self.tearDownUFO()
2188        # openTypeNamePreferredFamilyName
2189        infoObject = self.makeInfoObject()
2190        infoObject.openTypeNamePreferredFamilyName = 123
2191        writer = UFOWriter(self.dstDir, formatVersion=3)
2192        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2193        self.tearDownUFO()
2194        # openTypeNamePreferredSubfamilyName
2195        infoObject = self.makeInfoObject()
2196        infoObject.openTypeNamePreferredSubfamilyName = 123
2197        writer = UFOWriter(self.dstDir, formatVersion=3)
2198        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2199        self.tearDownUFO()
2200        # openTypeNameCompatibleFullName
2201        infoObject = self.makeInfoObject()
2202        infoObject.openTypeNameCompatibleFullName = 123
2203        writer = UFOWriter(self.dstDir, formatVersion=3)
2204        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2205        self.tearDownUFO()
2206        # openTypeNameSampleText
2207        infoObject = self.makeInfoObject()
2208        infoObject.openTypeNameSampleText = 123
2209        writer = UFOWriter(self.dstDir, formatVersion=3)
2210        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2211        self.tearDownUFO()
2212        # openTypeNameWWSFamilyName
2213        infoObject = self.makeInfoObject()
2214        infoObject.openTypeNameWWSFamilyName = 123
2215        writer = UFOWriter(self.dstDir, formatVersion=3)
2216        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2217        self.tearDownUFO()
2218        # openTypeNameWWSSubfamilyName
2219        infoObject = self.makeInfoObject()
2220        infoObject.openTypeNameWWSSubfamilyName = 123
2221        writer = UFOWriter(self.dstDir, formatVersion=3)
2222        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2223        self.tearDownUFO()
2224        # openTypeNameRecords
2225        ## not a list
2226        infoObject = self.makeInfoObject()
2227        infoObject.openTypeNameRecords = "abc"
2228        writer = UFOWriter(self.dstDir, formatVersion=3)
2229        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2230        self.tearDownUFO()
2231        ## not a dict
2232        infoObject = self.makeInfoObject()
2233        infoObject.openTypeNameRecords = ["abc"]
2234        writer = UFOWriter(self.dstDir, formatVersion=3)
2235        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2236        self.tearDownUFO()
2237        ## invalid dict structure
2238        infoObject = self.makeInfoObject()
2239        infoObject.openTypeNameRecords = [dict(foo="bar")]
2240        writer = UFOWriter(self.dstDir, formatVersion=3)
2241        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2242        self.tearDownUFO()
2243        ## incorrect keys
2244        infoObject = self.makeInfoObject()
2245        infoObject.openTypeNameRecords = [
2246            dict(
2247                nameID=1,
2248                platformID=1,
2249                encodingID=1,
2250                languageID=1,
2251                string="Name Record.",
2252                foo="bar",
2253            )
2254        ]
2255        writer = UFOWriter(self.dstDir, formatVersion=3)
2256        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2257        self.tearDownUFO()
2258        infoObject = self.makeInfoObject()
2259        infoObject.openTypeNameRecords = [
2260            dict(platformID=1, encodingID=1, languageID=1, string="Name Record.")
2261        ]
2262        writer = UFOWriter(self.dstDir, formatVersion=3)
2263        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2264        self.tearDownUFO()
2265        infoObject = self.makeInfoObject()
2266        infoObject.openTypeNameRecords = [
2267            dict(nameID=1, encodingID=1, languageID=1, string="Name Record.")
2268        ]
2269        writer = UFOWriter(self.dstDir, formatVersion=3)
2270        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2271        self.tearDownUFO()
2272        infoObject = self.makeInfoObject()
2273        infoObject.openTypeNameRecords = [
2274            dict(nameID=1, platformID=1, languageID=1, string="Name Record.")
2275        ]
2276        writer = UFOWriter(self.dstDir, formatVersion=3)
2277        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2278        self.tearDownUFO()
2279        infoObject = self.makeInfoObject()
2280        infoObject.openTypeNameRecords = [
2281            dict(nameID=1, platformID=1, encodingID=1, string="Name Record.")
2282        ]
2283        writer = UFOWriter(self.dstDir, formatVersion=3)
2284        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2285        self.tearDownUFO()
2286        infoObject = self.makeInfoObject()
2287        infoObject.openTypeNameRecords = [
2288            dict(nameID=1, platformID=1, encodingID=1, languageID=1)
2289        ]
2290        writer = UFOWriter(self.dstDir, formatVersion=3)
2291        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2292        self.tearDownUFO()
2293        ## invalid values
2294        infoObject = self.makeInfoObject()
2295        infoObject.openTypeNameRecords = [
2296            dict(
2297                nameID="1",
2298                platformID=1,
2299                encodingID=1,
2300                languageID=1,
2301                string="Name Record.",
2302            )
2303        ]
2304        writer = UFOWriter(self.dstDir, formatVersion=3)
2305        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2306        self.tearDownUFO()
2307        infoObject = self.makeInfoObject()
2308        infoObject.openTypeNameRecords = [
2309            dict(
2310                nameID=1,
2311                platformID="1",
2312                encodingID=1,
2313                languageID=1,
2314                string="Name Record.",
2315            )
2316        ]
2317        writer = UFOWriter(self.dstDir, formatVersion=3)
2318        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2319        self.tearDownUFO()
2320        infoObject = self.makeInfoObject()
2321        infoObject.openTypeNameRecords = [
2322            dict(
2323                nameID=1,
2324                platformID=1,
2325                encodingID="1",
2326                languageID=1,
2327                string="Name Record.",
2328            )
2329        ]
2330        writer = UFOWriter(self.dstDir, formatVersion=3)
2331        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2332        self.tearDownUFO()
2333        infoObject = self.makeInfoObject()
2334        infoObject.openTypeNameRecords = [
2335            dict(
2336                nameID=1,
2337                platformID=1,
2338                encodingID=1,
2339                languageID="1",
2340                string="Name Record.",
2341            )
2342        ]
2343        writer = UFOWriter(self.dstDir, formatVersion=3)
2344        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2345        self.tearDownUFO()
2346        infoObject = self.makeInfoObject()
2347        infoObject.openTypeNameRecords = [
2348            dict(nameID=1, platformID=1, encodingID=1, languageID=1, string=1)
2349        ]
2350        writer = UFOWriter(self.dstDir, formatVersion=3)
2351        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2352        self.tearDownUFO()
2353        ## duplicate
2354        infoObject = self.makeInfoObject()
2355        infoObject.openTypeNameRecords = [
2356            dict(
2357                nameID=1,
2358                platformID=1,
2359                encodingID=1,
2360                languageID=1,
2361                string="Name Record.",
2362            ),
2363            dict(
2364                nameID=1,
2365                platformID=1,
2366                encodingID=1,
2367                languageID=1,
2368                string="Name Record.",
2369            ),
2370        ]
2371        writer = UFOWriter(self.dstDir, formatVersion=3)
2372        writer.writeInfo(infoObject)
2373
2374    def testOS2Write(self):
2375        # openTypeOS2WidthClass
2376        ## not an int
2377        infoObject = self.makeInfoObject()
2378        infoObject.openTypeOS2WidthClass = "abc"
2379        writer = UFOWriter(self.dstDir, formatVersion=3)
2380        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2381        self.tearDownUFO()
2382        ## out or range
2383        infoObject = self.makeInfoObject()
2384        infoObject.openTypeOS2WidthClass = 15
2385        writer = UFOWriter(self.dstDir, formatVersion=3)
2386        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2387        self.tearDownUFO()
2388        # openTypeOS2WeightClass
2389        ## not an int
2390        infoObject = self.makeInfoObject()
2391        infoObject.openTypeOS2WeightClass = "abc"
2392        writer = UFOWriter(self.dstDir, formatVersion=3)
2393        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2394        self.tearDownUFO()
2395        ## out of range
2396        infoObject = self.makeInfoObject()
2397        infoObject.openTypeOS2WeightClass = -50
2398        writer = UFOWriter(self.dstDir, formatVersion=3)
2399        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2400        self.tearDownUFO()
2401        # openTypeOS2Selection
2402        infoObject = self.makeInfoObject()
2403        infoObject.openTypeOS2Selection = [-1]
2404        writer = UFOWriter(self.dstDir, formatVersion=3)
2405        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2406        self.tearDownUFO()
2407        # openTypeOS2VendorID
2408        infoObject = self.makeInfoObject()
2409        infoObject.openTypeOS2VendorID = 1234
2410        writer = UFOWriter(self.dstDir, formatVersion=3)
2411        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2412        self.tearDownUFO()
2413        # openTypeOS2Panose
2414        ## not an int
2415        infoObject = self.makeInfoObject()
2416        infoObject.openTypeOS2Panose = [0, 1, 2, 3, 4, 5, 6, 7, 8, str(9)]
2417        writer = UFOWriter(self.dstDir, formatVersion=3)
2418        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2419        self.tearDownUFO()
2420        ## too few values
2421        infoObject = self.makeInfoObject()
2422        infoObject.openTypeOS2Panose = [0, 1, 2, 3]
2423        writer = UFOWriter(self.dstDir, formatVersion=3)
2424        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2425        self.tearDownUFO()
2426        ## too many values
2427        infoObject = self.makeInfoObject()
2428        infoObject.openTypeOS2Panose = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
2429        writer = UFOWriter(self.dstDir, formatVersion=3)
2430        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2431        self.tearDownUFO()
2432        # openTypeOS2FamilyClass
2433        ## not an int
2434        infoObject = self.makeInfoObject()
2435        infoObject.openTypeOS2FamilyClass = [0, str(1)]
2436        writer = UFOWriter(self.dstDir, formatVersion=3)
2437        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2438        self.tearDownUFO()
2439        ## too few values
2440        infoObject = self.makeInfoObject()
2441        infoObject.openTypeOS2FamilyClass = [1]
2442        writer = UFOWriter(self.dstDir, formatVersion=3)
2443        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2444        self.tearDownUFO()
2445        ## too many values
2446        infoObject = self.makeInfoObject()
2447        infoObject.openTypeOS2FamilyClass = [1, 1, 1]
2448        writer = UFOWriter(self.dstDir, formatVersion=3)
2449        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2450        self.tearDownUFO()
2451        ## out of range
2452        infoObject = self.makeInfoObject()
2453        infoObject.openTypeOS2FamilyClass = [1, 20]
2454        writer = UFOWriter(self.dstDir, formatVersion=3)
2455        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2456        self.tearDownUFO()
2457        # openTypeOS2UnicodeRanges
2458        ## not an int
2459        infoObject = self.makeInfoObject()
2460        infoObject.openTypeOS2UnicodeRanges = ["0"]
2461        writer = UFOWriter(self.dstDir, formatVersion=3)
2462        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2463        self.tearDownUFO()
2464        ## out of range
2465        infoObject = self.makeInfoObject()
2466        infoObject.openTypeOS2UnicodeRanges = [-1]
2467        writer = UFOWriter(self.dstDir, formatVersion=3)
2468        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2469        self.tearDownUFO()
2470        # openTypeOS2CodePageRanges
2471        ## not an int
2472        infoObject = self.makeInfoObject()
2473        infoObject.openTypeOS2CodePageRanges = ["0"]
2474        writer = UFOWriter(self.dstDir, formatVersion=3)
2475        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2476        self.tearDownUFO()
2477        ## out of range
2478        infoObject = self.makeInfoObject()
2479        infoObject.openTypeOS2CodePageRanges = [-1]
2480        writer = UFOWriter(self.dstDir, formatVersion=3)
2481        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2482        self.tearDownUFO()
2483        # openTypeOS2TypoAscender
2484        infoObject = self.makeInfoObject()
2485        infoObject.openTypeOS2TypoAscender = "abc"
2486        writer = UFOWriter(self.dstDir, formatVersion=3)
2487        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2488        self.tearDownUFO()
2489        # openTypeOS2TypoDescender
2490        infoObject = self.makeInfoObject()
2491        infoObject.openTypeOS2TypoDescender = "abc"
2492        writer = UFOWriter(self.dstDir, formatVersion=3)
2493        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2494        self.tearDownUFO()
2495        # openTypeOS2TypoLineGap
2496        infoObject = self.makeInfoObject()
2497        infoObject.openTypeOS2TypoLineGap = "abc"
2498        writer = UFOWriter(self.dstDir, formatVersion=3)
2499        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2500        self.tearDownUFO()
2501        # openTypeOS2WinAscent
2502        infoObject = self.makeInfoObject()
2503        infoObject.openTypeOS2WinAscent = "abc"
2504        writer = UFOWriter(self.dstDir, formatVersion=3)
2505        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2506        self.tearDownUFO()
2507        infoObject = self.makeInfoObject()
2508        infoObject.openTypeOS2WinAscent = -1
2509        writer = UFOWriter(self.dstDir, formatVersion=3)
2510        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2511        self.tearDownUFO()
2512        # openTypeOS2WinDescent
2513        infoObject = self.makeInfoObject()
2514        infoObject.openTypeOS2WinDescent = "abc"
2515        writer = UFOWriter(self.dstDir, formatVersion=3)
2516        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2517        self.tearDownUFO()
2518        infoObject = self.makeInfoObject()
2519        infoObject.openTypeOS2WinDescent = -1
2520        writer = UFOWriter(self.dstDir, formatVersion=3)
2521        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2522        self.tearDownUFO()
2523        # openTypeOS2Type
2524        ## not an int
2525        infoObject = self.makeInfoObject()
2526        infoObject.openTypeOS2Type = ["1"]
2527        writer = UFOWriter(self.dstDir, formatVersion=3)
2528        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2529        self.tearDownUFO()
2530        ## out of range
2531        infoObject = self.makeInfoObject()
2532        infoObject.openTypeOS2Type = [-1]
2533        writer = UFOWriter(self.dstDir, formatVersion=3)
2534        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2535        self.tearDownUFO()
2536        # openTypeOS2SubscriptXSize
2537        infoObject = self.makeInfoObject()
2538        infoObject.openTypeOS2SubscriptXSize = "abc"
2539        writer = UFOWriter(self.dstDir, formatVersion=3)
2540        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2541        self.tearDownUFO()
2542        # openTypeOS2SubscriptYSize
2543        infoObject = self.makeInfoObject()
2544        infoObject.openTypeOS2SubscriptYSize = "abc"
2545        writer = UFOWriter(self.dstDir, formatVersion=3)
2546        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2547        self.tearDownUFO()
2548        # openTypeOS2SubscriptXOffset
2549        infoObject = self.makeInfoObject()
2550        infoObject.openTypeOS2SubscriptXOffset = "abc"
2551        writer = UFOWriter(self.dstDir, formatVersion=3)
2552        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2553        self.tearDownUFO()
2554        # openTypeOS2SubscriptYOffset
2555        infoObject = self.makeInfoObject()
2556        infoObject.openTypeOS2SubscriptYOffset = "abc"
2557        writer = UFOWriter(self.dstDir, formatVersion=3)
2558        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2559        self.tearDownUFO()
2560        # openTypeOS2SuperscriptXSize
2561        infoObject = self.makeInfoObject()
2562        infoObject.openTypeOS2SuperscriptXSize = "abc"
2563        writer = UFOWriter(self.dstDir, formatVersion=3)
2564        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2565        self.tearDownUFO()
2566        # openTypeOS2SuperscriptYSize
2567        infoObject = self.makeInfoObject()
2568        infoObject.openTypeOS2SuperscriptYSize = "abc"
2569        writer = UFOWriter(self.dstDir, formatVersion=3)
2570        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2571        self.tearDownUFO()
2572        # openTypeOS2SuperscriptXOffset
2573        infoObject = self.makeInfoObject()
2574        infoObject.openTypeOS2SuperscriptXOffset = "abc"
2575        writer = UFOWriter(self.dstDir, formatVersion=3)
2576        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2577        self.tearDownUFO()
2578        # openTypeOS2SuperscriptYOffset
2579        infoObject = self.makeInfoObject()
2580        infoObject.openTypeOS2SuperscriptYOffset = "abc"
2581        writer = UFOWriter(self.dstDir, formatVersion=3)
2582        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2583        self.tearDownUFO()
2584        # openTypeOS2StrikeoutSize
2585        infoObject = self.makeInfoObject()
2586        infoObject.openTypeOS2StrikeoutSize = "abc"
2587        writer = UFOWriter(self.dstDir, formatVersion=3)
2588        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2589        self.tearDownUFO()
2590        # openTypeOS2StrikeoutPosition
2591        infoObject = self.makeInfoObject()
2592        infoObject.openTypeOS2StrikeoutPosition = "abc"
2593        writer = UFOWriter(self.dstDir, formatVersion=3)
2594        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2595        self.tearDownUFO()
2596
2597    def testVheaWrite(self):
2598        # openTypeVheaVertTypoAscender
2599        infoObject = self.makeInfoObject()
2600        infoObject.openTypeVheaVertTypoAscender = "abc"
2601        writer = UFOWriter(self.dstDir, formatVersion=3)
2602        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2603        self.tearDownUFO()
2604        # openTypeVheaVertTypoDescender
2605        infoObject = self.makeInfoObject()
2606        infoObject.openTypeVheaVertTypoDescender = "abc"
2607        writer = UFOWriter(self.dstDir, formatVersion=3)
2608        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2609        self.tearDownUFO()
2610        # openTypeVheaVertTypoLineGap
2611        infoObject = self.makeInfoObject()
2612        infoObject.openTypeVheaVertTypoLineGap = "abc"
2613        writer = UFOWriter(self.dstDir, formatVersion=3)
2614        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2615        self.tearDownUFO()
2616        # openTypeVheaCaretSlopeRise
2617        infoObject = self.makeInfoObject()
2618        infoObject.openTypeVheaCaretSlopeRise = "abc"
2619        writer = UFOWriter(self.dstDir, formatVersion=3)
2620        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2621        self.tearDownUFO()
2622        # openTypeVheaCaretSlopeRun
2623        infoObject = self.makeInfoObject()
2624        infoObject.openTypeVheaCaretSlopeRun = "abc"
2625        writer = UFOWriter(self.dstDir, formatVersion=3)
2626        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2627        self.tearDownUFO()
2628        # openTypeVheaCaretOffset
2629        infoObject = self.makeInfoObject()
2630        infoObject.openTypeVheaCaretOffset = "abc"
2631        writer = UFOWriter(self.dstDir, formatVersion=3)
2632        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2633        self.tearDownUFO()
2634
2635    def testFONDWrite(self):
2636        # macintoshFONDFamilyID
2637        infoObject = self.makeInfoObject()
2638        infoObject.macintoshFONDFamilyID = "abc"
2639        writer = UFOWriter(self.dstDir, formatVersion=3)
2640        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2641        self.tearDownUFO()
2642        # macintoshFONDName
2643        infoObject = self.makeInfoObject()
2644        infoObject.macintoshFONDName = 123
2645        writer = UFOWriter(self.dstDir, formatVersion=3)
2646        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2647        self.tearDownUFO()
2648
2649    def testPostscriptWrite(self):
2650        # postscriptFontName
2651        infoObject = self.makeInfoObject()
2652        infoObject.postscriptFontName = 123
2653        writer = UFOWriter(self.dstDir, formatVersion=3)
2654        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2655        self.tearDownUFO()
2656        # postscriptFullName
2657        infoObject = self.makeInfoObject()
2658        infoObject.postscriptFullName = 123
2659        writer = UFOWriter(self.dstDir, formatVersion=3)
2660        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2661        self.tearDownUFO()
2662        # postscriptSlantAngle
2663        infoObject = self.makeInfoObject()
2664        infoObject.postscriptSlantAngle = "abc"
2665        writer = UFOWriter(self.dstDir, formatVersion=3)
2666        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2667        self.tearDownUFO()
2668        # postscriptUniqueID
2669        infoObject = self.makeInfoObject()
2670        infoObject.postscriptUniqueID = "abc"
2671        writer = UFOWriter(self.dstDir, formatVersion=3)
2672        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2673        self.tearDownUFO()
2674        # postscriptUnderlineThickness
2675        infoObject = self.makeInfoObject()
2676        infoObject.postscriptUnderlineThickness = "abc"
2677        writer = UFOWriter(self.dstDir, formatVersion=3)
2678        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2679        self.tearDownUFO()
2680        # postscriptUnderlinePosition
2681        infoObject = self.makeInfoObject()
2682        infoObject.postscriptUnderlinePosition = "abc"
2683        writer = UFOWriter(self.dstDir, formatVersion=3)
2684        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2685        self.tearDownUFO()
2686        # postscriptIsFixedPitch
2687        infoObject = self.makeInfoObject()
2688        infoObject.postscriptIsFixedPitch = 2
2689        writer = UFOWriter(self.dstDir, formatVersion=3)
2690        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2691        self.tearDownUFO()
2692        # postscriptBlueValues
2693        ## not a list
2694        infoObject = self.makeInfoObject()
2695        infoObject.postscriptBlueValues = "abc"
2696        writer = UFOWriter(self.dstDir, formatVersion=3)
2697        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2698        self.tearDownUFO()
2699        ## uneven value count
2700        infoObject = self.makeInfoObject()
2701        infoObject.postscriptBlueValues = [500]
2702        writer = UFOWriter(self.dstDir, formatVersion=3)
2703        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2704        self.tearDownUFO()
2705        ## too many values
2706        infoObject = self.makeInfoObject()
2707        infoObject.postscriptBlueValues = [
2708            10,
2709            20,
2710            30,
2711            40,
2712            50,
2713            60,
2714            70,
2715            80,
2716            90,
2717            100,
2718            110,
2719            120,
2720            130,
2721            140,
2722            150,
2723            160,
2724        ]
2725        writer = UFOWriter(self.dstDir, formatVersion=3)
2726        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2727        self.tearDownUFO()
2728        # postscriptOtherBlues
2729        ## not a list
2730        infoObject = self.makeInfoObject()
2731        infoObject.postscriptOtherBlues = "abc"
2732        writer = UFOWriter(self.dstDir, formatVersion=3)
2733        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2734        self.tearDownUFO()
2735        ## uneven value count
2736        infoObject = self.makeInfoObject()
2737        infoObject.postscriptOtherBlues = [500]
2738        writer = UFOWriter(self.dstDir, formatVersion=3)
2739        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2740        self.tearDownUFO()
2741        ## too many values
2742        infoObject = self.makeInfoObject()
2743        infoObject.postscriptOtherBlues = [
2744            10,
2745            20,
2746            30,
2747            40,
2748            50,
2749            60,
2750            70,
2751            80,
2752            90,
2753            100,
2754            110,
2755            120,
2756            130,
2757            140,
2758            150,
2759            160,
2760        ]
2761        writer = UFOWriter(self.dstDir, formatVersion=3)
2762        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2763        self.tearDownUFO()
2764        # postscriptFamilyBlues
2765        ## not a list
2766        infoObject = self.makeInfoObject()
2767        infoObject.postscriptFamilyBlues = "abc"
2768        writer = UFOWriter(self.dstDir, formatVersion=3)
2769        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2770        self.tearDownUFO()
2771        ## uneven value count
2772        infoObject = self.makeInfoObject()
2773        infoObject.postscriptFamilyBlues = [500]
2774        writer = UFOWriter(self.dstDir, formatVersion=3)
2775        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2776        self.tearDownUFO()
2777        ## too many values
2778        infoObject = self.makeInfoObject()
2779        infoObject.postscriptFamilyBlues = [
2780            10,
2781            20,
2782            30,
2783            40,
2784            50,
2785            60,
2786            70,
2787            80,
2788            90,
2789            100,
2790            110,
2791            120,
2792            130,
2793            140,
2794            150,
2795            160,
2796        ]
2797        writer = UFOWriter(self.dstDir, formatVersion=3)
2798        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2799        self.tearDownUFO()
2800        # postscriptFamilyOtherBlues
2801        ## not a list
2802        infoObject = self.makeInfoObject()
2803        infoObject.postscriptFamilyOtherBlues = "abc"
2804        writer = UFOWriter(self.dstDir, formatVersion=3)
2805        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2806        self.tearDownUFO()
2807        ## uneven value count
2808        infoObject = self.makeInfoObject()
2809        infoObject.postscriptFamilyOtherBlues = [500]
2810        writer = UFOWriter(self.dstDir, formatVersion=3)
2811        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2812        self.tearDownUFO()
2813        ## too many values
2814        infoObject = self.makeInfoObject()
2815        infoObject.postscriptFamilyOtherBlues = [
2816            10,
2817            20,
2818            30,
2819            40,
2820            50,
2821            60,
2822            70,
2823            80,
2824            90,
2825            100,
2826            110,
2827            120,
2828            130,
2829            140,
2830            150,
2831            160,
2832        ]
2833        writer = UFOWriter(self.dstDir, formatVersion=3)
2834        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2835        self.tearDownUFO()
2836        # postscriptStemSnapH
2837        ## not list
2838        infoObject = self.makeInfoObject()
2839        infoObject.postscriptStemSnapH = "abc"
2840        writer = UFOWriter(self.dstDir, formatVersion=3)
2841        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2842        self.tearDownUFO()
2843        ## too many values
2844        infoObject = self.makeInfoObject()
2845        infoObject.postscriptStemSnapH = [
2846            10,
2847            20,
2848            30,
2849            40,
2850            50,
2851            60,
2852            70,
2853            80,
2854            90,
2855            100,
2856            110,
2857            120,
2858            130,
2859            140,
2860            150,
2861            160,
2862        ]
2863        writer = UFOWriter(self.dstDir, formatVersion=3)
2864        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2865        self.tearDownUFO()
2866        # postscriptStemSnapV
2867        ## not list
2868        infoObject = self.makeInfoObject()
2869        infoObject.postscriptStemSnapV = "abc"
2870        writer = UFOWriter(self.dstDir, formatVersion=3)
2871        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2872        self.tearDownUFO()
2873        ## too many values
2874        infoObject = self.makeInfoObject()
2875        infoObject.postscriptStemSnapV = [
2876            10,
2877            20,
2878            30,
2879            40,
2880            50,
2881            60,
2882            70,
2883            80,
2884            90,
2885            100,
2886            110,
2887            120,
2888            130,
2889            140,
2890            150,
2891            160,
2892        ]
2893        writer = UFOWriter(self.dstDir, formatVersion=3)
2894        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2895        self.tearDownUFO()
2896        # postscriptBlueFuzz
2897        infoObject = self.makeInfoObject()
2898        infoObject.postscriptBlueFuzz = "abc"
2899        writer = UFOWriter(self.dstDir, formatVersion=3)
2900        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2901        self.tearDownUFO()
2902        # postscriptBlueShift
2903        infoObject = self.makeInfoObject()
2904        infoObject.postscriptBlueShift = "abc"
2905        writer = UFOWriter(self.dstDir, formatVersion=3)
2906        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2907        self.tearDownUFO()
2908        # postscriptBlueScale
2909        infoObject = self.makeInfoObject()
2910        infoObject.postscriptBlueScale = "abc"
2911        writer = UFOWriter(self.dstDir, formatVersion=3)
2912        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2913        self.tearDownUFO()
2914        # postscriptForceBold
2915        infoObject = self.makeInfoObject()
2916        infoObject.postscriptForceBold = "abc"
2917        writer = UFOWriter(self.dstDir, formatVersion=3)
2918        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2919        self.tearDownUFO()
2920        # postscriptDefaultWidthX
2921        infoObject = self.makeInfoObject()
2922        infoObject.postscriptDefaultWidthX = "abc"
2923        writer = UFOWriter(self.dstDir, formatVersion=3)
2924        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2925        self.tearDownUFO()
2926        # postscriptNominalWidthX
2927        infoObject = self.makeInfoObject()
2928        infoObject.postscriptNominalWidthX = "abc"
2929        writer = UFOWriter(self.dstDir, formatVersion=3)
2930        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2931        self.tearDownUFO()
2932        # postscriptWeightName
2933        infoObject = self.makeInfoObject()
2934        infoObject.postscriptWeightName = 123
2935        writer = UFOWriter(self.dstDir, formatVersion=3)
2936        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2937        self.tearDownUFO()
2938        # postscriptDefaultCharacter
2939        infoObject = self.makeInfoObject()
2940        infoObject.postscriptDefaultCharacter = 123
2941        writer = UFOWriter(self.dstDir, formatVersion=3)
2942        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2943        self.tearDownUFO()
2944        # postscriptWindowsCharacterSet
2945        infoObject = self.makeInfoObject()
2946        infoObject.postscriptWindowsCharacterSet = -1
2947        writer = UFOWriter(self.dstDir, formatVersion=3)
2948        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2949        self.tearDownUFO()
2950        # macintoshFONDFamilyID
2951        infoObject = self.makeInfoObject()
2952        infoObject.macintoshFONDFamilyID = "abc"
2953        writer = UFOWriter(self.dstDir, formatVersion=3)
2954        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2955        self.tearDownUFO()
2956        # macintoshFONDName
2957        infoObject = self.makeInfoObject()
2958        infoObject.macintoshFONDName = 123
2959        writer = UFOWriter(self.dstDir, formatVersion=3)
2960        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2961        self.tearDownUFO()
2962
2963    def testWOFFWrite(self):
2964        # woffMajorVersion
2965        infoObject = self.makeInfoObject()
2966        infoObject.woffMajorVersion = 1.0
2967        writer = UFOWriter(self.dstDir, formatVersion=3)
2968        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2969        self.tearDownUFO()
2970        infoObject = self.makeInfoObject()
2971        infoObject.woffMajorVersion = "abc"
2972        writer = UFOWriter(self.dstDir, formatVersion=3)
2973        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2974        self.tearDownUFO()
2975        # woffMinorVersion
2976        infoObject = self.makeInfoObject()
2977        infoObject.woffMinorVersion = 1.0
2978        writer = UFOWriter(self.dstDir, formatVersion=3)
2979        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2980        self.tearDownUFO()
2981        infoObject = self.makeInfoObject()
2982        infoObject.woffMinorVersion = "abc"
2983        writer = UFOWriter(self.dstDir, formatVersion=3)
2984        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2985        self.tearDownUFO()
2986        # woffMetadataUniqueID
2987        ## none
2988        infoObject = self.makeInfoObject()
2989        infoObject.woffMetadataUniqueID = None
2990        writer = UFOWriter(self.dstDir, formatVersion=3)
2991        writer.writeInfo(infoObject)
2992        self.tearDownUFO()
2993        ## not a dict
2994        infoObject = self.makeInfoObject()
2995        infoObject.woffMetadataUniqueID = 1
2996        writer = UFOWriter(self.dstDir, formatVersion=3)
2997        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
2998        self.tearDownUFO()
2999        ## unknown key
3000        infoObject = self.makeInfoObject()
3001        infoObject.woffMetadataUniqueID = dict(id="foo", notTheRightKey=1)
3002        writer = UFOWriter(self.dstDir, formatVersion=3)
3003        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3004        self.tearDownUFO()
3005        ## no id
3006        infoObject = self.makeInfoObject()
3007        infoObject.woffMetadataUniqueID = dict()
3008        writer = UFOWriter(self.dstDir, formatVersion=3)
3009        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3010        self.tearDownUFO()
3011        ## not a string for id
3012        infoObject = self.makeInfoObject()
3013        infoObject.woffMetadataUniqueID = dict(id=1)
3014        writer = UFOWriter(self.dstDir, formatVersion=3)
3015        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3016        self.tearDownUFO()
3017        ## empty string
3018        infoObject = self.makeInfoObject()
3019        infoObject.woffMetadataUniqueID = dict(id="")
3020        writer = UFOWriter(self.dstDir, formatVersion=3)
3021        writer.writeInfo(infoObject)
3022        self.tearDownUFO()
3023        # woffMetadataVendor
3024        ## no name
3025        infoObject = self.makeInfoObject()
3026        infoObject.woffMetadataVendor = dict(url="foo")
3027        writer = UFOWriter(self.dstDir, formatVersion=3)
3028        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3029        self.tearDownUFO()
3030        ## name not a string
3031        infoObject = self.makeInfoObject()
3032        infoObject.woffMetadataVendor = dict(name=1, url="foo")
3033        writer = UFOWriter(self.dstDir, formatVersion=3)
3034        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3035        self.tearDownUFO()
3036        ## name an empty string
3037        infoObject = self.makeInfoObject()
3038        infoObject.woffMetadataVendor = dict(name="", url="foo")
3039        writer = UFOWriter(self.dstDir, formatVersion=3)
3040        writer.writeInfo(infoObject)
3041        self.tearDownUFO()
3042        ## no URL
3043        infoObject = self.makeInfoObject()
3044        infoObject.woffMetadataVendor = dict(name="foo")
3045        writer = UFOWriter(self.dstDir, formatVersion=3)
3046        writer.writeInfo(infoObject)
3047        self.tearDownUFO()
3048        ## url not a string
3049        infoObject = self.makeInfoObject()
3050        infoObject.woffMetadataVendor = dict(name="foo", url=1)
3051        writer = UFOWriter(self.dstDir, formatVersion=3)
3052        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3053        self.tearDownUFO()
3054        ## url empty string
3055        infoObject = self.makeInfoObject()
3056        infoObject.woffMetadataVendor = dict(name="foo", url="")
3057        writer = UFOWriter(self.dstDir, formatVersion=3)
3058        writer.writeInfo(infoObject)
3059        self.tearDownUFO()
3060        ## have dir
3061        infoObject = self.makeInfoObject()
3062        infoObject.woffMetadataVendor = dict(name="foo", url="bar", dir="ltr")
3063        writer = UFOWriter(self.dstDir, formatVersion=3)
3064        writer.writeInfo(infoObject)
3065        self.tearDownUFO()
3066        infoObject = self.makeInfoObject()
3067        infoObject.woffMetadataVendor = dict(name="foo", url="bar", dir="rtl")
3068        writer = UFOWriter(self.dstDir, formatVersion=3)
3069        writer.writeInfo(infoObject)
3070        self.tearDownUFO()
3071        ## dir not a string
3072        infoObject = self.makeInfoObject()
3073        infoObject.woffMetadataVendor = dict(name="foo", url="bar", dir=1)
3074        writer = UFOWriter(self.dstDir, formatVersion=3)
3075        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3076        self.tearDownUFO()
3077        ## dir not ltr or rtl
3078        infoObject = self.makeInfoObject()
3079        infoObject.woffMetadataVendor = dict(name="foo", url="bar", dir="utd")
3080        writer = UFOWriter(self.dstDir, formatVersion=3)
3081        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3082        self.tearDownUFO()
3083        ## have class
3084        infoObject = self.makeInfoObject()
3085        infoObject.woffMetadataVendor = {"name": "foo", "url": "bar", "class": "hello"}
3086        writer = UFOWriter(self.dstDir, formatVersion=3)
3087        writer.writeInfo(infoObject)
3088        self.tearDownUFO()
3089        ## class not a string
3090        infoObject = self.makeInfoObject()
3091        infoObject.woffMetadataVendor = {"name": "foo", "url": "bar", "class": 1}
3092        writer = UFOWriter(self.dstDir, formatVersion=3)
3093        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3094        self.tearDownUFO()
3095        ## class empty string
3096        infoObject = self.makeInfoObject()
3097        infoObject.woffMetadataVendor = {"name": "foo", "url": "bar", "class": ""}
3098        writer = UFOWriter(self.dstDir, formatVersion=3)
3099        writer.writeInfo(infoObject)
3100        self.tearDownUFO()
3101        # woffMetadataCredits
3102        ## no credits attribute
3103        infoObject = self.makeInfoObject()
3104        infoObject.woffMetadataCredits = {}
3105        writer = UFOWriter(self.dstDir, formatVersion=3)
3106        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3107        self.tearDownUFO()
3108        ## unknown attribute
3109        infoObject = self.makeInfoObject()
3110        infoObject.woffMetadataCredits = dict(
3111            credits=[dict(name="foo")], notTheRightKey=1
3112        )
3113        writer = UFOWriter(self.dstDir, formatVersion=3)
3114        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3115        self.tearDownUFO()
3116        ## not a list
3117        infoObject = self.makeInfoObject()
3118        infoObject.woffMetadataCredits = dict(credits="abc")
3119        writer = UFOWriter(self.dstDir, formatVersion=3)
3120        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3121        self.tearDownUFO()
3122        ## no elements in credits
3123        infoObject = self.makeInfoObject()
3124        infoObject.woffMetadataCredits = dict(credits=[])
3125        writer = UFOWriter(self.dstDir, formatVersion=3)
3126        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3127        self.tearDownUFO()
3128        ## credit not a dict
3129        infoObject = self.makeInfoObject()
3130        infoObject.woffMetadataCredits = dict(credits=["abc"])
3131        writer = UFOWriter(self.dstDir, formatVersion=3)
3132        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3133        self.tearDownUFO()
3134        ## unknown key
3135        infoObject = self.makeInfoObject()
3136        infoObject.woffMetadataCredits = dict(
3137            credits=[dict(name="foo", notTheRightKey=1)]
3138        )
3139        writer = UFOWriter(self.dstDir, formatVersion=3)
3140        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3141        self.tearDownUFO()
3142        ## no name
3143        infoObject = self.makeInfoObject()
3144        infoObject.woffMetadataCredits = dict(credits=[dict(url="foo")])
3145        writer = UFOWriter(self.dstDir, formatVersion=3)
3146        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3147        self.tearDownUFO()
3148        ## name not a string
3149        infoObject = self.makeInfoObject()
3150        infoObject.woffMetadataCredits = dict(credits=[dict(name=1)])
3151        writer = UFOWriter(self.dstDir, formatVersion=3)
3152        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3153        self.tearDownUFO()
3154        ## url not a string
3155        infoObject = self.makeInfoObject()
3156        infoObject.woffMetadataCredits = dict(credits=[dict(name="foo", url=1)])
3157        writer = UFOWriter(self.dstDir, formatVersion=3)
3158        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3159        self.tearDownUFO()
3160        ## role not a string
3161        infoObject = self.makeInfoObject()
3162        infoObject.woffMetadataCredits = dict(credits=[dict(name="foo", role=1)])
3163        writer = UFOWriter(self.dstDir, formatVersion=3)
3164        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3165        self.tearDownUFO()
3166        ## dir not a string
3167        infoObject = self.makeInfoObject()
3168        infoObject.woffMetadataCredits = dict(credits=[dict(name="foo", dir=1)])
3169        writer = UFOWriter(self.dstDir, formatVersion=3)
3170        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3171        self.tearDownUFO()
3172        ## dir not ltr or rtl
3173        infoObject = self.makeInfoObject()
3174        infoObject.woffMetadataCredits = dict(credits=[dict(name="foo", dir="utd")])
3175        writer = UFOWriter(self.dstDir, formatVersion=3)
3176        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3177        self.tearDownUFO()
3178        ## class not a string
3179        infoObject = self.makeInfoObject()
3180        infoObject.woffMetadataCredits = dict(credits=[{"name": "foo", "class": 1}])
3181        writer = UFOWriter(self.dstDir, formatVersion=3)
3182        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3183        self.tearDownUFO()
3184        # woffMetadataDescription
3185        ## no url
3186        infoObject = self.makeInfoObject()
3187        infoObject.woffMetadataDescription = dict(text=[dict(text="foo")])
3188        writer = UFOWriter(self.dstDir, formatVersion=3)
3189        writer.writeInfo(infoObject)
3190        self.tearDownUFO()
3191        ## url not a string
3192        infoObject = self.makeInfoObject()
3193        infoObject.woffMetadataDescription = dict(text=[dict(text="foo")], url=1)
3194        writer = UFOWriter(self.dstDir, formatVersion=3)
3195        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3196        self.tearDownUFO()
3197        ## no text
3198        infoObject = self.makeInfoObject()
3199        infoObject.woffMetadataDescription = dict(url="foo")
3200        writer = UFOWriter(self.dstDir, formatVersion=3)
3201        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3202        self.tearDownUFO()
3203        ## text not a list
3204        infoObject = self.makeInfoObject()
3205        infoObject.woffMetadataDescription = dict(text="abc")
3206        writer = UFOWriter(self.dstDir, formatVersion=3)
3207        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3208        self.tearDownUFO()
3209        ## text item not a dict
3210        infoObject = self.makeInfoObject()
3211        infoObject.woffMetadataDescription = dict(text=["abc"])
3212        writer = UFOWriter(self.dstDir, formatVersion=3)
3213        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3214        self.tearDownUFO()
3215        ## text item unknown key
3216        infoObject = self.makeInfoObject()
3217        infoObject.woffMetadataDescription = dict(
3218            text=[dict(text="foo", notTheRightKey=1)]
3219        )
3220        writer = UFOWriter(self.dstDir, formatVersion=3)
3221        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3222        self.tearDownUFO()
3223        ## text item missing text
3224        infoObject = self.makeInfoObject()
3225        infoObject.woffMetadataDescription = dict(text=[dict(language="foo")])
3226        writer = UFOWriter(self.dstDir, formatVersion=3)
3227        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3228        self.tearDownUFO()
3229        ## text not a string
3230        infoObject = self.makeInfoObject()
3231        infoObject.woffMetadataDescription = dict(text=[dict(text=1)])
3232        writer = UFOWriter(self.dstDir, formatVersion=3)
3233        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3234        self.tearDownUFO()
3235        ## url not a string
3236        infoObject = self.makeInfoObject()
3237        infoObject.woffMetadataDescription = dict(text=[dict(text="foo", url=1)])
3238        writer = UFOWriter(self.dstDir, formatVersion=3)
3239        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3240        self.tearDownUFO()
3241        ## language not a string
3242        infoObject = self.makeInfoObject()
3243        infoObject.woffMetadataDescription = dict(text=[dict(text="foo", language=1)])
3244        writer = UFOWriter(self.dstDir, formatVersion=3)
3245        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3246        self.tearDownUFO()
3247        ## dir not ltr or rtl
3248        infoObject = self.makeInfoObject()
3249        infoObject.woffMetadataDescription = dict(text=[dict(text="foo", dir="utd")])
3250        writer = UFOWriter(self.dstDir, formatVersion=3)
3251        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3252        self.tearDownUFO()
3253        ## class not a string
3254        infoObject = self.makeInfoObject()
3255        infoObject.woffMetadataDescription = dict(text=[{"text": "foo", "class": 1}])
3256        writer = UFOWriter(self.dstDir, formatVersion=3)
3257        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3258        self.tearDownUFO()
3259        # woffMetadataLicense
3260        ## no url
3261        infoObject = self.makeInfoObject()
3262        infoObject.woffMetadataLicense = dict(text=[dict(text="foo")])
3263        writer = UFOWriter(self.dstDir, formatVersion=3)
3264        writer.writeInfo(infoObject)
3265        self.tearDownUFO()
3266        ## url not a string
3267        infoObject = self.makeInfoObject()
3268        infoObject.woffMetadataLicense = dict(text=[dict(text="foo")], url=1)
3269        writer = UFOWriter(self.dstDir, formatVersion=3)
3270        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3271        self.tearDownUFO()
3272        ## id not a string
3273        infoObject = self.makeInfoObject()
3274        infoObject.woffMetadataLicense = dict(text=[dict(text="foo")], id=1)
3275        writer = UFOWriter(self.dstDir, formatVersion=3)
3276        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3277        self.tearDownUFO()
3278        ## no text
3279        infoObject = self.makeInfoObject()
3280        infoObject.woffMetadataLicense = dict(url="foo")
3281        writer = UFOWriter(self.dstDir, formatVersion=3)
3282        writer.writeInfo(infoObject)
3283        self.tearDownUFO()
3284        ## text not a list
3285        infoObject = self.makeInfoObject()
3286        infoObject.woffMetadataLicense = dict(text="abc")
3287        writer = UFOWriter(self.dstDir, formatVersion=3)
3288        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3289        self.tearDownUFO()
3290        ## text item not a dict
3291        infoObject = self.makeInfoObject()
3292        infoObject.woffMetadataLicense = dict(text=["abc"])
3293        writer = UFOWriter(self.dstDir, formatVersion=3)
3294        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3295        self.tearDownUFO()
3296        ## text item unknown key
3297        infoObject = self.makeInfoObject()
3298        infoObject.woffMetadataLicense = dict(text=[dict(text="foo", notTheRightKey=1)])
3299        writer = UFOWriter(self.dstDir, formatVersion=3)
3300        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3301        self.tearDownUFO()
3302        ## text item missing text
3303        infoObject = self.makeInfoObject()
3304        writer = UFOWriter(self.dstDir, formatVersion=3)
3305        infoObject.woffMetadataLicense = dict(text=[dict(language="foo")])
3306        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3307        self.tearDownUFO()
3308        ## text not a string
3309        infoObject = self.makeInfoObject()
3310        writer = UFOWriter(self.dstDir, formatVersion=3)
3311        infoObject.woffMetadataLicense = dict(text=[dict(text=1)])
3312        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3313        self.tearDownUFO()
3314        ## url not a string
3315        infoObject = self.makeInfoObject()
3316        writer = UFOWriter(self.dstDir, formatVersion=3)
3317        infoObject.woffMetadataLicense = dict(text=[dict(text="foo", url=1)])
3318        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3319        self.tearDownUFO()
3320        ## language not a string
3321        infoObject = self.makeInfoObject()
3322        writer = UFOWriter(self.dstDir, formatVersion=3)
3323        infoObject.woffMetadataLicense = dict(text=[dict(text="foo", language=1)])
3324        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3325        self.tearDownUFO()
3326        ## dir not ltr or rtl
3327        infoObject = self.makeInfoObject()
3328        writer = UFOWriter(self.dstDir, formatVersion=3)
3329        infoObject.woffMetadataLicense = dict(text=[dict(text="foo", dir="utd")])
3330        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3331        self.tearDownUFO()
3332        ## class not a string
3333        infoObject = self.makeInfoObject()
3334        writer = UFOWriter(self.dstDir, formatVersion=3)
3335        infoObject.woffMetadataLicense = dict(text=[{"text": "foo", "class": 1}])
3336        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3337        self.tearDownUFO()
3338        # woffMetadataCopyright
3339        ## unknown attribute
3340        infoObject = self.makeInfoObject()
3341        writer = UFOWriter(self.dstDir, formatVersion=3)
3342        infoObject.woffMetadataCopyright = dict(
3343            text=[dict(text="foo")], notTheRightKey=1
3344        )
3345        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3346        self.tearDownUFO()
3347        ## no text
3348        infoObject = self.makeInfoObject()
3349        writer = UFOWriter(self.dstDir, formatVersion=3)
3350        infoObject.woffMetadataCopyright = dict()
3351        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3352        self.tearDownUFO()
3353        ## text not a list
3354        infoObject = self.makeInfoObject()
3355        writer = UFOWriter(self.dstDir, formatVersion=3)
3356        infoObject.woffMetadataCopyright = dict(text="abc")
3357        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3358        self.tearDownUFO()
3359        ## text item not a dict
3360        infoObject = self.makeInfoObject()
3361        writer = UFOWriter(self.dstDir, formatVersion=3)
3362        infoObject.woffMetadataCopyright = dict(text=["abc"])
3363        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3364        self.tearDownUFO()
3365        ## text item unknown key
3366        infoObject = self.makeInfoObject()
3367        writer = UFOWriter(self.dstDir, formatVersion=3)
3368        infoObject.woffMetadataCopyright = dict(
3369            text=[dict(text="foo", notTheRightKey=1)]
3370        )
3371        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3372        self.tearDownUFO()
3373        ## text item missing text
3374        infoObject = self.makeInfoObject()
3375        infoObject.woffMetadataCopyright = dict(text=[dict(language="foo")])
3376        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3377        self.tearDownUFO()
3378        ## text not a string
3379        infoObject = self.makeInfoObject()
3380        writer = UFOWriter(self.dstDir, formatVersion=3)
3381        infoObject.woffMetadataCopyright = dict(text=[dict(text=1)])
3382        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3383        self.tearDownUFO()
3384        ## url not a string
3385        infoObject = self.makeInfoObject()
3386        writer = UFOWriter(self.dstDir, formatVersion=3)
3387        infoObject.woffMetadataCopyright = dict(text=[dict(text="foo", url=1)])
3388        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3389        self.tearDownUFO()
3390        ## language not a string
3391        infoObject = self.makeInfoObject()
3392        writer = UFOWriter(self.dstDir, formatVersion=3)
3393        infoObject.woffMetadataCopyright = dict(text=[dict(text="foo", language=1)])
3394        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3395        self.tearDownUFO()
3396        ## dir not ltr or rtl
3397        infoObject = self.makeInfoObject()
3398        writer = UFOWriter(self.dstDir, formatVersion=3)
3399        infoObject.woffMetadataCopyright = dict(text=[dict(text="foo", dir="utd")])
3400        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3401        self.tearDownUFO()
3402        ## class not a string
3403        infoObject = self.makeInfoObject()
3404        writer = UFOWriter(self.dstDir, formatVersion=3)
3405        infoObject.woffMetadataCopyright = dict(text=[{"text": "foo", "class": 1}])
3406        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3407        self.tearDownUFO()
3408        # woffMetadataTrademark
3409        ## unknown attribute
3410        infoObject = self.makeInfoObject()
3411        writer = UFOWriter(self.dstDir, formatVersion=3)
3412        infoObject.woffMetadataTrademark = dict(
3413            text=[dict(text="foo")], notTheRightKey=1
3414        )
3415        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3416        self.tearDownUFO()
3417        ## no text
3418        infoObject = self.makeInfoObject()
3419        writer = UFOWriter(self.dstDir, formatVersion=3)
3420        infoObject.woffMetadataTrademark = dict()
3421        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3422        self.tearDownUFO()
3423        ## text not a list
3424        infoObject = self.makeInfoObject()
3425        writer = UFOWriter(self.dstDir, formatVersion=3)
3426        infoObject.woffMetadataTrademark = dict(text="abc")
3427        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3428        self.tearDownUFO()
3429        ## text item not a dict
3430        infoObject = self.makeInfoObject()
3431        writer = UFOWriter(self.dstDir, formatVersion=3)
3432        infoObject.woffMetadataTrademark = dict(text=["abc"])
3433        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3434        self.tearDownUFO()
3435        ## text item unknown key
3436        infoObject = self.makeInfoObject()
3437        writer = UFOWriter(self.dstDir, formatVersion=3)
3438        infoObject.woffMetadataTrademark = dict(
3439            text=[dict(text="foo", notTheRightKey=1)]
3440        )
3441        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3442        self.tearDownUFO()
3443        ## text item missing text
3444        infoObject = self.makeInfoObject()
3445        writer = UFOWriter(self.dstDir, formatVersion=3)
3446        infoObject.woffMetadataTrademark = dict(text=[dict(language="foo")])
3447        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3448        self.tearDownUFO()
3449        ## text not a string
3450        infoObject = self.makeInfoObject()
3451        writer = UFOWriter(self.dstDir, formatVersion=3)
3452        infoObject.woffMetadataTrademark = dict(text=[dict(text=1)])
3453        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3454        self.tearDownUFO()
3455        ## url not a string
3456        infoObject = self.makeInfoObject()
3457        writer = UFOWriter(self.dstDir, formatVersion=3)
3458        infoObject.woffMetadataTrademark = dict(text=[dict(text="foo", url=1)])
3459        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3460        self.tearDownUFO()
3461        ## language not a string
3462        infoObject = self.makeInfoObject()
3463        writer = UFOWriter(self.dstDir, formatVersion=3)
3464        infoObject.woffMetadataTrademark = dict(text=[dict(text="foo", language=1)])
3465        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3466        self.tearDownUFO()
3467        ## dir not ltr or rtl
3468        infoObject = self.makeInfoObject()
3469        writer = UFOWriter(self.dstDir, formatVersion=3)
3470        infoObject.woffMetadataTrademark = dict(text=[dict(text="foo", dir="utd")])
3471        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3472        self.tearDownUFO()
3473        ## class not a string
3474        infoObject = self.makeInfoObject()
3475        writer = UFOWriter(self.dstDir, formatVersion=3)
3476        infoObject.woffMetadataTrademark = dict(text=[{"text": "foo", "class": 1}])
3477        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3478        self.tearDownUFO()
3479        # woffMetadataLicensee
3480        ## no name
3481        infoObject = self.makeInfoObject()
3482        writer = UFOWriter(self.dstDir, formatVersion=3)
3483        infoObject.woffMetadataLicensee = dict()
3484        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3485        self.tearDownUFO()
3486        ## unknown attribute
3487        infoObject = self.makeInfoObject()
3488        writer = UFOWriter(self.dstDir, formatVersion=3)
3489        infoObject.woffMetadataLicensee = dict(name="foo", notTheRightKey=1)
3490        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3491        self.tearDownUFO()
3492        ## name not a string
3493        infoObject = self.makeInfoObject()
3494        writer = UFOWriter(self.dstDir, formatVersion=3)
3495        infoObject.woffMetadataLicensee = dict(name=1)
3496        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3497        self.tearDownUFO()
3498        ## dir options
3499        infoObject = self.makeInfoObject()
3500        infoObject.woffMetadataLicensee = dict(name="foo", dir="ltr")
3501        writer = UFOWriter(self.dstDir, formatVersion=3)
3502        writer.writeInfo(infoObject)
3503        self.tearDownUFO()
3504        infoObject = self.makeInfoObject()
3505        infoObject.woffMetadataLicensee = dict(name="foo", dir="rtl")
3506        writer = UFOWriter(self.dstDir, formatVersion=3)
3507        writer.writeInfo(infoObject)
3508        self.tearDownUFO()
3509        ## dir not ltr or rtl
3510        infoObject = self.makeInfoObject()
3511        infoObject.woffMetadataLicensee = dict(name="foo", dir="utd")
3512        writer = UFOWriter(self.dstDir, formatVersion=3)
3513        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3514        self.tearDownUFO()
3515        ## have class
3516        infoObject = self.makeInfoObject()
3517        infoObject.woffMetadataLicensee = {"name": "foo", "class": "hello"}
3518        writer = UFOWriter(self.dstDir, formatVersion=3)
3519        writer.writeInfo(infoObject)
3520        self.tearDownUFO()
3521        ## class not a string
3522        infoObject = self.makeInfoObject()
3523        infoObject.woffMetadataLicensee = {"name": "foo", "class": 1}
3524        writer = UFOWriter(self.dstDir, formatVersion=3)
3525        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3526        self.tearDownUFO()
3527
3528    def testGuidelinesWrite(self):
3529        # x
3530        ## not an int or float
3531        infoObject = self.makeInfoObject()
3532        infoObject.guidelines = [dict(x="1")]
3533        writer = UFOWriter(self.dstDir, formatVersion=3)
3534        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3535        self.tearDownUFO()
3536        # y
3537        ## not an int or float
3538        infoObject = self.makeInfoObject()
3539        infoObject.guidelines = [dict(y="1")]
3540        writer = UFOWriter(self.dstDir, formatVersion=3)
3541        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3542        self.tearDownUFO()
3543        # angle
3544        ## < 0
3545        infoObject = self.makeInfoObject()
3546        infoObject.guidelines = [dict(x=0, y=0, angle=-1)]
3547        writer = UFOWriter(self.dstDir, formatVersion=3)
3548        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3549        self.tearDownUFO()
3550        ## > 360
3551        infoObject = self.makeInfoObject()
3552        infoObject.guidelines = [dict(x=0, y=0, angle=361)]
3553        writer = UFOWriter(self.dstDir, formatVersion=3)
3554        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3555        self.tearDownUFO()
3556        # name
3557        ## not a string
3558        infoObject = self.makeInfoObject()
3559        infoObject.guidelines = [dict(x=0, name=1)]
3560        writer = UFOWriter(self.dstDir, formatVersion=3)
3561        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3562        self.tearDownUFO()
3563        # color
3564        ## not a string
3565        infoObject = self.makeInfoObject()
3566        infoObject.guidelines = [dict(x=0, color=1)]
3567        writer = UFOWriter(self.dstDir, formatVersion=3)
3568        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3569        self.tearDownUFO()
3570        ## not enough commas
3571        infoObject = self.makeInfoObject()
3572        infoObject.guidelines = [dict(x=0, color="1 0, 0, 0")]
3573        writer = UFOWriter(self.dstDir, formatVersion=3)
3574        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3575        self.tearDownUFO()
3576        infoObject = self.makeInfoObject()
3577        infoObject.guidelines = [dict(x=0, color="1 0 0, 0")]
3578        writer = UFOWriter(self.dstDir, formatVersion=3)
3579        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3580        self.tearDownUFO()
3581        infoObject = self.makeInfoObject()
3582        infoObject.guidelines = [dict(x=0, color="1 0 0 0")]
3583        writer = UFOWriter(self.dstDir, formatVersion=3)
3584        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3585        self.tearDownUFO()
3586        ## not enough parts
3587        infoObject = self.makeInfoObject()
3588        infoObject.guidelines = [dict(x=0, color=", 0, 0, 0")]
3589        writer = UFOWriter(self.dstDir, formatVersion=3)
3590        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3591        self.tearDownUFO()
3592        infoObject = self.makeInfoObject()
3593        infoObject.guidelines = [dict(x=0, color="1, , 0, 0")]
3594        writer = UFOWriter(self.dstDir, formatVersion=3)
3595        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3596        self.tearDownUFO()
3597        infoObject = self.makeInfoObject()
3598        infoObject.guidelines = [dict(x=0, color="1, 0, , 0")]
3599        writer = UFOWriter(self.dstDir, formatVersion=3)
3600        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3601        self.tearDownUFO()
3602        infoObject = self.makeInfoObject()
3603        infoObject.guidelines = [dict(x=0, color="1, 0, 0, ")]
3604        writer = UFOWriter(self.dstDir, formatVersion=3)
3605        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3606        self.tearDownUFO()
3607        infoObject = self.makeInfoObject()
3608        infoObject.guidelines = [dict(x=0, color=", , , ")]
3609        writer = UFOWriter(self.dstDir, formatVersion=3)
3610        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3611        self.tearDownUFO()
3612        ## not a number in all positions
3613        infoObject = self.makeInfoObject()
3614        infoObject.guidelines = [dict(x=0, color="r, 1, 1, 1")]
3615        writer = UFOWriter(self.dstDir, formatVersion=3)
3616        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3617        self.tearDownUFO()
3618        infoObject = self.makeInfoObject()
3619        infoObject.guidelines = [dict(x=0, color="1, g, 1, 1")]
3620        writer = UFOWriter(self.dstDir, formatVersion=3)
3621        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3622        self.tearDownUFO()
3623        infoObject = self.makeInfoObject()
3624        infoObject.guidelines = [dict(x=0, color="1, 1, b, 1")]
3625        writer = UFOWriter(self.dstDir, formatVersion=3)
3626        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3627        self.tearDownUFO()
3628        infoObject = self.makeInfoObject()
3629        infoObject.guidelines = [dict(x=0, color="1, 1, 1, a")]
3630        writer = UFOWriter(self.dstDir, formatVersion=3)
3631        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3632        self.tearDownUFO()
3633        ## too many parts
3634        infoObject = self.makeInfoObject()
3635        infoObject.guidelines = [dict(x=0, color="1, 0, 0, 0, 0")]
3636        writer = UFOWriter(self.dstDir, formatVersion=3)
3637        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3638        self.tearDownUFO()
3639        ## < 0 in each position
3640        infoObject = self.makeInfoObject()
3641        infoObject.guidelines = [dict(x=0, color="-1, 0, 0, 0")]
3642        writer = UFOWriter(self.dstDir, formatVersion=3)
3643        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3644        self.tearDownUFO()
3645        infoObject = self.makeInfoObject()
3646        infoObject.guidelines = [dict(x=0, color="0, -1, 0, 0")]
3647        writer = UFOWriter(self.dstDir, formatVersion=3)
3648        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3649        self.tearDownUFO()
3650        infoObject = self.makeInfoObject()
3651        infoObject.guidelines = [dict(x=0, color="0, 0, -1, 0")]
3652        writer = UFOWriter(self.dstDir, formatVersion=3)
3653        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3654        self.tearDownUFO()
3655        infoObject = self.makeInfoObject()
3656        infoObject.guidelines = [dict(x=0, color="0, 0, 0, -1")]
3657        writer = UFOWriter(self.dstDir, formatVersion=3)
3658        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3659        self.tearDownUFO()
3660        ## > 1 in each position
3661        infoObject = self.makeInfoObject()
3662        infoObject.guidelines = [dict(x=0, color="2, 0, 0, 0")]
3663        writer = UFOWriter(self.dstDir, formatVersion=3)
3664        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3665        self.tearDownUFO()
3666        infoObject = self.makeInfoObject()
3667        infoObject.guidelines = [dict(x=0, color="0, 2, 0, 0")]
3668        writer = UFOWriter(self.dstDir, formatVersion=3)
3669        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3670        self.tearDownUFO()
3671        infoObject = self.makeInfoObject()
3672        infoObject.guidelines = [dict(x=0, color="0, 0, 2, 0")]
3673        writer = UFOWriter(self.dstDir, formatVersion=3)
3674        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3675        self.tearDownUFO()
3676        infoObject = self.makeInfoObject()
3677        infoObject.guidelines = [dict(x=0, color="0, 0, 0, 2")]
3678        writer = UFOWriter(self.dstDir, formatVersion=3)
3679        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3680        self.tearDownUFO()
3681        # identifier
3682        ## duplicate
3683        infoObject = self.makeInfoObject()
3684        infoObject.guidelines = [
3685            dict(x=0, identifier="guide1"),
3686            dict(y=0, identifier="guide1"),
3687        ]
3688        writer = UFOWriter(self.dstDir, formatVersion=3)
3689        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3690        self.tearDownUFO()
3691        ## below min
3692        infoObject = self.makeInfoObject()
3693        infoObject.guidelines = [dict(x=0, identifier="\0x1F")]
3694        writer = UFOWriter(self.dstDir, formatVersion=3)
3695        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3696        self.tearDownUFO()
3697        ## above max
3698        infoObject = self.makeInfoObject()
3699        infoObject.guidelines = [dict(x=0, identifier="\0x7F")]
3700        writer = UFOWriter(self.dstDir, formatVersion=3)
3701        self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject)
3702        self.tearDownUFO()
3703
3704
3705# ------
3706# layers
3707# ------
3708
3709
3710class UFO3ReadLayersTestCase(unittest.TestCase):
3711    def setUp(self):
3712        self.tempDir = tempfile.mktemp()
3713        os.mkdir(self.tempDir)
3714        self.ufoPath = os.path.join(self.tempDir, "test.ufo")
3715
3716    def tearDown(self):
3717        shutil.rmtree(self.tempDir)
3718
3719    def makeUFO(self, metaInfo=None, layerContents=None):
3720        self.clearUFO()
3721        if not os.path.exists(self.ufoPath):
3722            os.mkdir(self.ufoPath)
3723        # metainfo.plist
3724        if metaInfo is None:
3725            metaInfo = dict(creator="test", formatVersion=3)
3726        path = os.path.join(self.ufoPath, "metainfo.plist")
3727        with open(path, "wb") as f:
3728            plistlib.dump(metaInfo, f)
3729        # layers
3730        if layerContents is None:
3731            layerContents = [
3732                ("public.default", "glyphs"),
3733                ("layer 1", "glyphs.layer 1"),
3734                ("layer 2", "glyphs.layer 2"),
3735            ]
3736        if layerContents:
3737            path = os.path.join(self.ufoPath, "layercontents.plist")
3738            with open(path, "wb") as f:
3739                plistlib.dump(layerContents, f)
3740        else:
3741            layerContents = [("", "glyphs")]
3742        for name, directory in layerContents:
3743            glyphsPath = os.path.join(self.ufoPath, directory)
3744            os.mkdir(glyphsPath)
3745            contents = dict(a="a.glif")
3746            path = os.path.join(glyphsPath, "contents.plist")
3747            with open(path, "wb") as f:
3748                plistlib.dump(contents, f)
3749            path = os.path.join(glyphsPath, "a.glif")
3750            with open(path, "w") as f:
3751                f.write(" ")
3752
3753    def clearUFO(self):
3754        if os.path.exists(self.ufoPath):
3755            shutil.rmtree(self.ufoPath)
3756
3757    # valid
3758
3759    def testValidRead(self):
3760        # UFO 1
3761        self.makeUFO(
3762            metaInfo=dict(creator="test", formatVersion=1), layerContents=dict()
3763        )
3764        reader = UFOReader(self.ufoPath, validate=True)
3765        reader.getGlyphSet()
3766        # UFO 2
3767        self.makeUFO(
3768            metaInfo=dict(creator="test", formatVersion=2), layerContents=dict()
3769        )
3770        reader = UFOReader(self.ufoPath, validate=True)
3771        reader.getGlyphSet()
3772        # UFO 3
3773        self.makeUFO()
3774        reader = UFOReader(self.ufoPath, validate=True)
3775        reader.getGlyphSet()
3776
3777    # missing layer contents
3778
3779    def testMissingLayerContents(self):
3780        self.makeUFO()
3781        path = os.path.join(self.ufoPath, "layercontents.plist")
3782        os.remove(path)
3783        reader = UFOReader(self.ufoPath, validate=True)
3784        self.assertRaises(UFOLibError, reader.getGlyphSet)
3785
3786    # layer contents invalid format
3787
3788    def testInvalidLayerContentsFormat(self):
3789        # bogus
3790        self.makeUFO()
3791        path = os.path.join(self.ufoPath, "layercontents.plist")
3792        os.remove(path)
3793        with open(path, "w") as f:
3794            f.write("test")
3795        reader = UFOReader(self.ufoPath, validate=True)
3796        self.assertRaises(UFOLibError, reader.getGlyphSet)
3797        # dict
3798        self.makeUFO()
3799        path = os.path.join(self.ufoPath, "layercontents.plist")
3800        os.remove(path)
3801        layerContents = {
3802            "public.default": "glyphs",
3803            "layer 1": "glyphs.layer 1",
3804            "layer 2": "glyphs.layer 2",
3805        }
3806        with open(path, "wb") as f:
3807            plistlib.dump(layerContents, f)
3808        reader = UFOReader(self.ufoPath, validate=True)
3809        self.assertRaises(UFOLibError, reader.getGlyphSet)
3810
3811    # layer contents invalid name format
3812
3813    def testInvalidLayerContentsNameFormat(self):
3814        self.makeUFO()
3815        path = os.path.join(self.ufoPath, "layercontents.plist")
3816        os.remove(path)
3817        layerContents = [
3818            (1, "glyphs"),
3819            ("layer 1", "glyphs.layer 1"),
3820            ("layer 2", "glyphs.layer 2"),
3821        ]
3822        with open(path, "wb") as f:
3823            plistlib.dump(layerContents, f)
3824        reader = UFOReader(self.ufoPath, validate=True)
3825        self.assertRaises(UFOLibError, reader.getGlyphSet)
3826
3827    # layer contents invalid directory format
3828
3829    def testInvalidLayerContentsDirectoryFormat(self):
3830        self.makeUFO()
3831        path = os.path.join(self.ufoPath, "layercontents.plist")
3832        os.remove(path)
3833        layerContents = [
3834            ("public.foregound", "glyphs"),
3835            ("layer 1", 1),
3836            ("layer 2", "glyphs.layer 2"),
3837        ]
3838        with open(path, "wb") as f:
3839            plistlib.dump(layerContents, f)
3840        reader = UFOReader(self.ufoPath, validate=True)
3841        self.assertRaises(UFOLibError, reader.getGlyphSet)
3842
3843    # directory listed in contents not on disk
3844
3845    def testLayerContentsHasMissingDirectory(self):
3846        self.makeUFO()
3847        path = os.path.join(self.ufoPath, "layercontents.plist")
3848        os.remove(path)
3849        layerContents = [
3850            ("public.foregound", "glyphs"),
3851            ("layer 1", "glyphs.doesnotexist"),
3852            ("layer 2", "glyphs.layer 2"),
3853        ]
3854        with open(path, "wb") as f:
3855            plistlib.dump(layerContents, f)
3856        reader = UFOReader(self.ufoPath, validate=True)
3857        self.assertRaises(UFOLibError, reader.getGlyphSet)
3858
3859    # # directory on disk not listed in contents
3860    # XXX should this raise an error?
3861    #
3862    # def testLayerContentsHasMissingDirectory(self):
3863    # 	self.makeUFO()
3864    # 	path = os.path.join(self.ufoPath, "layercontents.plist")
3865    # 	os.remove(path)
3866    # 	layerContents = [
3867    # 		("public.foregound", "glyphs"),
3868    # 		("layer 1", "glyphs.layer 2")
3869    # 	]
3870    # 	with open(path, "wb") as f:
3871    # 		plistlib.dump(layerContents, f)
3872    # 	reader = UFOReader(self.ufoPath, validate=True)
3873    # 	with self.assertRaises(UFOLibError):
3874    # 		reader.getGlyphSet()
3875
3876    # no default layer on disk
3877
3878    def testMissingDefaultLayer(self):
3879        self.makeUFO()
3880        path = os.path.join(self.ufoPath, "layercontents.plist")
3881        os.remove(path)
3882        layerContents = [("layer 1", "glyphs.layer 1"), ("layer 2", "glyphs.layer 2")]
3883        with open(path, "wb") as f:
3884            plistlib.dump(layerContents, f)
3885        reader = UFOReader(self.ufoPath, validate=True)
3886        self.assertRaises(UFOLibError, reader.getGlyphSet)
3887
3888    # duplicate layer name
3889
3890    def testDuplicateLayerName(self):
3891        self.makeUFO()
3892        path = os.path.join(self.ufoPath, "layercontents.plist")
3893        os.remove(path)
3894        layerContents = [
3895            ("public.foregound", "glyphs"),
3896            ("layer 1", "glyphs.layer 1"),
3897            ("layer 1", "glyphs.layer 2"),
3898        ]
3899        with open(path, "wb") as f:
3900            plistlib.dump(layerContents, f)
3901        reader = UFOReader(self.ufoPath, validate=True)
3902        self.assertRaises(UFOLibError, reader.getGlyphSet)
3903
3904    # directory referenced by two layer names
3905
3906    def testDuplicateLayerDirectory(self):
3907        self.makeUFO()
3908        path = os.path.join(self.ufoPath, "layercontents.plist")
3909        os.remove(path)
3910        layerContents = [
3911            ("public.foregound", "glyphs"),
3912            ("layer 1", "glyphs.layer 1"),
3913            ("layer 2", "glyphs.layer 1"),
3914        ]
3915        with open(path, "wb") as f:
3916            plistlib.dump(layerContents, f)
3917        reader = UFOReader(self.ufoPath, validate=True)
3918        self.assertRaises(UFOLibError, reader.getGlyphSet)
3919
3920    # default without a name
3921
3922    def testDefaultLayerNoName(self):
3923        # get the glyph set
3924        self.makeUFO()
3925        path = os.path.join(self.ufoPath, "layercontents.plist")
3926        os.remove(path)
3927        layerContents = [
3928            ("public.foregound", "glyphs"),
3929            ("layer 1", "glyphs.layer 1"),
3930            ("layer 2", "glyphs.layer 2"),
3931        ]
3932        with open(path, "wb") as f:
3933            plistlib.dump(layerContents, f)
3934        reader = UFOReader(self.ufoPath, validate=True)
3935        reader.getGlyphSet()
3936
3937    # default with a name
3938
3939    def testDefaultLayerName(self):
3940        # get the name
3941        self.makeUFO()
3942        path = os.path.join(self.ufoPath, "layercontents.plist")
3943        os.remove(path)
3944        layerContents = [
3945            ("custom name", "glyphs"),
3946            ("layer 1", "glyphs.layer 1"),
3947            ("layer 2", "glyphs.layer 2"),
3948        ]
3949        expected = layerContents[0][0]
3950        with open(path, "wb") as f:
3951            plistlib.dump(layerContents, f)
3952        reader = UFOReader(self.ufoPath, validate=True)
3953        result = reader.getDefaultLayerName()
3954        self.assertEqual(expected, result)
3955        # get the glyph set
3956        self.makeUFO()
3957        path = os.path.join(self.ufoPath, "layercontents.plist")
3958        os.remove(path)
3959        layerContents = [
3960            ("custom name", "glyphs"),
3961            ("layer 1", "glyphs.layer 1"),
3962            ("layer 2", "glyphs.layer 2"),
3963        ]
3964        with open(path, "wb") as f:
3965            plistlib.dump(layerContents, f)
3966        reader = UFOReader(self.ufoPath, validate=True)
3967        reader.getGlyphSet(expected)
3968
3969    # layer order
3970
3971    def testLayerOrder(self):
3972        self.makeUFO()
3973        path = os.path.join(self.ufoPath, "layercontents.plist")
3974        os.remove(path)
3975        layerContents = [
3976            ("public.foregound", "glyphs"),
3977            ("layer 1", "glyphs.layer 1"),
3978            ("layer 2", "glyphs.layer 2"),
3979        ]
3980        expected = [name for (name, directory) in layerContents]
3981        with open(path, "wb") as f:
3982            plistlib.dump(layerContents, f)
3983        reader = UFOReader(self.ufoPath, validate=True)
3984        result = reader.getLayerNames()
3985        self.assertEqual(expected, result)
3986        self.makeUFO()
3987        path = os.path.join(self.ufoPath, "layercontents.plist")
3988        os.remove(path)
3989        layerContents = [
3990            ("layer 1", "glyphs.layer 1"),
3991            ("public.foregound", "glyphs"),
3992            ("layer 2", "glyphs.layer 2"),
3993        ]
3994        expected = [name for (name, directory) in layerContents]
3995        with open(path, "wb") as f:
3996            plistlib.dump(layerContents, f)
3997        reader = UFOReader(self.ufoPath, validate=True)
3998        result = reader.getLayerNames()
3999        self.assertEqual(expected, result)
4000        self.makeUFO()
4001        path = os.path.join(self.ufoPath, "layercontents.plist")
4002        os.remove(path)
4003        layerContents = [
4004            ("layer 2", "glyphs.layer 2"),
4005            ("layer 1", "glyphs.layer 1"),
4006            ("public.foregound", "glyphs"),
4007        ]
4008        expected = [name for (name, directory) in layerContents]
4009        with open(path, "wb") as f:
4010            plistlib.dump(layerContents, f)
4011        reader = UFOReader(self.ufoPath, validate=True)
4012        result = reader.getLayerNames()
4013        self.assertEqual(expected, result)
4014
4015
4016class UFO3WriteLayersTestCase(unittest.TestCase):
4017    def setUp(self):
4018        self.tempDir = tempfile.mktemp()
4019        os.mkdir(self.tempDir)
4020        self.ufoPath = os.path.join(self.tempDir, "test.ufo")
4021
4022    def tearDown(self):
4023        shutil.rmtree(self.tempDir)
4024
4025    def makeUFO(self, metaInfo=None, layerContents=None):
4026        self.clearUFO()
4027        if not os.path.exists(self.ufoPath):
4028            os.mkdir(self.ufoPath)
4029        # metainfo.plist
4030        if metaInfo is None:
4031            metaInfo = dict(creator="test", formatVersion=3)
4032        path = os.path.join(self.ufoPath, "metainfo.plist")
4033        with open(path, "wb") as f:
4034            plistlib.dump(metaInfo, f)
4035        # layers
4036        if layerContents is None:
4037            layerContents = [
4038                ("public.default", "glyphs"),
4039                ("layer 1", "glyphs.layer 1"),
4040                ("layer 2", "glyphs.layer 2"),
4041            ]
4042        if layerContents:
4043            path = os.path.join(self.ufoPath, "layercontents.plist")
4044            with open(path, "wb") as f:
4045                plistlib.dump(layerContents, f)
4046        else:
4047            layerContents = [("", "glyphs")]
4048        for name, directory in layerContents:
4049            glyphsPath = os.path.join(self.ufoPath, directory)
4050            os.mkdir(glyphsPath)
4051            contents = dict(a="a.glif")
4052            path = os.path.join(glyphsPath, "contents.plist")
4053            with open(path, "wb") as f:
4054                plistlib.dump(contents, f)
4055            path = os.path.join(glyphsPath, "a.glif")
4056            with open(path, "w") as f:
4057                f.write(" ")
4058
4059    def clearUFO(self):
4060        if os.path.exists(self.ufoPath):
4061            shutil.rmtree(self.ufoPath)
4062
4063    # __init__: missing layer contents
4064
4065    def testMissingLayerContents(self):
4066        self.makeUFO()
4067        path = os.path.join(self.ufoPath, "layercontents.plist")
4068        os.remove(path)
4069        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)
4070
4071    # __init__: layer contents invalid format
4072
4073    def testInvalidLayerContentsFormat(self):
4074        # bogus
4075        self.makeUFO()
4076        path = os.path.join(self.ufoPath, "layercontents.plist")
4077        os.remove(path)
4078        with open(path, "w") as f:
4079            f.write("test")
4080        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)
4081        # dict
4082        self.makeUFO()
4083        path = os.path.join(self.ufoPath, "layercontents.plist")
4084        os.remove(path)
4085        layerContents = {
4086            "public.default": "glyphs",
4087            "layer 1": "glyphs.layer 1",
4088            "layer 2": "glyphs.layer 2",
4089        }
4090        with open(path, "wb") as f:
4091            plistlib.dump(layerContents, f)
4092        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)
4093
4094    # __init__: layer contents invalid name format
4095
4096    def testInvalidLayerContentsNameFormat(self):
4097        self.makeUFO()
4098        path = os.path.join(self.ufoPath, "layercontents.plist")
4099        os.remove(path)
4100        layerContents = [
4101            (1, "glyphs"),
4102            ("layer 1", "glyphs.layer 1"),
4103            ("layer 2", "glyphs.layer 2"),
4104        ]
4105        with open(path, "wb") as f:
4106            plistlib.dump(layerContents, f)
4107        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)
4108
4109    # __init__: layer contents invalid directory format
4110
4111    def testInvalidLayerContentsDirectoryFormat(self):
4112        self.makeUFO()
4113        path = os.path.join(self.ufoPath, "layercontents.plist")
4114        os.remove(path)
4115        layerContents = [
4116            ("public.foregound", "glyphs"),
4117            ("layer 1", 1),
4118            ("layer 2", "glyphs.layer 2"),
4119        ]
4120        with open(path, "wb") as f:
4121            plistlib.dump(layerContents, f)
4122        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)
4123
4124    # __init__: directory listed in contents not on disk
4125
4126    def testLayerContentsHasMissingDirectory(self):
4127        self.makeUFO()
4128        path = os.path.join(self.ufoPath, "layercontents.plist")
4129        os.remove(path)
4130        layerContents = [
4131            ("public.foregound", "glyphs"),
4132            ("layer 1", "glyphs.doesnotexist"),
4133            ("layer 2", "glyphs.layer 2"),
4134        ]
4135        with open(path, "wb") as f:
4136            plistlib.dump(layerContents, f)
4137        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)
4138
4139    # __init__: no default layer on disk
4140
4141    def testMissingDefaultLayer(self):
4142        self.makeUFO()
4143        path = os.path.join(self.ufoPath, "layercontents.plist")
4144        os.remove(path)
4145        layerContents = [("layer 1", "glyphs.layer 1"), ("layer 2", "glyphs.layer 2")]
4146        with open(path, "wb") as f:
4147            plistlib.dump(layerContents, f)
4148        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)
4149
4150    # __init__: duplicate layer name
4151
4152    def testDuplicateLayerName(self):
4153        self.makeUFO()
4154        path = os.path.join(self.ufoPath, "layercontents.plist")
4155        os.remove(path)
4156        layerContents = [
4157            ("public.foregound", "glyphs"),
4158            ("layer 1", "glyphs.layer 1"),
4159            ("layer 1", "glyphs.layer 2"),
4160        ]
4161        with open(path, "wb") as f:
4162            plistlib.dump(layerContents, f)
4163        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)
4164
4165    # __init__: directory referenced by two layer names
4166
4167    def testDuplicateLayerDirectory(self):
4168        self.makeUFO()
4169        path = os.path.join(self.ufoPath, "layercontents.plist")
4170        os.remove(path)
4171        layerContents = [
4172            ("public.foregound", "glyphs"),
4173            ("layer 1", "glyphs.layer 1"),
4174            ("layer 2", "glyphs.layer 1"),
4175        ]
4176        with open(path, "wb") as f:
4177            plistlib.dump(layerContents, f)
4178        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath)
4179
4180    # __init__: default without a name
4181
4182    def testDefaultLayerNoName(self):
4183        # get the glyph set
4184        self.makeUFO()
4185        path = os.path.join(self.ufoPath, "layercontents.plist")
4186        os.remove(path)
4187        layerContents = [
4188            ("public.foregound", "glyphs"),
4189            ("layer 1", "glyphs.layer 1"),
4190            ("layer 2", "glyphs.layer 2"),
4191        ]
4192        with open(path, "wb") as f:
4193            plistlib.dump(layerContents, f)
4194        writer = UFOWriter(self.ufoPath)
4195
4196    # __init__: default with a name
4197
4198    def testDefaultLayerName(self):
4199        self.makeUFO()
4200        path = os.path.join(self.ufoPath, "layercontents.plist")
4201        os.remove(path)
4202        layerContents = [
4203            ("custom name", "glyphs"),
4204            ("layer 1", "glyphs.layer 1"),
4205            ("layer 2", "glyphs.layer 2"),
4206        ]
4207        with open(path, "wb") as f:
4208            plistlib.dump(layerContents, f)
4209        writer = UFOWriter(self.ufoPath)
4210
4211    # __init__: up convert 1 > 3
4212
4213    def testUpConvert1To3(self):
4214        self.makeUFO(
4215            metaInfo=dict(creator="test", formatVersion=1), layerContents=dict()
4216        )
4217        writer = UFOWriter(self.ufoPath)
4218        writer.writeLayerContents(["public.default"])
4219        path = os.path.join(self.ufoPath, "layercontents.plist")
4220        with open(path, "rb") as f:
4221            result = plistlib.load(f)
4222        expected = [["public.default", "glyphs"]]
4223        self.assertEqual(expected, result)
4224
4225    # __init__: up convert 2 > 3
4226
4227    def testUpConvert2To3(self):
4228        self.makeUFO(
4229            metaInfo=dict(creator="test", formatVersion=2), layerContents=dict()
4230        )
4231        writer = UFOWriter(self.ufoPath)
4232        writer.writeLayerContents(["public.default"])
4233        path = os.path.join(self.ufoPath, "layercontents.plist")
4234        with open(path, "rb") as f:
4235            result = plistlib.load(f)
4236        expected = [["public.default", "glyphs"]]
4237        self.assertEqual(expected, result)
4238
4239    # __init__: down convert 3 > 1
4240
4241    def testDownConvert3To1(self):
4242        self.makeUFO()
4243        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath, formatVersion=1)
4244
4245    # __init__: down convert 3 > 2
4246
4247    def testDownConvert3To2(self):
4248        self.makeUFO()
4249        self.assertRaises(UFOLibError, UFOWriter, self.ufoPath, formatVersion=2)
4250
4251    # get glyph sets
4252
4253    def testGetGlyphSets(self):
4254        self.makeUFO()
4255        # hack contents.plist
4256        path = os.path.join(self.ufoPath, "glyphs.layer 1", "contents.plist")
4257        with open(path, "wb") as f:
4258            plistlib.dump(dict(b="a.glif"), f)
4259        path = os.path.join(self.ufoPath, "glyphs.layer 2", "contents.plist")
4260        with open(path, "wb") as f:
4261            plistlib.dump(dict(c="a.glif"), f)
4262        # now test
4263        writer = UFOWriter(self.ufoPath)
4264        # default
4265        expected = ["a"]
4266        result = list(writer.getGlyphSet().keys())
4267        self.assertEqual(expected, result)
4268        # layer 1
4269        expected = ["b"]
4270        result = list(writer.getGlyphSet("layer 1", defaultLayer=False).keys())
4271        self.assertEqual(expected, result)
4272        # layer 2
4273        expected = ["c"]
4274        result = list(writer.getGlyphSet("layer 2", defaultLayer=False).keys())
4275        self.assertEqual(expected, result)
4276
4277    def testGetGlyphSetNoContents(self):
4278        self.makeUFO()
4279        os.remove(os.path.join(self.ufoPath, "glyphs.layer 1", "contents.plist"))
4280
4281        reader = UFOReader(self.ufoPath, validate=True)
4282        with self.assertRaises(GlifLibError):
4283            reader.getGlyphSet("layer 1")
4284
4285        writer = UFOWriter(self.ufoPath, validate=True)
4286        with self.assertRaises(GlifLibError):
4287            writer.getGlyphSet("layer 1", defaultLayer=False, expectContentsFile=True)
4288
4289        # There's a separate code path for < v3 UFOs.
4290        with open(os.path.join(self.ufoPath, "metainfo.plist"), "wb") as f:
4291            plistlib.dump(dict(creator="test", formatVersion=2), f)
4292        os.remove(os.path.join(self.ufoPath, "glyphs", "contents.plist"))
4293        writer = UFOWriter(self.ufoPath, validate=True, formatVersion=2)
4294        with self.assertRaises(GlifLibError):
4295            writer.getGlyphSet(expectContentsFile=True)
4296
4297    # make a new font with two layers
4298
4299    def testNewFontOneLayer(self):
4300        self.clearUFO()
4301        writer = UFOWriter(self.ufoPath)
4302        writer.getGlyphSet()
4303        writer.writeLayerContents(["public.default"])
4304        # directory
4305        path = os.path.join(self.ufoPath, "glyphs")
4306        exists = os.path.exists(path)
4307        self.assertEqual(True, exists)
4308        # layer contents
4309        path = os.path.join(self.ufoPath, "layercontents.plist")
4310        with open(path, "rb") as f:
4311            result = plistlib.load(f)
4312        expected = [["public.default", "glyphs"]]
4313        self.assertEqual(expected, result)
4314
4315    def testNewFontThreeLayers(self):
4316        self.clearUFO()
4317        writer = UFOWriter(self.ufoPath)
4318        writer.getGlyphSet("layer 1", defaultLayer=False)
4319        writer.getGlyphSet()
4320        writer.getGlyphSet("layer 2", defaultLayer=False)
4321        writer.writeLayerContents(["layer 1", "public.default", "layer 2"])
4322        # directories
4323        path = os.path.join(self.ufoPath, "glyphs")
4324        exists = os.path.exists(path)
4325        self.assertEqual(True, exists)
4326        path = os.path.join(self.ufoPath, "glyphs.layer 1")
4327        exists = os.path.exists(path)
4328        self.assertEqual(True, exists)
4329        path = os.path.join(self.ufoPath, "glyphs.layer 2")
4330        exists = os.path.exists(path)
4331        self.assertEqual(True, exists)
4332        # layer contents
4333        path = os.path.join(self.ufoPath, "layercontents.plist")
4334        with open(path, "rb") as f:
4335            result = plistlib.load(f)
4336        expected = [
4337            ["layer 1", "glyphs.layer 1"],
4338            ["public.default", "glyphs"],
4339            ["layer 2", "glyphs.layer 2"],
4340        ]
4341        self.assertEqual(expected, result)
4342
4343    # add a layer to an existing font
4344
4345    def testAddLayerToExistingFont(self):
4346        self.makeUFO()
4347        writer = UFOWriter(self.ufoPath)
4348        writer.getGlyphSet("layer 3", defaultLayer=False)
4349        writer.writeLayerContents(["public.default", "layer 1", "layer 2", "layer 3"])
4350        # directories
4351        path = os.path.join(self.ufoPath, "glyphs")
4352        exists = os.path.exists(path)
4353        self.assertEqual(True, exists)
4354        path = os.path.join(self.ufoPath, "glyphs.layer 1")
4355        exists = os.path.exists(path)
4356        self.assertEqual(True, exists)
4357        path = os.path.join(self.ufoPath, "glyphs.layer 2")
4358        exists = os.path.exists(path)
4359        self.assertEqual(True, exists)
4360        path = os.path.join(self.ufoPath, "glyphs.layer 3")
4361        exists = os.path.exists(path)
4362        self.assertEqual(True, exists)
4363        # layer contents
4364        path = os.path.join(self.ufoPath, "layercontents.plist")
4365        with open(path, "rb") as f:
4366            result = plistlib.load(f)
4367        expected = [
4368            ["public.default", "glyphs"],
4369            ["layer 1", "glyphs.layer 1"],
4370            ["layer 2", "glyphs.layer 2"],
4371            ["layer 3", "glyphs.layer 3"],
4372        ]
4373        self.assertEqual(expected, result)
4374
4375    # rename valid name
4376
4377    def testRenameLayer(self):
4378        self.makeUFO()
4379        writer = UFOWriter(self.ufoPath)
4380        writer.renameGlyphSet("layer 1", "layer 3")
4381        writer.writeLayerContents(["public.default", "layer 3", "layer 2"])
4382        # directories
4383        path = os.path.join(self.ufoPath, "glyphs")
4384        exists = os.path.exists(path)
4385        self.assertEqual(True, exists)
4386        path = os.path.join(self.ufoPath, "glyphs.layer 1")
4387        exists = os.path.exists(path)
4388        self.assertEqual(False, exists)
4389        path = os.path.join(self.ufoPath, "glyphs.layer 2")
4390        exists = os.path.exists(path)
4391        self.assertEqual(True, exists)
4392        path = os.path.join(self.ufoPath, "glyphs.layer 3")
4393        exists = os.path.exists(path)
4394        self.assertEqual(True, exists)
4395        # layer contents
4396        path = os.path.join(self.ufoPath, "layercontents.plist")
4397        with open(path, "rb") as f:
4398            result = plistlib.load(f)
4399        expected = [
4400            ["public.default", "glyphs"],
4401            ["layer 3", "glyphs.layer 3"],
4402            ["layer 2", "glyphs.layer 2"],
4403        ]
4404        self.assertEqual(expected, result)
4405
4406    def testRenameLayerDefault(self):
4407        self.makeUFO()
4408        writer = UFOWriter(self.ufoPath)
4409        writer.renameGlyphSet("public.default", "layer xxx")
4410        writer.renameGlyphSet("layer 1", "layer 1", defaultLayer=True)
4411        writer.writeLayerContents(["layer xxx", "layer 1", "layer 2"])
4412        path = os.path.join(self.ufoPath, "glyphs")
4413        exists = os.path.exists(path)
4414        self.assertEqual(True, exists)
4415        path = os.path.join(self.ufoPath, "glyphs.layer 1")
4416        exists = os.path.exists(path)
4417        self.assertEqual(False, exists)
4418        path = os.path.join(self.ufoPath, "glyphs.layer 2")
4419        exists = os.path.exists(path)
4420        self.assertEqual(True, exists)
4421        path = os.path.join(self.ufoPath, "glyphs.layer xxx")
4422        exists = os.path.exists(path)
4423        self.assertEqual(True, exists)
4424        # layer contents
4425        path = os.path.join(self.ufoPath, "layercontents.plist")
4426        with open(path, "rb") as f:
4427            result = plistlib.load(f)
4428        expected = [
4429            ["layer xxx", "glyphs.layer xxx"],
4430            ["layer 1", "glyphs"],
4431            ["layer 2", "glyphs.layer 2"],
4432        ]
4433        self.assertEqual(expected, result)
4434
4435    # rename duplicate name
4436
4437    def testRenameLayerDuplicateName(self):
4438        self.makeUFO()
4439        writer = UFOWriter(self.ufoPath)
4440        self.assertRaises(UFOLibError, writer.renameGlyphSet, "layer 1", "layer 2")
4441
4442    # rename unknown layer
4443
4444    def testRenameLayerUnknownName(self):
4445        self.makeUFO()
4446        writer = UFOWriter(self.ufoPath)
4447        self.assertRaises(
4448            UFOLibError, writer.renameGlyphSet, "does not exist", "layer 2"
4449        )
4450
4451    # remove valid layer
4452
4453    def testRemoveLayer(self):
4454        self.makeUFO()
4455        writer = UFOWriter(self.ufoPath)
4456        writer.deleteGlyphSet("layer 1")
4457        writer.writeLayerContents(["public.default", "layer 2"])
4458        # directories
4459        path = os.path.join(self.ufoPath, "glyphs")
4460        exists = os.path.exists(path)
4461        self.assertEqual(True, exists)
4462        path = os.path.join(self.ufoPath, "glyphs.layer 1")
4463        exists = os.path.exists(path)
4464        self.assertEqual(False, exists)
4465        path = os.path.join(self.ufoPath, "glyphs.layer 2")
4466        exists = os.path.exists(path)
4467        self.assertEqual(True, exists)
4468        # layer contents
4469        path = os.path.join(self.ufoPath, "layercontents.plist")
4470        with open(path, "rb") as f:
4471            result = plistlib.load(f)
4472        expected = [["public.default", "glyphs"], ["layer 2", "glyphs.layer 2"]]
4473        self.assertEqual(expected, result)
4474
4475    # remove default layer
4476
4477    def testRemoveDefaultLayer(self):
4478        self.makeUFO()
4479        writer = UFOWriter(self.ufoPath)
4480        writer.deleteGlyphSet("public.default")
4481        writer.writeLayerContents(["layer 1", "layer 2"])
4482        # directories
4483        path = os.path.join(self.ufoPath, "glyphs")
4484        self.assertEqual(False, os.path.exists(path))
4485        path = os.path.join(self.ufoPath, "glyphs.layer 1")
4486        self.assertEqual(True, os.path.exists(path))
4487        path = os.path.join(self.ufoPath, "glyphs.layer 2")
4488        self.assertEqual(True, os.path.exists(path))
4489        # layer contents
4490        path = os.path.join(self.ufoPath, "layercontents.plist")
4491        with open(path, "rb") as f:
4492            result = plistlib.load(f)
4493        expected = [["layer 1", "glyphs.layer 1"], ["layer 2", "glyphs.layer 2"]]
4494        self.assertEqual(expected, result)
4495
4496    # remove unknown layer
4497
4498    def testRemoveDefaultLayer2(self):
4499        self.makeUFO()
4500        writer = UFOWriter(self.ufoPath)
4501        self.assertRaises(UFOLibError, writer.deleteGlyphSet, "does not exist")
4502
4503    def testWriteAsciiLayerOrder(self):
4504        self.makeUFO(
4505            layerContents=[
4506                ["public.default", "glyphs"],
4507                ["layer 1", "glyphs.layer 1"],
4508                ["layer 2", "glyphs.layer 2"],
4509            ]
4510        )
4511        writer = UFOWriter(self.ufoPath)
4512        writer.writeLayerContents(["public.default", "layer 2", "layer 1"])
4513        path = os.path.join(self.ufoPath, "layercontents.plist")
4514        with open(path, "rb") as f:
4515            result = plistlib.load(f)
4516        expected = [
4517            ["public.default", "glyphs"],
4518            ["layer 2", "glyphs.layer 2"],
4519            ["layer 1", "glyphs.layer 1"],
4520        ]
4521        self.assertEqual(expected, result)
4522        for layerName, _ in result:
4523            assert isinstance(layerName, str)
4524
4525
4526# -----
4527# /data
4528# -----
4529
4530
4531class UFO3ReadDataTestCase(unittest.TestCase):
4532    def getFontPath(self):
4533        testdata = os.path.join(os.path.dirname(__file__), "testdata")
4534        return os.path.join(testdata, "UFO3-Read Data.ufo")
4535
4536    def testUFOReaderDataDirectoryListing(self):
4537        reader = UFOReader(self.getFontPath())
4538        found = reader.getDataDirectoryListing()
4539        expected = [
4540            "org.unifiedfontobject.directory/bar/lol.txt",
4541            "org.unifiedfontobject.directory/foo.txt",
4542            "org.unifiedfontobject.file.txt",
4543        ]
4544        self.assertEqual(set(found), set(expected))
4545
4546    def testUFOReaderBytesFromPath(self):
4547        reader = UFOReader(self.getFontPath())
4548        found = reader.readBytesFromPath("data/org.unifiedfontobject.file.txt")
4549        expected = b"file.txt"
4550        self.assertEqual(found, expected)
4551        found = reader.readBytesFromPath(
4552            "data/org.unifiedfontobject.directory/bar/lol.txt"
4553        )
4554        expected = b"lol.txt"
4555        self.assertEqual(found, expected)
4556        found = reader.readBytesFromPath("data/org.unifiedfontobject.doesNotExist")
4557        expected = None
4558        self.assertEqual(found, expected)
4559
4560    def testUFOReaderReadFileFromPath(self):
4561        reader = UFOReader(self.getFontPath())
4562        fileObject = reader.getReadFileForPath("data/org.unifiedfontobject.file.txt")
4563        self.assertNotEqual(fileObject, None)
4564        hasRead = hasattr(fileObject, "read")
4565        self.assertEqual(hasRead, True)
4566        fileObject.close()
4567        fileObject = reader.getReadFileForPath(
4568            "data/org.unifiedfontobject.doesNotExist"
4569        )
4570        self.assertEqual(fileObject, None)
4571
4572    def testUFOReaderKernGroupDuplicatesRemoved(self):
4573        # Non-kerning group duplicates are kept
4574        # Kerning group duplicates are removed
4575        expected_groups = {
4576            "group1": ["A"],
4577            "group2": ["B", "C", "B"],
4578            "public.kern1.A": ["A"],
4579            "public.kern2.B": ["B", "A", "C"],
4580        }
4581        reader = UFOReader(self.getFontPath())
4582        groups = reader.readGroups()
4583        self.assertEqual(expected_groups, groups)
4584
4585
4586class UFO3WriteDataTestCase(unittest.TestCase):
4587    def setUp(self):
4588        self.tempDir = tempfile.mktemp()
4589        os.mkdir(self.tempDir)
4590        self.dstDir = os.path.join(self.tempDir, "test.ufo")
4591
4592    def tearDown(self):
4593        shutil.rmtree(self.tempDir)
4594
4595    def tearDownUFO(self):
4596        if os.path.exists(self.dstDir):
4597            shutil.rmtree(self.dstDir)
4598
4599    def testUFOWriterWriteBytesToPath(self):
4600        # basic file
4601        path = "data/org.unifiedfontobject.writebytesbasicfile.txt"
4602        testBytes = b"test"
4603        writer = UFOWriter(self.dstDir, formatVersion=3)
4604        writer.writeBytesToPath(path, testBytes)
4605        path = os.path.join(self.dstDir, path)
4606        self.assertEqual(os.path.exists(path), True)
4607        with open(path, "rb") as f:
4608            written = f.read()
4609        self.assertEqual(testBytes, written)
4610        self.tearDownUFO()
4611        # basic file with unicode text
4612        path = "data/org.unifiedfontobject.writebytesbasicunicodefile.txt"
4613        text = b"t\xeb\xdft"
4614        writer = UFOWriter(self.dstDir, formatVersion=3)
4615        writer.writeBytesToPath(path, text)
4616        path = os.path.join(self.dstDir, path)
4617        self.assertEqual(os.path.exists(path), True)
4618        with open(path, "rb") as f:
4619            written = f.read()
4620        self.assertEqual(text, written)
4621        self.tearDownUFO()
4622        # basic directory
4623        path = "data/org.unifiedfontobject.writebytesdirectory/level1/level2/file.txt"
4624        testBytes = b"test"
4625        writer = UFOWriter(self.dstDir, formatVersion=3)
4626        writer.writeBytesToPath(path, testBytes)
4627        path = os.path.join(self.dstDir, path)
4628        self.assertEqual(os.path.exists(path), True)
4629        with open(path, "rb") as f:
4630            written = f.read()
4631        self.assertEqual(testBytes, written)
4632        self.tearDownUFO()
4633
4634    def testUFOWriterWriteFileToPath(self):
4635        # basic file
4636        path = "data/org.unifiedfontobject.getwritefile.txt"
4637        writer = UFOWriter(self.dstDir, formatVersion=3)
4638        fileObject = writer.getFileObjectForPath(path)
4639        self.assertNotEqual(fileObject, None)
4640        hasRead = hasattr(fileObject, "read")
4641        self.assertEqual(hasRead, True)
4642        fileObject.close()
4643        self.tearDownUFO()
4644
4645    def testUFOWriterRemoveFile(self):
4646        path1 = "data/org.unifiedfontobject.removefile/level1/level2/file1.txt"
4647        path2 = "data/org.unifiedfontobject.removefile/level1/level2/file2.txt"
4648        path3 = "data/org.unifiedfontobject.removefile/level1/file3.txt"
4649        writer = UFOWriter(self.dstDir, formatVersion=3)
4650        writer.writeBytesToPath(path1, b"test")
4651        writer.writeBytesToPath(path2, b"test")
4652        writer.writeBytesToPath(path3, b"test")
4653        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path1)), True)
4654        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path2)), True)
4655        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path3)), True)
4656        writer.removeFileForPath(path1)
4657        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path1)), False)
4658        self.assertEqual(
4659            os.path.exists(os.path.dirname(os.path.join(self.dstDir, path1))), True
4660        )
4661        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path2)), True)
4662        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path3)), True)
4663        writer.removeFileForPath(path2)
4664        self.assertEqual(
4665            os.path.exists(os.path.dirname(os.path.join(self.dstDir, path1))), False
4666        )
4667        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path2)), False)
4668        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path3)), True)
4669        writer.removeFileForPath(path3)
4670        self.assertEqual(os.path.exists(os.path.join(self.dstDir, path3)), False)
4671        self.assertEqual(
4672            os.path.exists(os.path.dirname(os.path.join(self.dstDir, path2))), False
4673        )
4674        self.assertEqual(
4675            os.path.exists(
4676                os.path.join(self.dstDir, "data/org.unifiedfontobject.removefile")
4677            ),
4678            False,
4679        )
4680        self.assertRaises(
4681            UFOLibError,
4682            writer.removeFileForPath,
4683            path="data/org.unifiedfontobject.doesNotExist.txt",
4684        )
4685        self.tearDownUFO()
4686
4687    def testUFOWriterCopy(self):
4688        sourceDir = self.dstDir.replace(".ufo", "") + "-copy source" + ".ufo"
4689        dataPath = "data/org.unifiedfontobject.copy/level1/level2/file1.txt"
4690        writer = UFOWriter(sourceDir, formatVersion=3)
4691        writer.writeBytesToPath(dataPath, b"test")
4692        # copy a file
4693        reader = UFOReader(sourceDir)
4694        writer = UFOWriter(self.dstDir, formatVersion=3)
4695        writer.copyFromReader(reader, dataPath, dataPath)
4696        path = os.path.join(self.dstDir, dataPath)
4697        self.assertEqual(os.path.exists(path), True)
4698        self.tearDownUFO()
4699        # copy a directory
4700        reader = UFOReader(sourceDir)
4701        writer = UFOWriter(self.dstDir, formatVersion=3)
4702        p = "data/org.unifiedfontobject.copy"
4703        writer.copyFromReader(reader, p, p)
4704        path = os.path.join(self.dstDir, dataPath)
4705        self.assertEqual(os.path.exists(path), True)
4706        self.tearDownUFO()
4707
4708
4709# ---------------
4710# layerinfo.plist
4711# ---------------
4712
4713
4714class TestLayerInfoObject:
4715    color = guidelines = lib = None
4716
4717
4718class UFO3ReadLayerInfoTestCase(unittest.TestCase):
4719    def setUp(self):
4720        self.tempDir = tempfile.mktemp()
4721        os.mkdir(self.tempDir)
4722        self.ufoPath = os.path.join(self.tempDir, "test.ufo")
4723
4724    def tearDown(self):
4725        shutil.rmtree(self.tempDir)
4726
4727    def makeUFO(self, formatVersion=3, layerInfo=None):
4728        self.clearUFO()
4729        if not os.path.exists(self.ufoPath):
4730            os.mkdir(self.ufoPath)
4731        # metainfo.plist
4732        metaInfo = dict(creator="test", formatVersion=formatVersion)
4733        path = os.path.join(self.ufoPath, "metainfo.plist")
4734        with open(path, "wb") as f:
4735            plistlib.dump(metaInfo, f)
4736        # layercontents.plist
4737        layerContents = [("public.default", "glyphs")]
4738        path = os.path.join(self.ufoPath, "layercontents.plist")
4739        with open(path, "wb") as f:
4740            plistlib.dump(layerContents, f)
4741        # glyphs
4742        glyphsPath = os.path.join(self.ufoPath, "glyphs")
4743        os.mkdir(glyphsPath)
4744        contents = dict(a="a.glif")
4745        path = os.path.join(glyphsPath, "contents.plist")
4746        with open(path, "wb") as f:
4747            plistlib.dump(contents, f)
4748        path = os.path.join(glyphsPath, "a.glif")
4749        with open(path, "w") as f:
4750            f.write(" ")
4751        # layerinfo.plist
4752        if layerInfo is None:
4753            layerInfo = dict(color="0,0,0,1", lib={"foo": "bar"})
4754        path = os.path.join(glyphsPath, "layerinfo.plist")
4755        with open(path, "wb") as f:
4756            plistlib.dump(layerInfo, f)
4757
4758    def clearUFO(self):
4759        if os.path.exists(self.ufoPath):
4760            shutil.rmtree(self.ufoPath)
4761
4762    def testValidLayerInfo(self):
4763        self.makeUFO()
4764        reader = UFOReader(self.ufoPath, validate=True)
4765        glyphSet = reader.getGlyphSet()
4766        info = TestLayerInfoObject()
4767        glyphSet.readLayerInfo(info)
4768        expectedColor = "0,0,0,1"
4769        self.assertEqual(expectedColor, info.color)
4770        expectedLib = {"foo": "bar"}
4771        self.assertEqual(expectedLib, info.lib)
4772
4773    def testMissingLayerInfo(self):
4774        self.makeUFO()
4775        path = os.path.join(self.ufoPath, "glyphs", "layerinfo.plist")
4776        os.remove(path)
4777        # read
4778        reader = UFOReader(self.ufoPath, validate=True)
4779        glyphSet = reader.getGlyphSet()
4780        info = TestLayerInfoObject()
4781        glyphSet.readLayerInfo(info)
4782        self.assertEqual(None, info.color)
4783        self.assertEqual(None, info.guidelines)
4784        self.assertEqual(None, info.lib)
4785
4786    def testBogusLayerInfo(self):
4787        self.makeUFO()
4788        path = os.path.join(self.ufoPath, "glyphs", "layerinfo.plist")
4789        os.remove(path)
4790        with open(path, "w") as f:
4791            f.write("test")
4792        # read
4793        reader = UFOReader(self.ufoPath, validate=True)
4794        glyphSet = reader.getGlyphSet()
4795        info = TestLayerInfoObject()
4796        self.assertRaises(UFOLibError, glyphSet.readLayerInfo, info)
4797
4798    def testInvalidFormatLayerInfo(self):
4799        self.makeUFO()
4800        path = os.path.join(self.ufoPath, "glyphs", "layerinfo.plist")
4801        info = [("color", "0,0,0,0")]
4802        with open(path, "wb") as f:
4803            plistlib.dump(info, f)
4804        # read
4805        reader = UFOReader(self.ufoPath, validate=True)
4806        glyphSet = reader.getGlyphSet()
4807        info = TestLayerInfoObject()
4808        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, info)
4809
4810    def testColor(self):
4811        ## not a string
4812        info = {}
4813        info["color"] = 1
4814        self.makeUFO(layerInfo=info)
4815        reader = UFOReader(self.ufoPath, validate=True)
4816        glyphSet = reader.getGlyphSet()
4817        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4818        ## not enough commas
4819        info = {}
4820        info["color"] = "1 0, 0, 0"
4821        self.makeUFO(layerInfo=info)
4822        reader = UFOReader(self.ufoPath, validate=True)
4823        glyphSet = reader.getGlyphSet()
4824        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4825        info = {}
4826        info["color"] = "1 0 0, 0"
4827        self.makeUFO(layerInfo=info)
4828        reader = UFOReader(self.ufoPath, validate=True)
4829        glyphSet = reader.getGlyphSet()
4830        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4831        info = {}
4832        info["color"] = "1 0 0 0"
4833        self.makeUFO(layerInfo=info)
4834        reader = UFOReader(self.ufoPath, validate=True)
4835        glyphSet = reader.getGlyphSet()
4836        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4837        ## not enough parts
4838        info = {}
4839        info["color"] = ", 0, 0, 0"
4840        self.makeUFO(layerInfo=info)
4841        reader = UFOReader(self.ufoPath, validate=True)
4842        glyphSet = reader.getGlyphSet()
4843        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4844        info = {}
4845        info["color"] = "1, , 0, 0"
4846        self.makeUFO(layerInfo=info)
4847        reader = UFOReader(self.ufoPath, validate=True)
4848        glyphSet = reader.getGlyphSet()
4849        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4850        info = {}
4851        info["color"] = "1, 0, , 0"
4852        self.makeUFO(layerInfo=info)
4853        reader = UFOReader(self.ufoPath, validate=True)
4854        glyphSet = reader.getGlyphSet()
4855        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4856        info = {}
4857        info["color"] = "1, 0, 0, "
4858        self.makeUFO(layerInfo=info)
4859        reader = UFOReader(self.ufoPath, validate=True)
4860        glyphSet = reader.getGlyphSet()
4861        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4862        info = {}
4863        info["color"] = ", , , "
4864        self.makeUFO(layerInfo=info)
4865        reader = UFOReader(self.ufoPath, validate=True)
4866        glyphSet = reader.getGlyphSet()
4867        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4868        ## not a number in all positions
4869        info = {}
4870        info["color"] = "r, 1, 1, 1"
4871        self.makeUFO(layerInfo=info)
4872        reader = UFOReader(self.ufoPath, validate=True)
4873        glyphSet = reader.getGlyphSet()
4874        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4875        info = {}
4876        info["color"] = "1, g, 1, 1"
4877        self.makeUFO(layerInfo=info)
4878        reader = UFOReader(self.ufoPath, validate=True)
4879        glyphSet = reader.getGlyphSet()
4880        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4881        info = {}
4882        info["color"] = "1, 1, b, 1"
4883        self.makeUFO(layerInfo=info)
4884        reader = UFOReader(self.ufoPath, validate=True)
4885        glyphSet = reader.getGlyphSet()
4886        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4887        info = {}
4888        info["color"] = "1, 1, 1, a"
4889        self.makeUFO(layerInfo=info)
4890        reader = UFOReader(self.ufoPath, validate=True)
4891        glyphSet = reader.getGlyphSet()
4892        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4893        ## too many parts
4894        info = {}
4895        info["color"] = "1, 0, 0, 0, 0"
4896        self.makeUFO(layerInfo=info)
4897        reader = UFOReader(self.ufoPath, validate=True)
4898        glyphSet = reader.getGlyphSet()
4899        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4900        ## < 0 in each position
4901        info = {}
4902        info["color"] = "-1, 0, 0, 0"
4903        self.makeUFO(layerInfo=info)
4904        reader = UFOReader(self.ufoPath, validate=True)
4905        glyphSet = reader.getGlyphSet()
4906        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4907        info = {}
4908        info["color"] = "0, -1, 0, 0"
4909        self.makeUFO(layerInfo=info)
4910        reader = UFOReader(self.ufoPath, validate=True)
4911        glyphSet = reader.getGlyphSet()
4912        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4913        info = {}
4914        info["color"] = "0, 0, -1, 0"
4915        self.makeUFO(layerInfo=info)
4916        reader = UFOReader(self.ufoPath, validate=True)
4917        glyphSet = reader.getGlyphSet()
4918        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4919        info = {}
4920        info["color"] = "0, 0, 0, -1"
4921        self.makeUFO(layerInfo=info)
4922        reader = UFOReader(self.ufoPath, validate=True)
4923        glyphSet = reader.getGlyphSet()
4924        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4925        ## > 1 in each position
4926        info = {}
4927        info["color"] = "2, 0, 0, 0"
4928        self.makeUFO(layerInfo=info)
4929        reader = UFOReader(self.ufoPath, validate=True)
4930        glyphSet = reader.getGlyphSet()
4931        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4932        info = {}
4933        info["color"] = "0, 2, 0, 0"
4934        self.makeUFO(layerInfo=info)
4935        reader = UFOReader(self.ufoPath, validate=True)
4936        glyphSet = reader.getGlyphSet()
4937        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4938        info = {}
4939        info["color"] = "0, 0, 2, 0"
4940        self.makeUFO(layerInfo=info)
4941        reader = UFOReader(self.ufoPath, validate=True)
4942        glyphSet = reader.getGlyphSet()
4943        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4944        info = {}
4945        info["color"] = "0, 0, 0, 2"
4946        self.makeUFO(layerInfo=info)
4947        reader = UFOReader(self.ufoPath, validate=True)
4948        glyphSet = reader.getGlyphSet()
4949        self.assertRaises(GlifLibError, glyphSet.readLayerInfo, TestLayerInfoObject())
4950
4951
4952class UFO3WriteLayerInfoTestCase(unittest.TestCase):
4953    def setUp(self):
4954        self.tempDir = tempfile.mktemp()
4955        os.mkdir(self.tempDir)
4956        self.ufoPath = os.path.join(self.tempDir, "test.ufo")
4957
4958    def tearDown(self):
4959        shutil.rmtree(self.tempDir)
4960
4961    def makeGlyphSet(self):
4962        self.clearUFO()
4963        writer = UFOWriter(self.ufoPath)
4964        return writer.getGlyphSet()
4965
4966    def clearUFO(self):
4967        if os.path.exists(self.ufoPath):
4968            shutil.rmtree(self.ufoPath)
4969
4970    def testValidWrite(self):
4971        expected = dict(color="0,0,0,1", lib={"foo": "bar"})
4972        info = TestLayerInfoObject()
4973        info.color = expected["color"]
4974        info.lib = expected["lib"]
4975        glyphSet = self.makeGlyphSet()
4976        glyphSet.writeLayerInfo(info)
4977        path = os.path.join(self.ufoPath, "glyphs", "layerinfo.plist")
4978        with open(path, "rb") as f:
4979            result = plistlib.load(f)
4980        self.assertEqual(expected, result)
4981
4982    def testColor(self):
4983        ## not a string
4984        info = TestLayerInfoObject()
4985        info.color = 1
4986        glyphSet = self.makeGlyphSet()
4987        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
4988        ## not enough commas
4989        info = TestLayerInfoObject()
4990        info.color = "1 0, 0, 0"
4991        glyphSet = self.makeGlyphSet()
4992        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
4993        info = TestLayerInfoObject()
4994        info.color = "1 0 0, 0"
4995        glyphSet = self.makeGlyphSet()
4996        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
4997        info = TestLayerInfoObject()
4998        info.color = "1 0 0 0"
4999        glyphSet = self.makeGlyphSet()
5000        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5001        ## not enough parts
5002        info = TestLayerInfoObject()
5003        info.color = ", 0, 0, 0"
5004        glyphSet = self.makeGlyphSet()
5005        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5006        info = TestLayerInfoObject()
5007        info.color = "1, , 0, 0"
5008        glyphSet = self.makeGlyphSet()
5009        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5010        info = TestLayerInfoObject()
5011        info.color = "1, 0, , 0"
5012        glyphSet = self.makeGlyphSet()
5013        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5014        info = TestLayerInfoObject()
5015        info.color = "1, 0, 0, "
5016        glyphSet = self.makeGlyphSet()
5017        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5018        info = TestLayerInfoObject()
5019        info.color = ", , , "
5020        glyphSet = self.makeGlyphSet()
5021        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5022        ## not a number in all positions
5023        info = TestLayerInfoObject()
5024        info.color = "r, 1, 1, 1"
5025        glyphSet = self.makeGlyphSet()
5026        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5027        info = TestLayerInfoObject()
5028        info.color = "1, g, 1, 1"
5029        glyphSet = self.makeGlyphSet()
5030        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5031        info = TestLayerInfoObject()
5032        info.color = "1, 1, b, 1"
5033        glyphSet = self.makeGlyphSet()
5034        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5035        info = TestLayerInfoObject()
5036        info.color = "1, 1, 1, a"
5037        glyphSet = self.makeGlyphSet()
5038        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5039        ## too many parts
5040        info = TestLayerInfoObject()
5041        info.color = "1, 0, 0, 0, 0"
5042        glyphSet = self.makeGlyphSet()
5043        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5044        ## < 0 in each position
5045        info = TestLayerInfoObject()
5046        info.color = "-1, 0, 0, 0"
5047        glyphSet = self.makeGlyphSet()
5048        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5049        info = TestLayerInfoObject()
5050        info.color = "0, -1, 0, 0"
5051        glyphSet = self.makeGlyphSet()
5052        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5053        info = TestLayerInfoObject()
5054        info.color = "0, 0, -1, 0"
5055        glyphSet = self.makeGlyphSet()
5056        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5057        info = TestLayerInfoObject()
5058        info.color = "0, 0, 0, -1"
5059        glyphSet = self.makeGlyphSet()
5060        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5061        ## > 1 in each position
5062        info = TestLayerInfoObject()
5063        info.color = "2, 0, 0, 0"
5064        glyphSet = self.makeGlyphSet()
5065        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5066        info = TestLayerInfoObject()
5067        info.color = "0, 2, 0, 0"
5068        glyphSet = self.makeGlyphSet()
5069        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5070        info = TestLayerInfoObject()
5071        info.color = "0, 0, 2, 0"
5072        glyphSet = self.makeGlyphSet()
5073        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5074        info = TestLayerInfoObject()
5075        info.color = "0, 0, 0, 2"
5076        glyphSet = self.makeGlyphSet()
5077        self.assertRaises(GlifLibError, glyphSet.writeLayerInfo, info)
5078