xref: /aosp_15_r20/external/fonttools/Tests/ufoLib/GLIF1_test.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1import unittest
2from fontTools.ufoLib.glifLib import (
3    GlifLibError,
4    readGlyphFromString,
5    writeGlyphToString,
6)
7from .testSupport import Glyph, stripText
8from itertools import islice
9
10# ----------
11# Test Cases
12# ----------
13
14
15class TestGLIF1(unittest.TestCase):
16    def assertEqual(self, first, second, msg=None):
17        if isinstance(first, str):
18            first = stripText(first)
19        if isinstance(second, str):
20            second = stripText(second)
21        return super().assertEqual(first, second, msg=msg)
22
23    def pyToGLIF(self, py):
24        py = stripText(py)
25        glyph = Glyph()
26        exec(py, {"glyph": glyph, "pointPen": glyph})
27        glif = writeGlyphToString(
28            glyph.name,
29            glyphObject=glyph,
30            drawPointsFunc=glyph.drawPoints,
31            formatVersion=1,
32            validate=True,
33        )
34        # discard the first line containing the xml declaration
35        return "\n".join(islice(glif.splitlines(), 1, None))
36
37    def glifToPy(self, glif):
38        glif = stripText(glif)
39        glif = '<?xml version="1.0"?>\n' + glif
40        glyph = Glyph()
41        readGlyphFromString(glif, glyphObject=glyph, pointPen=glyph, validate=True)
42        return glyph.py()
43
44    def testTopElement(self):
45        # not glyph
46        glif = """
47		<notglyph name="a" format="1">
48			<outline>
49			</outline>
50		</notglyph>
51		"""
52        self.assertRaises(GlifLibError, self.glifToPy, glif)
53
54    def testName_legal(self):
55        # legal
56        glif = """
57		<glyph name="a" format="1">
58			<outline>
59			</outline>
60		</glyph>
61		"""
62        py = """
63		glyph.name = "a"
64		"""
65        resultGlif = self.pyToGLIF(py)
66        resultPy = self.glifToPy(glif)
67        self.assertEqual(glif, resultGlif)
68        self.assertEqual(py, resultPy)
69
70    def testName_empty(self):
71        # empty
72        glif = """
73		<glyph name="" format="1">
74			<outline>
75			</outline>
76		</glyph>
77		"""
78        py = """
79		glyph.name = ""
80		"""
81        self.assertRaises(GlifLibError, self.pyToGLIF, py)
82        self.assertRaises(GlifLibError, self.glifToPy, glif)
83
84    def testName_not_a_string(self):
85        # not a string
86        py = """
87		glyph.name = 1
88		"""
89        self.assertRaises(GlifLibError, self.pyToGLIF, py)
90
91    def testFormat_legal(self):
92        # legal
93        glif = """
94		<glyph name="a" format="1">
95			<outline>
96			</outline>
97		</glyph>
98		"""
99        py = """
100		glyph.name = "a"
101		"""
102        resultGlif = self.pyToGLIF(py)
103        resultPy = self.glifToPy(glif)
104        self.assertEqual(glif, resultGlif)
105        self.assertEqual(py, resultPy)
106
107    def testFormat_wrong_number(self):
108        # wrong number
109        glif = """
110		<glyph name="a" format="-1">
111			<outline>
112			</outline>
113		</glyph>
114		"""
115        self.assertRaises(GlifLibError, self.glifToPy, glif)
116
117    def testFormat_not_an_int(self):
118        # not an int
119        glif = """
120		<glyph name="a" format="A">
121			<outline>
122			</outline>
123		</glyph>
124		"""
125        self.assertRaises(GlifLibError, self.glifToPy, glif)
126
127    def testBogusGlyphStructure_unknown_element(self):
128        # unknown element
129        glif = """
130		<glyph name="a" format="1">
131			<unknown />
132		</glyph>
133		"""
134        self.assertRaises(GlifLibError, self.glifToPy, glif)
135
136    def testBogusGlyphStructure_content(self):
137        # content
138        glif = """
139		<glyph name="a" format="1">
140			Hello World.
141		</glyph>
142		"""
143        self.assertRaises(GlifLibError, self.glifToPy, glif)
144
145    def testAdvance_legal_width_and_height(self):
146        # legal: width and height
147        glif = """
148		<glyph name="a" format="1">
149			<advance height="200" width="100"/>
150			<outline>
151			</outline>
152		</glyph>
153		"""
154        py = """
155		glyph.name = "a"
156		glyph.width = 100
157		glyph.height = 200
158		"""
159        resultGlif = self.pyToGLIF(py)
160        resultPy = self.glifToPy(glif)
161        self.assertEqual(glif, resultGlif)
162        self.assertEqual(py, resultPy)
163
164    def testAdvance_legal_width_and_height_floats(self):
165        # legal: width and height floats
166        glif = """
167		<glyph name="a" format="1">
168			<advance height="200.1" width="100.1"/>
169			<outline>
170			</outline>
171		</glyph>
172		"""
173        py = """
174		glyph.name = "a"
175		glyph.width = 100.1
176		glyph.height = 200.1
177		"""
178        resultGlif = self.pyToGLIF(py)
179        resultPy = self.glifToPy(glif)
180        self.assertEqual(glif, resultGlif)
181        self.assertEqual(py, resultPy)
182
183    def testAdvance_legal_width(self):
184        # legal: width
185        glif = """
186		<glyph name="a" format="1">
187			<advance width="100"/>
188			<outline>
189			</outline>
190		</glyph>
191		"""
192        py = """
193		glyph.name = "a"
194		glyph.width = 100
195		"""
196        resultGlif = self.pyToGLIF(py)
197        resultPy = self.glifToPy(glif)
198        self.assertEqual(glif, resultGlif)
199        self.assertEqual(py, resultPy)
200
201    def testAdvance_legal_height(self):
202        # legal: height
203        glif = """
204		<glyph name="a" format="1">
205			<advance height="200"/>
206			<outline>
207			</outline>
208		</glyph>
209		"""
210        py = """
211		glyph.name = "a"
212		glyph.height = 200
213		"""
214        resultGlif = self.pyToGLIF(py)
215        resultPy = self.glifToPy(glif)
216        self.assertEqual(glif, resultGlif)
217        self.assertEqual(py, resultPy)
218
219    def testAdvance_illegal_width(self):
220        # illegal: not a number
221        glif = """
222		<glyph name="a" format="1">
223			<advance width="a"/>
224			<outline>
225			</outline>
226		</glyph>
227		"""
228        py = """
229		glyph.name = "a"
230		glyph.width = "a"
231		"""
232        self.assertRaises(GlifLibError, self.pyToGLIF, py)
233        self.assertRaises(GlifLibError, self.glifToPy, glif)
234
235    def testAdvance_illegal_height(self):
236        glif = """
237		<glyph name="a" format="1">
238			<advance height="a"/>
239			<outline>
240			</outline>
241		</glyph>
242		"""
243        py = """
244		glyph.name = "a"
245		glyph.height = "a"
246		"""
247        self.assertRaises(GlifLibError, self.pyToGLIF, py)
248        self.assertRaises(GlifLibError, self.glifToPy, glif)
249
250    def testUnicodes_legal(self):
251        # legal
252        glif = """
253		<glyph name="a" format="1">
254			<unicode hex="0061"/>
255			<outline>
256			</outline>
257		</glyph>
258		"""
259        py = """
260		glyph.name = "a"
261		glyph.unicodes = [97]
262		"""
263        resultGlif = self.pyToGLIF(py)
264        resultPy = self.glifToPy(glif)
265        self.assertEqual(glif, resultGlif)
266        self.assertEqual(py, resultPy)
267
268    def testUnicodes_legal_multiple(self):
269        glif = """
270		<glyph name="a" format="1">
271			<unicode hex="0062"/>
272			<unicode hex="0063"/>
273			<unicode hex="0061"/>
274			<outline>
275			</outline>
276		</glyph>
277		"""
278        py = """
279		glyph.name = "a"
280		glyph.unicodes = [98, 99, 97]
281		"""
282        resultGlif = self.pyToGLIF(py)
283        resultPy = self.glifToPy(glif)
284        self.assertEqual(glif, resultGlif)
285        self.assertEqual(py, resultPy)
286
287    def testUnicodes_illegal(self):
288        # illegal
289        glif = """
290		<glyph name="a" format="1">
291			<unicode hex="1.1"/>
292			<outline>
293			</outline>
294		</glyph>
295		"""
296        py = """
297		glyph.name = "zzzzzz"
298		glyph.unicodes = ["1.1"]
299		"""
300        self.assertRaises(GlifLibError, self.pyToGLIF, py)
301        self.assertRaises(GlifLibError, self.glifToPy, glif)
302
303    def testNote(self):
304        glif = """
305		<glyph name="a" format="1">
306			<note>
307				\U0001F4A9
308			</note>
309			<outline>
310			</outline>
311		</glyph>
312		"""
313        py = """
314		glyph.name = "a"
315		glyph.note = "��"
316		"""
317        resultGlif = self.pyToGLIF(py)
318        resultPy = self.glifToPy(glif)
319        self.assertEqual(glif, resultGlif)
320        self.assertEqual(py, resultPy)
321
322    def testLib_legal(self):
323        glif = """
324		<glyph name="a" format="1">
325			<outline>
326			</outline>
327			<lib>
328				<dict>
329					<key>dict</key>
330					<dict>
331						<key>hello</key>
332						<string>world</string>
333					</dict>
334					<key>float</key>
335					<real>2.5</real>
336					<key>int</key>
337					<integer>1</integer>
338					<key>list</key>
339					<array>
340						<string>a</string>
341						<string>b</string>
342						<integer>1</integer>
343						<real>2.5</real>
344					</array>
345					<key>string</key>
346					<string>a</string>
347				</dict>
348			</lib>
349		</glyph>
350		"""
351        py = """
352		glyph.name = "a"
353		glyph.lib = {"dict" : {"hello" : "world"}, "float" : 2.5, "int" : 1, "list" : ["a", "b", 1, 2.5], "string" : "a"}
354		"""
355        resultGlif = self.pyToGLIF(py)
356        resultPy = self.glifToPy(glif)
357        self.assertEqual(glif, resultGlif)
358        self.assertEqual(py, resultPy)
359
360    def testOutline_unknown_element(self):
361        # unknown element
362        glif = """
363		<glyph name="a" format="1">
364			<outline>
365				<unknown/>
366			</outline>
367		</glyph>
368		"""
369        self.assertRaises(GlifLibError, self.glifToPy, glif)
370
371    def testOutline_content(self):
372        # content
373        glif = """
374		<glyph name="a" format="1">
375			<outline>
376				hello
377			</outline>
378		</glyph>
379		"""
380        self.assertRaises(GlifLibError, self.glifToPy, glif)
381
382    def testComponent_legal(self):
383        # legal
384        glif = """
385		<glyph name="a" format="1">
386			<outline>
387				<component base="x" xScale="2" xyScale="3" yxScale="6" yScale="5" xOffset="1" yOffset="4"/>
388			</outline>
389		</glyph>
390		"""
391        py = """
392		glyph.name = "a"
393		pointPen.addComponent(*["x", (2, 3, 6, 5, 1, 4)])
394		"""
395        resultGlif = self.pyToGLIF(py)
396        resultPy = self.glifToPy(glif)
397        self.assertEqual(glif, resultGlif)
398        self.assertEqual(py, resultPy)
399
400    def testComponent_illegal_no_base(self):
401        # no base
402        glif = """
403		<glyph name="a" format="1">
404			<outline>
405				<component xScale="2" xyScale="3" yxScale="6" yScale="5" xOffset="1" yOffset="4"/>
406			</outline>
407		</glyph>
408		"""
409        self.assertRaises(GlifLibError, self.glifToPy, glif)
410
411    def testComponent_bogus_transformation(self):
412        # bogus values in transformation
413        glif = """
414		<glyph name="a" format="1">
415			<outline>
416				<component base="x" xScale="a" xyScale="3" yxScale="6" yScale="5" xOffset="1" yOffset="4"/>
417			</outline>
418		</glyph>
419		"""
420        py = """
421		glyph.name = "a"
422		pointPen.addComponent(*["x", ("a", 3, 6, 5, 1, 4)])
423		"""
424        self.assertRaises(GlifLibError, self.pyToGLIF, py)
425        self.assertRaises(GlifLibError, self.glifToPy, glif)
426        glif = """
427		<glyph name="a" format="1">
428			<outline>
429				<component base="x" xScale="a" xyScale="3" yxScale="6" yScale="5" xOffset="1" yOffset="4"/>
430			</outline>
431		</glyph>
432		"""
433        py = """
434		glyph.name = "a"
435		pointPen.addComponent(*["x", (2, "a", 6, 5, 1, 4)])
436		"""
437        self.assertRaises(GlifLibError, self.pyToGLIF, py)
438        self.assertRaises(GlifLibError, self.glifToPy, glif)
439        glif = """
440		<glyph name="a" format="1">
441			<outline>
442				<component base="x" xScale="2" xyScale="3" yxScale="a" yScale="5" xOffset="1" yOffset="4"/>
443			</outline>
444		</glyph>
445		"""
446        py = """
447		glyph.name = "a"
448		pointPen.addComponent(*["x", (2, 3, "a", 5, 1, 4)])
449		"""
450        self.assertRaises(GlifLibError, self.pyToGLIF, py)
451        self.assertRaises(GlifLibError, self.glifToPy, glif)
452        glif = """
453		<glyph name="a" format="1">
454			<outline>
455				<component base="x" xScale="2" xyScale="3" yxScale="6" yScale="a" xOffset="1" yOffset="4"/>
456			</outline>
457		</glyph>
458		"""
459        py = """
460		glyph.name = "a"
461		pointPen.addComponent(*["x", (2, 3, 6, "a", 1, 4)])
462		"""
463        self.assertRaises(GlifLibError, self.pyToGLIF, py)
464        self.assertRaises(GlifLibError, self.glifToPy, glif)
465        glif = """
466		<glyph name="a" format="1">
467			<outline>
468				<component base="x" xScale="2" xyScale="3" yxScale="6" yScale="5" xOffset="a" yOffset="4"/>
469			</outline>
470		</glyph>
471		"""
472        py = """
473		glyph.name = "a"
474		pointPen.addComponent(*["x", (2, 3, 6, 5, "a", 4)])
475		"""
476        self.assertRaises(GlifLibError, self.pyToGLIF, py)
477        self.assertRaises(GlifLibError, self.glifToPy, glif)
478        glif = """
479		<glyph name="a" format="1">
480			<outline>
481				<component base="x" xScale="2" xyScale="3" yxScale="6" yScale="5" xOffset="1" yOffset="a"/>
482			</outline>
483		</glyph>
484		"""
485        py = """
486		glyph.name = "a"
487		pointPen.addComponent(*["x", (2, 3, 6, 5, 1, "a")])
488		"""
489        self.assertRaises(GlifLibError, self.pyToGLIF, py)
490        self.assertRaises(GlifLibError, self.glifToPy, glif)
491
492    def testContour_legal_one_contour(self):
493        # legal: one contour
494        glif = """
495		<glyph name="a" format="1">
496			<outline>
497				<contour>
498				</contour>
499			</outline>
500		</glyph>
501		"""
502        py = """
503		glyph.name = "a"
504		pointPen.beginPath()
505		pointPen.endPath()
506		"""
507        resultGlif = self.pyToGLIF(py)
508        resultPy = self.glifToPy(glif)
509        self.assertEqual(glif, resultGlif)
510        self.assertEqual(py, resultPy)
511
512    def testContour_legal_two_contours(self):
513        # legal: two contours
514        glif = """
515		<glyph name="a" format="1">
516			<outline>
517				<contour>
518					<point x="1" y="2" type="move"/>
519					<point x="10" y="20" type="line"/>
520				</contour>
521				<contour>
522					<point x="1" y="2" type="move"/>
523					<point x="10" y="20" type="line"/>
524				</contour>
525			</outline>
526		</glyph>
527		"""
528        py = """
529		glyph.name = "a"
530		pointPen.beginPath()
531		pointPen.addPoint(*[(1, 2)], **{"segmentType" : "move", "smooth" : False})
532		pointPen.addPoint(*[(10, 20)], **{"segmentType" : "line", "smooth" : False})
533		pointPen.endPath()
534		pointPen.beginPath()
535		pointPen.addPoint(*[(1, 2)], **{"segmentType" : "move", "smooth" : False})
536		pointPen.addPoint(*[(10, 20)], **{"segmentType" : "line", "smooth" : False})
537		pointPen.endPath()
538		"""
539        resultGlif = self.pyToGLIF(py)
540        resultPy = self.glifToPy(glif)
541        self.assertEqual(glif, resultGlif)
542        self.assertEqual(py, resultPy)
543
544    def testContour_illegal_unkonwn_element(self):
545        # unknown element
546        glif = """
547		<glyph name="a" format="1">
548			<outline>
549				<contour>
550					<unknown/>
551				</contour>
552			</outline>
553		</glyph>
554		"""
555        self.assertRaises(GlifLibError, self.glifToPy, glif)
556
557    def testPointCoordinates_legal_int(self):
558        # legal: int
559        glif = """
560		<glyph name="a" format="1">
561			<outline>
562				<contour>
563					<point x="1" y="-2" type="move"/>
564					<point x="0" y="0" type="line" name="this is here so that the contour isn't seen as an anchor"/>
565				</contour>
566			</outline>
567		</glyph>
568		"""
569        py = """
570		glyph.name = "a"
571		pointPen.beginPath()
572		pointPen.addPoint(*[(1, -2)], **{"segmentType" : "move", "smooth" : False})
573		pointPen.addPoint(*[(0, 0)], **{"name" : "this is here so that the contour isn't seen as an anchor", "segmentType" : "line", "smooth" : False})
574		pointPen.endPath()
575		"""
576        resultGlif = self.pyToGLIF(py)
577        resultPy = self.glifToPy(glif)
578        self.assertEqual(glif, resultGlif)
579        self.assertEqual(py, resultPy)
580
581    def testPointCoordinates_legal_float(self):
582        # legal: float
583        glif = """
584		<glyph name="a" format="1">
585			<outline>
586				<contour>
587					<point x="1.1" y="-2.2" type="move"/>
588					<point x="0" y="0" type="line" name="this is here so that the contour isn't seen as an anchor"/>
589				</contour>
590			</outline>
591		</glyph>
592		"""
593        py = """
594		glyph.name = "a"
595		pointPen.beginPath()
596		pointPen.addPoint(*[(1.1, -2.2)], **{"segmentType" : "move", "smooth" : False})
597		pointPen.addPoint(*[(0, 0)], **{"name" : "this is here so that the contour isn't seen as an anchor", "segmentType" : "line", "smooth" : False})
598		pointPen.endPath()
599		"""
600        resultGlif = self.pyToGLIF(py)
601        resultPy = self.glifToPy(glif)
602        self.assertEqual(glif, resultGlif)
603        self.assertEqual(py, resultPy)
604
605    def testPointCoordinates_illegal_x(self):
606        # illegal: string
607        glif = """
608		<glyph name="a" format="1">
609			<outline>
610				<contour>
611					<point x="a" y="2" type="move"/>
612					<point x="0" y="0" type="line" name="this is here so that the contour isn't seen as an anchor"/>
613				</contour>
614			</outline>
615		</glyph>
616		"""
617        py = """
618		glyph.name = "a"
619		pointPen.beginPath()
620		pointPen.addPoint(*[("a", 2)], **{"segmentType" : "move", "smooth" : False})
621		pointPen.addPoint(*[(0, 0)], **{"name" : "this is here so that the contour isn't seen as an anchor", "segmentType" : "line", "smooth" : False})
622		pointPen.endPath()
623		"""
624        self.assertRaises(GlifLibError, self.pyToGLIF, py)
625        self.assertRaises(GlifLibError, self.glifToPy, glif)
626
627    def testPointCoordinates_illegal_y(self):
628        # legal: int
629        glif = """
630		<glyph name="a" format="1">
631			<outline>
632				<contour>
633					<point x="1" y="a" type="move"/>
634					<point x="0" y="0" type="line" name="this is here so that the contour isn't seen as an anchor"/>
635				</contour>
636			</outline>
637		</glyph>
638		"""
639        py = """
640		glyph.name = "a"
641		pointPen.beginPath()
642		pointPen.addPoint(*[(1, "a")], **{"segmentType" : "move", "smooth" : False})
643		pointPen.addPoint(*[(0, 0)], **{"name" : "this is here so that the contour isn't seen as an anchor", "segmentType" : "line", "smooth" : False})
644		pointPen.endPath()
645		"""
646        self.assertRaises(GlifLibError, self.pyToGLIF, py)
647        self.assertRaises(GlifLibError, self.glifToPy, glif)
648
649    def testPointTypeMove_legal(self):
650        # legal
651        glif = """
652		<glyph name="a" format="1">
653			<outline>
654				<contour>
655					<point x="1" y="-2" type="move"/>
656					<point x="3" y="-4" type="line"/>
657				</contour>
658			</outline>
659		</glyph>
660		"""
661        py = """
662		glyph.name = "a"
663		pointPen.beginPath()
664		pointPen.addPoint(*[(1, -2)], **{"segmentType" : "move", "smooth" : False})
665		pointPen.addPoint(*[(3, -4)], **{"segmentType" : "line", "smooth" : False})
666		pointPen.endPath()
667		"""
668        resultGlif = self.pyToGLIF(py)
669        resultPy = self.glifToPy(glif)
670        self.assertEqual(glif, resultGlif)
671        self.assertEqual(py, resultPy)
672
673    def testPointTypeMove_legal_smooth(self):
674        # legal: smooth=True
675        glif = """
676		<glyph name="a" format="1">
677			<outline>
678				<contour>
679					<point x="1" y="-2" type="move" smooth="yes"/>
680					<point x="3" y="-4" type="line"/>
681				</contour>
682			</outline>
683		</glyph>
684		"""
685        py = """
686		glyph.name = "a"
687		pointPen.beginPath()
688		pointPen.addPoint(*[(1, -2)], **{"segmentType" : "move", "smooth" : True})
689		pointPen.addPoint(*[(3, -4)], **{"segmentType" : "line", "smooth" : False})
690		pointPen.endPath()
691		"""
692        resultGlif = self.pyToGLIF(py)
693        resultPy = self.glifToPy(glif)
694        self.assertEqual(glif, resultGlif)
695        self.assertEqual(py, resultPy)
696
697    def testPointTypeMove_illegal_not_at_start(self):
698        # illegal: not at start
699        glif = """
700		<glyph name="a" format="1">
701			<outline>
702				<contour>
703					<point x="3" y="-4" type="line"/>
704					<point x="1" y="-2" type="move"/>
705				</contour>
706			</outline>
707		</glyph>
708		"""
709        py = """
710		glyph.name = "a"
711		pointPen.beginPath()
712		pointPen.addPoint(*[(3, -4)], **{"segmentType" : "line", "smooth" : False})
713		pointPen.addPoint(*[(1, -2)], **{"segmentType" : "move", "smooth" : False})
714		pointPen.endPath()
715		"""
716        self.assertRaises(GlifLibError, self.pyToGLIF, py)
717        self.assertRaises(GlifLibError, self.glifToPy, glif)
718
719    def testPointTypeLine_legal(self):
720        # legal
721        glif = """
722		<glyph name="a" format="1">
723			<outline>
724				<contour>
725					<point x="1" y="-2" type="move"/>
726					<point x="3" y="-4" type="line"/>
727				</contour>
728			</outline>
729		</glyph>
730		"""
731        py = """
732		glyph.name = "a"
733		pointPen.beginPath()
734		pointPen.addPoint(*[(1, -2)], **{"segmentType" : "move", "smooth" : False})
735		pointPen.addPoint(*[(3, -4)], **{"segmentType" : "line", "smooth" : False})
736		pointPen.endPath()
737		"""
738        resultGlif = self.pyToGLIF(py)
739        resultPy = self.glifToPy(glif)
740        self.assertEqual(glif, resultGlif)
741        self.assertEqual(py, resultPy)
742
743    def testPointTypeLine_legal_start_of_contour(self):
744        # legal: start of contour
745        glif = """
746		<glyph name="a" format="1">
747			<outline>
748				<contour>
749					<point x="1" y="-2" type="line"/>
750					<point x="3" y="-4" type="line"/>
751				</contour>
752			</outline>
753		</glyph>
754		"""
755        py = """
756		glyph.name = "a"
757		pointPen.beginPath()
758		pointPen.addPoint(*[(1, -2)], **{"segmentType" : "line", "smooth" : False})
759		pointPen.addPoint(*[(3, -4)], **{"segmentType" : "line", "smooth" : False})
760		pointPen.endPath()
761		"""
762        resultGlif = self.pyToGLIF(py)
763        resultPy = self.glifToPy(glif)
764        self.assertEqual(glif, resultGlif)
765        self.assertEqual(py, resultPy)
766
767    def testPointTypeLine_legal_smooth(self):
768        # legal: smooth=True
769        glif = """
770		<glyph name="a" format="1">
771			<outline>
772				<contour>
773					<point x="1" y="-2" type="move"/>
774					<point x="3" y="-4" type="line" smooth="yes"/>
775				</contour>
776			</outline>
777		</glyph>
778		"""
779        py = """
780		glyph.name = "a"
781		pointPen.beginPath()
782		pointPen.addPoint(*[(1, -2)], **{"segmentType" : "move", "smooth" : False})
783		pointPen.addPoint(*[(3, -4)], **{"segmentType" : "line", "smooth" : True})
784		pointPen.endPath()
785		"""
786        resultGlif = self.pyToGLIF(py)
787        resultPy = self.glifToPy(glif)
788        self.assertEqual(glif, resultGlif)
789        self.assertEqual(py, resultPy)
790
791    def testPointTypeCurve_legal(self):
792        # legal
793        glif = """
794		<glyph name="a" format="1">
795			<outline>
796				<contour>
797					<point x="0" y="0" type="move"/>
798					<point x="0" y="65"/>
799					<point x="65" y="200"/>
800					<point x="100" y="200" type="curve"/>
801				</contour>
802			</outline>
803		</glyph>
804		"""
805        py = """
806		glyph.name = "a"
807		pointPen.beginPath()
808		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
809		pointPen.addPoint(*[(0, 65)], **{"smooth" : False})
810		pointPen.addPoint(*[(65, 200)], **{"smooth" : False})
811		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "curve", "smooth" : False})
812		pointPen.endPath()
813		"""
814        resultGlif = self.pyToGLIF(py)
815        resultPy = self.glifToPy(glif)
816        self.assertEqual(glif, resultGlif)
817        self.assertEqual(py, resultPy)
818
819    def testPointTypeCurve_legal_start_of_contour(self):
820        # legal: start of contour
821        glif = """
822		<glyph name="a" format="1">
823			<outline>
824				<contour>
825					<point x="100" y="200" type="curve"/>
826					<point x="0" y="65"/>
827					<point x="65" y="200"/>
828				</contour>
829			</outline>
830		</glyph>
831		"""
832        py = """
833		glyph.name = "a"
834		pointPen.beginPath()
835		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "curve", "smooth" : False})
836		pointPen.addPoint(*[(0, 65)], **{"smooth" : False})
837		pointPen.addPoint(*[(65, 200)], **{"smooth" : False})
838		pointPen.endPath()
839		"""
840        resultGlif = self.pyToGLIF(py)
841        resultPy = self.glifToPy(glif)
842        self.assertEqual(glif, resultGlif)
843        self.assertEqual(py, resultPy)
844
845    def testPointTypeCurve_legal_smooth(self):
846        # legal: smooth=True
847        glif = """
848		<glyph name="a" format="1">
849			<outline>
850				<contour>
851					<point x="0" y="0" type="move"/>
852					<point x="0" y="65"/>
853					<point x="65" y="200"/>
854					<point x="100" y="200" type="curve" smooth="yes"/>
855				</contour>
856			</outline>
857		</glyph>
858		"""
859        py = """
860		glyph.name = "a"
861		pointPen.beginPath()
862		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
863		pointPen.addPoint(*[(0, 65)], **{"smooth" : False})
864		pointPen.addPoint(*[(65, 200)], **{"smooth" : False})
865		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "curve", "smooth" : True})
866		pointPen.endPath()
867		"""
868        resultGlif = self.pyToGLIF(py)
869        resultPy = self.glifToPy(glif)
870        self.assertEqual(glif, resultGlif)
871        self.assertEqual(py, resultPy)
872
873    def testPointTypeCurve_legal_no_off_curves(self):
874        # legal: no off-curves
875        glif = """
876		<glyph name="a" format="1">
877			<outline>
878				<contour>
879					<point x="0" y="0" type="move"/>
880					<point x="100" y="200" type="curve"/>
881				</contour>
882			</outline>
883		</glyph>
884		"""
885        py = """
886		glyph.name = "a"
887		pointPen.beginPath()
888		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
889		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "curve", "smooth" : False})
890		pointPen.endPath()
891		"""
892        resultGlif = self.pyToGLIF(py)
893        resultPy = self.glifToPy(glif)
894        self.assertEqual(glif, resultGlif)
895        self.assertEqual(py, resultPy)
896
897    def testPointTypeCurve_legal_1_off_curve(self):
898        # legal: 1 off-curve
899        glif = """
900		<glyph name="a" format="1">
901			<outline>
902				<contour>
903					<point x="0" y="0" type="move"/>
904					<point x="50" y="100"/>
905					<point x="100" y="200" type="curve"/>
906				</contour>
907			</outline>
908		</glyph>
909		"""
910        py = """
911		glyph.name = "a"
912		pointPen.beginPath()
913		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
914		pointPen.addPoint(*[(50, 100)], **{"smooth" : False})
915		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "curve", "smooth" : False})
916		pointPen.endPath()
917		"""
918        resultGlif = self.pyToGLIF(py)
919        resultPy = self.glifToPy(glif)
920        self.assertEqual(glif, resultGlif)
921        self.assertEqual(py, resultPy)
922
923    def testPointTypeCurve_illegal_3_off_curves(self):
924        # illegal: 3 off-curves
925        glif = """
926		<glyph name="a" format="1">
927			<outline>
928				<contour>
929					<point x="0" y="0" type="move"/>
930					<point x="0" y="100"/>
931					<point x="35" y="125"/>
932					<point x="65" y="200"/>
933					<point x="100" y="200" type="curve"/>
934				</contour>
935			</outline>
936		</glyph>
937		"""
938        py = """
939		glyph.name = "a"
940		pointPen.beginPath()
941		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
942		pointPen.addPoint(*[(0, 100)], **{"smooth" : False})
943		pointPen.addPoint(*[(35, 125)], **{"smooth" : False})
944		pointPen.addPoint(*[(65, 200)], **{"smooth" : False})
945		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "curve", "smooth" : False})
946		pointPen.endPath()
947		"""
948        self.assertRaises(GlifLibError, self.pyToGLIF, py)
949        self.assertRaises(GlifLibError, self.glifToPy, glif)
950
951    def testPointQCurve_legal(self):
952        # legal
953        glif = """
954		<glyph name="a" format="1">
955			<outline>
956				<contour>
957					<point x="0" y="0" type="move"/>
958					<point x="0" y="65"/>
959					<point x="65" y="200"/>
960					<point x="100" y="200" type="qcurve"/>
961				</contour>
962			</outline>
963		</glyph>
964		"""
965        py = """
966		glyph.name = "a"
967		pointPen.beginPath()
968		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
969		pointPen.addPoint(*[(0, 65)], **{"smooth" : False})
970		pointPen.addPoint(*[(65, 200)], **{"smooth" : False})
971		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "qcurve", "smooth" : False})
972		pointPen.endPath()
973		"""
974        resultGlif = self.pyToGLIF(py)
975        resultPy = self.glifToPy(glif)
976        self.assertEqual(glif, resultGlif)
977        self.assertEqual(py, resultPy)
978
979    def testPointQCurve_legal_start_of_contour(self):
980        # legal: start of contour
981        glif = """
982		<glyph name="a" format="1">
983			<outline>
984				<contour>
985					<point x="100" y="200" type="qcurve"/>
986					<point x="0" y="65"/>
987					<point x="65" y="200"/>
988				</contour>
989			</outline>
990		</glyph>
991		"""
992        py = """
993		glyph.name = "a"
994		pointPen.beginPath()
995		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "qcurve", "smooth" : False})
996		pointPen.addPoint(*[(0, 65)], **{"smooth" : False})
997		pointPen.addPoint(*[(65, 200)], **{"smooth" : False})
998		pointPen.endPath()
999		"""
1000        resultGlif = self.pyToGLIF(py)
1001        resultPy = self.glifToPy(glif)
1002        self.assertEqual(glif, resultGlif)
1003        self.assertEqual(py, resultPy)
1004
1005    def testPointQCurve_legal_smooth(self):
1006        # legal: smooth=True
1007        glif = """
1008		<glyph name="a" format="1">
1009			<outline>
1010				<contour>
1011					<point x="0" y="0" type="move"/>
1012					<point x="0" y="65"/>
1013					<point x="65" y="200"/>
1014					<point x="100" y="200" type="qcurve" smooth="yes"/>
1015				</contour>
1016			</outline>
1017		</glyph>
1018		"""
1019        py = """
1020		glyph.name = "a"
1021		pointPen.beginPath()
1022		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
1023		pointPen.addPoint(*[(0, 65)], **{"smooth" : False})
1024		pointPen.addPoint(*[(65, 200)], **{"smooth" : False})
1025		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "qcurve", "smooth" : True})
1026		pointPen.endPath()
1027		"""
1028        resultGlif = self.pyToGLIF(py)
1029        resultPy = self.glifToPy(glif)
1030        self.assertEqual(glif, resultGlif)
1031        self.assertEqual(py, resultPy)
1032
1033    def testPointQCurve_legal_no_off_curves(self):
1034        # legal: no off-curves
1035        glif = """
1036		<glyph name="a" format="1">
1037			<outline>
1038				<contour>
1039					<point x="0" y="0" type="move"/>
1040					<point x="100" y="200" type="qcurve"/>
1041				</contour>
1042			</outline>
1043		</glyph>
1044		"""
1045        py = """
1046		glyph.name = "a"
1047		pointPen.beginPath()
1048		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
1049		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "qcurve", "smooth" : False})
1050		pointPen.endPath()
1051		"""
1052        resultGlif = self.pyToGLIF(py)
1053        resultPy = self.glifToPy(glif)
1054        self.assertEqual(glif, resultGlif)
1055        self.assertEqual(py, resultPy)
1056
1057    def testPointQCurve_legal_one_off_curve(self):
1058        # legal: 1 off-curve
1059        glif = """
1060		<glyph name="a" format="1">
1061			<outline>
1062				<contour>
1063					<point x="0" y="0" type="move"/>
1064					<point x="50" y="100"/>
1065					<point x="100" y="200" type="qcurve"/>
1066				</contour>
1067			</outline>
1068		</glyph>
1069		"""
1070        py = """
1071		glyph.name = "a"
1072		pointPen.beginPath()
1073		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
1074		pointPen.addPoint(*[(50, 100)], **{"smooth" : False})
1075		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "qcurve", "smooth" : False})
1076		pointPen.endPath()
1077		"""
1078        resultGlif = self.pyToGLIF(py)
1079        resultPy = self.glifToPy(glif)
1080        self.assertEqual(glif, resultGlif)
1081        self.assertEqual(py, resultPy)
1082
1083    def testPointQCurve_legal_3_off_curves(self):
1084        # legal: 3 off-curves
1085        glif = """
1086		<glyph name="a" format="1">
1087			<outline>
1088				<contour>
1089					<point x="0" y="0" type="move"/>
1090					<point x="0" y="100"/>
1091					<point x="35" y="125"/>
1092					<point x="65" y="200"/>
1093					<point x="100" y="200" type="qcurve"/>
1094				</contour>
1095			</outline>
1096		</glyph>
1097		"""
1098        py = """
1099		glyph.name = "a"
1100		pointPen.beginPath()
1101		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
1102		pointPen.addPoint(*[(0, 100)], **{"smooth" : False})
1103		pointPen.addPoint(*[(35, 125)], **{"smooth" : False})
1104		pointPen.addPoint(*[(65, 200)], **{"smooth" : False})
1105		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "qcurve", "smooth" : False})
1106		pointPen.endPath()
1107		"""
1108        resultGlif = self.pyToGLIF(py)
1109        resultPy = self.glifToPy(glif)
1110        self.assertEqual(glif, resultGlif)
1111        self.assertEqual(py, resultPy)
1112
1113    def testSpecialCaseQCurve(self):
1114        # contour with no on curve
1115        glif = """
1116		<glyph name="a" format="1">
1117			<outline>
1118				<contour>
1119					<point x="0" y="0"/>
1120					<point x="0" y="100"/>
1121					<point x="100" y="100"/>
1122					<point x="100" y="0"/>
1123				</contour>
1124			</outline>
1125		</glyph>
1126		"""
1127        py = """
1128		glyph.name = "a"
1129		pointPen.beginPath()
1130		pointPen.addPoint(*[(0, 0)], **{"smooth" : False})
1131		pointPen.addPoint(*[(0, 100)], **{"smooth" : False})
1132		pointPen.addPoint(*[(100, 100)], **{"smooth" : False})
1133		pointPen.addPoint(*[(100, 0)], **{"smooth" : False})
1134		pointPen.endPath()
1135		"""
1136        resultGlif = self.pyToGLIF(py)
1137        resultPy = self.glifToPy(glif)
1138        self.assertEqual(glif, resultGlif)
1139        self.assertEqual(py, resultPy)
1140
1141    def testPointTypeOffCurve_legal(self):
1142        # legal
1143        glif = """
1144		<glyph name="a" format="1">
1145			<outline>
1146				<contour>
1147					<point x="0" y="0" type="move"/>
1148					<point x="0" y="65"/>
1149					<point x="65" y="200"/>
1150					<point x="100" y="200" type="curve"/>
1151				</contour>
1152			</outline>
1153		</glyph>
1154		"""
1155        py = """
1156		glyph.name = "a"
1157		pointPen.beginPath()
1158		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
1159		pointPen.addPoint(*[(0, 65)], **{"smooth" : False})
1160		pointPen.addPoint(*[(65, 200)], **{"smooth" : False})
1161		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "curve", "smooth" : False})
1162		pointPen.endPath()
1163		"""
1164        resultGlif = self.pyToGLIF(py)
1165        resultPy = self.glifToPy(glif)
1166        self.assertEqual(glif, resultGlif)
1167        self.assertEqual(py, resultPy)
1168
1169    def testPointTypeOffCurve_legal_start_of_contour(self):
1170        # legal: start of contour
1171        glif = """
1172		<glyph name="a" format="1">
1173			<outline>
1174				<contour>
1175					<point x="0" y="65"/>
1176					<point x="65" y="200"/>
1177					<point x="100" y="200" type="curve"/>
1178				</contour>
1179			</outline>
1180		</glyph>
1181		"""
1182        py = """
1183		glyph.name = "a"
1184		pointPen.beginPath()
1185		pointPen.addPoint(*[(0, 65)], **{"smooth" : False})
1186		pointPen.addPoint(*[(65, 200)], **{"smooth" : False})
1187		pointPen.addPoint(*[(100, 200)], **{"segmentType" : "curve", "smooth" : False})
1188		pointPen.endPath()
1189		"""
1190        resultGlif = self.pyToGLIF(py)
1191        resultPy = self.glifToPy(glif)
1192        self.assertEqual(glif, resultGlif)
1193        self.assertEqual(py, resultPy)
1194
1195    def testPointTypeOffCurve_illegal_before_move(self):
1196        # before move
1197        glif = """
1198		<glyph name="a" format="1">
1199			<outline>
1200				<contour>
1201					<point x="0" y="65"/>
1202					<point x="0" y="0" type="move"/>
1203				</contour>
1204			</outline>
1205		</glyph>
1206		"""
1207        py = """
1208		glyph.name = "a"
1209		pointPen.beginPath()
1210		pointPen.addPoint(*[(0, 65)], **{"smooth" : False})
1211		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "move", "smooth" : False})
1212		pointPen.endPath()
1213		"""
1214        self.assertRaises(GlifLibError, self.pyToGLIF, py)
1215        self.assertRaises(GlifLibError, self.glifToPy, glif)
1216
1217    def testPointTypeOffCurve_illegal_before_line(self):
1218        # before line
1219        glif = """
1220		<glyph name="a" format="1">
1221			<outline>
1222				<contour>
1223					<point x="0" y="65"/>
1224					<point x="0" y="0" type="line"/>
1225				</contour>
1226			</outline>
1227		</glyph>
1228		"""
1229        py = """
1230		glyph.name = "a"
1231		pointPen.beginPath()
1232		pointPen.addPoint(*[(0, 65)], **{"smooth" : False})
1233		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "line", "smooth" : False})
1234		pointPen.endPath()
1235		"""
1236        self.assertRaises(GlifLibError, self.pyToGLIF, py)
1237        self.assertRaises(GlifLibError, self.glifToPy, glif)
1238
1239    def testPointTypeOffCurve_illegal_smooth(self):
1240        # smooth=True
1241        glif = """
1242		<glyph name="a" format="1">
1243			<outline>
1244				<contour>
1245					<point x="0" y="65" smooth="yes"/>
1246					<point x="0" y="0" type="curve"/>
1247				</contour>
1248			</outline>
1249		</glyph>
1250		"""
1251        py = """
1252		glyph.name = "a"
1253		pointPen.beginPath()
1254		pointPen.addPoint(*[(0, 65)], **{"smooth" : True})
1255		pointPen.addPoint(*[(0, 0)], **{"segmentType" : "curve", "smooth" : False})
1256		pointPen.endPath()
1257		"""
1258        self.assertRaises(GlifLibError, self.pyToGLIF, py)
1259        self.assertRaises(GlifLibError, self.glifToPy, glif)
1260
1261    def testSinglePoint_legal_without_name(self):
1262        # legal
1263        # glif format 1 single point without a name was not an anchor
1264        glif = """
1265		<glyph name="a" format="1">
1266			<outline>
1267				<contour>
1268					<point x="1" y="2" type="move"/>
1269				</contour>
1270			</outline>
1271		</glyph>
1272		"""
1273        py = """
1274		glyph.name = "a"
1275		pointPen.beginPath()
1276		pointPen.addPoint(*[(1, 2)], **{"segmentType" : "move", "smooth" : False})
1277		pointPen.endPath()
1278		"""
1279        resultGlif = self.pyToGLIF(py)
1280        resultPy = self.glifToPy(glif)
1281        self.assertEqual(glif, resultGlif)
1282        self.assertEqual(py, resultPy)
1283
1284    def testAnchor_legal_with_name(self):
1285        glif = """
1286		<glyph name="a" format="1">
1287			<outline>
1288				<contour>
1289					<point x="1" y="2" type="move" name="test"/>
1290				</contour>
1291			</outline>
1292		</glyph>
1293		"""
1294        py = """
1295		glyph.name = "a"
1296		glyph.anchors = [{"name" : "test", "x" : 1, "y" : 2}]
1297		"""
1298        resultGlif = self.pyToGLIF(py)
1299        resultPy = self.glifToPy(glif)
1300        self.assertEqual(glif, resultGlif)
1301        self.assertEqual(py, resultPy)
1302
1303    def testOpenContourLooseOffCurves_legal(self):
1304        # a piece of software was writing this kind of structure
1305        glif = """
1306		<glyph name="a" format="1">
1307			<outline>
1308				<contour>
1309					<point x="1" y="2" type="move"/>
1310					<point x="1" y="2"/>
1311					<point x="1" y="2"/>
1312					<point x="1" y="2" type="curve"/>
1313					<point x="1" y="2"/>
1314				</contour>
1315			</outline>
1316		</glyph>
1317		"""
1318        expectedPy = """
1319		glyph.name = "a"
1320		pointPen.beginPath()
1321		pointPen.addPoint(*[(1, 2)], **{"segmentType" : "move", "smooth" : False})
1322		pointPen.addPoint(*[(1, 2)], **{"smooth" : False})
1323		pointPen.addPoint(*[(1, 2)], **{"smooth" : False})
1324		pointPen.addPoint(*[(1, 2)], **{"segmentType" : "curve", "smooth" : False})
1325		pointPen.endPath()
1326		"""
1327        resultPy = self.glifToPy(glif)
1328        self.assertEqual(resultPy, expectedPy)
1329
1330    def testOpenContourLooseOffCurves_illegal(self):
1331        py = """
1332		glyph.name = "a"
1333		pointPen.beginPath()
1334		pointPen.addPoint(*[(1, 2)], **{"segmentType" : "move", "smooth" : False})
1335		pointPen.addPoint(*[(1, 2)], **{"smooth" : False})
1336		pointPen.addPoint(*[(1, 2)], **{"smooth" : False})
1337		pointPen.addPoint(*[(1, 2)], **{"segmentType" : "curve", "smooth" : False})
1338		pointPen.addPoint(*[(1, 2)], **{"smooth" : False})
1339		pointPen.endPath()
1340		"""
1341        self.assertRaises(GlifLibError, self.pyToGLIF, py)
1342