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