Starting to test GLIF 1...and I found and fixed some bugs.
git-svn-id: http://svn.robofab.com/branches/ufo3k@345 b5fa9d6c-a76f-4ffd-b3cb-f825fc41095c
This commit is contained in:
parent
61fc46288f
commit
3001616877
@ -485,6 +485,10 @@ def writeGlyphToString(glyphName, glyphObject=None, drawPointsFunc=None, writer=
|
||||
aFile = None
|
||||
identifiers = set()
|
||||
# start
|
||||
if glyphName == "":
|
||||
raise GlifLibError("The glyph name is empty.")
|
||||
if not isinstance(glyphName, basestring):
|
||||
raise GlifLibError("The glyph name is not properly formatted.")
|
||||
writer.begintag("glyph", [("name", glyphName), ("format", formatVersion)])
|
||||
writer.newline()
|
||||
# advance
|
||||
@ -544,9 +548,13 @@ def _writeUnicodes(glyphObject, writer):
|
||||
unicodes = getattr(glyphObject, "unicodes", None)
|
||||
if isinstance(unicodes, int):
|
||||
unicodes = [unicodes]
|
||||
seen = set()
|
||||
for code in unicodes:
|
||||
if not isinstance(code, int):
|
||||
raise GlifLibError("unicode values must be int")
|
||||
if code in seen:
|
||||
continue
|
||||
seen.add(code)
|
||||
hexCode = hex(code)[2:].upper()
|
||||
if len(hexCode) < 4:
|
||||
hexCode = "0" * (4 - len(hexCode)) + hexCode
|
||||
@ -687,7 +695,10 @@ def validateLayerInfoVersion3Data(infoData):
|
||||
# -----------------
|
||||
|
||||
def _stripGlyphXMLTree(nodes):
|
||||
for element, attrs, children in nodes:
|
||||
for node in nodes:
|
||||
if len(node) != 3:
|
||||
raise GlifLibError("Invalid GLIF structure.")
|
||||
element, attrs, children = node
|
||||
# "lib" is formatted as a plist, so we need unstripped
|
||||
# character data so we can support strings with leading or
|
||||
# trailing whitespace. Do strip everything else.
|
||||
@ -723,6 +734,8 @@ def _readGlyphFromTree(tree, glyphObject=None, pointPen=None):
|
||||
raise GlifLibError, "Unsupported GLIF format version: %s" % formatVersion
|
||||
# get the name
|
||||
glyphName = tree[1].get("name")
|
||||
if glyphName == "":
|
||||
raise GlifLibError("Empty glyph name in GLIF.")
|
||||
if glyphName and glyphObject is not None:
|
||||
_relaxedSetattr(glyphObject, "name", glyphName)
|
||||
# populate the sub elements
|
||||
@ -751,7 +764,8 @@ def _readGlyphFromTree(tree, glyphObject=None, pointPen=None):
|
||||
try:
|
||||
v = attrs.get("hex", "undefined")
|
||||
v = int(v, 16)
|
||||
unicodes.append(v)
|
||||
if v not in unicodes:
|
||||
unicodes.append(v)
|
||||
except ValueError:
|
||||
raise GlifLibError("Illegal value for hex attribute of unicode element.")
|
||||
elif element == "guideline":
|
||||
@ -840,11 +854,14 @@ def _buildOutlineContour(pen, (attrs, children), formatVersion, identifiers):
|
||||
raise GlifLibError("The contour identifier %s is not valid." % identifier)
|
||||
identifiers.add(identifier)
|
||||
# try to pass the identifier attribute
|
||||
try:
|
||||
pen.beginPath(identifier)
|
||||
except TypeError:
|
||||
if formatVersion == 1:
|
||||
pen.beginPath()
|
||||
raise DeprecationWarning("The beginPath method needs an identifier kwarg. The contour's identifier value has been discarded.")
|
||||
else:
|
||||
try:
|
||||
pen.beginPath(identifier)
|
||||
except TypeError:
|
||||
pen.beginPath()
|
||||
raise DeprecationWarning("The beginPath method needs an identifier kwarg. The contour's identifier value has been discarded.")
|
||||
# points
|
||||
if children:
|
||||
# loop through the points very quickly to make sure that the number of off-curves is correct
|
||||
|
414
Lib/ufoLib/test/test_GLIF1.py
Normal file
414
Lib/ufoLib/test/test_GLIF1.py
Normal file
@ -0,0 +1,414 @@
|
||||
import unittest
|
||||
from ufoLib.glifLib import GlifLibError, readGlyphFromString, writeGlyphToString
|
||||
|
||||
# -----------------
|
||||
# Glyph and Support
|
||||
# -----------------
|
||||
|
||||
class Glyph(object):
|
||||
|
||||
def __init__(self):
|
||||
self.name = None
|
||||
self.width = None
|
||||
self.height = None
|
||||
self.unicodes = None
|
||||
self.note = None
|
||||
self.image = None
|
||||
self.guidelines = None
|
||||
self.outline = []
|
||||
|
||||
def _writePointPenCommand(self, command, args, kwargs):
|
||||
if args and kwargs:
|
||||
return "pointPen.%s(*%s, **%s)" % (command, listToString(args), dictToString(kwargs))
|
||||
elif args:
|
||||
return "pointPen.%s(*%s)" % (command, listToString(args))
|
||||
elif kwargs:
|
||||
return "pointPen.%s(**%s)" % (command, dictToString(kwargs))
|
||||
else:
|
||||
return "pointPen.%s()" % command
|
||||
|
||||
def beginPath(self, **kwargs):
|
||||
self.outline.append(self._writePointPenCommand("beginPath", args))
|
||||
|
||||
def endPath(self):
|
||||
self.outline.append(self._writePointPenCommand("endPath"))
|
||||
|
||||
def addPoint(self, *args, **kwargs):
|
||||
self.outline.append(self._writePointPenCommand("addPoint", args, kwargs))
|
||||
|
||||
def addComponent(self, *args, **kwargs):
|
||||
self.outline.append(self._writePointPenCommand("addComponent", args, kwargs))
|
||||
|
||||
def drawPoints(self, pointPen):
|
||||
if self.outline:
|
||||
py = "\n".join(self.outline)
|
||||
exec py in {"pointPen" : pointPen}
|
||||
|
||||
def py(self):
|
||||
text = []
|
||||
if self.name is not None:
|
||||
text.append("glyph.name = \"%s\"" % self.name)
|
||||
if self.width:
|
||||
text.append("glyph.width = %s" % str(self.width))
|
||||
if self.height:
|
||||
text.append("glyph.height = %s" % str(self.height))
|
||||
if self.unicodes is not None:
|
||||
text.append("glyph.unicodes = [%s]" % ", ".join([str(i) for i in self.unicodes]))
|
||||
if self.note is not None:
|
||||
text.append("glyph.note = \"%s\"" % self.note)
|
||||
if self.image is not None:
|
||||
text.append("glyph.image = %s" % dictToString(self.image))
|
||||
if self.guidelines is not None:
|
||||
text.append("glyph.guidelines = %s" % listToString(self.guidelines))
|
||||
if self.outline:
|
||||
text.append("pointPen = glyph.getPointPen()")
|
||||
text += self.outline
|
||||
return "\n".join(text)
|
||||
|
||||
def dictToString(d):
|
||||
text = []
|
||||
for key, value in sorted(d.items()):
|
||||
if value is None:
|
||||
continue
|
||||
key = "\"%s\"" % key
|
||||
if isinstance(value, dict):
|
||||
value = dictToString(value)
|
||||
elif isinstance(value, list):
|
||||
value = listToString(value)
|
||||
elif isinstance(value, tuple):
|
||||
value = tupleToString(value)
|
||||
elif isinstance(value, (int, float)):
|
||||
value = str(value)
|
||||
elif isinstance(value, basestring):
|
||||
value = "\"%s\"" % value
|
||||
text.append("%s : %s" % (key, value))
|
||||
return "{%s}" % ", ".join(text)
|
||||
|
||||
def listToString(l):
|
||||
text = []
|
||||
for value in l:
|
||||
if isinstance(value, dict):
|
||||
value = dictToString(value)
|
||||
elif isinstance(value, list):
|
||||
value = listToString(value)
|
||||
elif isinstance(value, tuple):
|
||||
value = tupleToString(value)
|
||||
elif isinstance(value, (int, float)):
|
||||
value = str(value)
|
||||
elif isinstance(value, basestring):
|
||||
value = "\"%s\"" % value
|
||||
text.append(value)
|
||||
return "[%s]" % ", ".join(text)
|
||||
|
||||
def tupleToString(t):
|
||||
text = []
|
||||
for value in t:
|
||||
if isinstance(value, dict):
|
||||
value = dictToString(value)
|
||||
elif isinstance(value, list):
|
||||
value = listToString(value)
|
||||
elif isinstance(value, tuple):
|
||||
value = tupleToString(value)
|
||||
elif isinstance(value, (int, float)):
|
||||
value = str(value)
|
||||
elif isinstance(value, basestring):
|
||||
value = "\"%s\"" % value
|
||||
text.append(value)
|
||||
return "(%s)" % ", ".join(text)
|
||||
|
||||
|
||||
def stripText(text):
|
||||
new = []
|
||||
for line in text.strip().splitlines():
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
new.append(line)
|
||||
return "\n".join(new)
|
||||
|
||||
# ----------
|
||||
# Test Cases
|
||||
# ----------
|
||||
|
||||
class TestGLIF1(unittest.TestCase):
|
||||
|
||||
def assertEqual(self, first, second, msg=None):
|
||||
if isinstance(first, basestring):
|
||||
first = stripText(first)
|
||||
if isinstance(second, basestring):
|
||||
second = stripText(second)
|
||||
return super(TestGLIF1, self).assertEqual(first, second, msg=msg)
|
||||
|
||||
def glyphToGLIF(self, py):
|
||||
py = stripText(py)
|
||||
glyph = Glyph()
|
||||
exec py in {"glyph" : glyph}
|
||||
glif = writeGlyphToString(glyph.name, glyphObject=glyph, drawPointsFunc=glyph.drawPoints, formatVersion=1)
|
||||
glif = "\n".join(glif.splitlines()[1:])
|
||||
return glif
|
||||
|
||||
def glifToPy(self, glif):
|
||||
glif = stripText(glif)
|
||||
glif = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + glif
|
||||
glyph = Glyph()
|
||||
readGlyphFromString(glif, glyphObject=glyph, pointPen=glyph)
|
||||
return glyph.py()
|
||||
|
||||
def testTopElement(self):
|
||||
# not glyph
|
||||
glif = """
|
||||
<notglyph name="a" format="1">
|
||||
<outline>
|
||||
</outline>
|
||||
</notglyph>
|
||||
"""
|
||||
self.assertRaises(GlifLibError, self.glifToPy, glif)
|
||||
|
||||
def testName(self):
|
||||
# legal
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
"""
|
||||
resultGlif = self.glyphToGLIF(py)
|
||||
resultPy = self.glifToPy(glif)
|
||||
self.assertEqual(glif, resultGlif)
|
||||
self.assertEqual(py, resultPy)
|
||||
# empty
|
||||
glif = """
|
||||
<glyph name="" format="1">
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = ""
|
||||
"""
|
||||
self.assertRaises(GlifLibError, self.glyphToGLIF, py)
|
||||
self.assertRaises(GlifLibError, self.glifToPy, glif)
|
||||
# not a string
|
||||
py = """
|
||||
glyph.name = 1
|
||||
"""
|
||||
self.assertRaises(GlifLibError, self.glyphToGLIF, py)
|
||||
|
||||
def testFormat(self):
|
||||
# legal
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
"""
|
||||
resultGlif = self.glyphToGLIF(py)
|
||||
resultPy = self.glifToPy(glif)
|
||||
self.assertEqual(glif, resultGlif)
|
||||
self.assertEqual(py, resultPy)
|
||||
# wrong number
|
||||
glif = """
|
||||
<glyph name="a" format="-1">
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
self.assertRaises(GlifLibError, self.glifToPy, glif)
|
||||
# not an int
|
||||
glif = """
|
||||
<glyph name="a" format="A">
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
self.assertRaises(GlifLibError, self.glifToPy, glif)
|
||||
|
||||
def testBogusGlyphStructure(self):
|
||||
# unknown element
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<unknown />
|
||||
</glyph>
|
||||
"""
|
||||
self.assertRaises(GlifLibError, self.glifToPy, glif)
|
||||
# content
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
Hello World.
|
||||
</glyph>
|
||||
"""
|
||||
self.assertRaises(GlifLibError, self.glifToPy, glif)
|
||||
|
||||
def testAdvance(self):
|
||||
# legal: width and height
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<advance height="200" width="100"/>
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
glyph.width = 100
|
||||
glyph.height = 200
|
||||
"""
|
||||
resultGlif = self.glyphToGLIF(py)
|
||||
resultPy = self.glifToPy(glif)
|
||||
self.assertEqual(glif, resultGlif)
|
||||
self.assertEqual(py, resultPy)
|
||||
# legal: width and height floats
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<advance height="200.1" width="100.1"/>
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
glyph.width = 100.1
|
||||
glyph.height = 200.1
|
||||
"""
|
||||
resultGlif = self.glyphToGLIF(py)
|
||||
resultPy = self.glifToPy(glif)
|
||||
self.assertEqual(glif, resultGlif)
|
||||
self.assertEqual(py, resultPy)
|
||||
# legal: width
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<advance width="100"/>
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
glyph.width = 100
|
||||
"""
|
||||
resultGlif = self.glyphToGLIF(py)
|
||||
resultPy = self.glifToPy(glif)
|
||||
self.assertEqual(glif, resultGlif)
|
||||
self.assertEqual(py, resultPy)
|
||||
# legal: height
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<advance height="200"/>
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
glyph.height = 200
|
||||
"""
|
||||
resultGlif = self.glyphToGLIF(py)
|
||||
resultPy = self.glifToPy(glif)
|
||||
self.assertEqual(glif, resultGlif)
|
||||
self.assertEqual(py, resultPy)
|
||||
# illegal: not a number
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<advance width="a"/>
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
glyph.width = "a"
|
||||
"""
|
||||
self.assertRaises(GlifLibError, self.glyphToGLIF, py)
|
||||
self.assertRaises(GlifLibError, self.glifToPy, glif)
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<advance height="a"/>
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
glyph.height = "a"
|
||||
"""
|
||||
self.assertRaises(GlifLibError, self.glyphToGLIF, py)
|
||||
self.assertRaises(GlifLibError, self.glifToPy, glif)
|
||||
|
||||
def testUnicodes(self):
|
||||
# legal
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<unicode hex="0061"/>
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
glyph.unicodes = [97]
|
||||
"""
|
||||
resultGlif = self.glyphToGLIF(py)
|
||||
resultPy = self.glifToPy(glif)
|
||||
self.assertEqual(glif, resultGlif)
|
||||
self.assertEqual(py, resultPy)
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<unicode hex="0062"/>
|
||||
<unicode hex="0063"/>
|
||||
<unicode hex="0061"/>
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
glyph.unicodes = [98, 99, 97]
|
||||
"""
|
||||
resultGlif = self.glyphToGLIF(py)
|
||||
resultPy = self.glifToPy(glif)
|
||||
self.assertEqual(glif, resultGlif)
|
||||
self.assertEqual(py, resultPy)
|
||||
# illegal
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<unicode hex="1.1"/>
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "zzzzzz"
|
||||
glyph.unicodes = ["1.1"]
|
||||
"""
|
||||
self.assertRaises(GlifLibError, self.glyphToGLIF, py)
|
||||
self.assertRaises(GlifLibError, self.glifToPy, glif)
|
||||
|
||||
def testNote(self):
|
||||
glif = """
|
||||
<glyph name="a" format="1">
|
||||
<note>
|
||||
hello
|
||||
</note>
|
||||
<outline>
|
||||
</outline>
|
||||
</glyph>
|
||||
"""
|
||||
py = """
|
||||
glyph.name = "a"
|
||||
glyph.note = "hello"
|
||||
"""
|
||||
resultGlif = self.glyphToGLIF(py)
|
||||
resultPy = self.glifToPy(glif)
|
||||
self.assertEqual(glif, resultGlif)
|
||||
self.assertEqual(py, resultPy)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
from robofab.test.testSupport import runTests
|
||||
runTests()
|
@ -696,7 +696,7 @@ def imageValidator(value):
|
||||
if not genericDictValidator(value, dictPrototype):
|
||||
return False
|
||||
# fileName must be one or more characters
|
||||
if not fileName:
|
||||
if not value["fileName"]:
|
||||
return False
|
||||
# color must follow the proper format
|
||||
color = value.get("color")
|
||||
|
Loading…
x
Reference in New Issue
Block a user