diff options
author | Rasmus Andersson <rasmus@notion.se> | 2017-09-04 06:03:17 +0300 |
---|---|---|
committer | Rasmus Andersson <rasmus@notion.se> | 2017-09-04 18:12:34 +0300 |
commit | 8234b62ab762637ef24c3398b4204a8ce8db31a7 (patch) | |
tree | 1c8df547021cdb58951630a015e4101ede46dbf1 /misc/pylib/robofab/test | |
parent | 31ae014e0c827dd76696fdab7e4ca3fed9f6402b (diff) | |
download | inter-8234b62ab762637ef24c3398b4204a8ce8db31a7.tar.xz |
Speeds up font compilation by around 200%
Cython is used to compile some hot paths into native Python extensions.
These hot paths were identified through running ufocompile with the hotshot
profiler and then converting file by file to Cython, starting with the "hottest"
paths and continuing until returns were deminishing. This means that only a few
Python files were converted to Cython.
Closes #23
Closes #20 (really this time)
Diffstat (limited to 'misc/pylib/robofab/test')
-rwxr-xr-x | misc/pylib/robofab/test/__init__.py | 8 | ||||
-rw-r--r-- | misc/pylib/robofab/test/runAll.py | 27 | ||||
-rwxr-xr-x | misc/pylib/robofab/test/testSupport.py | 278 | ||||
-rw-r--r-- | misc/pylib/robofab/test/test_RInfoFL.py | 111 | ||||
-rw-r--r-- | misc/pylib/robofab/test/test_RInfoRF.py | 56 | ||||
-rw-r--r-- | misc/pylib/robofab/test/test_dialogs.py | 218 | ||||
-rw-r--r-- | misc/pylib/robofab/test/test_fontLabUFOReadWrite.py | 565 | ||||
-rw-r--r-- | misc/pylib/robofab/test/test_glifLib.py | 150 | ||||
-rw-r--r-- | misc/pylib/robofab/test/test_noneLabUFOReadWrite.py | 321 | ||||
-rwxr-xr-x | misc/pylib/robofab/test/test_objectsFL.py | 54 | ||||
-rwxr-xr-x | misc/pylib/robofab/test/test_objectsUFO.py | 203 | ||||
-rwxr-xr-x | misc/pylib/robofab/test/test_pens.py | 149 | ||||
-rw-r--r-- | misc/pylib/robofab/test/test_psHints.py | 110 | ||||
-rw-r--r-- | misc/pylib/robofab/test/test_ufoLib.py | 1659 |
14 files changed, 3909 insertions, 0 deletions
diff --git a/misc/pylib/robofab/test/__init__.py b/misc/pylib/robofab/test/__init__.py new file mode 100755 index 000000000..f34415804 --- /dev/null +++ b/misc/pylib/robofab/test/__init__.py @@ -0,0 +1,8 @@ +"""Directory for unit tests. + +Modules here are typically named text_<something>.py, where <something> is +usually a module name, for example "test_flPen.py", but it can also be the name +of an area or concept to be tested, for example "test_drawing.py". + +Testmodules should use the unittest framework. +""" diff --git a/misc/pylib/robofab/test/runAll.py b/misc/pylib/robofab/test/runAll.py new file mode 100644 index 000000000..28446a7b8 --- /dev/null +++ b/misc/pylib/robofab/test/runAll.py @@ -0,0 +1,27 @@ +import os +import glob +import unittest + +import robofab.test + +if __name__ == "__main__": + testDir = os.path.dirname(robofab.test.__file__) + testFiles = glob.glob1(testDir, "test_*.py") + + loader = unittest.TestLoader() + suites = [] + for fileName in testFiles: + modName = "robofab.test." + fileName[:-3] + print "importing", fileName + try: + mod = __import__(modName, {}, {}, ["*"]) + except ImportError: + print "*** skipped", fileName + continue + + suites.append(loader.loadTestsFromModule(mod)) + + print "running tests..." + testRunner = unittest.TextTestRunner(verbosity=0) + testSuite = unittest.TestSuite(suites) + testRunner.run(testSuite) diff --git a/misc/pylib/robofab/test/testSupport.py b/misc/pylib/robofab/test/testSupport.py new file mode 100755 index 000000000..f7f96c9ff --- /dev/null +++ b/misc/pylib/robofab/test/testSupport.py @@ -0,0 +1,278 @@ +"""Miscellaneous helpers for our test suite.""" + + +import sys +import os +import types +import unittest + + +def getDemoFontPath(): + """Return the path to Data/DemoFont.ufo/.""" + import robofab + root = os.path.dirname(os.path.dirname(os.path.dirname(robofab.__file__))) + return os.path.join(root, "Data", "DemoFont.ufo") + + +def getDemoFontGlyphSetPath(): + """Return the path to Data/DemoFont.ufo/glyphs/.""" + return os.path.join(getDemoFontPath(), "glyphs") + + +def _gatherTestCasesFromCallerByMagic(): + # UGLY magic: fetch TestClass subclasses from the globals of our + # caller's caller. + frame = sys._getframe(2) + return _gatherTestCasesFromDict(frame.f_globals) + + +def _gatherTestCasesFromDict(d): + testCases = [] + for ob in d.values(): + if isinstance(ob, type) and issubclass(ob, unittest.TestCase): + testCases.append(ob) + return testCases + + +def runTests(testCases=None, verbosity=1): + """Run a series of tests.""" + if testCases is None: + testCases = _gatherTestCasesFromCallerByMagic() + loader = unittest.TestLoader() + suites = [] + for testCase in testCases: + suites.append(loader.loadTestsFromTestCase(testCase)) + + testRunner = unittest.TextTestRunner(verbosity=verbosity) + testSuite = unittest.TestSuite(suites) + testRunner.run(testSuite) + +# font info values used by several tests + +fontInfoVersion1 = { + "familyName" : "Some Font (Family Name)", + "styleName" : "Regular (Style Name)", + "fullName" : "Some Font-Regular (Postscript Full Name)", + "fontName" : "SomeFont-Regular (Postscript Font Name)", + "menuName" : "Some Font Regular (Style Map Family Name)", + "fontStyle" : 64, + "note" : "A note.", + "versionMajor" : 1, + "versionMinor" : 0, + "year" : 2008, + "copyright" : "Copyright Some Foundry.", + "notice" : "Some Font by Some Designer for Some Foundry.", + "trademark" : "Trademark Some Foundry", + "license" : "License info for Some Foundry.", + "licenseURL" : "http://somefoundry.com/license", + "createdBy" : "Some Foundry", + "designer" : "Some Designer", + "designerURL" : "http://somedesigner.com", + "vendorURL" : "http://somefoundry.com", + "unitsPerEm" : 1000, + "ascender" : 750, + "descender" : -250, + "capHeight" : 750, + "xHeight" : 500, + "defaultWidth" : 400, + "slantAngle" : -12.5, + "italicAngle" : -12.5, + "widthName" : "Medium (normal)", + "weightName" : "Medium", + "weightValue" : 500, + "fondName" : "SomeFont Regular (FOND Name)", + "otFamilyName" : "Some Font (Preferred Family Name)", + "otStyleName" : "Regular (Preferred Subfamily Name)", + "otMacName" : "Some Font Regular (Compatible Full Name)", + "msCharSet" : 0, + "fondID" : 15000, + "uniqueID" : 4000000, + "ttVendor" : "SOME", + "ttUniqueID" : "OpenType name Table Unique ID", + "ttVersion" : "OpenType name Table Version", +} + +fontInfoVersion2 = { + "familyName" : "Some Font (Family Name)", + "styleName" : "Regular (Style Name)", + "styleMapFamilyName" : "Some Font Regular (Style Map Family Name)", + "styleMapStyleName" : "regular", + "versionMajor" : 1, + "versionMinor" : 0, + "year" : 2008, + "copyright" : "Copyright Some Foundry.", + "trademark" : "Trademark Some Foundry", + "unitsPerEm" : 1000, + "descender" : -250, + "xHeight" : 500, + "capHeight" : 750, + "ascender" : 750, + "italicAngle" : -12.5, + "note" : "A note.", + "openTypeHeadCreated" : "2000/01/01 00:00:00", + "openTypeHeadLowestRecPPEM" : 10, + "openTypeHeadFlags" : [0, 1], + "openTypeHheaAscender" : 750, + "openTypeHheaDescender" : -250, + "openTypeHheaLineGap" : 200, + "openTypeHheaCaretSlopeRise" : 1, + "openTypeHheaCaretSlopeRun" : 0, + "openTypeHheaCaretOffset" : 0, + "openTypeNameDesigner" : "Some Designer", + "openTypeNameDesignerURL" : "http://somedesigner.com", + "openTypeNameManufacturer" : "Some Foundry", + "openTypeNameManufacturerURL" : "http://somefoundry.com", + "openTypeNameLicense" : "License info for Some Foundry.", + "openTypeNameLicenseURL" : "http://somefoundry.com/license", + "openTypeNameVersion" : "OpenType name Table Version", + "openTypeNameUniqueID" : "OpenType name Table Unique ID", + "openTypeNameDescription" : "Some Font by Some Designer for Some Foundry.", + "openTypeNamePreferredFamilyName" : "Some Font (Preferred Family Name)", + "openTypeNamePreferredSubfamilyName" : "Regular (Preferred Subfamily Name)", + "openTypeNameCompatibleFullName" : "Some Font Regular (Compatible Full Name)", + "openTypeNameSampleText" : "Sample Text for Some Font.", + "openTypeNameWWSFamilyName" : "Some Font (WWS Family Name)", + "openTypeNameWWSSubfamilyName" : "Regular (WWS Subfamily Name)", + "openTypeOS2WidthClass" : 5, + "openTypeOS2WeightClass" : 500, + "openTypeOS2Selection" : [3], + "openTypeOS2VendorID" : "SOME", + "openTypeOS2Panose" : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], + "openTypeOS2FamilyClass" : [1, 1], + "openTypeOS2UnicodeRanges" : [0, 1], + "openTypeOS2CodePageRanges" : [0, 1], + "openTypeOS2TypoAscender" : 750, + "openTypeOS2TypoDescender" : -250, + "openTypeOS2TypoLineGap" : 200, + "openTypeOS2WinAscent" : 750, + "openTypeOS2WinDescent" : -250, + "openTypeOS2Type" : [], + "openTypeOS2SubscriptXSize" : 200, + "openTypeOS2SubscriptYSize" : 400, + "openTypeOS2SubscriptXOffset" : 0, + "openTypeOS2SubscriptYOffset" : -100, + "openTypeOS2SuperscriptXSize" : 200, + "openTypeOS2SuperscriptYSize" : 400, + "openTypeOS2SuperscriptXOffset" : 0, + "openTypeOS2SuperscriptYOffset" : 200, + "openTypeOS2StrikeoutSize" : 20, + "openTypeOS2StrikeoutPosition" : 300, + "openTypeVheaVertTypoAscender" : 750, + "openTypeVheaVertTypoDescender" : -250, + "openTypeVheaVertTypoLineGap" : 200, + "openTypeVheaCaretSlopeRise" : 0, + "openTypeVheaCaretSlopeRun" : 1, + "openTypeVheaCaretOffset" : 0, + "postscriptFontName" : "SomeFont-Regular (Postscript Font Name)", + "postscriptFullName" : "Some Font-Regular (Postscript Full Name)", + "postscriptSlantAngle" : -12.5, + "postscriptUniqueID" : 4000000, + "postscriptUnderlineThickness" : 20, + "postscriptUnderlinePosition" : -200, + "postscriptIsFixedPitch" : False, + "postscriptBlueValues" : [500, 510], + "postscriptOtherBlues" : [-250, -260], + "postscriptFamilyBlues" : [500, 510], + "postscriptFamilyOtherBlues" : [-250, -260], + "postscriptStemSnapH" : [100, 120], + "postscriptStemSnapV" : [80, 90], + "postscriptBlueFuzz" : 1, + "postscriptBlueShift" : 7, + "postscriptBlueScale" : 0.039625, + "postscriptForceBold" : True, + "postscriptDefaultWidthX" : 400, + "postscriptNominalWidthX" : 400, + "postscriptWeightName" : "Medium", + "postscriptDefaultCharacter" : ".notdef", + "postscriptWindowsCharacterSet" : 1, + "macintoshFONDFamilyID" : 15000, + "macintoshFONDName" : "SomeFont Regular (FOND Name)", +} + +expectedFontInfo1To2Conversion = { + "familyName" : "Some Font (Family Name)", + "styleMapFamilyName" : "Some Font Regular (Style Map Family Name)", + "styleMapStyleName" : "regular", + "styleName" : "Regular (Style Name)", + "unitsPerEm" : 1000, + "ascender" : 750, + "capHeight" : 750, + "xHeight" : 500, + "descender" : -250, + "italicAngle" : -12.5, + "versionMajor" : 1, + "versionMinor" : 0, + "year" : 2008, + "copyright" : "Copyright Some Foundry.", + "trademark" : "Trademark Some Foundry", + "note" : "A note.", + "macintoshFONDFamilyID" : 15000, + "macintoshFONDName" : "SomeFont Regular (FOND Name)", + "openTypeNameCompatibleFullName" : "Some Font Regular (Compatible Full Name)", + "openTypeNameDescription" : "Some Font by Some Designer for Some Foundry.", + "openTypeNameDesigner" : "Some Designer", + "openTypeNameDesignerURL" : "http://somedesigner.com", + "openTypeNameLicense" : "License info for Some Foundry.", + "openTypeNameLicenseURL" : "http://somefoundry.com/license", + "openTypeNameManufacturer" : "Some Foundry", + "openTypeNameManufacturerURL" : "http://somefoundry.com", + "openTypeNamePreferredFamilyName" : "Some Font (Preferred Family Name)", + "openTypeNamePreferredSubfamilyName": "Regular (Preferred Subfamily Name)", + "openTypeNameCompatibleFullName" : "Some Font Regular (Compatible Full Name)", + "openTypeNameUniqueID" : "OpenType name Table Unique ID", + "openTypeNameVersion" : "OpenType name Table Version", + "openTypeOS2VendorID" : "SOME", + "openTypeOS2WeightClass" : 500, + "openTypeOS2WidthClass" : 5, + "postscriptDefaultWidthX" : 400, + "postscriptFontName" : "SomeFont-Regular (Postscript Font Name)", + "postscriptFullName" : "Some Font-Regular (Postscript Full Name)", + "postscriptSlantAngle" : -12.5, + "postscriptUniqueID" : 4000000, + "postscriptWeightName" : "Medium", + "postscriptWindowsCharacterSet" : 1 +} + +expectedFontInfo2To1Conversion = { + "familyName" : "Some Font (Family Name)", + "menuName" : "Some Font Regular (Style Map Family Name)", + "fontStyle" : 64, + "styleName" : "Regular (Style Name)", + "unitsPerEm" : 1000, + "ascender" : 750, + "capHeight" : 750, + "xHeight" : 500, + "descender" : -250, + "italicAngle" : -12.5, + "versionMajor" : 1, + "versionMinor" : 0, + "copyright" : "Copyright Some Foundry.", + "trademark" : "Trademark Some Foundry", + "note" : "A note.", + "fondID" : 15000, + "fondName" : "SomeFont Regular (FOND Name)", + "fullName" : "Some Font Regular (Compatible Full Name)", + "notice" : "Some Font by Some Designer for Some Foundry.", + "designer" : "Some Designer", + "designerURL" : "http://somedesigner.com", + "license" : "License info for Some Foundry.", + "licenseURL" : "http://somefoundry.com/license", + "createdBy" : "Some Foundry", + "vendorURL" : "http://somefoundry.com", + "otFamilyName" : "Some Font (Preferred Family Name)", + "otStyleName" : "Regular (Preferred Subfamily Name)", + "otMacName" : "Some Font Regular (Compatible Full Name)", + "ttUniqueID" : "OpenType name Table Unique ID", + "ttVersion" : "OpenType name Table Version", + "ttVendor" : "SOME", + "weightValue" : 500, + "widthName" : "Medium (normal)", + "defaultWidth" : 400, + "fontName" : "SomeFont-Regular (Postscript Font Name)", + "fullName" : "Some Font-Regular (Postscript Full Name)", + "slantAngle" : -12.5, + "uniqueID" : 4000000, + "weightName" : "Medium", + "msCharSet" : 0, + "year" : 2008 +} diff --git a/misc/pylib/robofab/test/test_RInfoFL.py b/misc/pylib/robofab/test/test_RInfoFL.py new file mode 100644 index 000000000..bfbd13477 --- /dev/null +++ b/misc/pylib/robofab/test/test_RInfoFL.py @@ -0,0 +1,111 @@ +import unittest +from cStringIO import StringIO +import sys +from robofab import ufoLib +from robofab.objects.objectsFL import NewFont +from robofab.test.testSupport import fontInfoVersion1, fontInfoVersion2 + + +class RInfoRFTestCase(unittest.TestCase): + + def testRoundTripVersion2(self): + font = NewFont() + infoObject = font.info + for attr, value in fontInfoVersion2.items(): + if attr in infoObject._ufoToFLAttrMapping and infoObject._ufoToFLAttrMapping[attr]["nakedAttribute"] is None: + continue + setattr(infoObject, attr, value) + newValue = getattr(infoObject, attr) + self.assertEqual((attr, newValue), (attr, value)) + font.close() + + def testVersion2UnsupportedSet(self): + saveStderr = sys.stderr + saveStdout = sys.stdout + tempStderr = StringIO() + sys.stderr = tempStderr + sys.stdout = tempStderr + font = NewFont() + infoObject = font.info + requiredWarnings = [] + try: + for attr, value in fontInfoVersion2.items(): + if attr in infoObject._ufoToFLAttrMapping and infoObject._ufoToFLAttrMapping[attr]["nakedAttribute"] is not None: + continue + setattr(infoObject, attr, value) + s = "The attribute %s is not supported by FontLab." % attr + requiredWarnings.append((attr, s)) + finally: + sys.stderr = saveStderr + sys.stdout = saveStdout + tempStderr = tempStderr.getvalue() + for attr, line in requiredWarnings: + self.assertEquals((attr, line in tempStderr), (attr, True)) + font.close() + + def testVersion2UnsupportedGet(self): + saveStderr = sys.stderr + saveStdout = sys.stdout + tempStderr = StringIO() + sys.stderr = tempStderr + sys.stdout = tempStderr + font = NewFont() + infoObject = font.info + requiredWarnings = [] + try: + for attr, value in fontInfoVersion2.items(): + if attr in infoObject._ufoToFLAttrMapping and infoObject._ufoToFLAttrMapping[attr]["nakedAttribute"] is not None: + continue + getattr(infoObject, attr, value) + s = "The attribute %s is not supported by FontLab." % attr + requiredWarnings.append((attr, s)) + finally: + sys.stderr = saveStderr + sys.stdout = saveStdout + tempStderr = tempStderr.getvalue() + for attr, line in requiredWarnings: + self.assertEquals((attr, line in tempStderr), (attr, True)) + font.close() + + def testRoundTripVersion1(self): + font = NewFont() + infoObject = font.info + for attr, value in fontInfoVersion1.items(): + if attr not in ufoLib.deprecatedFontInfoAttributesVersion2: + setattr(infoObject, attr, value) + for attr, expectedValue in fontInfoVersion1.items(): + if attr not in ufoLib.deprecatedFontInfoAttributesVersion2: + value = getattr(infoObject, attr) + self.assertEqual((attr, expectedValue), (attr, value)) + font.close() + + def testVersion1DeprecationRoundTrip(self): + saveStderr = sys.stderr + saveStdout = sys.stdout + tempStderr = StringIO() + sys.stderr = tempStderr + sys.stdout = tempStderr + font = NewFont() + infoObject = font.info + requiredWarnings = [] + try: + for attr, value in fontInfoVersion1.items(): + if attr in ufoLib.deprecatedFontInfoAttributesVersion2: + setattr(infoObject, attr, value) + v = getattr(infoObject, attr) + self.assertEquals((attr, value), (attr, v)) + s = "DeprecationWarning: The %s attribute has been deprecated." % attr + requiredWarnings.append((attr, s)) + finally: + sys.stderr = saveStderr + sys.stdout = saveStdout + tempStderr = tempStderr.getvalue() + for attr, line in requiredWarnings: + self.assertEquals((attr, line in tempStderr), (attr, True)) + font.close() + + +if __name__ == "__main__": + from robofab.test.testSupport import runTests + runTests() + diff --git a/misc/pylib/robofab/test/test_RInfoRF.py b/misc/pylib/robofab/test/test_RInfoRF.py new file mode 100644 index 000000000..3a8747033 --- /dev/null +++ b/misc/pylib/robofab/test/test_RInfoRF.py @@ -0,0 +1,56 @@ +import unittest +from cStringIO import StringIO +import sys +from robofab import ufoLib +from robofab.objects.objectsRF import RInfo +from robofab.test.testSupport import fontInfoVersion1, fontInfoVersion2 + + +class RInfoRFTestCase(unittest.TestCase): + + def testRoundTripVersion2(self): + infoObject = RInfo() + for attr, value in fontInfoVersion2.items(): + setattr(infoObject, attr, value) + newValue = getattr(infoObject, attr) + self.assertEqual((attr, newValue), (attr, value)) + + def testRoundTripVersion1(self): + infoObject = RInfo() + for attr, value in fontInfoVersion1.items(): + if attr not in ufoLib.deprecatedFontInfoAttributesVersion2: + setattr(infoObject, attr, value) + for attr, expectedValue in fontInfoVersion1.items(): + if attr not in ufoLib.deprecatedFontInfoAttributesVersion2: + value = getattr(infoObject, attr) + self.assertEqual((attr, expectedValue), (attr, value)) + + def testVersion1DeprecationRoundTrip(self): + """ + unittest doesn't catch warnings in self.assertRaises, + so some hackery is required to catch the warnings + that are raised when setting deprecated attributes. + """ + saveStderr = sys.stderr + tempStderr = StringIO() + sys.stderr = tempStderr + infoObject = RInfo() + requiredWarnings = [] + try: + for attr, value in fontInfoVersion1.items(): + if attr in ufoLib.deprecatedFontInfoAttributesVersion2: + setattr(infoObject, attr, value) + v = getattr(infoObject, attr) + self.assertEquals((attr, value), (attr, v)) + s = "DeprecationWarning: The %s attribute has been deprecated." % attr + requiredWarnings.append((attr, s)) + finally: + sys.stderr = saveStderr + tempStderr = tempStderr.getvalue() + for attr, line in requiredWarnings: + self.assertEquals((attr, line in tempStderr), (attr, True)) + + +if __name__ == "__main__": + from robofab.test.testSupport import runTests + runTests() diff --git a/misc/pylib/robofab/test/test_dialogs.py b/misc/pylib/robofab/test/test_dialogs.py new file mode 100644 index 000000000..c296a6bd7 --- /dev/null +++ b/misc/pylib/robofab/test/test_dialogs.py @@ -0,0 +1,218 @@ +import robofab.interface.all.dialogs +reload(robofab.interface.all.dialogs) +from robofab.interface.all.dialogs import * + +import unittest + + +__all__ = [ + "AskString", #x + "AskYesNoCancel", #x + "FindGlyph", + "GetFile", #x + "GetFolder", #x + "GetFileOrFolder", #x + "Message", #x + "OneList", + "PutFile", #x + "SearchList", + "SelectFont", + "SelectGlyph", + "TwoChecks", + "TwoFields", + "ProgressBar", +] + +class DialogRunner(object): + def __init__(self): + prompt = "The prompt for %s." + message = "The message for %s." + title = "The title for %s." + informativeText = "The informative text for %s." + fileTypes = ['ufo'] + fileName = "The_filename.txt" + + self.fonts = fonts = [self.makeTestFont(n) for n in range(4)] + + t = "AskString" + try: + print "About to try", t + print "\t>>>", AskString( + message=prompt%t, + value='', + title=title%t + ) + except NotImplementedError: + print t, "is not implemented." + + t = "AskYesNoCancel" + try: + print "About to try", t + print "\t>>>", AskYesNoCancel( + message=prompt%t+" default set to 0", + title=title%t, + default=0, + informativeText=informativeText%t + ) + print "\t>>>", AskYesNoCancel( + message=prompt%t+" default set to 1", + title=title%t, + default=1, + informativeText=informativeText%t + ) + except NotImplementedError: + print t, "is not implemented." + + t = "GetFile" + try: + print "About to try", t + print "\t>>>", GetFile( + message=message%t+" Only fileTypes "+`fileTypes`, + title=title%t, + directory=None, + fileName=fileName, + allowsMultipleSelection=False, + fileTypes=fileTypes + ) + print "\t>>>", GetFile( + message=message%t+" All filetypes, allow multiple selection.", + title=title%t, + directory=None, + fileName=fileName, + allowsMultipleSelection=True, + fileTypes=None + ) + except NotImplementedError: + print t, "is not implemented." + + t = "GetFolder" + try: + print "About to try", t + print "\t>>>", GetFolder( + message=message%t, + title=title%t, + directory=None, + allowsMultipleSelection=False + ) + print "\t>>>", GetFolder( + message=message%t + " Allow multiple selection.", + title=title%t, + directory=None, + allowsMultipleSelection=True + ) + except NotImplementedError: + print t, "is not implemented." + + t = "GetFileOrFolder" + try: + print "About to try", t + print "\t>>>", GetFileOrFolder( + message=message%t+" Only fileTypes "+`fileTypes`, + title=title%t, + directory=None, + fileName=fileName, + allowsMultipleSelection=False, + fileTypes=fileTypes + ) + print "\t>>>", GetFileOrFolder( + message=message%t + " Allow multiple selection.", + title=title%t, + directory=None, + fileName=fileName, + allowsMultipleSelection=True, + fileTypes=None + ) + except NotImplementedError: + print t, "is not implemented." + + t = "Message" + try: + print "About to try", t + print "\t>>>", Message( + message=message%t, + title=title%t, + informativeText=informativeText%t + ) + except NotImplementedError: + print t, "is not implemented." + + t = "PutFile" + try: + print "About to try", t + print "\t>>>", PutFile( + message=message%t, + fileName=fileName, + ) + except NotImplementedError: + print t, "is not implemented." + + # t = "SelectFont" + # try: + #print "About to try", t + # print "\t>>>", SelectFont( + # message=message%t, + # title=title%t, + # allFonts=fonts, + # ) + # except NotImplementedError: + # print t, "is not implemented." + + # t = 'SelectGlyph' + # try: + #print "About to try", t + # print "\t>>>", SelectGlyph( + # font=fonts[0], + # message=message%t, + # title=title%t, + # ) + # except NotImplementedError: + # print t, "is not implemented." + + print 'No more tests.' + + def makeTestFont(self, number): + from robofab.objects.objectsRF import RFont as _RFont + f = _RFont() + f.info.familyName = "TestFamily" + f.info.styleName = "weight%d"%number + f.info.postscriptFullName = "%s %s"%(f.info.familyName, f.info.styleName) + # make some glyphs + for name in ['A', 'B', 'C']: + g = f.newGlyph(name) + pen = g.getPen() + pen.moveTo((0,0)) + pen.lineTo((500, 0)) + pen.lineTo((500, 800)) + pen.lineTo((0, 800)) + pen.closePath() + return f + + +class DialogTests(unittest.TestCase): + def setUp(self): + from robofab.interface.all.dialogs import test + test() + + def tearDown(self): + pass + + def testDialogs(self): + import robofab.interface.all.dialogs + dialogModuleName = robofab.interface.all.dialogs.platformApplicationModuleName + application = robofab.interface.all.dialogs.application + + if application is None and dialogModuleName == "dialogs_mac_vanilla": + # in vanilla, but not in a host application, run with executeVanillaTest + print + print "I'm running these tests with executeVanillaTest" + from vanilla.test.testTools import executeVanillaTest + executeVanillaTest(DialogRunner) + else: + print + print "I'm running these tests natively in" + DialogRunner() + + +if __name__ == "__main__": + from robofab.test.testSupport import runTests + runTests() diff --git a/misc/pylib/robofab/test/test_fontLabUFOReadWrite.py b/misc/pylib/robofab/test/test_fontLabUFOReadWrite.py new file mode 100644 index 000000000..91c072d26 --- /dev/null +++ b/misc/pylib/robofab/test/test_fontLabUFOReadWrite.py @@ -0,0 +1,565 @@ +import os +import shutil +import unittest +import tempfile +from robofab.plistlib import readPlist +import robofab +from robofab.ufoLib import UFOReader, UFOWriter +from robofab.test.testSupport import fontInfoVersion2, expectedFontInfo1To2Conversion +from robofab.objects.objectsFL import NewFont, OpenFont + +vfbPath = os.path.dirname(robofab.__file__) +vfbPath = os.path.dirname(vfbPath) +vfbPath = os.path.dirname(vfbPath) +vfbPath = os.path.join(vfbPath, "TestData", "TestFont1.vfb") + +ufoPath1 = os.path.dirname(robofab.__file__) +ufoPath1 = os.path.dirname(ufoPath1) +ufoPath1 = os.path.dirname(ufoPath1) +ufoPath1 = os.path.join(ufoPath1, "TestData", "TestFont1 (UFO1).ufo") +ufoPath2 = ufoPath1.replace("TestFont1 (UFO1).ufo", "TestFont1 (UFO2).ufo") + + +expectedFormatVersion1Features = """@myClass = [A B]; + +feature liga { + sub A A by b; +} liga; +""" + +# robofab should remove these from the lib after a load. +removeFromFormatVersion1Lib = [ + "org.robofab.opentype.classes", + "org.robofab.opentype.features", + "org.robofab.opentype.featureorder", + "org.robofab.postScriptHintData" +] + + +class ReadUFOFormatVersion1TestCase(unittest.TestCase): + + def setUpFont(self, doInfo=False, doKerning=False, doGroups=False, doLib=False, doFeatures=False): + self.font = NewFont() + self.ufoPath = ufoPath1 + self.font.readUFO(ufoPath1, doInfo=doInfo, doKerning=doKerning, doGroups=doGroups, doLib=doLib, doFeatures=doFeatures) + self.font.update() + + def tearDownFont(self): + self.font.close() + self.font = None + + def compareToUFO(self, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True): + reader = UFOReader(self.ufoPath) + results = {} + if doInfo: + infoMatches = True + info = self.font.info + for attr, expectedValue in expectedFontInfo1To2Conversion.items(): + writtenValue = getattr(info, attr) + if expectedValue != writtenValue: + infoMatches = False + break + results["info"]= infoMatches + if doKerning: + kerning = self.font.kerning.asDict() + expectedKerning = reader.readKerning() + results["kerning"] = expectedKerning == kerning + if doGroups: + groups = dict(self.font.groups) + expectedGroups = reader.readGroups() + results["groups"] = expectedGroups == groups + if doFeatures: + features = self.font.features.text + expectedFeatures = expectedFormatVersion1Features + # FontLab likes to add lines to the features, so skip blank lines. + features = [line for line in features.splitlines() if line] + expectedFeatures = [line for line in expectedFeatures.splitlines() if line] + results["features"] = expectedFeatures == features + if doLib: + lib = dict(self.font.lib) + expectedLib = reader.readLib() + for key in removeFromFormatVersion1Lib: + if key in expectedLib: + del expectedLib[key] + results["lib"] = expectedLib == lib + return results + + def testFull(self): + self.setUpFont(doInfo=True, doKerning=True, doGroups=True, doFeatures=True, doLib=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], True) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + def testInfo(self): + self.setUpFont(doInfo=True) + otherResults = self.compareToUFO(doInfo=False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], False) + info = self.font.info + for attr, expectedValue in expectedFontInfo1To2Conversion.items(): + writtenValue = getattr(info, attr) + self.assertEqual((attr, expectedValue), (attr, writtenValue)) + self.tearDownFont() + + def testFeatures(self): + self.setUpFont(doFeatures=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], False) + self.tearDownFont() + + def testKerning(self): + self.setUpFont(doKerning=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], False) + self.tearDownFont() + + def testGroups(self): + self.setUpFont(doGroups=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], False) + self.tearDownFont() + + def testLib(self): + self.setUpFont(doLib=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + +class ReadUFOFormatVersion2TestCase(unittest.TestCase): + + def setUpFont(self, doInfo=False, doKerning=False, doGroups=False, doLib=False, doFeatures=False): + self.font = NewFont() + self.ufoPath = ufoPath2 + self.font.readUFO(ufoPath2, doInfo=doInfo, doKerning=doKerning, doGroups=doGroups, doLib=doLib, doFeatures=doFeatures) + self.font.update() + + def tearDownFont(self): + self.font.close() + self.font = None + + def compareToUFO(self, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True): + reader = UFOReader(self.ufoPath) + results = {} + if doInfo: + infoMatches = True + info = self.font.info + for attr, expectedValue in fontInfoVersion2.items(): + # cheat by skipping attrs that aren't supported + if info._ufoToFLAttrMapping[attr]["nakedAttribute"] is None: + continue + writtenValue = getattr(info, attr) + if expectedValue != writtenValue: + infoMatches = False + break + results["info"]= infoMatches + if doKerning: + kerning = self.font.kerning.asDict() + expectedKerning = reader.readKerning() + results["kerning"] = expectedKerning == kerning + if doGroups: + groups = dict(self.font.groups) + expectedGroups = reader.readGroups() + results["groups"] = expectedGroups == groups + if doFeatures: + features = self.font.features.text + expectedFeatures = reader.readFeatures() + results["features"] = expectedFeatures == features + if doLib: + lib = dict(self.font.lib) + expectedLib = reader.readLib() + results["lib"] = expectedLib == lib + return results + + def testFull(self): + self.setUpFont(doInfo=True, doKerning=True, doGroups=True, doFeatures=True, doLib=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], True) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + def testInfo(self): + self.setUpFont(doInfo=True) + otherResults = self.compareToUFO(doInfo=False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], False) + info = self.font.info + for attr, expectedValue in fontInfoVersion2.items(): + # cheat by skipping attrs that aren't supported + if info._ufoToFLAttrMapping[attr]["nakedAttribute"] is None: + continue + writtenValue = getattr(info, attr) + self.assertEqual((attr, expectedValue), (attr, writtenValue)) + self.tearDownFont() + + def testFeatures(self): + self.setUpFont(doFeatures=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], False) + self.tearDownFont() + + def testKerning(self): + self.setUpFont(doKerning=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], False) + self.tearDownFont() + + def testGroups(self): + self.setUpFont(doGroups=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], False) + self.tearDownFont() + + def testLib(self): + self.setUpFont(doLib=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + +class WriteUFOFormatVersion1TestCase(unittest.TestCase): + + def setUpFont(self, doInfo=False, doKerning=False, doGroups=False): + self.dstDir = tempfile.mktemp() + os.mkdir(self.dstDir) + self.font = OpenFont(vfbPath) + self.font.writeUFO(self.dstDir, doInfo=doInfo, doKerning=doKerning, doGroups=doGroups, formatVersion=1) + self.font.close() + + def tearDownFont(self): + shutil.rmtree(self.dstDir) + + def compareToUFO(self, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True): + readerExpected = UFOReader(ufoPath1) + readerWritten = UFOReader(self.dstDir) + results = {} + if doInfo: + matches = True + expectedPath = os.path.join(ufoPath1, "fontinfo.plist") + writtenPath = os.path.join(self.dstDir, "fontinfo.plist") + if not os.path.exists(writtenPath): + matches = False + else: + expected = readPlist(expectedPath) + written = readPlist(writtenPath) + for attr, expectedValue in expected.items(): + if expectedValue != written[attr]: + matches = False + break + results["info"] = matches + if doKerning: + matches = True + expectedPath = os.path.join(ufoPath1, "kerning.plist") + writtenPath = os.path.join(self.dstDir, "kerning.plist") + if not os.path.exists(writtenPath): + matches = False + else: + matches = readPlist(expectedPath) == readPlist(writtenPath) + results["kerning"] = matches + if doGroups: + matches = True + expectedPath = os.path.join(ufoPath1, "groups.plist") + writtenPath = os.path.join(self.dstDir, "groups.plist") + if not os.path.exists(writtenPath): + matches = False + else: + matches = readPlist(expectedPath) == readPlist(writtenPath) + results["groups"] = matches + if doFeatures: + matches = True + featuresPath = os.path.join(self.dstDir, "features.fea") + libPath = os.path.join(self.dstDir, "lib.plist") + if os.path.exists(featuresPath): + matches = False + else: + fontLib = readPlist(libPath) + writtenText = [fontLib.get("org.robofab.opentype.classes", "")] + features = fontLib.get("org.robofab.opentype.features", {}) + featureOrder= fontLib.get("org.robofab.opentype.featureorder", []) + for featureName in featureOrder: + writtenText.append(features.get(featureName, "")) + writtenText = "\n".join(writtenText) + # FontLab likes to add lines to the features, so skip blank lines. + expectedText = [line for line in expectedFormatVersion1Features.splitlines() if line] + writtenText = [line for line in writtenText.splitlines() if line] + matches = "\n".join(expectedText) == "\n".join(writtenText) + results["features"] = matches + if doLib: + matches = True + expectedPath = os.path.join(ufoPath1, "lib.plist") + writtenPath = os.path.join(self.dstDir, "lib.plist") + if not os.path.exists(writtenPath): + matches = False + else: + # the test file doesn't have the glyph order + # so purge it from the written + writtenLib = readPlist(writtenPath) + del writtenLib["org.robofab.glyphOrder"] + matches = readPlist(expectedPath) == writtenLib + results["lib"] = matches + return results + + def testFull(self): + self.setUpFont(doInfo=True, doKerning=True, doGroups=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], True) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + def testInfo(self): + self.setUpFont(doInfo=True) + otherResults = self.compareToUFO(doInfo=False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + expectedPath = os.path.join(ufoPath1, "fontinfo.plist") + writtenPath = os.path.join(self.dstDir, "fontinfo.plist") + expected = readPlist(expectedPath) + written = readPlist(writtenPath) + for attr, expectedValue in expected.items(): + self.assertEqual((attr, expectedValue), (attr, written[attr])) + self.tearDownFont() + + def testFeatures(self): + self.setUpFont() + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], True) + self.tearDownFont() + + def testKerning(self): + self.setUpFont(doKerning=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], False) + self.tearDownFont() + + def testGroups(self): + self.setUpFont(doGroups=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], True) + self.tearDownFont() + + def testLib(self): + self.setUpFont() + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + + +class WriteUFOFormatVersion2TestCase(unittest.TestCase): + + def setUpFont(self, doInfo=False, doKerning=False, doGroups=False, doLib=False, doFeatures=False): + self.dstDir = tempfile.mktemp() + os.mkdir(self.dstDir) + self.font = OpenFont(vfbPath) + self.font.writeUFO(self.dstDir, doInfo=doInfo, doKerning=doKerning, doGroups=doGroups, doLib=doLib, doFeatures=doFeatures) + self.font.close() + + def tearDownFont(self): + shutil.rmtree(self.dstDir) + + def compareToUFO(self, doInfo=True, doKerning=True, doGroups=True, doLib=True, doFeatures=True): + readerExpected = UFOReader(ufoPath2) + readerWritten = UFOReader(self.dstDir) + results = {} + if doInfo: + matches = True + expectedPath = os.path.join(ufoPath2, "fontinfo.plist") + writtenPath = os.path.join(self.dstDir, "fontinfo.plist") + if not os.path.exists(writtenPath): + matches = False + else: + dummyFont = NewFont() + _ufoToFLAttrMapping = dict(dummyFont.info._ufoToFLAttrMapping) + dummyFont.close() + expected = readPlist(expectedPath) + written = readPlist(writtenPath) + for attr, expectedValue in expected.items(): + # cheat by skipping attrs that aren't supported + if _ufoToFLAttrMapping[attr]["nakedAttribute"] is None: + continue + if expectedValue != written[attr]: + matches = False + break + results["info"] = matches + if doKerning: + matches = True + expectedPath = os.path.join(ufoPath2, "kerning.plist") + writtenPath = os.path.join(self.dstDir, "kerning.plist") + if not os.path.exists(writtenPath): + matches = False + else: + matches = readPlist(expectedPath) == readPlist(writtenPath) + results["kerning"] = matches + if doGroups: + matches = True + expectedPath = os.path.join(ufoPath2, "groups.plist") + writtenPath = os.path.join(self.dstDir, "groups.plist") + if not os.path.exists(writtenPath): + matches = False + else: + matches = readPlist(expectedPath) == readPlist(writtenPath) + results["groups"] = matches + if doFeatures: + matches = True + expectedPath = os.path.join(ufoPath2, "features.fea") + writtenPath = os.path.join(self.dstDir, "features.fea") + if not os.path.exists(writtenPath): + matches = False + else: + f = open(expectedPath, "r") + expectedText = f.read() + f.close() + f = open(writtenPath, "r") + writtenText = f.read() + f.close() + # FontLab likes to add lines to the features, so skip blank lines. + expectedText = [line for line in expectedText.splitlines() if line] + writtenText = [line for line in writtenText.splitlines() if line] + matches = "\n".join(expectedText) == "\n".join(writtenText) + results["features"] = matches + if doLib: + matches = True + expectedPath = os.path.join(ufoPath2, "lib.plist") + writtenPath = os.path.join(self.dstDir, "lib.plist") + if not os.path.exists(writtenPath): + matches = False + else: + # the test file doesn't have the glyph order + # so purge it from the written + writtenLib = readPlist(writtenPath) + del writtenLib["org.robofab.glyphOrder"] + matches = readPlist(expectedPath) == writtenLib + results["lib"] = matches + return results + + def testFull(self): + self.setUpFont(doInfo=True, doKerning=True, doGroups=True, doFeatures=True, doLib=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], True) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + def testInfo(self): + self.setUpFont(doInfo=True) + otherResults = self.compareToUFO(doInfo=False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], False) + expectedPath = os.path.join(ufoPath2, "fontinfo.plist") + writtenPath = os.path.join(self.dstDir, "fontinfo.plist") + expected = readPlist(expectedPath) + written = readPlist(writtenPath) + dummyFont = NewFont() + _ufoToFLAttrMapping = dict(dummyFont.info._ufoToFLAttrMapping) + dummyFont.close() + for attr, expectedValue in expected.items(): + # cheat by skipping attrs that aren't supported + if _ufoToFLAttrMapping[attr]["nakedAttribute"] is None: + continue + self.assertEqual((attr, expectedValue), (attr, written[attr])) + self.tearDownFont() + + def testFeatures(self): + self.setUpFont(doFeatures=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], False) + self.tearDownFont() + + def testKerning(self): + self.setUpFont(doKerning=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], False) + self.tearDownFont() + + def testGroups(self): + self.setUpFont(doGroups=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], False) + self.tearDownFont() + + def testLib(self): + self.setUpFont(doLib=True) + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], False) + self.assertEqual(otherResults["kerning"], False) + self.assertEqual(otherResults["groups"], False) + self.assertEqual(otherResults["features"], False) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + +if __name__ == "__main__": + from robofab.test.testSupport import runTests + runTests() diff --git a/misc/pylib/robofab/test/test_glifLib.py b/misc/pylib/robofab/test/test_glifLib.py new file mode 100644 index 000000000..13eca3a6a --- /dev/null +++ b/misc/pylib/robofab/test/test_glifLib.py @@ -0,0 +1,150 @@ +import os +import tempfile +import shutil +import unittest + +from robofab.test.testSupport import getDemoFontGlyphSetPath +from robofab.glifLib import GlyphSet, glyphNameToFileName, READ_MODE +from robofab.tools.glyphNameSchemes import glyphNameToShortFileName + + +GLYPHSETDIR = getDemoFontGlyphSetPath() + + +class GlyphSetTests(unittest.TestCase): + + def setUp(self): + self.dstDir = tempfile.mktemp() + os.mkdir(self.dstDir) + + def tearDown(self): + shutil.rmtree(self.dstDir) + + def testRoundTrip(self): + srcDir = GLYPHSETDIR + dstDir = self.dstDir + src = GlyphSet(srcDir) + dst = GlyphSet(dstDir) + for glyphName in src.keys(): + g = src[glyphName] + g.drawPoints(None) # load attrs + dst.writeGlyph(glyphName, g, g.drawPoints) + # compare raw file data: + for glyphName in src.keys(): + fileName = src.contents[glyphName] + org = file(os.path.join(srcDir, fileName), READ_MODE).read() + new = file(os.path.join(dstDir, fileName), READ_MODE).read() + self.assertEqual(org, new, "%r .glif file differs after round tripping" % glyphName) + + def testRebuildContents(self): + gset = GlyphSet(GLYPHSETDIR) + contents = gset.contents + gset.rebuildContents() + self.assertEqual(contents, gset.contents) + + def testReverseContents(self): + gset = GlyphSet(GLYPHSETDIR) + d = {} + for k, v in gset.getReverseContents().items(): + d[v] = k + org = {} + for k, v in gset.contents.items(): + org[k] = v.lower() + self.assertEqual(d, org) + + def testReverseContents2(self): + src = GlyphSet(GLYPHSETDIR) + dst = GlyphSet(self.dstDir) + dstMap = dst.getReverseContents() + self.assertEqual(dstMap, {}) + for glyphName in src.keys(): + g = src[glyphName] + g.drawPoints(None) # load attrs + dst.writeGlyph(glyphName, g, g.drawPoints) + self.assertNotEqual(dstMap, {}) + srcMap = dict(src.getReverseContents()) # copy + self.assertEqual(dstMap, srcMap) + del srcMap["a.glif"] + dst.deleteGlyph("a") + self.assertEqual(dstMap, srcMap) + + def testCustomFileNamingScheme(self): + def myGlyphNameToFileName(glyphName, glyphSet): + return "prefix" + glyphNameToFileName(glyphName, glyphSet) + src = GlyphSet(GLYPHSETDIR) + dst = GlyphSet(self.dstDir, myGlyphNameToFileName) + for glyphName in src.keys(): + g = src[glyphName] + g.drawPoints(None) # load attrs + dst.writeGlyph(glyphName, g, g.drawPoints) + d = {} + for k, v in src.contents.items(): + print k, v + d[k] = "prefix" + v + self.assertEqual(d, dst.contents) + + def testGetUnicodes(self): + src = GlyphSet(GLYPHSETDIR) + unicodes = src.getUnicodes() + for glyphName in src.keys(): + g = src[glyphName] + g.drawPoints(None) # load attrs + if not hasattr(g, "unicodes"): + self.assertEqual(unicodes[glyphName], []) + else: + self.assertEqual(g.unicodes, unicodes[glyphName]) + + +class FileNameTests(unittest.TestCase): + + def testDefaultFileNameScheme(self): + self.assertEqual(glyphNameToFileName("a", None), "a.glif") + self.assertEqual(glyphNameToFileName("A", None), "A_.glif") + self.assertEqual(glyphNameToFileName("Aring", None), "Aring_.glif") + self.assertEqual(glyphNameToFileName("F_A_B", None), "F__A__B_.glif") + self.assertEqual(glyphNameToFileName("A.alt", None), "A_.alt.glif") + self.assertEqual(glyphNameToFileName("A.Alt", None), "A_.Alt_.glif") + self.assertEqual(glyphNameToFileName(".notdef", None), "_notdef.glif") + self.assertEqual(glyphNameToFileName("T_H", None), "T__H_.glif") + self.assertEqual(glyphNameToFileName("T_h", None), "T__h.glif") + self.assertEqual(glyphNameToFileName("t_h", None), "t_h.glif") + self.assertEqual(glyphNameToFileName('F_F_I', None), "F__F__I_.glif") + self.assertEqual(glyphNameToFileName('f_f_i', None), "f_f_i.glif") + + + def testShortFileNameScheme(self): + print "testShortFileNameScheme" + self.assertEqual(glyphNameToShortFileName("a", None), "a.glif") + self.assertEqual(glyphNameToShortFileName("A", None), "A_.glif") + self.assertEqual(glyphNameToShortFileName("aE", None), "aE_.glif") + self.assertEqual(glyphNameToShortFileName("AE", None), "A_E_.glif") + self.assertEqual(glyphNameToShortFileName("a.alt", None), "a_alt.glif") + self.assertEqual(glyphNameToShortFileName("A.alt", None), "A__alt.glif") + self.assertEqual(glyphNameToShortFileName("a.alt#swash", None), "a_alt_swash.glif") + self.assertEqual(glyphNameToShortFileName("A.alt", None), "A__alt.glif") + self.assertEqual(glyphNameToShortFileName(".notdef", None), "_notdef.glif") + self.assertEqual(glyphNameToShortFileName("f_f_i", None), "f_f_i.glif") + self.assertEqual(glyphNameToShortFileName("F_F_I", None), "F__F__I_.glif") + self.assertEqual(glyphNameToShortFileName("acircumflexdieresis.swash.alt1", None), "acircumflexdieresi0cfc8352.glif") + self.assertEqual(glyphNameToShortFileName("acircumflexdieresis.swash.alt2", None), "acircumflexdieresi95f5d2e8.glif") + self.assertEqual(glyphNameToShortFileName("Acircumflexdieresis.swash.alt1", None), "A_circumflexdieresed24fb56.glif") + self.assertEqual(glyphNameToShortFileName("F#weight0.800_width0.425", None), "F__weight0_800_width0_425.glif") + self.assertEqual(glyphNameToShortFileName("F#weight0.83245511_width0.425693567", None), "F__weight0_8324551c9a4143c.glif") + self.assertEqual(len(glyphNameToShortFileName("F#weight0.83245511_width0.425693567", None)), 31) + + def testShortFileNameScheme_clashes(self): + # test for the condition in code.robofab.com ticket #5 + name1 = glyphNameToShortFileName('Adieresis', None) + name2 = glyphNameToShortFileName('a_dieresis', None) + self.assertNotEqual(name1, name2) + name1 = glyphNameToShortFileName('AE', None) + name2 = glyphNameToShortFileName('aE', None) + self.assertNotEqual(name1, name2) + + +if __name__ == "__main__": + from robofab.test.testSupport import runTests + import sys + if len(sys.argv) > 1 and os.path.isdir(sys.argv[-1]): + GLYPHSETDIR = sys.argv.pop() + runTests() diff --git a/misc/pylib/robofab/test/test_noneLabUFOReadWrite.py b/misc/pylib/robofab/test/test_noneLabUFOReadWrite.py new file mode 100644 index 000000000..36dcc0582 --- /dev/null +++ b/misc/pylib/robofab/test/test_noneLabUFOReadWrite.py @@ -0,0 +1,321 @@ +import os +import shutil +import unittest +import tempfile +from robofab.plistlib import readPlist +import robofab +from robofab.test.testSupport import fontInfoVersion2, expectedFontInfo1To2Conversion, expectedFontInfo2To1Conversion +from robofab.objects.objectsRF import NewFont, OpenFont +from robofab.ufoLib import UFOReader + +ufoPath1 = os.path.dirname(robofab.__file__) +ufoPath1 = os.path.dirname(ufoPath1) +ufoPath1 = os.path.dirname(ufoPath1) +ufoPath1 = os.path.join(ufoPath1, "TestData", "TestFont1 (UFO1).ufo") +ufoPath2 = ufoPath1.replace("TestFont1 (UFO1).ufo", "TestFont1 (UFO2).ufo") + +# robofab should remove these from the lib after a load. +removeFromFormatVersion1Lib = [ + "org.robofab.opentype.classes", + "org.robofab.opentype.features", + "org.robofab.opentype.featureorder", + "org.robofab.postScriptHintData" +] + + +class ReadUFOFormatVersion1TestCase(unittest.TestCase): + + def setUpFont(self): + self.font = OpenFont(ufoPath1) + self.font.update() + + def tearDownFont(self): + self.font.close() + self.font = None + + def compareToUFO(self, doInfo=True): + reader = UFOReader(ufoPath1) + results = {} + # info + infoMatches = True + info = self.font.info + for attr, expectedValue in expectedFontInfo1To2Conversion.items(): + writtenValue = getattr(info, attr) + if expectedValue != writtenValue: + infoMatches = False + break + results["info"]= infoMatches + # kerning + kerning = self.font.kerning.asDict() + expectedKerning = reader.readKerning() + results["kerning"] = expectedKerning == kerning + # groups + groups = dict(self.font.groups) + expectedGroups = reader.readGroups() + results["groups"] = expectedGroups == groups + # features + features = self.font.features.text + f = open(os.path.join(ufoPath2, "features.fea"), "r") + expectedFeatures = f.read() + f.close() + match = True + features = [line for line in features.splitlines() if line] + expectedFeatures = [line for line in expectedFeatures.splitlines() if line] + if expectedFeatures != features or reader.readFeatures() != "": + match = False + results["features"] = match + # lib + lib = dict(self.font.lib) + expectedLib = reader.readLib() + for key in removeFromFormatVersion1Lib: + if key in expectedLib: + del expectedLib[key] + results["lib"] = expectedLib == lib + return results + + def testFull(self): + self.setUpFont() + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], True) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + def testInfo(self): + self.setUpFont() + info = self.font.info + for attr, expectedValue in expectedFontInfo1To2Conversion.items(): + writtenValue = getattr(info, attr) + self.assertEqual((attr, expectedValue), (attr, writtenValue)) + self.tearDownFont() + + +class ReadUFOFormatVersion2TestCase(unittest.TestCase): + + def setUpFont(self): + self.font = OpenFont(ufoPath2) + self.font.update() + + def tearDownFont(self): + self.font.close() + self.font = None + + def compareToUFO(self, doInfo=True): + reader = UFOReader(ufoPath2) + results = {} + # info + infoMatches = True + info = self.font.info + for attr, expectedValue in fontInfoVersion2.items(): + writtenValue = getattr(info, attr) + if expectedValue != writtenValue: + infoMatches = False + break + results["info"]= infoMatches + # kerning + kerning = self.font.kerning.asDict() + expectedKerning = reader.readKerning() + results["kerning"] = expectedKerning == kerning + # groups + groups = dict(self.font.groups) + expectedGroups = reader.readGroups() + results["groups"] = expectedGroups == groups + # features + features = self.font.features.text + expectedFeatures = reader.readFeatures() + results["features"] = expectedFeatures == features + # lib + lib = dict(self.font.lib) + expectedLib = reader.readLib() + results["lib"] = expectedLib == lib + return results + + def testFull(self): + self.setUpFont() + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], True) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + def testInfo(self): + self.setUpFont() + info = self.font.info + for attr, expectedValue in fontInfoVersion2.items(): + writtenValue = getattr(info, attr) + self.assertEqual((attr, expectedValue), (attr, writtenValue)) + self.tearDownFont() + + +class WriteUFOFormatVersion1TestCase(unittest.TestCase): + + def setUpFont(self): + self.dstDir = tempfile.mktemp() + os.mkdir(self.dstDir) + self.font = OpenFont(ufoPath2) + self.font.save(self.dstDir, formatVersion=1) + + def tearDownFont(self): + shutil.rmtree(self.dstDir) + + def compareToUFO(self): + readerExpected = UFOReader(ufoPath1) + readerWritten = UFOReader(self.dstDir) + results = {} + # info + matches = True + expectedPath = os.path.join(ufoPath1, "fontinfo.plist") + writtenPath = os.path.join(self.dstDir, "fontinfo.plist") + if not os.path.exists(writtenPath): + matches = False + else: + expected = readPlist(expectedPath) + written = readPlist(writtenPath) + for attr, expectedValue in expected.items(): + if expectedValue != written.get(attr): + matches = False + break + results["info"] = matches + # kerning + matches = True + expectedPath = os.path.join(ufoPath1, "kerning.plist") + writtenPath = os.path.join(self.dstDir, "kerning.plist") + if not os.path.exists(writtenPath): + matches = False + else: + matches = readPlist(expectedPath) == readPlist(writtenPath) + results["kerning"] = matches + # groups + matches = True + expectedPath = os.path.join(ufoPath1, "groups.plist") + writtenPath = os.path.join(self.dstDir, "groups.plist") + if not os.path.exists(writtenPath): + matches = False + else: + matches = readPlist(expectedPath) == readPlist(writtenPath) + results["groups"] = matches + # features + matches = True + expectedPath = os.path.join(ufoPath1, "features.fea") + writtenPath = os.path.join(self.dstDir, "features.fea") + if os.path.exists(writtenPath): + matches = False + results["features"] = matches + # lib + matches = True + expectedPath = os.path.join(ufoPath1, "lib.plist") + writtenPath = os.path.join(self.dstDir, "lib.plist") + if not os.path.exists(writtenPath): + matches = False + else: + writtenLib = readPlist(writtenPath) + matches = readPlist(expectedPath) == writtenLib + results["lib"] = matches + return results + + def testFull(self): + self.setUpFont() + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], True) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + +class WriteUFOFormatVersion2TestCase(unittest.TestCase): + + def setUpFont(self): + self.dstDir = tempfile.mktemp() + os.mkdir(self.dstDir) + self.font = OpenFont(ufoPath2) + self.font.save(self.dstDir) + + def tearDownFont(self): + shutil.rmtree(self.dstDir) + + def compareToUFO(self): + readerExpected = UFOReader(ufoPath2) + readerWritten = UFOReader(self.dstDir) + results = {} + # info + matches = True + expectedPath = os.path.join(ufoPath2, "fontinfo.plist") + writtenPath = os.path.join(self.dstDir, "fontinfo.plist") + if not os.path.exists(writtenPath): + matches = False + else: + expected = readPlist(expectedPath) + written = readPlist(writtenPath) + for attr, expectedValue in expected.items(): + if expectedValue != written[attr]: + matches = False + break + results["info"] = matches + # kerning + matches = True + expectedPath = os.path.join(ufoPath2, "kerning.plist") + writtenPath = os.path.join(self.dstDir, "kerning.plist") + if not os.path.exists(writtenPath): + matches = False + else: + matches = readPlist(expectedPath) == readPlist(writtenPath) + results["kerning"] = matches + # groups + matches = True + expectedPath = os.path.join(ufoPath2, "groups.plist") + writtenPath = os.path.join(self.dstDir, "groups.plist") + if not os.path.exists(writtenPath): + matches = False + else: + matches = readPlist(expectedPath) == readPlist(writtenPath) + results["groups"] = matches + # features + matches = True + expectedPath = os.path.join(ufoPath2, "features.fea") + writtenPath = os.path.join(self.dstDir, "features.fea") + if not os.path.exists(writtenPath): + matches = False + else: + f = open(expectedPath, "r") + expectedText = f.read() + f.close() + f = open(writtenPath, "r") + writtenText = f.read() + f.close() + # FontLab likes to add lines to the features, so skip blank lines. + expectedText = [line for line in expectedText.splitlines() if line] + writtenText = [line for line in writtenText.splitlines() if line] + matches = "\n".join(expectedText) == "\n".join(writtenText) + results["features"] = matches + # lib + matches = True + expectedPath = os.path.join(ufoPath2, "lib.plist") + writtenPath = os.path.join(self.dstDir, "lib.plist") + if not os.path.exists(writtenPath): + matches = False + else: + writtenLib = readPlist(writtenPath) + matches = readPlist(expectedPath) == writtenLib + results["lib"] = matches + return results + + def testFull(self): + self.setUpFont() + otherResults = self.compareToUFO() + self.assertEqual(otherResults["info"], True) + self.assertEqual(otherResults["kerning"], True) + self.assertEqual(otherResults["groups"], True) + self.assertEqual(otherResults["features"], True) + self.assertEqual(otherResults["lib"], True) + self.tearDownFont() + + +if __name__ == "__main__": + from robofab.test.testSupport import runTests + runTests() diff --git a/misc/pylib/robofab/test/test_objectsFL.py b/misc/pylib/robofab/test/test_objectsFL.py new file mode 100755 index 000000000..948897097 --- /dev/null +++ b/misc/pylib/robofab/test/test_objectsFL.py @@ -0,0 +1,54 @@ +"""This test suite for various FontLab-specific tests.""" + + +import FL # needed to quickly raise ImportError if run outside of FL + + +import os +import tempfile +import unittest + +from robofab.world import NewFont +from robofab.test.testSupport import getDemoFontPath, getDemoFontGlyphSetPath +from robofab.tools.glifImport import importAllGlifFiles +from robofab.pens.digestPen import DigestPointPen +from robofab.pens.adapterPens import SegmentToPointPen + + +def getDigests(font): + digests = {} + for glyphName in font.keys(): + pen = DigestPointPen() + font[glyphName].drawPoints(pen) + digests[glyphName] = pen.getDigest() + return digests + + +class FLTestCase(unittest.TestCase): + + def testUFOVersusGlifImport(self): + font = NewFont() + font.readUFO(getDemoFontPath(), doProgress=False) + d1 = getDigests(font) + font.close(False) + font = NewFont() + importAllGlifFiles(font.naked(), getDemoFontGlyphSetPath(), doProgress=False) + d2 = getDigests(font) + self.assertEqual(d1, d2) + font.close(False) + + def testTwoUntitledFonts(self): + font1 = NewFont() + font2 = NewFont() + font1.unitsPerEm = 1024 + font2.unitsPerEm = 2048 + self.assertNotEqual(font1.unitsPerEm, font2.unitsPerEm) + font1.update() + font2.update() + font1.close(False) + font2.close(False) + + +if __name__ == "__main__": + from robofab.test.testSupport import runTests + runTests() diff --git a/misc/pylib/robofab/test/test_objectsUFO.py b/misc/pylib/robofab/test/test_objectsUFO.py new file mode 100755 index 000000000..c974a121c --- /dev/null +++ b/misc/pylib/robofab/test/test_objectsUFO.py @@ -0,0 +1,203 @@ +"""This test suite for ufo glyph methods""" + + +import unittest +import os +import tempfile +import shutil + +from robofab.objects.objectsRF import RFont +from robofab.test.testSupport import getDemoFontPath +from robofab.pens.digestPen import DigestPointPen +from robofab.pens.adapterPens import SegmentToPointPen, FabToFontToolsPenAdapter + + +class ContourMethodsTestCase(unittest.TestCase): + + def setUp(self): + self.font = RFont(getDemoFontPath()) + + def testReverseContour(self): + for glyph in self.font: + pen = DigestPointPen() + glyph.drawPoints(pen) + digest1 = pen.getDigest() + for contour in glyph: + contour.reverseContour() + contour.reverseContour() + pen = DigestPointPen() + glyph.drawPoints(pen) + digest2 = pen.getDigest() + self.assertEqual(digest1, digest2, "%r not the same after reversing twice" % glyph.name) + + def testStartSegment(self): + for glyph in self.font: + pen = DigestPointPen() + glyph.drawPoints(pen) + digest1 = pen.getDigest() + for contour in glyph: + contour.setStartSegment(2) + contour.setStartSegment(-2) + pen = DigestPointPen() + glyph.drawPoints(pen) + digest2 = pen.getDigest() + self.assertEqual(digest1, digest2, "%r not the same after seting start segment twice" % glyph.name) + + def testAppendSegment(self): + for glyph in self.font: + pen = DigestPointPen() + glyph.drawPoints(pen) + digest1 = pen.getDigest() + for contour in glyph: + contour.insertSegment(2, "curve", [(100, 100), (200, 200), (300, 300)]) + contour.removeSegment(2) + pen = DigestPointPen() + glyph.drawPoints(pen) + digest2 = pen.getDigest() + self.assertEqual(digest1, digest2, "%r not the same after inserting and removing segment" % glyph.name) + + +class GlyphsMethodsTestCase(ContourMethodsTestCase): + + def testCopyGlyph(self): + for glyph in self.font: + pen = DigestPointPen() + glyph.drawPoints(pen) + digest1 = pen.getDigest() + copy = glyph.copy() + pen = DigestPointPen() + copy.drawPoints(pen) + digest2 = pen.getDigest() + self.assertEqual(digest1, digest2, "%r not the same after copying" % glyph.name) + self.assertEqual(glyph.lib, copy.lib, "%r's lib not the same after copying" % glyph.name) + self.assertEqual(glyph.width, copy.width, "%r's width not the same after copying" % glyph.name) + self.assertEqual(glyph.unicodes, copy.unicodes, "%r's unicodes not the same after copying" % glyph.name) + + def testMoveGlyph(self): + for glyph in self.font: + pen = DigestPointPen() + glyph.drawPoints(pen) + digest1 = pen.getDigest() + glyph.move((100, 200)) + glyph.move((-100, -200)) + pen = DigestPointPen() + glyph.drawPoints(pen) + digest2 = pen.getDigest() + self.assertEqual(digest1, digest2, "%r not the same after moving twice" % glyph.name) + + def testScaleGlyph(self): + for glyph in self.font: + pen = DigestPointPen() + glyph.drawPoints(pen) + digest1 = pen.getDigest() + glyph.scale((2, 2)) + glyph.scale((.5, .5)) + pen = DigestPointPen() + glyph.drawPoints(pen) + digest2 = pen.getDigest() + self.assertEqual(digest1, digest2, "%r not the same after scaling twice" % glyph.name) + + def testSegmentPenInterface(self): + for glyph in self.font: + digestPen = DigestPointPen(ignoreSmoothAndName=True) + pen = SegmentToPointPen(digestPen) + glyph.draw(pen) + digest1 = digestPen.getDigest() + digestPen = DigestPointPen(ignoreSmoothAndName=True) + glyph.drawPoints(digestPen) + digest2 = digestPen.getDigest() + self.assertEqual(digest1, digest2, "%r not the same for gl.draw() and gl.drawPoints()" % glyph.name) + + def testFabPenCompatibility(self): + for glyph in self.font: + digestPen = DigestPointPen(ignoreSmoothAndName=True) + pen = FabToFontToolsPenAdapter(SegmentToPointPen(digestPen)) + glyph.draw(pen) + digest1 = digestPen.getDigest() + digestPen = DigestPointPen(ignoreSmoothAndName=True) + glyph.drawPoints(digestPen) + digest2 = digestPen.getDigest() + self.assertEqual(digest1, digest2, "%r not the same for gl.draw() and gl.drawPoints()" % glyph.name) + + def testComponentTransformations(self): + from robofab.objects.objectsRF import RComponent + name = "baseGlyphName" + c = RComponent(name, transform=(1,0,0,1,0,0)) + # get values + assert c.baseGlyph == "baseGlyphName" + assert c.transformation == c.transformation + assert c.scale == (1,1) + assert c.offset == (0,0) + # set values + c.offset = (12,34) + assert c.transformation == (1, 0, 0, 1, 12, 34) + c.offset = (0,0) + assert c.transformation == (1,0,0,1,0,0) + c.scale = (12,34) + assert c.transformation == (12, 0, 0, 34, 0, 0) + + +class SaveTestCase(ContourMethodsTestCase): + + def testSaveAs(self): + path = tempfile.mktemp(".ufo") + try: + keys1 = self.font.keys() + self.font.save(path) + keys2 = self.font.keys() + keys1.sort() + keys2.sort() + self.assertEqual(keys1, keys2) + self.assertEqual(self.font.path, path) + font2 = RFont(path) + keys3 = font2.keys() + keys3.sort() + self.assertEqual(keys1, keys3) + finally: + if os.path.exists(path): + shutil.rmtree(path) + + def testSaveAs2(self): + path = tempfile.mktemp(".ufo") + # copy a glyph + self.font["X"] = self.font["a"].copy() +# self.assertEqual(self.font["X"].name, "X") + # remove a glyph + self.font.removeGlyph("a") + keys1 = self.font.keys() + try: + self.font.save(path) + self.assertEqual(self.font.path, path) + keys2 = self.font.keys() + keys1.sort() + keys2.sort() + self.assertEqual(keys1, keys2) + font2 = RFont(path) + keys3 = font2.keys() + keys3.sort() + self.assertEqual(keys1, keys3) + finally: + if os.path.exists(path): + shutil.rmtree(path) + + def testCustomFileNameScheme(self): + path = tempfile.mktemp(".ufo") + libKey = "org.robofab.glyphNameToFileNameFuncName" + self.font.lib[libKey] = "robofab.test.test_objectsUFO.testGlyphNameToFileName" + try: + self.font.save(path) + self.assertEqual(os.path.exists(os.path.join(path, + "glyphs", "test_a.glif")), True) + finally: + if os.path.exists(path): + shutil.rmtree(path) + + +def testGlyphNameToFileName(glyphName, glyphSet): + from robofab.glifLib import glyphNameToFileName + return "test_" + glyphNameToFileName(glyphName, glyphSet) + + +if __name__ == "__main__": + from robofab.test.testSupport import runTests + runTests() diff --git a/misc/pylib/robofab/test/test_pens.py b/misc/pylib/robofab/test/test_pens.py new file mode 100755 index 000000000..a2a773cb2 --- /dev/null +++ b/misc/pylib/robofab/test/test_pens.py @@ -0,0 +1,149 @@ +"""This test suite test general Pen stuff, it should not contain +FontLab-specific code. +""" + +import unittest + +from robofab.pens.digestPen import DigestPointPen +from robofab.pens.adapterPens import SegmentToPointPen, PointToSegmentPen +from robofab.pens.adapterPens import GuessSmoothPointPen +from robofab.pens.reverseContourPointPen import ReverseContourPointPen +from robofab.test.testSupport import getDemoFontGlyphSetPath +from robofab.glifLib import GlyphSet + + +class TestShapes: + + # Collection of test shapes. It's probably better to add these as + # glyphs to the demo font. + + def square(pen): + # a simple square as a closed path (100, 100, 600, 600) + pen.beginPath() + pen.addPoint((100, 100), "line") + pen.addPoint((100, 600), "line") + pen.addPoint((600, 600), "line") + pen.addPoint((600, 100), "line") + pen.endPath() + square = staticmethod(square) + + def onCurveLessQuadShape(pen): + pen.beginPath() + pen.addPoint((100, 100)) + pen.addPoint((100, 600)) + pen.addPoint((600, 600)) + pen.addPoint((600, 100)) + pen.endPath() + onCurveLessQuadShape = staticmethod(onCurveLessQuadShape) + + def openPath(pen): + # a simple square as a closed path (100, 100, 600, 600) + pen.beginPath() + pen.addPoint((100, 100), "move") + pen.addPoint((100, 600), "line") + pen.addPoint((600, 600), "line") + pen.addPoint((600, 100), "line") + pen.endPath() + openPath = staticmethod(openPath) + + def circle(pen): + pen.beginPath() + pen.addPoint((0, 500), "curve") + pen.addPoint((0, 800)) + pen.addPoint((200, 1000)) + pen.addPoint((500, 1000), "curve") + pen.addPoint((800, 1000)) + pen.addPoint((1000, 800)) + pen.addPoint((1000, 500), "curve") + pen.addPoint((1000, 200)) + pen.addPoint((800, 0)) + pen.addPoint((500, 0), "curve") + pen.addPoint((200, 0)) + pen.addPoint((0, 200)) + pen.endPath() + circle = staticmethod(circle) + + +class RoundTripTestCase(unittest.TestCase): + + def _doTest(self, shapeFunc, shapeName): + pen = DigestPointPen(ignoreSmoothAndName=True) + shapeFunc(pen) + digest1 = pen.getDigest() + + digestPen = DigestPointPen(ignoreSmoothAndName=True) + pen = PointToSegmentPen(SegmentToPointPen(digestPen)) + shapeFunc(pen) + digest2 = digestPen.getDigest() + self.assertEqual(digest1, digest2, "%r failed round tripping" % shapeName) + + def testShapes(self): + for name in dir(TestShapes): + if name[0] != "_": + self._doTest(getattr(TestShapes, name), name) + + def testShapesFromGlyphSet(self): + glyphSet = GlyphSet(getDemoFontGlyphSetPath()) + for name in glyphSet.keys(): + self._doTest(glyphSet[name].drawPoints, name) + + def testGuessSmoothPen(self): + glyphSet = GlyphSet(getDemoFontGlyphSetPath()) + for name in glyphSet.keys(): + digestPen = DigestPointPen() + glyphSet[name].drawPoints(digestPen) + digest1 = digestPen.getDigest() + digestPen = DigestPointPen() + pen = GuessSmoothPointPen(digestPen) + glyphSet[name].drawPoints(pen) + digest2 = digestPen.getDigest() + self.assertEqual(digest1, digest2) + + +class ReverseContourTestCase(unittest.TestCase): + + def testReverseContourClosedPath(self): + digestPen = DigestPointPen() + TestShapes.square(digestPen) + d1 = digestPen.getDigest() + digestPen = DigestPointPen() + pen = ReverseContourPointPen(digestPen) + pen.beginPath() + pen.addPoint((100, 100), "line") + pen.addPoint((600, 100), "line") + pen.addPoint((600, 600), "line") + pen.addPoint((100, 600), "line") + pen.endPath() + d2 = digestPen.getDigest() + self.assertEqual(d1, d2) + + def testReverseContourOpenPath(self): + digestPen = DigestPointPen() + TestShapes.openPath(digestPen) + d1 = digestPen.getDigest() + digestPen = DigestPointPen() + pen = ReverseContourPointPen(digestPen) + pen.beginPath() + pen.addPoint((600, 100), "move") + pen.addPoint((600, 600), "line") + pen.addPoint((100, 600), "line") + pen.addPoint((100, 100), "line") + pen.endPath() + d2 = digestPen.getDigest() + self.assertEqual(d1, d2) + + def testReversContourFromGlyphSet(self): + glyphSet = GlyphSet(getDemoFontGlyphSetPath()) + digestPen = DigestPointPen() + glyphSet["testglyph1"].drawPoints(digestPen) + digest1 = digestPen.getDigest() + digestPen = DigestPointPen() + pen = ReverseContourPointPen(digestPen) + glyphSet["testglyph1.reversed"].drawPoints(pen) + digest2 = digestPen.getDigest() + self.assertEqual(digest1, digest2) + + +if __name__ == "__main__": + from robofab.test.testSupport import runTests + runTests() diff --git a/misc/pylib/robofab/test/test_psHints.py b/misc/pylib/robofab/test/test_psHints.py new file mode 100644 index 000000000..991e9d9cc --- /dev/null +++ b/misc/pylib/robofab/test/test_psHints.py @@ -0,0 +1,110 @@ +def test(): + """ + # some tests for the ps Hints operations + >>> from robofab.world import RFont, RGlyph + >>> g = RGlyph() + >>> g.psHints.isEmpty() + True + + >>> h = RGlyph() + >>> i = g + h + >>> i.psHints.isEmpty() + True + + >>> i = g - h + >>> i.psHints.isEmpty() + True + + >>> i = g * 2 + >>> i.psHints.isEmpty() + True + + >>> i = g / 2 + >>> i.psHints.isEmpty() + True + + >>> g.psHints.vHints = [(100, 50), (200, 50)] + >>> g.psHints.hHints = [(100, 50), (200, 5)] + + >>> not g.psHints.isEmpty() + True + + >>> gc = g.copy() + >>> gc.psHints.asDict() == g.psHints.asDict() + True + + # multiplication + >>> v = g.psHints * 2 + >>> v.asDict() == {'vHints': [[200, 100], [400, 100]], 'hHints': [[200, 100], [400, 10]]} + True + + # division + >>> v = g.psHints / 2 + >>> v.asDict() == {'vHints': [[50.0, 25.0], [100.0, 25.0]], 'hHints': [[50.0, 25.0], [100.0, 2.5]]} + True + + # multiplication with x, y, factor + # vertically oriented values should respond different + >>> v = g.psHints * (.5, 10) + >>> v.asDict() == {'vHints': [[1000, 500], [2000, 500]], 'hHints': [[50.0, 25.0], [100.0, 2.5]]} + True + + # division with x, y, factor + # vertically oriented values should respond different + >>> v = g.psHints / (.5, 10) + >>> v.asDict() == {'vHints': [[10.0, 5.0], [20.0, 5.0]], 'hHints': [[200.0, 100.0], [400.0, 10.0]]} + True + + # rounding to integer + >>> v = g.psHints / 2 + >>> v.round() + >>> v.asDict() == {'vHints': [(50, 25), (100, 25)], 'hHints': [(50, 25), (100, 3)]} + True + + # "ps hint values calculating with a glyph" + # ps hint values as part of glyphmath operations. + # multiplication + >>> h = g * 10 + >>> h.psHints.asDict() == {'vHints': [[1000, 500], [2000, 500]], 'hHints': [[1000, 500], [2000, 50]]} + True + + # division + >>> h = g / 2 + >>> h.psHints.asDict() == {'vHints': [[50.0, 25.0], [100.0, 25.0]], 'hHints': [[50.0, 25.0], [100.0, 2.5]]} + True + + # x, y factor multiplication + >>> h = g * (.5, 10) + >>> h.psHints.asDict() == {'vHints': [[1000, 500], [2000, 500]], 'hHints': [[50.0, 25.0], [100.0, 2.5]]} + True + + # x, y factor division + >>> h = g / (.5, 10) + >>> h.psHints.asDict() == {'vHints': [[10.0, 5.0], [20.0, 5.0]], 'hHints': [[200.0, 100.0], [400.0, 10.0]]} + True + + # "font ps hint values" + >>> f = RFont() + >>> f.psHints.isEmpty() + True + + >>> f.psHints.blueScale = .5 + >>> f.psHints.blueShift = 1 + >>> f.psHints.blueFuzz = 1 + >>> f.psHints.forceBold = True + >>> f.psHints.hStems = (100, 90) + >>> f.psHints.vStems = (500, 10) + + >>> not f.psHints.isEmpty() + True + + >>> f.insertGlyph(g, name="new") + <RGlyph for None.new> + >>> f["new"].psHints.asDict() == g.psHints.asDict() + True + """ + +if __name__ == "__main__": + import doctest + doctest.testmod() + diff --git a/misc/pylib/robofab/test/test_ufoLib.py b/misc/pylib/robofab/test/test_ufoLib.py new file mode 100644 index 000000000..e1da807bb --- /dev/null +++ b/misc/pylib/robofab/test/test_ufoLib.py @@ -0,0 +1,1659 @@ +import os +import shutil +import unittest +import tempfile +from plistlib import writePlist, readPlist +from robofab.ufoLib import UFOReader, UFOWriter, UFOLibError, \ + convertUFOFormatVersion1ToFormatVersion2, convertUFOFormatVersion2ToFormatVersion1 +from robofab.test.testSupport import fontInfoVersion1, fontInfoVersion2, expectedFontInfo1To2Conversion, expectedFontInfo2To1Conversion + + +# the format version 1 lib.plist contains some data +# that these tests shouldn't be concerned about. +removeFromFormatVersion1Lib = [ + "org.robofab.opentype.classes", + "org.robofab.opentype.features", + "org.robofab.opentype.featureorder", + "org.robofab.postScriptHintData" +] + + +class TestInfoObject(object): pass + + +class ReadFontInfoVersion1TestCase(unittest.TestCase): + + def setUp(self): + self.dstDir = tempfile.mktemp() + os.mkdir(self.dstDir) + metaInfo = { + "creator": "test", + "formatVersion": 1 + } + path = os.path.join(self.dstDir, "metainfo.plist") + writePlist(metaInfo, path) + + def tearDown(self): + shutil.rmtree(self.dstDir) + + def _writeInfoToPlist(self, info): + path = os.path.join(self.dstDir, "fontinfo.plist") + writePlist(info, path) + + def testRead(self): + originalData = dict(fontInfoVersion1) + self._writeInfoToPlist(originalData) + infoObject = TestInfoObject() + reader = UFOReader(self.dstDir) + reader.readInfo(infoObject) + for attr in dir(infoObject): + if attr not in fontInfoVersion2: + continue + originalValue = fontInfoVersion2[attr] + readValue = getattr(infoObject, attr) + self.assertEqual(originalValue, readValue) + + def testFontStyleConversion(self): + fontStyle1To2 = { + 64 : "regular", + 1 : "italic", + 32 : "bold", + 33 : "bold italic" + } + for old, new in fontStyle1To2.items(): + info = dict(fontInfoVersion1) + info["fontStyle"] = old + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + infoObject = TestInfoObject() + reader.readInfo(infoObject) + self.assertEqual(new, infoObject.styleMapStyleName) + + def testWidthNameConversion(self): + widthName1To2 = { + "Ultra-condensed" : 1, + "Extra-condensed" : 2, + "Condensed" : 3, + "Semi-condensed" : 4, + "Medium (normal)" : 5, + "Semi-expanded" : 6, + "Expanded" : 7, + "Extra-expanded" : 8, + "Ultra-expanded" : 9 + } + for old, new in widthName1To2.items(): + info = dict(fontInfoVersion1) + info["widthName"] = old + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + infoObject = TestInfoObject() + reader.readInfo(infoObject) + self.assertEqual(new, infoObject.openTypeOS2WidthClass) + + +class ReadFontInfoVersion2TestCase(unittest.TestCase): + + def setUp(self): + self.dstDir = tempfile.mktemp() + os.mkdir(self.dstDir) + metaInfo = { + "creator": "test", + "formatVersion": 2 + } + path = os.path.join(self.dstDir, "metainfo.plist") + writePlist(metaInfo, path) + + def tearDown(self): + shutil.rmtree(self.dstDir) + + def _writeInfoToPlist(self, info): + path = os.path.join(self.dstDir, "fontinfo.plist") + writePlist(info, path) + + def testRead(self): + originalData = dict(fontInfoVersion2) + self._writeInfoToPlist(originalData) + infoObject = TestInfoObject() + reader = UFOReader(self.dstDir) + reader.readInfo(infoObject) + readData = {} + for attr in fontInfoVersion2.keys(): + readData[attr] = getattr(infoObject, attr) + self.assertEqual(originalData, readData) + + def testGenericRead(self): + # familyName + info = dict(fontInfoVersion2) + info["familyName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # styleName + info = dict(fontInfoVersion2) + info["styleName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # styleMapFamilyName + info = dict(fontInfoVersion2) + info["styleMapFamilyName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # styleMapStyleName + ## not a string + info = dict(fontInfoVersion2) + info["styleMapStyleName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## out of range + info = dict(fontInfoVersion2) + info["styleMapStyleName"] = "REGULAR" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # versionMajor + info = dict(fontInfoVersion2) + info["versionMajor"] = "1" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # versionMinor + info = dict(fontInfoVersion2) + info["versionMinor"] = "0" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # copyright + info = dict(fontInfoVersion2) + info["copyright"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # trademark + info = dict(fontInfoVersion2) + info["trademark"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # unitsPerEm + info = dict(fontInfoVersion2) + info["unitsPerEm"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # descender + info = dict(fontInfoVersion2) + info["descender"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # xHeight + info = dict(fontInfoVersion2) + info["xHeight"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # capHeight + info = dict(fontInfoVersion2) + info["capHeight"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # ascender + info = dict(fontInfoVersion2) + info["ascender"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # italicAngle + info = dict(fontInfoVersion2) + info["italicAngle"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + + def testHeadRead(self): + # openTypeHeadCreated + ## not a string + info = dict(fontInfoVersion2) + info["openTypeHeadCreated"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## invalid format + info = dict(fontInfoVersion2) + info["openTypeHeadCreated"] = "2000-Jan-01 00:00:00" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeHeadLowestRecPPEM + info = dict(fontInfoVersion2) + info["openTypeHeadLowestRecPPEM"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeHeadFlags + info = dict(fontInfoVersion2) + info["openTypeHeadFlags"] = [-1] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + + def testHheaRead(self): + # openTypeHheaAscender + info = dict(fontInfoVersion2) + info["openTypeHheaAscender"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeHheaDescender + info = dict(fontInfoVersion2) + info["openTypeHheaDescender"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeHheaLineGap + info = dict(fontInfoVersion2) + info["openTypeHheaLineGap"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeHheaCaretSlopeRise + info = dict(fontInfoVersion2) + info["openTypeHheaCaretSlopeRise"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeHheaCaretSlopeRun + info = dict(fontInfoVersion2) + info["openTypeHheaCaretSlopeRun"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeHheaCaretOffset + info = dict(fontInfoVersion2) + info["openTypeHheaCaretOffset"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + + def testNameRead(self): + # openTypeNameDesigner + info = dict(fontInfoVersion2) + info["openTypeNameDesigner"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameDesignerURL + info = dict(fontInfoVersion2) + info["openTypeNameDesignerURL"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameManufacturer + info = dict(fontInfoVersion2) + info["openTypeNameManufacturer"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameManufacturerURL + info = dict(fontInfoVersion2) + info["openTypeNameManufacturerURL"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameLicense + info = dict(fontInfoVersion2) + info["openTypeNameLicense"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameLicenseURL + info = dict(fontInfoVersion2) + info["openTypeNameLicenseURL"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameVersion + info = dict(fontInfoVersion2) + info["openTypeNameVersion"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameUniqueID + info = dict(fontInfoVersion2) + info["openTypeNameUniqueID"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameDescription + info = dict(fontInfoVersion2) + info["openTypeNameDescription"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNamePreferredFamilyName + info = dict(fontInfoVersion2) + info["openTypeNamePreferredFamilyName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNamePreferredSubfamilyName + info = dict(fontInfoVersion2) + info["openTypeNamePreferredSubfamilyName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameCompatibleFullName + info = dict(fontInfoVersion2) + info["openTypeNameCompatibleFullName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameSampleText + info = dict(fontInfoVersion2) + info["openTypeNameSampleText"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameWWSFamilyName + info = dict(fontInfoVersion2) + info["openTypeNameWWSFamilyName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeNameWWSSubfamilyName + info = dict(fontInfoVersion2) + info["openTypeNameWWSSubfamilyName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + + def testOS2Read(self): + # openTypeOS2WidthClass + ## not an int + info = dict(fontInfoVersion2) + info["openTypeOS2WidthClass"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## out or range + info = dict(fontInfoVersion2) + info["openTypeOS2WidthClass"] = 15 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2WeightClass + info = dict(fontInfoVersion2) + ## not an int + info["openTypeOS2WeightClass"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## out of range + info["openTypeOS2WeightClass"] = -50 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2Selection + info = dict(fontInfoVersion2) + info["openTypeOS2Selection"] = [-1] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2VendorID + info = dict(fontInfoVersion2) + info["openTypeOS2VendorID"] = 1234 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2Panose + ## not an int + info = dict(fontInfoVersion2) + info["openTypeOS2Panose"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, str(9)] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## too few values + info = dict(fontInfoVersion2) + info["openTypeOS2Panose"] = [0, 1, 2, 3] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## too many values + info = dict(fontInfoVersion2) + info["openTypeOS2Panose"] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2FamilyClass + ## not an int + info = dict(fontInfoVersion2) + info["openTypeOS2FamilyClass"] = [1, str(1)] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## too few values + info = dict(fontInfoVersion2) + info["openTypeOS2FamilyClass"] = [1] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## too many values + info = dict(fontInfoVersion2) + info["openTypeOS2FamilyClass"] = [1, 1, 1] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## out of range + info = dict(fontInfoVersion2) + info["openTypeOS2FamilyClass"] = [1, 201] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2UnicodeRanges + ## not an int + info = dict(fontInfoVersion2) + info["openTypeOS2UnicodeRanges"] = ["0"] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## out of range + info = dict(fontInfoVersion2) + info["openTypeOS2UnicodeRanges"] = [-1] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2CodePageRanges + ## not an int + info = dict(fontInfoVersion2) + info["openTypeOS2CodePageRanges"] = ["0"] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## out of range + info = dict(fontInfoVersion2) + info["openTypeOS2CodePageRanges"] = [-1] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2TypoAscender + info = dict(fontInfoVersion2) + info["openTypeOS2TypoAscender"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2TypoDescender + info = dict(fontInfoVersion2) + info["openTypeOS2TypoDescender"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2TypoLineGap + info = dict(fontInfoVersion2) + info["openTypeOS2TypoLineGap"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2WinAscent + info = dict(fontInfoVersion2) + info["openTypeOS2WinAscent"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2WinDescent + info = dict(fontInfoVersion2) + info["openTypeOS2WinDescent"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2Type + ## not an int + info = dict(fontInfoVersion2) + info["openTypeOS2Type"] = ["1"] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + ## out of range + info = dict(fontInfoVersion2) + info["openTypeOS2Type"] = [-1] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2SubscriptXSize + info = dict(fontInfoVersion2) + info["openTypeOS2SubscriptXSize"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2SubscriptYSize + info = dict(fontInfoVersion2) + info["openTypeOS2SubscriptYSize"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2SubscriptXOffset + info = dict(fontInfoVersion2) + info["openTypeOS2SubscriptXOffset"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2SubscriptYOffset + info = dict(fontInfoVersion2) + info["openTypeOS2SubscriptYOffset"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2SuperscriptXSize + info = dict(fontInfoVersion2) + info["openTypeOS2SuperscriptXSize"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2SuperscriptYSize + info = dict(fontInfoVersion2) + info["openTypeOS2SuperscriptYSize"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2SuperscriptXOffset + info = dict(fontInfoVersion2) + info["openTypeOS2SuperscriptXOffset"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2SuperscriptYOffset + info = dict(fontInfoVersion2) + info["openTypeOS2SuperscriptYOffset"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2StrikeoutSize + info = dict(fontInfoVersion2) + info["openTypeOS2StrikeoutSize"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeOS2StrikeoutPosition + info = dict(fontInfoVersion2) + info["openTypeOS2StrikeoutPosition"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + + def testVheaRead(self): + # openTypeVheaVertTypoAscender + info = dict(fontInfoVersion2) + info["openTypeVheaVertTypoAscender"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeVheaVertTypoDescender + info = dict(fontInfoVersion2) + info["openTypeVheaVertTypoDescender"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeVheaVertTypoLineGap + info = dict(fontInfoVersion2) + info["openTypeVheaVertTypoLineGap"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeVheaCaretSlopeRise + info = dict(fontInfoVersion2) + info["openTypeVheaCaretSlopeRise"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeVheaCaretSlopeRun + info = dict(fontInfoVersion2) + info["openTypeVheaCaretSlopeRun"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # openTypeVheaCaretOffset + info = dict(fontInfoVersion2) + info["openTypeVheaCaretOffset"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + + def testFONDRead(self): + # macintoshFONDFamilyID + info = dict(fontInfoVersion2) + info["macintoshFONDFamilyID"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # macintoshFONDName + info = dict(fontInfoVersion2) + info["macintoshFONDName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + + def testPostscriptRead(self): + # postscriptFontName + info = dict(fontInfoVersion2) + info["postscriptFontName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # postscriptFullName + info = dict(fontInfoVersion2) + info["postscriptFullName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # postscriptSlantAngle + info = dict(fontInfoVersion2) + info["postscriptSlantAngle"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, info=TestInfoObject()) + # postscriptUniqueID + info = dict(fontInfoVersion2) + info["postscriptUniqueID"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptUnderlineThickness + info = dict(fontInfoVersion2) + info["postscriptUnderlineThickness"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptUnderlinePosition + info = dict(fontInfoVersion2) + info["postscriptUnderlinePosition"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptIsFixedPitch + info = dict(fontInfoVersion2) + info["postscriptIsFixedPitch"] = 2 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptBlueValues + ## not a list + info = dict(fontInfoVersion2) + info["postscriptBlueValues"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + ## uneven value count + info = dict(fontInfoVersion2) + info["postscriptBlueValues"] = [500] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + ## too many values + info = dict(fontInfoVersion2) + info["postscriptBlueValues"] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptOtherBlues + ## not a list + info = dict(fontInfoVersion2) + info["postscriptOtherBlues"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + ## uneven value count + info = dict(fontInfoVersion2) + info["postscriptOtherBlues"] = [500] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + ## too many values + info = dict(fontInfoVersion2) + info["postscriptOtherBlues"] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptFamilyBlues + ## not a list + info = dict(fontInfoVersion2) + info["postscriptFamilyBlues"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + ## uneven value count + info = dict(fontInfoVersion2) + info["postscriptFamilyBlues"] = [500] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + ## too many values + info = dict(fontInfoVersion2) + info["postscriptFamilyBlues"] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptFamilyOtherBlues + ## not a list + info = dict(fontInfoVersion2) + info["postscriptFamilyOtherBlues"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + ## uneven value count + info = dict(fontInfoVersion2) + info["postscriptFamilyOtherBlues"] = [500] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + ## too many values + info = dict(fontInfoVersion2) + info["postscriptFamilyOtherBlues"] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptStemSnapH + ## not list + info = dict(fontInfoVersion2) + info["postscriptStemSnapH"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + ## too many values + info = dict(fontInfoVersion2) + info["postscriptStemSnapH"] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptStemSnapV + ## not list + info = dict(fontInfoVersion2) + info["postscriptStemSnapV"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + ## too many values + info = dict(fontInfoVersion2) + info["postscriptStemSnapV"] = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptBlueFuzz + info = dict(fontInfoVersion2) + info["postscriptBlueFuzz"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptBlueShift + info = dict(fontInfoVersion2) + info["postscriptBlueShift"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptBlueScale + info = dict(fontInfoVersion2) + info["postscriptBlueScale"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptForceBold + info = dict(fontInfoVersion2) + info["postscriptForceBold"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptDefaultWidthX + info = dict(fontInfoVersion2) + info["postscriptDefaultWidthX"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptNominalWidthX + info = dict(fontInfoVersion2) + info["postscriptNominalWidthX"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptWeightName + info = dict(fontInfoVersion2) + info["postscriptWeightName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptDefaultCharacter + info = dict(fontInfoVersion2) + info["postscriptDefaultCharacter"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # postscriptWindowsCharacterSet + info = dict(fontInfoVersion2) + info["postscriptWindowsCharacterSet"] = -1 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # macintoshFONDFamilyID + info = dict(fontInfoVersion2) + info["macintoshFONDFamilyID"] = "abc" + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + # macintoshFONDName + info = dict(fontInfoVersion2) + info["macintoshFONDName"] = 123 + self._writeInfoToPlist(info) + reader = UFOReader(self.dstDir) + self.assertRaises(UFOLibError, reader.readInfo, TestInfoObject()) + + +class WriteFontInfoVersion1TestCase(unittest.TestCase): + + def setUp(self): + self.dstDir = tempfile.mktemp() + os.mkdir(self.dstDir) + + def tearDown(self): + shutil.rmtree(self.dstDir) + + def makeInfoObject(self): + infoObject = TestInfoObject() + for attr, value in fontInfoVersion2.items(): + setattr(infoObject, attr, value) + return infoObject + + def readPlist(self): + path = os.path.join(self.dstDir, "fontinfo.plist") + return readPlist(path) + + def testWrite(self): + infoObject = self.makeInfoObject() + writer = UFOWriter(self.dstDir, formatVersion=1) + writer.writeInfo(infoObject) + writtenData = self.readPlist() + for attr, originalValue in fontInfoVersion1.items(): + newValue = writtenData[attr] + self.assertEqual(newValue, originalValue) + + def testFontStyleConversion(self): + fontStyle1To2 = { + 64 : "regular", + 1 : "italic", + 32 : "bold", + 33 : "bold italic" + } + for old, new in fontStyle1To2.items(): + infoObject = self.makeInfoObject() + infoObject.styleMapStyleName = new + writer = UFOWriter(self.dstDir, formatVersion=1) + writer.writeInfo(infoObject) + writtenData = self.readPlist() + self.assertEqual(writtenData["fontStyle"], old) + + def testWidthNameConversion(self): + widthName1To2 = { + "Ultra-condensed" : 1, + "Extra-condensed" : 2, + "Condensed" : 3, + "Semi-condensed" : 4, + "Medium (normal)" : 5, + "Semi-expanded" : 6, + "Expanded" : 7, + "Extra-expanded" : 8, + "Ultra-expanded" : 9 + } + for old, new in widthName1To2.items(): + infoObject = self.makeInfoObject() + infoObject.openTypeOS2WidthClass = new + writer = UFOWriter(self.dstDir, formatVersion=1) + writer.writeInfo(infoObject) + writtenData = self.readPlist() + self.assertEqual(writtenData["widthName"], old) + + +class WriteFontInfoVersion2TestCase(unittest.TestCase): + + def setUp(self): + self.dstDir = tempfile.mktemp() + os.mkdir(self.dstDir) + + def tearDown(self): + shutil.rmtree(self.dstDir) + + def makeInfoObject(self): + infoObject = TestInfoObject() + for attr, value in fontInfoVersion2.items(): + setattr(infoObject, attr, value) + return infoObject + + def readPlist(self): + path = os.path.join(self.dstDir, "fontinfo.plist") + return readPlist(path) + + def testWrite(self): + infoObject = self.makeInfoObject() + writer = UFOWriter(self.dstDir) + writer.writeInfo(infoObject) + writtenData = self.readPlist() + for attr, originalValue in fontInfoVersion2.items(): + newValue = writtenData[attr] + self.assertEqual(newValue, originalValue) + + def testGenericWrite(self): + # familyName + infoObject = self.makeInfoObject() + infoObject.familyName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # styleName + infoObject = self.makeInfoObject() + infoObject.styleName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # styleMapFamilyName + infoObject = self.makeInfoObject() + infoObject.styleMapFamilyName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # styleMapStyleName + ## not a string + infoObject = self.makeInfoObject() + infoObject.styleMapStyleName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## out of range + infoObject = self.makeInfoObject() + infoObject.styleMapStyleName = "REGULAR" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # versionMajor + infoObject = self.makeInfoObject() + infoObject.versionMajor = "1" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # versionMinor + infoObject = self.makeInfoObject() + infoObject.versionMinor = "0" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # copyright + infoObject = self.makeInfoObject() + infoObject.copyright = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # trademark + infoObject = self.makeInfoObject() + infoObject.trademark = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # unitsPerEm + infoObject = self.makeInfoObject() + infoObject.unitsPerEm = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # descender + infoObject = self.makeInfoObject() + infoObject.descender = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # xHeight + infoObject = self.makeInfoObject() + infoObject.xHeight = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # capHeight + infoObject = self.makeInfoObject() + infoObject.capHeight = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # ascender + infoObject = self.makeInfoObject() + infoObject.ascender = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # italicAngle + infoObject = self.makeInfoObject() + infoObject.italicAngle = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + + def testHeadWrite(self): + # openTypeHeadCreated + ## not a string + infoObject = self.makeInfoObject() + infoObject.openTypeHeadCreated = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## invalid format + infoObject = self.makeInfoObject() + infoObject.openTypeHeadCreated = "2000-Jan-01 00:00:00" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeHeadLowestRecPPEM + infoObject = self.makeInfoObject() + infoObject.openTypeHeadLowestRecPPEM = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeHeadFlags + infoObject = self.makeInfoObject() + infoObject.openTypeHeadFlags = [-1] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + + def testHheaWrite(self): + # openTypeHheaAscender + infoObject = self.makeInfoObject() + infoObject.openTypeHheaAscender = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeHheaDescender + infoObject = self.makeInfoObject() + infoObject.openTypeHheaDescender = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeHheaLineGap + infoObject = self.makeInfoObject() + infoObject.openTypeHheaLineGap = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeHheaCaretSlopeRise + infoObject = self.makeInfoObject() + infoObject.openTypeHheaCaretSlopeRise = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeHheaCaretSlopeRun + infoObject = self.makeInfoObject() + infoObject.openTypeHheaCaretSlopeRun = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeHheaCaretOffset + infoObject = self.makeInfoObject() + infoObject.openTypeHheaCaretOffset = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + + def testNameWrite(self): + # openTypeNameDesigner + infoObject = self.makeInfoObject() + infoObject.openTypeNameDesigner = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameDesignerURL + infoObject = self.makeInfoObject() + infoObject.openTypeNameDesignerURL = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameManufacturer + infoObject = self.makeInfoObject() + infoObject.openTypeNameManufacturer = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameManufacturerURL + infoObject = self.makeInfoObject() + infoObject.openTypeNameManufacturerURL = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameLicense + infoObject = self.makeInfoObject() + infoObject.openTypeNameLicense = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameLicenseURL + infoObject = self.makeInfoObject() + infoObject.openTypeNameLicenseURL = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameVersion + infoObject = self.makeInfoObject() + infoObject.openTypeNameVersion = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameUniqueID + infoObject = self.makeInfoObject() + infoObject.openTypeNameUniqueID = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameDescription + infoObject = self.makeInfoObject() + infoObject.openTypeNameDescription = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNamePreferredFamilyName + infoObject = self.makeInfoObject() + infoObject.openTypeNamePreferredFamilyName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNamePreferredSubfamilyName + infoObject = self.makeInfoObject() + infoObject.openTypeNamePreferredSubfamilyName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameCompatibleFullName + infoObject = self.makeInfoObject() + infoObject.openTypeNameCompatibleFullName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameSampleText + infoObject = self.makeInfoObject() + infoObject.openTypeNameSampleText = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameWWSFamilyName + infoObject = self.makeInfoObject() + infoObject.openTypeNameWWSFamilyName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeNameWWSSubfamilyName + infoObject = self.makeInfoObject() + infoObject.openTypeNameWWSSubfamilyName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + + def testOS2Write(self): + # openTypeOS2WidthClass + ## not an int + infoObject = self.makeInfoObject() + infoObject.openTypeOS2WidthClass = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## out or range + infoObject = self.makeInfoObject() + infoObject.openTypeOS2WidthClass = 15 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2WeightClass + infoObject = self.makeInfoObject() + ## not an int + infoObject.openTypeOS2WeightClass = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## out of range + infoObject.openTypeOS2WeightClass = -50 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2Selection + infoObject = self.makeInfoObject() + infoObject.openTypeOS2Selection = [-1] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2VendorID + infoObject = self.makeInfoObject() + infoObject.openTypeOS2VendorID = 1234 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2Panose + ## not an int + infoObject = self.makeInfoObject() + infoObject.openTypeOS2Panose = [0, 1, 2, 3, 4, 5, 6, 7, 8, str(9)] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## too few values + infoObject = self.makeInfoObject() + infoObject.openTypeOS2Panose = [0, 1, 2, 3] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## too many values + infoObject = self.makeInfoObject() + infoObject.openTypeOS2Panose = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2FamilyClass + ## not an int + infoObject = self.makeInfoObject() + infoObject.openTypeOS2FamilyClass = [0, str(1)] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## too few values + infoObject = self.makeInfoObject() + infoObject.openTypeOS2FamilyClass = [1] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## too many values + infoObject = self.makeInfoObject() + infoObject.openTypeOS2FamilyClass = [1, 1, 1] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## out of range + infoObject = self.makeInfoObject() + infoObject.openTypeOS2FamilyClass = [1, 20] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2UnicodeRanges + ## not an int + infoObject = self.makeInfoObject() + infoObject.openTypeOS2UnicodeRanges = ["0"] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## out of range + infoObject = self.makeInfoObject() + infoObject.openTypeOS2UnicodeRanges = [-1] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2CodePageRanges + ## not an int + infoObject = self.makeInfoObject() + infoObject.openTypeOS2CodePageRanges = ["0"] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## out of range + infoObject = self.makeInfoObject() + infoObject.openTypeOS2CodePageRanges = [-1] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2TypoAscender + infoObject = self.makeInfoObject() + infoObject.openTypeOS2TypoAscender = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2TypoDescender + infoObject = self.makeInfoObject() + infoObject.openTypeOS2TypoDescender = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2TypoLineGap + infoObject = self.makeInfoObject() + infoObject.openTypeOS2TypoLineGap = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2WinAscent + infoObject = self.makeInfoObject() + infoObject.openTypeOS2WinAscent = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2WinDescent + infoObject = self.makeInfoObject() + infoObject.openTypeOS2WinDescent = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2Type + ## not an int + infoObject = self.makeInfoObject() + infoObject.openTypeOS2Type = ["1"] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## out of range + infoObject = self.makeInfoObject() + infoObject.openTypeOS2Type = [-1] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2SubscriptXSize + infoObject = self.makeInfoObject() + infoObject.openTypeOS2SubscriptXSize = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2SubscriptYSize + infoObject = self.makeInfoObject() + infoObject.openTypeOS2SubscriptYSize = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2SubscriptXOffset + infoObject = self.makeInfoObject() + infoObject.openTypeOS2SubscriptXOffset = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2SubscriptYOffset + infoObject = self.makeInfoObject() + infoObject.openTypeOS2SubscriptYOffset = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2SuperscriptXSize + infoObject = self.makeInfoObject() + infoObject.openTypeOS2SuperscriptXSize = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2SuperscriptYSize + infoObject = self.makeInfoObject() + infoObject.openTypeOS2SuperscriptYSize = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2SuperscriptXOffset + infoObject = self.makeInfoObject() + infoObject.openTypeOS2SuperscriptXOffset = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2SuperscriptYOffset + infoObject = self.makeInfoObject() + infoObject.openTypeOS2SuperscriptYOffset = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2StrikeoutSize + infoObject = self.makeInfoObject() + infoObject.openTypeOS2StrikeoutSize = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeOS2StrikeoutPosition + infoObject = self.makeInfoObject() + infoObject.openTypeOS2StrikeoutPosition = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + + def testVheaWrite(self): + # openTypeVheaVertTypoAscender + infoObject = self.makeInfoObject() + infoObject.openTypeVheaVertTypoAscender = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeVheaVertTypoDescender + infoObject = self.makeInfoObject() + infoObject.openTypeVheaVertTypoDescender = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeVheaVertTypoLineGap + infoObject = self.makeInfoObject() + infoObject.openTypeVheaVertTypoLineGap = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeVheaCaretSlopeRise + infoObject = self.makeInfoObject() + infoObject.openTypeVheaCaretSlopeRise = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeVheaCaretSlopeRun + infoObject = self.makeInfoObject() + infoObject.openTypeVheaCaretSlopeRun = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # openTypeVheaCaretOffset + infoObject = self.makeInfoObject() + infoObject.openTypeVheaCaretOffset = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + + def testFONDWrite(self): + # macintoshFONDFamilyID + infoObject = self.makeInfoObject() + infoObject.macintoshFONDFamilyID = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # macintoshFONDName + infoObject = self.makeInfoObject() + infoObject.macintoshFONDName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + + def testPostscriptWrite(self): + # postscriptFontName + infoObject = self.makeInfoObject() + infoObject.postscriptFontName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptFullName + infoObject = self.makeInfoObject() + infoObject.postscriptFullName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptSlantAngle + infoObject = self.makeInfoObject() + infoObject.postscriptSlantAngle = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptUniqueID + infoObject = self.makeInfoObject() + infoObject.postscriptUniqueID = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptUnderlineThickness + infoObject = self.makeInfoObject() + infoObject.postscriptUnderlineThickness = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptUnderlinePosition + infoObject = self.makeInfoObject() + infoObject.postscriptUnderlinePosition = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptIsFixedPitch + infoObject = self.makeInfoObject() + infoObject.postscriptIsFixedPitch = 2 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptBlueValues + ## not a list + infoObject = self.makeInfoObject() + infoObject.postscriptBlueValues = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## uneven value count + infoObject = self.makeInfoObject() + infoObject.postscriptBlueValues = [500] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## too many values + infoObject = self.makeInfoObject() + infoObject.postscriptBlueValues = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptOtherBlues + ## not a list + infoObject = self.makeInfoObject() + infoObject.postscriptOtherBlues = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## uneven value count + infoObject = self.makeInfoObject() + infoObject.postscriptOtherBlues = [500] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## too many values + infoObject = self.makeInfoObject() + infoObject.postscriptOtherBlues = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptFamilyBlues + ## not a list + infoObject = self.makeInfoObject() + infoObject.postscriptFamilyBlues = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## uneven value count + infoObject = self.makeInfoObject() + infoObject.postscriptFamilyBlues = [500] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## too many values + infoObject = self.makeInfoObject() + infoObject.postscriptFamilyBlues = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptFamilyOtherBlues + ## not a list + infoObject = self.makeInfoObject() + infoObject.postscriptFamilyOtherBlues = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## uneven value count + infoObject = self.makeInfoObject() + infoObject.postscriptFamilyOtherBlues = [500] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## too many values + infoObject = self.makeInfoObject() + infoObject.postscriptFamilyOtherBlues = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptStemSnapH + ## not list + infoObject = self.makeInfoObject() + infoObject.postscriptStemSnapH = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## too many values + infoObject = self.makeInfoObject() + infoObject.postscriptStemSnapH = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptStemSnapV + ## not list + infoObject = self.makeInfoObject() + infoObject.postscriptStemSnapV = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + ## too many values + infoObject = self.makeInfoObject() + infoObject.postscriptStemSnapV = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160] + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptBlueFuzz + infoObject = self.makeInfoObject() + infoObject.postscriptBlueFuzz = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptBlueShift + infoObject = self.makeInfoObject() + infoObject.postscriptBlueShift = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptBlueScale + infoObject = self.makeInfoObject() + infoObject.postscriptBlueScale = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptForceBold + infoObject = self.makeInfoObject() + infoObject.postscriptForceBold = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptDefaultWidthX + infoObject = self.makeInfoObject() + infoObject.postscriptDefaultWidthX = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptNominalWidthX + infoObject = self.makeInfoObject() + infoObject.postscriptNominalWidthX = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptWeightName + infoObject = self.makeInfoObject() + infoObject.postscriptWeightName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptDefaultCharacter + infoObject = self.makeInfoObject() + infoObject.postscriptDefaultCharacter = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # postscriptWindowsCharacterSet + infoObject = self.makeInfoObject() + infoObject.postscriptWindowsCharacterSet = -1 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # macintoshFONDFamilyID + infoObject = self.makeInfoObject() + infoObject.macintoshFONDFamilyID = "abc" + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + # macintoshFONDName + infoObject = self.makeInfoObject() + infoObject.macintoshFONDName = 123 + writer = UFOWriter(self.dstDir) + self.assertRaises(UFOLibError, writer.writeInfo, info=infoObject) + + + + +class ConversionFunctionsTestCase(unittest.TestCase): + + def tearDown(self): + path = self.getFontPath("TestFont1 (UFO1) converted.ufo") + if os.path.exists(path): + shutil.rmtree(path) + path = self.getFontPath("TestFont1 (UFO2) converted.ufo") + if os.path.exists(path): + shutil.rmtree(path) + + def getFontPath(self, fileName): + import robofab + path = os.path.dirname(robofab.__file__) + path = os.path.dirname(path) + path = os.path.dirname(path) + path = os.path.join(path, "TestData", fileName) + return path + + def compareFileStructures(self, path1, path2, expectedInfoData, testFeatures): + # result + metainfoPath1 = os.path.join(path1, "metainfo.plist") + fontinfoPath1 = os.path.join(path1, "fontinfo.plist") + kerningPath1 = os.path.join(path1, "kerning.plist") + groupsPath1 = os.path.join(path1, "groups.plist") + libPath1 = os.path.join(path1, "lib.plist") + featuresPath1 = os.path.join(path1, "features.plist") + glyphsPath1 = os.path.join(path1, "glyphs") + glyphsPath1_contents = os.path.join(glyphsPath1, "contents.plist") + glyphsPath1_A = os.path.join(glyphsPath1, "A_.glif") + glyphsPath1_B = os.path.join(glyphsPath1, "B_.glif") + # expected result + metainfoPath2 = os.path.join(path2, "metainfo.plist") + fontinfoPath2 = os.path.join(path2, "fontinfo.plist") + kerningPath2 = os.path.join(path2, "kerning.plist") + groupsPath2 = os.path.join(path2, "groups.plist") + libPath2 = os.path.join(path2, "lib.plist") + featuresPath2 = os.path.join(path2, "features.plist") + glyphsPath2 = os.path.join(path2, "glyphs") + glyphsPath2_contents = os.path.join(glyphsPath2, "contents.plist") + glyphsPath2_A = os.path.join(glyphsPath2, "A_.glif") + glyphsPath2_B = os.path.join(glyphsPath2, "B_.glif") + # look for existence + self.assertEqual(os.path.exists(metainfoPath1), True) + self.assertEqual(os.path.exists(fontinfoPath1), True) + self.assertEqual(os.path.exists(kerningPath1), True) + self.assertEqual(os.path.exists(groupsPath1), True) + self.assertEqual(os.path.exists(libPath1), True) + self.assertEqual(os.path.exists(glyphsPath1), True) + self.assertEqual(os.path.exists(glyphsPath1_contents), True) + self.assertEqual(os.path.exists(glyphsPath1_A), True) + self.assertEqual(os.path.exists(glyphsPath1_B), True) + if testFeatures: + self.assertEqual(os.path.exists(featuresPath1), True) + # look for aggrement + data1 = readPlist(metainfoPath1) + data2 = readPlist(metainfoPath2) + self.assertEqual(data1, data2) + data1 = readPlist(fontinfoPath1) + self.assertEqual(sorted(data1.items()), sorted(expectedInfoData.items())) + data1 = readPlist(kerningPath1) + data2 = readPlist(kerningPath2) + self.assertEqual(data1, data2) + data1 = readPlist(groupsPath1) + data2 = readPlist(groupsPath2) + self.assertEqual(data1, data2) + data1 = readPlist(libPath1) + data2 = readPlist(libPath2) + if "UFO1" in libPath1: + for key in removeFromFormatVersion1Lib: + if key in data1: + del data1[key] + if "UFO1" in libPath2: + for key in removeFromFormatVersion1Lib: + if key in data2: + del data2[key] + self.assertEqual(data1, data2) + data1 = readPlist(glyphsPath1_contents) + data2 = readPlist(glyphsPath2_contents) + self.assertEqual(data1, data2) + data1 = readPlist(glyphsPath1_A) + data2 = readPlist(glyphsPath2_A) + self.assertEqual(data1, data2) + data1 = readPlist(glyphsPath1_B) + data2 = readPlist(glyphsPath2_B) + self.assertEqual(data1, data2) + + def test1To2(self): + path1 = self.getFontPath("TestFont1 (UFO1).ufo") + path2 = self.getFontPath("TestFont1 (UFO1) converted.ufo") + path3 = self.getFontPath("TestFont1 (UFO2).ufo") + convertUFOFormatVersion1ToFormatVersion2(path1, path2) + self.compareFileStructures(path2, path3, expectedFontInfo1To2Conversion, False) + + def test2To1(self): + path1 = self.getFontPath("TestFont1 (UFO2).ufo") + path2 = self.getFontPath("TestFont1 (UFO2) converted.ufo") + path3 = self.getFontPath("TestFont1 (UFO1).ufo") + convertUFOFormatVersion2ToFormatVersion1(path1, path2) + self.compareFileStructures(path2, path3, expectedFontInfo2To1Conversion, False) + + +if __name__ == "__main__": + from robofab.test.testSupport import runTests + runTests() |